fix(universal-link): more new link format, handle old link format (#17721)

Co-authored-by: pavloburykh <pavlo@status.im>
This commit is contained in:
yqrashawn 2023-11-02 15:31:49 +08:00 committed by GitHub
parent 2d92b515b8
commit 859cb19886
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 181 additions and 135 deletions

View File

@ -106,11 +106,9 @@
:target :node-test :target :node-test
;; Uncomment line below to `make test-watch` a specific file ;; Uncomment line below to `make test-watch` a specific file
;; :ns-regexp "status-im2.subs.messages-test$" ;; :ns-regexp "status-im2.subs.messages-test$"
:main :main status-im.test-runner/main
status-im.test-runner/main
;; set :ui-driven to true to let shadow-cljs inject node-repl ;; set :ui-driven to true to let shadow-cljs inject node-repl
:ui-driven :ui-driven true
true
:closure-defines :closure-defines
{status-im2.config/POKT_TOKEN #shadow/env "POKT_TOKEN" {status-im2.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im2.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN" status-im2.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"

View File

@ -24,7 +24,7 @@
(defn universal-link (defn universal-link
[community-id] [community-id]
(str (:external universal-links/domains) (str (:external universal-links/domains)
"/c/" "/c#"
community-id)) community-id))
(defn <-request-to-join-community-rpc (defn <-request-to-join-community-rpc

View File

@ -30,6 +30,10 @@
(def handled-schemes (set (into uri-schemes web-urls))) (def handled-schemes (set (into uri-schemes web-urls)))
(def group-chat-extractor
{[#"(.*)" :params] {"" :group-chat
"/" :group-chat}})
(def eip-extractor (def eip-extractor
{#{[:prefix "-" :address] {#{[:prefix "-" :address]
[:address]} [:address]}
@ -39,9 +43,15 @@
(def routes (def routes
["" [""
{handled-schemes {["c/" :community-data] :community {handled-schemes {["c/" :community-data] :community
["cc/" :chat-data] :community-chat ["cc/" :community-data] :community-chat
["u/" :user-data] :user} ["p/" :chat-id] :private-chat
["cr/" :community-id] :community-requests
"g/" group-chat-extractor
["wallet/" :account] :wallet-account
["u/" :user-data] :user
"c" :community
"u" :user}
ethereum-scheme eip-extractor}]) ethereum-scheme eip-extractor}])
(defn parse-query-params (defn parse-query-params
@ -58,7 +68,6 @@
(defn match-uri (defn match-uri
[uri] [uri]
;;
(let [;; bidi has trouble parse path with `=` in it extract `=` here and add back to parsed (let [;; bidi has trouble parse path with `=` in it extract `=` here and add back to parsed
;; base64url regex based on https://datatracker.ietf.org/doc/html/rfc4648#section-5 may ;; base64url regex based on https://datatracker.ietf.org/doc/html/rfc4648#section-5 may
;; include invalid base64 (invalid length, length of any base64 encoded string must be a ;; include invalid base64 (invalid length, length of any base64 encoded string must be a
@ -70,6 +79,7 @@
uri-without-equal-in-path uri-without-equal-in-path
(if equal-end-of-base64url (string/replace-first uri equal-end-of-base64url "") uri) (if equal-end-of-base64url (string/replace-first uri equal-end-of-base64url "") uri)
;; fragment is the one after `#`, usually user-id, ens-name, community-id
fragment (parse-fragment uri) fragment (parse-fragment uri)
ens? (ens/is-valid-eth-name? fragment) ens? (ens/is-valid-eth-name? fragment)
@ -87,8 +97,18 @@
(and equal-end-of-base64url (= handler :community) (:community-data route-params)) (and equal-end-of-base64url (= handler :community) (:community-data route-params))
(update-in [:route-params :community-data] #(str % equal-end-of-base64url)) (update-in [:route-params :community-data] #(str % equal-end-of-base64url))
(and equal-end-of-base64url (= handler :community-chat) (:chat-data route-params)) (and equal-end-of-base64url (= handler :community-chat) (:community-data route-params))
(update-in [:route-params :chat-data] #(str % equal-end-of-base64url)) (update-in [:route-params :community-data] #(str % equal-end-of-base64url))
(and fragment (= handler :community-chat) (:community-data route-params))
(assoc-in [:route-params :community-id] fragment)
(and fragment
(= handler :community-chat)
(:community-data route-params)
(string? (:community-data route-params))
(re-find constants/regx-starts-with-uuid (:community-data route-params)))
(assoc-in [:route-params :community-channel-id] (:community-data route-params))
(and equal-end-of-base64url (= handler :user) (:user-data route-params)) (and equal-end-of-base64url (= handler :user) (:user-data route-params))
(update-in [:route-params :user-data] #(str % equal-end-of-base64url)) (update-in [:route-params :user-data] #(str % equal-end-of-base64url))
@ -174,6 +194,15 @@
(cb {:type :private-chat (cb {:type :private-chat
:error :invalid-chat-id}))))) :error :invalid-chat-id})))))
(defn match-community-channel-async
[{:keys [community-channel-id community-id]} cb]
(if (validators/valid-compressed-key? community-id)
(native-module/deserialize-and-compress-key
community-id
#(cb {:type :community-chat :chat-id (str % community-channel-id)}))
(cb {:type :community-chat
:error :not-found})))
(defn match-browser (defn match-browser
[uri {:keys [domain]}] [uri {:keys [domain]}]
;; NOTE: We rebuild domain from original URI and matched domain ;; NOTE: We rebuild domain from original URI and matched domain
@ -238,8 +267,8 @@
:community)) :community))
(defn handle-uri (defn handle-uri
[chain _chats uri cb] [chain chats uri cb]
(let [{:keys [handler route-params]} (match-uri uri)] (let [{:keys [handler route-params query-params]} (match-uri uri)]
(log/info "[router] uri " uri " matched " handler " with " route-params) (log/info "[router] uri " uri " matched " handler " with " route-params)
(cond (cond
@ -253,36 +282,35 @@
(and (= handler :user) (:user-id route-params)) (and (= handler :user) (:user-id route-params))
(match-contact-async chain route-params cb) (match-contact-async chain route-params cb)
;; ;; NOTE: removed in `match-uri`, might need this in the future ;; NOTE: removed in `match-uri`, might need this in the future
;; (= handler :private-chat) (= handler :private-chat)
;; (match-private-chat-async chain route-params cb) (match-private-chat-async chain route-params cb)
;; ;; NOTE: removed in `match-uri`, might need this in the future ;; NOTE: removed in `match-uri`, might need this in the future
;; (= handler :group-chat) (= handler :group-chat)
;; (cb (match-group-chat chats query-params)) (cb (match-group-chat chats query-params))
(validators/valid-public-key? uri) (validators/valid-public-key? uri)
(match-contact-async chain {:user-id uri} cb) (match-contact-async chain {:user-id uri} cb)
;; ;; NOTE: removed in `match-uri`, might need this in the future ;; NOTE: removed in `match-uri`, might need this in the future
;; (= handler :community-requests) (= handler :community-requests)
;; (cb {:type handler :community-id (:community-id route-params)}) (cb {:type handler :community-id (:community-id route-params)})
(and (= handler :community) (:community-id route-params)) (and (= handler :community) (:community-id route-params))
(cb {:type (community-route-type route-params) (cb {:type (community-route-type route-params)
:community-id (:community-id route-params)}) :community-id (:community-id route-params)})
;; ;; TODO: jump to community overview for now, should jump to community channel (and (= handler :community-chat) (:community-channel-id route-params) (:community-id route-params))
;; (and (= handler :community-chat) (:chat-id route-params)) (match-community-channel-async route-params cb)
;; (cb {:type handler :chat-id (:chat-id route-params)})
(and (= handler :community-chat) (:community-id route-params)) (and (= handler :community-chat) (:community-id route-params))
(cb {:type (community-route-type route-params) (cb {:type (community-route-type route-params)
:community-id (:community-id route-params)}) :community-id (:community-id route-params)})
;; ;; NOTE: removed in `match-uri`, might need this in the future ;; NOTE: removed in `match-uri`, might need this in the future
;; (= handler :wallet-account) (= handler :wallet-account)
;; (cb (match-wallet-account route-params)) (cb (match-wallet-account route-params))
(address/address? uri) (address/address? uri)
(cb (address->eip681 uri)) (cb (address->eip681 uri))

View File

@ -19,6 +19,9 @@
:query-params (when (= 3 (count expected)) (last expected)) :query-params (when (= 3 (count expected)) (last expected))
:uri uri}) :uri uri})
"https://status.app/u#zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj"
[:user
{:user-id "zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj"}]
"https://status.app/u/G10A4B0JdgwyRww90WXtnP1oNH1ZLQNM0yX0Ja9YyAMjrqSZIYINOHCbFhrnKRAcPGStPxCMJDSZlGCKzmZrJcimHY8BbcXlORrElv_BbQEegnMDPx1g9C5VVNl0fE4y#zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj" "https://status.app/u/G10A4B0JdgwyRww90WXtnP1oNH1ZLQNM0yX0Ja9YyAMjrqSZIYINOHCbFhrnKRAcPGStPxCMJDSZlGCKzmZrJcimHY8BbcXlORrElv_BbQEegnMDPx1g9C5VVNl0fE4y#zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj"
[:user [:user
{:user-data {:user-data
@ -31,23 +34,46 @@
"G10A4B0JdgwyRww90WXtnP1oNH1ZLQNM0yX0Ja9YyAMjrqSZIYINOHCbFhrnKRAcPGStPxCMJDSZlGCKzmZrJcimHY8BbcXlORrElv_BbQEegnMDPx1g9C5VVNl0fE4y" "G10A4B0JdgwyRww90WXtnP1oNH1ZLQNM0yX0Ja9YyAMjrqSZIYINOHCbFhrnKRAcPGStPxCMJDSZlGCKzmZrJcimHY8BbcXlORrElv_BbQEegnMDPx1g9C5VVNl0fE4y"
:user-id "zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj"}] :user-id "zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj"}]
"status-app://u#zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj"
[:user
{:user-id "zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj"}]
"https://status.app/cc/G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11" "https://status.app/cc/G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"
[:community-chat [:community-chat
{:chat-data {:community-data
"G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=" "G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM="
:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}] :community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
"status-app://cc/G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11" "status-app://cc/G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"
[:community-chat [:community-chat
{:chat-data {:community-data
"G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=" "G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM="
:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}] :community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
"https://status.app/cc/c432709e-fc73-440d-bb67-cb3a0929dfda#zQ3shZL6dXiFCbDyxnXxwQa9v8QFC2q19subFtyxd7kVszMVo"
[:community-chat
{:community-data
"c432709e-fc73-440d-bb67-cb3a0929dfda"
:community-channel-id
"c432709e-fc73-440d-bb67-cb3a0929dfda"
:community-id "zQ3shZL6dXiFCbDyxnXxwQa9v8QFC2q19subFtyxd7kVszMVo"}]
"status-app://cc/c432709e-fc73-440d-bb67-cb3a0929dfda#zQ3shZL6dXiFCbDyxnXxwQa9v8QFC2q19subFtyxd7kVszMVo"
[:community-chat
{:community-data
"c432709e-fc73-440d-bb67-cb3a0929dfda"
:community-channel-id
"c432709e-fc73-440d-bb67-cb3a0929dfda"
:community-id "zQ3shZL6dXiFCbDyxnXxwQa9v8QFC2q19subFtyxd7kVszMVo"}]
"https://status.app/c/iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11" "https://status.app/c/iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"
[:community [:community
{:community-data {:community-data
"iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM=" "iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM="
:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}] :community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
"https://status.app/c#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"
[:community
{:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
"status-app://c/iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11" "status-app://c/iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"
[:community [:community
@ -55,6 +81,10 @@
"iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM=" "iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM="
:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}] :community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
"status-app://c#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"
[:community
{:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
"ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
[:ethereum {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"}] [:ethereum {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"}]

View File

@ -1,7 +1,6 @@
(ns status-im.utils.universal-links.core (ns status-im.utils.universal-links.core
(:require (:require
[clojure.string :as string] [clojure.string :as string]
[goog.string :as gstring]
[native-module.core :as native-module] [native-module.core :as native-module]
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
[status-im.group-chats.core :as group-chats] [status-im.group-chats.core :as group-chats]
@ -9,7 +8,6 @@
[status-im.router.core :as router] [status-im.router.core :as router]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.wallet.choose-recipient.core :as choose-recipient] [status-im.wallet.choose-recipient.core :as choose-recipient]
[status-im2.constants :as constants]
[status-im2.navigation.events :as navigation] [status-im2.navigation.events :as navigation]
[taoensso.timbre :as log] [taoensso.timbre :as log]
[utils.ethereum.chain :as chain] [utils.ethereum.chain :as chain]
@ -27,27 +25,11 @@
(def links (def links
{:private-chat "%s/p/%s" {:private-chat "%s/p/%s"
:community-requests "%s/cr/%s" :community-requests "%s/cr/%s"
:community "%s/c/%s" :community "%s/c#%s"
:group-chat "%s/g/%s" :group-chat "%s/g/%s"
:user "%s/u/%s" :user "%s/u#%s"
:browse "%s/b/%s"}) :browse "%s/b/%s"})
(defn generate-link
[link-type domain-type param]
(gstring/format (get links link-type)
(get domains domain-type)
param))
(defn universal-link?
[url]
(boolean
(re-matches constants/regx-universal-link url)))
(defn deep-link?
[url]
(boolean
(re-matches constants/regx-deep-link url)))
(rf/defn handle-browse (rf/defn handle-browse
[cofx {:keys [url]}] [cofx {:keys [url]}]
(log/info "universal-links: handling browse" url) (log/info "universal-links: handling browse" url)
@ -220,7 +202,6 @@
#_(native-module/start-searching-for-local-pairing-peers #_(native-module/start-searching-for-local-pairing-peers
#(log/info "[local-pairing] errors from local-pairing-preflight-outbound-check ->" %))) #(log/info "[local-pairing] errors from local-pairing-preflight-outbound-check ->" %)))
(defn finalize (defn finalize
"Remove event listener for url" "Remove event listener for url"
[] []

View File

@ -20,9 +20,9 @@
(is (nil? (get-in (links/handle-url {:db db} "some-url") (is (nil? (get-in (links/handle-url {:db db} "some-url")
[:db :universal-links/url])))) [:db :universal-links/url]))))
(testing "Handle a custom string" (testing "Handle a custom string"
(is (= (get-in (links/handle-url {:db db} "https://status.app/u/statuse2e") (is (= (get-in (links/handle-url {:db db} "https://status.app/u#statuse2e")
[::router/handle-uri :uri]) [::router/handle-uri :uri])
"https://status.app/u/statuse2e"))))))) "https://status.app/u#statuse2e")))))))
(deftest url-event-listener (deftest url-event-listener
(testing "the url is not nil" (testing "the url is not nil"

View File

@ -10,7 +10,7 @@
(def links (def links
{:private-chat "%s/p/%s" {:private-chat "%s/p/%s"
:user "%s/u/%s" :user "%s/u#%s"
:browse "%s/b/%s"}) :browse "%s/b/%s"})
(defn universal-link? (defn universal-link?

View File

@ -184,6 +184,7 @@
(def regx-ens #"^(?=.{5,255}$)([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$") (def regx-ens #"^(?=.{5,255}$)([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$")
(def regx-address #"^0x[a-fA-F0-9]{40}$") (def regx-address #"^0x[a-fA-F0-9]{40}$")
(def regx-address-contains #"(?i)0x[a-fA-F0-9]{40}") (def regx-address-contains #"(?i)0x[a-fA-F0-9]{40}")
(def regx-starts-with-uuid #"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")
(def ^:const dapp-permission-contact-code "contact-code") (def ^:const dapp-permission-contact-code "contact-code")
(def ^:const dapp-permission-web3 "web3") (def ^:const dapp-permission-web3 "web3")

View File

@ -34,14 +34,14 @@
(zipmap (repeat nil)))) (zipmap (repeat nil))))
([kv] (-> (init-contact) (merge kv)))) ([kv] (-> (init-contact) (merge kv))))
(def url-regex #"^https?://status.app/u/(.+)") (def url-regex #"^https?://status.app/u(/([a-zA-Z0-9_-]+)(={0,2}))?#(.+)")
(defn ->id (defn ->id
[{:keys [input] :as contact}] [{:keys [input] :as contact}]
(let [trimmed-input (utils.string/safe-trim input)] (let [trimmed-input (utils.string/safe-trim input)]
(->> {:id (if (empty? trimmed-input) (->> {:id (if (empty? trimmed-input)
nil nil
(if-some [[_ id] (re-matches url-regex trimmed-input)] (if-some [id (last (re-matches url-regex trimmed-input))]
id id
trimmed-input))} trimmed-input))}
(merge contact)))) (merge contact))))
@ -175,8 +175,11 @@
(let [contact (get-in db [:contacts/new-identity])] (let [contact (get-in db [:contacts/new-identity])]
(when (= (:input contact) input) (when (= (:input contact) input)
(let [state (cond (let [state (cond
(or (string/includes? (:message err) "fallback failed") (and (string? err) (string/includes? err "invalid public key"))
(string/includes? (:message err) "no such host")) {:state :invalid :msg :t/not-a-chatkey}
(and (string? (:message err))
(or (string/includes? (:message err) "fallback failed")
(string/includes? (:message err) "no such host")))
{:state :invalid :msg :t/lost-connection} {:state :invalid :msg :t/lost-connection}
:else {:state :invalid})] :else {:state :invalid})]
{:db (assoc db :contacts/new-identity (merge contact state))})))) {:db (assoc db :contacts/new-identity (merge contact state))}))))

View File

@ -11,8 +11,9 @@
(def ckey "zQ3shWj4WaBdf2zYKCkXe6PHxDxNTzZyid1i75879Ue9cX9gA") (def ckey "zQ3shWj4WaBdf2zYKCkXe6PHxDxNTzZyid1i75879Ue9cX9gA")
(def ens "esep") (def ens "esep")
(def ens-stateofus-eth (str ens ".stateofus.eth")) (def ens-stateofus-eth (str ens ".stateofus.eth"))
(def link-ckey (str "https://status.app/u/" ckey)) (def link-ckey (str "https://status.app/u#" ckey))
(def link-ens (str "https://status.app/u/" ens)) (def link-ckey-with-encoded-data (str "https://status.app/u/CwSACgcKBVBhdmxvAw==#" ckey))
(def link-ens (str "https://status.app/u#" ens))
;;; unit tests (no app-db involved) ;;; unit tests (no app-db involved)
@ -22,56 +23,61 @@
:input i})) :input i}))
(events/init-contact e)) (events/init-contact e))
"" {:user-public-key user-ukey "" {:user-public-key user-ukey
:input "" :input ""
:type :empty :type :empty
:state :empty} :state :empty}
" " {:user-public-key user-ukey " " {:user-public-key user-ukey
:input " " :input " "
:type :empty :type :empty
:state :empty} :state :empty}
ukey {:user-public-key user-ukey ukey {:user-public-key user-ukey
:input ukey :input ukey
:id ukey :id ukey
:type :public-key :type :public-key
:public-key ukey :public-key ukey
:state :invalid :state :invalid
:msg :t/not-a-chatkey} :msg :t/not-a-chatkey}
ens {:user-public-key user-ukey ens {:user-public-key user-ukey
:input ens :input ens
:id ens :id ens
:type :ens :type :ens
:ens ens-stateofus-eth :ens ens-stateofus-eth
:state :resolve-ens} :state :resolve-ens}
(str " " ens) {:user-public-key user-ukey (str " " ens) {:user-public-key user-ukey
:input (str " " ens) :input (str " " ens)
:id ens :id ens
:type :ens :type :ens
:ens ens-stateofus-eth :ens ens-stateofus-eth
:state :resolve-ens} :state :resolve-ens}
ckey {:user-public-key user-ukey ckey {:user-public-key user-ukey
:input ckey :input ckey
:id ckey :id ckey
:type :compressed-key :type :compressed-key
:state :decompress-key} :state :decompress-key}
link-ckey {:user-public-key user-ukey link-ckey {:user-public-key user-ukey
:input link-ckey :input link-ckey
:id ckey :id ckey
:type :compressed-key :type :compressed-key
:state :decompress-key} :state :decompress-key}
link-ckey-with-encoded-data {:user-public-key user-ukey
:input link-ckey-with-encoded-data
:id ckey
:type :compressed-key
:state :decompress-key}
link-ens {:user-public-key user-ukey link-ens {:user-public-key user-ukey
:input link-ens :input link-ens
:id ens :id ens
:type :ens :type :ens
:ens ens-stateofus-eth :ens ens-stateofus-eth
:state :resolve-ens})) :state :resolve-ens}))
;;; event handler tests (no callbacks) ;;; event handler tests (no callbacks)

View File

@ -80,11 +80,10 @@
:button (when empty-input? :button (when empty-input?
{:on-press paste-on-input {:on-press paste-on-input
:text (i18n/label :t/paste)}) :text (i18n/label :t/paste)})
;; NOTE: `scanned` has priority over `@input-value`, we clean it when the input ;; NOTE: `scanned` has priority over `@input-value`, we clean it when the input is updated
;; is updated so that it's `nil` and `@input-value` is shown. ;; so that it's `nil` and `@input-value` is shown. To fastly clean it, we use
;; To fastly clean it, we use `dispatch-sync`. ;; `dispatch-sync`. This call could be avoided if `::qr-scanner/scan-code` were able to
;; This call could be avoided if `::qr-scanner/scan-code` were able to receive a ;; receive a callback function, not only a re-frame event as callback.
;; callback function, not only a re-frame event as callback.
:value (or scanned @input-value) :value (or scanned @input-value)
:on-change-text (fn [new-text] :on-change-text (fn [new-text]
(reset! input-value new-text) (reset! input-value new-text)

View File

@ -9,7 +9,7 @@
(defn community-link (defn community-link
[id] [id]
(str "https://status.app/c/" id)) (str "https://status.app/c#" id))
(rf/defn cache-link-preview-data (rf/defn cache-link-preview-data
{:events [:chat.ui/cache-link-preview-data]} {:events [:chat.ui/cache-link-preview-data]}

View File

@ -62,16 +62,16 @@
[] []
(let [media-server-port (rf/sub [:mediaserver/port]) (let [media-server-port (rf/sub [:mediaserver/port])
state (reagent/atom state (reagent/atom
{:url "https://join.status.im/status" {:url "https://status.app/u#zQ34e1zlOdas0pKnvrweeedsasas12adjie8"
:size 250 :size 250
:avatar :none :avatar :none
:profile-picture (resources/get-mock-image :user-picture-male5) :profile-picture (resources/get-mock-image :user-picture-male5)
:customization-color :army :customization-color :army
:full-name "Full Name" :full-name "Full Name"
:emoji "🍒" :emoji "🍒"
:picture (resources/get-mock-image :community-logo) :picture (resources/get-mock-image :community-logo)
:f-name "First Name" :f-name "First Name"
:l-name "Last Name"})] :l-name "Last Name"})]
(fn [] (fn []
(let [qr-media-server-uri (image-server/get-qr-image-uri-for-any-url (let [qr-media-server-uri (image-server/get-qr-image-uri-for-any-url
{:url (:url @state) {:url (:url @state)

View File

@ -68,7 +68,7 @@
(str (name network) ":"))) (str (name network) ":")))
(def ^:private profile-link (def ^:private profile-link
"https://join.status.im/u/zQ3shfc5Wqnu") "https://status.app/u#zQ34e1zlOdas0pKnvrweeedsasas12adjie8")
(def ^:private wallet-address "0x39cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2") (def ^:private wallet-address "0x39cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2")

View File

@ -43,11 +43,11 @@
(defn get-abbreviated-profile-url (defn get-abbreviated-profile-url
"The goal here is to generate a string that begins with "The goal here is to generate a string that begins with
status.app/u/ joined with the 1st 5 characters status.app/u# joined with the 1st 5 characters
of the compressed public key followed by an ellipsis followed by of the compressed public key followed by an ellipsis followed by
the last 10 characters of the compressed public key" the last 10 characters of the compressed public key"
[base-url public-key] [base-url public-key]
(if (and public-key base-url (> (count public-key) 17) (= "status.app/u/" base-url)) (if (and public-key base-url (> (count public-key) 17) (= "status.app/u#" base-url))
(let [first-part-of-public-pk (subs public-key 0 5) (let [first-part-of-public-pk (subs public-key 0 5)
ellipsis "..." ellipsis "..."
public-key-size (count public-key) public-key-size (count public-key)

View File

@ -22,22 +22,22 @@
(deftest test-get-abbreviated-profile-url (deftest test-get-abbreviated-profile-url
(testing "Ensure the function correctly generates an abbreviated profile URL for a valid public key" (testing "Ensure the function correctly generates an abbreviated profile URL for a valid public key"
(is (= "status.app/u/zQ3sh...mrdYpzeFUa" (is (= "status.app/u#zQ3sh...mrdYpzeFUa"
(utils.address/get-abbreviated-profile-url (utils.address/get-abbreviated-profile-url
"status.app/u/" "status.app/u#"
"zQ3shPrnUhhR42JJn3QdhodGest8w8MjiH8hPaimrdYpzeFUa")))) "zQ3shPrnUhhR42JJn3QdhodGest8w8MjiH8hPaimrdYpzeFUa"))))
(testing "Ensure the function returns nil when given an empty public key" (testing "Ensure the function returns nil when given an empty public key"
(is (nil? (utils.address/get-abbreviated-profile-url "status.app/u/" "")))) (is (nil? (utils.address/get-abbreviated-profile-url "status.app/u#" ""))))
(testing "Ensure the function returns nil when given a nil public key" (testing "Ensure the function returns nil when given a nil public key"
(is (nil? (utils.address/get-abbreviated-profile-url "status.app/u/" nil)))) (is (nil? (utils.address/get-abbreviated-profile-url "status.app/u#" nil))))
(testing "Ensure the function returns nil when given an incorrect base URL" (testing "Ensure the function returns nil when given an incorrect base URL"
(is (nil? (utils.address/get-abbreviated-profile-url (is (nil? (utils.address/get-abbreviated-profile-url
"status.app/uwu/" "status.app/uwu#"
"zQ3shPrnUhhR42JJn3QdhodGest8w8MjiH8hPaimrdYpzeFUa")))) "zQ3shPrnUhhR42JJn3QdhodGest8w8MjiH8hPaimrdYpzeFUa"))))
(testing "Ensure the function returns nil when given a public key shorter than 17 characters" (testing "Ensure the function returns nil when given a public key shorter than 17 characters"
(is (nil? (utils.address/get-abbreviated-profile-url "status.app/u/" "abc"))) (is (nil? (utils.address/get-abbreviated-profile-url "status.app/u#" "abc")))
(is (nil? (utils.address/get-abbreviated-profile-url "status.app/u/" "1234"))))) (is (nil? (utils.address/get-abbreviated-profile-url "status.app/u#" "1234")))))

View File

@ -11,8 +11,8 @@
(def ^:const account-initials-action "/accountInitials") (def ^:const account-initials-action "/accountInitials")
(def ^:const contact-images-action "/contactImages") (def ^:const contact-images-action "/contactImages")
(def ^:const generate-qr-action "/GenerateQRCode") (def ^:const generate-qr-action "/GenerateQRCode")
(def ^:const status-profile-base-url "https://status.app/u/") (def ^:const status-profile-base-url "https://status.app/u#")
(def ^:const status-profile-base-url-without-https "status.app/u/") (def ^:const status-profile-base-url-without-https "status.app/u#")
(defn get-font-file-ready (defn get-font-file-ready
"setup font file and get the absolute path to it "setup font file and get the absolute path to it

View File

@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>", "_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im", "owner": "status-im",
"repo": "status-go", "repo": "status-go",
"version": "v0.171.7", "version": "v0.171.8",
"commit-sha1": "74396b461df0c18593262a67c9fd79d706287f7a", "commit-sha1": "678fc03b376e02df7142e89f2c626e3ba1c03807",
"src-sha256": "1d46lav3g6m1f6ifpypjlsp2qm82c6yk4478awb8f68azpdkvcg5" "src-sha256": "0bapjbyyyrvg2k3jimpfshcwc77lylamhlm9si3mbnrbm1dl89xc"
} }

View File

@ -145,7 +145,7 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
self.device_2.create_user(third_user=True, username=new_username_2) self.device_2.create_user(third_user=True, username=new_username_2)
self.device_2.just_fyi('Device2 sends a contact request to Device1 using his profile link') self.device_2.just_fyi('Device2 sends a contact request to Device1 using his profile link')
self.home_2.driver.set_clipboard_text("https://status.app/u/" + self.public_key_1) self.home_2.driver.set_clipboard_text("https://status.app/u#" + self.public_key_1)
self.home_2.chats_tab.click() self.home_2.chats_tab.click()
self.home_2.new_chat_button.click_until_presence_of_element(self.home_2.add_a_contact_chat_bottom_sheet_button) self.home_2.new_chat_button.click_until_presence_of_element(self.home_2.add_a_contact_chat_bottom_sheet_button)
self.home_2.add_a_contact_chat_bottom_sheet_button.click() self.home_2.add_a_contact_chat_bottom_sheet_button.click()

View File

@ -564,4 +564,4 @@ class HomeView(BaseView):
self.link_to_profile_text.click() self.link_to_profile_text.click()
c_text = self.driver.get_clipboard_text() c_text = self.driver.get_clipboard_text()
self.click_system_back_button() self.click_system_back_button()
return c_text.split("/")[-1] return c_text.split("#")[-1]