[slow sign in] Unlock account's DB before starting node

There is no need to wait for `Statusgo.Login` callback in order to start
unlocking realm db: currently it is encrypted via a key which is derived
from user’s password, so we can try to unlock that DB before starting
node. That’s how password will be checked. Right after that `:home`
screen is shown, the node is started, then `Statusgo.Login` executed.

The difference in sign in duration is more noticeable on Android
devices, where `Statusgo.Login` is much slower because of PFS database
encryption.
This commit is contained in:
Roman Volosovskyi 2018-11-26 17:52:29 +02:00
parent f6777edbdc
commit 4aa562f6a8
No known key found for this signature in database
GPG Key ID: 0238A4B5ECEE70DE
21 changed files with 303 additions and 114 deletions

View File

@ -391,6 +391,31 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
public void verify(final String address, final String password, final Callback callback) {
Log.d(TAG, "verify");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Activity currentActivity = getCurrentActivity();
final String absRootDirPath = currentActivity.getApplicationInfo().dataDir;
final String newKeystoreDir = pathCombine(absRootDirPath, "keystore");
Runnable r = new Runnable() {
@Override
public void run() {
String result = Statusgo.VerifyAccountPassword(newKeystoreDir, address, password);
callback.invoke(result);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
public void createAccount(final String password, final Callback callback) {
Log.d(TAG, "createAccount");

View File

@ -228,6 +228,25 @@ RCT_EXPORT_METHOD(login:(NSString *)address
callback(@[[NSString stringWithUTF8String: result]]);
}
//////////////////////////////////////////////////////////////////// login
RCT_EXPORT_METHOD(verify:(NSString *)address
password:(NSString *)password
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"VerifyAccountPassword() method called");
#endif
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *absKeystoreUrl = [rootUrl URLByAppendingPathComponent:@"keystore"];
char * result = VerifyAccountPassword((char *) [absKeystoreUrl.path UTF8String],
(char *) [address UTF8String],
(char *) [password UTF8String]);
callback(@[[NSString stringWithUTF8String: result]]);
}
////////////////////////////////////////////////////////////////////
#pragma mark - SendTransaction
//////////////////////////////////////////////////////////////////// sendTransaction

View File

@ -3,13 +3,17 @@
[status-im.accounts.db :as accounts.db]
[status-im.data-store.core :as data-store]
[status-im.native-module.core :as status]
[status-im.node.core :as node]
[status-im.ui.screens.navigation :as navigation]
[status-im.utils.fx :as fx]
[status-im.utils.keychain.core :as keychain]
[status-im.utils.types :as types]
[taoensso.timbre :as log]
[status-im.utils.security :as security]))
[status-im.utils.security :as security]
[status-im.utils.platform :as platform]
[status-im.protocol.core :as protocol]
[status-im.models.wallet :as models.wallet]
[status-im.models.transactions :as transactions]
[status-im.i18n :as i18n]))
;; login flow:
;;
@ -22,13 +26,18 @@
(defn login! [address password save-password?]
(status/login address password #(re-frame/dispatch [:accounts.login.callback/login-success %])))
(defn verify! [address password realm-error]
(status/verify address password
#(re-frame/dispatch
[:accounts.login.callback/verify-success % realm-error])))
(defn clear-web-data! []
(status/clear-web-data))
(defn change-account! [address password]
(defn change-account! [address password create-database-if-not-exist?]
;; No matter what is the keychain we use, as checks are done on decrypting base
(.. (keychain/safe-get-encryption-key)
(then #(data-store/change-account address password %))
(then #(data-store/change-account address password % create-database-if-not-exist?))
(then (fn [] (re-frame/dispatch [:init.callback/account-change-success address])))
(catch (fn [error]
(log/warn "Could not change account" error)
@ -40,26 +49,137 @@
(let [{:keys [address password save-password?]} (accounts.db/credentials cofx)]
{:accounts.login/login [address password save-password?]}))
(fx/defn user-login [{:keys [db] :as cofx}]
(fx/defn initialize-wallet [cofx]
(fx/merge cofx
{:db (assoc-in db [:accounts/login :processing] true)}
(node/initialize (get-in db [:accounts/login :address]))))
(models.wallet/initialize-tokens)
(models.wallet/update-wallet)
(transactions/start-sync)))
(fx/defn user-login [{:keys [db] :as cofx}]
(let [{:keys [address password save-password?]} (accounts.db/credentials cofx)]
(fx/merge
cofx
(merge
{:db (assoc-in db [:accounts/login :processing] true)
:accounts.login/clear-web-data nil
:data-store/change-account [address password false]}
(when save-password?
{:keychain/save-user-password [address password]})))))
(fx/defn account-and-db-password-do-not-match
[{:keys [db] :as cofx} error]
(fx/merge
cofx
{:db
(update db :accounts/login assoc
:error error
:processing false)
:utils/show-popup
{:title (i18n/label :account-and-db-password-mismatch-title)
:content (i18n/label :account-and-db-password-mismatch-content)}
:dispatch [:accounts.logout.ui/logout-confirmed]}))
(fx/defn user-login-callback
[{db :db :as cofx} login-result]
[{:keys [db web3] :as cofx} login-result]
(let [data (types/json->clj login-result)
error (:error data)
success (empty? error)
address (get-in db [:account/account :address])]
;; check if logged into account
(when address
(if success
(fx/merge
cofx
{:db (dissoc db :accounts/login)
:web3/set-default-account [web3 address]
:web3/fetch-node-version [web3
#(re-frame/dispatch
[:web3/fetch-node-version-callback %])]}
(protocol/initialize-protocol address)
#(when-not platform/desktop?
(initialize-wallet %)))
(account-and-db-password-do-not-match cofx error)))))
(fx/defn show-migration-error-dialog
[{:keys [db]} realm-error]
(let [{:keys [message]} realm-error
address (get-in db [:accounts/login :address])
erase-button (i18n/label :migrations-erase-accounts-data-button)]
{:ui/show-confirmation
{:title (i18n/label :invalid-key-title)
:content (i18n/label
:invalid-key-content
{:message message
:erase-accounts-data-button-text erase-button})
:confirm-button-text (i18n/label :invalid-key-confirm)
:on-cancel #(re-frame/dispatch
[:init.ui/data-reset-cancelled ""])
:on-accept #(re-frame/dispatch
[:init.ui/account-data-reset-accepted address])}}))
(fx/defn verify-callback
[{:keys [db] :as cofx} verify-result realm-error]
(let [data (types/json->clj verify-result)
error (:error data)
success (empty? error)]
(if success
(let [{:keys [address password save-password?]} (accounts.db/credentials cofx)]
(merge {:accounts.login/clear-web-data nil
:data-store/change-account [address password]}
(when save-password?
{:keychain/save-user-password [address password]})))
(case (:error realm-error)
:decryption-failed
(show-migration-error-dialog cofx realm-error)
:database-does-not-exist
(let [{:keys [address password]} (accounts.db/credentials cofx)]
{:data-store/change-account [address password true]}))
{:db (update db :accounts/login assoc
:error error
:processing false)})))
(fx/defn handle-change-account-error
[{:keys [db] :as cofx} error]
(let [{:keys [error message details] :as realm-error}
(if (map? error)
error
{:message (str error)})
{:keys [address password]} (accounts.db/credentials cofx)
erase-button (i18n/label :migrations-erase-accounts-data-button)]
(case error
:migrations-failed
(let [{:keys [message]} realm-error
address (get-in db [:accounts/login :address])]
{:ui/show-confirmation
{:title (i18n/label :migrations-failed-title)
:content (i18n/label
:migrations-failed-content
(merge
{:message message
:erase-accounts-data-button-text erase-button}
details))
:confirm-button-text erase-button
:on-cancel #(re-frame/dispatch
[:init.ui/data-reset-cancelled ""])
:on-accept #(re-frame/dispatch
[:init.ui/account-data-reset-accepted address])}})
:database-does-not-exist
{:accounts.login/verify [address password realm-error]}
:decryption-failed
;; check if decryption failed because of wrong password
{:accounts.login/verify [address password realm-error]}
{:ui/show-confirmation
{:title (i18n/label :unknown-realm-error)
:content (i18n/label
:unknown-realm-error-content
{:message message
:erase-accounts-data-button-text erase-button})
:confirm-button-text (i18n/label :invalid-key-confirm)
:on-cancel #(re-frame/dispatch
[:init.ui/data-reset-cancelled ""])
:on-accept #(re-frame/dispatch
[:init.ui/account-data-reset-accepted address])}})))
(fx/defn open-login [{:keys [db]} address photo-path name]
{:db (-> db
(update :accounts/login assoc
@ -87,11 +207,17 @@
(fn [[address password save-password?]]
(login! address (security/safe-unmask-data password) save-password?)))
(re-frame/reg-fx
:accounts.login/verify
(fn [[address password realm-error]]
(verify! address (security/safe-unmask-data password) realm-error)))
(re-frame/reg-fx
:accounts.login/clear-web-data
clear-web-data!)
(re-frame/reg-fx
:data-store/change-account
(fn [[address password]]
(change-account! address (security/safe-unmask-data password))))
(fn [[address password create-database-if-not-exist?]]
(change-account! address (security/safe-unmask-data password)
create-database-if-not-exist?)))

View File

@ -1,7 +1,6 @@
(ns status-im.accounts.logout.core
(:require [re-frame.core :as re-frame]
[status-im.i18n :as i18n]
[status-im.init.core :as init]
[status-im.transport.core :as transport]
[status-im.ui.screens.navigation :as navigation]
[status-im.utils.fx :as fx]
@ -12,11 +11,11 @@
(let [{:transport/keys [chats]} db]
(fx/merge cofx
{:keychain/clear-user-password (get-in db [:account/account :address])
:dev-server/stop nil}
:dev-server/stop nil
:keychain/get-encryption-key [:init.callback/get-encryption-key-success]}
(transactions/stop-sync)
(navigation/navigate-to-clean :login {})
(transport/stop-whisper)
(init/initialize-keychain))))
(transport/stop-whisper))))
(fx/defn show-logout-confirmation [_]
{:ui/show-confirmation

View File

@ -25,7 +25,8 @@
(log/error "Could not move realms" error)))
(then #(data-source/open-base-realm encryption-key)))))
(defn change-account [address password encryption-key]
(defn change-account
[address password encryption-key create-database-if-not-exist?]
(log/debug "changing account to: " address)
(..
(js/Promise.
@ -36,6 +37,10 @@
(catch :default e
(on-error {:message (str e)
:error :closing-account-failed})))))
(then
(if create-database-if-not-exist?
#(js/Promise. (fn [on-success] (on-success)))
#(data-source/db-exists? address)))
(then
#(data-source/check-db-encryption address password encryption-key))
(then

View File

@ -255,6 +255,16 @@
#(re-encrypt-realm file-name old-key new-key on-success on-error))
(catch on-error)))))))))
(defn db-exists? [address]
(js/Promise.
(fn [on-success on-error]
(.. (fs/file-exists? (get-account-db-path address))
(then (fn [db-exists?]
(if db-exists?
(on-success)
(on-error {:message "Account's database doesn't exist."
:error :database-does-not-exist}))))))))
(defn open-account [address password encryption-key]
(let [path (get-account-db-path address)
account-db-key (db-encryption-key password encryption-key)]

View File

@ -45,7 +45,8 @@
[taoensso.timbre :as log]
[status-im.utils.datetime :as time]
[status-im.chat.commands.core :as commands]
[status-im.chat.models.loading :as chat-loading]))
[status-im.chat.models.loading :as chat-loading]
[status-im.node.core :as node]))
;; init module
@ -102,15 +103,11 @@
:init-chats
[(re-frame/inject-cofx :web3/get-web3)
(re-frame/inject-cofx :get-default-dapps)
(re-frame/inject-cofx :data-store/all-chats)
(re-frame/inject-cofx :data-store/get-all-mailservers)
(re-frame/inject-cofx :data-store/transport)
(re-frame/inject-cofx :data-store/mailserver-topics)]
(re-frame/inject-cofx :data-store/all-chats)]
(fn [{:keys [db] :as cofx} [_ address]]
(fx/merge cofx
{:db (assoc db :chats/loading? false)}
(chat-loading/initialize-chats)
(protocol/initialize-protocol address)
(chat-loading/initialize-pending-messages))))
(handlers/register-handler-fx
@ -120,13 +117,11 @@
(re-frame/inject-cofx :data-store/get-all-installations)
(re-frame/inject-cofx :data-store/all-browsers)
(re-frame/inject-cofx :data-store/all-dapp-permissions)]
(fn [cofx [_ address]]
(init/initialize-account cofx address)))
(handlers/register-handler-fx
:init.callback/account-change-error
(fn [cofx [_ error]]
(init/handle-change-account-error cofx error)))
(fn [{:keys [db] :as cofx} [_ address]]
(fx/merge
cofx
(node/initialize (get-in db [:accounts/login :address]))
(init/initialize-account address))))
(handlers/register-handler-fx
:init.callback/keychain-reset
@ -261,9 +256,24 @@
(handlers/register-handler-fx
:accounts.login.callback/login-success
[(re-frame/inject-cofx :web3/get-web3)
(re-frame/inject-cofx :data-store/all-chats)
(re-frame/inject-cofx :data-store/get-all-mailservers)
(re-frame/inject-cofx :data-store/transport)
(re-frame/inject-cofx :data-store/mailserver-topics)]
(fn [cofx [_ login-result]]
(accounts.login/user-login-callback cofx login-result)))
(handlers/register-handler-fx
:accounts.login.callback/verify-success
(fn [cofx [_ verify-result realm-error]]
(accounts.login/verify-callback cofx verify-result realm-error)))
(handlers/register-handler-fx
:init.callback/account-change-error
(fn [cofx [_ error]]
(accounts.login/handle-change-account-error cofx error)))
(handlers/register-handler-fx
:accounts.login.ui/account-selected
(fn [cofx [_ address photo-path name]]

View File

@ -106,41 +106,6 @@
[{:keys [db]} device-uuid]
{:db (assoc db :device-UUID device-uuid)})
(fx/defn handle-change-account-error
[{:keys [db]} error]
(let [{:keys [error message details]}
(if (map? error)
error
{:message (str error)})
address (get-in db [:accounts/login :address])
erase-button-text (i18n/label :migrations-erase-accounts-data-button)]
(case error
:migrations-failed
{:ui/show-confirmation
{:title (i18n/label :migrations-failed-title)
:content (i18n/label
:migrations-failed-content
(merge
{:message message
:erase-accounts-data-button-text erase-button-text}
details))
:confirm-button-text erase-button-text
:on-cancel #(re-frame/dispatch [:init.ui/data-reset-cancelled ""])
:on-accept #(re-frame/dispatch [:init.ui/account-data-reset-accepted address])}}
;; TODO(rasom): handle different errors as separate cases
;; Right now it might be corrupted db file, wrong password,
;; problem with permissions, etc.
{:ui/show-confirmation
{:title (i18n/label :invalid-key-title)
:content (i18n/label
:invalid-key-content
{:message message
:erase-accounts-data-button-text erase-button-text})
:confirm-button-text (i18n/label :invalid-key-confirm)
:on-cancel #(re-frame/dispatch [:init.ui/data-reset-cancelled ""])
:on-accept #(re-frame/dispatch [:init.ui/account-data-reset-accepted address])}})))
(fx/defn handle-init-store-error
[encryption-key cofx]
{:ui/show-confirmation
@ -183,9 +148,9 @@
(fx/defn initialize-account-db [{:keys [db web3]} address]
(let [{:universal-links/keys [url]
:keys [accounts/accounts accounts/create contacts/contacts networks/networks
network network-status peers-count peers-summary view-id navigation-stack
pairing/installations status-module-initialized? device-UUID semaphores]
:keys [accounts/accounts accounts/create networks/networks network
network-status peers-count peers-summary view-id navigation-stack
status-module-initialized? device-UUID semaphores accounts/login]
:node/keys [status]
:or {network (get app-db :network)}} db
current-account (get accounts address)
@ -199,6 +164,8 @@
:accounts/create create
:networks/networks networks
:account/account current-account
:accounts/login login
:accounts/accounts accounts
:network-status network-status
:network network
:chain (ethereum/network->chain-name account-network)
@ -211,12 +178,6 @@
(= view-id :create-account)
(assoc-in [:accounts/create :step] :enter-name))}))
(defn initialize-wallet [cofx]
(fx/merge cofx
(models.wallet/initialize-tokens)
(models.wallet/update-wallet)
(transactions/start-sync)))
(defn login-only-events [cofx address]
(fx/merge cofx
{:notifications/request-notifications-permissions nil}
@ -234,23 +195,18 @@
(= (get-in cofx [:db :view-id])
:create-account))
(fx/defn initialize-account [{:keys [db web3] :as cofx} address]
(fx/defn initialize-account [cofx address]
(fx/merge cofx
{:web3/set-default-account [web3 address]
:web3/fetch-node-version [web3
#(re-frame/dispatch
[:web3/fetch-node-version-callback %])]
:notifications/get-fcm-token nil}
{:notifications/get-fcm-token nil}
(initialize-account-db address)
(contact/load-contacts)
(pairing/load-installations)
#(when (dev-mode? %)
(models.dev-server/start))
(browser/initialize-browsers)
(browser/initialize-dapp-permissions)
(extensions.registry/initialize)
#(when-not platform/desktop?
(initialize-wallet %))
(accounts.update/update-sign-in-time)
#(when-not (creating-account? %)
(login-only-events % address))))

View File

@ -365,12 +365,13 @@
[{:keys [db] :as cofx}]
;; check if logged into account
(when (contains? db :account/account)
(if (zero? (dec (:mailserver/connection-checks db)))
(let [connection-checks (dec (:mailserver/connection-checks db))]
(if (>= 0 connection-checks)
(fx/merge cofx
{:db (dissoc db :mailserver/connection-checks)}
(when (= :connecting (:mailserver/state db))
(change-mailserver cofx)))
{:db (update db :mailserver/connection-checks dec)})))
{:db (update db :mailserver/connection-checks dec)}))))
(fx/defn reset-request-to
[{:keys [db]}]

View File

@ -6,6 +6,9 @@
(defn start-node [config]
(native-module/start-node config))
(defn node-ready []
(native-module/node-ready))
(defn stop-node []
(native-module/stop-node))
@ -18,6 +21,9 @@
(defn login [address password callback]
(native-module/login address password callback))
(defn verify [address password callback]
(native-module/verify address password callback))
(defn set-soft-input-mode [mode]
(native-module/set-soft-input-mode mode))

View File

@ -54,10 +54,16 @@
(.addListener r/device-event-emitter "gethEvent"
#(re-frame/dispatch [:signals/signal-received (.-jsonEvent %)])))
(defonce node-started (atom false))
(defn stop-node []
(reset! node-started false)
(when status
(call-module #(.stopNode status))))
(defn node-ready []
(reset! node-started true))
(defn start-node [config]
(when status
(call-module #(.startNode status config))))
@ -82,17 +88,21 @@
(call-module #(.notifyUsers status message payload tokens on-result))))
(defn add-peer [enode on-result]
(when status
(when (and @node-started status)
(call-module #(.addPeer status enode on-result))))
(defn recover-account [passphrase password on-result]
(when status
(when (and @node-started status)
(call-module #(.recoverAccount status passphrase password on-result))))
(defn login [address password on-result]
(when status
(when (and @node-started status)
(call-module #(.login status address password on-result))))
(defn verify [address password on-result]
(when (and @node-started status)
(call-module #(.verify status address password on-result))))
(defn set-soft-input-mode [mode]
(when status
(call-module #(.setSoftInputMode status mode))))
@ -103,19 +113,19 @@
(call-module #(.clearStorageAPIs status))))
(defn call-rpc [payload callback]
(when status
(when (and @node-started status)
(call-module #(.callRPC status payload callback))))
(defn call-private-rpc [payload callback]
(when status
(when (and @node-started status)
(call-module #(.callPrivateRPC status payload callback))))
(defn sign-message [rpcParams callback]
(when status
(when (and @node-started status)
(call-module #(.signMessage status rpcParams callback))))
(defn send-transaction [rpcParams password callback]
(when status
(when (and @node-started status)
(call-module #(.sendTransaction status rpcParams password callback))))
(defn close-application []

View File

@ -177,6 +177,11 @@
(fn [config]
(status/start-node config)))
(re-frame/reg-fx
:node/ready
(fn [config]
(status/node-ready)))
(re-frame/reg-fx
:node/stop
(fn []

View File

@ -4,7 +4,6 @@
[status-im.react-native.js-dependencies :as rn]
[taoensso.timbre :as log]
[status-im.accounts.db :as accounts.db]
[status-im.accounts.login.core :as accounts.login]
[status-im.chat.models :as chat-model]
[status-im.utils.platform :as platform]
[status-im.utils.fx :as fx]))

View File

@ -18,7 +18,8 @@
(fx/merge cofx
{:db (-> db
(assoc :node/status :started)
(dissoc :node/restart? :node/address))}
(dissoc :node/restart? :node/address))
:node/ready nil}
(when restart?
(node/initialize address))

View File

@ -38,7 +38,9 @@
(string/starts-with? error "there is no running node")
:t/node-unavailable
(or
(string/starts-with? error "cannot retrieve a valid key")
(string/starts-with? error "could not decrypt key"))
:t/wrong-password
:else

View File

@ -14,20 +14,22 @@
(animation/timing spin-value {:toValue to-spin-value
:duration 300})))))
(defn sendable? [input-text offline?]
(defn sendable? [input-text offline? login-processing?]
(let [trimmed (string/trim input-text)]
(not (or (string/blank? trimmed)
(= trimmed "/")
offline?))))
offline?
login-processing?))))
(defview send-button-view []
(letsubs [{:keys [command-completion]} [:chats/selected-chat-command]
{:keys [input-text seq-arg-input-text]} [:chats/current-chat]
{:keys [input-text]} [:chats/current-chat]
offline? [:offline?]
spin-value (animation/create-value 1)]
spin-value (animation/create-value 1)
login-processing? [:get-in [:accounts/login :processing]]]
{:component-did-update (send-button-view-on-update {:spin-value spin-value
:command-completion command-completion})}
(when (and (sendable? input-text offline?)
(when (and (sendable? input-text offline? login-processing?)
(or (not command-completion)
(#{:complete :less-than-needed} command-completion)))
[react/touchable-highlight {:on-press #(re-frame/dispatch [:chat.ui/send-current-message])}

View File

@ -72,6 +72,9 @@
(def settings-item-destructive
{:color colors/red})
(def settings-item-disabled
{:color colors/gray})
(def settings-item-value
{:flex 1
:flex-wrap :nowrap

View File

@ -84,7 +84,8 @@
[react/view styles/settings-item
[react/view styles/settings-item-text-wrapper
[react/text {:style (merge styles/settings-item-text
(when destructive? styles/settings-item-destructive))
(when destructive? styles/settings-item-destructive)
(when-not active? styles/settings-item-disabled))
:number-of-lines 1}
(or item-text (i18n/label label-kw))]
(when-not (string/blank? value)

View File

@ -98,7 +98,7 @@
:source source
:value value}]))
(defn- my-profile-settings [{:keys [seed-backed-up? mnemonic]} {:keys [settings]} currency]
(defn- my-profile-settings [{:keys [seed-backed-up? mnemonic]} {:keys [settings]} currency logged-in?]
(let [show-backup-seed? (and (not seed-backed-up?) (not (string/blank? mnemonic)))]
[react/view
[profile.components/settings-title (i18n/label :t/settings)]
@ -143,6 +143,7 @@
:accessibility-label :log-out-button
:destructive? true
:hide-arrow? true
:active? logged-in?
:action-fn #(re-frame/dispatch [:accounts.logout.ui/logout-pressed])}]]]]))
(defview advanced-settings [{:keys [network networks dev-mode? settings]} on-show]
@ -214,6 +215,7 @@
editing? [:get :my-profile/editing?]
changed-account [:get :my-profile/profile]
currency [:wallet/currency]
login-data [:get :accounts/login]
scroll (reagent/atom nil)]
(let [shown-account (merge current-account changed-account)
;; We scroll on the component once rendered. setTimeout is necessary,
@ -252,5 +254,5 @@
:accessibility-label :share-my-profile-button}
(i18n/label :t/share-my-profile)]]
[react/view styles/my-profile-info-container
[my-profile-settings current-account shown-account currency]]
[my-profile-settings current-account shown-account currency (nil? login-data)]]
[advanced shown-account on-show-advanced]]])))

View File

@ -17,3 +17,6 @@
(defn unlink [path]
(.unlink rn-dependencies/fs path))
(defn file-exists? [path]
(.exists rn-dependencies/fs path))

View File

@ -385,6 +385,7 @@
"currency-display-name-ron": "Romania Leu",
"log-level-settings": "Log level settings",
"invalid-key-content": "{{message}}\n\nAccount's database can't be encrypted because file is corrupted. There is no way to restore it. If you press \"Cancel\" button, nothing will happen. If you press \"{{erase-accounts-data-button-text}}\" button, account's db will be removed and you will be able to unlock account. All account's data will be lost.",
"unknown-realm-error-content": "{{message}}\n\nAccount's database can't be opened. Please let us know about this problem at #status public chat. If you press \"Cancel\" button, nothing will happen. If you press \"{{erase-accounts-data-button-text}}\" button, account's db will be removed and you will be able to unlock account. All account's data will be lost.",
"advanced-settings": "Advanced settings",
"group-info": "Group info",
"currency-display-name-nio": "Nicaragua Cordoba",
@ -420,6 +421,7 @@
"wallet-send": "Send",
"wallet-deposit": "Deposit",
"invalid-key-title": "We detected a problem with the encryption key",
"unknown-realm-error": "Something went wrong",
"notifications": "Notifications",
"currency-display-name-czk": "Czech Koruna",
"extension-installed": "You installed an extension",
@ -791,5 +793,7 @@
"install-the-extension": "install the extension",
"migrations-failed-title": "Migration failed",
"migrations-failed-content": "{{message}}\nschema version: initial {{initial-version}}, current {{current-version}}, last {{last-version}}\n\nPlease let us know about this problem at #status public chat. If you press \"Cancel\" button, nothing will happen. If you press \"{{erase-accounts-data-button-text}}\" button, account's db will be removed and you will be able to unlock account. All account's data will be lost.",
"migrations-erase-accounts-data-button": "Erase account's db"
"migrations-erase-accounts-data-button": "Erase account's db",
"account-and-db-password-mismatch-title": "The problem occurred!",
"account-and-db-password-mismatch-content": "Account's and realm db passwords do not match."
}