finish recovery PDF and few fixes

pull/32/head
Niko PLP 4 months ago
parent 18101e4fae
commit 577fc40bb2
  1. 79
      nextgraph/src/local_broker.rs
  2. 2
      ng-app/src/classes.ts
  3. 22
      ng-app/src/routes/WalletCreate.svelte
  4. 15
      ng-wallet/src/emojis.rs
  5. 21
      ng-wallet/src/lib.rs

@ -44,8 +44,10 @@ use ng_verifier::types::*;
use ng_verifier::verifier::Verifier; use ng_verifier::verifier::Verifier;
use ng_wallet::bip39::encode_mnemonic; use ng_wallet::bip39::encode_mnemonic;
use ng_wallet::emojis::encode_pazzle; use ng_wallet::emojis::{display_pazzle, display_pazzle_one, encode_pazzle};
use ng_wallet::{create_wallet_first_step_v0, create_wallet_second_step_v0, types::*}; use ng_wallet::{
create_wallet_first_step_v0, create_wallet_second_step_v0, display_mnemonic, types::*,
};
#[cfg(not(target_family = "wasm"))] #[cfg(not(target_family = "wasm"))]
use ng_client_ws::remote_ws::ConnectionWebSocket; use ng_client_ws::remote_ws::ConnectionWebSocket;
@ -1582,10 +1584,10 @@ pub fn wallet_to_wallet_recovery(
/// Generates the Recovery PDF containing the Wallet, PIN, Pazzle and Mnemonic. /// Generates the Recovery PDF containing the Wallet, PIN, Pazzle and Mnemonic.
pub async fn wallet_recovery_pdf( pub async fn wallet_recovery_pdf(
content: NgQRCodeWalletRecoveryV0, recovery: NgQRCodeWalletRecoveryV0,
size: u32, size: u32,
) -> Result<Vec<u8>, NgError> { ) -> Result<Vec<u8>, NgError> {
let ser = serde_bare::to_vec(&content)?; let ser = serde_bare::to_vec(&recovery)?;
if ser.len() > 2_953 { if ser.len() > 2_953 {
return Err(NgError::InvalidPayload); return Err(NgError::InvalidPayload);
} }
@ -1607,20 +1609,7 @@ pub async fn wallet_recovery_pdf(
let tree = svg2pdf::usvg::Tree::from_str(&wallet_svg, &options) let tree = svg2pdf::usvg::Tree::from_str(&wallet_svg, &options)
.map_err(|e| NgError::WalletError(e.to_string()))?; .map_err(|e| NgError::WalletError(e.to_string()))?;
// PDF uses A4 format (21cm x 29.7cm)
// TODO: instead of to_pdf in the next line, do to_chunk, and then add the text below the SVG.
// the SVG should take all the width of the A4 (so that only 29.7-21 = 8cm remains below the SVG, for all the following)
// the text is :
// - one line with : "PIN = 1234 pazzle = cat_slug:emoji_slug cat_slug:emoji_slug ...[x9]"
// - one line with the 9 emoji SVGs (with size so they fit in one line, width of the A4)
// - one line with : "mnemonic = [12 words of mnemonic]"
// - one line with recovery_str (it is quite long. choose a font size that make it fit here so the whole document is only one page)
// you can use the methods of pdf_writer library.
let (chunk, qrcode_ref) = svg2pdf::to_chunk(&tree, ConversionOptions::default()); let (chunk, qrcode_ref) = svg2pdf::to_chunk(&tree, ConversionOptions::default());
// probably then: add the text with chunk.stream() or chunk.indirect()
//let pdf_buf = svg2pdf::to_pdf(&tree, ConversionOptions::default(), PageOptions::default()); //let pdf_buf = svg2pdf::to_pdf(&tree, ConversionOptions::default(), PageOptions::default());
// Define some indirect reference ids we'll use. // Define some indirect reference ids we'll use.
@ -1632,17 +1621,52 @@ pub async fn wallet_recovery_pdf(
let font_name = Name(b"F1"); let font_name = Name(b"F1");
let qrcode_name = Name(b"Im1"); let qrcode_name = Name(b"Im1");
let chunks = recovery_str
.as_bytes()
.chunks(92)
.map(|buf| buf)
.collect::<Vec<&[u8]>>();
let mut content = Content::new(); let mut content = Content::new();
content.begin_text();
content.set_font(font_name, 14.0); for (line, string) in chunks.iter().enumerate() {
content.next_line(108.0, 734.0); content.begin_text();
content.show(Str(b"Hello World from Rust!")); content.set_font(font_name, 10.0);
content.end_text(); content.next_line(20.0, 810.0 - line as f32 * 15.0);
content.begin_text(); content.show(Str(*string));
content.set_font(font_name, 14.0); content.end_text();
content.next_line(15.0, 810.0); }
content.show(Str(recovery_str.as_bytes()));
content.end_text(); let pazzle: Vec<String> = display_pazzle(&recovery.pazzle)
.iter()
.map(|p| p.1.to_string())
.collect();
let mnemonic = display_mnemonic(&recovery.mnemonic);
let credentials = format!(
"PIN:{}{}{}{} PAZZLE:{} MNEMONIC:{}",
recovery.pin[0],
recovery.pin[1],
recovery.pin[2],
recovery.pin[3],
pazzle.join(" "),
mnemonic.join(" ")
);
let chunks = credentials
.as_bytes()
.chunks(92)
.map(|buf| buf)
.collect::<Vec<&[u8]>>();
for (line, string) in chunks.iter().enumerate() {
content.begin_text();
content.set_font(font_name, 10.0);
content.next_line(20.0, 630.0 - line as f32 * 15.0);
content.show(Str(*string));
content.end_text();
}
content.save_state(); content.save_state();
content.transform([595.0, 0.0, 0.0, 595.0, 0.0, 0.0]); content.transform([595.0, 0.0, 0.0, 595.0, 0.0, 0.0]);
content.x_object(qrcode_name); content.x_object(qrcode_name);
@ -2924,7 +2948,6 @@ mod test {
let mnemonic = encode_mnemonic(&mnemonic_words).expect("encode_mnemonic"); let mnemonic = encode_mnemonic(&mnemonic_words).expect("encode_mnemonic");
let wallet_recovery = wallet_to_wallet_recovery(&wallet, pazzle, mnemonic, pin); let wallet_recovery = wallet_to_wallet_recovery(&wallet, pazzle, mnemonic, pin);
let pdf_buffer = wallet_recovery_pdf(wallet_recovery, 600) let pdf_buffer = wallet_recovery_pdf(wallet_recovery, 600)
.await .await
.expect("wallet_recovery_pdf"); .expect("wallet_recovery_pdf");

@ -16,7 +16,7 @@
// "media/image", "media/reel", "media/album", "media/video", "media/audio", "media/song", "media/subtitle", "media/overlay", // "media/image", "media/reel", "media/album", "media/video", "media/audio", "media/song", "media/subtitle", "media/overlay",
// "social/channel", "social/stream", "social/contact", "social/event", "social/calendar", "social/scheduler", "social/reaction" // "social/channel", "social/stream", "social/contact", "social/event", "social/calendar", "social/scheduler", "social/reaction"
// "prod/task", "prod/project", "prod/issue", "prod/form", "prod/filling", "prod/cad", "prod/slides", "prod/question", "prod/answer", "prod/poll", "prod/vote" // "prod/task", "prod/project", "prod/issue", "prod/form", "prod/filling", "prod/cad", "prod/slides", "prod/question", "prod/answer", "prod/poll", "prod/vote"
// "file", "file/iana/*", "file/gimp", "file/inkscape", "file/kdenlive", "file/blender", "file/openscad", "file/lyx", "file/scribus", "file/libreoffice", // "file", "file/iana/*", "file/gimp", "file/inkscape", "file/kdenlive", "file/blender", "file/openscad", "file/lyx", "file/scribus", "file/libreoffice", "file/audacity"
// application/vnd.api+json // application/vnd.api+json

@ -1539,7 +1539,27 @@
{#if !ready} {#if !ready}
<div class=" max-w-6xl lg:px-8 mx-auto px-4 text-primary-700"> <div class=" max-w-6xl lg:px-8 mx-auto px-4 text-primary-700">
{$t("pages.wallet_create.creating")} {$t("pages.wallet_create.creating")}
<Spinner className="mt-10 h-6 w-6 mx-auto" /> <svg
class="animate-spin mt-10 h-6 w-6 mx-auto"
xmlns="http://www.w3.org/2000/svg"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<circle
class="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="4"
/>
<path
class="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
</div> </div>
{:else} {:else}
<div class="text-left mx-4"> <div class="text-left mx-4">

@ -1258,13 +1258,20 @@ pub fn display_pazzle(pazzle: &Vec<u8>) -> Vec<(&'static str, &'static str)> {
for emoji in pazzle { for emoji in pazzle {
let cat = (emoji & 240) >> 4; let cat = (emoji & 240) >> 4;
let idx = emoji & 15; let idx = emoji & 15;
res.push(( let cat_str = EMOJI_CAT[cat as usize];
EMOJI_CAT[cat as usize], res.push((cat_str, EMOJIS.get(cat_str).unwrap()[idx as usize].code));
EMOJIS.get(&EMOJI_CAT[cat as usize]).unwrap()[idx as usize].code,
));
} }
res res
} }
pub fn display_pazzle_one(pazzle: &Vec<u8>) -> Vec<String> {
let res: Vec<String> = display_pazzle(pazzle)
.into_iter()
.map(|(cat, emoji)| String::from(format!("{cat}:{emoji}")))
.collect();
res
}
//use ng_repo::log::*; //use ng_repo::log::*;
/// taking a list of pazzle words, returns a list of u8 codes /// taking a list of pazzle words, returns a list of u8 codes

@ -408,25 +408,6 @@ pub fn display_mnemonic(mnemonic: &[u16; 12]) -> Vec<String> {
res res
} }
use crate::emojis::{EMOJIS, EMOJI_CAT};
pub fn display_pazzle(pazzle: &Vec<u8>) -> Vec<String> {
let res: Vec<String> = pazzle
.into_iter()
.map(|i| {
let cat = i >> 4;
let idx = i & 15;
let cat_str = EMOJI_CAT[cat as usize];
String::from(format!(
"{}:{}",
cat_str,
EMOJIS.get(cat_str).unwrap()[idx as usize].code
))
})
.collect();
res
}
pub fn gen_shuffle_for_pazzle_opening(pazzle_length: u8) -> ShuffledPazzle { pub fn gen_shuffle_for_pazzle_opening(pazzle_length: u8) -> ShuffledPazzle {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let mut category_indices: Vec<u8> = (0..pazzle_length).collect(); let mut category_indices: Vec<u8> = (0..pazzle_length).collect();
@ -870,7 +851,7 @@ mod test {
let _ = file.write_all(&ser_wallet); let _ = file.write_all(&ser_wallet);
log_debug!("wallet id: {}", res.wallet.id()); log_debug!("wallet id: {}", res.wallet.id());
log_debug!("pazzle {:?}", display_pazzle(&res.pazzle)); log_debug!("pazzle {:?}", display_pazzle_one(&res.pazzle));
log_debug!("mnemonic {:?}", display_mnemonic(&res.mnemonic)); log_debug!("mnemonic {:?}", display_mnemonic(&res.mnemonic));
log_debug!("pin {:?}", pin); log_debug!("pin {:?}", pin);

Loading…
Cancel
Save