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
;; Uncomment line below to `make test-watch` a specific file
;; :ns-regexp "status-im2.subs.messages-test$"
:main
status-im.test-runner/main
:main status-im.test-runner/main
;; set :ui-driven to true to let shadow-cljs inject node-repl
:ui-driven
true
:ui-driven true
:closure-defines
{status-im2.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im2.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"

View File

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

View File

@ -30,6 +30,10 @@
(def handled-schemes (set (into uri-schemes web-urls)))
(def group-chat-extractor
{[#"(.*)" :params] {"" :group-chat
"/" :group-chat}})
(def eip-extractor
{#{[:prefix "-" :address]
[:address]}
@ -40,8 +44,14 @@
(def routes
[""
{handled-schemes {["c/" :community-data] :community
["cc/" :chat-data] :community-chat
["u/" :user-data] :user}
["cc/" :community-data] :community-chat
["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}])
(defn parse-query-params
@ -58,7 +68,6 @@
(defn match-uri
[uri]
;;
(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
;; include invalid base64 (invalid length, length of any base64 encoded string must be a
@ -70,6 +79,7 @@
uri-without-equal-in-path
(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)
ens? (ens/is-valid-eth-name? fragment)
@ -87,8 +97,18 @@
(and equal-end-of-base64url (= handler :community) (:community-data route-params))
(update-in [:route-params :community-data] #(str % equal-end-of-base64url))
(and equal-end-of-base64url (= handler :community-chat) (:chat-data route-params))
(update-in [:route-params :chat-data] #(str % equal-end-of-base64url))
(and equal-end-of-base64url (= handler :community-chat) (:community-data route-params))
(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))
(update-in [:route-params :user-data] #(str % equal-end-of-base64url))
@ -174,6 +194,15 @@
(cb {:type :private-chat
: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
[uri {:keys [domain]}]
;; NOTE: We rebuild domain from original URI and matched domain
@ -238,8 +267,8 @@
:community))
(defn handle-uri
[chain _chats uri cb]
(let [{:keys [handler route-params]} (match-uri uri)]
[chain chats uri cb]
(let [{:keys [handler route-params query-params]} (match-uri uri)]
(log/info "[router] uri " uri " matched " handler " with " route-params)
(cond
@ -253,36 +282,35 @@
(and (= handler :user) (:user-id route-params))
(match-contact-async chain route-params cb)
;; ;; NOTE: removed in `match-uri`, might need this in the future
;; (= handler :private-chat)
;; (match-private-chat-async chain route-params cb)
;; NOTE: removed in `match-uri`, might need this in the future
(= handler :private-chat)
(match-private-chat-async chain route-params cb)
;; ;; NOTE: removed in `match-uri`, might need this in the future
;; (= handler :group-chat)
;; (cb (match-group-chat chats query-params))
;; NOTE: removed in `match-uri`, might need this in the future
(= handler :group-chat)
(cb (match-group-chat chats query-params))
(validators/valid-public-key? uri)
(match-contact-async chain {:user-id uri} cb)
;; ;; NOTE: removed in `match-uri`, might need this in the future
;; (= handler :community-requests)
;; (cb {:type handler :community-id (:community-id route-params)})
;; NOTE: removed in `match-uri`, might need this in the future
(= handler :community-requests)
(cb {:type handler :community-id (:community-id route-params)})
(and (= handler :community) (:community-id route-params))
(cb {:type (community-route-type route-params)
:community-id (:community-id route-params)})
;; ;; TODO: jump to community overview for now, should jump to community channel
;; (and (= handler :community-chat) (:chat-id route-params))
;; (cb {:type handler :chat-id (:chat-id route-params)})
(and (= handler :community-chat) (:community-channel-id route-params) (:community-id route-params))
(match-community-channel-async route-params cb)
(and (= handler :community-chat) (:community-id route-params))
(cb {:type (community-route-type route-params)
:community-id (:community-id route-params)})
;; ;; NOTE: removed in `match-uri`, might need this in the future
;; (= handler :wallet-account)
;; (cb (match-wallet-account route-params))
;; NOTE: removed in `match-uri`, might need this in the future
(= handler :wallet-account)
(cb (match-wallet-account route-params))
(address/address? uri)
(cb (address->eip681 uri))

View File

@ -19,6 +19,9 @@
:query-params (when (= 3 (count expected)) (last expected))
:uri uri})
"https://status.app/u#zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj"
[:user
{:user-id "zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj"}]
"https://status.app/u/G10A4B0JdgwyRww90WXtnP1oNH1ZLQNM0yX0Ja9YyAMjrqSZIYINOHCbFhrnKRAcPGStPxCMJDSZlGCKzmZrJcimHY8BbcXlORrElv_BbQEegnMDPx1g9C5VVNl0fE4y#zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj"
[:user
{:user-data
@ -31,23 +34,46 @@
"G10A4B0JdgwyRww90WXtnP1oNH1ZLQNM0yX0Ja9YyAMjrqSZIYINOHCbFhrnKRAcPGStPxCMJDSZlGCKzmZrJcimHY8BbcXlORrElv_BbQEegnMDPx1g9C5VVNl0fE4y"
:user-id "zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj"}]
"status-app://u#zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj"
[:user
{:user-id "zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj"}]
"https://status.app/cc/G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"
[:community-chat
{:chat-data
{:community-data
"G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM="
:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
"status-app://cc/G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"
[:community-chat
{:chat-data
{:community-data
"G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM="
: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"
[:community
{:community-data
"iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM="
:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
"https://status.app/c#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"
[:community
{:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
"status-app://c/iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"
[:community
@ -55,6 +81,10 @@
"iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM="
:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
"status-app://c#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"
[:community
{:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
"ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
[:ethereum {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"}]

View File

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

View File

@ -20,9 +20,9 @@
(is (nil? (get-in (links/handle-url {:db db} "some-url")
[:db :universal-links/url]))))
(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])
"https://status.app/u/statuse2e")))))))
"https://status.app/u#statuse2e")))))))
(deftest url-event-listener
(testing "the url is not nil"

View File

@ -10,7 +10,7 @@
(def links
{:private-chat "%s/p/%s"
:user "%s/u/%s"
:user "%s/u#%s"
:browse "%s/b/%s"})
(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-address #"^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-web3 "web3")

View File

@ -34,14 +34,14 @@
(zipmap (repeat nil))))
([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
[{:keys [input] :as contact}]
(let [trimmed-input (utils.string/safe-trim input)]
(->> {:id (if (empty? trimmed-input)
nil
(if-some [[_ id] (re-matches url-regex trimmed-input)]
(if-some [id (last (re-matches url-regex trimmed-input))]
id
trimmed-input))}
(merge contact))))
@ -175,8 +175,11 @@
(let [contact (get-in db [:contacts/new-identity])]
(when (= (:input contact) input)
(let [state (cond
(and (string? err) (string/includes? err "invalid public key"))
{: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"))
(string/includes? (:message err) "no such host")))
{:state :invalid :msg :t/lost-connection}
:else {:state :invalid})]
{:db (assoc db :contacts/new-identity (merge contact state))}))))

View File

@ -11,8 +11,9 @@
(def ckey "zQ3shWj4WaBdf2zYKCkXe6PHxDxNTzZyid1i75879Ue9cX9gA")
(def ens "esep")
(def ens-stateofus-eth (str ens ".stateofus.eth"))
(def link-ckey (str "https://status.app/u/" ckey))
(def link-ens (str "https://status.app/u/" ens))
(def link-ckey (str "https://status.app/u#" ckey))
(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)
@ -65,6 +66,11 @@
:id ckey
:type :compressed-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
:input link-ens

View File

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

View File

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

View File

@ -62,7 +62,7 @@
[]
(let [media-server-port (rf/sub [:mediaserver/port])
state (reagent/atom
{:url "https://join.status.im/status"
{:url "https://status.app/u#zQ34e1zlOdas0pKnvrweeedsasas12adjie8"
:size 250
:avatar :none
:profile-picture (resources/get-mock-image :user-picture-male5)

View File

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

View File

@ -43,11 +43,11 @@
(defn get-abbreviated-profile-url
"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
the last 10 characters of the compressed 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)
ellipsis "..."
public-key-size (count public-key)

View File

@ -22,22 +22,22 @@
(deftest test-get-abbreviated-profile-url
(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
"status.app/u/"
"status.app/u#"
"zQ3shPrnUhhR42JJn3QdhodGest8w8MjiH8hPaimrdYpzeFUa"))))
(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"
(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"
(is (nil? (utils.address/get-abbreviated-profile-url
"status.app/uwu/"
"status.app/uwu#"
"zQ3shPrnUhhR42JJn3QdhodGest8w8MjiH8hPaimrdYpzeFUa"))))
(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/" "1234")))))
(is (nil? (utils.address/get-abbreviated-profile-url "status.app/u#" "abc")))
(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 contact-images-action "/contactImages")
(def ^:const generate-qr-action "/GenerateQRCode")
(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 "https://status.app/u#")
(def ^:const status-profile-base-url-without-https "status.app/u#")
(defn get-font-file-ready
"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>",
"owner": "status-im",
"repo": "status-go",
"version": "v0.171.7",
"commit-sha1": "74396b461df0c18593262a67c9fd79d706287f7a",
"src-sha256": "1d46lav3g6m1f6ifpypjlsp2qm82c6yk4478awb8f68azpdkvcg5"
"version": "v0.171.8",
"commit-sha1": "678fc03b376e02df7142e89f2c626e3ba1c03807",
"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.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.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()

View File

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