Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#10195] Separate keystore dir per multiacc #10847

Merged
merged 1 commit into from
Jul 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ private String pathCombine(final String path1, final String path2) {
return file.getAbsolutePath();
}

private String prepareDirAndUpdateConfig(final String jsonConfigString) {
private String prepareDirAndUpdateConfig(final String jsonConfigString, final String keyUID) {

Activity currentActivity = getCurrentActivity();

Expand Down Expand Up @@ -303,7 +303,8 @@ private String prepareDirAndUpdateConfig(final String jsonConfigString) {
}

try {
final String updatedJsonConfigString = this.updateConfig(jsonConfigString, absRootDirPath, "/keystore");
final String multiaccountKeystoreDir = pathCombine("/keystore", keyUID);
final String updatedJsonConfigString = this.updateConfig(jsonConfigString, absRootDirPath, multiaccountKeystoreDir);

prettyPrintConfig(updatedJsonConfigString);

Expand All @@ -317,41 +318,55 @@ private String prepareDirAndUpdateConfig(final String jsonConfigString) {
}

@ReactMethod
public void prepareDirAndUpdateConfig(final String config, final Callback callback) {
public void prepareDirAndUpdateConfig(final String keyUID, final String config, final Callback callback) {
Log.d(TAG, "prepareDirAndUpdateConfig");
String finalConfig = prepareDirAndUpdateConfig(config);
String finalConfig = prepareDirAndUpdateConfig(config, keyUID);
callback.invoke(finalConfig);
}

@ReactMethod
public void saveAccountAndLogin(final String multiaccountData, final String password, final String settings, final String config, final String accountsData) {
Log.d(TAG, "saveAccountAndLogin");
String finalConfig = prepareDirAndUpdateConfig(config);
String result = Statusgo.saveAccountAndLogin(multiaccountData, password, settings, finalConfig, accountsData);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "saveAccountAndLogin result: " + result);
Log.d(TAG, "Geth node started");
} else {
Log.e(TAG, "saveAccountAndLogin failed: " + result);
try {
Log.d(TAG, "saveAccountAndLogin");
String finalConfig = prepareDirAndUpdateConfig(config, this.getKeyUID(multiaccountData));
String result = Statusgo.saveAccountAndLogin(multiaccountData, password, settings, finalConfig, accountsData);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "saveAccountAndLogin result: " + result);
Log.d(TAG, "Geth node started");
} else {
Log.e(TAG, "saveAccountAndLogin failed: " + result);
}
} catch (JSONException e) {
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
}
}

@ReactMethod
public void saveAccountAndLoginWithKeycard(final String multiaccountData, final String password, final String settings, final String config, final String accountsData, final String chatKey) {
Log.d(TAG, "saveAccountAndLoginWithKeycard");
String finalConfig = prepareDirAndUpdateConfig(config);
String result = Statusgo.saveAccountAndLoginWithKeycard(multiaccountData, password, settings, finalConfig, accountsData, chatKey);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "saveAccountAndLoginWithKeycard result: " + result);
Log.d(TAG, "Geth node started");
} else {
Log.e(TAG, "saveAccountAndLoginWithKeycard failed: " + result);
try {
Log.d(TAG, "saveAccountAndLoginWithKeycard");
String finalConfig = prepareDirAndUpdateConfig(config, this.getKeyUID(multiaccountData));
String result = Statusgo.saveAccountAndLoginWithKeycard(multiaccountData, password, settings, finalConfig, accountsData, chatKey);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "saveAccountAndLoginWithKeycard result: " + result);
Log.d(TAG, "Geth node started");
} else {
Log.e(TAG, "saveAccountAndLoginWithKeycard failed: " + result);
}
} catch (JSONException e) {
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
}
}

private String getKeyUID(final String json) throws JSONException {
final JSONObject jsonObj = new JSONObject(json);
return jsonObj.getString("key-uid");
}

