diff --git a/STATUS_GO_SHA256 b/STATUS_GO_SHA256 index 9484c62978c..4449fb0ae69 100644 --- a/STATUS_GO_SHA256 +++ b/STATUS_GO_SHA256 @@ -1,3 +1,3 @@ ## DO NOT EDIT THIS FILE BY HAND. USE `scripts/update-status-go.sh ` instead -0049i6znvl45hc651bqyzwgmzlv0fp40maggfjsrv13q5avd0g6d +1bhwwmypb64kf180kp634jwfppd3h6yda3qyh2icj3lz7y10pgvp diff --git a/STATUS_GO_VERSION b/STATUS_GO_VERSION index 6162c3d599e..1b0c69ee3b1 100644 --- a/STATUS_GO_VERSION +++ b/STATUS_GO_VERSION @@ -1,3 +1,3 @@ ## DO NOT EDIT THIS FILE BY HAND. USE `scripts/update-status-go.sh ` instead -v0.25.0-beta.1 +v0.27.0-beta.1 diff --git a/desktop_files/package.json.orig b/desktop_files/package.json.orig index 68da9b4c68e..c4c4a21bf09 100644 --- a/desktop_files/package.json.orig +++ b/desktop_files/package.json.orig @@ -98,7 +98,7 @@ "string_decoder": "0.10.31", "text-encoding": "^0.6.4", "url": "0.10.3", - "web3": "git+https://github.com/status-im/web3.js.git#0.20.2-status", + "web3": "git+https://github.com/status-im/web3.js.git#0.20.3-status.alpha.3", "web3-utils": "1.0.0-beta.36", "hi-base32": "0.5.0" }, diff --git a/desktop_files/yarn.lock b/desktop_files/yarn.lock index 9718b510ffa..6a762ef9265 100644 --- a/desktop_files/yarn.lock +++ b/desktop_files/yarn.lock @@ -7139,7 +7139,7 @@ react-native-invertible-scroll-view@1.1.0: react-native-scrollable-mixin "^1.0.1" "react-native-keychain@git+https://github.com/status-im/react-native-keychain.git#v.3.0.0-3-status": - version "3.0.0-rc.4" + version "3.0.0-rc.3" resolved "git+https://github.com/status-im/react-native-keychain.git#5895bafa11e734325eaaffd56dda8ca50bfc5275" "react-native-languages@git+https://github.com/status-im/react-native-languages.git#v0.1.1-status": @@ -7297,8 +7297,8 @@ react-native-udp@2.2.1: xcode "^1.0.0" xmldoc "^0.4.0" yargs "^9.0.0" - yeoman-environment "^1.2.7" - yeoman-generator "^0.20.3" + yeoman-environment "^2.3.4" + yeoman-generator "^3.2.0" react-navigation-deprecated-tab-navigator@1.3.0: version "1.3.0" @@ -9089,9 +9089,9 @@ web3-utils@1.0.0-beta.36: underscore "1.8.3" utf8 "2.1.1" -"web3@git+https://github.com/status-im/web3.js.git#0.20.2-status": +"web3@git+https://github.com/status-im/web3.js.git#0.20.3-status.alpha.3": version "0.20.1" - resolved "git+https://github.com/status-im/web3.js.git#958dbabff2c77615e23f5de678a6fae0b0d70147" + resolved "git+https://github.com/status-im/web3.js.git#29677754c8b87c55c828df2694e35b0b760dca5f" dependencies: bignumber.js "git+https://github.com/status-im/bignumber.js.git#v4.0.2-status" crypto-js "^3.1.4" diff --git a/externs.js b/externs.js index c2be1eefc8b..eff5fd929cf 100644 --- a/externs.js +++ b/externs.js @@ -260,6 +260,7 @@ var TopLevel = { "NavigationEvents" : function () {}, "newKeyPair" : function () {}, "newMessageFilter" : function () {}, + "newRawMessageFilter": function() {}, "newSymKey" : function () {}, "nfcIsEnabled" : function () {}, "nfcIsSupported" : function () {}, diff --git a/mobile_files/package.json.orig b/mobile_files/package.json.orig index 07f5d2c98a5..8ac3195d1aa 100644 --- a/mobile_files/package.json.orig +++ b/mobile_files/package.json.orig @@ -71,7 +71,7 @@ "string_decoder": "0.10.31", "text-encoding": "^0.6.4", "url": "0.10.3", - "web3": "git+https://github.com/status-im/web3.js.git#0.20.2-status", + "web3": "git+https://github.com/status-im/web3.js.git#0.20.3-status.alpha.3", "web3-utils": "1.0.0-beta.36" } } diff --git a/mobile_files/yarn.lock b/mobile_files/yarn.lock index 01262eb3bef..b3830981ec7 100644 --- a/mobile_files/yarn.lock +++ b/mobile_files/yarn.lock @@ -7058,9 +7058,9 @@ web3-utils@1.0.0-beta.36: underscore "1.8.3" utf8 "2.1.1" -"web3@git+https://github.com/status-im/web3.js.git#0.20.2-status": +"web3@git+https://github.com/status-im/web3.js.git#0.20.3-status.alpha.3": version "0.20.1" - resolved "git+https://github.com/status-im/web3.js.git#958dbabff2c77615e23f5de678a6fae0b0d70147" + resolved "git+https://github.com/status-im/web3.js.git#29677754c8b87c55c828df2694e35b0b760dca5f" dependencies: bignumber.js "git+https://github.com/status-im/bignumber.js.git#v4.0.2-status" crypto-js "^3.1.4" diff --git a/src/status_im/accounts/core.cljs b/src/status_im/accounts/core.cljs index 6dfff05a8a6..aeddda2d5f4 100644 --- a/src/status_im/accounts/core.cljs +++ b/src/status_im/accounts/core.cljs @@ -94,13 +94,14 @@ {:desktop-notifications? desktop-notifications?} {})) -(fx/defn toggle-pfs [{:keys [db] :as cofx} enabled?] +(fx/defn toggle-device-to-device [{:keys [db] :as cofx} enabled?] (let [settings (get-in db [:account/account :settings]) - warning {:utils/show-popup {:title (i18n/label :t/pfs-warning-title) - :content (i18n/label :t/pfs-warning-content)}}] + warning {:utils/show-popup {:title (i18n/label :t/device-to-device-warning-title) + :content (i18n/label :t/device-to-device-warning-content)}}] (fx/merge cofx (when enabled? warning) + ;; Set to pfs? for backward compatibility (accounts.update/update-settings (assoc settings :pfs? enabled?) {})))) diff --git a/src/status_im/chat/db.cljs b/src/status_im/chat/db.cljs index 8130d494527..b7be0117162 100644 --- a/src/status_im/chat/db.cljs +++ b/src/status_im/chat/db.cljs @@ -5,8 +5,7 @@ [status-im.chat.commands.input :as commands.input] [status-im.contact.db :as contact.db] [status-im.group-chats.db :as group-chats.db] - [status-im.mailserver.core :as mailserver] - [status-im.transport.partitioned-topic :as topic] + [status-im.mailserver.constants :as mailserver.constants] [status-im.utils.gfycat.core :as gfycat])) (defn group-chat-name @@ -53,14 +52,6 @@ {} chats)) -(defn topic-by-current-chat - [{:keys [current-chat-id chats] :as db}] - (let [{:keys [public?]} (get chats current-chat-id) - public-key (get-in db [:account/account :public-key])] - (if public? - (get-in db [:transport/chats current-chat-id :topic]) - (topic/public-key->discovery-topic-hash public-key)))) - (defn sort-message-groups "Sorts message groups according to timestamp of first message in group" [message-groups messages] @@ -164,7 +155,7 @@ (not (nil? highest-request-to)) (not (nil? lowest-request-from)) (< (- highest-request-to lowest-request-from) - mailserver/max-gaps-range)) + mailserver.constants/max-gaps-range)) (update acc :messages conj {:type :gap :value (str :first-gap) :first-gap? true}) diff --git a/src/status_im/chat/models.cljs b/src/status_im/chat/models.cljs index c8dc6ee1742..6bb925b389d 100644 --- a/src/status_im/chat/models.cljs +++ b/src/status_im/chat/models.cljs @@ -1,14 +1,13 @@ (ns status-im.chat.models (:require [re-frame.core :as re-frame] [status-im.accounts.model :as accounts.model] - [status-im.contact-code.core :as contact-code] + [status-im.transport.filters.core :as transport.filters] [status-im.contact.core :as contact.core] [status-im.data-store.chats :as chats-store] [status-im.data-store.messages :as messages-store] [status-im.i18n :as i18n] [status-im.mailserver.core :as mailserver] - [status-im.transport.chat.core :as transport.chat] - [status-im.transport.message.public-chat :as public-chat] + [status-im.transport.message.protocol :as transport.protocol] [status-im.tribute-to-talk.core :as tribute-to-talk] [status-im.ui.components.colors :as colors] [status-im.ui.components.desktop.events :as desktop.events] @@ -169,22 +168,14 @@ (log/error "can't remove a chat:" error))}]} (navigation/navigate-to-cofx :home {})) (fx/merge cofx - ;; TODO: There's a race condition here, as the removal of the filter (async) - ;; is done at the same time as the removal of the chat, so a message - ;; might come between and restore the chat. Multiple way to handle this - ;; (remove chat only after the filter has been removed, probably the safest, - ;; flag the chat to ignore new messages, change receive method for public/group chats) - ;; For now to keep the code simplier and avoid significant changes, best to leave as it is. - #(when (public-chat? % chat-id) - (transport.chat/unsubscribe-from-chat % chat-id)) - #(when (group-chat? % chat-id) - (mailserver/remove-chat-from-mailserver-topic % chat-id)) (mailserver/remove-gaps chat-id) (mailserver/remove-range chat-id) (deactivate-chat chat-id) (clear-history chat-id) - #(when (one-to-one-chat? % chat-id) - (contact-code/stop-listening % chat-id)) + (transport.filters/stop-listening chat-id) + ;; TODO: this is not accurate, if there's a pending contact + ;; request it will not be sent anymore + (transport.protocol/remove-chat chat-id) (navigation/navigate-to-cofx :home {})))) (defn- unread-messages-number [chats] @@ -249,7 +240,10 @@ (fx/merge cofx {:db (-> (assoc db :current-chat-id chat-id) (set-chat-ui-props {:validation-messages nil}))} - (contact-code/listen-to-chat chat-id) + ;; Group chat don't need this to load as all the loading of topics + ;; happens on membership changes + (when-not (group-chat? cofx chat-id) + (transport.filters/load-chat chat-id)) (when platform/desktop? (mark-messages-seen chat-id)) (tribute-to-talk/check-tribute chat-id))) @@ -286,6 +280,7 @@ (fx/merge cofx (upsert-chat {:chat-id chat-id :is-active true}) + (transport.filters/load-chat chat-id) (navigate-to-chat chat-id opts))))) (fx/defn start-public-chat @@ -296,9 +291,9 @@ (navigate-to-chat cofx topic opts)) (fx/merge cofx (add-public-chat topic) + (transport.filters/load-chat topic) #(when-not dont-navigate? (navigate-to-chat % topic opts)) - (public-chat/join-public-chat topic) #(when platform/desktop? (desktop.events/change-tab % :home))))) diff --git a/src/status_im/chat/models/loading.cljs b/src/status_im/chat/models/loading.cljs index 12caf463bb1..a0f37c7d425 100644 --- a/src/status_im/chat/models/loading.cljs +++ b/src/status_im/chat/models/loading.cljs @@ -111,6 +111,7 @@ get-unviewed-message-ids :get-unviewed-message-ids :as cofx}] ;; TODO: re-implement functionality for status-go protocol (when-not (or config/use-status-go-protocol? + (nil? current-chat-id) (get-in db [:chats current-chat-id :all-loaded?])) (let [previous-pagination-info (get-in db [:chats current-chat-id :pagination-info]) {:keys [messages diff --git a/src/status_im/chat/models/message.cljs b/src/status_im/chat/models/message.cljs index 6d992ee80c5..8861636101b 100644 --- a/src/status_im/chat/models/message.cljs +++ b/src/status_im/chat/models/message.cljs @@ -74,10 +74,15 @@ {}))})) (defn add-outgoing-status - [{:keys [from] :as message} current-public-key] + [{:keys [from outgoing-status] :as message} current-public-key] (if (and (= from current-public-key) (not (system-message? message))) - (assoc message :outgoing true) + (assoc message + :outgoing true + ;; We don't override outgoing-status if there, which means + ;; that our device has sent the message, while if empty is coming + ;; from a different device + :outgoing-status (or outgoing-status :sent)) message)) (defn build-desktop-notification diff --git a/src/status_im/contact/core.cljs b/src/status_im/contact/core.cljs index 96821dad9ce..3fc8a8901a0 100644 --- a/src/status_im/contact/core.cljs +++ b/src/status_im/contact/core.cljs @@ -1,6 +1,6 @@ (ns status-im.contact.core (:require [status-im.accounts.model :as accounts.model] - [status-im.contact-code.core :as contact-code] + [status-im.transport.filters.core :as transport.filters] [status-im.contact.db :as contact.db] [status-im.contact.device-info :as device-info] [status-im.ethereum.core :as ethereum] @@ -8,7 +8,6 @@ [status-im.mailserver.core :as mailserver] [status-im.transport.message.contact :as message.contact] [status-im.transport.message.protocol :as protocol] - [status-im.transport.partitioned-topic :as transport.topic] [status-im.tribute-to-talk.db :as tribute-to-talk] [status-im.tribute-to-talk.whitelist :as whitelist] [status-im.ui.screens.navigation :as navigation] @@ -50,8 +49,7 @@ {:db (-> db (update-in [:contacts/contacts public-key] merge contact)) :data-store/tx [(contacts-store/save-contact-tx contact)]} - #(when (contact.db/added? contact) - (contact-code/listen-to-chat % public-key)))) + (transport.filters/load-contact contact))) (fx/defn send-contact-request [{:keys [db] :as cofx} {:keys [public-key] :as contact}] @@ -70,10 +68,6 @@ (fx/merge cofx {:db (assoc-in db [:contacts/new-identity] "")} (upsert-contact contact) - (mailserver/upsert-mailserver-topic - {:chat-ids [public-key] - :topic (transport.topic/discovery-topic-hash) - :fetch? false}) (whitelist/add-to-whitelist public-key) (send-contact-request contact) (mailserver/process-next-messages-request))))) @@ -87,24 +81,6 @@ {:db (assoc-in db [:contacts/new-identity] "")} (upsert-contact contact))))) -(fx/defn add-contacts-filter [{:keys [db]} public-key action] - (when (not= (get-in db [:account/account :public-key]) public-key) - (let [current-public-key (get-in db [:account/account :public-key])] - {:db - (cond-> db - config/partitioned-topic-enabled? - (assoc :filters/after-adding-discovery-filter - {:action action - :public-key public-key})) - - :shh/add-discovery-filters - {:web3 (:web3 db) - :private-key-id current-public-key - :topics [{:topic (transport.topic/partitioned-topic-hash public-key) - :chat-id public-key - :minPow 1 - :callback (constantly nil)}]}}))) - (defn handle-contact-update [public-key timestamp diff --git a/src/status_im/contact_code/core.cljs b/src/status_im/contact_code/core.cljs deleted file mode 100644 index 573cca2cb22..00000000000 --- a/src/status_im/contact_code/core.cljs +++ /dev/null @@ -1,98 +0,0 @@ -(ns status-im.contact-code.core - "This namespace is used to listen for and publish contact-codes. We want to listen - to contact codes once we engage in the conversation with someone, or once someone is - in our contacts." - (:require - [taoensso.timbre :as log] - [status-im.contact.db :as contact.db] - [status-im.utils.fx :as fx] - [status-im.transport.shh :as shh] - [status-im.transport.message.public-chat :as transport.public-chat] - [status-im.data-store.accounts :as data-store.accounts] - [status-im.transport.chat.core :as transport.chat] - [status-im.accounts.model :as accounts.model] - [status-im.mailserver.core :as mailserver])) - -(defn topic [pk] - (str pk "-contact-code")) - -(fx/defn listen [cofx chat-id] - (transport.public-chat/join-public-chat - cofx - (topic chat-id))) - -(fx/defn listen-to-chat - "For a one-to-one chat, listen to the pk of the user, for a group chat - listen for any member" - [cofx chat-id] - (let [{:keys [members - public? - is-active - group-chat]} (get-in cofx [:db :chats chat-id])] - (when is-active - (cond - (and group-chat - (not public?)) - (apply fx/merge cofx - (map listen members)) - (not public?) - (listen cofx chat-id))))) - -(fx/defn stop-listening - "We can stop listening to contact codes when we don't have any active chat - with the user (one-to-one or group-chat), and it is not in our contacts" - [{:keys [db] :as cofx} their-public-key] - (let [my-public-key (accounts.model/current-public-key cofx) - active-group-chats (filter (fn [{:keys [is-active members members-joined]}] - (and is-active - (contains? members-joined my-public-key) - (contains? members their-public-key))) - (vals (:chats db))) - their-topic (topic their-public-key)] - (when (and (not (contact.db/active? db their-public-key)) - (not= my-public-key their-public-key) - (not (get-in db [:chats their-public-key :is-active])) - (empty? active-group-chats)) - (fx/merge - cofx - (mailserver/remove-gaps their-topic) - (mailserver/remove-range their-topic) - (transport.chat/unsubscribe-from-chat their-topic))))) - -;; Publish contact code every 12hrs -(def publish-contact-code-interval (* 12 60 60 1000)) - -(fx/defn init [cofx] - (log/debug "initializing contact-code") - (let [current-public-key (accounts.model/current-public-key cofx)] - (listen cofx current-public-key))) - -(defn publish! [{:keys [web3 now] :as cofx}] - (let [current-public-key (accounts.model/current-public-key cofx) - chat-id (topic current-public-key) - peers-count (:peers-count @re-frame.db/app-db) - last-published (get-in - @re-frame.db/app-db - [:account/account :last-published-contact-code])] - (when (and (pos? peers-count) - (< publish-contact-code-interval - (- now last-published))) - - (let [message {:chat chat-id - :sig current-public-key - :payload ""}] - (shh/send-public-message! - web3 - message - [:contact-code.callback/contact-code-published] - :contact-code.callback/contact-code-publishing-failed))))) - -(fx/defn published [{:keys [now db] :as cofx}] - (let [new-account (assoc (:account/account db) - :last-published-contact-code - now)] - {:db (assoc db :account/account new-account) - :data-store/base-tx [(data-store.accounts/save-account-tx new-account)]})) - -(fx/defn publishing-failed [cofx] - (log/warn "failed to publish contact-code")) diff --git a/src/status_im/contact_recovery/core.cljs b/src/status_im/contact_recovery/core.cljs index 9bedec66e2f..197e8c6a80c 100644 --- a/src/status_im/contact_recovery/core.cljs +++ b/src/status_im/contact_recovery/core.cljs @@ -56,7 +56,6 @@ [{:web3 web3 :src current-public-key :dst public-key - :topics (get-in cofx [:db :mailserver/topics]) :payload ""}]})) (re-frame/reg-fx diff --git a/src/status_im/data_store/chats.cljs b/src/status_im/data_store/chats.cljs index 88d173b7274..f6a2e8fbbe8 100644 --- a/src/status_im/data_store/chats.cljs +++ b/src/status_im/data_store/chats.cljs @@ -4,6 +4,7 @@ [status-im.data-store.messages :as messages] [status-im.data-store.realm.core :as core] [status-im.ethereum.core :as ethereum] + [taoensso.timbre :as log] [status-im.utils.clocks :as utils.clocks] [status-im.utils.core :as utils])) @@ -72,6 +73,7 @@ "Returns tx function for saving chat" [chat] (fn [realm] + (log/debug "saving chat" chat) (core/create realm :chat diff --git a/src/status_im/data_store/mailservers.cljs b/src/status_im/data_store/mailservers.cljs index 2668c9a1584..eb83e077a07 100644 --- a/src/status_im/data_store/mailservers.cljs +++ b/src/status_im/data_store/mailservers.cljs @@ -1,6 +1,7 @@ (ns status-im.data-store.mailservers (:require [cljs.tools.reader.edn :as edn] [re-frame.core :as re-frame] + [taoensso.timbre :as log] [status-im.data-store.realm.core :as core])) (re-frame/reg-cofx @@ -31,7 +32,6 @@ (defn deserialize-mailserver-topic [serialized-mailserver-topic] (-> serialized-mailserver-topic - (dissoc :topic) (update :chat-ids edn/read-string))) (re-frame/reg-cofx @@ -50,6 +50,7 @@ "Returns tx function for saving mailserver topic" [{:keys [topic mailserver-topic]}] (fn [realm] + (log/debug "saving mailserver-topic:" topic mailserver-topic) (core/create realm :mailserver-topic (-> mailserver-topic @@ -61,6 +62,7 @@ "Returns tx function for deleting mailserver topic" [topic] (fn [realm] + (log/debug "deleting mailserver-topic:" topic) (let [mailserver-topic (.objectForPrimaryKey realm "mailserver-topic" topic)] @@ -69,6 +71,7 @@ (defn save-chat-requests-range [chat-requests-range] (fn [realm] + (log/debug "saving ranges" chat-requests-range) (core/create realm :chat-requests-range chat-requests-range true))) (re-frame/reg-cofx @@ -98,11 +101,13 @@ (defn save-mailserver-requests-gap [gap] (fn [realm] + (log/debug "saving gap" gap) (core/create realm :mailserver-requests-gap gap true))) (defn delete-mailserver-requests-gaps [ids] (fn [realm] + (log/debug "deleting gaps" ids) (doseq [id ids] (core/delete realm @@ -111,11 +116,13 @@ (defn delete-all-gaps-by-chat [chat-id] (fn [realm] + (log/debug "deleting all gaps for chat" chat-id) (core/delete realm (core/get-by-field realm :mailserver-requests-gap :chat-id chat-id)))) (defn delete-range [chat-id] (fn [realm] + (log/debug "deleting range" chat-id) (core/delete realm (core/get-by-field realm :chat-requests-range :chat-id chat-id)))) diff --git a/src/status_im/data_store/realm/schemas/account/core.cljs b/src/status_im/data_store/realm/schemas/account/core.cljs index bcb1e8b3dc5..5eb1d6138ac 100644 --- a/src/status_im/data_store/realm/schemas/account/core.cljs +++ b/src/status_im/data_store/realm/schemas/account/core.cljs @@ -560,6 +560,21 @@ contact-recovery/v1 mailserver-requests-gap/v1]) +(def v47 [chat/v15 + chat-requests-range/v1 + transport/v10 + contact/v8 + message/v11 + mailserver/v11 + mailserver-topic/v2 + membership-update/v1 + installation/v3 + browser/v8 + dapp-permissions/v9 + contact-device-info/v1 + contact-recovery/v1 + mailserver-requests-gap/v1]) + ;; put schemas ordered by version (def schemas [{:schema v1 :schemaVersion 1 @@ -698,4 +713,7 @@ :migration (constantly nil)} {:schema v46 :schemaVersion 46 - :migration migrations/v46}]) + :migration migrations/v46} + {:schema v47 + :schemaVersion 47 + :migration (constantly nil)}]) diff --git a/src/status_im/data_store/realm/schemas/account/migrations.cljs b/src/status_im/data_store/realm/schemas/account/migrations.cljs index f48f7ca5e00..265f8af9931 100644 --- a/src/status_im/data_store/realm/schemas/account/migrations.cljs +++ b/src/status_im/data_store/realm/schemas/account/migrations.cljs @@ -422,9 +422,10 @@ status (aget user-status "status") message-id (aget user-status "message-id") message (message-by-id new-realm message-id)] - (cond - (= status "seen") - (aset message "seen" true) + (when message + (cond + (= status "seen") + (aset message "seen" true) - (#{"sent" "sending" "not-sent"} status) - (aset message "outgoing-status" status)))))) + (#{"sent" "sending" "not-sent"} status) + (aset message "outgoing-status" status))))))) diff --git a/src/status_im/data_store/realm/schemas/account/transport.cljs b/src/status_im/data_store/realm/schemas/account/transport.cljs index da7cda00d1d..de03f9c29f6 100644 --- a/src/status_im/data_store/realm/schemas/account/transport.cljs +++ b/src/status_im/data_store/realm/schemas/account/transport.cljs @@ -72,3 +72,5 @@ (def v9 (update v8 :properties dissoc :ack :seen :pending-ack :pending-send)) + +(def v10 (update v9 :properties dissoc :one-to-one :topic :sym-key-id :sym-key)) diff --git a/src/status_im/data_store/transport.cljs b/src/status_im/data_store/transport.cljs index 33070b7a6ca..e28b75605df 100644 --- a/src/status_im/data_store/transport.cljs +++ b/src/status_im/data_store/transport.cljs @@ -1,5 +1,6 @@ (ns status-im.data-store.transport (:require [re-frame.core :as re-frame] + [taoensso.timbre :as log] [status-im.data-store.realm.core :as core])) (defn deserialize-chat [serialized-chat] @@ -21,6 +22,7 @@ "Returns tx function for saving transport" [{:keys [chat-id chat]}] (fn [realm] + (log/debug "saving transport, chat-id:" chat-id "chat" chat) (core/create realm :transport (assoc chat :chat-id chat-id) @@ -30,5 +32,6 @@ "Returns tx function for deleting transport" [chat-id] (fn [realm] + (log/debug "deleting transport, chat-id:" chat-id) (let [transport (.objectForPrimaryKey realm "transport" chat-id)] (core/delete realm transport)))) diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index c628fbcdb34..efef687e637 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -18,7 +18,6 @@ [status-im.chat.models.input :as chat.input] [status-im.chat.models.loading :as chat.loading] [status-im.chat.models.message :as chat.message] - [status-im.contact-code.core :as contact-code] [status-im.contact-recovery.core :as contact-recovery] [status-im.contact.block :as contact.block] [status-im.contact.core :as contact] @@ -33,6 +32,8 @@ [status-im.init.core :as init] [status-im.log-level.core :as log-level] [status-im.mailserver.core :as mailserver] + [status-im.mailserver.constants :as mailserver.constants] + [status-im.mailserver.topics :as mailserver.topics] [status-im.node.core :as node] [status-im.notifications.core :as notifications] [status-im.pairing.core :as pairing] @@ -227,9 +228,9 @@ (accounts/enable-notifications cofx desktop-notifications?))) (handlers/register-handler-fx - :accounts.ui/toggle-pfs + :accounts.ui/toggle-device-to-device (fn [cofx [_ enabled?]] - (accounts/toggle-pfs cofx enabled?))) + (accounts/toggle-device-to-device cofx enabled?))) (handlers/register-handler-fx :accounts.ui/web3-opt-in-mode-switched @@ -632,29 +633,29 @@ :chat.ui/fetch-history-pressed (fn [{:keys [now] :as cofx} [_ chat-id]] (mailserver/fetch-history cofx chat-id - {:from (- (quot now 1000) mailserver/one-day)}))) + {:from (- (quot now 1000) mailserver.constants/one-day)}))) (handlers/register-handler-fx :chat.ui/fetch-history-pressed48-60 (fn [{:keys [now] :as cofx} [_ chat-id]] (let [now (quot now 1000)] (mailserver/fetch-history cofx chat-id - {:from (- now (* 2.5 mailserver/one-day)) - :to (- now (* 2 mailserver/one-day))})))) + {:from (- now (* 2.5 mailserver.constants/one-day)) + :to (- now (* 2 mailserver.constants/one-day))})))) (handlers/register-handler-fx :chat.ui/fetch-history-pressed84-96 (fn [{:keys [now] :as cofx} [_ chat-id]] (let [now (quot now 1000)] (mailserver/fetch-history cofx chat-id - {:from (- now (* 4 mailserver/one-day)) - :to (- now (* 3.5 mailserver/one-day))})))) + {:from (- now (* 4 mailserver.constants/one-day)) + :to (- now (* 3.5 mailserver.constants/one-day))})))) (handlers/register-handler-fx :chat.ui/fill-gaps (fn [{:keys [db] :as cofx} [_ gap-ids]] (let [chat-id (:current-chat-id db) - topic (chat.db/topic-by-current-chat db) + topics (mailserver.topics/topics-for-current-chat db) gaps (keep (fn [id] (get-in db [:mailserver/gaps chat-id id])) @@ -662,7 +663,7 @@ (mailserver/fill-the-gap cofx {:gaps gaps - :topic topic + :topics topics :chat-id chat-id})))) (handlers/register-handler-fx @@ -673,14 +674,14 @@ {:keys [lowest-request-from]} (get-in db [:mailserver/ranges chat-id]) - topic (chat.db/topic-by-current-chat db) + topics (mailserver.topics/topics-for-current-chat db) gaps [{:id :first-gap :to lowest-request-from - :from (- lowest-request-from mailserver/one-day)}]] + :from (- lowest-request-from mailserver.constants/one-day)}]] (mailserver/fill-the-gap cofx {:gaps gaps - :topic topic + :topics topics :chat-id chat-id})))) (handlers/register-handler-fx @@ -1595,9 +1596,7 @@ :contact.ui/add-to-contact-pressed [(re-frame/inject-cofx :random-id-generator)] (fn [cofx [_ public-key]] - (if config/partitioned-topic-enabled? - (contact/add-contacts-filter cofx public-key :add-contact) - (contact/add-contact cofx public-key)))) + (contact/add-contact cofx public-key))) (handlers/register-handler-fx :contact.ui/block-contact-pressed @@ -1628,14 +1627,7 @@ :on-dismiss #(re-frame/dispatch [:navigate-to-clean :home])}} (fx/merge cofx fx - (if config/partitioned-topic-enabled? - (contact/add-contacts-filter contact-identity :open-chat) - (chat/start-chat contact-identity {:navigation-reset? true}))))))) - -(handlers/register-handler-fx - :contact/filters-added - (fn [cofx [_ contact-identity]] - (chat/start-chat cofx contact-identity {:navigation-reset? true}))) + (chat/start-chat contact-identity {:navigation-reset? true})))))) (handlers/register-handler-fx :contact.ui/start-group-chat-pressed @@ -1683,16 +1675,6 @@ (fn [cofx [_ initial-props]] {:db (assoc (:db cofx) :initial-props initial-props)})) -(handlers/register-handler-fx - :contact-code.callback/contact-code-published - (fn [cofx arg] - (contact-code/published cofx))) - -(handlers/register-handler-fx - :contact-code.callback/contact-code-publishing-failed - (fn [cofx _] - (contact-code/publishing-failed cofx))) - (handlers/register-handler-fx :pairing.ui/enable-installation-pressed (fn [cofx [_ installation-id]] diff --git a/src/status_im/group_chats/core.cljs b/src/status_im/group_chats/core.cljs index 7d975891610..5d405fc36f6 100644 --- a/src/status_im/group_chats/core.cljs +++ b/src/status_im/group_chats/core.cljs @@ -5,19 +5,20 @@ [clojure.string :as string] [re-frame.core :as re-frame] [status-im.accounts.model :as accounts.model] + [status-im.pairing.core :as pairing] [status-im.chat.models :as models.chat] [status-im.chat.models.message :as models.message] [status-im.contact.core :as models.contact] - [status-im.contact-code.core :as contact-code] + [status-im.transport.filters.core :as transport.filters] [status-im.group-chats.db :as group-chats.db] [status-im.i18n :as i18n] [status-im.native-module.core :as native-module] [status-im.transport.message.group-chat :as message.group-chat] [status-im.transport.message.protocol :as protocol] - [status-im.transport.partitioned-topic :as transport.topic] [status-im.utils.clocks :as utils.clocks] [status-im.utils.fx :as fx] [status-im.mailserver.core :as mailserver] + [status-im.mailserver.topics :as mailserver.topics] [taoensso.timbre :as log])) ;; Description of the flow: @@ -121,22 +122,21 @@ removed-members) {:keys [web3]} (:db cofx) current-public-key (accounts.model/current-public-key cofx) - ;; If a member has joined is listening to the shared topic and we send there - ;; to ourselves we send always on contact-discovery to make sure all devices - ;; are informed, in case of dropped messages. - ;; We check that it has explicitly joined, regardless of the local - ;; version of the group chat, for backward compatibility + members-allowed (filter + (fn [pk] + (if (= pk current-public-key) + (pairing/has-paired-installations? cofx) + true)) + members) destinations (map (fn [member] - {:public-key member - :chat (transport.topic/public-key->discovery-topic member)}) - members)] + {:public-key member}) + members-allowed)] (fx/merge cofx {:shh/send-group-message {:web3 web3 :src current-public-key :dsts destinations - :available-topics (get-in cofx [:db :mailserver/topics]) :success-event [:transport/message-sent chat-id message-id @@ -217,12 +217,7 @@ {:group-chats/sign-membership {:chat-id chat-id :from my-public-key :events events} - :db (assoc db :group/selected-contacts #{})} - (mailserver/upsert-mailserver-topic - {:chat-ids [chat-id] - :topic (transport.topic/discovery-topic-hash) - :fetch? false}) - (mailserver/process-next-messages-request)))) + :db (assoc db :group/selected-contacts #{})}))) (fx/defn remove-member "Format group update message and sign membership" @@ -254,12 +249,7 @@ cofx {:group-chats/sign-membership {:chat-id chat-id :from my-public-key - :events [event]}} - (mailserver/upsert-mailserver-topic - {:chat-ids [chat-id] - :topic (transport.topic/discovery-topic-hash) - :fetch false}) - (mailserver/process-next-messages-request))))) + :events [event]}})))) (fx/defn make-admin "Format group update with make admin message and sign membership" @@ -459,27 +449,20 @@ (membership-changes->system-messages cofx clock-values) (models.message/add-system-messages cofx))))) -(fx/defn set-up-topic +(fx/defn set-up-filter "Listen/Tear down the shared topic/contact-codes. Stop listening for members who have left the chat" [cofx chat-id previous-chat] (let [my-public-key (accounts.model/current-public-key cofx) - new-chat (get-in cofx [:db :chats chat-id])] - ;; If we left the chat, teardown, otherwise upsert - (if (and (group-chats.db/joined? my-public-key previous-chat) - (not (group-chats.db/joined? my-public-key new-chat))) - (apply fx/merge - cofx - (map #(contact-code/stop-listening %) - (:members new-chat))) - (apply fx/merge - cofx - (concat - (map #(contact-code/listen-to-chat %) - (:members new-chat)) - (map #(contact-code/stop-listening %) - (clojure.set/difference (:members previous-chat) - (:members new-chat)))))))) + new-chat (get-in cofx [:db :chats chat-id]) + members (:members-joined new-chat)] + ;; If we left the chat do nothing + (when-not (and (group-chats.db/joined? my-public-key previous-chat) + (not (group-chats.db/joined? my-public-key new-chat))) + (fx/merge + cofx + (transport.filters/upsert-group-chat-topics) + (transport.filters/load-members members))))) (fx/defn handle-membership-update "Upsert chat and receive message if valid" @@ -512,7 +495,7 @@ :contacts (:contacts new-group)}) (add-system-messages chat-id previous-chat new-group) - (set-up-topic chat-id previous-chat) + (set-up-filter chat-id previous-chat) #(when (and message ;; don't allow anything but group messages (instance? protocol/Message message) diff --git a/src/status_im/mailserver/constants.cljs b/src/status_im/mailserver/constants.cljs new file mode 100644 index 00000000000..2db0b56035c --- /dev/null +++ b/src/status_im/mailserver/constants.cljs @@ -0,0 +1,16 @@ +(ns ^{:doc "Mailserver events and API"} + status-im.mailserver.constants) + +(def one-day (* 24 3600)) +(def seven-days (* 7 one-day)) +(def max-gaps-range (* 30 one-day)) +(def max-request-range one-day) +(def maximum-number-of-attempts 2) +(def request-timeout 30) +(def min-limit 100) +(def max-limit 2000) +(def backoff-interval-ms 3000) +(def default-limit max-limit) +(def connection-timeout + "Time after which mailserver connection is considered to have failed" + 10000) diff --git a/src/status_im/mailserver/core.cljs b/src/status_im/mailserver/core.cljs index d88b594f2ec..5746c5a7c28 100644 --- a/src/status_im/mailserver/core.cljs +++ b/src/status_im/mailserver/core.cljs @@ -12,12 +12,13 @@ [status-im.transport.db :as transport.db] [status-im.transport.message.protocol :as protocol] [clojure.string :as string] + [status-im.mailserver.topics :as mailserver.topics] + [status-im.mailserver.constants :as constants] [status-im.data-store.mailservers :as data-store.mailservers] [status-im.i18n :as i18n] [status-im.utils.handlers :as handlers] [status-im.accounts.update.core :as accounts.update] [status-im.ui.screens.navigation :as navigation] - [status-im.transport.partitioned-topic :as transport.topic] [status-im.ui.screens.mobile-network-settings.utils :as mobile-network-utils] [status-im.utils.random :as rand])) @@ -34,20 +35,7 @@ ;; as soon as the mailserver becomes available -(def one-day (* 24 3600)) -(def seven-days (* 7 one-day)) -(def max-gaps-range (* 30 one-day)) -(def max-request-range one-day) -(def maximum-number-of-attempts 2) -(def request-timeout 30) -(def min-limit 100) -(def max-limit 2000) -(def backoff-interval-ms 3000) -(def default-limit max-limit) -(def connection-timeout - "Time after which mailserver connection is considered to have failed" - 10000) -(def limit (atom default-limit)) +(def limit (atom constants/default-limit)) (def success-counter (atom 0)) (defn connected? [{:keys [db]} id] @@ -147,10 +135,10 @@ (update-mailservers! enodes))) (defn decrease-limit [] - (max min-limit (/ @limit 2))) + (max constants/min-limit (/ @limit 2))) (defn increase-limit [] - (min max-limit (* @limit 2))) + (min constants/max-limit (* @limit 2))) (re-frame/reg-fx :mailserver/set-limit @@ -224,7 +212,7 @@ ;; Any message sent before this takes effect will not be marked as sent ;; probably we should improve the UX so that is more transparent to the user :mailserver/update-mailservers [address] - :utils/dispatch-later [{:ms connection-timeout + :utils/dispatch-later [{:ms constants/connection-timeout :dispatch [:mailserver/check-connection-timeout]}]} (when-not (or sym-key-id generating-sym-key?) (generate-mailserver-symkey mailserver))))) @@ -327,7 +315,7 @@ (clj->js (cond-> {:topics topics :mailServerPeer address :symKeyID sym-key-id - :timeout request-timeout + :timeout constants/request-timeout :limit actual-limit :cursor cursor :from actual-from} @@ -341,7 +329,7 @@ (do (log/error "mailserver: messages request error for topic " topics ": " error) (utils/set-timeout #(re-frame/dispatch [:mailserver.callback/resend-request {:request-id nil}]) - backoff-interval-ms))))))) + constants/backoff-interval-ms))))))) (re-frame/reg-fx :mailserver/request-messages @@ -366,19 +354,19 @@ (> default-request-to last-request)) (let [from (or force-request-from (max last-request - (- default-request-to max-request-range))) + (- default-request-to constants/max-request-range))) to (or force-request-to default-request-to)] - {:topic topic + {:gap-topics #{topic} :from from :to to :force-to? (not (nil? force-request-to))}))))) (defn aggregate-requests - [acc {:keys [topic from to force-to? gap chat-id]}] + [acc {:keys [gap-topics from to force-to? gap chat-id]}] (when from (update acc [from to force-to?] (fn [{:keys [topics]}] - {:topics ((fnil conj #{}) topics topic) + {:topics ((fnil clojure.set/union #{}) topics gap-topics) :from from :to to ;; To is sent to the mailserver only when force-to? is true, @@ -405,8 +393,8 @@ (fx/defn process-next-messages-request [{:keys [db now] :as cofx}] (when (and + (:filters/initialized db) (mobile-network-utils/syncing-allowed? cofx) - (transport.db/all-filters-added? cofx) (not (:mailserver/current-request db))) (when-let [mailserver (get-mailserver-when-ready cofx)] (let [request-to (or (:mailserver/request-to db) @@ -510,28 +498,6 @@ (reset-request-to) (connect-to-mailserver)))) -(fx/defn remove-chat-from-mailserver-topic - "if the chat is the only chat of the mailserver topic delete the mailserver topic - and process-next-messages-requests again to remove pending request for that topic - otherwise remove the chat-id of the chat from the mailserver topic and save" - [{:keys [db] :as cofx} chat-id] - (let [{:keys [public?] :as chat} (get-in db [:chats chat-id]) - topic (if (and chat (not public?)) - (transport.topic/discovery-topic-hash) - (get-in db [:transport/chats chat-id :topic])) - {:keys [chat-ids] :as mailserver-topic} (update (get-in db [:mailserver/topics topic]) - :chat-ids - disj chat-id)] - (if (empty? chat-ids) - (fx/merge cofx - {:db (update db :mailserver/topics dissoc topic) - :data-store/tx [(data-store.mailservers/delete-mailserver-topic-tx topic)]} - (process-next-messages-request)) - {:db (assoc-in db [:mailserver/topics topic] mailserver-topic) - :data-store/tx [(data-store.mailservers/save-mailserver-topic-tx - {:topic topic - :mailserver-topic mailserver-topic})]}))) - (fx/defn remove-gaps [{:keys [db]} chat-id] {:db (update db :mailserver/gaps dissoc chat-id) @@ -860,77 +826,38 @@ :on-accept #(re-frame/dispatch [:mailserver.ui/retry-request-pressed]) :confirm-button-text (i18n/label :t/mailserver-request-retry)}})) -(fx/defn upsert-mailserver-topic - "if the topic didn't exist - create the topic - else if chat-id is not in the topic - add the chat-id to the topic and reset last-request - there was no filter for the chat and messages for that - so the whole history for that topic needs to be re-fetched" - [{:keys [db now] :as cofx} {:keys [topic chat-ids fetch?] - :or {fetch? true}}] - (let [current-mailserver-topic (get-in db [:mailserver/topics topic] - {:chat-ids #{}}) - existing-ids (:chat-ids current-mailserver-topic) - chat-id (first chat-ids)] - (when-not (every? (partial contains? existing-ids) chat-ids) - (let [{:keys [new-account? public-key]} (:account/account db) - now-s (quot now 1000) - previous-last-request (get current-mailserver-topic :last-request) - last-request (cond (and new-account? - (nil? previous-last-request) - (or (= chat-id :discovery-topic) - (and - (string? chat-id) - (string/starts-with? - chat-id - public-key)))) - (- now-s 10) - - (not fetch?) - ;; in case a topic has been already requested - ;; reset `last-request` so that creation - ;; of an extra gap is prevented - (max (or previous-last-request (- now-s 10)) - (- now-s max-request-range)) - - :else - (- now-s max-request-range)) - mailserver-topic (-> current-mailserver-topic - (assoc :last-request last-request) - (update :chat-ids clojure.set/union (set chat-ids)))] - (fx/merge cofx - {:db (assoc-in db [:mailserver/topics topic] mailserver-topic) - :data-store/tx [(data-store.mailservers/save-mailserver-topic-tx - {:topic topic - :mailserver-topic mailserver-topic})]}))))) - (fx/defn fetch-history + "Retrive a list of topics given a chat id, set them to the specified time interval + and start a mailserver request" [{:keys [db] :as cofx} chat-id {:keys [from to]}] - (log/debug "fetch-history" "chat-id:" chat-id "from-timestamp:" from) - (let [public-key (accounts.model/current-public-key cofx) - topic (or (get-in db [:transport/chats chat-id :topic]) - (transport.topic/public-key->discovery-topic-hash public-key))] + (let [topics (mailserver.topics/topics-for-chat + db + chat-id)] + (log/debug "fetch-history" "chat-id:" chat-id "from-timestamp:" from "topics:" topics) (fx/merge cofx - {:db (cond-> (assoc-in db [:mailserver/requests-from topic] from) - - to - (assoc-in [:mailserver/requests-to topic] to))} + {:db (reduce + (fn [db topic] + (cond-> (assoc-in db [:mailserver/requests-from topic] from) + + to + (assoc-in [:mailserver/requests-to topic] to))) + db + topics)} (process-next-messages-request)))) (fx/defn fill-the-gap - [{:keys [db] :as cofx} {:keys [gaps topic chat-id]}] + [{:keys [db] :as cofx} {:keys [gaps topics chat-id]}] (let [mailserver (get-mailserver-when-ready cofx) requests (into {} (map (fn [{:keys [from to id]}] [id {:from (max from - (- to max-request-range)) + (- to constants/max-request-range)) :to to :force-to? true - :topics [topic] - :topic topic + :topics topics + :gap-topics topics :chat-id chat-id :gap id}])) gaps) @@ -962,7 +889,7 @@ ;; this is the same request that we are currently processing (= request-id (:request-id current-request)))) - (if (<= maximum-number-of-attempts + (if (<= constants/maximum-number-of-attempts (:attempts current-request)) (fx/merge cofx {:db (update db :mailserver/current-request dissoc :attempts)} @@ -993,7 +920,7 @@ (fx/defn initialize-mailserver [cofx custom-mailservers] (fx/merge cofx - {:mailserver/set-limit default-limit} + {:mailserver/set-limit constants/default-limit} (add-custom-mailservers custom-mailservers) (set-current-mailserver))) @@ -1153,7 +1080,7 @@ (let [now-s (quot now 1000) gaps (all-gaps chat-id) outdated-gaps (into [] (comp (filter #(< (:to %) - (- now-s max-gaps-range))) + (- now-s constants/max-gaps-range))) (map :id)) (vals gaps)) gaps (apply dissoc gaps outdated-gaps)] diff --git a/src/status_im/mailserver/topics.cljs b/src/status_im/mailserver/topics.cljs new file mode 100644 index 00000000000..9a4ca7eef3c --- /dev/null +++ b/src/status_im/mailserver/topics.cljs @@ -0,0 +1,175 @@ +(ns ^{:doc "Mailserver events and API"} + status-im.mailserver.topics + (:require + [clojure.string :as string] + [taoensso.timbre :as log] + [status-im.data-store.mailservers :as data-store.mailservers] + [status-im.mailserver.constants :as constants] + [status-im.utils.fx :as fx])) + +(defn calculate-last-request [{:keys [discovery?]} + {:keys [previous-last-request + now-s]}] + ;; New topic, if discovery we don't fetch history + (if (and (nil? previous-last-request) + discovery?) + (- now-s 10) + (max previous-last-request + (- now-s constants/max-request-range)))) + +(fx/defn store [{:keys [db]} {:keys [topic + filter-ids + chat-ids] :as mailserver-topic}] + (if (or (empty? chat-ids) + (empty? filter-ids)) + {:db (update db :mailserver/topics dissoc topic)} + {:db (assoc-in db [:mailserver/topics topic] mailserver-topic)})) + +(fx/defn persist [_ {:keys [chat-ids topic filter-ids] + :as mailserver-topic}] + (let [op (if (or (empty? chat-ids) + (empty? filter-ids)) + (data-store.mailservers/delete-mailserver-topic-tx topic) + (data-store.mailservers/save-mailserver-topic-tx + {:topic topic + :mailserver-topic mailserver-topic}))] + {:data-store/tx [op]})) + +(defn new-chat-ids? [previous-mailserver-topic new-mailserver-topic] + (seq (clojure.set/difference (:chat-ids new-mailserver-topic) + (:chat-ids previous-mailserver-topic)))) + +(defn new-filter-ids? [previous-mailserver-topic new-mailserver-topic] + (seq (clojure.set/difference (:chat-ids new-mailserver-topic) + (:chat-ids previous-mailserver-topic)))) + +(defn merge-topic + "Calculate last-request and merge chat-ids keeping the old ones and new ones" + [old-mailserver-topic + new-mailserver-topic + {:keys [now-s]}] + (let [last-request (calculate-last-request + new-mailserver-topic + {:previous-last-request (:last-request old-mailserver-topic) + :now-s now-s})] + (-> old-mailserver-topic + (assoc + :topic (:topic new-mailserver-topic) + :discovery? (boolean (:discovery? new-mailserver-topic)) + :negotiated? (boolean (:negotiated? new-mailserver-topic)) + :last-request last-request) + (update :filter-ids + clojure.set/union + (set (:filter-ids new-mailserver-topic))) + (update :chat-ids + clojure.set/union + (set (:chat-ids new-mailserver-topic)))))) + +(fx/defn update-topic [cofx persist? topic] + (fx/merge cofx + (store topic) + (when persist? (persist topic)))) + +(fx/defn upsert + "if the topic didn't exist + create the topic + else if chat-id is not in the topic + add the chat-id to the topic and reset last-request + there was no filter for the chat and messages for that + so the whole history for that topic needs to be re-fetched" + [{:keys [db now] :as cofx} new-mailserver-topic] + (let [old-mailserver-topic (get-in db [:mailserver/topics (:topic new-mailserver-topic)] + {:topic (:topic new-mailserver-topic) + :filter-ids #{} + :chat-ids #{}})] + (let [updated-topic (merge-topic old-mailserver-topic + new-mailserver-topic + {:now-s (quot now 1000)})] + (update-topic cofx + (new-chat-ids? old-mailserver-topic + new-mailserver-topic) + updated-topic)))) + +(fx/defn upsert-many [cofx mailserver-topics] + (apply fx/merge cofx (map upsert mailserver-topics))) + +(fx/defn update-many [cofx mailserver-topics] + (apply fx/merge cofx (map (partial update-topic true) mailserver-topics))) + +(fx/defn delete [{:keys [db] :as cofx} {:keys [chat-id filter-id]}] + (when-let [matching-topics (filter (fn [{:keys [filter-ids] :as topic}] + (if (not filter-ids) + (do (log/warn "topic not initialized, removing" topic) + true) + (filter-ids filter-id))) + (vals (:mailserver/topics db)))] + (update-many cofx (map #(update % :filter-ids disj filter-id) matching-topics)))) + +(fx/defn delete-many + "Remove filter-ids from any topics and save" + [cofx filters] + (apply fx/merge cofx (map delete filters))) + +(defn extract-topics + "return all the topics for this chat, including discovery topics if specified" + [topics chat-id include-discovery?] + (reduce-kv + (fn [acc topic {:keys [discovery? chat-ids]}] + (if (or (and discovery? + include-discovery?) + (chat-ids chat-id)) + (conj acc topic) + acc)) + #{} + topics)) + +(defn changed-for-group-chat + "Returns all the discovery topics, or those topics that have at least one of the members. + Returns those topic that had chat-id but the member is not there anymore" + [topics chat-id members] + (reduce + (fn [acc {:keys [discovery? chat-ids] :as topic}] + (cond (some chat-ids members) + (update acc :modified conj + (assoc topic + :chat-ids #{chat-id})) + (and + (chat-ids chat-id) + (not-any? chat-ids members)) + (update acc :removed conj + (-> topic + (assoc :topic (:topic topic)) + (update :chat-ids disj chat-id))) + :else + acc)) + {:modified [] :removed []} + topics)) + +(fx/defn upsert-group-chat + "Based on the members it will upsert a mailserver topic for any discovery topic + and any personal topic that is in members. It will also remove the chat-id from any existing topic if not with a member" + [{:keys [db] :as cofx} chat-id members] + (let [topics (reduce-kv + (fn [acc topic-id topic] + (conj acc (assoc topic :topic topic-id))) + [] + (:mailserver/topics db)) + {:keys [modified + removed]} (changed-for-group-chat + topics + chat-id + members)] + (fx/merge cofx + (upsert-many modified) + (update-many removed)))) + +(defn topics-for-chat [db chat-id] + (extract-topics (:mailserver/topics db) + chat-id + (not (get-in (:chats db) [chat-id :public?])))) + +(defn topics-for-current-chat + "return a list of topics used by the current-chat, include discovery if + private group chat or one-to-one" + [{:keys [current-chat-id] :as db}] + (topics-for-chat db current-chat-id)) diff --git a/src/status_im/native_module/core.cljs b/src/status_im/native_module/core.cljs index 0f09fa09f14..32f779cfc5c 100644 --- a/src/status_im/native_module/core.cljs +++ b/src/status_im/native_module/core.cljs @@ -103,6 +103,12 @@ (def enable-installation native-module/enable-installation) +(def load-filters native-module/load-filters) + +(def load-filter native-module/load-filter) + +(def remove-filters native-module/remove-filters) + (def disable-installation native-module/disable-installation) (def update-mailservers native-module/update-mailservers) diff --git a/src/status_im/native_module/impl/module.cljs b/src/status_im/native_module/impl/module.cljs index 5d505949d16..fb6c2ea9708 100644 --- a/src/status_im/native_module/impl/module.cljs +++ b/src/status_im/native_module/impl/module.cljs @@ -152,6 +152,30 @@ (when (status) (.disableInstallation (status) installation-id callback))) +(defn load-filters [chats callback] + (let [params {:jsonrpc "2.0" + :id 2 + :method "shhext_loadFilters" + :params [chats]} + payload (.stringify js/JSON (clj->js params))] + (call-private-rpc payload callback))) + +(defn load-filter [chat callback] + (let [params {:jsonrpc "2.0" + :id 2 + :method "shhext_loadFilter" + :params [chat]} + payload (.stringify js/JSON (clj->js params))] + (call-private-rpc payload callback))) + +(defn remove-filters [chats callback] + (let [params {:jsonrpc "2.0" + :id 2 + :method "shhext_removeFilters" + :params [chats]} + payload (.stringify js/JSON (clj->js params))] + (call-private-rpc payload callback))) + (defn is24Hour [] (when (status) (.-is24Hour (status)))) diff --git a/src/status_im/pairing/core.cljs b/src/status_im/pairing/core.cljs index 4151dcce26d..d4215a3561c 100644 --- a/src/status_im/pairing/core.cljs +++ b/src/status_im/pairing/core.cljs @@ -15,6 +15,8 @@ [status-im.native-module.core :as native-module] [status-im.utils.identicon :as identicon] [status-im.contact.core :as contact] + [status-im.transport.filters.core :as transport.filters] + [status-im.data-store.contacts :as data-store.contacts] [status-im.data-store.accounts :as data-store.accounts] [status-im.transport.message.pairing :as transport.pairing])) @@ -148,8 +150,8 @@ (map #(transport.pairing/SyncInstallation. {} {} %)))) (defn sync-installation-messages [{:keys [db] :as cofx}] - (let [contacts (:contacts/contacts db) - contact-batches (partition-all contact-batch-n (vals contacts))] + (let [contacts (contact.db/get-active-contacts (:contacts/contacts db)) + contact-batches (partition-all contact-batch-n contacts)] (concat (mapv contact-batch->sync-installation-message contact-batches) [(sync-installation-account-message cofx)] (chats->sync-installation-messages cofx)))) @@ -215,7 +217,6 @@ [{:web3 web3 :src current-public-key :dst current-public-key - :topics (get-in cofx [:db :mailserver/topics]) :payload payload}]})) (fx/defn send-installation-message-fx [cofx payload] diff --git a/src/status_im/signals/core.cljs b/src/status_im/signals/core.cljs index 317b9883558..a5fd597c721 100644 --- a/src/status_im/signals/core.cljs +++ b/src/status_im/signals/core.cljs @@ -9,6 +9,7 @@ [status-im.node.core :as node] [status-im.pairing.core :as pairing] [status-im.transport.message.core :as transport.message] + [status-im.transport.filters.core :as transport.filters] [status-im.utils.fx :as fx] [status-im.utils.security :as security] [status-im.utils.types :as types] @@ -77,4 +78,5 @@ "subscriptions.data" (ethereum.subscriptions/handle-signal cofx event) "subscriptions.error" (ethereum.subscriptions/handle-error cofx event) "status.chats.did-change" (chat.loading/load-chats-from-rpc cofx) + "whisper.filter.added" (transport.filters/handle-negotiated-filter cofx event) (log/debug "Event " type " not handled")))) diff --git a/src/status_im/transport/chat/core.cljs b/src/status_im/transport/chat/core.cljs deleted file mode 100644 index 22424e050ea..00000000000 --- a/src/status_im/transport/chat/core.cljs +++ /dev/null @@ -1,18 +0,0 @@ -(ns status-im.transport.chat.core - (:require [status-im.data-store.transport :as transport-store] - [status-im.mailserver.core :as mailserver] - [status-im.utils.fx :as fx])) - -(fx/defn remove-transport-chat - [{:keys [db]} chat-id] - {:db (update db :transport/chats dissoc chat-id) - :data-store/tx [(transport-store/delete-transport-tx chat-id)] - :shh/remove-filters {:filters (map - (fn [filter] - [chat-id filter]) - (get-in db [:transport/filters chat-id]))}}) - -(fx/defn unsubscribe-from-chat - "Unsubscribe from chat on transport layer" - [cofx chat-id] - (remove-transport-chat cofx chat-id)) diff --git a/src/status_im/transport/core.cljs b/src/status_im/transport/core.cljs index 6d2b59c52b5..fa40bcdb656 100644 --- a/src/status_im/transport/core.cljs +++ b/src/status_im/transport/core.cljs @@ -1,33 +1,17 @@ (ns ^{:doc "API to init and stop whisper messaging"} status-im.transport.core - (:require status-im.transport.filters - [re-frame.core :as re-frame] - [status-im.native-module.core :as status] - [status-im.mailserver.core :as mailserver] - [status-im.transport.message.core :as message] - [status-im.transport.partitioned-topic :as transport.topic] - [status-im.contact-code.core :as contact-code] - [status-im.utils.publisher :as publisher] - [status-im.utils.fx :as fx] - [status-im.utils.handlers :as handlers] - [taoensso.timbre :as log] - status-im.transport.shh - [status-im.utils.config :as config])) - -(defn get-public-key-topics [chats] - (keep (fn [[chat-id {:keys [topic sym-key one-to-one]}]] - (cond (and (not sym-key) topic) - {:topic topic - :chat-id chat-id} - - ;; we have to listen the topic to which we are going to send - ;; a message, otherwise the message will not match bloom - (and config/partitioned-topic-enabled? one-to-one) - {:topic (transport.topic/partitioned-topic-hash chat-id) - :chat-id chat-id - :minPow 1 - :callback (constantly nil)})) - chats)) + (:require + [re-frame.core :as re-frame] + [status-im.native-module.core :as status] + [status-im.mailserver.core :as mailserver] + [status-im.transport.message.core :as message] + [status-im.transport.filters.core :as transport.filters] + [status-im.utils.publisher :as publisher] + [status-im.utils.fx :as fx] + [status-im.utils.handlers :as handlers] + [taoensso.timbre :as log] + status-im.transport.shh + [status-im.utils.config :as config])) (defn set-node-info [{:keys [db]} node-info] {:db (assoc db :node-info node-info)}) @@ -46,77 +30,21 @@ (fn [] (fetch-node-info))) +(fx/defn fetch-node-info-fx [cofx] + {::fetch-node-info []}) + (fx/defn init-whisper "Initialises whisper protocol by: - adding fixed shh discovery filter - restoring existing symetric keys along with their unique filters - (optionally) initializing mailserver" [{:keys [db web3] :as cofx}] - (when-let [public-key (get-in db [:account/account :public-key])] - (let [public-key-topics (get-public-key-topics (:transport/chats db)) - discovery-topics (transport.topic/discovery-topics public-key)] - (fx/merge cofx - {:shh/add-discovery-filters - {:web3 web3 - :private-key-id public-key - :topics (concat public-key-topics - (map - (fn [discovery-topic] - {:topic discovery-topic - :chat-id :discovery-topic}) - discovery-topics))} - - ::fetch-node-info [] - :shh/restore-sym-keys-batch - {:web3 web3 - :transport (keep (fn [[chat-id {:keys [topic sym-key] - :as chat}]] - (when (and topic sym-key) - (assoc chat :chat-id chat-id))) - (:transport/chats db)) - :on-success #(re-frame/dispatch [::sym-keys-added %])}} - (publisher/start-fx) - (contact-code/init) - (mailserver/connect-to-mailserver) - (message/resend-contact-messages []))))) - -;;TODO (yenda) remove once go implements persistence -;;Since symkeys are not persisted, we restore them via add sym-keys, -;;this is the callback that is called when a key has been restored for a particular chat. -;;it saves the sym-key-id in app-db to send messages later -;;and starts a filter to receive messages -(handlers/register-handler-fx - ::sym-keys-added - (fn [{:keys [db]} [_ keys]] - (log/debug "PERF" ::sym-keys-added (count keys)) - (let [web3 (:web3 db) - chats (:transport/chats db) - {:keys [updated-chats filters]} - (reduce - (fn [{:keys [updated-chats filters]} chat] - (let [{:keys [chat-id sym-key-id]} chat - {:keys [topic one-to-one]} (get updated-chats chat-id)] - {:updated-chats (assoc-in updated-chats - [chat-id :sym-key-id] sym-key-id) - :filters (conj filters {:sym-key-id sym-key-id - :topic topic - :chat-id chat-id - :one-to-one one-to-one})})) - {:updated-chats chats - :filters []} - keys)] - {:db (assoc db :transport/chats updated-chats) - :shh/add-filters {:web3 web3 - :filters filters}}))) - -;;TODO (yenda) uncomment and rework once go implements persistence -#_(doseq [[chat-id {:keys [sym-key-id topic] :as chat}] transport] - (when sym-key-id - (filters/add-filter! web3 - {:symKeyID sym-key-id - :topics [topic]} - (fn [js-error js-message] - (re-frame/dispatch [:protocol/receive-whisper-message js-error js-message chat-id]))))) + (fx/merge cofx + (fetch-node-info-fx) + (transport.filters/load-filters) + (publisher/start-fx) + (mailserver/connect-to-mailserver) + (message/resend-contact-messages []))) (fx/defn stop-whisper "Stops whisper protocol by removing all existing shh filters @@ -127,11 +55,5 @@ (let [{:transport/keys [filters]} db] (fx/merge cofx - - {:shh/remove-filters {:filters (mapcat (fn [[chat-id chat-filters]] - (map (fn [filter] - [chat-id filter]) - chat-filters)) - filters) - :callback callback}} + (transport.filters/stop-filters callback) (publisher/stop-fx)))) diff --git a/src/status_im/transport/db.cljs b/src/status_im/transport/db.cljs index 5589bfd9a21..b7c4d312f24 100644 --- a/src/status_im/transport/db.cljs +++ b/src/status_im/transport/db.cljs @@ -35,8 +35,7 @@ (spec/def :pairing/installation-id :global/not-empty-string) (spec/def :pairing/device-type :global/not-empty-string) -(spec/def :transport/chat (spec/keys :req-un [::topic] - :opt-un [::sym-key-id ::sym-key ::resend?])) +(spec/def :transport/chat (spec/keys :opt-un [::resend?])) (spec/def :transport/chats (spec/map-of :global/not-empty-string :transport/chat)) (spec/def :transport/filters (spec/map-of :transport/filter-id (spec/coll-of :transport/filter))) @@ -126,15 +125,3 @@ (spec/keys :req-un [:message.text/content]))) (spec/def :message/message (spec/multi-spec content-type :content-type)) - -(defn all-filters-added? - [{:keys [db]}] - (let [filters (set (keys (get db :transport/filters))) - chats (into #{:discovery-topic} - (keys (filter (fn [[chat-id {:keys [topic one-to-one]}]] - (if one-to-one - (and config/partitioned-topic-enabled? - chat-id) - topic)) - (get db :transport/chats))))] - (empty? (sets/difference chats filters)))) diff --git a/src/status_im/transport/filters.cljs b/src/status_im/transport/filters.cljs deleted file mode 100644 index 55bce509178..00000000000 --- a/src/status_im/transport/filters.cljs +++ /dev/null @@ -1,123 +0,0 @@ -(ns ^{:doc "API for whisper filters"} - status-im.transport.filters - (:require [re-frame.core :as re-frame] - [status-im.chat.models :as chat] - [status-im.contact.core :as contact] - [status-im.mailserver.core :as mailserver] - [status-im.transport.utils :as utils] - [status-im.utils.fx :as fx] - [status-im.utils.handlers :as handlers] - [taoensso.timbre :as log])) - -(defn- receive-message [chat-id js-error js-message] - (re-frame/dispatch [:transport/messages-received js-error js-message chat-id])) - -(defn remove-filter! [{:keys [chat-id filter success-callback?] - :or {success-callback? true}}] - (.stopWatching filter - (fn [error _] - (if error - (log/warn :remove-filter-error filter error) - (when success-callback? - (re-frame/dispatch [:shh.callback/filter-removed chat-id]))))) - (log/debug :stop-watching filter)) - -(defn add-filters! - [web3 filters] - (log/debug "PERF" :add-filters (first filters)) - (re-frame/dispatch - [:shh.callback/filters-added - (keep - (fn [{:keys [options callback chat-id]}] - (when-let [filter (.newMessageFilter - (utils/shh web3) - (clj->js (assoc options :allowP2P true)) - callback - #(log/warn :add-filter-error - (.stringify js/JSON (clj->js options)) %))] - {:topic (first (:topics options)) - :chat-id chat-id - :filter filter})) - filters)])) - -(re-frame/reg-fx - :shh/add-filters - (fn [{:keys [web3 filters]}] - (log/debug "PERF" :shh/add-filters) - (let [filters - (reduce - (fn [acc {:keys [sym-key-id topic chat-id]}] - (conj acc - {:options {:topics [topic] - :symKeyID sym-key-id} - :callback (partial receive-message chat-id) - :chat-id chat-id})) - [] - filters)] - (add-filters! web3 filters)))) - -(re-frame/reg-fx - :shh/add-discovery-filters - (fn [{:keys [web3 private-key-id topics]}] - (let [params {:privateKeyID private-key-id}] - (add-filters! - web3 - (map (fn [{:keys [chat-id topic callback minPow]}] - {:options (cond-> (assoc params :topics [topic]) - minPow - (assoc :minPow minPow)) - ;; We don't pass a chat id on discovery-filters as we might receive - ;; messages for multiple chats - :callback (or callback (partial receive-message nil)) - :chat-id chat-id}) topics))))) - -(fx/defn add-filter - [{:keys [db]} chat-id filter] - {:db (update-in db [:transport/filters chat-id] conj filter)}) - -(handlers/register-handler-fx - :shh.callback/filters-added - (fn [{:keys [db] :as cofx} [_ filters]] - (log/debug "PERF" :shh.callback/filters-added) - (let [{:keys [action public-key]} (:filters/after-adding-discovery-filter db) - filters-fx-fns - (mapcat - (fn [{:keys [topic chat-id filter]}] - [(add-filter chat-id filter) - (mailserver/upsert-mailserver-topic {:topic topic - :chat-ids [chat-id]})]) - filters)] - (apply fx/merge cofx - {:db (dissoc db :filters/after-adding-discovery-filter)} - (mailserver/reset-request-to) - (concat - [(when action - (case action - :add-contact - (contact/add-contact public-key) - - :open-chat - (chat/start-chat public-key {:navigation-reset? true})))] - filters-fx-fns - [(mailserver/process-next-messages-request)]))))) - -(handlers/register-handler-fx - :shh.callback/filter-removed - (fn [{:keys [db]} [_ chat-id]] - {:db (update db :transport/filters dissoc chat-id)})) - -(re-frame/reg-fx - :shh/remove-filter - (fn [filters] - (doseq [{:keys [filter] :as params} filters] - (when filter (remove-filter! params))))) - -(re-frame/reg-fx - :shh/remove-filters - (fn [{:keys [filters callback]}] - (doseq [[chat-id filter] filters] - (when filter (remove-filter! - {:chat-id chat-id - :filter filter - :success-callback false}))) - (when callback (callback)))) diff --git a/src/status_im/transport/filters/core.cljs b/src/status_im/transport/filters/core.cljs new file mode 100644 index 00000000000..17604ed02c1 --- /dev/null +++ b/src/status_im/transport/filters/core.cljs @@ -0,0 +1,384 @@ +(ns status-im.transport.filters.core + "This namespace is used to handle filters loading and unloading from statusgo" + (:require + [taoensso.timbre :as log] + [re-frame.core :as re-frame] + [status-im.contact.db :as contact.db] + [status-im.utils.fx :as fx] + [status-im.transport.utils :as utils] + [status-im.data-store.accounts :as data-store.accounts] + [status-im.accounts.model :as accounts.model] + [status-im.utils.handlers :as handlers] + [status-im.native-module.core :as status] + [status-im.mailserver.topics :as mailserver.topics] + [status-im.mailserver.core :as mailserver])) + +;; fx functions + +(defn load-filter-fx [web3 filters] + {:filters/load-filters [[web3 filters]]}) + +(defn remove-filter-fx [filters] + (when (seq filters) + {:filters/remove-filters filters})) + +(defn stop-filter-fx [filters callback] + {:filters/stop-filters [filters callback]}) + +;; dispatches + +(defn filters-added! [filters] + (re-frame/dispatch [:filters.callback/filters-added filters])) + +(defn filters-removed! [filters] + (re-frame/dispatch [:filters.callback/filters-removed filters])) + +(defn- receive-message [chat-id js-error js-message] + (re-frame/dispatch [:transport/messages-received js-error js-message chat-id])) + +;; Mailserver topics + +(fx/defn upsert-mailserver-topic + "Update the topics with the newly created filter" + [cofx {:keys [discovery? + negotiated? + filter-id + topic + chat-id + filter]}] + (mailserver.topics/upsert cofx {:topic topic + :negotiated? negotiated? + :filter-ids #{filter-id} + :discovery? discovery? + :chat-ids #{chat-id}})) + +;; Every time we load a filter, we want to update group chats where the user is a member, has it might be a negotiated filter, so should be included in the request topics +(fx/defn upsert-group-chat-topics + "Update topics for each member of the group chat" + [{:keys [db] :as cofx}] + (let [group-chats (filter (fn [{:keys [group-chat + public?]}] + (and group-chat + (not public?))) + (vals (:chats db)))] + (apply fx/merge + cofx + (map + #(mailserver.topics/upsert-group-chat (:chat-id %) (:members-joined %)) + group-chats)))) + +;; Filter db + + +;; We use two structures for filters: +;; filter/filters -> {"filter-id" filter} which is just a map of filters indexed by filte-id +;; filter/chat-ids -> which is a set of loaded chat-ids, which is set everytime we load +;; a non negotiated filter for a chat. + +(defn loaded? + "Given a filter, check if we already loaded it" + [db {:keys [filter-id] :as f}] + (get-in db [:filter/filters filter-id])) + +(def not-loaded? + (complement loaded?)) + +(defn chat-loaded? + [db chat-id] + (get-in db [:filter/chat-ids chat-id])) + +(defn new-filters? [db filters] + (some + (partial not-loaded? db) + filters)) + +(fx/defn set-raw-filter + "Update filter ids cached and set filter in the db" + [{:keys [db]} {:keys [chat-id negotiated? filter-id] :as filter}] + {:db (cond-> (assoc-in db [:filter/filters filter-id] filter) + ;; We only set non negotiated filters as negotiated filters are not to + ;; be removed + (not negotiated?) + (update :filter/chat-ids (fnil conj #{}) chat-id))}) + +(fx/defn unset-raw-filter + "Remove filter from db and from chat-id" + [{:keys [db]} {:keys [chat-id filter-id]}] + {:db (-> db + (update :filter/chat-ids disj chat-id) + (update :filter/filters dissoc filter-id))}) + +(fx/defn add-filter-to-db + "Set the filter in the db and upsert a mailserver topic" + [{:keys [db] :as cofx} filter] + (when-not (loaded? db filter) + (fx/merge cofx + (set-raw-filter filter) + (upsert-mailserver-topic filter)))) + +(fx/defn remove-filter-from-db + "Remve the filter from the db" + [cofx filter] + (fx/merge cofx + (unset-raw-filter filter))) + +(fx/defn add-filters-to-db [cofx filters] + (apply fx/merge cofx (map add-filter-to-db filters))) + +(fx/defn remove-filters-from-db [cofx filters] + (apply fx/merge cofx (map remove-filter-from-db filters))) + +(defn non-negotiated-filters-for-chat-id + "Returns all the non-negotiated filters matching chat-id" + [db chat-id] + (filter + (fn [{:keys [negotiated? + filter-id] :as f}] + (and (= chat-id + (:chat-id f)) + (not negotiated?))) + (vals (:filter/filters db)))) + +;; Filter requests + +(defn- ->remove-filter-request [{:keys [id filter-id filter]}] + {:chatId id + :filterId filter-id}) + +(defn- ->filter-request + "Transform input in a filter-request. For a group chat we need a filter-request + for each member." + [{:keys [chat-id + group-chat + members-joined + public?]}] + (cond + (not group-chat) + [{:ChatID chat-id + :OneToOne true + :Identity (subs chat-id 2)}] + public? + [{:ChatID chat-id + :OneToOne false}] + :else + (mapcat #(->filter-request {:chat-id %}) members-joined))) + +(defn- chats->filter-requests + "Convert a list of active chats to filter requests" + [chats] + (->> chats + (filter :is-active) + (mapcat ->filter-request))) + +(defn- contacts->filter-requests + [contacts] + "Convert added contacts to filter requests" + (->> contacts + (filter contact.db/added?) + (map #(hash-map :chat-id (:public-key %))) + (mapcat ->filter-request))) + +;; shh filters + +(defn build-filter + "Create a raw filter from a filter response" + [web3 {:keys [filter-id + discovery? + negotiated? + chat-id] :as f}] + (let [shh-filter (.newRawMessageFilter + (utils/shh web3) + (clj->js {:allowP2P true + :filterId filter-id}) + ;; We set chat-id to nil on discovery or negotiated + ;; as we have multiple people sending on discovery and pairing + ;; messages on negotiated + (partial receive-message (if (or discovery? negotiated?) nil chat-id)))] + (assoc f :filter shh-filter))) + +(defn- add-filters! + [web3 filters] + (log/debug "PERF" :add-raw-filters filters) + (filters-added! + (map (partial build-filter web3) filters))) + +(defn- responses->filters [{:keys [negotiated + discovery + filterId + chatId + topic + identity]}] + {:chat-id (if (not= identity "") (str "0x" identity) chatId) + :id chatId + :filter-id filterId + :negotiated? negotiated + :discovery? discovery + :topic topic}) + +(fx/defn set-filters-initialized [{:keys [db]}] + {:db (assoc db :filters/initialized true)}) + +(defn filters-initialized? [db] + (:filters/initialized db)) + +(fx/defn handle-filters-added + "Called every time we load a filter from statusgo, either from explicit call + or through signals. It stores the filter in the db and upsert the relevant + mailserver topics." + [{:keys [db] :as cofx} filters] + (fx/merge cofx + (mailserver/reset-request-to) + (add-filters-to-db filters) + (upsert-group-chat-topics) + (when (new-filters? db filters) + (mailserver/process-next-messages-request)) + (set-filters-initialized))) + +(fx/defn handle-filters-removed + "Called when we remove a filter from status-go, it will update the mailserver + topics" + [cofx filters] + (fx/merge cofx + (remove-filters-from-db filters) + (mailserver.topics/delete-many filters) + (mailserver/process-next-messages-request))) + +;; Public functions + +(fx/defn handle-negotiated-filter + "Check if it's a new filter, if so create an shh filter and process it" + [{:keys [db] :as cofx} {:keys [filters]}] + (let [processed-filters (map responses->filters filters) + new-filters (filter + (partial not-loaded? db) + processed-filters)] + (when (seq new-filters) + {:filters/add-raw-filters + {:web3 (get-in cofx [:db :web3]) + :filters new-filters}}))) + +(fx/defn load-filters + "Load all contacts and chats as filters" + [{:keys [db]}] + (log/debug "loading filters") + (let [chats (vals (:chats db)) + contacts (vals (:contacts/contacts db)) + filters (concat + (chats->filter-requests chats) + (contacts->filter-requests contacts))] + (load-filter-fx (:web3 db) filters))) + +(defn stop-watching! [filters] + (doseq [f filters] + (.stopWatching f (constantly nil)))) + +(fx/defn stop-filters + "Stop all filters" + [{:keys [db]} callback] + (let [filters (map :filter (vals + (:filter/filters db)))] + (stop-filter-fx filters callback))) + +;; Load functions: utility function to load filters + +(fx/defn load-chat + "Check if a filter already exists for that chat, otherw load the filter" + [{:keys [db]} chat-id] + (when (and (filters-initialized? db) + (not (chat-loaded? db chat-id))) + (let [chat (get-in db [:chats chat-id])] + (load-filter-fx (:web3 db) (->filter-request chat))))) + +(fx/defn load-contact + "Check if we already have a filter for that contact, otherwise load the filter + if the contact has been added" + [{:keys [db]} contact] + (when-not (chat-loaded? db (:public-key contact)) + (load-filter-fx (:web3 db) (contacts->filter-requests [contact])))) + +(fx/defn load-member + "Check if we already have a filter for that member, otherwise load the filter, regardless of whether is in our contacts" + [{:keys [db]} public-key] + (when-not (chat-loaded? db public-key) + (load-filter-fx (:web3 db) (->filter-request {:chat-id public-key})))) + +(fx/defn load-members + "Load multiple members" + [cofx members] + (apply fx/merge cofx (map load-member members))) + +(fx/defn stop-listening + "We can stop listening to contact codes when we don't have any active chat + with the user (one-to-one or group-chat), and it is not in our contacts" + [{:keys [db] :as cofx} chat-id] + (let [my-public-key (accounts.model/current-public-key cofx) + one-to-one? (not (get-in db [:chats chat-id :group-chat])) + public? (get-in db [:chats chat-id :public?]) + active-group-chats (filter (fn [{:keys [is-active members members-joined]}] + (and is-active + (contains? members-joined my-public-key) + (contains? members chat-id))) + (vals (:chats db)))] + (when + (or public? + (and one-to-one? + (not (contact.db/active? db chat-id)) + (not= my-public-key chat-id) + (not (get-in db [:chats chat-id :is-active])) + (empty? active-group-chats))) + (fx/merge + cofx + ;; we exclude the negotiated filters as those are not to be removed + ;; otherwise we might miss messages + (remove-filter-fx + (non-negotiated-filters-for-chat-id db chat-id)))))) + +;; reg-fx + +(handlers/register-handler-fx + :filters.callback/filters-added + (fn [{:keys [db] :as cofx} [_ filters]] + (log/debug "PERF" :filters.callback/filters-added) + (handle-filters-added cofx filters))) + +(handlers/register-handler-fx + :filters.callback/filters-removed + (fn [{:keys [db] :as cofx} [_ filters]] + (handle-filters-removed cofx filters))) + +(re-frame/reg-fx + :filters/add-raw-filters + (fn [{:keys [web3 filters]}] + (log/debug "PERF" :filters/add-raw-filters) + (add-filters! web3 filters))) + +;; Here we stop first polling and then we hit status-go, otherwise it would throw +;; an error trying to poll from a delete filter. If we fail to remove the filter though +;; we should recreate it. +(re-frame/reg-fx + :filters/remove-filters + (fn [filters] + (log/debug "removing filters" filters) + (stop-watching! (map :filter filters)) + (status/remove-filters + (map ->remove-filter-request filters) + (handlers/response-handler #(filters-removed! filters) + #(log/error "remove-filters: failed error" %))))) + +(re-frame/reg-fx + :filters/stop-filters + (fn [[filters callback]] + (stop-watching! filters) + (callback))) + +(re-frame/reg-fx + :filters/load-filters + (fn [ops] + (when (seq ops) + (let [web3 (first (peek ops)) + filters (mapcat peek ops)] + (status/load-filters + filters + (handlers/response-handler #(add-filters! web3 + (map responses->filters %)) + #(log/error "load-filters: failed error" %))))))) diff --git a/src/status_im/transport/message/contact.cljs b/src/status_im/transport/message/contact.cljs index c9ce2920591..e32ce4d4ce6 100644 --- a/src/status_im/transport/message/contact.cljs +++ b/src/status_im/transport/message/contact.cljs @@ -21,11 +21,3 @@ (validate [this] (when (spec/valid? :message/contact-update this) this))) - -(fx/defn remove-chat-filter - "Stops the filter for the given chat-id" - [{:keys [db]} chat-id] - (when-let [filters (get-in db [:transport/filters chat-id])] - {:shh/remove-filters - {:filters (map (fn [filter] [chat-id filter]) filters)}})) - diff --git a/src/status_im/transport/message/core.cljs b/src/status_im/transport/message/core.cljs index ec3952f7eef..ba260bb5b21 100644 --- a/src/status_im/transport/message/core.cljs +++ b/src/status_im/transport/message/core.cljs @@ -55,9 +55,12 @@ %))) (catch :default e nil))))) ; ignore unknown message types -(defn- js-array->seq [array] - (for [i (range (.-length array))] - (aget array i))) +(defn- js-obj->seq [obj] + ;; Sometimes the filter will return a single object instead of a collection + (if (array? obj) + (for [i (range (.-length obj))] + (aget obj i)) + [obj])) (fx/defn receive-whisper-messages [{:keys [now] :as cofx} js-error js-messages chat-id] @@ -66,7 +69,7 @@ (let [now-in-s (quot now 1000) receive-message-fxs (map (fn [message] (receive-message now-in-s chat-id message)) - (js-array->seq js-messages))] + (js-obj->seq js-messages))] (apply fx/merge cofx receive-message-fxs)) (log/error "Something went wrong" js-error js-messages))) diff --git a/src/status_im/transport/message/protocol.cljs b/src/status_im/transport/message/protocol.cljs index a776dd0cb4e..5d993a16af4 100644 --- a/src/status_im/transport/message/protocol.cljs +++ b/src/status_im/transport/message/protocol.cljs @@ -2,15 +2,24 @@ status-im.transport.message.protocol (:require [cljs.spec.alpha :as spec] [status-im.accounts.model :as accounts.model] + [status-im.constants :as constants] [status-im.ethereum.core :as ethereum] [status-im.transport.db :as transport.db] - [status-im.transport.partitioned-topic :as transport.topic] + [status-im.data-store.transport :as transport-store] [status-im.transport.utils :as transport.utils] [status-im.tribute-to-talk.whitelist :as whitelist] [status-im.utils.config :as config] [status-im.utils.fx :as fx] [taoensso.timbre :as log])) +(defn has-paired-installations? [cofx] + (->> + (get-in cofx [:db :pairing/installations]) + vals + (some :enabled?))) + +(defn discovery-topic-hash [] (transport.utils/get-topic constants/contact-discovery)) + (defprotocol StatusMessage "Protocol for the messages that are sent through the transport layer" (send [this chat-id cofx] "Method producing all effects necessary for sending the message record") @@ -26,16 +35,22 @@ :powTime config/pow-time}) (fx/defn init-chat - "Initialises chat on protocol layer. - If topic is not passed as argument it is derived from `chat-id`" + "Initialises chat on protocol layer." [{:keys [db now]} - {:keys [chat-id topic one-to-one resend?]}] - {:db (assoc-in db - [:transport/chats chat-id] - (transport.db/create-chat {:topic topic - :one-to-one one-to-one - :resend? resend? - :now now}))}) + {:keys [chat-id resend?]}] + (let [transport-chat (transport.db/create-chat {:resend? resend?})] + {:db (assoc-in db + [:transport/chats chat-id] + transport-chat) + + :data-store/tx [(transport-store/save-transport-tx {:chat-id chat-id + :chat transport-chat})]})) + +(fx/defn remove-chat + [{:keys [db]} chat-id] + (when (get-in db [:transport/chats chat-id]) + {:db (update db :transport/chats dissoc chat-id) + :data-store/tx [(transport-store/delete-transport-tx chat-id)]})) (defn send-public-message "Sends the payload to topic" @@ -47,21 +62,6 @@ :chat chat-id :payload payload}]})) -(fx/defn send-with-sym-key - "Sends the payload using symetric key and topic from db (looked up by `chat-id`)" - [{:keys [db] :as cofx} {:keys [payload chat-id success-event]}] - ;; we assume that the chat contains the contact public-key - (let [{:keys [web3]} db - {:keys [sym-key-id topic]} (get-in db [:transport/chats chat-id])] - {:shh/post [{:web3 web3 - :success-event success-event - :message (merge {:sig (accounts.model/current-public-key cofx) - :symKeyID sym-key-id - :payload payload - :topic (or topic - (transport.topic/public-key->discovery-topic-hash chat-id))} - whisper-opts)}]})) - (fx/defn send-direct-message "Sends the payload using to dst" [{:keys [db] :as cofx} dst success-event payload] @@ -70,7 +70,6 @@ :success-event success-event :src (accounts.model/current-public-key cofx) :dst dst - :topics (:mailserver/topics db) :payload payload}]})) (fx/defn send-with-pubkey @@ -78,16 +77,12 @@ [{:keys [db] :as cofx} {:keys [payload chat-id success-event]}] (let [{:keys [web3]} db] (let [pfs? (get-in db [:account/account :settings :pfs?])] - (if (and config/pfs-toggle-visible? pfs?) + (if pfs? (send-direct-message cofx chat-id success-event payload) - (let [partitioned-topic-hash (transport.topic/public-key->discovery-topic-hash chat-id) - topics (db :mailserver/topics) - topic-hash (if (contains? topics partitioned-topic-hash) - partitioned-topic-hash - (transport.topic/discovery-topic-hash))] + (let [topic-hash (discovery-topic-hash)] {:shh/post [{:web3 web3 :success-event success-event :message (merge {:sig (accounts.model/current-public-key cofx) @@ -108,11 +103,12 @@ message-type]}] (case message-type :public-group-user-message - (send-with-sym-key cofx params) + (send-public-message cofx chat-id (:success-event params) this) :user-message (fx/merge cofx - (send-direct-message current-public-key nil this) + (when (has-paired-installations? cofx) + (send-direct-message current-public-key nil this)) (send-with-pubkey params))))) (receive [this chat-id signature timestamp cofx] (let [received-message-fx {:chat-received-message/add-fx diff --git a/src/status_im/transport/message/public_chat.cljs b/src/status_im/transport/message/public_chat.cljs deleted file mode 100644 index 8c21a38fe61..00000000000 --- a/src/status_im/transport/message/public_chat.cljs +++ /dev/null @@ -1,43 +0,0 @@ -(ns ^{:doc "Public chat API"} - status-im.transport.message.public-chat - (:require [re-frame.core :as re-frame] - [status-im.data-store.transport :as transport-store] - [status-im.transport.message.protocol :as protocol] - [status-im.transport.utils :as transport.utils] - [status-im.utils.fx :as fx] - [status-im.utils.handlers :as handlers])) - -(defn- has-already-joined? [{:keys [db]} chat-id] - (get-in db [:transport/chats chat-id])) - -(fx/defn join-public-chat - "Function producing all protocol level effects necessary for joining public chat identified by chat-id" - [{:keys [db] :as cofx} chat-id] - (when-not (has-already-joined? cofx chat-id) - (let [on-success (fn [sym-key sym-key-id] - (re-frame/dispatch [::add-new-sym-key {:chat-id chat-id - :sym-key sym-key - :sym-key-id sym-key-id}]))] - (fx/merge cofx - {:shh/generate-sym-key-from-password [{:web3 (:web3 db) - :password chat-id - :on-success on-success}]} - (protocol/init-chat {:chat-id chat-id - :topic (transport.utils/get-topic chat-id)}))))) - -(handlers/register-handler-fx - ::add-new-sym-key - (fn [{:keys [db]} [_ {:keys [sym-key-id sym-key chat-id]}]] - (let [{:keys [web3]} db - topic (transport.utils/get-topic chat-id)] - {:db (assoc-in db [:transport/chats chat-id :sym-key-id] sym-key-id) - :shh/add-filters {:web3 web3 - :filters [{:sym-key-id sym-key-id - :topic topic - :chat-id chat-id}]} - :data-store/tx [(transport-store/save-transport-tx - {:chat-id chat-id - :chat (-> (get-in db [:transport/chats chat-id]) - (assoc :sym-key-id sym-key-id) - ;;TODO (yenda) remove once go implements persistence - (assoc :sym-key sym-key))})]}))) diff --git a/src/status_im/transport/partitioned_topic.cljs b/src/status_im/transport/partitioned_topic.cljs deleted file mode 100644 index 34e3aa37292..00000000000 --- a/src/status_im/transport/partitioned_topic.cljs +++ /dev/null @@ -1,60 +0,0 @@ -(ns status-im.transport.partitioned-topic - (:require [status-im.utils.random :as random] - [status-im.transport.utils :as utils] - [status-im.constants :as constants] - [status-im.utils.config :as config])) - -;; Number of different personal topics -(def n-partitions 5000) - -(defn expected-number-of-collisions - "Expected number of topic collision given the number of expected users, - we want this value to be greater than a threshold to avoid positive - identification given the attacker has a topic & public key. - Used only for safety-checking n-partitions. - - https://en.wikipedia.org/wiki/Birthday_problem#Collision_counting" - [total-users] - (+ - (- total-users n-partitions) - (* n-partitions - (js/Math.pow - (/ - (- n-partitions 1) - n-partitions) - total-users)))) - -(defn- partitioned-topic - [public-key] - (let [gen (random/rand-gen public-key)] - (-> (random/seeded-rand-int gen n-partitions) - (str "-discovery")))) - -(defn partitioned-topic-hash - "Given a public key return a partitioned topic between 0 and n" - [public-key] - (-> public-key - partitioned-topic - utils/get-topic)) - -(def discovery-topic constants/contact-discovery) -(defn discovery-topic-hash [] (utils/get-topic constants/contact-discovery)) - -(defn public-key->discovery-topic - [public-key] - (if config/partitioned-topic-enabled? - (partitioned-topic public-key) - constants/contact-discovery)) - -(defn public-key->discovery-topic-hash - [public-key] - (if config/partitioned-topic-enabled? - (partitioned-topic-hash public-key) - (discovery-topic-hash))) - -(defn discovery-topics [public-key] - [(partitioned-topic-hash public-key) (discovery-topic-hash)]) - -(defn contains-topic? - [available-topics topic] - (contains? available-topics (utils/get-topic topic))) diff --git a/src/status_im/transport/shh.cljs b/src/status_im/transport/shh.cljs index aac2270328c..fd606334e7b 100644 --- a/src/status_im/transport/shh.cljs +++ b/src/status_im/transport/shh.cljs @@ -3,45 +3,9 @@ (:require [re-frame.core :as re-frame] [status-im.ethereum.core :as ethereum] [status-im.transport.message.transit :as transit] - [status-im.transport.partitioned-topic :as transport.topic] [status-im.transport.utils :as transport.utils] [taoensso.timbre :as log])) -(defn get-new-key-pair [{:keys [web3 on-success on-error]}] - (if web3 - (.. web3 - -shh - (newKeyPair (fn [err resp] - (if-not err - (on-success resp) - (on-error err))))) - (on-error "web3 not available."))) - -(re-frame/reg-fx - :shh/get-new-key-pair - (fn [{:keys [web3 success-event error-event]}] - (get-new-key-pair {:web3 web3 - :on-success #(re-frame/dispatch [success-event %]) - :on-error #(re-frame/dispatch [error-event %])}))) - -(defn get-public-key [{:keys [web3 key-pair-id on-success on-error]}] - (if (and web3 key-pair-id) - (.. web3 - -shh - (getPublicKey key-pair-id (fn [err resp] - (if-not err - (on-success resp) - (on-error err))))) - (on-error "web3 or key-pair id not available."))) - -(re-frame/reg-fx - :shh/get-public-key - (fn [{:keys [web3 key-pair-id success-event error-event]}] - (get-public-key {:web3 web3 - :key-pair-id key-pair-id - :on-success #(re-frame/dispatch [success-event %]) - :on-error #(re-frame/dispatch [error-event %])}))) - (defn generate-sym-key-from-password [{:keys [web3 password on-success on-error]}] (.. web3 @@ -79,15 +43,10 @@ (re-frame/reg-fx :shh/send-direct-message (fn [post-calls] - (doseq [{:keys [web3 payload src dst success-event error-event topics] + (doseq [{:keys [web3 payload src dst success-event error-event] :or {error-event :transport/send-status-message-error}} post-calls] - (let [part-topic-hash (transport.topic/public-key->discovery-topic-hash dst) - topic (if (contains? topics part-topic-hash) - (transport.topic/public-key->discovery-topic dst) - transport.topic/discovery-topic) - direct-message {:pubKey dst + (let [direct-message {:pubKey dst :sig src - :chat topic :payload payload}] (send-direct-message! web3 direct-message success-event error-event 1))))) @@ -95,30 +54,28 @@ :shh/send-pairing-message (fn [params] (let [{:keys [web3 payload src success-event error-event] - :or {error-event :protocol/send-status-message-error}} params + :or {error-event :transport/send-status-message-error}} params message (clj->js {:sig src - :chat (transport.topic/public-key->discovery-topic src) + :pubKey src + ;; Send to any device + :DH true :payload (-> payload transit/serialize ethereum/utf8-to-hex)})] (.. web3 -shh - (sendPairingMessage + (sendDirectMessage message (handle-response success-event error-event 1)))))) (re-frame/reg-fx :shh/send-group-message (fn [params] - (let [{:keys [web3 payload src dsts success-event error-event available-topics] + (let [{:keys [web3 payload src dsts success-event error-event] :or {error-event :transport/send-status-message-error}} params] (doseq [{:keys [public-key chat]} dsts] - (let [topic (if (transport.topic/contains-topic? available-topics chat) - chat - transport.topic/discovery-topic) - message + (let [message (clj->js {:pubKey public-key - :chat topic :sig src :payload (-> payload transit/serialize @@ -162,40 +119,6 @@ #(log/debug :shh/post-success)) :on-error #(re-frame/dispatch [error-event %])})))) -(defn add-sym-key - [{:keys [web3 sym-key on-success on-error]}] - (.. web3 - -shh - (addSymKey sym-key (fn [err resp] - (if-not err - (on-success resp) - (on-error err)))))) - -(defn add-sym-keys-batch - [{:keys [web3 keys on-success on-error]}] - (let [batch (.createBatch web3) - results (atom []) - total (count keys) - counter (atom 0) - callback (fn [chat-id sym-key err resp] - (swap! counter inc) - (if err - (on-error err) - (swap! results conj {:chat-id chat-id - :sym-key sym-key - :sym-key-id resp})) - (when (= @counter total) - (on-success @results)))] - (log/debug "PERF" :add-sym-key-batch total) - (doseq [{:keys [chat-id sym-key]} keys] - (let [request (.. web3 - -shh - -addSymKey - (request sym-key - (partial callback chat-id sym-key)))] - (.add batch request))) - (.execute batch))) - (defn get-sym-key [{:keys [web3 sym-key-id on-success on-error]}] (.. web3 @@ -205,54 +128,9 @@ (on-success resp) (on-error err)))))) -(defn new-sym-key - [{:keys [web3 on-success on-error]}] - (.. web3 - -shh - (newSymKey (fn [err resp] - (if-not err - (on-success resp) - (on-error err)))))) - (defn log-error [error] (log/error :shh/get-new-sym-key-error error)) -;;TODO (yenda) remove once go implements persistence -(re-frame/reg-fx - :shh/restore-sym-keys-batch - (fn [{:keys [web3 transport on-success]}] - (log/debug "PERF" :shh/restore-sym-keys-batch (.now js/Date)) - (add-sym-keys-batch {:web3 web3 - :keys transport - :on-success on-success - :on-error log-error}))) - -(defn add-new-sym-key [{:keys [web3 sym-key on-success]}] - (add-sym-key {:web3 web3 - :sym-key sym-key - :on-success (fn [sym-key-id] - (on-success sym-key sym-key-id)) - :on-error log-error})) - -(re-frame/reg-fx - :shh/add-new-sym-keys - (fn [args] - (doseq [add-new-sym-key-params args] - (add-new-sym-key add-new-sym-key-params)))) - -(re-frame/reg-fx - :shh/get-new-sym-keys - (fn [args] - (doseq [{:keys [web3 on-success]} args] - (new-sym-key {:web3 web3 - :on-success (fn [sym-key-id] - (get-sym-key {:web3 web3 - :sym-key-id sym-key-id - :on-success (fn [sym-key] - (on-success sym-key sym-key-id)) - :on-error log-error})) - :on-error log-error})))) - (re-frame/reg-fx :shh/generate-sym-key-from-password (fn [args] diff --git a/src/status_im/ui/screens/desktop/main/tabs/profile/views.cljs b/src/status_im/ui/screens/desktop/main/tabs/profile/views.cljs index 5bb2dee2806..7cea1d9bc75 100644 --- a/src/status_im/ui/screens/desktop/main/tabs/profile/views.cljs +++ b/src/status_im/ui/screens/desktop/main/tabs/profile/views.cljs @@ -214,12 +214,12 @@ [logging-display] [react/view {:style styles/title-separator}] - [react/text {:style styles/adv-settings-subtitle} (i18n/label :t/pfs)] + [react/text {:style styles/adv-settings-subtitle} (i18n/label :t/device-to-device)] [react/view {:style (styles/profile-row false)} - [react/text {:style (styles/profile-row-text colors/black)} (i18n/label :t/pfs)] + [react/text {:style (styles/profile-row-text colors/black)} (i18n/label :t/device-to-device)] [react/switch {:track-color #js {:true colors/blue :false nil} :value pfs? - :on-value-change #(re-frame/dispatch [:accounts.ui/toggle-pfs (not pfs?)])}]]]))) + :on-value-change #(re-frame/dispatch [:accounts.ui/toggle-device-to-device (not pfs?)])}]]]))) (views/defview installations [] (views/letsubs [installations [:pairing/installations] diff --git a/src/status_im/ui/screens/profile/user/views.cljs b/src/status_im/ui/screens/profile/user/views.cljs index 3087b586894..f164bd446e2 100644 --- a/src/status_im/ui/screens/profile/user/views.cljs +++ b/src/status_im/ui/screens/profile/user/views.cljs @@ -216,13 +216,13 @@ {:label-kw :t/bootnodes :action-fn #(re-frame/dispatch [:navigate-to :bootnodes-settings]) :accessibility-label :bootnodes-settings-button}]) - (when (and dev-mode? config/pfs-toggle-visible?) + (when dev-mode? [profile.components/settings-item-separator]) - (when (and dev-mode? config/pfs-toggle-visible?) + (when dev-mode? [profile.components/settings-switch-item - {:label-kw :t/pfs + {:label-kw :t/device-to-device :value (:pfs? settings) - :action-fn #(re-frame/dispatch [:accounts.ui/toggle-pfs %])}]) + :action-fn #(re-frame/dispatch [:accounts.ui/toggle-device-to-device %])}]) [profile.components/settings-item-separator] [profile.components/settings-switch-item {:label-kw :t/dev-mode diff --git a/src/status_im/utils/config.cljs b/src/status_im/utils/config.cljs index 77b981c0b88..6746543c8fd 100644 --- a/src/status_im/utils/config.cljs +++ b/src/status_im/utils/config.cljs @@ -23,9 +23,7 @@ (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"))) (def pairing-popup-disabled? (enabled? (get-config :PAIRING_POPUP_DISABLED "0"))) -(def pfs-toggle-visible? (enabled? (get-config :PFS_TOGGLE_VISIBLE "0"))) (def cached-webviews-enabled? (enabled? (get-config :CACHED_WEBVIEWS_ENABLED 0))) (def rn-bridge-threshold-warnings-enabled? (enabled? (get-config :RN_BRIDGE_THRESHOLD_WARNINGS 0))) (def extensions-enabled? (enabled? (get-config :EXTENSIONS 0))) @@ -33,7 +31,6 @@ (def hardwallet-enabled? (enabled? (get-config :HARDWALLET_ENABLED 0))) (def dev-build? (enabled? (get-config :DEV_BUILD 0))) (def erc20-contract-warnings-enabled? (enabled? (get-config :ERC20_CONTRACT_WARNINGS))) -(def partitioned-topic-enabled? (enabled? (get-config :PARTITIONED_TOPIC "0"))) (def tr-to-talk-enabled? (enabled? (get-config :TRIBUTE_TO_TALK 0))) (def max-message-delivery-attempts (js/parseInt (get-config :MAX_MESSAGE_DELIVERY_ATTEMPTS "6"))) (def contract-nodes-enabled? (enabled? (get-config :CONTRACT_NODES "0"))) @@ -53,5 +50,4 @@ (def default-network (get-config :DEFAULT_NETWORK)) (def pow-target (js/parseFloat (get-config :POW_TARGET "0.002"))) (def pow-time (js/parseInt (get-config :POW_TIME "1"))) -(def use-sym-key (enabled? (get-config :USE_SYM_KEY 0))) (def max-installations 2) diff --git a/src/status_im/utils/fx.cljs b/src/status_im/utils/fx.cljs index 1f7e5494ef6..a65e81aa0e4 100644 --- a/src/status_im/utils/fx.cljs +++ b/src/status_im/utils/fx.cljs @@ -11,7 +11,7 @@ (def ^:private mergable-keys #{:data-store/tx :data-store/base-tx :chat-received-message/add-fx - :shh/add-new-sym-keys :shh/get-new-sym-keys :shh/post + :shh/post :filters/load-filters :shh/send-direct-message :shh/remove-filter :shh/generate-sym-key-from-password :transport/confirm-messages-processed :group-chats/extract-membership-signature :utils/dispatch-later :json-rpc/call}) diff --git a/src/status_im/utils/publisher.cljs b/src/status_im/utils/publisher.cljs index cae8201f1fd..259a850bc1c 100644 --- a/src/status_im/utils/publisher.cljs +++ b/src/status_im/utils/publisher.cljs @@ -2,7 +2,6 @@ (:require [re-frame.core :as re-frame] [re-frame.db] [status-im.accounts.update.publisher :as accounts] - [status-im.contact-code.core :as contact-code] [status-im.utils.async :as async-util] [status-im.utils.datetime :as datetime] [status-im.utils.fx :as fx])) @@ -21,7 +20,6 @@ :now (datetime/timestamp) :db @re-frame.db/app-db}] (accounts/publish-update! cofx) - (contact-code/publish! cofx) (done-fn))) sync-interval-ms sync-timeout-ms))) diff --git a/test/cljs/status_im/test/chat/models.cljs b/test/cljs/status_im/test/chat/models.cljs index 412fbd50544..82fcde5a63e 100644 --- a/test/cljs/status_im/test/chat/models.cljs +++ b/test/cljs/status_im/test/chat/models.cljs @@ -139,13 +139,10 @@ (is (:shh/post actual)) (testing "it does not remove transport, only after send is successful" (is (get-in actual [:db :transport/chats chat-id]))))) - (testing "it does not remove it from transport if it's a one-to-one" - (let [actual (chat/remove-chat cofx chat-id)] - (is (get-in actual [:db :transport/chats chat-id])))) (testing "it adds the relevant transactions for realm" (let [actual (chat/remove-chat cofx chat-id)] (is (:data-store/tx actual)) - (is (= 8 (count (:data-store/tx actual)))))))) + (is (= 6 (count (:data-store/tx actual)))))))) (deftest multi-user-chat? (let [chat-id "1"] diff --git a/test/cljs/status_im/test/chat/models/message.cljs b/test/cljs/status_im/test/chat/models/message.cljs index 47d97656297..173423bd5fd 100644 --- a/test/cljs/status_im/test/chat/models/message.cljs +++ b/test/cljs/status_im/test/chat/models/message.cljs @@ -236,3 +236,26 @@ (get-in fx2 [:db :chats "chat-id" :messages]))) (is (= {} (get-in fx2 [:db :chats "chat-id" :message-groups])))))) + +(deftest add-outgoing-status + (testing "coming from us" + (testing "system-message" + (let [message (message/add-outgoing-status {:message-type :system-message + :from "us"} "us")] + (is (not (:outgoing message))) + (is (not (:outgoing-status message))))) + (testing "has already a an outgoing status" + (testing "it does not override it" + (let [message (message/add-outgoing-status {:outgoing-status :sending + :from "us"} "us")] + (is (:outgoing message)) + (is (= :sending (:outgoing-status message)))))) + (testing "does not have an outgoing status" + (testing "it sets it to sent" + (let [message (message/add-outgoing-status {:from "us"} "us")] + (is (:outgoing message)) + (is (= :sent (:outgoing-status message))))))) + (testing "not coming from us" + (let [message (message/add-outgoing-status {:from "not-us"} "us")] + (is (not (:outgoing message))) + (is (not (:outgoing-status message)))))) diff --git a/test/cljs/status_im/test/contact_code/core.cljs b/test/cljs/status_im/test/contact_code/core.cljs deleted file mode 100644 index cc5313200aa..00000000000 --- a/test/cljs/status_im/test/contact_code/core.cljs +++ /dev/null @@ -1,79 +0,0 @@ -(ns status-im.test.contact-code.core - (:require [cljs.test :refer-macros [deftest is testing]] - [status-im.contact-code.core :as contact-code])) - -(def me "me") -(def member-1 "member-1") -(def member-1-topic "member-1-contact-code") -(def member-2 "member-2") -(def member-2-topic "member-2-contact-code") -(def chat-id "chat-id") -(def chat-id-topic "chat-id-contact-code") - -(deftest listen-to-chat - (testing "an inactive chat" - (testing "it does nothing" - (is (not (contact-code/listen-to-chat {:db {}} chat-id))))) - (testing "an active 1-to-1 chat" - (testing "it listen to the topic" - (is (get-in - (contact-code/listen-to-chat {:db {:chats {chat-id {:is-active true}}}} - chat-id) - [:db :transport/chats chat-id-topic])))) - (testing "an active group chat" - (testing "it listen to any member" - (let [transport (get-in - (contact-code/listen-to-chat {:db {:chats {chat-id - {:is-active true - :group-chat true - :members #{member-1 - member-2}}}}} - chat-id) - [:db :transport/chats])] - (is (not (get transport chat-id-topic))) - (is (get transport member-1-topic)) - (is (get transport member-2-topic)))))) - -(deftest stop-listening - (testing "the user is in our contacts" - (testing "it does not remove transport" - (is (not (contact-code/stop-listening - {:db {:contacts/contacts - {chat-id {:system-tags #{:contact/added}}}}} - chat-id))))) - (testing "the user is not in our contacts" - (testing "the user is not in any group chats or 1-to1-" - (testing "it removes the transport" - (let [transport (contact-code/stop-listening {:db {:transport/chats - {chat-id-topic {}}}} - chat-id)] - (is transport) - (is (not (get transport chat-id-topic)))))) - (testing "the user is still in some group chats" - (testing "we joined, and group chat is active it does not remove transport" - (let [transport (contact-code/stop-listening {:db {:account/account {:public-key me} - :chats - {chat-id {:is-active true - :members-joined #{me} - :members #{member-1}}} - :transport/chats - {member-1-topic {}}}} - member-1)] - (is (not transport)))) - (testing "we didn't join, it removes transport" - (let [transport (contact-code/stop-listening {:db {:account/account {:public-key me} - :chats - {chat-id {:is-active true - :members-joined #{member-1} - :members #{member-1}}} - :transport/chats - {member-1-topic {}}}} - member-1)] - (is transport) - (is (not (get transport member-1-topic)))))) - (testing "we have a 1-to-1 chat with the user" - (testing "it does not remove transport" - (let [transport (contact-code/stop-listening {:db {:chats - {member-1 {:is-active true}}}} - member-1)] - (is (not transport))))))) diff --git a/test/cljs/status_im/test/mailserver/core.cljs b/test/cljs/status_im/test/mailserver/core.cljs index 9e54c9386d4..94e77ee77a0 100644 --- a/test/cljs/status_im/test/mailserver/core.cljs +++ b/test/cljs/status_im/test/mailserver/core.cljs @@ -2,6 +2,7 @@ (:require [cljs.test :refer-macros [deftest is testing]] [status-im.transport.utils :as utils] [status-im.mailserver.core :as mailserver] + [status-im.mailserver.constants :as constants] [status-im.utils.random :as rand])) (def enode "enode://08d8eb6177b187049f6c97ed3f6c74fbbefb94c7ad10bafcaf4b65ce89c314dcfee0a8bc4e7a5b824dfa08b45b360cc78f34f0aff981f8386caa07652d2e601b@163.172.177.138:40404") @@ -349,7 +350,7 @@ (is (= :connecting (get-in (mailserver/resend-request {:db {:mailserver/current-request - {:attempts mailserver/maximum-number-of-attempts}}} + {:attempts constants/maximum-number-of-attempts}}} {}) [:db :mailserver/state]))))) (testing "it did not reach the maximum number of attempts" diff --git a/test/cljs/status_im/test/mailserver/topics.cljs b/test/cljs/status_im/test/mailserver/topics.cljs new file mode 100644 index 00000000000..5ef0339c909 --- /dev/null +++ b/test/cljs/status_im/test/mailserver/topics.cljs @@ -0,0 +1,159 @@ +(ns status-im.test.mailserver.topics + (:require [cljs.test :refer-macros [deftest is testing]] + [status-im.transport.utils :as utils] + [status-im.mailserver.constants :as c] + [status-im.mailserver.topics :as t] + [status-im.utils.random :as rand])) + +(def now-s 100000) + +(deftest test-merge-topic-basic-functionality + (testing "a new topic" + (let [old-topic {:chat-ids #{}} + new-topic {:topic "a" + :chat-ids #{"a"} + :filter-ids #{"b" "c"}} + expected-topic {:last-request (- now-s c/max-request-range) + :topic "a" + :filter-ids #{"b" "c"} + :discovery? false + :negotiated? false + :chat-ids #{"a"}}] + (is (= expected-topic + (t/merge-topic old-topic new-topic {:now-s now-s}))))) + (testing "an already existing topic" + (let [old-topic {:filter-ids #{"a" "b"} + :chat-ids #{"a" "b"}} + new-topic {:topic "a" + :filter-ids #{"a" "c"} + :chat-ids #{"a" "c"}} + expected-topic {:last-request (- now-s c/max-request-range) + :topic "a" + :discovery? false + :negotiated? false + :filter-ids #{"a" "b" "c"} + :chat-ids #{"a" "b" "c"}}] + (is (= expected-topic + (t/merge-topic old-topic new-topic {:now-s now-s})))))) + +(deftest test-merge-topic + (testing "previous last request is nil and not discovery" + (let [old-topic {:chat-ids #{}} + new-topic {:chat-ids #{"a"}} + expected-topic {:last-request (- now-s c/max-request-range) + :discovery? false + :negotiated? false + :topic nil + :filter-ids nil + :chat-ids #{"a"}}] + (is (= expected-topic + (t/merge-topic old-topic new-topic {:now-s now-s}))))) + (testing "previous last request is nil and discovery" + (let [old-topic {:chat-ids #{}} + new-topic {:discovery? true + :chat-ids #{"a"}} + expected-topic {:last-request (- now-s 10) + :discovery? true + :negotiated? false + :topic nil + :filter-ids nil + :chat-ids #{"a"}}] + (is (= expected-topic + (t/merge-topic old-topic new-topic {:now-s now-s}))))) + (testing "previous last request is set to less then max range ago" + (let [old-last-request (inc (- now-s c/max-request-range)) + old-topic {:last-request old-last-request + :chat-ids #{}} + new-topic {:chat-ids #{"a"}} + expected-topic {:last-request old-last-request + :discovery? false + :negotiated? false + :topic nil + :filter-ids nil + :chat-ids #{"a"}}] + (is (= expected-topic + (t/merge-topic old-topic new-topic {:now-s now-s}))))) + (testing "previous last request is set to less then max range ago" + (let [old-last-request (- now-s (* 2 c/max-request-range)) + old-topic {:last-request old-last-request + :chat-ids #{}} + new-topic {:chat-ids #{"a"}} + expected-topic {:last-request (- now-s c/max-request-range) + :discovery? false + :negotiated? false + :topic nil + :filter-ids nil + :chat-ids #{"a"}}] + (is (= expected-topic + (t/merge-topic old-topic new-topic {:now-s now-s})))))) + +(deftest new-chat-ids? + (testing "new-chat-ids?" + (is (not (t/new-chat-ids? {:chat-ids #{"a" "b" "c"}} + {:chat-ids #{"a"}}))) + (is (t/new-chat-ids? {:chat-ids #{"a" "b"}} + {:chat-ids #{"a" "b" "c"}})))) + +(deftest topics-for-chat + (testing "a public chat" + (testing "the chat is in multiple topics" + (is (= #{"a" "b"} + (t/topics-for-chat {:chats {"chat-id-1" {:public? true}} + :mailserver/topics {"a" {:chat-ids #{"chat-id-1" "chat-id-2"}} + "b" {:chat-ids #{"chat-id-1"}} + "c" {:discovery? true + :chat-ids #{"chat-id-2"}}}} + "chat-id-1")))) + (testing "the chat is not there" + (is (= #{} + (t/topics-for-chat {:chats {"chat-id-3" {:public? true}} + :mailserver/topics {"a" {:chat-ids #{"chat-id-1" "chat-id-2"}} + "b" {:chat-ids #{"chat-id-1"}} + "c" {:discovery? true + :chat-ids #{"chat-id-2"}}}} + "chat-id-3"))))) + (testing "a one to one" + (is (= #{"a" "c"} + (t/topics-for-chat {:mailserver/topics {"a" {:chat-ids #{"chat-id-1" "chat-id-2"}} + "b" {:chat-ids #{"chat-id-1"}} + "c" {:discovery? true}}} + "chat-id-2"))))) + +(deftest upsert-group-chat-test + (testing "new group chat" + (let [expected-topics {:modified [{:topic "2" + :chat-ids #{"chat-id"}} + {:topic "4" + :chat-ids #{"chat-id"}}] + :removed []}] + (is (= expected-topics + (t/changed-for-group-chat [{:topic "1" + :discovery? true + :chat-ids #{}} + {:topic "2" + :chat-ids #{"a"}} + {:topic "3" + :chat-ids #{"b"}} + {:topic "4" + :chat-ids #{"c"}}] + "chat-id" + ["a" "c"]))))) + (testing "existing group chat" + (let [expected-topics {:modified [{:topic "2" + :chat-ids #{"chat-id"}} + {:topic "4" + :chat-ids #{"chat-id"}}] + :removed [{:topic "3" + :chat-ids #{"b"}}]}] + (is (= expected-topics + (t/changed-for-group-chat [{:topic "1" + :discovery? true + :chat-ids #{}} + {:topic "2" + :chat-ids #{"a"}} + {:topic "3" + :chat-ids #{"chat-id" "b"}} + {:topic "4" + :chat-ids #{"c"}}] + "chat-id" + ["a" "c"])))))) diff --git a/test/cljs/status_im/test/pairing/core.cljs b/test/cljs/status_im/test/pairing/core.cljs index 1699e6d2bf8..7b405749902 100644 --- a/test/cljs/status_im/test/pairing/core.cljs +++ b/test/cljs/status_im/test/pairing/core.cljs @@ -252,35 +252,43 @@ :chat-id "status"}} :contacts/contacts {"contact-1" {:name "contact-1" :public-key "contact-1" - :system-tags #{}} + :system-tags #{:contact/added}} "contact-2" {:name "contact-2" :public-key "contact-2" - :system-tags #{}} + :system-tags #{:contact/added}} "contact-3" {:name "contact-3" :public-key "contact-3" - :system-tags #{}} + :system-tags #{:contact/added}} "contact-4" {:name "contact-4" :public-key "contact-4" - :system-tags #{}} + :system-tags #{:contact/added}} "contact-5" {:name "contact-5" :public-key "contact-5" + :system-tags #{:contact/added}} + "contact-6" {:name "contact-6" + :public-key "contact-6" :system-tags #{:contact/blocked}}}}} expected [(transport.pairing/SyncInstallation. {"contact-1" {:name "contact-1" :public-key "contact-1" - :system-tags #{}} + :pending? false + :system-tags #{:contact/added}} "contact-2" {:name "contact-2" + :pending? false :public-key "contact-2" - :system-tags #{}} + :system-tags #{:contact/added}} "contact-3" {:name "contact-3" + :pending? false :public-key "contact-3" - :system-tags #{}} + :system-tags #{:contact/added}} "contact-4" {:name "contact-4" + :pending? false :public-key "contact-4" - :system-tags #{}}} + :system-tags #{:contact/added}}} {} {}) (transport.pairing/SyncInstallation. {"contact-5" {:name "contact-5" :public-key "contact-5" - :system-tags #{}}} {} {}) + :pending? false + :system-tags #{:contact/added}}} {} {}) (transport.pairing/SyncInstallation. {} {:photo-path "photo-path" :name "name" :last-updated 1} {}) diff --git a/test/cljs/status_im/test/runner.cljs b/test/cljs/status_im/test/runner.cljs index b37ba896a9d..9fc76a3609b 100644 --- a/test/cljs/status_im/test/runner.cljs +++ b/test/cljs/status_im/test/runner.cljs @@ -13,7 +13,7 @@ [status-im.test.chat.models.message] [status-im.test.chat.models] [status-im.test.chat.views.photos] - [status-im.test.contact-code.core] + [status-im.test.transport.filters.core] [status-im.test.contact-recovery.core] [status-im.test.contacts.device-info] [status-im.test.data-store.chats] @@ -33,8 +33,9 @@ [status-im.test.hardwallet.core] [status-im.test.i18n] [status-im.test.init.core] - [status-im.test.mailserver.core] [status-im.test.models.account] + [status-im.test.mailserver.core] + [status-im.test.mailserver.topics] [status-im.test.models.bootnode] [status-im.test.models.contact] [status-im.test.models.network] @@ -93,7 +94,7 @@ 'status-im.test.chat.models.message 'status-im.test.chat.models.message-content 'status-im.test.chat.views.photos - 'status-im.test.contact-code.core + 'status-im.test.transport.filters.core 'status-im.test.contact-recovery.core 'status-im.test.contacts.db 'status-im.test.contacts.device-info @@ -115,6 +116,7 @@ 'status-im.test.i18n 'status-im.test.init.core 'status-im.test.mailserver.core + 'status-im.test.mailserver.topics 'status-im.test.models.account 'status-im.test.models.bootnode 'status-im.test.models.contact diff --git a/test/cljs/status_im/test/sign_in/flow.cljs b/test/cljs/status_im/test/sign_in/flow.cljs index 4e3a8d6f130..cbee5169bfb 100644 --- a/test/cljs/status_im/test/sign_in/flow.cljs +++ b/test/cljs/status_im/test/sign_in/flow.cljs @@ -187,9 +187,7 @@ (testing ":accounts/login cleared." (is (not (contains? new-db :accounts/login)))) (testing "Check messaging related effects." - (is (= 1 (count (get-in efx [:shh/restore-sym-keys-batch :transport])))) - (is (contains? efx :shh/generate-sym-key-from-password)) - (is (contains? efx :shh/add-discovery-filters)) + (is (contains? efx :filters/load-filters)) (is (contains? efx :mailserver/add-peer)) (is (contains? efx :mailserver/update-mailservers)) (is (= #{{:ms 10000 diff --git a/test/cljs/status_im/test/transport/core.cljs b/test/cljs/status_im/test/transport/core.cljs index b5359692179..b9c3cddcef3 100644 --- a/test/cljs/status_im/test/transport/core.cljs +++ b/test/cljs/status_im/test/transport/core.cljs @@ -14,19 +14,8 @@ :sym-key "sk3"} "4" {:topic "topic-4"}} :semaphores #{}}}] - (testing "it adds the discover filters" - (is (= {:web3 nil :private-key-id "1" :topics '({:topic "topic-4" - :chat-id "4"} - {:topic "0x2af2e6e7" - :chat-id :discovery-topic} - {:topic "0xf8946aac" - :chat-id :discovery-topic})} - (:shh/add-discovery-filters (transport/init-whisper cofx))))) - - (testing "it restores the sym-keys" - (is (= [{:topic "topic-1", :sym-key "sk1", :chat-id "1"} - {:topic "topic-3", :sym-key "sk3", :chat-id "3"}] - (-> (transport/init-whisper cofx) :shh/restore-sym-keys-batch :transport)))) + (testing "it loads the filters" + (is (:filters/load-filters (transport/init-whisper cofx)))) (testing "custom mailservers" (let [ms-1 {:id "1" :fleet :eth.beta diff --git a/test/cljs/status_im/test/transport/filters/core.cljs b/test/cljs/status_im/test/transport/filters/core.cljs new file mode 100644 index 00000000000..ced2ff3224e --- /dev/null +++ b/test/cljs/status_im/test/transport/filters/core.cljs @@ -0,0 +1,143 @@ +(ns status-im.test.transport.filters.core + (:require [cljs.test :refer-macros [deftest is testing]] + [status-im.utils.fx :as fx] + [status-im.mailserver.topics :as mailserver.topics] + [status-im.transport.filters.core :as transport.filters])) + +(def me "me") +(def member-1 "member-1") +(def member-2 "member-2") +(def chat-id "chat-id") + +(deftest stop-listening + (testing "the user is in our contacts" + (testing "it does not remove filters" + (is (not (transport.filters/stop-listening + {:db {:contacts/contacts + {chat-id {:system-tags #{:contact/added}}}}} + chat-id))))) + (testing "the user is not in our contacts" + (testing "the user is not in any group chats or 1-to1-" + (testing "it removes the filters" + (let [fx (transport.filters/stop-listening {:db {:filter/filters + {"a" {:chat-id chat-id :filter-id "a"} + "b" {:chat-id chat-id :negotiated? true}}}} + chat-id)] + (is fx) + (is (= fx {:filters/remove-filters [{:chat-id chat-id :filter-id "a"}]}))))) + (testing "the user is still in some group chats" + (testing "we joined, and group chat is active it does not remove filters" + (let [fx (transport.filters/stop-listening {:db {:account/account {:public-key me} + :chats + {chat-id {:is-active true + :members-joined #{me} + :members #{member-1}}} + :filter/filters + {member-1 {}}}} + member-1)] + (is (not fx)))) + (testing "we didn't join, it removes transport" + (let [fx (transport.filters/stop-listening {:db {:account/account {:public-key me} + :chats + {chat-id {:is-active true + :members-joined #{member-1} + :members #{member-1}}} + :filter/filters + {member-1 {:chat-id member-1 :filter-id "a"}}}} + member-1)] + (is fx) + (is (= fx {:filters/remove-filters [{:chat-id member-1 :filter-id "a"}]}))))) + (testing "we have a 1-to-1 chat with the user" + (testing "it does not remove filter" + (let [fx (transport.filters/stop-listening {:db {:chats + {member-1 {:is-active true}}}} + member-1)] + (is (not fx))))))) + +(deftest chats->filter-requests + (testing "a single one to one chat" + (is (= [{:ChatID "0xchat-id" + :OneToOne true + :Identity "chat-id"}] + (transport.filters/chats->filter-requests [{:is-active true + :group-chat false + :chat-id "0xchat-id"}])))) + (testing "a single public chat" + (is (= [{:ChatID "chat-id" + :OneToOne false}] + (transport.filters/chats->filter-requests [{:is-active true + :group-chat true + :public? true + :chat-id "chat-id"}])))) + (testing "a single group chat" + (is (= [{:ChatID "0xchat-id-2" + :OneToOne true + :Identity "chat-id-2"} + {:ChatID "0xchat-id-1" + :OneToOne true + :Identity "chat-id-1"}] + (transport.filters/chats->filter-requests [{:is-active true + :group-chat true + :members-joined #{"0xchat-id-1" "0xchat-id-2"} + :chat-id "chat-id"}]))))) + +(deftest contacts->filters + (testing "converting contacts to filters" + (is (= [{:ChatID "0xchat-id-2" + :OneToOne true + :Identity "chat-id-2"}] + (transport.filters/contacts->filter-requests [{:system-tags #{} + :public-key "0xchat-id-1"} + {:system-tags #{:contact/added} + :public-key "0xchat-id-2"}]))))) + +(deftest load-member + (testing "it returns fx for a member" + (is (= {:filters/load-filters [[nil [{:ChatID "0xchat-id-2" + :OneToOne true + :Identity "chat-id-2"}]]]} + (transport.filters/load-member {:db {}} "0xchat-id-2")))) + (testing "merging fx" + (is (= + {:db {} + :filters/load-filters [[nil [{:ChatID "0xchat-id-1" + :OneToOne true + :Identity "chat-id-1"}]] + [nil [{:ChatID "0xchat-id-2" + :OneToOne true + :Identity "chat-id-2"}]]]} + (apply fx/merge {:db {}} + (map transport.filters/load-member ["0xchat-id-1" "0xchat-id-2"])))))) + +(deftest add-filter-to-db + (with-redefs [mailserver.topics/upsert (fn [{:keys [db]} r] {:db (assoc db :upsert r)})] + (let [expected {:db {:filter/chat-ids #{"chat-id"} + :filter/filters {"filter-id" {:filter-id "filter-id" + :discovery? false + :chat-id "chat-id" + :negotiated? false + :topic "topic"}} + :upsert {:topic "topic" + :negotiated? false + :discovery? false + :chat-ids #{"chat-id"} + :filter-ids #{"filter-id"}}}}] + (is (= expected + (transport.filters/add-filter-to-db {:db {}} {:filter-id "filter-id" + :discovery? false + :chat-id "chat-id" + :negotiated? false + :topic "topic"})))))) + +(deftest new-filters? + (testing "new-filters?" + (let [db {:filter/filters {"a" {} + "b" {} + "c" {}}}] + (is (not (transport.filters/new-filters? db [{:filter-id "a"} + {:filter-id "b"} + {:filter-id "c"}]))) + (is (not (transport.filters/new-filters? db [{:filter-id "a"}]))) + (is (transport.filters/new-filters? db [{:filter-id "d"}])) + (is (transport.filters/new-filters? db [{:filter-id "a"} + {:filter-id "d"}]))))) diff --git a/test/cljs/status_im/test/transport/partitioned_topic.cljs b/test/cljs/status_im/test/transport/partitioned_topic.cljs deleted file mode 100644 index 4334e832bb4..00000000000 --- a/test/cljs/status_im/test/transport/partitioned_topic.cljs +++ /dev/null @@ -1,38 +0,0 @@ -(ns status-im.test.transport.filters - (:require [cljs.test :refer-macros [deftest is testing]] - [status-im.transport.partitioned-topic :as t])) - -(def pk "0x04985040682b77a32bb4bb58268a0719bd24ca4d07c255153fe1eb2ccd5883669627bd1a092d7cc76e8e4b9104327667b19dcda3ac469f572efabe588c38c1985f") - -(def expected-users 40000) -(def average-number-of-contacts 100) -;; Minimum number of identical personal topics -(def min-number-of-clashes 1000) -;; Maximum share of traffic that each user will be receiving -(def max-share-of-traffic (/ 1 250)) -(def partitioned-topic "0xed2fdbad") -(def discovery-topic "0xf8946aac") - -(deftest partition-topic - (testing "it returns a seeded topic based on an input string" - (is (= partitioned-topic (t/partitioned-topic-hash pk)))) - (testing "same input same output" - (is (= (t/partitioned-topic-hash "a") (t/partitioned-topic-hash "a"))))) - -(deftest discovery-topics - (testing "it returns a partition topic & the discovery topic" - (is (= [partitioned-topic discovery-topic] - (t/discovery-topics pk))))) - -(deftest minimum-number-of-clashes-test - (testing (str "it needs to be greater than " min-number-of-clashes) - (is (<= min-number-of-clashes (t/expected-number-of-collisions expected-users))))) - -(deftest max-avg-share-of-traffic-test - (testing (str "it needs to be less than " max-share-of-traffic) - (is (>= max-share-of-traffic - ;; we always listen to our personal topic + - ;; we listen to contact topics - collisions - (/ (+ 1 (- average-number-of-contacts - (t/expected-number-of-collisions average-number-of-contacts))) - expected-users))))) diff --git a/translations/en.json b/translations/en.json index 5ee810a5eb5..e4d50037bd6 100644 --- a/translations/en.json +++ b/translations/en.json @@ -217,9 +217,9 @@ "currency-display-name-tzs": "Tanzanian Shilling", "currency-display-name-brl": "Brazil Real", "mainnet-network": "Main network", - "pfs": "PFS Enabled", - "pfs-warning-title": "Warning, experimental feature", - "pfs-warning-content": "PFS support is still experimental, so use at your own risk.\nIf enabled, only users who are running 0.9.32 and higher will be able to read your direct and public messages. This does not guarantee PFS for all your messages yet, and it will only encrypt your messages, not the one you receive.", + "device-to-device": "Device-to-device Enabled", + "device-to-device-warning-title": "Warning, experimental feature", + "device-to-device-warning-content": "If enabled, only users who are running 0.9.32 and higher will be able to read your direct and public messages.", "open-dapp": "Open ÐApp", "new-transaction": "New Transaction", "currency-display-name-bbd": "Barbados Dollar", diff --git a/translations/ko.json b/translations/ko.json index 2f5f03cc95f..df9648a5620 100644 --- a/translations/ko.json +++ b/translations/ko.json @@ -679,9 +679,9 @@ "pending": "대기 중", "pending-confirmation": "확인 대기 중 ...", "permissions": "권한", - "pfs": "PFS 활성화", - "pfs-warning-content": "PFS 지원은 아직 테스트 중이므로 스테이터스는 오류에 대해 책임지지 않습니다. PFS를 활성화하면, 0.9.32 이상의 버전을 사용하는 유저들은 귀하의 개인, 공개 메시지를 읽을 수 있습니다. 아직 모든 메시지에 대한 PFS를 보장하지는 않으며, 귀하의 메시지를 암호화하지만 수신 메시지는 암호화 하지 않습니다.", - "pfs-warning-title": "경고, 테스트 중인 기능임", + "device-to-device": "PFS 활성화", + "device-to-device-warning-content": "PFS 지원은 아직 테스트 중이므로 스테이터스는 오류에 대해 책임지지 않습니다. PFS를 활성화하면, 0.9.32 이상의 버전을 사용하는 유저들은 귀하의 개인, 공개 메시지를 읽을 수 있습니다. 아직 모든 메시지에 대한 PFS를 보장하지는 않으며, 귀하의 메시지를 암호화하지만 수신 메시지는 암호화 하지 않습니다.", + "device-to-device-warning-title": "경고, 테스트 중인 기능임", "phew-here-is-your-passphrase": "휴, 꽤 어려웠습니다. 이것이 당신의 패스 구문입니다. *구문을 적어두신 다음 안전한 곳에 보관하세요!* 추후 계정을 복구할 때 필요합니다.", "phone-e164": "국제전화 1", "phone-international": "국제전화 2",