From 8420c18ca3bfd4d3df42760fccf621d75a433463 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 232990ff..3f42fa14 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 558a6689..24e27f91 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 1ff38cf9..f1e78c79 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 80b4f217..19dfd7b8 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 dcbb4605..0e8bdcb8 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 e47c572d..7959fb6e 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 2953f3df..ba6eeb3d 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 b0e39fcf..a8759f51 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 bd605736..2f25d11c 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 90d38ee9..f18a89d1 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],