Propagate signed membership information
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
parent
e89628ce3a
commit
165f1a46c7
3
.env
3
.env
|
@ -12,9 +12,8 @@ TESTFAIRY_TOKEN=969f6c921cb435cea1d41d1ea3f5b247d6026d55
|
|||
INSTABUG_TOKEN=758630ed52864cbad9c5eeeac596c60c
|
||||
DEBUG_WEBVIEW=1
|
||||
INSTABUG_SURVEYS=1
|
||||
GROUP_CHATS_ENABLED=0
|
||||
GROUP_CHATS_ENABLED=1
|
||||
CACHED_WEBVIEWS_ENABLED=1
|
||||
EXTENSIONS=1
|
||||
HARDWALLET_ENABLED=0
|
||||
PFS_ENCRYPTION_ENABLED=0
|
||||
GROUP_CHATS_ENABLED=0
|
||||
|
|
|
@ -11,7 +11,7 @@ POW_TIME=1
|
|||
DEFAULT_NETWORK=mainnet_rpc
|
||||
INSTABUG_TOKEN=758630ed52864cbad9c5eeeac596c60c
|
||||
DEBUG_WEBVIEW=1
|
||||
GROUP_CHATS_ENABLED=0
|
||||
GROUP_CHATS_ENABLED=1
|
||||
MAINNET_WARNING_ENABLED=1
|
||||
CACHED_WEBVIEWS_ENABLED=1
|
||||
EXTENSIONS=0
|
||||
|
|
|
@ -10,7 +10,7 @@ POW_TIME=1
|
|||
DEFAULT_NETWORK=mainnet_rpc
|
||||
INSTABUG_TOKEN=758630ed52864cbad9c5eeeac596c60c
|
||||
DEBUG_WEBVIEW=1
|
||||
GROUP_CHATS_ENABLED=0
|
||||
GROUP_CHATS_ENABLED=1
|
||||
MAINNET_WARNING_ENABLED=1
|
||||
EXTENSIONS=1
|
||||
PFS_ENCRYPTION_ENABLED=0
|
||||
|
|
|
@ -13795,7 +13795,7 @@
|
|||
}
|
||||
},
|
||||
"web3": {
|
||||
"version": "github:status-im/web3.js#ff09ce57e9574a1c42138832a7d6bf6c2e699048",
|
||||
"version": "git+https://github.com/status-im/web3.js.git#b1c2e2b75f6a190b320dda4be7931d3680ecb727",
|
||||
"requires": {
|
||||
"bignumber.js": "github:status-im/bignumber.js#cc066a0a3d6bfe0c436c9957f4ea8344bf963c89",
|
||||
"crypto-js": "3.1.8",
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
"string_decoder": "0.10.31",
|
||||
"text-encoding": "^0.6.4",
|
||||
"url": "0.10.3",
|
||||
"web3": "github:status-im/web3.js#feature/shhext",
|
||||
"web3": "https://github.com/status-im/web3.js.git#feature/chat-api",
|
||||
"web3-utils": "1.0.0-beta.36"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -8456,7 +8456,7 @@
|
|||
},
|
||||
"react-native-tab-view": {
|
||||
"version": "0.0.77",
|
||||
"resolved": "http://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-0.0.77.tgz",
|
||||
"resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-0.0.77.tgz",
|
||||
"integrity": "sha512-9vjD4Ly1Zlum1Y4g23ODpi/F3gYIUIsKWrsZO/Oh5cuX1eiB1DRVn11nY1z+j/hsQfhfyW6nDlmySyDvYQvYCA==",
|
||||
"requires": {
|
||||
"prop-types": "15.6.0"
|
||||
|
@ -10505,7 +10505,7 @@
|
|||
}
|
||||
},
|
||||
"web3": {
|
||||
"version": "git+https://github.com/status-im/web3.js.git#ff09ce57e9574a1c42138832a7d6bf6c2e699048",
|
||||
"version": "git+https://github.com/status-im/web3.js.git#b1c2e2b75f6a190b320dda4be7931d3680ecb727",
|
||||
"requires": {
|
||||
"bignumber.js": "github:status-im/bignumber.js#cc066a0a3d6bfe0c436c9957f4ea8344bf963c89",
|
||||
"crypto-js": "3.1.8",
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
"string_decoder": "0.10.31",
|
||||
"text-encoding": "^0.6.4",
|
||||
"url": "0.10.3",
|
||||
"web3": "https://github.com/status-im/web3.js.git#feature/shhext",
|
||||
"web3": "https://github.com/status-im/web3.js.git#feature/chat-api",
|
||||
"web3-utils": "1.0.0-beta.36"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ dependencies {
|
|||
implementation 'com.instabug.library:instabug:3+'
|
||||
implementation 'status-im:function:0.0.1'
|
||||
|
||||
String statusGoVersion = 'v0.15.0'
|
||||
String statusGoVersion = 'v0.16.0-1-gf3880f8f'
|
||||
final String statusGoGroup = 'status-im', statusGoName = 'status-go'
|
||||
|
||||
// Check if the local status-go jar exists, and compile against that if it does
|
||||
|
|
|
@ -693,6 +693,47 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
|||
return android.text.format.DateFormat.is24HourFormat(this.reactContext.getApplicationContext());
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void verifyGroupMembershipSignatures(final String signaturePairs, final Callback callback) {
|
||||
Log.d(TAG, "verifyGroupMembershipSignatures");
|
||||
if (!checkAvailability()) {
|
||||
callback.invoke(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String result = Statusgo.VerifyGroupMembershipSignatures(signaturePairs);
|
||||
|
||||
callback.invoke(result);
|
||||
}
|
||||
};
|
||||
|
||||
StatusThreadPoolExecutor.getInstance().execute(r);
|
||||
}
|
||||
|
||||
|
||||
@ReactMethod
|
||||
public void signGroupMembership(final String content, final Callback callback) {
|
||||
Log.d(TAG, "signGroupMembership");
|
||||
if (!checkAvailability()) {
|
||||
callback.invoke(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String result = Statusgo.SignGroupMembership(content);
|
||||
|
||||
callback.invoke(result);
|
||||
}
|
||||
};
|
||||
|
||||
StatusThreadPoolExecutor.getInstance().execute(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable
|
||||
Map<String, Object> getConstants() {
|
||||
|
|
|
@ -37,7 +37,8 @@ ExternalProject_Add(StatusGo_ep
|
|||
PREFIX ${StatusGo_PREFIX}
|
||||
SOURCE_DIR ${StatusGo_SOURCE_DIR}
|
||||
GIT_REPOSITORY https://github.com/status-im/status-go.git
|
||||
GIT_TAG v0.15.0
|
||||
GIT_TAG f3880f8fe1f11e2cd59382c34dd826ebbf9662cf
|
||||
|
||||
BUILD_BYPRODUCTS ${StatusGo_STATIC_LIB}
|
||||
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/${CONFIGURE_SCRIPT} ${GO_ROOT_PATH} ${StatusGo_ROOT} ${StatusGo_SOURCE_DIR}
|
||||
BUILD_COMMAND ""
|
||||
|
|
|
@ -193,6 +193,25 @@ void RCTStatus::signMessage(QString rpcParams, double callbackId) {
|
|||
}, rpcParams, callbackId);
|
||||
}
|
||||
|
||||
void RCTStatus::signGroupMembership(QString content, double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::signGroupMembership with param callbackId: " << callbackId;
|
||||
QtConcurrent::run([&](QString content, double callbackId) {
|
||||
const char* result = SignGroupMembership(content.toUtf8().data());
|
||||
qDebug() << "RCTStatus::signGroupMembership SignGroupMembership result: " << statusGoResultError(result);
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
|
||||
}, content, callbackId);
|
||||
}
|
||||
|
||||
void RCTStatus::verifyGroupMembershipSignatures(QString signatures, double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::verifyGroupMembershipSignatures with param callbackId: " << callbackId;
|
||||
QtConcurrent::run([&](QString signatures, double callbackId) {
|
||||
const char* result = VerifyGroupMembershipSignatures(signatures.toUtf8().data());
|
||||
qDebug() << "RCTStatus::verifyGroupMembershipSignatures VerifyGroupMembershipSignatures result: " << statusGoResultError(result);
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
|
||||
}, signatures, callbackId);
|
||||
}
|
||||
|
||||
void RCTStatus::setAdjustResize() {
|
||||
}
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
Q_INVOKABLE void login(QString address, QString password, double callbackId);
|
||||
Q_INVOKABLE void sendTransaction(QString txArgsJSON, QString password, double callbackId);
|
||||
Q_INVOKABLE void signMessage(QString rpcParams, double callbackId);
|
||||
Q_INVOKABLE void signGroupMembership(QString content, double callbackId);
|
||||
Q_INVOKABLE void verifyGroupMembershipSignatures(QString signatures, double callbackId);
|
||||
|
||||
Q_INVOKABLE void setAdjustResize();
|
||||
Q_INVOKABLE void setAdjustPan();
|
||||
|
|
|
@ -253,6 +253,30 @@ RCT_EXPORT_METHOD(signMessage:(NSString *)message
|
|||
callback(@[[NSString stringWithUTF8String: result]]);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
#pragma mark - SignGroupMembership
|
||||
//////////////////////////////////////////////////////////////////// signGroupMembership
|
||||
RCT_EXPORT_METHOD(signGroupMembership:(NSString *)content
|
||||
callback:(RCTResponseSenderBlock)callback) {
|
||||
#if DEBUG
|
||||
NSLog(@"SignGroupMembership() method called");
|
||||
#endif
|
||||
char * result = SignGroupMembership((char *) [content UTF8String]);
|
||||
callback(@[[NSString stringWithUTF8String: result]]);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
#pragma mark - VerifyGroupMembershipSignatures
|
||||
//////////////////////////////////////////////////////////////////// verifyGroupMembershipSignatures
|
||||
RCT_EXPORT_METHOD(verifyGroupMembershipSignatures:(NSString *)content
|
||||
callback:(RCTResponseSenderBlock)callback) {
|
||||
#if DEBUG
|
||||
NSLog(@"VerifyGroupMembershipSignatures() method called");
|
||||
#endif
|
||||
char * result = VerifyGroupMembershipSignatures((char *) [content UTF8String]);
|
||||
callback(@[[NSString stringWithUTF8String: result]]);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
#pragma mark - only android methods
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<artifactItem>
|
||||
<groupId>status-im</groupId>
|
||||
<artifactId>status-go-ios-simulator</artifactId>
|
||||
<version>v0.15.0</version>
|
||||
<version>v0.16.0-1-gf3880f8f</version>
|
||||
<type>zip</type>
|
||||
<overWrite>true</overWrite>
|
||||
<outputDirectory>./</outputDirectory>
|
||||
|
|
|
@ -213,7 +213,7 @@
|
|||
(fx/merge cofx
|
||||
(add-public-chat topic)
|
||||
(navigate-to-chat topic {:modal? modal?
|
||||
:navigation-replace? true})
|
||||
:navigation-reset? true})
|
||||
(public-chat/join-public-chat topic)))
|
||||
|
||||
(fx/defn disable-chat-cooldown
|
||||
|
|
|
@ -32,40 +32,6 @@
|
|||
(seq removed-participants)
|
||||
(str admin-name " " (i18n/label :t/removed) " " (apply str (interpose ", " removed-participants-names))))))
|
||||
|
||||
(fx/defn handle-group-admin-update [{:keys [now db random-id-generator] :as cofx}
|
||||
{:keys [chat-name participants]} chat-id signature]
|
||||
(let [me (:current-public-key db)
|
||||
system-message-id (random-id-generator)]
|
||||
;; we have to check if we already have a chat, or it's a new one
|
||||
(if-let [{:keys [group-admin contacts] :as chat} (get-in db [:chats chat-id])]
|
||||
;; update for existing group chat
|
||||
(when (and (= signature group-admin) ;; make sure that admin is the one making changes
|
||||
(not= (set contacts) (set participants))) ;; make sure it's actually changing something
|
||||
(let [{:keys [removed added]} (participants-diff (set contacts) (set participants))
|
||||
admin-name (or (get-in db [:contacts/contacts group-admin :name])
|
||||
group-admin)]
|
||||
(if (removed me) ;; we were removed
|
||||
(fx/merge cofx
|
||||
(models.message/receive
|
||||
(models.message/system-message chat-id system-message-id now
|
||||
(str admin-name " " (i18n/label :t/removed-from-chat))))
|
||||
(models.chat/upsert-chat {:chat-id chat-id
|
||||
:removed-from-at now
|
||||
:is-active false})
|
||||
(transport.utils/unsubscribe-from-chat chat-id))
|
||||
(fx/merge cofx
|
||||
(models.message/receive
|
||||
(models.message/system-message chat-id system-message-id now
|
||||
(prepare-system-message admin-name
|
||||
added
|
||||
removed
|
||||
(:contacts/contacts db))))
|
||||
(group/participants-added chat-id added)
|
||||
(group/participants-removed chat-id removed)))))
|
||||
;; first time we hear about chat -> create it if we are among participants
|
||||
(when (get (set participants) me)
|
||||
(models.chat/add-group-chat cofx chat-id chat-name signature participants)))))
|
||||
|
||||
(fx/defn handle-group-leave
|
||||
[{:keys [db random-id-generator now] :as cofx} chat-id signature]
|
||||
(let [me (:current-public-key db)
|
||||
|
@ -77,9 +43,9 @@
|
|||
(get-in db [:chats chat-id])) ;; chat is present
|
||||
|
||||
(fx/merge cofx
|
||||
(models.message/receive
|
||||
(models.message/system-message chat-id system-message-id now
|
||||
(str participant-leaving-name " " (i18n/label :t/left))))
|
||||
#_(models.message/receive
|
||||
(models.message/system-message chat-id random-id now
|
||||
(str participant-leaving-name " " (i18n/label :t/left))))
|
||||
(group/participants-removed chat-id #{signature})))))
|
||||
|
||||
(defn- group-name-from-contacts [selected-contacts all-contacts username]
|
||||
|
@ -87,20 +53,3 @@
|
|||
(map (comp :name (partial get all-contacts)))
|
||||
(cons username)
|
||||
(string/join ", ")))
|
||||
|
||||
(fx/defn send-group-update [cofx group-update chat-id]
|
||||
(transport/send group-update chat-id cofx))
|
||||
|
||||
(fx/defn start-group-chat
|
||||
"Starts a new group chat"
|
||||
[{:keys [db random-id-generator] :as cofx} group-name]
|
||||
(let [my-public-key (:current-public-key db)
|
||||
chat-id (random-id-generator)
|
||||
selected-contacts (conj (:group/selected-contacts db)
|
||||
my-public-key)
|
||||
group-update (transport.message/GroupMembershipUpdate. chat-id group-name my-public-key selected-contacts nil nil nil)]
|
||||
(fx/merge cofx
|
||||
{:db (assoc db :group/selected-contacts #{})}
|
||||
(models.chat/navigate-to-chat chat-id {})
|
||||
(group-chat/handle-membership-update group-update my-public-key)
|
||||
(send-group-update group-update chat-id))))
|
||||
|
|
|
@ -150,15 +150,6 @@
|
|||
(not (= constants/system from))
|
||||
(not (:outgoing message)))))))
|
||||
|
||||
(fx/defn receive
|
||||
[{:keys [now] :as cofx} {:keys [chat-id message-id] :as message}]
|
||||
(fx/merge cofx
|
||||
(chat-model/upsert-chat {:chat-id chat-id
|
||||
;; We activate a chat again on new messages
|
||||
:is-active true
|
||||
:timestamp now})
|
||||
(add-received-message false message)))
|
||||
|
||||
(fx/defn update-group-messages [cofx chat->message chat-id]
|
||||
(fx/merge cofx
|
||||
(re-index-message-groups chat-id)
|
||||
|
@ -185,9 +176,19 @@
|
|||
:accumulated []}
|
||||
messages)))
|
||||
|
||||
(defn valid-chat-id? [cofx {:keys [chat-id from message-type]}]
|
||||
"Validate chat-id and message-type"
|
||||
(case message-type
|
||||
:group-user-message (get-in cofx [:db :chats chat-id :contacts from])
|
||||
:public-group-user-message (get-in cofx [:db :chats chat-id :public?])
|
||||
:user-message (or (= (get-in cofx [:db :current-public-key]) from)
|
||||
(= chat-id from))
|
||||
false))
|
||||
|
||||
(fx/defn receive-many
|
||||
[{:keys [now] :as cofx} messages]
|
||||
(let [deduped-messages (filter-messages cofx messages)
|
||||
(let [valid-messages (filter (partial valid-chat-id? cofx) messages)
|
||||
deduped-messages (filter-messages cofx valid-messages)
|
||||
chat->message (group-by :chat-id deduped-messages)
|
||||
chat-ids (keys chat->message)
|
||||
chats-fx-fns (map #(chat-model/upsert-chat {:chat-id %
|
||||
|
|
|
@ -92,3 +92,37 @@
|
|||
:default false}
|
||||
:public? {:type :bool
|
||||
:default false}}})
|
||||
|
||||
(def v6 {:name :chat
|
||||
:primaryKey :chat-id
|
||||
:properties {:chat-id :string
|
||||
:name :string
|
||||
:color {:type :string
|
||||
:default default-chat-color}
|
||||
:group-chat {:type :bool
|
||||
:indexed true}
|
||||
:group-admin {:type :string
|
||||
:optional true}
|
||||
:is-active :bool
|
||||
:timestamp :int
|
||||
:contacts {:type "string[]"}
|
||||
:removed-at {:type :int
|
||||
:optional true}
|
||||
:removed-from-at {:type :int
|
||||
:optional true}
|
||||
:deleted-at-clock-value {:type :int
|
||||
:optional true}
|
||||
:added-to-at {:type :int
|
||||
:optional true}
|
||||
:updated-at {:type :int
|
||||
:optional true}
|
||||
:message-overhead {:type :int
|
||||
:default 0}
|
||||
:membership-version {:type :int
|
||||
:optional true}
|
||||
:membership-signature {:type :string
|
||||
:optional true}
|
||||
:debug? {:type :bool
|
||||
:default false}
|
||||
:public? {:type :bool
|
||||
:default false}}})
|
||||
|
|
|
@ -132,6 +132,16 @@
|
|||
browser/v8
|
||||
dapp-permissions/v9])
|
||||
|
||||
(def v13 [chat/v6
|
||||
transport/v6
|
||||
contact/v1
|
||||
message/v7
|
||||
mailserver/v11
|
||||
user-status/v1
|
||||
local-storage/v1
|
||||
browser/v8
|
||||
dapp-permissions/v9])
|
||||
|
||||
;; put schemas ordered by version
|
||||
(def schemas [{:schema v1
|
||||
:schemaVersion 1
|
||||
|
@ -168,4 +178,7 @@
|
|||
:migration migrations/v11}
|
||||
{:schema v12
|
||||
:schemaVersion 12
|
||||
:migration migrations/v12}])
|
||||
:migration migrations/v12}
|
||||
{:schema v13
|
||||
:schemaVersion 13
|
||||
:migration migrations/v13}])
|
||||
|
|
|
@ -84,3 +84,5 @@
|
|||
new-content {:text content}]
|
||||
(aset message "content" (pr-str new-content)))))))
|
||||
|
||||
(defn v13 [old-realm new-realm]
|
||||
(log/debug "migrating v13 account database"))
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
[status-im.chat.commands.input :as commands.input]
|
||||
[status-im.data-store.core :as data-store]
|
||||
[status-im.fleet.core :as fleet]
|
||||
[status-im.group-chats.core :as group-chats]
|
||||
[status-im.hardwallet.core :as hardwallet]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.init.core :as init]
|
||||
|
@ -504,11 +505,6 @@
|
|||
(fn [cofx [_ topic modal?]]
|
||||
(chat/start-public-chat cofx topic modal?)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:chat.ui/start-group-chat
|
||||
(fn [cofx [_ group-name]]
|
||||
(chat.group/start-group-chat cofx group-name)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:chat.ui/remove-chat
|
||||
(fn [cofx [_ chat-id]]
|
||||
|
@ -844,3 +840,32 @@
|
|||
:browser.ui/open-modal-chat-button-pressed
|
||||
(fn [cofx [_ host]]
|
||||
(browser/open-chat-from-browser cofx host)))
|
||||
|
||||
;; group-chats module
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:group-chats.ui/create-pressed
|
||||
[(re-frame/inject-cofx :random-guid-generator)]
|
||||
(fn [cofx [_ chat-name]]
|
||||
(group-chats/create cofx chat-name)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:group-chats.ui/name-changed
|
||||
(fn [cofx [_ chat-name]]
|
||||
(group-chats/handle-name-changed cofx chat-name)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:group-chats.ui/save-pressed
|
||||
(fn [cofx _]
|
||||
(group-chats/save cofx)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:group-chats.callback/sign-success
|
||||
[(re-frame/inject-cofx :random-guid-generator)]
|
||||
(fn [cofx [_ group-update]]
|
||||
(group-chats/handle-sign-success cofx group-update)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:group-chats.callback/verify-signature-success
|
||||
(fn [cofx [_ group-update sender-signature]]
|
||||
(group-chats/handle-membership-update cofx group-update sender-signature)))
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
(ns status-im.group-chats.core
|
||||
(:require [status-im.utils.config :as config]
|
||||
(:require [clojure.string :as string]
|
||||
[clojure.spec.alpha :as spec]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.native-module.core :as native-module]
|
||||
[status-im.transport.utils :as transport.utils]
|
||||
[status-im.transport.db :as transport.db]
|
||||
[status-im.transport.utils :as transport.utils]
|
||||
|
@ -9,60 +13,199 @@
|
|||
[status-im.utils.fx :as fx]
|
||||
[status-im.chat.models :as models.chat]))
|
||||
|
||||
(defn wrap-group-message [cofx chat-id message]
|
||||
(defn- parse-response [response-js]
|
||||
(-> response-js
|
||||
js/JSON.parse
|
||||
(js->clj :keywordize-keys true)))
|
||||
|
||||
(defn signature-material [{:keys [chat-id admin participants]}]
|
||||
(apply str
|
||||
(concat (sort participants)
|
||||
admin
|
||||
chat-id)))
|
||||
|
||||
(defn signature-pairs [{:keys [admin signature] :as payload}]
|
||||
(js/JSON.stringify (clj->js [[(signature-material payload)
|
||||
signature
|
||||
(subs admin 2)]])))
|
||||
|
||||
(defn valid-chat-id?
|
||||
;; We need to make sure the chat-id ends with the admin pk (and it's not the same).
|
||||
;; this is due to prevent an attack whereby a non-admin user would
|
||||
;; send out a message with identical chat-id and themselves as admin to other members,
|
||||
;; who would then have to trust the first of the two messages received, possibly
|
||||
;; resulting in a situation where some of the members in the chat trust a different admin.
|
||||
[chat-id admin]
|
||||
(and (string/ends-with? chat-id admin)
|
||||
(not= chat-id admin)))
|
||||
|
||||
(defn wrap-group-message
|
||||
"Wrap a group message in a membership update"
|
||||
[cofx chat-id message]
|
||||
(when-let [chat (get-in cofx [:db :chats chat-id])]
|
||||
(transport/GroupMembershipUpdate.
|
||||
chat-id
|
||||
(:name chat)
|
||||
(:group-admin chat)
|
||||
(:contacts chat)
|
||||
nil
|
||||
nil
|
||||
message)))
|
||||
(transport/map->GroupMembershipUpdate.
|
||||
{:chat-id chat-id
|
||||
:chat-name (:name chat)
|
||||
:admin (:group-admin chat)
|
||||
:participants (:contacts chat)
|
||||
:signature (:membership-signature chat)
|
||||
:version (:membership-version chat)
|
||||
:message message})))
|
||||
|
||||
(fx/defn update-membership
|
||||
"Upsert chat when version is greater or not existing"
|
||||
[cofx previous-chat {:keys [chat-id
|
||||
chat-name
|
||||
participants
|
||||
leaves
|
||||
admin
|
||||
signature
|
||||
version]}]
|
||||
(when
|
||||
(or
|
||||
(nil? previous-chat)
|
||||
(< (:membership-version previous-chat)
|
||||
version))
|
||||
|
||||
(defn update-membership [cofx previous-chat {:keys [chat-id chat-name participants leaves signature version]}]
|
||||
(when (< (:membership-version previous-chat)
|
||||
version)
|
||||
(models.chat/upsert-chat cofx
|
||||
{:chat-id chat-id
|
||||
:membership-version version})))
|
||||
{:chat-id chat-id
|
||||
:name chat-name
|
||||
:is-active (get previous-chat :is-active true)
|
||||
:group-chat true
|
||||
:group-admin admin
|
||||
:contacts participants
|
||||
:membership-signature signature
|
||||
:membership-version version})))
|
||||
|
||||
(defn send-membership-update [cofx payload chat-id]
|
||||
(defn send-membership-update
|
||||
"Send a membership update to all participants but the sender"
|
||||
[cofx payload chat-id]
|
||||
(let [{:keys [participants]} payload
|
||||
{:keys [current-public-key web3]} (:db cofx)]
|
||||
(fx/merge
|
||||
cofx
|
||||
{:shh/send-group-message {:web3 web3
|
||||
:src current-public-key
|
||||
|
||||
:dsts (disj participants current-public-key)
|
||||
{:shh/send-group-message {:web3 web3
|
||||
:src current-public-key
|
||||
:dsts (disj participants current-public-key)
|
||||
:success-event [:transport/set-message-envelope-hash
|
||||
chat-id
|
||||
(transport.utils/message-id (:message payload))
|
||||
:group-user-message]
|
||||
:payload payload}})))
|
||||
:payload payload}})))
|
||||
|
||||
(defn handle-group-leave [payload chat-id cofx]
|
||||
(defn send-group-leave [payload chat-id cofx]
|
||||
(transport.protocol/send cofx
|
||||
{:chat-id chat-id
|
||||
:payload payload
|
||||
:success-event [:group/unsubscribe-from-chat chat-id]}))
|
||||
|
||||
(fx/defn handle-membership-update [cofx {:keys [chat-id chat-name participants leaves message signature version] :as membership-update} sender-signature]
|
||||
(when config/group-chats-enabled?
|
||||
(let [chat-fx (if-let [previous-chat (get-in cofx [:db :chats chat-id])]
|
||||
(update-membership cofx previous-chat membership-update)
|
||||
(models.chat/upsert-chat
|
||||
cofx
|
||||
{:chat-id chat-id
|
||||
:name chat-name
|
||||
:is-active true
|
||||
:group-chat true
|
||||
:group-admin signature
|
||||
:contacts participants
|
||||
:membership-version version}))]
|
||||
(if message
|
||||
(fx/merge cofx
|
||||
chat-fx
|
||||
#(protocol.message/receive message chat-id sender-signature nil %))
|
||||
chat-fx))))
|
||||
(fx/defn handle-membership-update-received
|
||||
"Verify signatures in status-go and act if successful"
|
||||
[cofx membership-update signature]
|
||||
{:group-chats/verify-membership-signature [[membership-update signature]]})
|
||||
|
||||
(fx/defn handle-membership-update
|
||||
"Upsert chat and receive message if valid"
|
||||
;; Care needs to be taken here as chat-id is not coming from a whisper filter
|
||||
;; so can be manipulated by the sending user.
|
||||
[cofx {:keys [chat-id
|
||||
chat-name
|
||||
participants
|
||||
signature
|
||||
leaves
|
||||
message
|
||||
admin
|
||||
version] :as membership-update}
|
||||
sender-signature]
|
||||
(when (and config/group-chats-enabled?
|
||||
(valid-chat-id? chat-id admin))
|
||||
(let [previous-chat (get-in cofx [:db :chats chat-id])]
|
||||
(fx/merge cofx
|
||||
(update-membership previous-chat membership-update)
|
||||
#(when (and message
|
||||
;; don't allow anything but group messages
|
||||
(instance? transport.protocol/Message message)
|
||||
(= :group-user-message (:message-type message)))
|
||||
(protocol.message/receive message chat-id sender-signature nil %))))))
|
||||
|
||||
(defn handle-sign-success
|
||||
"Upsert chat and send signed payload to group members"
|
||||
[{:keys [db] :as cofx} {:keys [chat-id] :as group-update}]
|
||||
(let [my-public-key (:current-public-key db)]
|
||||
(fx/merge cofx
|
||||
(models.chat/navigate-to-chat chat-id {:navigation-reset? true})
|
||||
(handle-membership-update group-update my-public-key)
|
||||
#(protocol.message/send group-update chat-id %))))
|
||||
|
||||
(defn handle-sign-response
|
||||
"Callback to dispatch on sign response"
|
||||
[payload response-js]
|
||||
(let [{:keys [error signature]} (parse-response response-js)]
|
||||
(if error
|
||||
(re-frame/dispatch [:group-chats.callback/sign-failed error])
|
||||
(re-frame/dispatch [:group-chats.callback/sign-success (assoc payload :signature signature)]))))
|
||||
|
||||
(defn handle-verify-signature-response
|
||||
"Callback to dispatch on verify signature response"
|
||||
[payload sender-signature response-js]
|
||||
(let [{:keys [error]} (parse-response response-js)]
|
||||
(if error
|
||||
(re-frame/dispatch [:group-chats.callback/verify-signature-failed error])
|
||||
(re-frame/dispatch [:group-chats.callback/verify-signature-success payload sender-signature]))))
|
||||
|
||||
(defn sign-membership [payload]
|
||||
(native-module/sign-group-membership (signature-material payload)
|
||||
(partial handle-sign-response payload)))
|
||||
|
||||
(defn verify-membership-signature [signatures]
|
||||
(doseq [[payload sender-signature] signatures]
|
||||
(native-module/verify-group-membership-signatures (signature-pairs payload)
|
||||
(partial handle-verify-signature-response payload sender-signature))))
|
||||
|
||||
(fx/defn create
|
||||
"Format group update message and sign membership"
|
||||
[{:keys [db random-guid-generator] :as cofx} group-name]
|
||||
(let [my-public-key (:current-public-key db)
|
||||
chat-id (str (random-guid-generator) my-public-key)
|
||||
selected-contacts (conj (:group/selected-contacts db)
|
||||
my-public-key)
|
||||
group-update (transport/map->GroupMembershipUpdate
|
||||
{:chat-id chat-id
|
||||
:chat-name group-name
|
||||
:admin my-public-key
|
||||
:participants selected-contacts
|
||||
:version 1})]
|
||||
{:group-chats/sign-membership group-update
|
||||
:db (assoc db :group/selected-contacts #{})}))
|
||||
|
||||
(defn- valid-name? [name]
|
||||
(spec/valid? :profile/name name))
|
||||
|
||||
(fx/defn update-name [{:keys [db]} name]
|
||||
{:db (-> db
|
||||
(assoc-in [:group-chat-profile/profile :valid-name?] (valid-name? name))
|
||||
(assoc-in [:group-chat-profile/profile :name] name))})
|
||||
|
||||
(fx/defn handle-name-changed
|
||||
"Store name in profile scratchpad"
|
||||
[cofx new-chat-name]
|
||||
(update-name cofx new-chat-name))
|
||||
|
||||
(fx/defn save
|
||||
"Save chat from edited profile"
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [current-chat-id (get-in cofx [:db :current-chat-id])
|
||||
new-name (get-in cofx [:db :group-chat-profile/profile :name])]
|
||||
(when (valid-name? new-name)
|
||||
(fx/merge cofx
|
||||
{:db (assoc db :group-chat-profile/editing? false)}
|
||||
(models.chat/upsert-chat {:chat-id current-chat-id
|
||||
:name new-name})))))
|
||||
(re-frame/reg-fx
|
||||
:group-chats/sign-membership
|
||||
sign-membership)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:group-chats/verify-membership-signature
|
||||
(fn [signatures]
|
||||
(verify-membership-signature signatures)))
|
||||
|
|
|
@ -59,3 +59,7 @@
|
|||
|
||||
(defn is24Hour []
|
||||
(native-module/is24Hour))
|
||||
|
||||
(def verify-group-membership-signatures native-module/verify-group-membership-signatures)
|
||||
|
||||
(def sign-group-membership native-module/sign-group-membership)
|
||||
|
|
|
@ -134,6 +134,14 @@
|
|||
(fn [UUID]
|
||||
(callback (string/upper-case UUID))))))
|
||||
|
||||
(defn verify-group-membership-signatures [signature-pairs callback]
|
||||
(when status
|
||||
(call-module #(.verifyGroupMembershipSignatures status signature-pairs callback))))
|
||||
|
||||
(defn sign-group-membership [content callback]
|
||||
(when status
|
||||
(call-module #(.signGroupMembership status content callback))))
|
||||
|
||||
(defn is24Hour []
|
||||
(when status
|
||||
(.-is24Hour status)))
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
|
||||
(defn- get-base-node-config [config]
|
||||
(assoc config
|
||||
:BackupDisabledDataDir (utils.platform/no-backup-directory)
|
||||
:Name "StatusIM"))
|
||||
|
||||
(defn- pick-nodes
|
||||
|
@ -94,7 +95,6 @@
|
|||
:MinimumPoW 0.001
|
||||
:EnableNTPSync true}
|
||||
:RequireTopics (get-topics network)
|
||||
:BackupDisabledDataDir (utils.platform/no-backup-directory)
|
||||
:InstallationID installation-id
|
||||
:PFSEnabled (or config/pfs-encryption-enabled?
|
||||
config/group-chats-enabled?))
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
(extend-type transport.protocol/GroupMembershipUpdate
|
||||
message/StatusMessage
|
||||
(receive [this _ signature _ cofx]
|
||||
(group-chats/handle-membership-update cofx this signature)))
|
||||
(group-chats/handle-membership-update-received cofx this signature)))
|
||||
|
||||
(extend-type transport.protocol/GroupLeave
|
||||
message/StatusMessage
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
(extend-type transport/GroupLeave
|
||||
message/StatusMessage
|
||||
(send [this chat-id cofx]
|
||||
(group-chats/handle-group-leave this chat-id cofx)))
|
||||
(group-chats/send-group-leave this chat-id cofx)))
|
||||
|
|
|
@ -65,8 +65,8 @@
|
|||
(deftype GroupMembershipUpdateHandler []
|
||||
Object
|
||||
(tag [this v] "g5")
|
||||
(rep [this {:keys [chat-id chat-name admin participants signature message]}]
|
||||
#js [chat-id chat-name admin participants signature message]))
|
||||
(rep [this {:keys [chat-id chat-name admin participants leaves version signature message]}]
|
||||
#js [chat-id chat-name admin participants leaves version signature message]))
|
||||
|
||||
(def writer (transit/writer :json
|
||||
{:handlers
|
||||
|
@ -110,8 +110,8 @@
|
|||
(v1.protocol/MessagesSeen. message-ids))
|
||||
"c6" (fn [[name profile-image address fcm-token]]
|
||||
(v1.contact/ContactUpdate. name profile-image address fcm-token))
|
||||
"g5" (fn [[chat-id chat-name admin participants signature message]]
|
||||
(v1/GroupMembershipUpdate. chat-id chat-name admin participants nil signature message))}})) ; removed group chat handlers for https://github.com/status-im/status-react/issues/4506
|
||||
"g5" (fn [[chat-id chat-name admin participants leaves version signature message]]
|
||||
(v1/GroupMembershipUpdate. chat-id chat-name admin participants leaves version signature message))}})) ; removed group chat handlers for https://github.com/status-im/status-react/issues/4506
|
||||
|
||||
(defn serialize
|
||||
"Serializes a record implementing the StatusMessage protocol using the custom writers"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
(:require [status-im.transport.message.core :as message]))
|
||||
|
||||
(defrecord GroupMembershipUpdate
|
||||
[chat-id chat-name admin participants leaves signature message]
|
||||
[chat-id chat-name admin participants leaves version signature message]
|
||||
message/StatusMessage)
|
||||
|
||||
(defrecord GroupLeave
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
[status-im.react-native.resources :as resources]))
|
||||
|
||||
(defn default-chat-icon [name styles]
|
||||
(when name
|
||||
(when-not (string/blank? name)
|
||||
[react/view (:default-chat-icon styles)
|
||||
[react/text {:style (:default-chat-icon-text styles)}
|
||||
(string/capitalize (first name))]]))
|
||||
|
|
|
@ -14,8 +14,7 @@
|
|||
(fn [{:keys [db] :as cofx} [_ chat-id]]
|
||||
(fx/merge cofx
|
||||
{:db (assoc db
|
||||
:new-chat-name (get-in db [:chats chat-id :name])
|
||||
:group/group-type :chat-group)}
|
||||
:new-chat-name (get-in db [:chats chat-id :name]))}
|
||||
(navigation/navigate-to-cofx :group-chat-profile nil))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
|
@ -32,9 +31,9 @@
|
|||
(assoc-in [:chats current-chat-id :contacts] participants)
|
||||
(assoc :selected-participants #{}))
|
||||
:data-store/tx [(chats-store/add-chat-contacts-tx current-chat-id selected-participants)]}
|
||||
(models.message/receive
|
||||
(models.message/system-message current-chat-id message-id now
|
||||
(str "You've added " (apply str (interpose ", " added-participants-names)))))
|
||||
#_(models.message/receive
|
||||
(models.message/system-message current-chat-id message-id now
|
||||
(str "You've added " (apply str (interpose ", " added-participants-names)))))
|
||||
#_(transport/send (protocol/GroupAdminUpdate. nil participants current-chat-id) current-chat-id)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
|
@ -49,14 +48,7 @@
|
|||
(fx/merge cofx
|
||||
{:db (assoc-in db [:chats current-chat-id :contacts] participants)
|
||||
:data-store/tx [(chats-store/remove-chat-contacts-tx current-chat-id removed-participants)]}
|
||||
(models.message/receive
|
||||
(models.message/system-message current-chat-id message-id now
|
||||
(str "You've removed " (apply str (interpose ", " removed-participants-names)))))
|
||||
#_(models.message/receive
|
||||
(models.message/system-message current-chat-id message-id now
|
||||
(str "You've removed " (apply str (interpose ", " removed-participants-names)))))
|
||||
#_(transport/send (protocol/GroupAdminUpdate. nil participants current-chat-id) current-chat-id)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:set-group-chat-name
|
||||
(fn [{{:keys [current-chat-id] :as db} :db} [_ new-chat-name]]
|
||||
{:db (assoc-in db [:chats current-chat-id :name] new-chat-name)
|
||||
:data-store/tx [(chats-store/save-chat-tx {:chat-id current-chat-id
|
||||
:name new-chat-name})]}))
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
toolbar/default-nav-back
|
||||
[toolbar/content-title (i18n/label :t/group-chat)]
|
||||
(when save-btn-enabled?
|
||||
(let [handler #(re-frame/dispatch [:chat.ui/start-group-chat group-name])]
|
||||
(let [handler #(re-frame/dispatch [:group-chats.ui/create-pressed group-name])]
|
||||
(if platform/android?
|
||||
[toolbar/actions [{:icon :icons/ok
|
||||
:icon-opts {:color :blue
|
||||
|
|
|
@ -12,12 +12,6 @@
|
|||
(update :navigation-stack conj view-id)
|
||||
(assoc :view-id view-id)))
|
||||
|
||||
(defn- replace-top-element [stack view-id]
|
||||
(let [stack' (if (> 2 (count stack))
|
||||
(list :home)
|
||||
(pop stack))]
|
||||
(conj stack' view-id)))
|
||||
|
||||
;; public fns
|
||||
|
||||
(fx/defn navigate-to-clean
|
||||
|
|
|
@ -49,11 +49,6 @@
|
|||
(fn [cofx _]
|
||||
(profile.models/start-editing-group-chat-profile cofx)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:group-chat-profile/save-profile
|
||||
(fn [cofx _]
|
||||
(profile.models/save-group-chat-profile cofx)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:my-profile/enter-two-random-words
|
||||
(fn [cofx _]
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
[toolbar/toolbar {}
|
||||
nil
|
||||
[toolbar/content-title ""]
|
||||
[toolbar/default-done {:handler #(re-frame/dispatch [:group-chat-profile/save-profile])
|
||||
[toolbar/default-done {:handler #(re-frame/dispatch [:group-chats.ui/save-pressed])
|
||||
:icon :icons/ok
|
||||
:icon-opts {:color colors/blue
|
||||
:accessibility-label :done-button}}]])
|
||||
|
@ -47,7 +47,7 @@
|
|||
:accessibility-label :clear-history-button}
|
||||
{:label (i18n/label :t/delete-chat)
|
||||
:icon :icons/arrow-left
|
||||
:action #(re-frame/dispatch [:group-chat.ui/leave-group-pressed chat-id])
|
||||
:action #(re-frame/dispatch [:chat.ui/remove-chat-pressed chat-id])
|
||||
:accessibility-label :delete-chat-button}]))
|
||||
|
||||
(defn contact-actions [contact]
|
||||
|
@ -99,7 +99,7 @@
|
|||
{:contact shown-chat
|
||||
:editing? editing?
|
||||
:allow-icon-change? false
|
||||
:on-change-text-event :set-group-chat-name}]
|
||||
:on-change-text-event :group-chats.ui/name-changed}]
|
||||
[list/action-list (actions admin? (:chat-id current-chat))
|
||||
{:container-style styles/action-container
|
||||
:action-style styles/action
|
||||
|
|
|
@ -73,10 +73,6 @@
|
|||
(defn start-editing-group-chat-profile [{:keys [db]}]
|
||||
{:db (assoc db :group-chat-profile/editing? true)})
|
||||
|
||||
(defn save-group-chat-profile [{:keys [db]}]
|
||||
(-> {:db db}
|
||||
(update :db dissoc :group-chat-profile/editing?)))
|
||||
|
||||
(defn enter-two-random-words [{:keys [db]}]
|
||||
(let [{:keys [mnemonic]} (:account/account db)
|
||||
shuffled-mnemonic (shuffle (map-indexed vector (clojure.string/split mnemonic #" ")))]
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#{: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/generate-sym-key-from-password :confirm-messages-processed
|
||||
:utils/dispatch-later})
|
||||
:group-chats/verify-membership-signature :utils/dispatch-later})
|
||||
|
||||
(defn- safe-merge [fx new-fx]
|
||||
(if (:merging-fx-with-common-keys fx)
|
||||
|
|
|
@ -48,12 +48,13 @@
|
|||
:current-chat-id "chat-id"
|
||||
:chats {"chat-id" {:messages {}}}}]
|
||||
(testing "a message coming from you!"
|
||||
(let [actual (message/receive {:db db}
|
||||
{:from "me"
|
||||
:message-id "id"
|
||||
:chat-id "chat-id"
|
||||
:content "b"
|
||||
:clock-value 1})
|
||||
(let [actual (message/receive-many {:db db}
|
||||
[{:from "me"
|
||||
:message-type :user-message
|
||||
:message-id "id"
|
||||
:chat-id "chat-id"
|
||||
:content "b"
|
||||
:clock-value 1}])
|
||||
message (get-in actual [:db :chats "chat-id" :messages "id"])
|
||||
status (get-in actual [:db :chats "chat-id" :message-statuses "id" "me" :status])]
|
||||
(testing "it adds the message"
|
||||
|
@ -69,34 +70,119 @@
|
|||
(testing "it marks it as sent"
|
||||
(is (= :sent status)))))))
|
||||
|
||||
(deftest receive-group-chats
|
||||
(let [cofx {:db {:chats {"chat-id" {:contacts #{"present"}}}
|
||||
:account/account {:public-key "a"}
|
||||
:current-chat-id "chat-id"
|
||||
:view-id :chat}}
|
||||
valid-message {:chat-id "chat-id"
|
||||
:from "present"
|
||||
:message-type :group-user-message
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:timestamp 0}
|
||||
bad-chat-id-message {:chat-id "bad-chat-id"
|
||||
:from "present"
|
||||
:message-type :group-user-message
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:timestamp 0}
|
||||
bad-from-message {:chat-id "chat-id"
|
||||
:from "not-present"
|
||||
:message-type :group-user-message
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:timestamp 0}]
|
||||
(testing "a valid message"
|
||||
(is (get-in (message/receive-many cofx [valid-message]) [:db :chats "chat-id" :messages "1"])))
|
||||
(testing "a message from someone not in the list of participants"
|
||||
(is (= cofx (message/receive-many cofx [bad-from-message]))))
|
||||
(testing "a message with non existing chat-id"
|
||||
(is (= cofx (message/receive-many cofx [bad-chat-id-message]))))))
|
||||
|
||||
(deftest receive-public-chats
|
||||
(let [cofx {:db {:chats {"chat-id" {:public? true}}
|
||||
:account/account {:public-key "a"}
|
||||
:current-chat-id "chat-id"
|
||||
:view-id :chat}}
|
||||
valid-message {:chat-id "chat-id"
|
||||
:from "anyone"
|
||||
:message-type :public-group-user-message
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:timestamp 0}
|
||||
bad-chat-id-message {:chat-id "bad-chat-id"
|
||||
:from "present"
|
||||
:message-type :public-group-user-message
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:timestamp 0}]
|
||||
(testing "a valid message"
|
||||
(is (get-in (message/receive-many cofx [valid-message]) [:db :chats "chat-id" :messages "1"])))
|
||||
(testing "a message with non existing chat-id"
|
||||
(is (= cofx (message/receive-many cofx [bad-chat-id-message]))))))
|
||||
|
||||
(deftest receive-one-to-one
|
||||
(let [cofx {:db {:chats {"matching" {}}
|
||||
:account/account {:public-key "a"}
|
||||
:current-public-key "me"
|
||||
:current-chat-id "chat-id"
|
||||
:view-id :chat}}
|
||||
valid-message {:chat-id "matching"
|
||||
:from "matching"
|
||||
:message-type :user-message
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:timestamp 0}
|
||||
own-message {:chat-id "matching"
|
||||
:from "me"
|
||||
:message-type :user-message
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:timestamp 0}
|
||||
|
||||
bad-chat-id-message {:chat-id "bad-chat-id"
|
||||
:from "not-matching"
|
||||
:message-type :user-message
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:timestamp 0}]
|
||||
(testing "a valid message"
|
||||
(is (get-in (message/receive-many cofx [valid-message]) [:db :chats "matching" :messages "1"])))
|
||||
(testing "our own message"
|
||||
(is (get-in (message/receive-many cofx [own-message]) [:db :chats "matching" :messages "1"])))
|
||||
(testing "a message with non matching chat-id"
|
||||
(is (= cofx (message/receive-many cofx [bad-chat-id-message]))))))
|
||||
|
||||
(deftest receive-send-seen
|
||||
(let [cofx {:db {:chats {"chat-id" {}}
|
||||
:account/account {:public-key "a"}
|
||||
:current-chat-id "chat-id"
|
||||
:view-id :chat}}
|
||||
message {:chat-id "chat-id"
|
||||
:from "a"
|
||||
:message-type :user-message
|
||||
:from "chat-id"
|
||||
:message-id "1"
|
||||
:clock-value 0
|
||||
:clock-value 1
|
||||
:timestamp 0}
|
||||
extract-seen (comp :payload :message first :shh/post)]
|
||||
(testing "it send a seen message when the chat is 1-to-1 and is open"
|
||||
(is (instance? protocol/MessagesSeen
|
||||
(extract-seen (message/receive cofx message))))
|
||||
(is (= #{"1"} (:message-ids (extract-seen (message/receive cofx message))))))
|
||||
(extract-seen (message/receive-many cofx [message]))))
|
||||
(is (= #{"1"} (:message-ids (extract-seen (message/receive-many cofx [message]))))))
|
||||
(testing "it does not send any when the chat is a group-chat"
|
||||
(is (nil? (extract-seen
|
||||
(message/receive
|
||||
(message/receive-many
|
||||
(assoc-in cofx [:db :chats "chat-id" :group-chat] true)
|
||||
message)))))
|
||||
[message])))))
|
||||
(testing "it does not send any when we are in a different chat"
|
||||
(is (nil? (extract-seen
|
||||
(message/receive (assoc-in cofx [:db :current-chat-id] :different)
|
||||
message)))))
|
||||
(message/receive-many (assoc-in cofx [:db :current-chat-id] :different)
|
||||
[message])))))
|
||||
(testing "it does not send any when we are not in a chat view"
|
||||
(is (nil? (extract-seen
|
||||
(message/receive (assoc-in cofx [:db :view-id] :home)
|
||||
message)))))))
|
||||
(message/receive-many (assoc-in cofx [:db :view-id] :home)
|
||||
[message])))))))
|
||||
|
||||
(deftest delete-message
|
||||
(let [timestamp (time/now)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[status-im.utils.config :as config]
|
||||
[status-im.group-chats.core :as group-chats]))
|
||||
|
||||
(def chat-id "0xba")
|
||||
(def random-id "685a9351-417e-587c-8bc1-191ac2a57ef8")
|
||||
(def chat-name "chat-name")
|
||||
|
||||
(def member-1 "member-1")
|
||||
|
@ -11,6 +11,8 @@
|
|||
|
||||
(def admin member-1)
|
||||
|
||||
(def chat-id (str random-id admin))
|
||||
|
||||
(def invitation-m1 {:id "m-1"
|
||||
:user member-1})
|
||||
(def invitation-m2 {:id "m-2"
|
||||
|
@ -42,6 +44,18 @@
|
|||
(testing "it sets the right version"
|
||||
(is (= 1
|
||||
(:membership-version actual))))))
|
||||
(testing "a chat with the wrong id"
|
||||
(let [bad-chat-id (str random-id member-2)
|
||||
actual (->
|
||||
(group-chats/handle-membership-update
|
||||
{:db {}}
|
||||
(assoc initial-message :chat-id bad-chat-id)
|
||||
admin)
|
||||
:db
|
||||
:chats
|
||||
(get bad-chat-id))]
|
||||
(testing "it does not create a chat"
|
||||
(is (not actual)))))
|
||||
(testing "an already existing chat"
|
||||
(let [cofx {:db {:chats {chat-id {:contacts [invitation-m1
|
||||
invitation-m2]
|
||||
|
@ -51,7 +65,7 @@
|
|||
(testing "the message is an older version"
|
||||
(let [actual (group-chats/handle-membership-update cofx initial-message admin)]
|
||||
(testing "it noops"
|
||||
(is (not actual)))))
|
||||
(is (= actual cofx)))))
|
||||
(testing "the message is a more recent version"
|
||||
(testing "it sets the right participants")))
|
||||
(testing "a leave from a member is received"
|
||||
|
|
Loading…
Reference in New Issue