From 91115fdea86524d309d465936bb635a5457e0bc8 Mon Sep 17 00:00:00 2001 From: Niko PLP Date: Tue, 5 Sep 2023 22:56:55 +0300 Subject: [PATCH] import wallet file --- Cargo.lock | 3 +- Cargo.toml | 6 +- ng-app/src-tauri/Cargo.toml | 4 +- ng-app/src-tauri/src/lib.rs | 104 +++++++++++++++++++++++---- ng-app/src/api.ts | 10 +++ ng-app/src/lib/Login.svelte | 30 ++++---- ng-app/src/routes/WalletLogin.svelte | 84 ++++++++++++++++++++-- ng-sdk-js/src/lib.rs | 68 ++++++++++++++++++ ng-wallet/src/lib.rs | 94 +++++++++++++++++++++--- ng-wallet/src/types.rs | 101 +++++++++++++++++++------- p2p-repo/src/errors.rs | 1 + 11 files changed, 435 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d6ab9b..2a26c42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5175,7 +5175,8 @@ dependencies = [ [[package]] name = "tauri-plugin-window" version = "2.0.0-alpha.1" -source = "git+https://git.nextgraph.org/NextGraph/plugins-workspace.git?branch=window-alpha.1-nextgraph#0beae8162f66bcb8a1ec902738507f7ebe6b8a5e" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06f3c1d40ae1a1b2b837e7f9b8db80aa2ee8c4594f63d729d2abd69f0741225a" dependencies = [ "serde", "tauri", diff --git a/Cargo.toml b/Cargo.toml index 7cc0513..775ff15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,4 +18,8 @@ members = [ [profile.release] lto = true -opt-level = 's' \ No newline at end of file +opt-level = 's' + +[patch.crates-io] +# tauri = { git = "https://github.com/simonhyll/tauri.git", branch="fix/ipc-mixup"} +tauri = { git = "https://git.nextgraph.org/NextGraph/tauri.git", branch="alpha.11-nextgraph", features = ["no-ipc-custom-protocol"] } \ No newline at end of file diff --git a/ng-app/src-tauri/Cargo.toml b/ng-app/src-tauri/Cargo.toml index 18aeaed..039495e 100644 --- a/ng-app/src-tauri/Cargo.toml +++ b/ng-app/src-tauri/Cargo.toml @@ -21,13 +21,15 @@ tauri-build = { version = "2.0.0-alpha.6", features = [] } [dependencies] tauri = { git = "https://git.nextgraph.org/NextGraph/tauri.git", branch="alpha.11-nextgraph", features = ["no-ipc-custom-protocol"] } +# tauri = { git = "https://github.com/simonhyll/tauri.git", branch="fix/ipc-mixup", features = [] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" p2p-repo = { path = "../../p2p-repo" } p2p-net = { path = "../../p2p-net" } ng-wallet = { path = "../../ng-wallet" } async-std = { version = "1.12.0", features = ["attributes", "unstable"] } -tauri-plugin-window = { git = "https://git.nextgraph.org/NextGraph/plugins-workspace.git", branch="window-alpha.1-nextgraph" } +# tauri-plugin-window = { git = "https://git.nextgraph.org/NextGraph/plugins-workspace.git", branch="window-alpha.1-nextgraph" } +tauri-plugin-window = "2.0.0-alpha.1" [features] # this feature is used for production builds or when `devPath` points to the filesystem diff --git a/ng-app/src-tauri/src/lib.rs b/ng-app/src-tauri/src/lib.rs index bb9b160..458acc8 100644 --- a/ng-app/src-tauri/src/lib.rs +++ b/ng-app/src-tauri/src/lib.rs @@ -12,6 +12,7 @@ use ng_wallet::*; use p2p_net::broker::*; use p2p_net::types::{CreateAccountBSP, Invitation}; use p2p_net::utils::{decode_invitation_string, spawn_and_log_error, Receiver, ResultSend}; +use p2p_repo::errors::NgError; use p2p_repo::log::*; use p2p_repo::types::*; use std::collections::HashMap; @@ -115,21 +116,92 @@ async fn save_wallet_locally( .path() .resolve("wallets", BaseDirectory::AppLocalData) .map_err(|_| ())?; - let sws = save_new_session(&res.wallet_name, res.wallet.id(), res.user, app.clone())?; - let mut wallets: HashMap = get_wallets_from_localstorage(app) - .await - .unwrap_or(Some(HashMap::new())) - .unwrap_or(HashMap::new()); - // TODO: check that the wallet is not already present in localStorage - let lws: LocalWalletStorageV0 = res.into(); - wallets.insert(res.wallet_name.clone(), lws); - let lws_ser = LocalWalletStorage::v0_to_vec(wallets); - let r = write(path.clone(), &lws_ser); - if r.is_err() { - log_debug!("write {:?} {}", path, r.unwrap_err()); - return Err(()); + let mut wallets: HashMap = + get_wallets_from_localstorage(app.clone()) + .await + .unwrap_or(Some(HashMap::new())) + .unwrap_or(HashMap::new()); + // check that the wallet is not already present in localStorage + if wallets.get(&res.wallet_name).is_none() { + let lws: LocalWalletStorageV0 = res.into(); + wallets.insert(res.wallet_name.clone(), lws); + let lws_ser = LocalWalletStorage::v0_to_vec(wallets); + let r = write(path.clone(), &lws_ser); + if r.is_err() { + log_debug!("write {:?} {}", path, r.unwrap_err()); + return Err(()); + } + let sws = save_new_session(&res.wallet_name, res.wallet.id(), res.user, app)?; + Ok(sws) + } else { + Err(()) + } +} + +#[tauri::command(rename_all = "snake_case")] +async fn wallet_open_file(file: Vec, app: tauri::AppHandle) -> Result { + let ngf: NgFile = file.try_into().map_err(|e: NgError| e.to_string())?; + if let NgFile::V0(NgFileV0::Wallet(wallet)) = ngf { + let mut wallets: HashMap = + get_wallets_from_localstorage(app.clone()) + .await + .unwrap_or(Some(HashMap::new())) + .unwrap_or(HashMap::new()); + // check that the wallet is not already present in localStorage + let wallet_name = wallet.name(); + if wallets.get(&wallet_name).is_none() { + Ok(wallet) + } else { + Err("Wallet already present on this device".to_string()) + } + } else { + Err("File does not contain a wallet".to_string()) + } +} + +#[tauri::command(rename_all = "snake_case")] +async fn wallet_import( + previous_wallet: Wallet, + opened_wallet: EncryptedWallet, + app: tauri::AppHandle, +) -> Result<(), String> { + let path = app + .path() + .resolve("wallets", BaseDirectory::AppLocalData) + .map_err(|_| "wallet directory error".to_string())?; + let mut wallets: HashMap = + get_wallets_from_localstorage(app.clone()) + .await + .unwrap_or(Some(HashMap::new())) + .unwrap_or(HashMap::new()); + // check that the wallet is not already present in localStorage + let EncryptedWallet::V0(mut opened_wallet_v0) = opened_wallet; + let wallet_name = opened_wallet_v0.wallet_id.clone(); + if wallets.get(&wallet_name).is_none() { + let session = save_new_session( + &wallet_name, + opened_wallet_v0.wallet_privkey.to_pub(), + opened_wallet_v0.personal_site, + app, + ) + .map_err(|_| "Cannot create new session".to_string())?; + let (wallet, client) = opened_wallet_v0 + .import(previous_wallet, session) + .map_err(|e| e.to_string())?; + let lws = LocalWalletStorageV0::new(wallet, client); + + wallets.insert(wallet_name, lws); + let lws_ser = LocalWalletStorage::v0_to_vec(wallets); + let r = write(path.clone(), &lws_ser); + if r.is_err() { + log_debug!("write {:?} {}", path, r.unwrap_err()); + Err("Write error".to_string()) + } else { + Ok(()) + } + } else { + Err("Already present on this device".to_string()) } - Ok(sws) } #[tauri::command(rename_all = "snake_case")] @@ -161,7 +233,7 @@ fn save_new_session( .map_err(|_| ())?; let session_v0 = create_new_session(wallet_id, user); if session_v0.is_err() { - log_debug!("create_new_session {}", session_v0.unwrap_err()); + log_debug!("create_new_session failed {}", session_v0.unwrap_err()); return Err(()); } let sws = session_v0.unwrap(); @@ -356,6 +428,8 @@ impl AppBuilder { wallet_gen_shuffle_for_pin, wallet_open_wallet_with_pazzle, wallet_create_wallet, + wallet_open_file, + wallet_import, encode_create_account, get_local_session, get_wallets_from_localstorage, diff --git a/ng-app/src/api.ts b/ng-app/src/api.ts index d171b4f..365ada3 100644 --- a/ng-app/src/api.ts +++ b/ng-app/src/api.ts @@ -18,6 +18,8 @@ const mapping = { "wallet_gen_shuffle_for_pin": [], "wallet_open_wallet_with_pazzle": ["wallet","pazzle","pin"], "wallet_create_wallet": ["params"], + "wallet_open_file": ["file"], + "wallet_import": ["previous_wallet","opened_wallet"], "encode_create_account": ["payload"], "get_local_session": ["id","key","user"], "get_wallets_from_localstorage": [], @@ -122,6 +124,14 @@ const handler = { params.result_with_wallet_file = false; params.security_img = Array.from(new Uint8Array(params.security_img)); return await tauri.invoke(path[0],{params}) + } else if (path[0] === "wallet_open_file") { + let file = args[0]; + file = Array.from(new Uint8Array(file)); + return await tauri.invoke(path[0],{file}) + } else if (path[0] === "wallet_import") { + let previous_wallet = args[0]; + previous_wallet.V0.content.security_img = Array.from(new Uint8Array(previous_wallet.V0.content.security_img)); + return await tauri.invoke(path[0],{previous_wallet, opened_wallet:args[1]}) } else if (path[0] && path[0].startsWith("get_local_bootstrap")) { return false; } else if (path[0] === "get_local_url") { diff --git a/ng-app/src/lib/Login.svelte b/ng-app/src/lib/Login.svelte index b0d320a..1d2296c 100644 --- a/ng-app/src/lib/Login.svelte +++ b/ng-app/src/lib/Login.svelte @@ -23,7 +23,7 @@ onMount(async () => { await load_svg(); - console.log(wallet); + //console.log(wallet); await init(); }); @@ -81,10 +81,10 @@ async function start_pin() { pin_code = []; - console.log(ordered); + //console.log(ordered); shuffle_pin = await ng.wallet_gen_shuffle_for_pin(); step = "pin"; - console.log(shuffle_pin); + //console.log(shuffle_pin); } function select(val) { @@ -92,10 +92,10 @@ let cat_idx = shuffle.category_indices[display]; let cat = emojis[emoji_cat[cat_idx]]; let idx = shuffle.emoji_indices[display][val]; - console.log(cat_idx, emoji_cat[cat_idx], idx, cat[idx].code); + //console.log(cat_idx, emoji_cat[cat_idx], idx, cat[idx].code); selection.push({ cat: cat_idx, index: idx }); - console.log(selection); + //console.log(selection); if (display == pazzle_length - 1) { order(); @@ -113,8 +113,8 @@ pazzle.push((emoji.cat << 4) + emoji.index); } - console.log(pazzle); - console.log(wallet); + //console.log(pazzle); + //console.log(wallet); // open the wallet try { @@ -143,7 +143,7 @@ } async function pin(val) { - console.log(val); + //console.log(val); pin_code.push(val); if (pin_code.length == 4) { await finish(); @@ -152,8 +152,8 @@ async function select_order(val, pos) { delete last_one[pos]; - console.log(last_one); - console.log(val); + //console.log(last_one); + //console.log(val); ordered.push(val); val.sel = ordered.length; selection = selection; @@ -162,7 +162,7 @@ ordered.push(last); last.sel = ordered.length; selection = selection; - console.log(last); + //console.log(last); await start_pin(); } } @@ -195,7 +195,9 @@ {:else if step == "pazzle"}
@@ -218,7 +220,9 @@ {:else if step == "order"}
diff --git a/ng-app/src/routes/WalletLogin.svelte b/ng-app/src/routes/WalletLogin.svelte index 81f58e5..5f07b7d 100644 --- a/ng-app/src/routes/WalletLogin.svelte +++ b/ng-app/src/routes/WalletLogin.svelte @@ -14,6 +14,7 @@ import { link, push } from "svelte-spa-router"; import Login from "../lib/Login.svelte"; import ng from "../api"; + import { Fileupload } from "flowbite-svelte"; // @ts-ignore import Logo from "../assets/nextgraph.svg?component"; import { @@ -27,6 +28,8 @@ let wallet; let selected; let step; + let error; + let importing = false; let wallets_unsub; let opened_wallets_unsub; @@ -59,7 +62,7 @@ value.wallet.V0.wallet_privkey, value.wallet.V0.personal_site ); - console.log(session); + //console.log(session); if (session) { set_active_session(session); loggedin(); @@ -80,15 +83,29 @@ if (active_wallet_unsub) active_wallet_unsub(); }); async function gotError(event) { + importing = false; console.error(event.detail); } async function gotWallet(event) { - console.log(event.detail); + //console.log(event.detail); + if (importing) { + try { + await ng.wallet_import(wallet, event.detail.wallet); + let walls = await ng.get_wallets_from_localstorage(); + wallets.set(walls); + } catch (e) { + importing = false; + wallet = undefined; + error = e; + return; + } + } active_wallet.set(event.detail); // wallet // id } function cancelLogin(event) { + importing = false; selected = undefined; wallet = undefined; } @@ -100,9 +117,57 @@ wallet = $wallets[selected]?.wallet; } } + function handleWalletUpload(event) { + const files = event.target.files; + if (files.length > 0) { + let reader = new FileReader(); + reader.readAsArrayBuffer(files[0]); + reader.onload = async (e) => { + try { + //console.log(e.target.result); + wallet = await ng.wallet_open_file(e.target.result); + importing = true; + } catch (e) { + error = e; + } + }; + } + } -{#if wallet} +{#if error} +
+ + +

+ An error occurred:
{error} +

+ +
+{:else if wallet} Log in with another wallet

{:else}

Import your wallet

{/if} +
-{:else if step == "security"}{:else if step == "qrcode"}{:else if step == "drop"}{:else if step == "cloud"}{:else if step == "loggedin"}you +{:else if step == "security"}{:else if step == "qrcode"}{:else if step == "cloud"}{:else if step == "loggedin"}you are logged in{/if}