@ReactMethod
public void login(final String accountData, final String password) {
Log.d(TAG, "login");
this.migrateKeyStoreDir(accountData, password);
String result = Statusgo.login(accountData, password);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "Login result: " + result);
Expand Down Expand Up @@ -416,23 +431,25 @@ private void copyDirectory(File sourceLocation, File targetLocation) throws IOEx
}

@ReactMethod
private void initKeystore() {
private void initKeystore(final String keyUID, final Callback callback) {
Log.d(TAG, "initKeystore");

Activity currentActivity = getCurrentActivity();

final String keydir = pathCombine(this.getNoBackupDirectory(), "/keystore");

if (!checkAvailability()) {
Log.e(TAG, "[initKeystore] Activity doesn't exist, cannot init keystore");
System.exit(0);
return;
}

final String commonKeydir = pathCombine(this.getNoBackupDirectory(), "/keystore");
final String keydir = pathCombine(commonKeydir, keyUID);

Runnable r = new Runnable() {
@Override
public void run() {
Statusgo.initKeystore(keydir);
callback.invoke(true);
}
};

Expand Down Expand Up @@ -487,9 +504,27 @@ public void run() {
StatusThreadPoolExecutor.getInstance().execute(r);
}

public void migrateKeyStoreDir(final String accountData, final String password) {
try {
final String commonKeydir = pathCombine(this.getNoBackupDirectory(), "/keystore");
final String keydir = pathCombine(commonKeydir, getKeyUID(accountData));
Log.d(TAG, "before migrateKeyStoreDir " + keydir);

File keydirFile = new File(keydir);
if(!keydirFile.exists() || keydirFile.list().length == 0) {
Log.d(TAG, "migrateKeyStoreDir");
Statusgo.migrateKeyStoreDir(accountData, password, commonKeydir, keydir);
Statusgo.initKeystore(keydir);
}
} catch (JSONException e) {
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
}
}

@ReactMethod
public void loginWithKeycard(final String accountData, final String password, final String chatKey) {
Log.d(TAG, "loginWithKeycard");
this.migrateKeyStoreDir(accountData, password);
String result = Statusgo.loginWithKeycard(accountData, password, chatKey);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "LoginWithKeycard result: " + result);
Expand Down
64 changes: 54 additions & 10 deletions modules/react-native-status/ios/RCTStatus/RCTStatus.m
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ - (void)handleSignal:(NSString *)signal
////////////////////////////////////////////////////////////////////
#pragma mark - InitKeystore method
//////////////////////////////////////////////////////////////////// StopNode
RCT_EXPORT_METHOD(initKeystore) {
RCT_EXPORT_METHOD(initKeystore:(NSString *)keyUID
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"initKeystore() method called");
#endif
Expand All @@ -119,12 +120,15 @@ - (void)handleSignal:(NSString *)signal
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];

NSURL *keystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSURL *commonKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSURL *keystoreDir = [commonKeystoreDir URLByAppendingPathComponent:keyUID];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^(void)
{
NSString *res = StatusgoInitKeystore(keystoreDir.path);
NSLog(@"InitKeyStore result %@", res);
callback(@[]);
});
}

Expand Down Expand Up @@ -306,8 +310,19 @@ - (void)handleSignal:(NSString *)signal
callback(@[result]);
}

-(NSString *) getKeyUID:(NSString *)jsonString {
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *json = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:nil];

return [json valueForKey:@"key-uid"];
}

