Rust implementation of NextGraph, a Decentralized and local-first web 3.0 ecosystem https://nextgraph.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
nextgraph-rs/ng-app/src/lib/Login.svelte

421 lines
11 KiB

<!--
// Copyright (c) 2022-2023 Niko Bonnieure, Par le Peuple, NextGraph.org developers
// All rights reserved.
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
-->
<script lang="ts">
import { Alert } from "flowbite-svelte";
import { onMount, createEventDispatcher, tick } from "svelte";
import ng from "../api";
import { emoji_cat, emojis, load_svg } from "../wallet_emojis";
export let wallet;
const dispatch = createEventDispatcher();
onMount(async () => {
await load_svg();
await init();
//console.log(JSON.stringify(await ng.test_create_wallet()));
//console.log(await ng.test_create_wallet());
// let ref = {
// id: {
// Blake3Digest32: [
// 228, 228, 181, 117, 36, 206, 41, 223, 130, 96, 85, 195, 104, 137, 78,
// 145, 42, 176, 58, 244, 111, 97, 246, 39, 11, 76, 135, 150, 188, 111,
// 66, 33,
// ],
// },
// key: {
// ChaCha20Key: [
// 100, 243, 39, 242, 203, 131, 102, 50, 9, 54, 248, 113, 4, 160, 28, 45,
// 73, 56, 217, 112, 95, 150, 144, 137, 9, 57, 106, 5, 39, 202, 146, 94,
// ],
// },
// };
// let img = await ng.doc_get_file_from_store_with_object_ref("ng:", ref);
// let c = {
// security_img: img["File"].V0.content,
// security_txt: " know yourself ",
// pin: [5, 2, 9, 1],
// pazzle_length: 9,
// send_bootstrap: false,
// send_wallet: false,
// result_with_wallet_file: true,
// local_save: false,
// };
// try {
// let res = await ng.wallet_create_wallet(c);
// console.log(res);
// wallet = res.wallet;
// for (const emoji of res.pazzle) {
// let cat = (emoji & 240) >> 4;
// let idx = emoji & 15;
// console.log(emoji_cat[cat], emojis[emoji_cat[cat]][idx].code);
// }
// } catch (e) {
// console.error(e);
// }
//await start_pin();
});
async function init() {
shuffle = await ng.wallet_gen_shuffle_for_pazzle_opening(pazzle_length);
emojis2 = [];
for (const [idx, cat_idx] of shuffle.category_indices.entries()) {
let cat = emojis[emoji_cat[cat_idx]];
let items = [];
for (const id of shuffle.emoji_indices[idx]) {
items.push(cat[id]);
}
emojis2.push(items);
}
emojis2 = emojis2;
display = 0;
selection = [];
error = undefined;
step = "pazzle";
}
let emojis2 = [];
let shuffle;
let step = "load";
let pazzle_length = 9;
let display = 0;
let selection = [];
let pin_code = [];
let ordered = [];
let last_one = {};
let shuffle_pin;
let error;
function order() {
step = "order";
ordered = [];
last_one = {};
for (let i = 0; i < pazzle_length; i++) {
last_one[i] = true;
}
}
async function start_pin() {
pin_code = [];
console.log(ordered);
shuffle_pin = await ng.wallet_gen_shuffle_for_pin();
step = "pin";
console.log(shuffle_pin);
}
function select(val) {
//console.log(emojis2[display][val]);
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);
selection.push({ cat: cat_idx, index: idx });
console.log(selection);
if (display == pazzle_length - 1) {
order();
} else {
display = display + 1;
}
}
async function finish() {
step = "opening";
let pazzle = [];
for (const emoji of ordered) {
pazzle.push((emoji.cat << 4) + emoji.index);
}
console.log(pazzle);
// open the wallet
try {
let secret_wallet = await ng.wallet_open_wallet_with_pazzle(
wallet,
pazzle,
pin_code
);
step = "end";
console.log(secret_wallet);
dispatch("opened", {
wallet: secret_wallet,
id: secret_wallet.V0.wallet_id,
});
} catch (e) {
console.error(e);
error = e;
step = "end";
dispatch("error", { error: e });
}
// display the result
}
function cancel() {
dispatch("cancel");
}
async function pin(val) {
console.log(val);
pin_code.push(val);
if (pin_code.length == 4) {
await finish();
}
}
async function select_order(val, pos) {
delete last_one[pos];
console.log(last_one);
console.log(val);
ordered.push(val);
val.sel = ordered.length;
selection = selection;
if (ordered.length == pazzle_length - 1) {
let last = selection[Object.keys(last_one)[0]];
ordered.push(last);
last.sel = ordered.length;
selection = selection;
console.log(last);
await start_pin();
}
}
</script>
{#if step == "load"}
<div class=" max-w-6xl lg:px-8 mx-auto px-4 text-primary-700">
Loading...
<svg
class="animate-spin mt-10 h-14 w-14 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>
{:else if step == "pazzle"}
<div class="h-screen aspect-[3/5] pazzleline max-w-[500px] min-w-[200px]">
{#each [0, 1, 2, 3, 4] as row}
<div class="columns-3 gap-0">
{#each emojis2[display]?.slice(0 + row * 3, 3 + row * 3) || [] as emoji, i}
<div
role="button"
tabindex="0"
class="w-full aspect-square emoji"
on:click={() => select(row * 3 + i)}
on:keypress={() => select(row * 3 + i)}
>
<svelte:component this={emoji.svg?.default} />
</div>
{/each}
</div>
{/each}
</div>
{:else if step == "order"}
<!-- console.log(cat_idx, emoji_cat[cat_idx], idx, cat[idx].code); -->
<div class="h-screen aspect-[3/3] pazzleline max-w-[500px] min-w-[200px]">
{#each [0, 1, 2] as row}
<div class="columns-3 gap-0">
{#each selection.slice(0 + row * 3, 3 + row * 3) || [] as emoji, i}
{#if !emoji.sel}
<div
role="button"
tabindex="0"
class="w-full aspect-square emoji"
on:click={() => select_order(emoji, row * 3 + i)}
on:keypress={() => select_order(emoji, row * 3 + i)}
>
<svelte:component
this={emojis[emoji_cat[emoji.cat]][emoji.index].svg?.default}
/>
</div>
{:else}
<div class="w-full aspect-square opacity-25 select-none sel-emoji">
<svelte:component
this={emojis[emoji_cat[emoji.cat]][emoji.index].svg?.default}
/>
<span class="sel drop-shadow-[2px_2px_2px_rgba(255,255,255,1)]"
>{emoji.sel}</span
>
</div>
{/if}
{/each}
</div>
{/each}
</div>
{:else if step == "pin"}
<div class=" max-w-6xl lg:px-8 mx-auto px-4">
<p class="max-w-xl md:mx-auto lg:max-w-2xl">
<span class="text-xl">Enter your PIN code</span>
</p>
<div class="w-[325px] mx-auto">
{#each [0, 1, 2] as row}
<div class="">
{#each shuffle_pin.slice(0 + row * 3, 3 + row * 3) as num}
<button
tabindex="0"
class="m-1 select-none align-bottom text-7xl w-[100px] h-[100px] p-0"
on:click={async () => await pin(num)}
>
<span>{num}</span>
</button>
{/each}
</div>
{/each}
<button
tabindex="0"
class="m-1 select-none mx-auto align-bottom text-7xl w-[100px] h-[100px] p-0"
on:click={async () => await pin(shuffle_pin[9])}
>
<span>{shuffle_pin[9]}</span>
</button>
</div>
</div>
{:else if step == "opening"}
<div class=" max-w-6xl lg:px-8 mx-auto px-4 text-primary-700">
Opening your wallet...<br />
Please wait
<svg
class="animate-spin mt-10 h-14 w-14 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>
{:else if step == "end"}
{#if error}
<div class=" max-w-6xl lg:px-8 mx-auto px-4 text-red-800">
An error occurred !
<svg
fill="none"
class="animate-bounce mt-10 h-10 w-10 mx-auto"
stroke="currentColor"
stroke-width="1.5"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"
/>
</svg>
<Alert color="red" class="mt-5">
{error}
</Alert>
<button class="mt-10 select-none" on:click={init}> Try again </button>
<button class="mt-10 ml-5 select-none" on:click={cancel}> Cancel </button>
</div>
{:else}
<div class=" max-w-6xl lg:px-8 mx-auto px-4 text-green-800">
Your wallet is opened!
<svg
class="my-10 h-16 w-16 mx-auto"
fill="none"
stroke="currentColor"
stroke-width="1.5"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9 12.75L11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 01-1.043 3.296 3.745 3.745 0 01-3.296 1.043A3.745 3.745 0 0112 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 01-3.296-1.043 3.745 3.745 0 01-1.043-3.296A3.745 3.745 0 013 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 011.043-3.296 3.746 3.746 0 013.296-1.043A3.746 3.746 0 0112 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 013.296 1.043 3.746 3.746 0 011.043 3.296A3.745 3.745 0 0121 12z"
/>
</svg>
</div>
{/if}
{/if}
<style>
.pazzleline {
margin-right: auto;
margin-left: auto;
}
.pin {
cursor: pointer;
text-align: center;
}
.sel {
position: relative;
top: -56%;
font-size: 100px;
font-weight: 700;
}
.sel-emoji {
overflow: hidden;
}
.emoji {
cursor: pointer;
/* padding: 0;
margin: 0;
border: 0;
box-shadow: none; */
}
</style>