Enable pairing & contact recovery
This PR enables pairing outside of dev-mode and contact-recovery, which is useful in the case a new device is added or re-installed. Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
parent
ac758f5348
commit
13b04f17eb
|
@ -1,42 +1,66 @@
|
|||
(ns status-im.contact-recovery.core
|
||||
"This namespace handles the case where a user has just recovered their account
|
||||
and is not able to decrypt messages, as the encryption is device-to-device.
|
||||
Upon receiving this message, an empty message is sent back carrying device information
|
||||
which will tell the other peer to target this device as well"
|
||||
(:require
|
||||
[status-im.i18n :as i18n]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.data-store.contact-recovery :as data-store.contact-recovery]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.accounts.db :as accounts.db]
|
||||
[status-im.contact.core :as models.contact]))
|
||||
|
||||
;; How long do we wait until we process a contact-recovery again?
|
||||
(def contact-recovery-interval-ms (* 6 60 60 1000))
|
||||
|
||||
(defn prompt-dismissed! [public-key]
|
||||
(re-frame/dispatch [:contact-recovery.ui/prompt-dismissed public-key]))
|
||||
|
||||
(defn prompt-accepted! [public-key]
|
||||
(re-frame/dispatch [:contact-recovery.ui/prompt-accepted public-key]))
|
||||
|
||||
(defn show-contact-recovery-fx
|
||||
"Check that a pop up for that given user is not already shown, if not proceed fetching from the db whether we should be showing it"
|
||||
[{:keys [db] :as cofx} public-key]
|
||||
(let [my-public-key (accounts.db/current-public-key cofx)
|
||||
pfs? (get-in db [:account/account :settings :pfs?])]
|
||||
(defn handle-contact-recovery-fx
|
||||
"Check that a contact-recovery for the given user is not already in process, if not
|
||||
fetch from db and check"
|
||||
[{:keys [db now] :as cofx} public-key]
|
||||
(let [my-public-key (accounts.db/current-public-key cofx)]
|
||||
(when (and (not= public-key my-public-key)
|
||||
pfs?
|
||||
(not (get-in db [:contact-recovery/pop-up public-key])))
|
||||
{:db (update db :contact-recovery/pop-up conj public-key)
|
||||
:contact-recovery/show-contact-recovery-message public-key})))
|
||||
:contact-recovery/handle-recovery [now public-key]})))
|
||||
|
||||
(fx/defn prompt-dismissed [{:keys [db]} public-key]
|
||||
{:db (update db :contact-recovery/pop-up disj public-key)})
|
||||
|
||||
(defn show-contact-recovery-message? [public-key]
|
||||
(not (data-store.contact-recovery/get-contact-recovery-by-id public-key)))
|
||||
(defn notified-recently?
|
||||
"We don't want to notify the user each time, so we wait an interval before
|
||||
sending a message again"
|
||||
[now public-key]
|
||||
(let [{:keys [timestamp]} (data-store.contact-recovery/get-contact-recovery-by-id public-key)]
|
||||
(and timestamp
|
||||
(< contact-recovery-interval-ms (- now timestamp)))))
|
||||
|
||||
(defn show-contact-recovery-message-fx [public-key]
|
||||
(when (show-contact-recovery-message? public-key)
|
||||
(re-frame/dispatch [:contact-recovery.callback/show-contact-recovery-message public-key])))
|
||||
(defn handle-recovery-fx [now public-key]
|
||||
(when-not (notified-recently? now public-key)
|
||||
(re-frame/dispatch [:contact-recovery.callback/handle-recovery public-key])))
|
||||
|
||||
(fx/defn notify-user
|
||||
"Send an empty message to the user, which will carry device information"
|
||||
[cofx public-key]
|
||||
(let [{:keys [web3]} (:db cofx)
|
||||
current-public-key (accounts.db/current-public-key cofx)]
|
||||
{:shh/send-direct-message
|
||||
[{:web3 web3
|
||||
:src current-public-key
|
||||
:dst public-key
|
||||
:payload ""}]}))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:contact-recovery/show-contact-recovery-message
|
||||
show-contact-recovery-message-fx)
|
||||
:contact-recovery/handle-recovery
|
||||
(fn [[now public-key]]
|
||||
(handle-recovery-fx now public-key)))
|
||||
|
||||
(fx/defn save-contact-recovery [{:keys [now]} public-key]
|
||||
{:data-store/tx [(data-store.contact-recovery/save-contact-recovery-tx {:timestamp now
|
||||
|
@ -46,18 +70,18 @@
|
|||
(fx/merge
|
||||
cofx
|
||||
(prompt-dismissed public-key)
|
||||
(save-contact-recovery public-key)))
|
||||
(save-contact-recovery public-key)
|
||||
(notify-user public-key)))
|
||||
|
||||
(fx/defn show-contact-recovery-message [{:keys [db] :as cofx} public-key]
|
||||
(let [pfs? (get-in db [:account/account :settings :pfs?])
|
||||
contact (models.contact/build-contact cofx public-key)
|
||||
(fx/defn handle-recovery [{:keys [db] :as cofx} public-key]
|
||||
(let [contact (models.contact/build-contact cofx public-key)
|
||||
popup {:ui/show-confirmation {:title (i18n/label :t/contact-recovery-title {:name (:name contact)})
|
||||
:content (i18n/label :t/contact-recovery-content {:name (:name contact)})
|
||||
:confirm-button-text (i18n/label :t/add-to-contacts)
|
||||
:confirm-button-text (i18n/label :t/notify)
|
||||
:cancel-button-text (i18n/label :t/cancel)
|
||||
:on-cancel #(prompt-dismissed! public-key)
|
||||
:on-accept #(prompt-accepted! public-key)}}]
|
||||
|
||||
(when pfs?
|
||||
(fx/merge cofx
|
||||
popup))))
|
||||
(if config/show-contact-recovery-pop-up?
|
||||
(fx/merge cofx popup)
|
||||
(prompt-accepted cofx public-key))))
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
(:require [status-im.data-store.realm.core :as core]))
|
||||
|
||||
(defn get-contact-recovery-by-id [public-key]
|
||||
(core/single (core/get-by-field @core/account-realm :contact-recovery :id public-key)))
|
||||
(-> @core/account-realm
|
||||
(core/get-by-field :contact-recovery :id public-key)
|
||||
(core/single-clj :contact-recovery)))
|
||||
|
||||
(defn save-contact-recovery-tx
|
||||
"Returns tx function for saving a contact-recovery"
|
||||
|
|
|
@ -1568,10 +1568,7 @@
|
|||
:contact-recovery.ui/prompt-accepted
|
||||
[(re-frame/inject-cofx :random-id-generator)]
|
||||
(fn [cofx [_ public-key]]
|
||||
(fx/merge
|
||||
cofx
|
||||
(contact/add-contact public-key)
|
||||
(contact-recovery/prompt-accepted public-key))))
|
||||
(contact-recovery/prompt-accepted cofx public-key)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:contact-recovery.ui/prompt-dismissed
|
||||
|
@ -1579,10 +1576,10 @@
|
|||
(contact-recovery/prompt-dismissed cofx public-key)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:contact-recovery.callback/show-contact-recovery-message
|
||||
:contact-recovery.callback/handle-recovery
|
||||
[(re-frame/inject-cofx :random-id-generator)]
|
||||
(fn [cofx [_ public-key]]
|
||||
(contact-recovery/show-contact-recovery-message cofx public-key)))
|
||||
(contact-recovery/handle-recovery cofx public-key)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:stickers/load-sticker-pack-success
|
||||
|
@ -1609,4 +1606,4 @@
|
|||
(handlers/register-handler-fx
|
||||
:stickers/select-pack
|
||||
(fn [{:keys [db]} [_ id]]
|
||||
{:db (assoc db :stickers/selected-pack id)}))
|
||||
{:db (assoc db :stickers/selected-pack id)}))
|
||||
|
|
|
@ -86,21 +86,19 @@
|
|||
:data-store/tx [(data-store.installations/save updated-installation)]}))
|
||||
|
||||
(defn handle-bundles-added [{:keys [db] :as cofx} bundle]
|
||||
(let [dev-mode? (get-in db [:account/account :dev-mode?])]
|
||||
(when (config/pairing-enabled? dev-mode?)
|
||||
(let [installation-id (:installationID bundle)
|
||||
new-installation {:installation-id installation-id
|
||||
:has-bundle? true}]
|
||||
(when
|
||||
(and (= (:identity bundle)
|
||||
(accounts.db/current-public-key cofx))
|
||||
(not= (get-in db [:account/account :installation-id]) installation-id)
|
||||
(not (get-in db [:pairing/installations installation-id])))
|
||||
(fx/merge cofx
|
||||
(upsert-installation new-installation)
|
||||
#(when-not (or (get-in % [:db :pairing/prompt-user-pop-up])
|
||||
(= :installations (:view-id db)))
|
||||
(prompt-user-on-new-installation %))))))))
|
||||
(let [installation-id (:installationID bundle)
|
||||
new-installation {:installation-id installation-id
|
||||
:has-bundle? true}]
|
||||
(when
|
||||
(and (= (:identity bundle)
|
||||
(accounts.db/current-public-key cofx))
|
||||
(not= (get-in db [:account/account :installation-id]) installation-id)
|
||||
(not (get-in db [:pairing/installations installation-id])))
|
||||
(fx/merge cofx
|
||||
(upsert-installation new-installation)
|
||||
#(when-not (or (get-in % [:db :pairing/prompt-user-pop-up])
|
||||
(= :installations (:view-id db)))
|
||||
(prompt-user-on-new-installation %))))))
|
||||
|
||||
(defn sync-installation-account-message [{:keys [db]}]
|
||||
(let [account (-> db
|
||||
|
@ -191,18 +189,15 @@
|
|||
(fx/defn send-sync-installation [cofx payload]
|
||||
(let [{:keys [web3]} (:db cofx)
|
||||
current-public-key (accounts.db/current-public-key cofx)]
|
||||
|
||||
{:shh/send-direct-message
|
||||
[{:web3 web3
|
||||
:src current-public-key
|
||||
:dst current-public-key
|
||||
[{:web3 web3
|
||||
:src current-public-key
|
||||
:dst current-public-key
|
||||
:payload payload}]}))
|
||||
|
||||
(fx/defn send-installation-message-fx [cofx payload]
|
||||
(let [dev-mode? (get-in cofx [:db :account/account :dev-mode?])]
|
||||
(when (and (config/pairing-enabled? dev-mode?)
|
||||
(has-paired-installations? cofx))
|
||||
(protocol/send payload nil cofx))))
|
||||
(when (has-paired-installations? cofx)
|
||||
(protocol/send payload nil cofx)))
|
||||
|
||||
(fx/defn sync-public-chat [cofx chat-id]
|
||||
(let [sync-message (transport.pairing/SyncInstallation. {} {} {:public? true
|
||||
|
@ -230,30 +225,26 @@
|
|||
contacts))
|
||||
|
||||
(defn handle-sync-installation [{:keys [db] :as cofx} {:keys [contacts account chat]} sender]
|
||||
(let [dev-mode? (get-in db [:account/account :dev-mode?])]
|
||||
(when (and (config/pairing-enabled? dev-mode?)
|
||||
(= sender (accounts.db/current-public-key cofx)))
|
||||
(let [new-contacts (merge-contacts (:contacts/contacts db) (ensure-photo-path contacts))
|
||||
new-account (merge-account (:account/account db) account)]
|
||||
(fx/merge cofx
|
||||
{:db (assoc db
|
||||
:contacts/contacts new-contacts
|
||||
:account/account new-account)
|
||||
:data-store/base-tx [(data-store.accounts/save-account-tx new-account)]
|
||||
:data-store/tx [(data-store.contacts/save-contacts-tx (vals new-contacts))]}
|
||||
#(when (:public? chat)
|
||||
(models.chat/start-public-chat % (:chat-id chat) {:dont-navigate? true})))))))
|
||||
(when (= sender (accounts.db/current-public-key cofx))
|
||||
(let [new-contacts (merge-contacts (:contacts/contacts db) (ensure-photo-path contacts))
|
||||
new-account (merge-account (:account/account db) account)]
|
||||
(fx/merge cofx
|
||||
{:db (assoc db
|
||||
:contacts/contacts new-contacts
|
||||
:account/account new-account)
|
||||
:data-store/base-tx [(data-store.accounts/save-account-tx new-account)]
|
||||
:data-store/tx [(data-store.contacts/save-contacts-tx (vals new-contacts))]}
|
||||
#(when (:public? chat)
|
||||
(models.chat/start-public-chat % (:chat-id chat) {:dont-navigate? true}))))))
|
||||
|
||||
(defn handle-pair-installation [{:keys [db] :as cofx} {:keys [name installation-id device-type]} timestamp sender]
|
||||
(let [dev-mode? (get-in db [:account/account :dev-mode?])]
|
||||
(when (and (config/pairing-enabled? dev-mode?)
|
||||
(= sender (accounts.db/current-public-key cofx))
|
||||
(not= (get-in db [:account/account :installation-id]) installation-id))
|
||||
(let [installation {:installation-id installation-id
|
||||
:name name
|
||||
:device-type device-type
|
||||
:last-paired timestamp}]
|
||||
(upsert-installation cofx installation)))))
|
||||
(when (and (= sender (accounts.db/current-public-key cofx))
|
||||
(not= (get-in db [:account/account :installation-id]) installation-id))
|
||||
(let [installation {:installation-id installation-id
|
||||
:name name
|
||||
:device-type device-type
|
||||
:last-paired timestamp}]
|
||||
(upsert-installation cofx installation))))
|
||||
|
||||
(fx/defn set-name [{:keys [db] :as cofx} installation-name]
|
||||
(let [new-account (assoc (get-in cofx [:db :account/account]) :installation-name installation-name)]
|
||||
|
|
|
@ -71,6 +71,6 @@
|
|||
"mailserver.request.completed" (mailserver/handle-request-completed cofx event)
|
||||
"mailserver.request.expired" (when (accounts.db/logged-in? cofx)
|
||||
(mailserver/resend-request cofx {:request-id (:hash event)}))
|
||||
"messages.decrypt.failed" (contact-recovery/show-contact-recovery-fx cofx (:sender event))
|
||||
"messages.decrypt.failed" (contact-recovery/handle-contact-recovery-fx cofx (:sender event))
|
||||
"discovery.summary" (summary cofx event)
|
||||
(log/debug "Event " type " not handled"))))
|
||||
|
|
|
@ -90,8 +90,7 @@
|
|||
(defrecord Message [content content-type message-type clock-value timestamp]
|
||||
StatusMessage
|
||||
(send [this chat-id {:keys [message-id] :as cofx}]
|
||||
(let [dev-mode? (get-in cofx [:db :account/account :dev-mode?])
|
||||
current-public-key (accounts.db/current-public-key cofx)
|
||||
(let [current-public-key (accounts.db/current-public-key cofx)
|
||||
params {:chat-id chat-id
|
||||
:payload this
|
||||
:success-event [:transport/message-sent
|
||||
|
@ -104,8 +103,7 @@
|
|||
|
||||
:user-message
|
||||
(fx/merge cofx
|
||||
#(when (config/pairing-enabled? dev-mode?)
|
||||
(send-direct-message % current-public-key nil this))
|
||||
(send-direct-message current-public-key nil this)
|
||||
(send-with-pubkey params)))))
|
||||
(receive [this chat-id signature _ cofx]
|
||||
{:chat-received-message/add-fx
|
||||
|
|
|
@ -203,11 +203,10 @@
|
|||
installation-id [:pairing/installation-id]
|
||||
installation-name [:pairing/installation-name]]
|
||||
[react/scroll-view
|
||||
(when (config/pairing-enabled? true)
|
||||
(installations-section
|
||||
installation-id
|
||||
installation-name
|
||||
installations))]))
|
||||
(installations-section
|
||||
installation-id
|
||||
installation-name
|
||||
installations)]))
|
||||
|
||||
(views/defview backup-recovery-phrase []
|
||||
[profile.recovery/backup-seed])
|
||||
|
|
|
@ -140,8 +140,8 @@
|
|||
(if utils.platform/ios?
|
||||
;; On IOS switches seems to be broken, they take up value of dev-mode? (so if dev mode is on they all show to be on).
|
||||
;; Replacing therefore with checkbox until I have more time to investigate
|
||||
(checkbox.views/plain-checkbox {:checked? enabled?
|
||||
:on-value-change (partial toggle-enabled! installation-id enabled?)})
|
||||
(checkbox.views/checkbox {:checked? enabled?
|
||||
:on-value-change (partial toggle-enabled! installation-id enabled?)})
|
||||
[react/switch {:on-tint-color colors/blue
|
||||
:value enabled?
|
||||
:on-value-change (partial toggle-enabled! installation-id enabled?)}])]]])
|
||||
|
|
|
@ -127,13 +127,11 @@
|
|||
{:label-kw :t/backup-your-recovery-phrase
|
||||
:action-fn #(re-frame/dispatch [:navigate-to :backup-seed])
|
||||
:icon-content [components.common/counter {:size 22} 1]}])
|
||||
(when (config/pairing-enabled? dev-mode?)
|
||||
[profile.components/settings-item-separator])
|
||||
(when (config/pairing-enabled? dev-mode?)
|
||||
[profile.components/settings-item
|
||||
{:label-kw :t/devices
|
||||
:action-fn #(re-frame/dispatch [:navigate-to :installations])
|
||||
:accessibility-label :pairing-settings-button}])
|
||||
[profile.components/settings-item-separator]
|
||||
[profile.components/settings-item
|
||||
{:label-kw :t/devices
|
||||
:action-fn #(re-frame/dispatch [:navigate-to :installations])
|
||||
:accessibility-label :pairing-settings-button}]
|
||||
[profile.components/settings-item-separator]
|
||||
[profile.components/settings-switch-item
|
||||
{:label-kw :t/web3-opt-in
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
(def bootnodes-settings-enabled? (enabled? (get-config :BOOTNODES_SETTINGS_ENABLED "1")))
|
||||
(def rpc-networks-only? (enabled? (get-config :RPC_NETWORKS_ONLY "1")))
|
||||
(def group-chats-publish-to-topic? (enabled? (get-config :GROUP_CHATS_PUBLISH_TO_TOPIC "0")))
|
||||
(defn pairing-enabled? [dev-mode?]
|
||||
(and (enabled? (get-config :PAIRING_ENABLED "0"))
|
||||
(or dev-mode? platform/desktop?)))
|
||||
(def show-contact-recovery-pop-up? (enabled? (get-config :SHOW_CONTACT_RECOVERY_POPUP)))
|
||||
(def mailserver-confirmations-enabled? (enabled? (get-config :MAILSERVER_CONFIRMATIONS_ENABLED)))
|
||||
(def mainnet-warning-enabled? (enabled? (get-config :MAINNET_WARNING_ENABLED 0)))
|
||||
(def pfs-encryption-enabled? (enabled? (get-config :PFS_ENCRYPTION_ENABLED "0")))
|
||||
|
|
|
@ -1,38 +1,29 @@
|
|||
(ns status-im.test.contact-recovery.core
|
||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.contact-recovery.core :as contact-recovery]))
|
||||
|
||||
(deftest show-contact-recovery-fx
|
||||
(let [public-key "pk"]
|
||||
(testing "pfs is not enabled"
|
||||
(testing "no pop up is displayed"
|
||||
(let [actual (contact-recovery/show-contact-recovery-fx {:db {:contact-recovery/pop-up #{}}} public-key)]
|
||||
(testing "it does nothing"
|
||||
(is (not (:db actual)))
|
||||
(is (not (:contact-recovery/show-contact-recovery-message actual)))))))
|
||||
(testing "no pop up is displayed"
|
||||
(let [cofx {:db {:contact-recovery/pop-up #{}
|
||||
(testing "no contact-recovery in place"
|
||||
(let [cofx {:now "now"
|
||||
:db {:contact-recovery/pop-up #{}
|
||||
:account/account {:settings {:pfs? true}}}}
|
||||
actual (contact-recovery/show-contact-recovery-fx cofx public-key)]
|
||||
actual (contact-recovery/handle-contact-recovery-fx cofx public-key)]
|
||||
(testing "it sets the pop up as displayed"
|
||||
(is (get-in actual [:db :contact-recovery/pop-up public-key])))
|
||||
(testing "it adds an fx for fetching the contact"
|
||||
(is (= public-key (:contact-recovery/show-contact-recovery-message actual))))))
|
||||
(testing "pop up is already displayed"
|
||||
(let [actual (contact-recovery/show-contact-recovery-fx {:db {:contact-recovery/pop-up #{public-key}}} public-key)]
|
||||
(is (= ["now" public-key] (:contact-recovery/handle-recovery actual))))))
|
||||
(testing "contact recovery is in place"
|
||||
(let [actual (contact-recovery/handle-contact-recovery-fx {:db {:contact-recovery/pop-up #{public-key}}} public-key)]
|
||||
(testing "it does nothing"
|
||||
(is (not (:db actual)))
|
||||
(is (not (:contact-recovery/show-contact-recovery-message actual))))))))
|
||||
|
||||
(deftest show-contact-recovery-message
|
||||
(let [public-key "pk"]
|
||||
(testing "pfs is enabled"
|
||||
(let [cofx {:db {:account/account {:settings {:pfs? true}}}}
|
||||
actual (contact-recovery/show-contact-recovery-message cofx public-key)]
|
||||
(with-redefs [config/show-contact-recovery-pop-up? true]
|
||||
(let [cofx {:db {}}
|
||||
actual (contact-recovery/handle-recovery cofx public-key)]
|
||||
(testing "it shows a pop up"
|
||||
(is (:ui/show-confirmation actual)))))
|
||||
(testing "pfs is not enabled"
|
||||
(let [cofx {:db {:account/account {:settings {}}}}
|
||||
actual (contact-recovery/show-contact-recovery-message cofx public-key)]
|
||||
(testing "it shows a pop up"
|
||||
(is (not (:ui/show-confirmation actual))))))))
|
||||
(is (:ui/show-confirmation actual)))))))
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
"syncing-disabled": "Syncing disabled",
|
||||
"sync-all-devices": "Sync all devices",
|
||||
"syncing-devices": "Syncing...",
|
||||
"notify": "Notify",
|
||||
"paired-devices": "Paired devices",
|
||||
"contact-recovery-title": "{{name}} has sent you a message",
|
||||
"contact-recovery-content": "{{name}} has sent you a message but did not include this device.\nThis might happen if you have more than 3 devices, you haven't paired your devices correctly or you just recovered your account.\nPlease make sure your devices are paired correctly and click Add to contacts to notify the user of this device.",
|
||||
"contact-recovery-content": "{{name}} has sent you a message but did not include this device.\nThis might happen if you have more than 3 devices, you haven't paired your devices correctly or you just recovered your account.\nPlease make sure your devices are paired correctly and click Notify to let the user know of this device.",
|
||||
"pairing-maximum-number-reached-title": "Max number of devices reached",
|
||||
"pairing-maximum-number-reached-content": "Please disable one of your devices before enabling a new one.",
|
||||
"pairing-new-installation-detected-title": "New device detected",
|
||||
|
|
Loading…
Reference in New Issue