Support join.status.im links for adding a contact (#14964)

* Support join.status.im links for adding a contact (#14814)

* refactor tests, add caret to regex
This commit is contained in:
erikseppanen 2023-02-06 17:23:34 -05:00 committed by GitHub
parent e61bd769a8
commit 7315dc8914
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 243 additions and 205 deletions

View File

@ -1,5 +1,5 @@
(ns status-im.integration-test
(:require [cljs.test :refer [deftest is run-tests]]
(:require [cljs.test :refer [deftest is]]
[clojure.string :as string]
[day8.re-frame.test :as rf-test]
[re-frame.core :as rf]
@ -10,7 +10,7 @@
[status-im.transport.core :as transport]
[status-im.utils.test :as utils.test]
status-im2.navigation.core
status-im2.subs.root ;;so integration tests can run independently
status-im2.subs.root ; so integration tests can run independently
[taoensso.timbre :as log]
[utils.security.core :as security]))
@ -107,9 +107,7 @@
[::transport/messenger-started]
(assert-messenger-started)
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not in
; an
; inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout)))))))
(deftest create-community-test
@ -156,9 +154,7 @@
[:wallet.accounts/account-stored]
(assert-new-account-created) ; assert account was created
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not in
; an
; inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))
(deftest back-up-seed-phrase-test
@ -191,9 +187,7 @@
[:my-profile/finish-success]
(is (nil? @(rf/subscribe [:mnemonic]))) ; assert seed phrase has been removed
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not
; in
; an inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout)))))))))
(def multiaccount-name "Narrow Frail Lemming")
@ -226,9 +220,7 @@
[::transport/messenger-started]
(assert-messenger-started)
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not in
; an
; inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))
(def chat-id
@ -254,9 +246,7 @@
(rf/dispatch-sync [:chat/navigate-to-chat chat-id])
(is (= chat-id @(rf/subscribe [:chats/current-chat-id])))
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not in
; an
; inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))
(deftest delete-chat-test
@ -282,9 +272,7 @@
(rf/dispatch-sync [:chat.ui/show-remove-confirmation chat-id])
(rf/dispatch-sync [:chat.ui/remove-chat chat-id])
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not
; in an
; inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))
(deftest mute-chat-test
@ -316,10 +304,41 @@
[:chat/mute-successfully]
(is (not @(rf/subscribe [:chats/muted chat-id])))
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is
; not in
; an inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))))
(comment
(run-tests))
(deftest add-contact-test
(log/info "========= add-contact-test ==================")
(let
[compressed-key "zQ3shWj4WaBdf2zYKCkXe6PHxDxNTzZyid1i75879Ue9cX9gA"
public-key
"0x048a6773339d11ccf5fd81677b7e54daeec544a1287bd92b725047ad6faa9a9b9f8ea86ed5a226d2a994f5f46d0b43321fd8de7b7997a166e67905c8c73cd37cea"
three-words-name "Rich Total Pondskater"]
(rf-test/run-test-async
(initialize-app!)
(rf-test/wait-for
[:setup/initialize-view]
(generate-and-derive-addresses!)
(rf-test/wait-for
[:multiaccount-generate-and-derive-addresses-success]
(assert-multiaccount-loaded)
(create-multiaccount!)
(rf-test/wait-for
[::transport/messenger-started]
(assert-messenger-started)
;; search for contact using compressed key
(rf/dispatch [:contacts/set-new-identity compressed-key])
(rf-test/wait-for
[:contacts/set-new-identity-success]
(let [new-identity @(rf/subscribe [:contacts/new-identity])]
(is (= public-key (:public-key new-identity)))
(is (= :valid (:state new-identity))))
;; click 'view profile' button
(rf/dispatch [:chat.ui/show-profile public-key])
(rf-test/wait-for
[:contacts/contact-built]
(let [contact @(rf/subscribe [:contacts/current-contact])]
(is (= three-words-name (:three-words-name (:names contact)))))
(logout!)
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))))

View File

@ -27,101 +27,102 @@
(def status
(clj->js
{:openAccounts (fn [callback]
(callback
(.openAccounts
native-status
test-dir)))
:multiAccountStoreDerived (fn [json callback]
(callback (.multiAccountStoreDerivedAccounts
native-status
json)))
{:openAccounts
(fn [callback]
(callback (.openAccounts native-status test-dir)))
:multiAccountStoreDerived
(fn [json callback]
(callback (.multiAccountStoreDerivedAccounts native-status json)))
:clearCookies identity
:clearStorageAPIs identity
:setBlankPreviewFlag identity
:callPrivateRPC (fn [payload callback]
(callback
(.callPrivateRPC
native-status
payload)))
:saveAccountAndLogin (fn [multiaccount-data password settings config
accounts-data]
(.saveAccountAndLogin
native-status
multiaccount-data
password
settings
config
accounts-data))
:logout (fn []
(.logout native-status))
:generateAlias (fn [seed]
(.generateAlias native-status seed))
:generateAliasAndIdenticonAsync (fn [seed callback]
(let [generated-identicon (.identicon native-status seed)
generated-alias (.generateAlias native-status
seed)]
(callback generated-alias generated-identicon)))
:multiAccountGenerateAndDeriveAddresses (fn [json callback]
(callback
(.multiAccountGenerateAndDeriveAddresses
native-status
json)))
:multiAccountImportMnemonic (fn [json callback]
(callback
(.multiAccountImportMnemonic
native-status
json)))
:multiAccountLoadAccount (fn [json callback]
(callback
(.multiAccountLoadAccount
native-status
json)))
:multiAccountDeriveAddresses (fn [json callback]
(callback
(.multiAccountDeriveAddresses
native-status
json)))
:initKeystore (fn [key-uid callback]
(callback
(.initKeystore
native-status
(str test-dir "/keystore/" key-uid))))
:identicon (fn [pk]
(.identicon native-status pk))
:callPrivateRPC
(fn [payload callback]
(callback (.callPrivateRPC native-status payload)))
:encodeTransfer (fn [to-norm amount-hex]
(.encodeTransfer native-status to-norm amount-hex))
:saveAccountAndLogin
(fn [multiaccount-data password settings config accounts-data]
(.saveAccountAndLogin native-status multiaccount-data password settings config accounts-data))
:encodeFunctionCall (fn [method params-json]
(.encodeFunctionCall native-status method params-json))
:logout
(fn [] (.logout native-status))
:decodeParameters (fn [decode-param-json]
(.decodeParameters native-status decode-param-json))
:generateAlias
(fn [seed] (.generateAlias native-status seed))
:hexToNumber (fn [hex]
(.hexToNumber native-status hex))
:generateAliasAndIdenticonAsync
(fn [seed callback]
(let [generated-identicon (.identicon native-status seed)
generated-alias (.generateAlias native-status seed)]
(callback generated-alias generated-identicon)))
:numberToHex (fn [num-str]
(.numberToHex native-status num-str))
:multiAccountGenerateAndDeriveAddresses
(fn [json callback]
(callback (.multiAccountGenerateAndDeriveAddresses native-status json)))
:checkAddressChecksum (fn [address]
(.checkAddressChecksum native-status address))
:multiAccountImportMnemonic
(fn [json callback]
(callback (.multiAccountImportMnemonic native-status json)))
:sha3 (fn [str]
(.sha3 native-status str))
:multiAccountLoadAccount
(fn [json callback]
(callback (.multiAccountLoadAccount native-status json)))
:toChecksumAddress (fn [address]
(.toChecksumAddress native-status address))
:multiAccountDeriveAddresses
(fn [json callback]
(callback (.multiAccountDeriveAddresses native-status json)))
:isAddress (fn [address]
(.isAddress native-status address))
:multiformatDeserializePublicKey
(fn [public-key deserialization-key callback]
(callback (.multiformatDeserializePublicKey
native-status
public-key
deserialization-key)))
:validateMnemonic (fn [json callback]
(callback
(.validateMnemonic
native-status
json)))
:initKeystore
(fn [key-uid callback]
(callback (.initKeystore native-status
(str test-dir "/keystore/" key-uid))))
:identicon
(fn [pk] (.identicon native-status pk))
:encodeTransfer
(fn [to-norm amount-hex]
(.encodeTransfer native-status to-norm amount-hex))
:encodeFunctionCall
(fn [method params-json]
(.encodeFunctionCall native-status method params-json))
:decodeParameters
(fn [decode-param-json]
(.decodeParameters native-status decode-param-json))
:hexToNumber
(fn [hex] (.hexToNumber native-status hex))
:numberToHex
(fn [num-str] (.numberToHex native-status num-str))
:checkAddressChecksum
(fn [address] (.checkAddressChecksum native-status address))
:sha3
(fn [str] (.sha3 native-status str))
:toChecksumAddress
(fn [address] (.toChecksumAddress native-status address))
:isAddress
(fn [address] (.isAddress native-status address))
:validateMnemonic
(fn [json callback] (callback (.validateMnemonic native-status json)))
:startLocalNotifications identity}))

View File

@ -9,11 +9,6 @@
[status-im2.utils.validators :as validators]
[status-im.utils.utils :as utils]))
(re-frame/reg-fx
:contacts/resolve-public-key-from-ens-name
(fn [{:keys [chain-id ens-name on-success on-error]}]
(ens/pubkey chain-id ens-name on-success on-error)))
(re-frame/reg-fx
:contacts/decompress-public-key
(fn [{:keys [public-key on-success on-error]}]
@ -23,50 +18,73 @@
(let [{:keys [error]} (types/json->clj resp)]
(if error
(on-error error)
(on-success
(str "0x" (subs resp 5)))))))))
(on-success (str "0x" (subs resp 5)))))))))
(re-frame/reg-fx
:contacts/resolve-public-key-from-ens-name
(fn [{:keys [chain-id ens-name on-success on-error]}]
(ens/pubkey chain-id ens-name on-success on-error)))
(defn fx-callbacks
[input ens-name]
{:on-success (fn [pubkey]
(rf/dispatch
[:contacts/set-new-identity-success
input ens-name pubkey]))
:on-error (fn [err]
(rf/dispatch
[:contacts/set-new-identity-error err input]))})
(defn identify-type
[input]
(let [regex #"^https?://join.status.im/u/(.+)"
id (as-> (utils/safe-trim input) $
(if-some [[_ match] (re-matches regex $)]
match
$)
(if (empty? $) nil $))
public-key? (validators/valid-public-key? id)
compressed-key? (validators/valid-compressed-key? id)
type (cond (empty? id) :empty
public-key? :public-key
compressed-key? :compressed-key
:else :ens-name)
ens-name (when (= type :ens-name)
(stateofus/ens-name-parse id))]
{:input input
:id id
:type type
:ens-name ens-name}))
(rf/defn set-new-identity
{:events [:contacts/set-new-identity]}
[{:keys [db]} input]
(let [input (utils/safe-trim input)
public-key? (validators/valid-public-key? input)
compressed-key? (validators/valid-compressed-key? input)
ens-name (if compressed-key? nil (stateofus/ens-name-parse input))
on-success (fn [pubkey]
(rf/dispatch
[:contacts/set-new-identity-success
input ens-name pubkey]))
on-error (fn [err]
(rf/dispatch
[:contacts/set-new-identity-error err input]))]
(cond
(empty? input) {:db (dissoc db :contacts/new-identity)}
public-key? {:db (assoc db
:contacts/new-identity
{:input input
:public-key input
:ens-name nil
:state :error
:error :uncompressed-key})}
:else
(cond->
{:db (assoc db
:contacts/new-identity
{:input input
:public-key nil
:ens-name nil
:state :searching
:error nil})}
compressed-key? (assoc :contacts/decompress-public-key
{:public-key input
:on-success on-success
:on-error on-error})
(not compressed-key?) (assoc :contacts/resolve-public-key-from-ens-name
{:chain-id (ethereum/chain-id db)
:ens-name ens-name
:on-success on-success
:on-error on-error})))))
(let [{:keys [input id type ens-name]} (identify-type input)]
(case type
:empty {:db (dissoc db :contacts/new-identity)}
:public-key {:db (assoc db
:contacts/new-identity
{:input input
:public-key id
:state :error
:error :uncompressed-key})}
:compressed-key {:db
(assoc db
:contacts/new-identity
{:input input
:state :searching})
:contacts/decompress-public-key
(merge {:public-key id}
(fx-callbacks id ens-name))}
:ens-name {:db
(assoc db
:contacts/new-identity
{:input input
:state :searching})
:contacts/resolve-public-key-from-ens-name
(merge {:chain-id (ethereum/chain-id db)
:ens-name ens-name}
(fx-callbacks id ens-name))})))
(rf/defn set-new-identity-success
{:events [:contacts/set-new-identity-success]}
@ -76,19 +94,16 @@
{:input input
:public-key pubkey
:ens-name ens-name
:state :valid
:error nil})})
:state :valid})})
(rf/defn set-new-identity-error
{:events [:contacts/set-new-identity-error]}
[{:keys [db]} error input]
{:db (assoc db
:contacts/new-identity
{:input input
:public-key nil
:ens-name nil
:state :error
:error :invalid})})
{:input input
:state :error
:error :invalid})})
(rf/defn clear-new-identity
{:events [:contacts/clear-new-identity :contacts/new-chat-focus]}

View File

@ -1,53 +1,56 @@
(ns status-im2.contexts.add-new-contact.events-test
(:require [cljs.test :refer-macros [deftest is]]
(:require [cljs.test :refer-macros [deftest is are]]
[status-im2.contexts.add-new-contact.events :as core]))
(def init-db
{:networks/current-network "mainnet_rpc"
:networks/networks {"mainnet_rpc"
{:id "mainnet_rpc"
:config {:NetworkId 1}}}})
(def ukey
"0x045596a7ff87da36860a84b0908191ce60a504afc94aac93c1abd774f182967ce694f1bf2d8773cd59f4dd0863e951f9b7f7351c5516291a0fceb73f8c392a0e88")
(def ckey "zQ3shWj4WaBdf2zYKCkXe6PHxDxNTzZyid1i75879Ue9cX9gA")
(def ens "esep")
(def ens-stateofus-eth (str ens ".stateofus.eth"))
(def link-ckey (str "https://join.status.im/u/" ckey))
(def link-ens (str "https://join.status.im/u/" ens))
(defn search-db
[input]
{:contacts/new-identity {:input input
:public-key nil
:ens-name nil
:state :searching
:error nil}})
(deftest identify-type-test
(are [input expected] (= (core/identify-type input) expected)
"" {:input ""
:id nil
:type :empty
:ens-name nil}
(deftest search-empty-string
(let [input ""
expected {:db init-db}
actual (core/set-new-identity {:db init-db} input)]
(is (= actual expected))))
ukey {:input ukey
:id ukey
:type :public-key
:ens-name nil}
(deftest search-ens
(let [input "esep"
clean (fn [db]
(-> db
(assoc-in [:contacts/resolve-public-key-from-ens-name :on-success] nil)
(assoc-in [:contacts/resolve-public-key-from-ens-name :on-error] nil)))
expected {:db (merge init-db (search-db input))
:contacts/resolve-public-key-from-ens-name
{:chain-id 1
:ens-name (str input ".stateofus.eth")
:on-success nil
:on-error nil}}
actual (core/set-new-identity {:db init-db} input)]
(is (= (clean actual) expected))))
ens {:input ens
:id ens
:type :ens-name
:ens-name ens-stateofus-eth}
(deftest search-compressed-key
(let [input "zQ3shWj4WaBdf2zYKCkXe6PHxDxNTzZyid1i75879Ue9cX9gA"
clean (fn [db]
(-> db
(assoc-in [:contacts/decompress-public-key :on-success] nil)
(assoc-in [:contacts/decompress-public-key :on-error] nil)))
expected {:db (merge init-db (search-db input))
:contacts/decompress-public-key
{:public-key input
:on-success nil
:on-error nil}}
actual (core/set-new-identity {:db init-db} input)]
(is (= (clean actual) expected))))
ckey {:input ckey
:id ckey
:type :compressed-key
:ens-name nil}
link-ckey {:input link-ckey
:id ckey
:type :compressed-key
:ens-name nil}
link-ens {:input link-ens
:id ens
:type :ens-name
:ens-name ens-stateofus-eth}))
(deftest search-empty-string-test
(is (= (core/set-new-identity {:db {:contacts/new-identity :foo}} "")
{:db {}})))
(deftest search-uncompressed-key-test
(is (= (core/set-new-identity {:db {}} ukey)
{:db {:contacts/new-identity
{:input ukey
:public-key ukey
:state :error
:error :uncompressed-key}}})))

View File

@ -1875,7 +1875,7 @@
"identity-verification-request": "Identity verification",
"identity-verification-request-sent": "asks",
"type-something": "Type something",
"type-some-chat-key": "0x123abc",
"type-some-chat-key": "zQ3abc...123",
"your-answer": "Your answer",
"membership": "Membership",
"jump-to": "Jump to",