handle initialized cards
Signed-off-by: Dmitry Novotochinov <dmitry.novot@gmail.com>
This commit is contained in:
parent
8ace86f7da
commit
1df30f7447
|
@ -19,8 +19,10 @@ var TopLevel = {
|
||||||
"argv" : function () {},
|
"argv" : function () {},
|
||||||
"Array" : function () {},
|
"Array" : function () {},
|
||||||
"array" : function () {},
|
"array" : function () {},
|
||||||
|
"AsyncStorage" : function () {},
|
||||||
"at" : function () {},
|
"at" : function () {},
|
||||||
"back" : function () {},
|
"back" : function () {},
|
||||||
|
"BackHandler" : function () {},
|
||||||
"balanceOf" : function () {},
|
"balanceOf" : function () {},
|
||||||
"bezier" : function () {},
|
"bezier" : function () {},
|
||||||
"BigNumber" : function () {},
|
"BigNumber" : function () {},
|
||||||
|
@ -151,6 +153,7 @@ var TopLevel = {
|
||||||
"getInitialNotification" : function () {},
|
"getInitialNotification" : function () {},
|
||||||
"getInitialURL" : function () {},
|
"getInitialURL" : function () {},
|
||||||
"getInternetCredentials" : function () {},
|
"getInternetCredentials" : function () {},
|
||||||
|
"getItem" : function () {},
|
||||||
"getKeys" : function () {},
|
"getKeys" : function () {},
|
||||||
"getLayout" : function () {},
|
"getLayout" : function () {},
|
||||||
"getNetwork" : function () {},
|
"getNetwork" : function () {},
|
||||||
|
@ -401,6 +404,7 @@ var TopLevel = {
|
||||||
"routeName" : function () {},
|
"routeName" : function () {},
|
||||||
"routes" : function () {},
|
"routes" : function () {},
|
||||||
"saveAccountAndLogin" : function () {},
|
"saveAccountAndLogin" : function () {},
|
||||||
|
"saveAccountAndLoginWithKeycard" : function () {},
|
||||||
"schemaVersion" : function () {},
|
"schemaVersion" : function () {},
|
||||||
"scrollTo" : function () {},
|
"scrollTo" : function () {},
|
||||||
"scrollToEnd" : function () {},
|
"scrollToEnd" : function () {},
|
||||||
|
@ -432,6 +436,7 @@ var TopLevel = {
|
||||||
"setHidden" : function () {},
|
"setHidden" : function () {},
|
||||||
"setInternetCredentials" : function () {},
|
"setInternetCredentials" : function () {},
|
||||||
"setInterval" : function () {},
|
"setInterval" : function () {},
|
||||||
|
"setItem" : function () {},
|
||||||
"setNativeProps" : function () {},
|
"setNativeProps" : function () {},
|
||||||
"setNetworkActivityIndicatorVisible" : function () {},
|
"setNetworkActivityIndicatorVisible" : function () {},
|
||||||
"setPriority" : function () {},
|
"setPriority" : function () {},
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
"react-native-screens": "1.0.0-alpha.22",
|
"react-native-screens": "1.0.0-alpha.22",
|
||||||
"react-native-shake": "^3.3.1",
|
"react-native-shake": "^3.3.1",
|
||||||
"react-native-splash-screen": "^3.2.0",
|
"react-native-splash-screen": "^3.2.0",
|
||||||
"react-native-status-keycard": "^2.5.7",
|
"react-native-status-keycard": "^2.5.11",
|
||||||
"react-native-svg": "9.8.4",
|
"react-native-svg": "9.8.4",
|
||||||
"react-native-touch-id": "^4.4.1",
|
"react-native-touch-id": "^4.4.1",
|
||||||
"react-native-webview": "6.11.1",
|
"react-native-webview": "6.11.1",
|
||||||
|
|
|
@ -4898,7 +4898,7 @@ react-native-splash-screen@^3.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/react-native-splash-screen/-/react-native-splash-screen-3.2.0.tgz#d47ec8557b1ba988ee3ea98d01463081b60fff45"
|
resolved "https://registry.yarnpkg.com/react-native-splash-screen/-/react-native-splash-screen-3.2.0.tgz#d47ec8557b1ba988ee3ea98d01463081b60fff45"
|
||||||
integrity sha512-Ls9qiNZzW/OLFoI25wfjjAcrf2DZ975hn2vr6U9gyuxi2nooVbzQeFoQS5vQcbCt9QX5NY8ASEEAtlLdIa6KVg==
|
integrity sha512-Ls9qiNZzW/OLFoI25wfjjAcrf2DZ975hn2vr6U9gyuxi2nooVbzQeFoQS5vQcbCt9QX5NY8ASEEAtlLdIa6KVg==
|
||||||
|
|
||||||
react-native-status-keycard@^2.5.7:
|
react-native-status-keycard@^2.5.11:
|
||||||
version "2.5.11"
|
version "2.5.11"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-status-keycard/-/react-native-status-keycard-2.5.11.tgz#ba7d6b417ca3de345b7da27997d799ece6de6b68"
|
resolved "https://registry.yarnpkg.com/react-native-status-keycard/-/react-native-status-keycard-2.5.11.tgz#ba7d6b417ca3de345b7da27997d799ece6de6b68"
|
||||||
integrity sha512-yc1Jkr+mKJpyd8QRJuYFchzkZ8ANDSC2CPYVKJJN2i93RReft3o2cHAi+Sn5LxI5Ex5ZpLaEzdL5ezG2EWbrjA==
|
integrity sha512-yc1Jkr+mKJpyd8QRJuYFchzkZ8ANDSC2CPYVKJJN2i93RReft3o2cHAi+Sn5LxI5Ex5ZpLaEzdL5ezG2EWbrjA==
|
||||||
|
|
|
@ -292,6 +292,20 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void saveAccountAndLoginWithKeycard(final String accountData, final String password , final String config, final String chatKey) {
|
||||||
|
Log.d(TAG, "saveAccountAndLoginWithKeycard");
|
||||||
|
String finalConfig = prepareDirAndUpdateConfig(config);
|
||||||
|
String result = Statusgo.saveAccountAndLoginWithKeycard(accountData, password, finalConfig, chatKey);
|
||||||
|
if (result.startsWith("{\"error\":\"\"")) {
|
||||||
|
Log.d(TAG, "StartNode result: " + result);
|
||||||
|
Log.d(TAG, "Geth node started");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log.e(TAG, "StartNode failed: " + result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
public void login(final String accountData, final String password) {
|
public void login(final String accountData, final String password) {
|
||||||
Log.d(TAG, "login");
|
Log.d(TAG, "login");
|
||||||
|
@ -432,22 +446,15 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
public void loginWithKeycard(final String whisperPrivateKey, final String encryptionPublicKey, final String configJSON, final Callback callback) {
|
public void loginWithKeycard(final String accountData, final String password, final String chatKey) {
|
||||||
Log.d(TAG, "loginWithKeycard");
|
Log.d(TAG, "loginWithKeycard");
|
||||||
if (!checkAvailability()) {
|
String result = Statusgo.loginWithKeycard(accountData, password, chatKey);
|
||||||
callback.invoke(false);
|
if (result.startsWith("{\"error\":\"\"")) {
|
||||||
return;
|
Log.d(TAG, "LoginWithKeycard result: " + result);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
Runnable r = new Runnable() {
|
Log.e(TAG, "LoginWithKeycard failed: " + result);
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
String result = Statusgo.loginWithKeycard(whisperPrivateKey, encryptionPublicKey, configJSON);
|
|
||||||
callback.invoke(result);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
StatusThreadPoolExecutor.getInstance().execute(r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
|
|
|
@ -403,6 +403,18 @@ RCT_EXPORT_METHOD(saveAccountAndLogin:(NSString *)accountData
|
||||||
NSLog(@"%@", result);
|
NSLog(@"%@", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////// saveAccountAndLoginWithKeycard
|
||||||
|
RCT_EXPORT_METHOD(saveAccountAndLogin:(NSString *)accountData
|
||||||
|
password:(NSString *)password
|
||||||
|
config:(NSString *)config
|
||||||
|
chatKey:(NSString *)chatKey) {
|
||||||
|
#if DEBUG
|
||||||
|
NSLog(@"SaveAccountAndLoginWithKeycard() method called");
|
||||||
|
#endif
|
||||||
|
NSString *finalConfig = [self prepareDirAndUpdateConfig:config];
|
||||||
|
NSString *result = StatusgoSaveAccountAndLoginWithKeycard(accountData, password, finalConfig, chatKey);
|
||||||
|
NSLog(@"%@", result);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////// login
|
//////////////////////////////////////////////////////////////////// login
|
||||||
RCT_EXPORT_METHOD(login:(NSString *)accountData
|
RCT_EXPORT_METHOD(login:(NSString *)accountData
|
||||||
|
|
|
@ -35,6 +35,8 @@
|
||||||
(def net-info (js/require "@react-native-community/netinfo"))
|
(def net-info (js/require "@react-native-community/netinfo"))
|
||||||
(def mail-class (js/require "react-native-mail"))
|
(def mail-class (js/require "react-native-mail"))
|
||||||
(def react-native-mail (.-default mail-class))
|
(def react-native-mail (.-default mail-class))
|
||||||
|
(def async-storage (.-AsyncStorage react-native))
|
||||||
|
(def back-handler (.-BackHandler react-native))
|
||||||
(def desktop-linking #js {:addEventListener (fn [])})
|
(def desktop-linking #js {:addEventListener (fn [])})
|
||||||
(def desktop-menu #js {:addEventListener (fn [])})
|
(def desktop-menu #js {:addEventListener (fn [])})
|
||||||
(def desktop-config #js {:addEventListener (fn [])})
|
(def desktop-config #js {:addEventListener (fn [])})
|
||||||
|
|
|
@ -758,11 +758,6 @@
|
||||||
(fn [cofx [_ error]]
|
(fn [cofx [_ error]]
|
||||||
(hardwallet/on-init-card-error cofx error)))
|
(hardwallet/on-init-card-error cofx error)))
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
|
||||||
:hardwallet.callback/on-install-applet-and-init-card-success
|
|
||||||
(fn [cofx [_ secrets]]
|
|
||||||
(hardwallet/on-install-applet-and-init-card-success cofx secrets)))
|
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:hardwallet.callback/on-install-applet-and-init-card-error
|
:hardwallet.callback/on-install-applet-and-init-card-error
|
||||||
(fn [cofx [_ error]]
|
(fn [cofx [_ error]]
|
||||||
|
@ -1025,11 +1020,6 @@
|
||||||
(fn [cofx _]
|
(fn [cofx _]
|
||||||
(hardwallet/generate-mnemonic cofx)))
|
(hardwallet/generate-mnemonic cofx)))
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
|
||||||
:hardwallet/generate-and-load-key
|
|
||||||
(fn [cofx _]
|
|
||||||
(hardwallet/generate-and-load-key cofx)))
|
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:hardwallet.ui/create-pin-button-pressed
|
:hardwallet.ui/create-pin-button-pressed
|
||||||
(fn [{:keys [db]} _]
|
(fn [{:keys [db]} _]
|
||||||
|
|
|
@ -56,6 +56,25 @@
|
||||||
(:keycard-pairing
|
(:keycard-pairing
|
||||||
(find-multiaccount-by-keycard-instance-uid db instance-uid))))))
|
(find-multiaccount-by-keycard-instance-uid db instance-uid))))))
|
||||||
|
|
||||||
|
(fx/defn listen-to-hardware-back-button
|
||||||
|
[{:keys [db]}]
|
||||||
|
(when-not (get-in db [:hardwallet :back-button-listener])
|
||||||
|
{:hardwallet/listen-to-hardware-back-button nil}))
|
||||||
|
|
||||||
|
(fx/defn remove-listener-to-hardware-back-button
|
||||||
|
[{:keys [db]}]
|
||||||
|
(when-let [listener (get-in db [:hardwallet :back-button-listener])]
|
||||||
|
{:hardwallet/remove-listener-to-hardware-back-button listener}))
|
||||||
|
|
||||||
|
(fx/defn on-add-listener-to-hardware-back-button
|
||||||
|
"Adds listener to hardware back button on Android.
|
||||||
|
During keycard setup we show user a warning that setup will be cancelled
|
||||||
|
when back button pressed. This prevents user from going back during setup
|
||||||
|
flow as some of the actions changing keycard step could not be repeated."
|
||||||
|
{:events [:hardwallet/add-listener-to-hardware-back-button]}
|
||||||
|
[{:keys [db]} listener]
|
||||||
|
{:db (assoc-in db [:hardwallet :back-button-listener] listener)})
|
||||||
|
|
||||||
(fx/defn hardwallet-connect-navigate-back-button-clicked
|
(fx/defn hardwallet-connect-navigate-back-button-clicked
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
|
@ -183,6 +202,7 @@
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:hardwallet :setup-step] :pair))}
|
(assoc-in [:hardwallet :setup-step] :pair))}
|
||||||
|
(listen-to-hardware-back-button)
|
||||||
(navigation/navigate-to-cofx :keycard-recovery-pair nil)))
|
(navigation/navigate-to-cofx :keycard-recovery-pair nil)))
|
||||||
|
|
||||||
(fx/defn load-pairing-screen
|
(fx/defn load-pairing-screen
|
||||||
|
@ -212,6 +232,8 @@
|
||||||
|
|
||||||
(fx/defn cancel-setup-pressed
|
(fx/defn cancel-setup-pressed
|
||||||
{:events [:keycard.onboarding.ui/cancel-pressed
|
{:events [:keycard.onboarding.ui/cancel-pressed
|
||||||
|
:hardwallet/back-button-pressed
|
||||||
|
:keycard.onboarding.recovery-phrase.ui/cancel-pressed
|
||||||
:keycard.onboarding.connection-lost-setup.ui/cancel-setup-pressed]}
|
:keycard.onboarding.connection-lost-setup.ui/cancel-setup-pressed]}
|
||||||
[_]
|
[_]
|
||||||
{:ui/show-confirmation {:title (i18n/label :t/keycard-cancel-setup-title)
|
{:ui/show-confirmation {:title (i18n/label :t/keycard-cancel-setup-title)
|
||||||
|
@ -223,10 +245,12 @@
|
||||||
|
|
||||||
(fx/defn cancel-setup-confirm-pressed
|
(fx/defn cancel-setup-confirm-pressed
|
||||||
{:events [:keycard.onboarding.ui/cancel-confirm-pressed]}
|
{:events [:keycard.onboarding.ui/cancel-confirm-pressed]}
|
||||||
[cofx]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{}
|
(remove-listener-to-hardware-back-button)
|
||||||
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
|
(navigation/navigate-reset {:index 0
|
||||||
|
:actions [{:routeName (if (:multiaccounts/multiaccounts db)
|
||||||
|
:multiaccounts :intro)}]})))
|
||||||
|
|
||||||
(fx/defn load-finishing-screen
|
(fx/defn load-finishing-screen
|
||||||
{:events [:keycard.onboarding.recovery-phrase-confirm-word2.ui/next-pressed
|
{:events [:keycard.onboarding.recovery-phrase-confirm-word2.ui/next-pressed
|
||||||
|
@ -248,10 +272,6 @@
|
||||||
[_]
|
[_]
|
||||||
(.openURL react/linking "https://keycard.status.im"))
|
(.openURL react/linking "https://keycard.status.im"))
|
||||||
|
|
||||||
(fx/defn recovery-phrase-cancel-pressed
|
|
||||||
{:events [:keycard.onboarding.recovery-phrase.ui/cancel-pressed]}
|
|
||||||
[_])
|
|
||||||
|
|
||||||
(fx/defn recovery-phrase-next-pressed
|
(fx/defn recovery-phrase-next-pressed
|
||||||
{:events [:keycard.onboarding.recovery-phrase.ui/next-pressed]}
|
{:events [:keycard.onboarding.recovery-phrase.ui/next-pressed]}
|
||||||
[_]
|
[_]
|
||||||
|
@ -262,18 +282,21 @@
|
||||||
:on-accept #(re-frame/dispatch [:keycard.onboarding.recovery-phrase.ui/confirm-pressed])
|
:on-accept #(re-frame/dispatch [:keycard.onboarding.recovery-phrase.ui/confirm-pressed])
|
||||||
:on-cancel #()}})
|
:on-cancel #()}})
|
||||||
|
|
||||||
(fx/defn recovery-phrase-start-confirmation [{:keys [db]}]
|
(fx/defn recovery-phrase-start-confirmation
|
||||||
|
[{:keys [db] :as cofx}]
|
||||||
(let [mnemonic (get-in db [:hardwallet :secrets :mnemonic])
|
(let [mnemonic (get-in db [:hardwallet :secrets :mnemonic])
|
||||||
[word1 word2] (shuffle (map-indexed vector (clojure.string/split mnemonic #" ")))
|
[word1 word2] (shuffle (map-indexed vector (clojure.string/split mnemonic #" ")))
|
||||||
word1 (zipmap [:idx :word] word1)
|
word1 (zipmap [:idx :word] word1)
|
||||||
word2 (zipmap [:idx :word] word2)]
|
word2 (zipmap [:idx :word] word2)]
|
||||||
|
(fx/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:hardwallet :setup-step] :recovery-phrase-confirm-word1)
|
(assoc-in [:hardwallet :setup-step] :recovery-phrase-confirm-word1)
|
||||||
(assoc-in [:hardwallet :recovery-phrase :step] :word1)
|
(assoc-in [:hardwallet :recovery-phrase :step] :word1)
|
||||||
(assoc-in [:hardwallet :recovery-phrase :confirm-error] nil)
|
(assoc-in [:hardwallet :recovery-phrase :confirm-error] nil)
|
||||||
(assoc-in [:hardwallet :recovery-phrase :input-word] nil)
|
(assoc-in [:hardwallet :recovery-phrase :input-word] nil)
|
||||||
(assoc-in [:hardwallet :recovery-phrase :word1] word1)
|
(assoc-in [:hardwallet :recovery-phrase :word1] word1)
|
||||||
(assoc-in [:hardwallet :recovery-phrase :word2] word2))}))
|
(assoc-in [:hardwallet :recovery-phrase :word2] word2))}
|
||||||
|
(remove-listener-to-hardware-back-button))))
|
||||||
|
|
||||||
(fx/defn recovery-phrase-confirm-pressed
|
(fx/defn recovery-phrase-confirm-pressed
|
||||||
{:events [:keycard.onboarding.recovery-phrase.ui/confirm-pressed]}
|
{:events [:keycard.onboarding.recovery-phrase.ui/confirm-pressed]}
|
||||||
|
@ -341,29 +364,78 @@
|
||||||
(assoc-in [:hardwallet :pin] {:enter-step :import-multiaccount
|
(assoc-in [:hardwallet :pin] {:enter-step :import-multiaccount
|
||||||
:import-multiaccount []
|
:import-multiaccount []
|
||||||
:current []}))}
|
:current []}))}
|
||||||
|
(listen-to-hardware-back-button)
|
||||||
(navigation/navigate-to-cofx :keycard-recovery-pin nil)))
|
(navigation/navigate-to-cofx :keycard-recovery-pin nil)))
|
||||||
|
|
||||||
|
(fx/defn generate-mnemonic
|
||||||
|
[cofx]
|
||||||
|
(let [{:keys [pairing]} (get-in cofx [:db :hardwallet :secrets])]
|
||||||
|
{:hardwallet/generate-mnemonic {:pairing pairing
|
||||||
|
:words (string/join "\n" mnemonic/dictionary)}}))
|
||||||
|
|
||||||
|
(fx/defn proceed-with-generating-mnemonic
|
||||||
|
[{:keys [db] :as cofx}]
|
||||||
|
(let [pin (or (get-in db [:hardwallet :secrets :pin])
|
||||||
|
(vector->string (get-in db [:hardwallet :pin :current])))]
|
||||||
|
(if (empty? pin)
|
||||||
|
(fx/merge cofx
|
||||||
|
{:db (assoc-in db [:hardwallet :pin] {:enter-step :current
|
||||||
|
:on-verified :hardwallet/generate-mnemonic
|
||||||
|
:current []})}
|
||||||
|
(navigation/navigate-to-cofx :keycard-onboarding-pin nil))
|
||||||
|
(generate-mnemonic cofx))))
|
||||||
|
|
||||||
|
(fx/defn proceed-setup-with-initialized-card
|
||||||
|
[{:keys [db] :as cofx} flow instance-uid]
|
||||||
|
(if (= flow :import)
|
||||||
|
(navigation/navigate-to-cofx cofx :keycard-recovery-no-key nil)
|
||||||
|
(let [pairing-data (get-in db [:hardwallet :pairings (keyword instance-uid)])]
|
||||||
|
(if pairing-data
|
||||||
|
(fx/merge cofx
|
||||||
|
{:db (update-in db [:hardwallet :secrets] merge pairing-data)}
|
||||||
|
(listen-to-hardware-back-button)
|
||||||
|
(when (= flow :create)
|
||||||
|
(proceed-with-generating-mnemonic))
|
||||||
|
(when (= flow :recovery)
|
||||||
|
(proceed-with-generating-key)))
|
||||||
|
(load-pair-screen cofx)))))
|
||||||
|
|
||||||
|
(fx/defn show-existing-multiaccount-alert
|
||||||
|
[{:keys [db] :as cofx}]
|
||||||
|
(fx/merge cofx
|
||||||
|
{:utils/show-confirmation {:title nil
|
||||||
|
:content (i18n/label :t/keycard-existing-multiaccount)
|
||||||
|
:cancel-button-text ""
|
||||||
|
:confirm-button-text :t/okay}}
|
||||||
|
(navigation/navigate-back)))
|
||||||
|
|
||||||
(fx/defn check-card-state
|
(fx/defn check-card-state
|
||||||
{:events [:hardwallet/check-card-state]}
|
{:events [:hardwallet/check-card-state]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [app-info (get-in db [:hardwallet :application-info])
|
(let [app-info (get-in db [:hardwallet :application-info])
|
||||||
flow (get-in db [:hardwallet :flow])
|
flow (get-in db [:hardwallet :flow])
|
||||||
instance-uid (:instance-uid app-info)
|
{:keys [instance-uid key-uid]} app-info
|
||||||
pairing (get-pairing db instance-uid)
|
pairing (get-pairing db instance-uid)
|
||||||
app-info' (if pairing (assoc app-info :paired? true) app-info)
|
app-info' (if pairing (assoc app-info :paired? true) app-info)
|
||||||
card-state (get-card-state app-info')]
|
card-state (get-card-state app-info')]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (assoc-in db [:hardwallet :card-state] card-state)}
|
{:db (assoc-in db [:hardwallet :card-state] card-state)}
|
||||||
(set-setup-step card-state)
|
(set-setup-step card-state)
|
||||||
|
(when (and flow
|
||||||
|
(= card-state :init))
|
||||||
|
(proceed-setup-with-initialized-card flow instance-uid))
|
||||||
(when (= card-state :pre-init)
|
(when (= card-state :pre-init)
|
||||||
(if (= flow :import)
|
(if (= flow :import)
|
||||||
(navigation/navigate-to-cofx :keycard-recovery-no-key nil)
|
(navigation/navigate-to-cofx :keycard-recovery-no-key nil)
|
||||||
(load-pin-screen)))
|
(load-pin-screen)))
|
||||||
(when (and (= card-state :multiaccount)
|
(when (and (= card-state :multiaccount)
|
||||||
(= flow :import))
|
(= flow :import))
|
||||||
|
(let [existing-multiaccount (find-multiaccount-by-keycard-key-uid db key-uid)]
|
||||||
|
(if existing-multiaccount
|
||||||
|
(show-existing-multiaccount-alert)
|
||||||
(if pairing
|
(if pairing
|
||||||
(load-recovery-pin-screen)
|
(load-recovery-pin-screen)
|
||||||
(load-pair-screen)))
|
(load-pair-screen)))))
|
||||||
(when (= card-state :blank)
|
(when (= card-state :blank)
|
||||||
(if (= flow :import)
|
(if (= flow :import)
|
||||||
(navigation/navigate-to-cofx :keycard-recovery-no-key nil)
|
(navigation/navigate-to-cofx :keycard-recovery-no-key nil)
|
||||||
|
@ -383,11 +455,11 @@
|
||||||
|
|
||||||
(fx/defn navigate-to-enter-pin-screen
|
(fx/defn navigate-to-enter-pin-screen
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [keycard-instance-uid (get-in db [:hardwallet :application-info :instance-uid])
|
(let [keycard-key-uid (get-in db [:hardwallet :application-info :key-uid])
|
||||||
multiaccount-instance-uid (get-in db [:multiaccount :keycard-instance-uid])]
|
multiaccount-key-uid (get-in db [:multiaccount :keycard-key-uid])]
|
||||||
(if (or (nil? multiaccount-instance-uid)
|
(if (or (nil? multiaccount-key-uid)
|
||||||
(and keycard-instance-uid
|
(and keycard-key-uid
|
||||||
(= keycard-instance-uid multiaccount-instance-uid)))
|
(= keycard-key-uid multiaccount-key-uid)))
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (assoc-in db [:hardwallet :pin :current] [])}
|
{:db (assoc-in db [:hardwallet :pin :current] [])}
|
||||||
(navigation/navigate-to-cofx :enter-pin-settings nil))
|
(navigation/navigate-to-cofx :enter-pin-settings nil))
|
||||||
|
@ -479,14 +551,10 @@
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [application-info (get-in db [:hardwallet :application-info])
|
(let [application-info (get-in db [:hardwallet :application-info])
|
||||||
keycard-key-uid (get-in db [:hardwallet :application-info :key-uid])
|
keycard-key-uid (get-in db [:hardwallet :application-info :key-uid])
|
||||||
keycard-instance-uid (get-in db [:hardwallet :application-info :instance-uid])
|
|
||||||
multiaccount (get-in db [:multiaccounts/multiaccounts (get-in db [:multiaccounts/login :address])])
|
multiaccount (get-in db [:multiaccounts/multiaccounts (get-in db [:multiaccounts/login :address])])
|
||||||
multiaccount-key-uid (get multiaccount :keycard-key-uid)
|
multiaccount-key-uid (get multiaccount :keycard-key-uid)
|
||||||
multiaccount-instance-uid (get multiaccount :keycard-instance-uid)
|
|
||||||
multiaccount-mismatch? (or (nil? multiaccount)
|
multiaccount-mismatch? (or (nil? multiaccount)
|
||||||
(if (:keycard-key-uid multiaccount)
|
(not= multiaccount-key-uid keycard-key-uid))
|
||||||
(not= multiaccount-key-uid keycard-key-uid)
|
|
||||||
(not= multiaccount-instance-uid keycard-instance-uid)))
|
|
||||||
pairing (:keycard-pairing multiaccount)]
|
pairing (:keycard-pairing multiaccount)]
|
||||||
(cond
|
(cond
|
||||||
(empty? application-info)
|
(empty? application-info)
|
||||||
|
@ -584,8 +652,11 @@
|
||||||
|
|
||||||
(fx/defn keycard-connection-lost-cancel-pressed
|
(fx/defn keycard-connection-lost-cancel-pressed
|
||||||
{:events [:keycard.connection-lost.ui/cancel-pressed]}
|
{:events [:keycard.connection-lost.ui/cancel-pressed]}
|
||||||
[cofx]
|
[{:keys [db] :as cofx}]
|
||||||
(navigation/navigate-back cofx))
|
(if (contains? (set (take 3 (:navigation-stack db)))
|
||||||
|
:keycard-login-pin)
|
||||||
|
(navigation/navigate-to-cofx cofx :multiaccounts nil)
|
||||||
|
(navigation/navigate-back cofx)))
|
||||||
|
|
||||||
(fx/defn start-onboarding-flow
|
(fx/defn start-onboarding-flow
|
||||||
{:events [:keycard.recovery.no-key.ui/generate-key-pressed
|
{:events [:keycard.recovery.no-key.ui/generate-key-pressed
|
||||||
|
@ -773,23 +844,26 @@
|
||||||
:pairing pairing}}
|
:pairing pairing}}
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/remove-key-with-unpair)}
|
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/remove-key-with-unpair)}
|
||||||
(navigation/navigate-to-cofx :hardwallet-connect-settings nil)))))
|
(navigation/navigate-to-cofx :keycard-connection-lost nil)))))
|
||||||
|
|
||||||
(fx/defn on-remove-key-success
|
(fx/defn on-remove-key-success
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [multiaccount-address (get-in db [:multiaccount :address])
|
(let [multiaccount-address (get-in db [:multiaccount :address])
|
||||||
pairing (get-in db [:multiaccount :keycard-pairing])]
|
instance-uid (get-in db [:hardwallet :application-info :instance-uid])
|
||||||
|
pairings (get-in db [:hardwallet :pairings])]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update :multiaccounts/multiaccounts dissoc multiaccount-address)
|
(update :multiaccounts/multiaccounts dissoc multiaccount-address)
|
||||||
|
(assoc-in [:hardwallet :secrets] nil)
|
||||||
|
(update-in [:hardwallet :pairings] dissoc (keyword instance-uid))
|
||||||
(assoc-in [:hardwallet :whisper-public-key] nil)
|
(assoc-in [:hardwallet :whisper-public-key] nil)
|
||||||
(assoc-in [:hardwallet :wallet-address] nil)
|
(assoc-in [:hardwallet :wallet-address] nil)
|
||||||
(assoc-in [:hardwallet :secrets] {:pairing pairing})
|
|
||||||
(assoc-in [:hardwallet :application-info] nil)
|
(assoc-in [:hardwallet :application-info] nil)
|
||||||
(assoc-in [:hardwallet :on-card-connected] nil)
|
(assoc-in [:hardwallet :on-card-connected] nil)
|
||||||
(assoc-in [:hardwallet :pin] {:status nil
|
(assoc-in [:hardwallet :pin] {:status nil
|
||||||
:error-label nil
|
:error-label nil
|
||||||
:on-verified nil}))
|
:on-verified nil}))
|
||||||
|
:hardwallet/persist-pairings (dissoc pairings (keyword instance-uid))
|
||||||
;;FIXME delete multiaccount
|
;;FIXME delete multiaccount
|
||||||
:utils/show-popup {:title ""
|
:utils/show-popup {:title ""
|
||||||
:content (i18n/label :t/card-reseted)}}
|
:content (i18n/label :t/card-reseted)}}
|
||||||
|
@ -807,7 +881,7 @@
|
||||||
(assoc-in [:hardwallet :pin :status] nil))
|
(assoc-in [:hardwallet :pin :status] nil))
|
||||||
:utils/show-popup {:title (i18n/label :t/error)
|
:utils/show-popup {:title (i18n/label :t/error)
|
||||||
:content (i18n/label :t/cannot-read-card)}}
|
:content (i18n/label :t/cannot-read-card)}}
|
||||||
(navigation/navigate-to-cofx :hardwallet-connect-settings nil))
|
(navigation/navigate-to-cofx :keycard-connection-lost nil))
|
||||||
(show-wrong-keycard-alert cofx true)))))
|
(show-wrong-keycard-alert cofx true)))))
|
||||||
|
|
||||||
(fx/defn on-delete-success
|
(fx/defn on-delete-success
|
||||||
|
@ -848,11 +922,11 @@
|
||||||
|
|
||||||
(fx/defn delete-card
|
(fx/defn delete-card
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [keycard-instance-uid (get-in db [:hardwallet :application-info :instance-uid])
|
(let [keycard-key-uid (get-in db [:hardwallet :application-info :key-uid])
|
||||||
multiaccount-instance-uid (get-in db [:multiaccount :keycard-instance-uid])]
|
multiaccount-key-uid (get-in db [:multiaccount :keycard-key-uid])]
|
||||||
(if (or (nil? multiaccount-instance-uid)
|
(if (or (nil? multiaccount-key-uid)
|
||||||
(and keycard-instance-uid
|
(and keycard-key-uid
|
||||||
(= keycard-instance-uid multiaccount-instance-uid)))
|
(= keycard-key-uid multiaccount-key-uid)))
|
||||||
{:hardwallet/delete nil}
|
{:hardwallet/delete nil}
|
||||||
(unauthorized-operation cofx))))
|
(unauthorized-operation cofx))))
|
||||||
|
|
||||||
|
@ -1019,8 +1093,8 @@
|
||||||
:utils/show-popup {:title (i18n/label :t/error)
|
:utils/show-popup {:title (i18n/label :t/error)
|
||||||
:content (i18n/label :t/cannot-read-card)}}
|
:content (i18n/label :t/cannot-read-card)}}
|
||||||
(navigation/navigate-to-cofx (if setup?
|
(navigation/navigate-to-cofx (if setup?
|
||||||
:hardwallet-connect
|
:keycard-connection-lost-setup
|
||||||
:hardwallet-connect-settings) nil))
|
:keycard-connection-lost) nil))
|
||||||
(if (re-matches pin-mismatch-error (:error error))
|
(if (re-matches pin-mismatch-error (:error error))
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (update-in db [:hardwallet :pin] merge {:status :error
|
{:db (update-in db [:hardwallet :pin] merge {:status :error
|
||||||
|
@ -1077,17 +1151,21 @@
|
||||||
|
|
||||||
(fx/defn on-unpair-success
|
(fx/defn on-unpair-success
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
|
(let [instance-uid (get-in db [:hardwallet :application-info :instance-uid])
|
||||||
|
pairings (get-in db [:hardwallet :pairings])]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:hardwallet :secrets] nil)
|
(assoc-in [:hardwallet :secrets] nil)
|
||||||
|
(update-in [:hardwallet :pairings] dissoc (keyword instance-uid))
|
||||||
(assoc-in [:hardwallet :on-card-connected] nil)
|
(assoc-in [:hardwallet :on-card-connected] nil)
|
||||||
(assoc-in [:hardwallet :pin] {:status nil
|
(assoc-in [:hardwallet :pin] {:status nil
|
||||||
:error-label nil
|
:error-label nil
|
||||||
:on-verified nil}))
|
:on-verified nil}))
|
||||||
|
:hardwallet/persist-pairings (dissoc pairings (keyword instance-uid))
|
||||||
:utils/show-popup {:title ""
|
:utils/show-popup {:title ""
|
||||||
:content (i18n/label :t/card-unpaired)}}
|
:content (i18n/label :t/card-unpaired)}}
|
||||||
(remove-pairing-from-multiaccount nil)
|
(remove-pairing-from-multiaccount nil)
|
||||||
(navigation/navigate-to-cofx :keycard-settings nil)))
|
(navigation/navigate-to-cofx :keycard-settings nil))))
|
||||||
|
|
||||||
(fx/defn on-unpair-error
|
(fx/defn on-unpair-error
|
||||||
[{:keys [db] :as cofx} error]
|
[{:keys [db] :as cofx} error]
|
||||||
|
@ -1116,8 +1194,8 @@
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/verify-pin)}
|
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/verify-pin)}
|
||||||
(navigation/navigate-to-cofx (if setup?
|
(navigation/navigate-to-cofx (if setup?
|
||||||
:hardwallet-connect
|
:keycard-connection-lost-setup
|
||||||
:hardwallet-connect-settings) nil)))))
|
:keycard-connection-lost) nil)))))
|
||||||
|
|
||||||
(defn unblock-pin
|
(defn unblock-pin
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
|
@ -1132,7 +1210,7 @@
|
||||||
:pairing pairing}}
|
:pairing pairing}}
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/unblock-pin)}
|
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/unblock-pin)}
|
||||||
(navigation/navigate-to-cofx :hardwallet-connect-settings nil)))))
|
(navigation/navigate-to-cofx :keycard-connection-lost nil)))))
|
||||||
|
|
||||||
(def pin-code-length 6)
|
(def pin-code-length 6)
|
||||||
(def puk-code-length 12)
|
(def puk-code-length 12)
|
||||||
|
@ -1316,12 +1394,6 @@
|
||||||
(dispatch-event :hardwallet/generate-mnemonic)
|
(dispatch-event :hardwallet/generate-mnemonic)
|
||||||
(navigation/navigate-to-cofx :hardwallet-connect nil)))))
|
(navigation/navigate-to-cofx :hardwallet-connect nil)))))
|
||||||
|
|
||||||
(fx/defn generate-mnemonic
|
|
||||||
[cofx]
|
|
||||||
(let [{:keys [pairing]} (get-in cofx [:db :hardwallet :secrets])]
|
|
||||||
{:hardwallet/generate-mnemonic {:pairing pairing
|
|
||||||
:words (string/join "\n" mnemonic/dictionary)}}))
|
|
||||||
|
|
||||||
(fx/defn on-card-connected
|
(fx/defn on-card-connected
|
||||||
[{:keys [db] :as cofx} _]
|
[{:keys [db] :as cofx} _]
|
||||||
(log/debug "[hardwallet] card connected")
|
(log/debug "[hardwallet] card connected")
|
||||||
|
@ -1383,6 +1455,7 @@
|
||||||
(navigation/navigate-to-cofx :hardwallet-authentication-method nil))))))
|
(navigation/navigate-to-cofx :hardwallet-authentication-method nil))))))
|
||||||
|
|
||||||
(fx/defn on-install-applet-and-init-card-success
|
(fx/defn on-install-applet-and-init-card-success
|
||||||
|
{:events [:hardwallet.callback/on-install-applet-and-init-card-success]}
|
||||||
[{:keys [db] :as cofx} secrets]
|
[{:keys [db] :as cofx} secrets]
|
||||||
(let [secrets' (js->clj secrets :keywordize-keys true)]
|
(let [secrets' (js->clj secrets :keywordize-keys true)]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
|
@ -1392,6 +1465,7 @@
|
||||||
(assoc-in [:hardwallet :on-card-connected] nil)
|
(assoc-in [:hardwallet :on-card-connected] nil)
|
||||||
(assoc-in [:hardwallet :setup-step] :secret-keys)
|
(assoc-in [:hardwallet :setup-step] :secret-keys)
|
||||||
(update-in [:hardwallet :secrets] merge secrets'))}
|
(update-in [:hardwallet :secrets] merge secrets'))}
|
||||||
|
(listen-to-hardware-back-button)
|
||||||
(navigation/navigate-to-cofx :keycard-onboarding-puk-code nil))))
|
(navigation/navigate-to-cofx :keycard-onboarding-puk-code nil))))
|
||||||
|
|
||||||
(def on-init-card-success on-install-applet-and-init-card-success)
|
(def on-init-card-success on-install-applet-and-init-card-success)
|
||||||
|
@ -1419,6 +1493,11 @@
|
||||||
:keycard-paired-on paired-on}
|
:keycard-paired-on paired-on}
|
||||||
{}))
|
{}))
|
||||||
|
|
||||||
|
(fx/defn on-retrieve-pairings-success
|
||||||
|
{:events [:hardwallet.callback/on-retrieve-pairings-success]}
|
||||||
|
[{:keys [db]} pairings]
|
||||||
|
{:db (assoc-in db [:hardwallet :pairings] pairings)})
|
||||||
|
|
||||||
(fx/defn on-pair-success
|
(fx/defn on-pair-success
|
||||||
[{:keys [db] :as cofx} pairing]
|
[{:keys [db] :as cofx} pairing]
|
||||||
(let [setup-step (get-in db [:hardwallet :setup-step])
|
(let [setup-step (get-in db [:hardwallet :setup-step])
|
||||||
|
@ -1426,11 +1505,15 @@
|
||||||
instance-uid (get-in db [:hardwallet :application-info :instance-uid])
|
instance-uid (get-in db [:hardwallet :application-info :instance-uid])
|
||||||
multiaccount (find-multiaccount-by-keycard-instance-uid db instance-uid)
|
multiaccount (find-multiaccount-by-keycard-instance-uid db instance-uid)
|
||||||
paired-on (utils.datetime/timestamp)
|
paired-on (utils.datetime/timestamp)
|
||||||
|
pairings (get-in db [:hardwallet :pairings])
|
||||||
|
instance-uid (get-in db [:hardwallet :application-info :instance-uid])
|
||||||
next-step (if (= setup-step :pair)
|
next-step (if (= setup-step :pair)
|
||||||
:begin
|
:begin
|
||||||
:card-ready)]
|
:card-ready)]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (-> db
|
{:hardwallet/persist-pairings (assoc pairings instance-uid {:pairing pairing
|
||||||
|
:paired-on paired-on})
|
||||||
|
:db (-> db
|
||||||
(assoc-in [:hardwallet :application-info :paired?] true)
|
(assoc-in [:hardwallet :application-info :paired?] true)
|
||||||
(assoc-in [:hardwallet :on-card-connected] nil)
|
(assoc-in [:hardwallet :on-card-connected] nil)
|
||||||
(assoc-in [:hardwallet :setup-step] next-step)
|
(assoc-in [:hardwallet :setup-step] next-step)
|
||||||
|
@ -1543,6 +1626,7 @@
|
||||||
(navigation/navigate-to-cofx :enter-pin-login nil)))
|
(navigation/navigate-to-cofx :enter-pin-login nil)))
|
||||||
|
|
||||||
(fx/defn generate-and-load-key
|
(fx/defn generate-and-load-key
|
||||||
|
{:events [:hardwallet/generate-and-load-key]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [mnemonic pairing pin]} (get-in db [:hardwallet :secrets])
|
(let [{:keys [mnemonic pairing pin]} (get-in db [:hardwallet :secrets])
|
||||||
{:keys [selected-id multiaccounts]} (:intro-wizard db)
|
{:keys [selected-id multiaccounts]} (:intro-wizard db)
|
||||||
|
@ -1550,7 +1634,8 @@
|
||||||
(filter #(= (:id %) selected-id))
|
(filter #(= (:id %) selected-id))
|
||||||
first
|
first
|
||||||
:mnemonic)
|
:mnemonic)
|
||||||
mnemonic' (or user-selected-mnemonic mnemonic)
|
recovery-mnemonic (get-in db [:multiaccounts/recover :passphrase])
|
||||||
|
mnemonic' (or user-selected-mnemonic mnemonic recovery-mnemonic)
|
||||||
pin' (or pin (vector->string (get-in db [:hardwallet :pin :current])))]
|
pin' (or pin (vector->string (get-in db [:hardwallet :pin :current])))]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:hardwallet/generate-and-load-key {:mnemonic mnemonic'
|
{:hardwallet/generate-and-load-key {:mnemonic mnemonic'
|
||||||
|
@ -1561,40 +1646,51 @@
|
||||||
(fx/defn create-keycard-multiaccount
|
(fx/defn create-keycard-multiaccount
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{{:keys [multiaccount secrets flow]} :hardwallet} db
|
(let [{{:keys [multiaccount secrets flow]} :hardwallet} db
|
||||||
{:keys [whisper-public-key
|
{:keys [address
|
||||||
|
public-key
|
||||||
|
whisper-public-key
|
||||||
wallet-public-key
|
wallet-public-key
|
||||||
whisper-address
|
whisper-address
|
||||||
wallet-address
|
wallet-address
|
||||||
|
whisper-private-key
|
||||||
encryption-public-key
|
encryption-public-key
|
||||||
instance-uid
|
instance-uid
|
||||||
key-uid]} multiaccount
|
key-uid]} multiaccount
|
||||||
{:keys [pairing paired-on]} secrets]
|
{:keys [pairing paired-on]} secrets]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (assoc-in db [:hardwallet :setup-step] nil)}
|
{:db (-> db
|
||||||
|
(assoc-in [:hardwallet :setup-step] nil)
|
||||||
|
(assoc :intro-wizard nil))}
|
||||||
(multiaccounts.create/on-multiaccount-created
|
(multiaccounts.create/on-multiaccount-created
|
||||||
{:derived {constants/path-whisper-keyword {:publicKey whisper-public-key
|
{:derived {constants/path-whisper-keyword {:publicKey whisper-public-key
|
||||||
:address whisper-address}
|
:address whisper-address}
|
||||||
constants/path-default-wallet-keyword {:publicKey wallet-public-key
|
constants/path-default-wallet-keyword {:publicKey wallet-public-key
|
||||||
:address wallet-address}}
|
:address wallet-address}}
|
||||||
:mnemonic ""
|
:mnemonic ""
|
||||||
|
:address address
|
||||||
|
:publicKey public-key
|
||||||
:keycard-instance-uid instance-uid
|
:keycard-instance-uid instance-uid
|
||||||
:keycard-key-uid key-uid
|
:keycard-key-uid key-uid
|
||||||
:keycard-pairing pairing
|
:keycard-pairing pairing
|
||||||
:keycard-paired-on paired-on}
|
:keycard-paired-on paired-on
|
||||||
|
:chat-key whisper-private-key}
|
||||||
encryption-public-key
|
encryption-public-key
|
||||||
{:seed-backed-up? true
|
{:seed-backed-up? true
|
||||||
:login? true})
|
:login? true})
|
||||||
(if (= flow :import)
|
(if (= flow :import)
|
||||||
(navigation/navigate-to-cofx :keycard-recovery-success nil)
|
(navigation/navigate-to-cofx :keycard-recovery-success nil)
|
||||||
(navigation/navigate-to-cofx :keycard-welcome nil)))))
|
(navigation/navigate-to-cofx :home nil)))))
|
||||||
|
|
||||||
(fx/defn on-generate-and-load-key-success
|
(fx/defn on-generate-and-load-key-success
|
||||||
[{:keys [db random-guid-generator] :as cofx} data]
|
[{:keys [db random-guid-generator] :as cofx} data]
|
||||||
(let [account-data (js->clj data :keywordize-keys true)
|
(let [account-data (js->clj data :keywordize-keys true)]
|
||||||
flow (get-in db [:hardwallet :flow])]
|
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:hardwallet :multiaccount] (-> account-data
|
(assoc-in [:hardwallet :multiaccount] (-> account-data
|
||||||
|
(update :address #(str "0x" %))
|
||||||
|
(update :whisper-address #(str "0x" %))
|
||||||
|
(update :wallet-address #(str "0x" %))
|
||||||
|
(update :public-key #(str "0x" %))
|
||||||
(update :whisper-public-key #(str "0x" %))
|
(update :whisper-public-key #(str "0x" %))
|
||||||
(update :wallet-public-key #(str "0x" %))
|
(update :wallet-public-key #(str "0x" %))
|
||||||
(update :instance-uid #(get-in db [:hardwallet :multiaccount :instance-uid] %))))
|
(update :instance-uid #(get-in db [:hardwallet :multiaccount :instance-uid] %))))
|
||||||
|
@ -1606,9 +1702,8 @@
|
||||||
(update-in [:hardwallet :secrets] dissoc :pin :puk :password)
|
(update-in [:hardwallet :secrets] dissoc :pin :puk :password)
|
||||||
(assoc :multiaccounts/new-installation-id (random-guid-generator))
|
(assoc :multiaccounts/new-installation-id (random-guid-generator))
|
||||||
(update-in [:hardwallet :secrets] dissoc :mnemonic))}
|
(update-in [:hardwallet :secrets] dissoc :mnemonic))}
|
||||||
(create-keycard-multiaccount)
|
(remove-listener-to-hardware-back-button)
|
||||||
(when-not (= flow :import)
|
(create-keycard-multiaccount))))
|
||||||
(navigation/navigate-to-cofx :keycard-welcome nil)))))
|
|
||||||
|
|
||||||
(fx/defn on-generate-and-load-key-error
|
(fx/defn on-generate-and-load-key-error
|
||||||
[{:keys [db] :as cofx} {:keys [error code]}]
|
[{:keys [db] :as cofx} {:keys [error code]}]
|
||||||
|
@ -1619,11 +1714,18 @@
|
||||||
(assoc-in [:hardwallet :setup-error] error))}
|
(assoc-in [:hardwallet :setup-error] error))}
|
||||||
(process-error code error)))
|
(process-error code error)))
|
||||||
|
|
||||||
|
(fx/defn on-login-success
|
||||||
|
{:events [:keycard.login.callback/login-success]}
|
||||||
|
[cofx result]
|
||||||
|
(log/debug "loginWithKeycard success: " result))
|
||||||
|
|
||||||
(fx/defn on-get-keys-success
|
(fx/defn on-get-keys-success
|
||||||
[{:keys [db] :as cofx} data]
|
[{:keys [db] :as cofx} data]
|
||||||
(let [{:keys [wallet-address whisper-address encryption-public-key whisper-private-key] :as account-data} (js->clj data :keywordize-keys true)
|
(let [{:keys [address whisper-address encryption-public-key whisper-private-key] :as account-data} (js->clj data :keywordize-keys true)
|
||||||
{:keys [photo-path name]} (get-in db [:multiaccounts/multiaccounts whisper-address])
|
address (str "0x" address)
|
||||||
instance-uid (get-in db [:hardwallet :application-info :instance-uid])]
|
{:keys [photo-path name]} (get-in db [:multiaccounts/multiaccounts address])
|
||||||
|
instance-uid (get-in db [:hardwallet :application-info :instance-uid])
|
||||||
|
multiaccount-data (types/clj->json {:name name :address address :photo-path photo-path})]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:hardwallet :pin :status] nil)
|
(assoc-in [:hardwallet :pin :status] nil)
|
||||||
|
@ -1632,13 +1734,13 @@
|
||||||
(assoc-in [:hardwallet :flow] nil)
|
(assoc-in [:hardwallet :flow] nil)
|
||||||
(update :multiaccounts/login assoc
|
(update :multiaccounts/login assoc
|
||||||
:password encryption-public-key
|
:password encryption-public-key
|
||||||
:address whisper-address
|
:address address
|
||||||
:photo-path photo-path
|
:photo-path photo-path
|
||||||
:name name))
|
:name name))
|
||||||
:hardwallet/get-application-info {:pairing (get-pairing db instance-uid)}
|
:hardwallet/get-application-info {:pairing (get-pairing db instance-uid)}
|
||||||
:hardwallet/login-with-keycard {:whisper-private-key whisper-private-key
|
:hardwallet/login-with-keycard {:multiaccount-data multiaccount-data
|
||||||
:encryption-public-key encryption-public-key
|
:password encryption-public-key
|
||||||
:on-result #(re-frame/dispatch [:multiaccounts.login.callback/login-success %])}})))
|
:chat-key whisper-private-key}})))
|
||||||
|
|
||||||
(fx/defn on-get-keys-error
|
(fx/defn on-get-keys-error
|
||||||
[{:keys [db] :as cofx} error]
|
[{:keys [db] :as cofx} error]
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
(ns status-im.hardwallet.fx
|
(ns status-im.hardwallet.fx
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[status-im.utils.types :as types]
|
||||||
[status-im.hardwallet.card :as card]
|
[status-im.hardwallet.card :as card]
|
||||||
[status-im.native-module.core :as status]))
|
[status-im.native-module.core :as status]
|
||||||
|
[status-im.react-native.js-dependencies :as js-dependencies]
|
||||||
|
[status-im.utils.platform :as platform]))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:hardwallet/get-application-info
|
:hardwallet/get-application-info
|
||||||
|
@ -95,3 +98,34 @@
|
||||||
:send-transaction-with-signature
|
:send-transaction-with-signature
|
||||||
(fn [{:keys [transaction signature on-completed]}]
|
(fn [{:keys [transaction signature on-completed]}]
|
||||||
(status/send-transaction-with-signature transaction signature on-completed)))
|
(status/send-transaction-with-signature transaction signature on-completed)))
|
||||||
|
|
||||||
|
(re-frame/reg-fx
|
||||||
|
:hardwallet/persist-pairings
|
||||||
|
(fn [pairings]
|
||||||
|
(.. js-dependencies/async-storage
|
||||||
|
(setItem "status-keycard-pairings" (types/serialize pairings)))))
|
||||||
|
|
||||||
|
(re-frame/reg-fx
|
||||||
|
:hardwallet/retrieve-pairings
|
||||||
|
(fn []
|
||||||
|
(when platform/android?
|
||||||
|
(.. js-dependencies/async-storage
|
||||||
|
(getItem "status-keycard-pairings")
|
||||||
|
(then #(re-frame/dispatch [:hardwallet.callback/on-retrieve-pairings-success
|
||||||
|
(types/deserialize %)]))))))
|
||||||
|
|
||||||
|
(re-frame/reg-fx
|
||||||
|
:hardwallet/listen-to-hardware-back-button
|
||||||
|
;;NOTE: not done in view because effect should happen under different conditions and is not dependent on
|
||||||
|
;;particular screen to be loaded. An fx is easier to re-use and test.
|
||||||
|
(fn []
|
||||||
|
(re-frame/dispatch [:hardwallet/add-listener-to-hardware-back-button
|
||||||
|
(.addEventListener js-dependencies/back-handler "hardwareBackPress"
|
||||||
|
(fn []
|
||||||
|
(re-frame/dispatch [:hardwallet/back-button-pressed])
|
||||||
|
true))])))
|
||||||
|
|
||||||
|
(re-frame/reg-fx
|
||||||
|
:hardwallet/remove-listener-to-hardware-back-button
|
||||||
|
(fn [listener]
|
||||||
|
(.remove listener)))
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
[status-im.ui.screens.db :refer [app-db]]
|
[status-im.ui.screens.db :refer [app-db]]
|
||||||
[status-im.ui.screens.navigation :as navigation]
|
[status-im.ui.screens.navigation :as navigation]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.fx :as fx]
|
||||||
[status-im.utils.platform :as platform]))
|
[status-im.utils.platform :as platform]
|
||||||
|
[clojure.string :as string]))
|
||||||
|
|
||||||
(defn restore-native-settings! []
|
(defn restore-native-settings! []
|
||||||
(when platform/desktop?
|
(when platform/desktop?
|
||||||
|
@ -65,8 +66,12 @@
|
||||||
(fx/defn initialize-multiaccounts
|
(fx/defn initialize-multiaccounts
|
||||||
{:events [::initialize-multiaccounts]}
|
{:events [::initialize-multiaccounts]}
|
||||||
[{:keys [db] :as cofx} all-multiaccounts]
|
[{:keys [db] :as cofx} all-multiaccounts]
|
||||||
(let [multiaccounts (reduce (fn [acc {:keys [address] :as multiaccount}]
|
(let [multiaccounts (reduce (fn [acc {:keys [address keycard-key-uid keycard-pairing] :as multiaccount}]
|
||||||
(assoc acc address multiaccount))
|
(-> (assoc acc address multiaccount)
|
||||||
|
(assoc-in [address :keycard-key-uid] (when-not (string/blank? keycard-key-uid)
|
||||||
|
keycard-key-uid))
|
||||||
|
(assoc-in [address :keycard-pairing] (when-not (string/blank? keycard-pairing)
|
||||||
|
keycard-pairing))))
|
||||||
{}
|
{}
|
||||||
all-multiaccounts)]
|
all-multiaccounts)]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
|
@ -85,7 +90,8 @@
|
||||||
::network/listen-to-network-info nil
|
::network/listen-to-network-info nil
|
||||||
:hardwallet/register-card-events nil
|
:hardwallet/register-card-events nil
|
||||||
:hardwallet/check-nfc-support nil
|
:hardwallet/check-nfc-support nil
|
||||||
:hardwallet/check-nfc-enabled nil}
|
:hardwallet/check-nfc-enabled nil
|
||||||
|
:hardwallet/retrieve-pairings nil}
|
||||||
(initialize-app-db)))
|
(initialize-app-db)))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
|
|
|
@ -161,16 +161,30 @@
|
||||||
:path constants/path-whisper
|
:path constants/path-whisper
|
||||||
:chat true})])
|
:chat true})])
|
||||||
|
|
||||||
|
(fx/defn save-account-and-login-with-keycard
|
||||||
|
[_ multiaccount-data password node-config chat-key]
|
||||||
|
{::save-account-and-login-with-keycard [(types/clj->json multiaccount-data)
|
||||||
|
password
|
||||||
|
node-config
|
||||||
|
chat-key]})
|
||||||
|
|
||||||
|
(fx/defn save-account-and-login
|
||||||
|
[_ multiaccount-data password node-config accounts-data]
|
||||||
|
{::save-account-and-login [(types/clj->json multiaccount-data)
|
||||||
|
password
|
||||||
|
node-config
|
||||||
|
(types/clj->json accounts-data)]})
|
||||||
|
|
||||||
(fx/defn on-multiaccount-created
|
(fx/defn on-multiaccount-created
|
||||||
[{:keys [signing-phrase random-guid-generator db] :as cofx}
|
[{:keys [signing-phrase random-guid-generator db] :as cofx}
|
||||||
{:keys [address publicKey keycard-instance-uid keycard-key-uid keycard-pairing keycard-paired-on mnemonic] :as multiaccount}
|
{:keys [address chat-key keycard-instance-uid keycard-key-uid keycard-pairing keycard-paired-on mnemonic] :as multiaccount}
|
||||||
password
|
password
|
||||||
{:keys [seed-backed-up? login?] :or {login? true}}]
|
{:keys [seed-backed-up? login?] :or {login? true}}]
|
||||||
(let [[wallet-account {:keys [publicKey]} :as accounts-data] (prepare-accounts-data multiaccount)
|
(let [[wallet-account {:keys [publicKey]} :as accounts-data] (prepare-accounts-data multiaccount)
|
||||||
name (gfycat/generate-gfy publicKey)
|
name (gfycat/generate-gfy publicKey)
|
||||||
photo-path (identicon/identicon publicKey)
|
photo-path (identicon/identicon publicKey)
|
||||||
multiaccount-data {:name name :address address :photo-path photo-path}
|
multiaccount-data {:name name :address address :photo-path photo-path}
|
||||||
new-multiaccount {:address address
|
new-multiaccount (cond-> {:address address
|
||||||
:name name
|
:name name
|
||||||
:photo-path photo-path
|
:photo-path photo-path
|
||||||
:public-key publicKey
|
:public-key publicKey
|
||||||
|
@ -182,6 +196,11 @@
|
||||||
:installation-id (random-guid-generator)
|
:installation-id (random-guid-generator)
|
||||||
:mnemonic mnemonic
|
:mnemonic mnemonic
|
||||||
:settings constants/default-multiaccount-settings}
|
:settings constants/default-multiaccount-settings}
|
||||||
|
|
||||||
|
keycard-key-uid (assoc :keycard-instance-uid keycard-instance-uid
|
||||||
|
:keycard-key-uid keycard-key-uid
|
||||||
|
:keycard-pairing keycard-pairing
|
||||||
|
:keycard-paired-on keycard-paired-on))
|
||||||
db (assoc db
|
db (assoc db
|
||||||
:multiaccounts/login {:address address
|
:multiaccounts/login {:address address
|
||||||
:name name
|
:name name
|
||||||
|
@ -195,11 +214,16 @@
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (cond-> db
|
{:db (cond-> db
|
||||||
seed-backed-up?
|
seed-backed-up?
|
||||||
(assoc-in [:multiaccount :seed-backed-up?] true))
|
(assoc-in [:multiaccount :seed-backed-up?] true))}
|
||||||
::save-account-and-login [(types/clj->json multiaccount-data)
|
(if keycard-key-uid
|
||||||
|
(save-account-and-login-with-keycard new-multiaccount
|
||||||
|
password
|
||||||
|
(node/get-new-config db)
|
||||||
|
chat-key)
|
||||||
|
(save-account-and-login multiaccount-data
|
||||||
(ethereum/sha3 (security/safe-unmask-data password))
|
(ethereum/sha3 (security/safe-unmask-data password))
|
||||||
(node/get-new-config db)
|
(node/get-new-config db)
|
||||||
(types/clj->json accounts-data)]}
|
accounts-data))
|
||||||
(when (:intro-wizard db)
|
(when (:intro-wizard db)
|
||||||
(intro-step-forward {})))))
|
(intro-step-forward {})))))
|
||||||
|
|
||||||
|
@ -300,3 +324,10 @@
|
||||||
hashed-password
|
hashed-password
|
||||||
config
|
config
|
||||||
accounts-data)))
|
accounts-data)))
|
||||||
|
(re-frame/reg-fx
|
||||||
|
::save-account-and-login-with-keycard
|
||||||
|
(fn [[multiaccount-data password config chat-key]]
|
||||||
|
(status/save-account-and-login-with-keycard multiaccount-data
|
||||||
|
(security/safe-unmask-data password)
|
||||||
|
config
|
||||||
|
chat-key)))
|
||||||
|
|
|
@ -271,7 +271,7 @@
|
||||||
|
|
||||||
(fx/defn open-login
|
(fx/defn open-login
|
||||||
[{:keys [db] :as cofx} address photo-path name public-key]
|
[{:keys [db] :as cofx} address photo-path name public-key]
|
||||||
(let [keycard-multiaccount? (get-in db [:multiaccounts/multiaccounts address :keycard-instance-uid])]
|
(let [keycard-multiaccount? (get-in db [:multiaccounts/multiaccounts address :keycard-key-uid])]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update :multiaccounts/login assoc
|
(update :multiaccounts/login assoc
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
multiaccount-address (-> (:address multiaccount)
|
multiaccount-address (-> (:address multiaccount)
|
||||||
(string/lower-case)
|
(string/lower-case)
|
||||||
(string/replace-first "0x" ""))
|
(string/replace-first "0x" ""))
|
||||||
keycard-multiaccount? (boolean (get-in db [:multiaccounts/multiaccounts multiaccount-address :keycard-instance-uid]))]
|
keycard-multiaccount? (boolean (get-in db [:multiaccounts/multiaccounts multiaccount-address :keycard-key-uid]))]
|
||||||
(if keycard-multiaccount?
|
(if keycard-multiaccount?
|
||||||
;; trying to recover multiaccount created with keycard
|
;; trying to recover multiaccount created with keycard
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
|
@ -171,8 +171,9 @@
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [storage-type (get-in db [:intro-wizard :selected-storage-type])]
|
(let [storage-type (get-in db [:intro-wizard :selected-storage-type])]
|
||||||
(if (= storage-type :advanced)
|
(if (= storage-type :advanced)
|
||||||
{:dispatch [:recovery.ui/keycard-option-pressed]})
|
;;TODO: fix circular dependency to remove dispatch here
|
||||||
(navigation/navigate-to-cofx cofx :recover-multiaccount-enter-password nil)))
|
{:dispatch [:recovery.ui/keycard-option-pressed]}
|
||||||
|
(navigation/navigate-to-cofx cofx :recover-multiaccount-enter-password nil))))
|
||||||
|
|
||||||
(fx/defn re-encrypt-pressed
|
(fx/defn re-encrypt-pressed
|
||||||
{:events [::re-encrypt-pressed]}
|
{:events [::re-encrypt-pressed]}
|
||||||
|
|
|
@ -35,6 +35,11 @@
|
||||||
(clear-web-data)
|
(clear-web-data)
|
||||||
(.saveAccountAndLogin (status) multiaccount-data hashed-password config accounts-data))
|
(.saveAccountAndLogin (status) multiaccount-data hashed-password config accounts-data))
|
||||||
|
|
||||||
|
(defn save-account-and-login-with-keycard
|
||||||
|
"NOTE: chat-key is a whisper private key sent from keycard"
|
||||||
|
[multiaccount-data password config chat-key]
|
||||||
|
(.saveAccountAndLoginWithKeycard (status) multiaccount-data password config chat-key))
|
||||||
|
|
||||||
(defn login
|
(defn login
|
||||||
"NOTE: beware, the password has to be sha3 hashed"
|
"NOTE: beware, the password has to be sha3 hashed"
|
||||||
[account-data hashed-password]
|
[account-data hashed-password]
|
||||||
|
@ -133,9 +138,9 @@
|
||||||
(.verify (status) address hashed-password callback))
|
(.verify (status) address hashed-password callback))
|
||||||
|
|
||||||
(defn login-with-keycard
|
(defn login-with-keycard
|
||||||
[{:keys [whisper-private-key encryption-public-key on-result]}]
|
[{:keys [multiaccount-data password chat-key]}]
|
||||||
(clear-web-data)
|
(clear-web-data)
|
||||||
(.loginWithKeycard (status) whisper-private-key encryption-public-key on-result))
|
(.loginWithKeycard (status) multiaccount-data password chat-key))
|
||||||
|
|
||||||
(defn set-soft-input-mode [mode]
|
(defn set-soft-input-mode [mode]
|
||||||
(.setSoftInputMode (status) mode))
|
(.setSoftInputMode (status) mode))
|
||||||
|
|
|
@ -171,7 +171,7 @@
|
||||||
(fx/defn show-sign [{:keys [db] :as cofx}]
|
(fx/defn show-sign [{:keys [db] :as cofx}]
|
||||||
(let [{:signing/keys [queue]} db
|
(let [{:signing/keys [queue]} db
|
||||||
{{:keys [gas gasPrice] :as tx-obj} :tx-obj {:keys [data typed?] :as message} :message :as tx} (last queue)
|
{{:keys [gas gasPrice] :as tx-obj} :tx-obj {:keys [data typed?] :as message} :message :as tx} (last queue)
|
||||||
keycard-multiaccount? (boolean (get-in db [:multiaccount :keycard-instance-uid]))
|
keycard-multiaccount? (boolean (get-in db [:multiaccount :keycard-key-uid]))
|
||||||
wallet-set-up-passed? (get-in db [:multiaccount :wallet-set-up-passed?])
|
wallet-set-up-passed? (get-in db [:multiaccount :wallet-set-up-passed?])
|
||||||
updated-db (if wallet-set-up-passed? db (assoc db :popover/popover {:view :signing-phrase}))]
|
updated-db (if wallet-set-up-passed? db (assoc db :popover/popover {:view :signing-phrase}))]
|
||||||
(if message
|
(if message
|
||||||
|
|
|
@ -180,6 +180,8 @@
|
||||||
(reg-root-key-sub :popover/popover :popover/popover)
|
(reg-root-key-sub :popover/popover :popover/popover)
|
||||||
(reg-root-key-sub :generate-account :generate-account)
|
(reg-root-key-sub :generate-account :generate-account)
|
||||||
|
|
||||||
|
(reg-root-key-sub :keycard :hardwallet)
|
||||||
|
|
||||||
;;GENERAL ==============================================================================================================
|
;;GENERAL ==============================================================================================================
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
|
|
|
@ -10,22 +10,21 @@
|
||||||
{:flex 1
|
{:flex 1
|
||||||
:flex-direction :column
|
:flex-direction :column
|
||||||
:justify-content :space-between
|
:justify-content :space-between
|
||||||
:padding-bottom 10
|
:android {:margin-top 10}
|
||||||
:android {:margin-top 40}
|
:ios {:margin-top 10}})
|
||||||
:ios {:margin-top 30}})
|
|
||||||
|
|
||||||
(defstyle error-container
|
(defstyle error-container
|
||||||
{:android {:margin-top 25}
|
{:height 22})
|
||||||
:ios {:margin-top 28}})
|
|
||||||
|
|
||||||
(def error-text
|
(def error-text
|
||||||
{:color colors/red
|
{:color colors/red
|
||||||
|
:font-size 15
|
||||||
:text-align :center})
|
:text-align :center})
|
||||||
|
|
||||||
(defn center-container [title]
|
(defn center-container [title]
|
||||||
{:flex-direction :column
|
{:flex-direction :column
|
||||||
:align-items :center
|
:align-items :center
|
||||||
:margin-top (if title 28 5)})
|
:margin-top (if title 20 5)})
|
||||||
|
|
||||||
(def center-title-text
|
(def center-title-text
|
||||||
{:typography :header})
|
{:typography :header})
|
||||||
|
@ -39,18 +38,20 @@
|
||||||
(def pin-indicator-container
|
(def pin-indicator-container
|
||||||
{:flex-direction :row
|
{:flex-direction :row
|
||||||
:justify-content :space-between
|
:justify-content :space-between
|
||||||
:margin-top 30})
|
:margin-top 16})
|
||||||
|
|
||||||
(def pin-indicator-group-container
|
(def pin-indicator-group-container
|
||||||
{:flex-direction :row
|
{:flex-direction :row
|
||||||
:justify-content :space-between})
|
:justify-content :space-between})
|
||||||
|
|
||||||
(defn pin-indicator [pressed?]
|
(defn pin-indicator [pressed? status]
|
||||||
{:width 8
|
{:width 8
|
||||||
:height 8
|
:height 8
|
||||||
:background-color (if pressed?
|
:background-color (if (= status :error)
|
||||||
|
colors/red
|
||||||
|
(if pressed?
|
||||||
colors/blue
|
colors/blue
|
||||||
colors/black-transparent)
|
colors/black-transparent))
|
||||||
:border-radius 50
|
:border-radius 50
|
||||||
:margin-horizontal 5})
|
:margin-horizontal 5})
|
||||||
|
|
||||||
|
|
|
@ -40,10 +40,10 @@
|
||||||
[react/view styles/numpad-delete-button
|
[react/view styles/numpad-delete-button
|
||||||
[vector-icons/icon :main-icons/backspace {:color colors/blue}]]]]])
|
[vector-icons/icon :main-icons/backspace {:color colors/blue}]]]]])
|
||||||
|
|
||||||
(defn pin-indicator [pressed?]
|
(defn pin-indicator [pressed? status]
|
||||||
[react/view (styles/pin-indicator pressed?)])
|
[react/view (styles/pin-indicator pressed? status)])
|
||||||
|
|
||||||
(defn pin-indicators [pin style]
|
(defn pin-indicators [pin status style]
|
||||||
[react/view (merge styles/pin-indicator-container style)
|
[react/view (merge styles/pin-indicator-container style)
|
||||||
(map-indexed
|
(map-indexed
|
||||||
(fn [i group]
|
(fn [i group]
|
||||||
|
@ -54,17 +54,17 @@
|
||||||
(map-indexed
|
(map-indexed
|
||||||
(fn [i n]
|
(fn [i n]
|
||||||
^{:key i}
|
^{:key i}
|
||||||
[pin-indicator (number? n)])
|
[pin-indicator (number? n) status])
|
||||||
(concat pin
|
(concat pin
|
||||||
(repeat (- 6 (count pin))
|
(repeat (- 6 (count pin))
|
||||||
nil)))))])
|
nil)))))])
|
||||||
|
|
||||||
(defn puk-indicators [puk]
|
(defn puk-indicators [puk status]
|
||||||
[react/view
|
[react/view
|
||||||
(map-indexed
|
(map-indexed
|
||||||
(fn [i puk-group]
|
(fn [i puk-group]
|
||||||
^{:key i}
|
^{:key i}
|
||||||
[pin-indicators puk-group {:margin-top 15}])
|
[pin-indicators puk-group status {:margin-top 15}])
|
||||||
(partition 6
|
(partition 6
|
||||||
(concat puk
|
(concat puk
|
||||||
(repeat (- 12 (count puk))
|
(repeat (- 12 (count puk))
|
||||||
|
@ -83,11 +83,12 @@
|
||||||
[react/text {:style styles/create-pin-text
|
[react/text {:style styles/create-pin-text
|
||||||
:number-of-lines 2}
|
:number-of-lines 2}
|
||||||
(i18n/label description-label)])
|
(i18n/label description-label)])
|
||||||
|
[react/view {:height 10}
|
||||||
(when retry-counter
|
(when retry-counter
|
||||||
[react/text {:style {:font-weight "700"
|
[react/text {:style {:font-weight "700"
|
||||||
:padding-top 10
|
|
||||||
:color colors/red}}
|
:color colors/red}}
|
||||||
(i18n/label :t/pin-retries-left {:number retry-counter})])
|
(i18n/label :t/pin-retries-left {:number retry-counter})])]
|
||||||
|
[react/view {:height 22}
|
||||||
(case status
|
(case status
|
||||||
:verifying [react/view styles/waiting-indicator-container
|
:verifying [react/view styles/waiting-indicator-container
|
||||||
[react/activity-indicator {:animating true
|
[react/activity-indicator {:animating true
|
||||||
|
@ -95,9 +96,10 @@
|
||||||
:error [react/view styles/error-container
|
:error [react/view styles/error-container
|
||||||
[react/text {:style styles/error-text}
|
[react/text {:style styles/error-text}
|
||||||
(i18n/label error-label)]]
|
(i18n/label error-label)]]
|
||||||
|
nil)]
|
||||||
(if (= step :puk)
|
(if (= step :puk)
|
||||||
[puk-indicators pin]
|
[puk-indicators pin status]
|
||||||
[pin-indicators pin]))
|
[pin-indicators pin status nil])
|
||||||
[numpad step enabled?]]]]))
|
[numpad step enabled?]]]]))
|
||||||
|
|
||||||
(def pin-retries 3)
|
(def pin-retries 3)
|
||||||
|
|
|
@ -38,4 +38,4 @@
|
||||||
:keycard-multiaccount?
|
:keycard-multiaccount?
|
||||||
(fn [db]
|
(fn [db]
|
||||||
(boolean
|
(boolean
|
||||||
(get-in db [:multiaccount :keycard-instance-uid]))))
|
(get-in db [:multiaccount :keycard-key-uid]))))
|
||||||
|
|
|
@ -113,7 +113,7 @@
|
||||||
(if (zero? puk-retry-counter)
|
(if (zero? puk-retry-counter)
|
||||||
[card-blocked]
|
[card-blocked]
|
||||||
[react/view
|
[react/view
|
||||||
[action-row {:icon :main-icons/info
|
[action-row {:icon :main-icons/help
|
||||||
:label :t/help-capitalized
|
:label :t/help-capitalized
|
||||||
:on-press #(.openURL react/linking "https://hardwallet.status.im")}]
|
:on-press #(.openURL react/linking "https://hardwallet.status.im")}]
|
||||||
(when pairing
|
(when pairing
|
||||||
|
@ -124,10 +124,11 @@
|
||||||
[action-row {:icon :main-icons/close
|
[action-row {:icon :main-icons/close
|
||||||
:label :t/unpair-card
|
:label :t/unpair-card
|
||||||
:on-press #(re-frame/dispatch [:keycard-settings.ui/unpair-card-pressed])}]])])]
|
:on-press #(re-frame/dispatch [:keycard-settings.ui/unpair-card-pressed])}]])])]
|
||||||
(when pairing
|
; NOTE: Reset card is hidden until multiaccount removal will be implemented
|
||||||
|
#_(when pairing
|
||||||
[react/view {:margin-bottom 35
|
[react/view {:margin-bottom 35
|
||||||
:margin-left 16}
|
:margin-left 16}
|
||||||
[action-row {:icon :main-icons/logout
|
[action-row {:icon :main-icons/warning
|
||||||
:color-theme :red
|
:color-theme :red
|
||||||
:label :t/reset-card
|
:label :t/reset-card
|
||||||
:on-press #(re-frame/dispatch [:keycard-settings.ui/reset-card-pressed])}]])]]))
|
:on-press #(re-frame/dispatch [:keycard-settings.ui/reset-card-pressed])}]])]]))
|
||||||
|
|
|
@ -261,12 +261,25 @@
|
||||||
:text-align :center}}
|
:text-align :center}}
|
||||||
(i18n/label (if (= :original enter-step)
|
(i18n/label (if (= :original enter-step)
|
||||||
:t/intro-wizard-title4
|
:t/intro-wizard-title4
|
||||||
:t/intro-wizard-title5))]]]
|
:t/intro-wizard-title5))]]
|
||||||
|
[react/view {:margin-top 16
|
||||||
|
:height 22}
|
||||||
|
(when (= :original enter-step)
|
||||||
|
[react/text {:style {:color colors/gray}}
|
||||||
|
(i18n/label :t/intro-wizard-text4)])]]
|
||||||
[pin.views/pin-view
|
[pin.views/pin-view
|
||||||
{:pin pin
|
{:pin pin
|
||||||
:status status
|
:status status
|
||||||
:error-label error-label
|
:error-label error-label
|
||||||
:step enter-step}]]]))
|
:step enter-step}]
|
||||||
|
[react/view {:align-items :center
|
||||||
|
:flex-direction :column
|
||||||
|
:justify-content :center
|
||||||
|
:margin-bottom 15}
|
||||||
|
[react/text {:style {:color colors/gray
|
||||||
|
:padding-horizontal 40
|
||||||
|
:text-align :center}}
|
||||||
|
(i18n/label :t/you-will-need-this-code)]]]]))
|
||||||
|
|
||||||
(defview recovery-phrase []
|
(defview recovery-phrase []
|
||||||
(letsubs [mnemonic [:hardwallet-mnemonic]]
|
(letsubs [mnemonic [:hardwallet-mnemonic]]
|
||||||
|
|
|
@ -12,9 +12,11 @@
|
||||||
[status-im.utils.core :as utils.core]
|
[status-im.utils.core :as utils.core]
|
||||||
[status-im.utils.gfycat.core :as gfy]
|
[status-im.utils.gfycat.core :as gfy]
|
||||||
[status-im.utils.identicon :as identicon]
|
[status-im.utils.identicon :as identicon]
|
||||||
[status-im.ui.components.list-item.views :as list-item]))
|
[status-im.ui.components.list-item.views :as list-item]
|
||||||
|
[status-im.ui.screens.chat.photos :as photos]))
|
||||||
|
|
||||||
(defn connection-lost []
|
(defview connection-lost []
|
||||||
|
(letsubs [{:keys [card-connected?]} [:keycard]]
|
||||||
[react/view {:flex 1
|
[react/view {:flex 1
|
||||||
:justify-content :center
|
:justify-content :center
|
||||||
:align-items :center
|
:align-items :center
|
||||||
|
@ -32,19 +34,23 @@
|
||||||
(i18n/label :t/connection-with-the-card-lost)]
|
(i18n/label :t/connection-with-the-card-lost)]
|
||||||
[react/view {:margin-top 16}
|
[react/view {:margin-top 16}
|
||||||
[react/text {:style {:color colors/gray
|
[react/text {:style {:color colors/gray
|
||||||
|
:padding-horizontal 50
|
||||||
:text-align :center}}
|
:text-align :center}}
|
||||||
(i18n/label :t/connection-with-the-card-lost-text)]]]
|
(i18n/label :t/connection-with-the-card-lost-text)]]]
|
||||||
[react/view {:margin-top 16}
|
[react/view {:margin-top 16}
|
||||||
|
(if card-connected?
|
||||||
|
[react/activity-indicator {:size :large
|
||||||
|
:animating true}]
|
||||||
[react/image {:source (resources/get-image :keycard-connection)
|
[react/image {:source (resources/get-image :keycard-connection)
|
||||||
:resize-mode :center
|
:resize-mode :center
|
||||||
:style {:width 200
|
:style {:width 200
|
||||||
:height 200}}]]
|
:height 200}}])]
|
||||||
[react/view {:margin-bottom 43}
|
[react/view {:margin-bottom 43}
|
||||||
[react/touchable-highlight
|
[react/touchable-highlight
|
||||||
{:on-press #(re-frame/dispatch [:keycard.connection-lost.ui/cancel-pressed])}
|
{:on-press #(re-frame/dispatch [:keycard.connection-lost.ui/cancel-pressed])}
|
||||||
[react/text {:style {:color colors/red
|
[react/text {:style {:color colors/red
|
||||||
:text-align :center}}
|
:text-align :center}}
|
||||||
(i18n/label :t/cancel)]]]]])
|
(i18n/label :t/cancel)]]]]]))
|
||||||
|
|
||||||
(defn connection-lost-setup []
|
(defn connection-lost-setup []
|
||||||
[react/view {:flex 1
|
[react/view {:flex 1
|
||||||
|
@ -356,8 +362,7 @@
|
||||||
enter-step [:hardwallet/pin-enter-step]
|
enter-step [:hardwallet/pin-enter-step]
|
||||||
status [:hardwallet/pin-status]
|
status [:hardwallet/pin-status]
|
||||||
error-label [:hardwallet/pin-error-label]
|
error-label [:hardwallet/pin-error-label]
|
||||||
{:keys [address public-key]} [:multiaccounts/login]]
|
{:keys [address name photo-path]} [:multiaccounts/login]]
|
||||||
(let [address (str "0x" address)]
|
|
||||||
[react/view styles/container
|
[react/view styles/container
|
||||||
[toolbar/toolbar
|
[toolbar/toolbar
|
||||||
{:transparent? true
|
{:transparent? true
|
||||||
|
@ -392,12 +397,7 @@
|
||||||
:height 69
|
:height 69
|
||||||
:justify-content :center
|
:justify-content :center
|
||||||
:align-items :center}
|
:align-items :center}
|
||||||
[react/image {:source {:uri (identicon/identicon public-key)}
|
[photos/photo photo-path {:size 61}]
|
||||||
:style {:width 61
|
|
||||||
:height 61
|
|
||||||
:border-radius 30
|
|
||||||
:border-width 1
|
|
||||||
:border-color colors/black-transparent}}]
|
|
||||||
[react/view {:justify-content :center
|
[react/view {:justify-content :center
|
||||||
:align-items :center
|
:align-items :center
|
||||||
:width 24
|
:width 24
|
||||||
|
@ -418,7 +418,7 @@
|
||||||
:font-weight "500"}
|
:font-weight "500"}
|
||||||
:number-of-lines 1
|
:number-of-lines 1
|
||||||
:ellipsize-mode :middle}
|
:ellipsize-mode :middle}
|
||||||
(gfy/generate-gfy public-key)]
|
name]
|
||||||
[react/text {:style {:text-align :center
|
[react/text {:style {:text-align :center
|
||||||
:margin-top 4
|
:margin-top 4
|
||||||
:color colors/gray
|
:color colors/gray
|
||||||
|
@ -435,13 +435,12 @@
|
||||||
[react/touchable-highlight
|
[react/touchable-highlight
|
||||||
{:on-press #(re-frame/dispatch [:keycard.login.ui/recover-key-pressed])}
|
{:on-press #(re-frame/dispatch [:keycard.login.ui/recover-key-pressed])}
|
||||||
[react/text {:style {:color colors/blue}}
|
[react/text {:style {:color colors/blue}}
|
||||||
(i18n/label :t/recover-key)]]]]])))
|
(i18n/label :t/recover-key)]]]]]))
|
||||||
|
|
||||||
(defview login-connect-card []
|
(defview login-connect-card []
|
||||||
(letsubs [status [:hardwallet/pin-status]
|
(letsubs [status [:hardwallet/pin-status]
|
||||||
{:keys [address public-key]} [:multiaccounts/login]]
|
{:keys [address name photo-path]} [:multiaccounts/login]]
|
||||||
(let [address (str "0x" address)
|
(let [in-progress? (= status :verifying)]
|
||||||
in-progress? (= status :verifying)]
|
|
||||||
[react/view styles/container
|
[react/view styles/container
|
||||||
[toolbar/toolbar
|
[toolbar/toolbar
|
||||||
{:transparent? true
|
{:transparent? true
|
||||||
|
@ -472,12 +471,7 @@
|
||||||
:height 69
|
:height 69
|
||||||
:justify-content :center
|
:justify-content :center
|
||||||
:align-items :center}
|
:align-items :center}
|
||||||
[react/image {:source {:uri (identicon/identicon public-key)}
|
[photos/photo photo-path {:size 61}]
|
||||||
:style {:width 61
|
|
||||||
:height 61
|
|
||||||
:border-radius 30
|
|
||||||
:border-width 1
|
|
||||||
:border-color colors/black-transparent}}]
|
|
||||||
[react/view {:justify-content :center
|
[react/view {:justify-content :center
|
||||||
:align-items :center
|
:align-items :center
|
||||||
:width 24
|
:width 24
|
||||||
|
@ -498,7 +492,7 @@
|
||||||
:font-weight "500"}
|
:font-weight "500"}
|
||||||
:number-of-lines 1
|
:number-of-lines 1
|
||||||
:ellipsize-mode :middle}
|
:ellipsize-mode :middle}
|
||||||
(gfy/generate-gfy public-key)]
|
name]
|
||||||
[react/text {:style {:text-align :center
|
[react/text {:style {:text-align :center
|
||||||
:margin-top 4
|
:margin-top 4
|
||||||
:color colors/gray
|
:color colors/gray
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
[status-im.ui.screens.privacy-policy.views :as privacy-policy]
|
[status-im.ui.screens.privacy-policy.views :as privacy-policy]
|
||||||
[status-im.react-native.resources :as resources]))
|
[status-im.react-native.resources :as resources]))
|
||||||
|
|
||||||
(defn multiaccount-view [{:keys [address photo-path name public-key keycard-instance-uid]}]
|
(defn multiaccount-view [{:keys [address photo-path name public-key keycard-key-uid]}]
|
||||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:multiaccounts.login.ui/multiaccount-selected address photo-path name public-key])}
|
[react/touchable-highlight {:on-press #(re-frame/dispatch [:multiaccounts.login.ui/multiaccount-selected address photo-path name public-key])}
|
||||||
[react/view styles/multiaccount-view
|
[react/view styles/multiaccount-view
|
||||||
[photos/photo photo-path {:size styles/multiaccount-image-size}]
|
[photos/photo photo-path {:size styles/multiaccount-image-size}]
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
[react/text {:style styles/multiaccount-badge-pub-key-text}
|
[react/text {:style styles/multiaccount-badge-pub-key-text}
|
||||||
(utils/get-shortened-address public-key)]]
|
(utils/get-shortened-address public-key)]]
|
||||||
[react/view {:flex 1}]
|
[react/view {:flex 1}]
|
||||||
(when keycard-instance-uid
|
(when keycard-key-uid
|
||||||
[react/view {:justify-content :center
|
[react/view {:justify-content :center
|
||||||
:align-items :center
|
:align-items :center
|
||||||
:margin-right 7
|
:margin-right 7
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
[status-im.ui.screens.profile.user.styles :as styles]
|
[status-im.ui.screens.profile.user.styles :as styles]
|
||||||
[status-im.utils.identicon :as identicon]
|
[status-im.utils.identicon :as identicon]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
|
[status-im.utils.config :as config]
|
||||||
[status-im.utils.universal-links.core :as universal-links])
|
[status-im.utils.universal-links.core :as universal-links])
|
||||||
(:require-macros [status-im.utils.views :as views]))
|
(:require-macros [status-im.utils.views :as views]))
|
||||||
|
|
||||||
|
@ -159,6 +160,13 @@
|
||||||
:accessibility-label :sync-settings-button
|
:accessibility-label :sync-settings-button
|
||||||
:accessories [:chevron]
|
:accessories [:chevron]
|
||||||
:on-press #(re-frame/dispatch [:navigate-to :sync-settings])}
|
:on-press #(re-frame/dispatch [:navigate-to :sync-settings])}
|
||||||
|
(when (and platform/android?
|
||||||
|
config/hardwallet-enabled?)
|
||||||
|
{:icon :main-icons/keycard
|
||||||
|
:title :t/keycard
|
||||||
|
:accessibility-label :keycard-button
|
||||||
|
:accessories [:chevron]
|
||||||
|
:on-press #(re-frame/dispatch [:navigate-to :keycard-settings])})
|
||||||
{:icon :main-icons/settings-advanced
|
{:icon :main-icons/settings-advanced
|
||||||
:title :t/advanced
|
:title :t/advanced
|
||||||
:accessibility-label :advanced-button
|
:accessibility-label :advanced-button
|
||||||
|
|
|
@ -39,6 +39,6 @@
|
||||||
config/hardwallet-enabled?
|
config/hardwallet-enabled?
|
||||||
(concat [:keycard-settings
|
(concat [:keycard-settings
|
||||||
:reset-card
|
:reset-card
|
||||||
:hardwallet-connect-settings
|
:keycard-connection-lost
|
||||||
:enter-pin-settings]))
|
:enter-pin-settings]))
|
||||||
:config {:initialRouteName :my-profile}})
|
:config {:initialRouteName :my-profile}})
|
||||||
|
|
|
@ -154,7 +154,7 @@
|
||||||
[amount-error gas-error]
|
[amount-error gas-error]
|
||||||
[button/button {:on-press #(re-frame/dispatch [:signing.ui/sign-with-keycard-pressed])
|
[button/button {:on-press #(re-frame/dispatch [:signing.ui/sign-with-keycard-pressed])
|
||||||
:disabled? (or amount-error gas-error)
|
:disabled? (or amount-error gas-error)
|
||||||
:label :t/sign-with}])
|
:label :t/sign-with-keycard}])
|
||||||
|
|
||||||
(defn- signing-phrase-view [phrase]
|
(defn- signing-phrase-view [phrase]
|
||||||
[react/view {:align-items :center}
|
[react/view {:align-items :center}
|
||||||
|
@ -163,7 +163,7 @@
|
||||||
|
|
||||||
(defn- keycard-view
|
(defn- keycard-view
|
||||||
[{:keys [keycard-step]} phrase]
|
[{:keys [keycard-step]} phrase]
|
||||||
[react/view {:height 450}
|
[react/view {:height 500}
|
||||||
[signing-phrase-view phrase]
|
[signing-phrase-view phrase]
|
||||||
(case keycard-step
|
(case keycard-step
|
||||||
:pin [keycard-pin-view]
|
:pin [keycard-pin-view]
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
"owner": "status-im",
|
"owner": "status-im",
|
||||||
"repo": "status-go",
|
"repo": "status-go",
|
||||||
"version": "develop",
|
"version": "develop",
|
||||||
"commit-sha1": "76d184b4c9e666383ba54303b3c4a438ac4519de",
|
"commit-sha1": "d263be10c46aa8788bc776069225ab31c52c6c51",
|
||||||
"src-sha256": "141glfhal3chlykz5m3jbmzrv10rprly9yk4xf1ss4a3hd8hj90c"
|
"src-sha256": "0r7hp9a946s1sbh5dbl8s2p0z0yrzyi7pjhbwy3hqm25bbprrql0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,7 +147,7 @@
|
||||||
:network "mainnet_rpc"
|
:network "mainnet_rpc"
|
||||||
:wallet-set-up-passed? false
|
:wallet-set-up-passed? false
|
||||||
:public-key "0x04173f7cdea0076a7998abb674cc79fe61337c42db77043c01d5b0f3e3ac1e5a45bca0c93bb9f3c3d38b7cc9a7337cd64f9f9b2114fe4bbdfe1ae2633ba14d8c9c"
|
:public-key "0x04173f7cdea0076a7998abb674cc79fe61337c42db77043c01d5b0f3e3ac1e5a45bca0c93bb9f3c3d38b7cc9a7337cd64f9f9b2114fe4bbdfe1ae2633ba14d8c9c"
|
||||||
:keycard-instance-uid nil
|
:keycard-key-uid nil
|
||||||
:installation-id "618ec020-13c8-5505-8aa6-9c5444317e7f"})
|
:installation-id "618ec020-13c8-5505-8aa6-9c5444317e7f"})
|
||||||
|
|
||||||
(def multiaccounts
|
(def multiaccounts
|
||||||
|
|
|
@ -465,6 +465,7 @@
|
||||||
"generate-new-key": "Generate a new key",
|
"generate-new-key": "Generate a new key",
|
||||||
"generating-codes-for-pairing": "> Downloading product software to card\n > Generating unlocking & pairing codes",
|
"generating-codes-for-pairing": "> Downloading product software to card\n > Generating unlocking & pairing codes",
|
||||||
"generating-keys": "Generating keys...",
|
"generating-keys": "Generating keys...",
|
||||||
|
"you-will-need-this-code": "You'll need this code to open Status and sign transactions",
|
||||||
"generating-mnemonic": "Generating mnemonic phrase",
|
"generating-mnemonic": "Generating mnemonic phrase",
|
||||||
"get-started": "Get started",
|
"get-started": "Get started",
|
||||||
"get-status-at": "Get Status at http://status.im",
|
"get-status-at": "Get Status at http://status.im",
|
||||||
|
@ -555,6 +556,7 @@
|
||||||
"keycard-cancel-setup-title": "Dangerous operation",
|
"keycard-cancel-setup-title": "Dangerous operation",
|
||||||
"keycard-desc": "Android only. You will need to get a Keycard first",
|
"keycard-desc": "Android only. You will need to get a Keycard first",
|
||||||
"keycard-has-multiaccount-on-it": "This card has already an multiaccount on it. If you wish to change it, login first and reset your card. If you want to import keycard multiaccount, please use \"Add existing multiaccount\"",
|
"keycard-has-multiaccount-on-it": "This card has already an multiaccount on it. If you wish to change it, login first and reset your card. If you want to import keycard multiaccount, please use \"Add existing multiaccount\"",
|
||||||
|
"keycard-existing-multiaccount": "You can't recover this multiaccount because it's already on your phone",
|
||||||
"keycard-onboarding-finishing-header": "Finishing up",
|
"keycard-onboarding-finishing-header": "Finishing up",
|
||||||
"keycard-onboarding-intro-header": "Store your key on Keycard",
|
"keycard-onboarding-intro-header": "Store your key on Keycard",
|
||||||
"keycard-onboarding-intro-text": "Get ready, this might take a few minutes, but it's important to secure your account",
|
"keycard-onboarding-intro-text": "Get ready, this might take a few minutes, but it's important to secure your account",
|
||||||
|
|
Loading…
Reference in New Issue