Support universal link for ens name

Handle ens-name in qr reader

If user has an username generate link with it

Ensure no infinite recursion happens on qr scan event

Fix test for custom profile ens-name

Fix QR code read for ens-name

Extra check for ens name in QR code

Do not open unknown profile for bad ens name

Signed-off-by: Gheorghe Pinzaru <feross95@gmail.com>
This commit is contained in:
Gheorghe Pinzaru 2020-01-13 17:19:52 +03:00
parent 60af04ff06
commit 028543aa31
No known key found for this signature in database
GPG Key ID: C9A094959935A952
5 changed files with 72 additions and 32 deletions

View File

@ -1205,12 +1205,23 @@
:contact/qr-code-scanned :contact/qr-code-scanned
[(re-frame/inject-cofx :random-id-generator)] [(re-frame/inject-cofx :random-id-generator)]
(fn [{:keys [db] :as cofx} [_ contact-identity _]] (fn [{:keys [db] :as cofx} [_ contact-identity _]]
(let [validation-result (new-chat.db/validate-pub-key db contact-identity)] (let [public-key? (and (string? contact-identity)
(if (some? validation-result) (string/starts-with? contact-identity "0x"))
{:utils/show-popup {:title (i18n/label :t/unable-to-read-this-code) validation-result (new-chat.db/validate-pub-key db contact-identity)]
:content validation-result (cond
:on-dismiss #(re-frame/dispatch [:navigate-to-clean :home])}} (and public-key? (not (some? validation-result)))
(chat/start-chat cofx contact-identity {:navigation-reset? true}))))) (chat/start-chat cofx contact-identity {:navigation-reset? true})
(and (not public-key?) (string? contact-identity))
(let [chain (ethereum/chain-keyword db)]
{:resolve-public-key {:chain chain
:contact-identity contact-identity
:cb #(re-frame/dispatch [:contact/qr-code-scanned %])}})
:else
{:utils/show-popup {:title (i18n/label :t/unable-to-read-this-code)
:content validation-result
:on-dismiss #(re-frame/dispatch [:navigate-to-clean :home])}}))))
(handlers/register-handler-fx (handlers/register-handler-fx
:contact.ui/start-group-chat-pressed :contact.ui/start-group-chat-pressed

View File

@ -8,10 +8,19 @@
[status-im.utils.handlers :as handlers] [status-im.utils.handlers :as handlers]
[status-im.ethereum.stateofus :as stateofus])) [status-im.ethereum.stateofus :as stateofus]))
(defn- ens-name-parse [contact-identity]
(when (string? contact-identity)
(string/lower-case
(if (ens/is-valid-eth-name? contact-identity)
contact-identity
(stateofus/subdomain contact-identity)))))
(re-frame/reg-fx (re-frame/reg-fx
:resolve-public-key :resolve-public-key
(fn [{:keys [registry ens-name cb]}] (fn [{:keys [chain contact-identity cb]}]
(resolver/pubkey registry ens-name cb))) (let [registry (get ens/ens-registries chain)
ens-name (ens-name-parse contact-identity)]
(resolver/pubkey registry ens-name cb))))
(handlers/register-handler-fx (handlers/register-handler-fx
:new-chat/set-new-identity :new-chat/set-new-identity
@ -19,15 +28,12 @@
(let [is-public-key? (and (string? new-identity) (let [is-public-key? (and (string? new-identity)
(string/starts-with? new-identity "0x"))] (string/starts-with? new-identity "0x"))]
(merge {:db (assoc db (merge {:db (assoc db
:contacts/new-identity {:public-key new-identity :ens-name new-ens-name} :contacts/new-identity {:public-key new-identity
:ens-name (ens-name-parse new-ens-name)}
:contacts/new-identity-error (db/validate-pub-key db new-identity))} :contacts/new-identity-error (db/validate-pub-key db new-identity))}
(when (and (not is-public-key?) (when (and (not is-public-key?)
(ens/valid-eth-name-prefix? new-identity)) (ens/valid-eth-name-prefix? new-identity))
(let [chain (ethereum/chain-keyword db) (let [chain (ethereum/chain-keyword db)]
ens-name (string/lower-case {:resolve-public-key {:chain chain
(if (ens/is-valid-eth-name? new-identity) :contact-identity new-identity
new-identity :cb #(re-frame/dispatch [:new-chat/set-new-identity % new-identity])}}))))))
(stateofus/subdomain new-identity)))]
{:resolve-public-key {:registry (get ens/ens-registries chain)
:ens-name ens-name
:cb #(re-frame/dispatch [:new-chat/set-new-identity % ens-name])}}))))))

View File

@ -26,7 +26,7 @@
(views/defview share-chat-key [] (views/defview share-chat-key []
(views/letsubs [{:keys [address ens-name]} [:popover/popover] (views/letsubs [{:keys [address ens-name]} [:popover/popover]
width (reagent/atom nil)] width (reagent/atom nil)]
(let [link (universal-links/generate-link :user :external address)] (let [link (universal-links/generate-link :user :external (or ens-name address))]
[react/view {:on-layout #(reset! width (-> % .-nativeEvent .-layout .-width))} [react/view {:on-layout #(reset! width (-> % .-nativeEvent .-layout .-width))}
[react/view {:style {:padding-top 16 :padding-horizontal 16}} [react/view {:style {:padding-top 16 :padding-horizontal 16}}
(when @width (when @width
@ -42,12 +42,12 @@
:font-family "monospace"} :font-family "monospace"}
:accessibility-label :ens-username} :accessibility-label :ens-username}
ens-name]] ens-name]]
[react/view {:height 1 :margin-top 12 :margin-horizontal -16 [react/view {:height 1 :margin-top 12 :margin-horizontal -16
:background-color colors/gray-lighter}]]) :background-color colors/gray-lighter}]])
[copyable-text/copyable-text-view [copyable-text/copyable-text-view
{:label :t/chat-key {:label :t/chat-key
:container-style {:margin-top 12 :margin-bottom 4} :container-style {:margin-top 12 :margin-bottom 4}
:copied-text address} :copied-text address}
[react/text {:number-of-lines 1 [react/text {:number-of-lines 1
:ellipsize-mode :middle :ellipsize-mode :middle
:accessibility-label :chat-key :accessibility-label :chat-key

View File

@ -6,16 +6,15 @@
[status-im.multiaccounts.model :as multiaccounts.model] [status-im.multiaccounts.model :as multiaccounts.model]
[status-im.chat.models :as chat] [status-im.chat.models :as chat]
[status-im.constants :as constants] [status-im.constants :as constants]
[status-im.ethereum.eip681 :as eip681] [status-im.ethereum.ens :as ens]
[status-im.ethereum.core :as ethereum]
[status-im.pairing.core :as pairing] [status-im.pairing.core :as pairing]
[status-im.utils.security :as security] [status-im.utils.security :as security]
[status-im.ui.components.list-selection :as list-selection] [status-im.ui.components.list-selection :as list-selection]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.ui.screens.add-new.new-chat.db :as new-chat.db] [status-im.ui.screens.add-new.new-chat.db :as new-chat.db]
[status-im.ui.screens.navigation :as navigation] [status-im.ui.screens.navigation :as navigation]
[status-im.utils.config :as config]
[status-im.utils.fx :as fx] [status-im.utils.fx :as fx]
[status-im.utils.platform :as platform]
[taoensso.timbre :as log] [taoensso.timbre :as log]
[status-im.wallet.choose-recipient.core :as choose-recipient])) [status-im.wallet.choose-recipient.core :as choose-recipient]))
@ -73,11 +72,30 @@
(log/info "universal-links: handling public chat" public-chat) (log/info "universal-links: handling public chat" public-chat)
(chat/start-public-chat cofx public-chat {})) (chat/start-public-chat cofx public-chat {}))
(fx/defn handle-view-profile [{:keys [db] :as cofx} public-key] (fx/defn handle-view-profile
(log/info "universal-links: handling view profile" public-key) [{:keys [db] :as cofx} {:keys [public-key ens-name]}]
(if (new-chat.db/own-public-key? db public-key) (log/info "universal-links: handling view profile" (or ens-name public-key))
(cond
(and public-key (new-chat.db/own-public-key? db public-key))
(navigation/navigate-to-cofx cofx :my-profile nil) (navigation/navigate-to-cofx cofx :my-profile nil)
(navigation/navigate-to-cofx (assoc-in cofx [:db :contacts/identity] public-key) :profile nil)))
public-key
(navigation/navigate-to-cofx (assoc-in cofx [:db :contacts/identity] public-key) :profile nil)
ens-name
(let [chain (ethereum/chain-keyword db)]
{:resolve-public-key {:chain chain
:contact-identity ens-name
:cb (fn [pub-key]
(cond
(and pub-key (new-chat.db/own-public-key? db pub-key))
(re-frame/dispatch [:navigate-to :my-profile])
pub-key
(re-frame/dispatch [:chat.ui/show-profile pub-key])
:else
(log/info "universal-link: no pub-key for ens-name " ens-name)))}})))
(fx/defn handle-eip681 [cofx url] (fx/defn handle-eip681 [cofx url]
(fx/merge cofx (fx/merge cofx
@ -102,7 +120,11 @@
(handle-public-chat cofx (match-url url public-chat-regex)) (handle-public-chat cofx (match-url url public-chat-regex))
(spec/valid? :global/public-key (match-url url profile-regex)) (spec/valid? :global/public-key (match-url url profile-regex))
(handle-view-profile cofx (match-url url profile-regex)) (handle-view-profile cofx {:public-key (match-url url profile-regex)})
(or (ens/valid-eth-name-prefix? (match-url url profile-regex))
(ens/is-valid-eth-name? (match-url url profile-regex)))
(handle-view-profile cofx {:ens-name (match-url url profile-regex)})
(match-url url browse-regex) (match-url url browse-regex)
(handle-browse cofx (match-url url browse-regex)) (handle-browse cofx (match-url url browse-regex))

View File

@ -32,9 +32,10 @@
(testing "it loads the profile" (testing "it loads the profile"
(let [actual (links/handle-url {:db db} "status-im://user/0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073")] (let [actual (links/handle-url {:db db} "status-im://user/0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073")]
(is (= "0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073" (get-in actual [:db :contacts/identity])))))) (is (= "0x04fbce10971e1cd7253b98c7b7e54de3729ca57ce41a2bfb0d1c4e0a26f72c4b6913c3487fa1b4bb86125770f1743fb4459da05c1cbe31d938814cfaf36e252073" (get-in actual [:db :contacts/identity]))))))
(testing "if does nothing because the link is invalid" (testing "Handle a custom string as a an profile link with ens-name"
(is (= (links/handle-url {:db db} "status-im://user/CONTACTCODE") (is (= (get-in (links/handle-url {:db db} "status-im://user/CONTACTCODE")
nil))) [:resolve-public-key :contact-identity])
"CONTACTCODE")))
(testing "a not found url" (testing "a not found url"
(testing "it does nothing" (testing "it does nothing"
(is (nil? (links/handle-url {:db db} "status-im://not-existing"))))))))) (is (nil? (links/handle-url {:db db} "status-im://not-existing")))))))))