//////////////////////////////////////////////////////////////////// prepareDirAndUpdateConfig
-(NSString *) prepareDirAndUpdateConfig:(NSString *)config {
-(NSString *) prepareDirAndUpdateConfig:(NSString *)config
withKeyUID:(NSString *)keyUID {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
NSURL *rootUrl =[[fileManager
Expand Down Expand Up @@ -354,7 +369,8 @@ -(NSString *) prepareDirAndUpdateConfig:(NSString *)config {
NSURL *absDataDirUrl = [NSURL fileURLWithPath:absDataDir];
NSURL *dataDirUrl = [NSURL fileURLWithPath:relativeDataDir];
NSURL *logUrl = [dataDirUrl URLByAppendingPathComponent:@"geth.log"];
[configJSON setValue:@"/keystore" forKey:@"KeyStoreDir"];
NSString *keystoreDir = [@"/keystore/" stringByAppendingString:keyUID];
[configJSON setValue:keystoreDir forKey:@"KeyStoreDir"];
[configJSON setValue:@"" forKey:@"LogDir"];
[configJSON setValue:logUrl.path forKey:@"LogFile"];

Expand All @@ -380,15 +396,15 @@ -(NSString *) prepareDirAndUpdateConfig:(NSString *)config {


//////////////////////////////////////////////////////////////////// prepareDirAndUpdateConfig
RCT_EXPORT_METHOD(prepareDirAndUpdateConfig:(NSString *)config
RCT_EXPORT_METHOD(prepareDirAndUpdateConfig:(NSString *)keyUID
config:(NSString *)config
callback:(RCTResponseSenderBlock)callback) {

#if DEBUG
NSLog(@"PrepareDirAndUpdateConfig() method called");
#endif
NSString *updatedConfig = [self prepareDirAndUpdateConfig:config];
NSString *updatedConfig = [self prepareDirAndUpdateConfig:config
withKeyUID:keyUID];
callback(@[updatedConfig]);

}

//////////////////////////////////////////////////////////////////// saveAccountAndLogin
Expand All @@ -400,7 +416,9 @@ -(NSString *) prepareDirAndUpdateConfig:(NSString *)config {
#if DEBUG
NSLog(@"SaveAccountAndLogin() method called");
#endif
NSString *finalConfig = [self prepareDirAndUpdateConfig:config];
NSString *keyUID = [self getKeyUID:multiaccountData];
NSString *finalConfig = [self prepareDirAndUpdateConfig:config
withKeyUID:keyUID];
NSString *result = StatusgoSaveAccountAndLogin(multiaccountData, password, settings, finalConfig, accountsData);
NSLog(@"%@", result);
}
Expand All @@ -415,17 +433,41 @@ -(NSString *) prepareDirAndUpdateConfig:(NSString *)config {
#if DEBUG
NSLog(@"SaveAccountAndLoginWithKeycard() method called");
#endif
NSString *finalConfig = [self prepareDirAndUpdateConfig:config];
NSString *keyUID = [self getKeyUID:multiaccountData];
NSString *finalConfig = [self prepareDirAndUpdateConfig:config
withKeyUID:keyUID];
NSString *result = StatusgoSaveAccountAndLoginWithKeycard(multiaccountData, password, settings, finalConfig, accountsData, chatKey);
NSLog(@"%@", result);
}

- (void) migrateKeystore:(NSString *)accountData
password:(NSString *)password {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];

NSString *keyUID = [self getKeyUID:accountData];
NSURL *oldKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSURL *multiaccountKeystoreDir = [oldKeystoreDir URLByAppendingPathComponent:keyUID];

NSArray *keys = [fileManager contentsOfDirectoryAtPath:multiaccountKeystoreDir.path error:nil];
if (keys.count == 0) {
NSString *migrationResult = StatusgoMigrateKeyStoreDir(accountData, password, oldKeystoreDir.path, multiaccountKeystoreDir.path);
NSLog(@"keystore migration result %@", migrationResult);

NSString *initKeystoreResult = StatusgoInitKeystore(multiaccountKeystoreDir.path);
NSLog(@"InitKeyStore result %@", initKeystoreResult);
}
}

//////////////////////////////////////////////////////////////////// login
RCT_EXPORT_METHOD(login:(NSString *)accountData
password:(NSString *)password) {
#if DEBUG
NSLog(@"Login() method called");
#endif
[self migrateKeystore:accountData password:password];
NSString *result = StatusgoLogin(accountData, password);
NSLog(@"%@", result);
}
Expand All @@ -437,6 +479,8 @@ -(NSString *) prepareDirAndUpdateConfig:(NSString *)config {
#if DEBUG
NSLog(@"LoginWithKeycard() method called");
#endif
[self migrateKeystore:accountData password:password];

NSString *result = StatusgoLoginWithKeycard(accountData, password, chatKey);

NSLog(@"%@", result);
Expand Down
3 changes: 2 additions & 1 deletion src/status_im/hardwallet/common.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,8 @@
:hardwallet/get-application-info {:pairing (get-pairing db key-uid)}
:hardwallet/login-with-keycard {:multiaccount-data multiaccount-data
:password encryption-public-key
:chat-key whisper-private-key}}
:chat-key whisper-private-key
:key-uid key-uid}}
(when save-keys?
(keychain/save-hardwallet-keys key-uid encryption-public-key whisper-private-key))
(clear-on-card-connected)
Expand Down
3 changes: 2 additions & 1 deletion src/status_im/hardwallet/real_keycard.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,9 @@
(catch on-failure))))

(defn save-multiaccount-and-login
[{:keys [multiaccount-data password settings node-config accounts-data chat-key]}]
[{:keys [key-uid multiaccount-data password settings node-config accounts-data chat-key]}]
(status/save-multiaccount-and-login-with-keycard
key-uid
(types/clj->json multiaccount-data)
password
(types/clj->json settings)
Expand Down
14 changes: 8 additions & 6 deletions src/status_im/hardwallet/simulated_keycard.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
(log/debug "[simulated kk] generate-and-load-key response" response)
(status/multiaccount-store-derived
id
key-uid
[constants/path-wallet-root
constants/path-eip1581
constants/path-whisper
Expand Down Expand Up @@ -197,9 +198,8 @@
path))

(defn export-key [{:keys [pin on-success on-failure]}]
(let [wallet-root-address (get-in
@re-frame.db/app-db
[:multiaccount :wallet-root-address])
(let [{:keys [key-uid wallet-root-address]}
(get @re-frame.db/app-db :multiaccount)
accounts (get @re-frame.db/app-db :multiaccount/accounts)
hashed-password (ethereum/sha3 pin)
path-num (inc (get-in @re-frame.db/app-db [:multiaccount :latest-derived-path]))
Expand All @@ -220,6 +220,7 @@
(re-frame/dispatch [::new-account-error :account-error (i18n/label :t/account-exists-title)])
(status/multiaccount-store-derived
id
key-uid
[path]
hashed-password
(fn [result]
Expand Down Expand Up @@ -293,16 +294,17 @@
(log/warn "sign-typed-data not implemented" args))

(defn save-multiaccount-and-login
[{:keys [multiaccount-data password settings node-config accounts-data]}]
[{:keys [key-uid multiaccount-data password settings node-config accounts-data]}]
(status/save-account-and-login
key-uid
(types/clj->json multiaccount-data)
password
(types/clj->json settings)
node-config
(types/clj->json accounts-data)))

(defn login [{:keys [multiaccount-data password]}]
(status/login multiaccount-data password))
(defn login [{:keys [key-uid multiaccount-data password]}]
(status/login key-uid multiaccount-data password))

(defn send-transaction-with-signature
[{:keys [transaction on-completed]}]
Expand Down
6 changes: 0 additions & 6 deletions src/status_im/init/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
(fx/merge cofx
{:get-supported-biometric-auth nil
::init-theme nil
::init-keystore nil
::open-multiaccounts #(re-frame/dispatch [::initialize-multiaccounts % {:logout? false}])
:ui/listen-to-window-dimensions-change nil
::network/listen-to-network-info nil
Expand All @@ -70,11 +69,6 @@
(fn [callback]
(status/open-accounts callback)))

(re-frame/reg-fx
::init-keystore
(fn []
(status/init-keystore)))

(re-frame/reg-fx
::init-theme
(fn []
Expand Down
Loading