From 76ef3eee4d0004f55de382e565d56ac6295994c1 Mon Sep 17 00:00:00 2001 From: Niko PLP Date: Tue, 13 Aug 2024 17:36:47 +0300 Subject: [PATCH] download recovery PDF --- Cargo.lock | 1 + nextgraph/examples/in_memory.rs | 2 + nextgraph/examples/persistent.rs | 2 + nextgraph/src/local_broker.rs | 14 +++++- ng-app/src-tauri/Cargo.toml | 1 + ng-app/src-tauri/src/lib.rs | 16 +++++++ ng-app/src/App.svelte | 2 +- ng-app/src/lib/Login.svelte | 2 +- ng-app/src/locales/en.json | 3 ++ ng-app/src/routes/WalletCreate.svelte | 69 +++++++++++++++++++++++---- ng-sdk-js/src/lib.rs | 8 ++-- ng-wallet/src/lib.rs | 4 ++ ng-wallet/src/types.rs | 21 +++++++- 13 files changed, 130 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 232990f..3f42fa1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3323,6 +3323,7 @@ dependencies = [ "tauri-plugin-barcode-scanner", "tauri-plugin-window", "tauri-utils", + "zeroize", ] [[package]] diff --git a/nextgraph/examples/in_memory.rs b/nextgraph/examples/in_memory.rs index 558a668..24e27f9 100644 --- a/nextgraph/examples/in_memory.rs +++ b/nextgraph/examples/in_memory.rs @@ -55,6 +55,8 @@ async fn main() -> std::io::Result<()> { core_bootstrap: BootstrapContentV0::new_localhost(peer_id_of_server_broker), core_registration: None, additional_bootstrap: None, + pdf: false, + device_name: "test".to_string(), }) .await?; diff --git a/nextgraph/examples/persistent.rs b/nextgraph/examples/persistent.rs index 1ff38cf..f1e78c7 100644 --- a/nextgraph/examples/persistent.rs +++ b/nextgraph/examples/persistent.rs @@ -63,6 +63,8 @@ async fn main() -> std::io::Result<()> { core_bootstrap: BootstrapContentV0::new_localhost(peer_id_of_server_broker), core_registration: None, additional_bootstrap: None, + pdf: false, + device_name: "test".to_string(), }) .await?; diff --git a/nextgraph/src/local_broker.rs b/nextgraph/src/local_broker.rs index 80b4f21..19dfd7b 100644 --- a/nextgraph/src/local_broker.rs +++ b/nextgraph/src/local_broker.rs @@ -1570,10 +1570,20 @@ pub async fn wallet_create_v0(params: CreateWalletV0) -> Result { - //console.log(event.data.cmd, event.data); + // console.log(event.data.cmd, event.data); if (!location.href.startsWith(event.origin)) return; switch (event.data.cmd) { case "startup": diff --git a/ng-app/src/lib/Login.svelte b/ng-app/src/lib/Login.svelte index dcbb460..0e8bdcb 100644 --- a/ng-app/src/lib/Login.svelte +++ b/ng-app/src/lib/Login.svelte @@ -411,7 +411,7 @@
- {#if for_import} + {#if for_import && trusted} diff --git a/ng-app/src/locales/en.json b/ng-app/src/locales/en.json index e47c572..7959fb6 100644 --- a/ng-app/src/locales/en.json +++ b/ng-app/src/locales/en.json @@ -468,6 +468,9 @@ "download_wallet_description": "Please download your wallet and keep it in a safe location", "download_wallet": "Download my wallet", "download_wallet_done": "Your wallet file has been downloaded into your \"Downloads\" folder, with the name
{download_name}
Please move it to a safe and durable place.
", + "download_pdf_description": "Please download your Recovery PDF, print it, and delete it.", + "download_pdf": "Download my PDF", + "download_pdf_done": "Your Recovery PDF file has been downloaded into your \"Downloads\" folder, with the name
{pdf_name}
Please print it and then delete it.
", "your_pazzle": "Here below is your Pazzle.
The order of each image is important!", "your_mnemonic": "And here is your mnemonic (your alternative passphrase):", "unlock_tips_1": "You can use both the pazzle or the mnemonic to unlock your wallet. The pazzle is easier to remember. The mnemonic is useful in some special cases. We recommend that you use the pazzle. Copy both on a piece of paper. You should try to memorize the pazzle. Once you did, you won't need the paper anymore.", diff --git a/ng-app/src/routes/WalletCreate.svelte b/ng-app/src/routes/WalletCreate.svelte index 2953f3d..ba6eeb3 100644 --- a/ng-app/src/routes/WalletCreate.svelte +++ b/ng-app/src/routes/WalletCreate.svelte @@ -128,8 +128,11 @@ let ready; let download_link; let download_name; + let pdf_link; + let pdf_name; let cloud_link; let animateDownload = true; + let animatePdf = true; let invitation; let pre_invitation; @@ -228,7 +231,7 @@ trusted: true, cloud: false, bootstrap: false, - pdf: false, + pdf: !mobile, }; await tick(); scrollToTop(); @@ -257,7 +260,8 @@ core_bootstrap: invitation.V0.bootstrap, core_registration, additional_bootstrap, - //TODO: device_name, + device_name, + pdf: options.pdf }; //console.log("do wallet with params", params); try { @@ -275,11 +279,12 @@ window.wallet_channel.postMessage(new_in_mem, location.href); } } - console.log("pazzle", ready.pazzle); - console.log("pazzle words", display_pazzle(ready.pazzle)); - console.log("mnemonic", ready.mnemonic); - console.log("mnemonic words", ready.mnemonic_str); + // console.log("pazzle", ready.pazzle); + // console.log("pazzle words", display_pazzle(ready.pazzle)); + // console.log("mnemonic", ready.mnemonic); + // console.log("mnemonic words", ready.mnemonic_str); download_name = "wallet-" + ready.wallet_name + ".ngw"; + pdf_name = "wallet-" + ready.wallet_name + ".pdf"; if (options.cloud) { cloud_link = "https://nextgraph.one/#/w/" + ready.wallet_name; } @@ -289,6 +294,12 @@ }); download_link = URL.createObjectURL(blob); } + if (ready.pdf_file.length) { + const blob = new Blob([ready.pdf_file], { + type: "application/octet-stream", + }); + pdf_link = URL.createObjectURL(blob); + } } catch (e) { console.error(e); error = e; @@ -1518,7 +1529,7 @@ {#if !tauri_platform}{@html $t( "pages.login.trust_device_allow_cookies" )}{/if}

- {if (!options.trusted) options.pdf=false;}} >{@html $t( "pages.wallet_create.save_wallet_options.trust_toggle" )}
- {@html $t( "pages.wallet_create.save_wallet_options.pdf_toggle" )} + + + + +
+ {:else if options.pdf} + {@html $t("pages.wallet_create.download_pdf_done", { + values: { pdf_name }, + })} + {/if} {@html $t("pages.wallet_create.your_pazzle")}
@@ -1854,6 +1906,7 @@ creating = false; error = undefined; animateDownload = true; + animatePdf = true; }} > {$t("buttons.start_over")} diff --git a/ng-sdk-js/src/lib.rs b/ng-sdk-js/src/lib.rs index b0e39fc..a8759f5 100644 --- a/ng-sdk-js/src/lib.rs +++ b/ng-sdk-js/src/lib.rs @@ -566,9 +566,11 @@ pub async fn add_in_memory_wallet(lws_js: JsValue) -> Result<(), String> { if !lws.in_memory { return Err("This is not an in memory wallet".to_string()); } - nextgraph::local_broker::wallet_add(lws) - .await - .map_err(|e: NgError| e.to_string()) + match nextgraph::local_broker::wallet_add(lws).await { + Ok(_) => Ok(()), + Err(NgError::WalletAlreadyAdded) => Ok(()), + Err(e) => Err(e.to_string()), + } } #[cfg(not(wasmpack_target = "nodejs"))] diff --git a/ng-wallet/src/lib.rs b/ng-wallet/src/lib.rs index bd60573..2f25d11 100644 --- a/ng-wallet/src/lib.rs +++ b/ng-wallet/src/lib.rs @@ -548,6 +548,7 @@ pub fn create_wallet_first_step_v0( core_bootstrap: params.core_bootstrap.clone(), core_registration: params.core_registration, additional_bootstrap: params.additional_bootstrap.clone(), + pdf: params.pdf, }; Ok(intermediary) } @@ -773,6 +774,7 @@ pub async fn create_wallet_second_step_v0( user, in_memory: params.in_memory, session_id: 0, + pdf_file: vec![], }, site, brokers, @@ -832,6 +834,8 @@ mod test { BootstrapContentV0::new_localhost(PubKey::nil()), None, None, + false, + "test".to_string(), )) .expect("create_wallet_first_step_v0"); diff --git a/ng-wallet/src/types.rs b/ng-wallet/src/types.rs index 90d38ee..f18a89d 100644 --- a/ng-wallet/src/types.rs +++ b/ng-wallet/src/types.rs @@ -1248,6 +1248,14 @@ pub struct CreateWalletV0 { #[zeroize(skip)] /// Bootstrap of another server that you might use in order to connect to NextGraph network. It can be another interface on the same `core` server. pub additional_bootstrap: Option, + + #[zeroize(skip)] + /// Should generate a recovery PDF containing all the information of the wallet in plain text. + pub pdf: bool, + + #[zeroize(skip)] + /// short name of the device + pub device_name: String, } impl CreateWalletV0 { @@ -1261,6 +1269,8 @@ impl CreateWalletV0 { core_bootstrap: BootstrapContentV0, core_registration: Option<[u8; 32]>, additional_bootstrap: Option, + pdf: bool, + device_name: String, ) -> Self { CreateWalletV0 { result_with_wallet_file: false, @@ -1274,6 +1284,8 @@ impl CreateWalletV0 { core_bootstrap, core_registration, additional_bootstrap, + pdf, + device_name, } } } @@ -1324,6 +1336,10 @@ pub struct CreateWalletResultV0 { pub in_memory: bool, pub session_id: u64, + + #[serde(with = "serde_bytes")] + /// The PDF file that can be printed by the user + pub pdf_file: Vec, } impl CreateWalletResultV0 { @@ -1369,6 +1385,8 @@ pub struct CreateWalletIntermediaryV0 { pub core_registration: Option<[u8; 32]>, #[zeroize(skip)] pub additional_bootstrap: Option, + #[zeroize(skip)] + pub pdf: bool, } #[derive(Debug, Eq, PartialEq, Clone)] @@ -1441,8 +1459,9 @@ pub struct NgQRCodeWalletTransferV0 { pub is_rendezvous: bool, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop, Serialize, Deserialize)] pub struct NgQRCodeWalletRecoveryV0 { + #[zeroize(skip)] pub wallet: WalletContentV0, //of which security_img is emptied pub pazzle: Vec, pub mnemonic: [u16; 12],