Make sure mobile understands community share link by Desktop (#14679)

* we are now able to navigate to desktop communities

b4bdfd3d...d2e95eee

In this commit we add support for various status-go methods in mobile :
- `multiformatSerializePublicKey`
- `multiformatDeserializePublicKey`
- `compressPublicKey`
- `decompressPublicKey`
- and my personal favourite `deserializeAndCompressKey`

When someone pastes a community joining share url into chat and taps on it, we check whether the community was generated on a desktop or mobile.
We need to do this because currently both the clients have different urls for joining a community.

Once we have identified that the url is generated via desktop we then convert that url to something that the mobile client is used to.
This enables the mobile client to view this community and interact with it.

However more work needs to be done in the future to ensure that mobile implements these compressed keys end to end, we need to get this feature in so that
by the time RC1 is released mobile client is able to join communities created by Desktop.
This commit is contained in:
Siddarth Kumar 2023-01-04 18:24:11 +05:30 committed by GitHub
parent 590c0629b6
commit ec15232af8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 219 additions and 8 deletions

View File

@ -985,6 +985,95 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
StatusThreadPoolExecutor.getInstance().execute(runnableTask); StatusThreadPoolExecutor.getInstance().execute(runnableTask);
} }
@ReactMethod
public void multiformatSerializePublicKey(final String multiCodecKey, final String base58btc, final Callback callback) throws JSONException {
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable runnableTask = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiformatSerializePublicKey(multiCodecKey,base58btc);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod
public void multiformatDeserializePublicKey(final String multiCodecKey, final String base58btc, final Callback callback) throws JSONException {
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable runnableTask = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiformatDeserializePublicKey(multiCodecKey,base58btc);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod
public void compressPublicKey(final String multiCodecKey, final Callback callback) throws JSONException {
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable runnableTask = new Runnable() {
@Override
public void run() {
String res = Statusgo.compressPublicKey(multiCodecKey);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod
public void decompressPublicKey(final String multiCodecKey, final Callback callback) throws JSONException {
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable runnableTask = new Runnable() {
@Override
public void run() {
String res = Statusgo.decompressPublicKey(multiCodecKey);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod
public void deserializeAndCompressKey(final String desktopKey, final Callback callback) throws JSONException {
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable runnableTask = new Runnable() {
@Override
public void run() {
String res = Statusgo.deserializeAndCompressKey(desktopKey);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod @ReactMethod
public void hashTypedData(final String data, final Callback callback) { public void hashTypedData(final String data, final Callback callback) {

View File

@ -339,6 +339,38 @@ RCT_EXPORT_METHOD(inputConnectionStringForBootstrapping:(NSString *)cs
callback(@[result]); callback(@[result]);
} }
RCT_EXPORT_METHOD(multiformatSerializePublicKey:(NSString *)multiCodecKey
base58btc:(NSString *)base58btc
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoMultiformatSerializePublicKey(multiCodecKey,base58btc);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiformatDeserializePublicKey:(NSString *)multiCodecKey
base58btc:(NSString *)base58btc
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoMultiformatDeserializePublicKey(multiCodecKey,base58btc);
callback(@[result]);
}
RCT_EXPORT_METHOD(decompressPublicKey:(NSString *)multiCodecKey
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoDecompressPublicKey(multiCodecKey);
callback(@[result]);
}
RCT_EXPORT_METHOD(compressPublicKey:(NSString *)multiCodecKey
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoCompressPublicKey(multiCodecKey);
callback(@[result]);
}
RCT_EXPORT_METHOD(deserializeAndCompressKey:(NSString *)desktopKey
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoDeserializeAndCompressKey(desktopKey);
callback(@[result]);
}
RCT_EXPORT_METHOD(hashTypedData:(NSString *)data RCT_EXPORT_METHOD(hashTypedData:(NSString *)data
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG

View File

@ -205,9 +205,26 @@
(def ^:const community-member-role-manage-users 2) (def ^:const community-member-role-manage-users 2)
(def ^:const community-member-role-moderator 3) (def ^:const community-member-role-moderator 3)
(def local-pairing-connection-string-identifier (def ^:const local-pairing-connection-string-identifier
"If any string begins with cs we know its a connection string. "If any string begins with cs we know its a connection string.
This is useful when we read QR codes we know it is a connection string if it begins with this identifier. This is useful when we read QR codes we know it is a connection string if it begins with this identifier.
An example of a connection string is -> cs2:5vd6J6:Jfc:27xMmHKEYwzRGXcvTtuiLZFfXscMx4Mz8d9wEHUxDj4p7:EG7Z13QScfWBJNJ5cprszzDQ5fBVsYMirXo8MaQFJvpF:3 " An example of a connection string is -> cs2:5vd6J6:Jfc:27xMmHKEYwzRGXcvTtuiLZFfXscMx4Mz8d9wEHUxDj4p7:EG7Z13QScfWBJNJ5cprszzDQ5fBVsYMirXo8MaQFJvpF:3 "
"cs") "cs")
(def ^:const serialization-key
"We pass this serialization key as a parameter to MultiformatSerializePublicKey
function at status-go, This key determines the output base of the serialization.
according to https://specs.status.im/spec/2#public-key-serialization we serialize
keys with base58btc encoding"
"z")
(def ^:const deserialization-key
"We pass this deserialization key as a parameter to MultiformatDeserializePublicKey
function at status-go, This key determines the output base of the deserialization.
according to https://specs.status.im/spec/2#public-key-serialization we deserialize
keys with base16 hexadecimal encoding"
"f")
(def ^:const multi-code-prefix
"We prefix our keys with 0xe701 prior to serialisation them"
"0xe701")

View File

@ -5,7 +5,8 @@
[status-im.utils.platform :as platform] [status-im.utils.platform :as platform]
[status-im.utils.react-native :as react-native-utils] [status-im.utils.react-native :as react-native-utils]
[status-im.utils.types :as types] [status-im.utils.types :as types]
[taoensso.timbre :as log])) [taoensso.timbre :as log]
[status-im.constants :as constants]))
(defn status (defn status
[] []
@ -278,6 +279,55 @@
:connection-string connection-string}) :connection-string connection-string})
(.inputConnectionStringForBootstrapping ^js (status) connection-string config-json callback)) (.inputConnectionStringForBootstrapping ^js (status) connection-string config-json callback))
(defn deserialize-and-compress-key
"Provides a community id (public key) to status-go which is first deserialized
and then compressed. Example input/output :
input key = zQ3shTAten2v9CwyQD1Kc7VXAqNPDcHZAMsfbLHCZEx6nFqk9 and
output key = 0x025596a7ff87da36860a84b0908191ce60a504afc94aac93c1abd774f182967ce6"
[key callback]
(log/info "[native-module] Deserializing and then compressing public key"
{:fn :deserialize-and-compress-key
:key key})
(.deserializeAndCompressKey ^js (status) key callback))
(defn public-key->compressed-key
"Provides public key to status-go and gets back a compressed key via serialization"
[public-key callback]
(let [serialization-key constants/serialization-key
multi-code-prefix constants/multi-code-prefix
multi-code-key (str multi-code-prefix (subs public-key 2))]
(log/info "[native-module] Serializing public key"
{:fn :public-key->compressed-key
:public-key public-key
:multi-code-key multi-code-key})
(.multiformatSerializePublicKey ^js (status) multi-code-key serialization-key callback)))
(defn compressed-key->public-key
"Provides compressed key to status-go and gets back the uncompressed public key via deserialization"
[public-key callback]
(let [deserialization-key constants/deserialization-key]
(log/info "[native-module] Deserializing compressed key"
{:fn :compressed-key->public-key
:public-key public-key})
(.multiformatDeserializePublicKey ^js (status) public-key deserialization-key callback)))
(defn decompress-public-key
"Provides compressed key to status-go and gets back the uncompressed public key"
[public-key callback]
(log/info "[native-module] Decompressing public key"
{:fn :decompress-public-key
:public-key public-key})
(.decompressPublicKey ^js (status) public-key callback))
(defn compress-public-key
"Provides a public key to status-go and gets back a 33bit compressed key back"
[public-key callback]
(log/info "[native-module] Compressing public key"
{:fn :compress-public-key
:public-key public-key})
(.compressPublicKey ^js (status) public-key callback))
(defn hash-typed-data (defn hash-typed-data
"used for keycard" "used for keycard"
[data callback] [data callback]

View File

@ -199,6 +199,12 @@
{:type :wallet-account {:type :wallet-account
:account (when account (string/lower-case account))}) :account (when account (string/lower-case account))})
(defn community-route-type
[route-params]
(if (string/starts-with? (:community-id route-params) "z")
:desktop-community
:community))
(defn handle-uri (defn handle-uri
[chain chats uri cb] [chain chats uri cb]
(let [{:keys [handler route-params query-params]} (match-uri uri)] (let [{:keys [handler route-params query-params]} (match-uri uri)]
@ -229,7 +235,8 @@
(cb {:type handler :community-id (:community-id route-params)}) (cb {:type handler :community-id (:community-id route-params)})
(= handler :community) (= handler :community)
(cb {:type handler :community-id (:community-id route-params)}) (cb {:type (community-route-type route-params)
:community-id (:community-id route-params)})
(= handler :community-chat) (= handler :community-chat)
(cb {:type handler :chat-id (:chat-id route-params)}) (cb {:type handler :chat-id (:chat-id route-params)})

View File

@ -14,7 +14,8 @@
[utils.re-frame :as rf] [utils.re-frame :as rf]
[status-im.wallet.choose-recipient.core :as choose-recipient] [status-im.wallet.choose-recipient.core :as choose-recipient]
[status-im2.navigation.events :as navigation] [status-im2.navigation.events :as navigation]
[taoensso.timbre :as log])) [taoensso.timbre :as log]
[status-im.native-module.core :as status]))
;; TODO(yenda) investigate why `handle-universal-link` event is ;; TODO(yenda) investigate why `handle-universal-link` event is
;; dispatched 7 times for the same link ;; dispatched 7 times for the same link
@ -76,7 +77,21 @@
(rf/defn handle-community (rf/defn handle-community
[cofx {:keys [community-id]}] [cofx {:keys [community-id]}]
(log/info "universal-links: handling community" community-id) (log/info "universal-links: handling community" community-id)
(navigation/navigate-to-cofx cofx :community {:community-id community-id})) (navigation/navigate-to-cofx cofx :community {:community-id community-id})
)
(rf/defn handle-navigation-to-desktop-community-from-mobile
{:events [:handle-navigation-to-desktop-community-from-mobile]}
[{:keys [db]} cofx deserialized-key]
(navigation/navigate-to-cofx cofx :community {:community-id deserialized-key})
)
(rf/defn handle-desktop-community
[cofx {:keys [community-id]}]
(status/deserialize-and-compress-key
community-id
(fn [deserialized-key]
(rf/dispatch [:handle-navigation-to-desktop-community-from-mobile cofx (str deserialized-key)]))))
(rf/defn handle-community-chat (rf/defn handle-community-chat
[cofx {:keys [chat-id]}] [cofx {:keys [chat-id]}]
@ -145,6 +160,7 @@
:private-chat (handle-private-chat cofx data) :private-chat (handle-private-chat cofx data)
:community-requests (handle-community-requests cofx data) :community-requests (handle-community-requests cofx data)
:community (handle-community cofx data) :community (handle-community cofx data)
:desktop-community (handle-desktop-community cofx data)
:community-chat (handle-community-chat cofx data) :community-chat (handle-community-chat cofx data)
:contact (handle-view-profile cofx data) :contact (handle-view-profile cofx data)
:browser (handle-browse cofx data) :browser (handle-browse cofx data)

View File

@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>", "_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im", "owner": "status-im",
"repo": "status-go", "repo": "status-go",
"version": "v0.117.1a", "version": "d43e06f4c27a900641cd55c2a46002e6f0909c95",
"commit-sha1": "b4bdfd3df6cf5fb91ab2d0e9f3b38e8d1b9703e5", "commit-sha1": "d43e06f4c27a900641cd55c2a46002e6f0909c95",
"src-sha256": "1s50q53p1j5ysnbj88c52zb2rh1ms21pnf6bjc7wja8gzcpih2wl" "src-sha256": "18n5h3yx6wxb5l1nvra868dhnyl732zvpdn3mqg4zfsjxmx82np7"
} }