mirror of
https://github.com/status-im/status-mobile.git
synced 2025-02-02 11:57:04 +00:00
[#10195] Delete multiaccount
This commit is contained in:
parent
4254dbcb26
commit
10a814764d
@ -504,10 +504,17 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
||||
StatusThreadPoolExecutor.getInstance().execute(r);
|
||||
}
|
||||
|
||||
public String getKeyStorePath(String keyUID) {
|
||||
final String commonKeydir = pathCombine(this.getNoBackupDirectory(), "/keystore");
|
||||
final String keydir = pathCombine(commonKeydir, keyUID);
|
||||
|
||||
return keydir;
|
||||
}
|
||||
|
||||
public void migrateKeyStoreDir(final String accountData, final String password) {
|
||||
try {
|
||||
final String commonKeydir = pathCombine(this.getNoBackupDirectory(), "/keystore");
|
||||
final String keydir = pathCombine(commonKeydir, getKeyUID(accountData));
|
||||
final String keydir = this.getKeyStorePath(this.getKeyUID(accountData));
|
||||
Log.d(TAG, "before migrateKeyStoreDir " + keydir);
|
||||
|
||||
File keydirFile = new File(keydir);
|
||||
@ -1183,6 +1190,27 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
||||
StatusThreadPoolExecutor.getInstance().execute(r);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void deleteMultiaccount(final String keyUID, final Callback callback) {
|
||||
Log.d(TAG, "deleteMultiaccount");
|
||||
if (!checkAvailability()) {
|
||||
callback.invoke(false);
|
||||
return;
|
||||
}
|
||||
|
||||
final String keyStoreDir = this.getKeyStorePath(keyUID);
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String res = Statusgo.deleteMultiaccount(keyUID, keyStoreDir);
|
||||
|
||||
callback.invoke(res);
|
||||
}
|
||||
};
|
||||
|
||||
StatusThreadPoolExecutor.getInstance().execute(r);
|
||||
}
|
||||
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
public String generateAlias(final String seed) {
|
||||
return Statusgo.generateAlias(seed);
|
||||
|
@ -221,6 +221,17 @@ RCT_EXPORT_METHOD(chaosModeUpdate:(BOOL)on
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////// multiAccountImportPrivateKey
|
||||
RCT_EXPORT_METHOD(deleteMultiaccount:(NSString *)keyUID
|
||||
callback:(RCTResponseSenderBlock)callback) {
|
||||
#if DEBUG
|
||||
NSLog(@"MultiAccountImportPrivateKey() method called");
|
||||
#endif
|
||||
NSURL *multiaccountKeystoreDir = [self getKeyStoreDir:keyUID];
|
||||
NSString *result = StatusgoDeleteMultiaccount(keyUID, multiaccountKeystoreDir.path);
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////// multiAccountGenerateAndDeriveAddresses
|
||||
RCT_EXPORT_METHOD(multiAccountGenerateAndDeriveAddresses:(NSString *)json
|
||||
callback:(RCTResponseSenderBlock)callback) {
|
||||
@ -440,6 +451,18 @@ RCT_EXPORT_METHOD(saveAccountAndLoginWithKeycard:(NSString *)multiaccountData
|
||||
NSLog(@"%@", result);
|
||||
}
|
||||
|
||||
- (NSURL *) getKeyStoreDir:(NSString *)keyUID {
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSURL *rootUrl =[[fileManager
|
||||
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
|
||||
lastObject];
|
||||
|
||||
NSURL *oldKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
|
||||
NSURL *multiaccountKeystoreDir = [oldKeystoreDir URLByAppendingPathComponent:keyUID];
|
||||
|
||||
return multiaccountKeystoreDir;
|
||||
}
|
||||
|
||||
- (void) migrateKeystore:(NSString *)accountData
|
||||
password:(NSString *)password {
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
@ -449,7 +472,7 @@ RCT_EXPORT_METHOD(saveAccountAndLoginWithKeycard:(NSString *)multiaccountData
|
||||
|
||||
NSString *keyUID = [self getKeyUID:accountData];
|
||||
NSURL *oldKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
|
||||
NSURL *multiaccountKeystoreDir = [oldKeystoreDir URLByAppendingPathComponent:keyUID];
|
||||
NSURL *multiaccountKeystoreDir = [self getKeyStoreDir:keyUID];
|
||||
|
||||
NSArray *keys = [fileManager contentsOfDirectoryAtPath:multiaccountKeystoreDir.path error:nil];
|
||||
if (keys.count == 0) {
|
||||
|
12
src/quo/components/separator.cljs
Normal file
12
src/quo/components/separator.cljs
Normal file
@ -0,0 +1,12 @@
|
||||
(ns quo.components.separator
|
||||
(:require [quo.react-native :as react]
|
||||
[quo.design-system.colors :as colors]))
|
||||
|
||||
(defn separator [{:keys [color style]}]
|
||||
[react/view
|
||||
{:style
|
||||
(merge
|
||||
style
|
||||
{:background-color (colors/get-color (or color :ui-01))
|
||||
:align-self :stretch
|
||||
:height 1})}])
|
@ -10,7 +10,9 @@
|
||||
[quo.components.list.footer :as list-footer]
|
||||
[quo.components.list.item :as list-item]
|
||||
[quo.components.controls.view :as controls]
|
||||
[quo.components.bottom-sheet.view :as bottom-sheet]))
|
||||
[quo.components.bottom-sheet.view :as bottom-sheet]
|
||||
[quo.components.separator :as separator]
|
||||
[quo.design-system.colors :as colors]))
|
||||
|
||||
(def text text/text)
|
||||
(def header header/header)
|
||||
@ -28,3 +30,5 @@
|
||||
(def safe-area-provider safe-area/provider)
|
||||
(def safe-area-consumer safe-area/consumer)
|
||||
(def safe-area-view safe-area/view)
|
||||
(def separator separator/separator)
|
||||
(def get-color colors/get-color)
|
||||
|
@ -71,3 +71,6 @@
|
||||
:backdrop "rgba(0,0,0,0.4)"})
|
||||
|
||||
(def theme (reagent/atom light-theme))
|
||||
|
||||
(defn get-color [color]
|
||||
(get @theme color))
|
||||
|
@ -65,7 +65,8 @@
|
||||
status-im.utils.universal-links.events
|
||||
status-im.search.core
|
||||
status-im.ui.screens.profile.events
|
||||
status-im.chat.models.images))
|
||||
status-im.chat.models.images
|
||||
status-im.ui.screens.privacy-and-security-settings.events))
|
||||
|
||||
;; init module
|
||||
(handlers/register-handler-fx
|
||||
|
@ -357,3 +357,10 @@
|
||||
[mnemonic callback]
|
||||
(log/debug "[native-module] validate-mnemonic")
|
||||
(.validateMnemonic ^js (status) mnemonic callback))
|
||||
|
||||
(defn delete-multiaccount
|
||||
"Delete multiaccount from database, deletes multiaccount's database and
|
||||
key files."
|
||||
[key-uid callback]
|
||||
(log/debug "[native-module] delete-multiaccount")
|
||||
(.deleteMultiaccount ^js (status) key-uid callback))
|
||||
|
@ -188,6 +188,9 @@
|
||||
;; keycard
|
||||
(reg-root-key-sub :keycard/new-account-sheet? :keycard/new-account-sheet?)
|
||||
|
||||
;; delete profile
|
||||
(reg-root-key-sub :delete-profile/error :delete-profile/error)
|
||||
|
||||
;;GENERAL ==============================================================================================================
|
||||
|
||||
(re-frame/reg-sub
|
||||
|
@ -0,0 +1,86 @@
|
||||
(ns status-im.ui.screens.privacy-and-security-settings.delete-profile
|
||||
(:require [status-im.ui.components.react :as react]
|
||||
[quo.core :as quo]
|
||||
[status-im.multiaccounts.core :as multiaccounts]
|
||||
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ui.components.topbar :as topbar]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.i18n :as i18n]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.utils.security :as security]
|
||||
[status-im.ui.screens.privacy-and-security-settings.events :as delete-profile]))
|
||||
|
||||
(defn valid-password? [password]
|
||||
(>= (count password) 6))
|
||||
|
||||
(defn keycard-pin []
|
||||
#_(let [pin @(re-frame/subscribe [:keycard/pin])
|
||||
step @(re-frame/subscribe [:keycard/pin-enter-step])
|
||||
status @(re-frame/subscribe [:keycard/pin-status])
|
||||
pin-retry-counter @(re-frame/subscribe [:keycard/pin-retry-counter])
|
||||
puk-retry-counter @(re-frame/subscribe [:keycard/puk-retry-counter])
|
||||
error-label @(re-frame/subscribe [:keycard/pin-error-label])]
|
||||
[pin.views/pin-view
|
||||
{:pin pin
|
||||
:status status
|
||||
:retry-counter pin-retry-counter
|
||||
:error-label error-label
|
||||
:step :current}]))
|
||||
|
||||
(defn delete-profile []
|
||||
(let [password (reagent/atom nil)
|
||||
text-input-ref (atom nil)]
|
||||
(fn []
|
||||
(let [keycard? @(re-frame/subscribe [:keycard-multiaccount?])
|
||||
multiaccount @(re-frame/subscribe [:multiaccount])
|
||||
error @(re-frame/subscribe [:delete-profile/error])]
|
||||
(when (and @text-input-ref error (not @password))
|
||||
(.clear ^js @text-input-ref))
|
||||
[react/view components.styles/flex
|
||||
[topbar/topbar {:modal? true}]
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:justify-content :space-between}}
|
||||
[react/scroll-view {:style {:flex 1}}
|
||||
[react/view {:style {:align-items :center}}
|
||||
[quo/text {:weight :bold
|
||||
:size :x-large}
|
||||
(i18n/label :t/delete-profile)]]
|
||||
[quo/list-item
|
||||
{:title (multiaccounts/displayed-name multiaccount)
|
||||
:icon [chat-icon.screen/contact-icon-contacts-tab
|
||||
(multiaccounts/displayed-photo multiaccount)]}]
|
||||
[quo/text {:style {:margin-horizontal 24}
|
||||
:align :center
|
||||
:color :negative}
|
||||
(i18n/label :t/delete-profile-warning)]
|
||||
(if keycard?
|
||||
[keycard-pin]
|
||||
[quo/text-input
|
||||
{:style {:margin-horizontal 36
|
||||
:margin-top 36}
|
||||
:show-cancel false
|
||||
:secure-text-entry true
|
||||
:return-key-type :next
|
||||
:on-submit-editing nil
|
||||
:auto-focus true
|
||||
:on-change-text #(reset! password (security/mask-data %))
|
||||
:bottom-value 36
|
||||
:get-ref #(reset! text-input-ref %)
|
||||
:error (when (and error (not @password))
|
||||
(if (= :wrong-password error)
|
||||
(i18n/label :t/wrong-password)
|
||||
(str error)))}])]
|
||||
(when-not keycard?
|
||||
[react/view {:style {:align-items :center}}
|
||||
[quo/separator]
|
||||
[react/view
|
||||
{:style {:margin-vertical 8}}
|
||||
[quo/button {:on-press #(do
|
||||
(re-frame/dispatch
|
||||
[::delete-profile/delete-profile @password])
|
||||
(reset! password nil))
|
||||
:theme :negative
|
||||
:disabled ((complement valid-password?) @password)}
|
||||
(i18n/label :t/delete-profile)]]])]]))))
|
@ -0,0 +1,67 @@
|
||||
(ns status-im.ui.screens.privacy-and-security-settings.events
|
||||
(:require [status-im.utils.fx :as fx]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.utils.security :as security]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.utils.types :as types]
|
||||
[taoensso.timbre :as log]
|
||||
[clojure.string :as clojure.string]
|
||||
[status-im.i18n :as i18n]))
|
||||
|
||||
(defn safe-blank? [s]
|
||||
(or (not s)
|
||||
(clojure.string/blank? s)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::delete-profile
|
||||
(fn [{:keys [address key-uid callback masked-password]}]
|
||||
(let [hashed-password
|
||||
(-> masked-password
|
||||
security/safe-unmask-data
|
||||
ethereum/sha3)]
|
||||
(status/verify
|
||||
address
|
||||
hashed-password
|
||||
(fn [result]
|
||||
(let [{:keys [error]} (types/json->clj result)]
|
||||
(log/info "[delete-profile] verify-password" result error)
|
||||
(if-not (safe-blank? error)
|
||||
(callback :wrong-password nil)
|
||||
(status/delete-multiaccount
|
||||
key-uid
|
||||
(fn [result]
|
||||
(let [{:keys [error]} (types/json->clj result)]
|
||||
(callback error nil)))))))))))
|
||||
|
||||
(fx/defn delete-profile
|
||||
{:events [::delete-profile]}
|
||||
[{:keys [db] :as cofx} masked-password]
|
||||
(log/info "[delete-profile] delete")
|
||||
(let [{:keys [key-uid wallet-root-address]} (:multiaccount db)]
|
||||
{:db (dissoc db :delete-profile/error)
|
||||
::delete-profile
|
||||
{:masked-password masked-password
|
||||
:key-uid key-uid
|
||||
:address wallet-root-address
|
||||
:callback
|
||||
(fn [error result]
|
||||
(log/info "[delete-profile] callback" error)
|
||||
(if (safe-blank? error)
|
||||
(re-frame/dispatch [::on-delete-profile-success result])
|
||||
(re-frame/dispatch [::on-delete-profile-failure error])))}}))
|
||||
|
||||
(fx/defn on-delete-profile-success
|
||||
{:events [::on-delete-profile-success]}
|
||||
[cofx]
|
||||
(log/info "[delete-profile] on-success")
|
||||
{:utils/show-popup
|
||||
{:title (i18n/label :t/profile-deleted-title)
|
||||
:content (i18n/label :t/profile-deleted-content)
|
||||
:on-dismiss #(re-frame/dispatch [:logout])}})
|
||||
|
||||
(fx/defn on-delete-profile-failure
|
||||
{:events [::on-delete-profile-failure]}
|
||||
[{:keys [db]} error]
|
||||
(log/info "[delete-profile] on-failure" error)
|
||||
{:db (assoc db :delete-profile/error error)})
|
@ -10,10 +10,14 @@
|
||||
[status-im.utils.platform :as platform])
|
||||
(:require-macros [status-im.utils.views :as views]))
|
||||
|
||||
(defn separator []
|
||||
[quo/separator {:style {:margin-vertical 8}}])
|
||||
|
||||
(views/defview privacy-and-security []
|
||||
(views/letsubs [{:keys [mnemonic preview-privacy?]} [:multiaccount]
|
||||
supported-biometric-auth [:supported-biometric-auth]
|
||||
auth-method [:auth-method]]
|
||||
auth-method [:auth-method]
|
||||
keycard? [:keycard-multiaccount?]]
|
||||
[react/view {:flex 1 :background-color colors/white}
|
||||
[topbar/topbar {:title :t/privacy-and-security}]
|
||||
[react/scroll-view {:padding-vertical 8}
|
||||
@ -34,9 +38,7 @@
|
||||
:accessory :switch
|
||||
:on-press #(re-frame/dispatch [:multiaccounts.ui/biometric-auth-switched
|
||||
((complement boolean) (= auth-method "biometric"))])}])
|
||||
[react/view {:margin-vertical 8
|
||||
:background-color colors/gray-lighter
|
||||
:height 1}]
|
||||
[separator]
|
||||
;; TODO - uncomment when implemented
|
||||
;; {:size :small
|
||||
;; :title (i18n/label :t/change-password)
|
||||
@ -61,9 +63,14 @@
|
||||
:on-press #(re-frame/dispatch
|
||||
[:multiaccounts.ui/preview-privacy-mode-switched
|
||||
((complement boolean) preview-privacy?)])}]
|
||||
|
||||
(comment
|
||||
{:container-margin-top 8
|
||||
:size :small
|
||||
:title :t/delete-my-account
|
||||
:theme :negative})]]))
|
||||
;; TODO(rasom): remove this condition when kk support will be added
|
||||
(when-not keycard?
|
||||
[separator])
|
||||
(when-not keycard?
|
||||
[quo/list-item
|
||||
{:size :small
|
||||
:theme :negative
|
||||
:title (i18n/label :t/delete-my-profile)
|
||||
:on-press #(re-frame/dispatch [:navigate-to :delete-profile])
|
||||
:accessibility-label :dapps-permissions-button
|
||||
:chevron true}])]]))
|
||||
|
@ -37,7 +37,8 @@
|
||||
[status-im.ui.screens.keycard.settings.views :as keycard.settings]
|
||||
[status-im.ui.components.tabbar.styles :as tabbar.styles]
|
||||
[status-im.ui.screens.routing.core :as navigation]
|
||||
[status-im.ui.screens.appearance.views :as appearance]))
|
||||
[status-im.ui.screens.appearance.views :as appearance]
|
||||
[status-im.ui.screens.privacy-and-security-settings.delete-profile :as delete-profile]))
|
||||
|
||||
(defonce stack (navigation/create-stack))
|
||||
|
||||
@ -115,6 +116,10 @@
|
||||
:component profile.seed/backup-seed}
|
||||
{:name :tribute-to-talk
|
||||
:component tr-to-talk/tribute-to-talk}
|
||||
{:name :delete-profile
|
||||
:transition :presentation-ios
|
||||
:insets {:bottom true}
|
||||
:component delete-profile/delete-profile}
|
||||
;; {:name:my-profile-ext-settings
|
||||
;; :component}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
"_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh <tag>' instead",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v0.55.1",
|
||||
"commit-sha1": "6d5a93287b2c1b4d4d5d1178a3ecec870bf18b9e",
|
||||
"src-sha256": "1wly0km9bxxv1wwj6jchqh4d4x2m86fxrdqixjzldy70vl6qbyqa"
|
||||
"version": "v0.55.2",
|
||||
"commit-sha1": "0b3cdf7362bbdf9ba7fc11da803105f9417dfbac",
|
||||
"src-sha256": "1vq3z150p0fbwjc1mqmi8lz4vg28dzqhlpsn7kar8j5z4rx5z5hn"
|
||||
}
|
||||
|
@ -311,6 +311,11 @@
|
||||
"delete-network-confirmation": "Are you sure you want to delete this network?",
|
||||
"delete-network-error": "Please connect to a different network before deleting this one",
|
||||
"delete-network-title": "Delete network?",
|
||||
"delete-profile": "Delete profile",
|
||||
"delete-my-profile": "Delete my profile",
|
||||
"delete-profile-warning": "Warning: If you don’t have your seed phrase written down, you will loose access to your funds after you delete your profile",
|
||||
"profile-deleted-title": "Profile deleted",
|
||||
"profile-deleted-content": "Your profile was successfully deleted",
|
||||
"deny": "Deny",
|
||||
"description": "Description",
|
||||
"dev-mode": "Development mode",
|
||||
|
Loading…
x
Reference in New Issue
Block a user