diff options
| author | Adam Soltys <[email protected]> | 2022-12-21 13:40:25 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2022-12-21 13:40:31 -0800 |
| commit | 9cdb89fdeee99301d77e5d26efb87a309effd635 (patch) | |
| tree | 998041eeb01d8fed826968436d0667d3f4ec5c3c /src | |
| parent | 615ab1d9086a028b6208dc9100593fb4feb734b9 (diff) | |
| download | coinos-ui-9cdb89fdeee99301d77e5d26efb87a309effd635.tar.gz coinos-ui-9cdb89fdeee99301d77e5d26efb87a309effd635.zip | |
generate keypair for users that don't have one
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/RegisterOrLogin.svelte | 16 | ||||
| -rw-r--r-- | src/hooks.server.js | 2 | ||||
| -rw-r--r-- | src/lib/socket.js | 2 | ||||
| -rw-r--r-- | src/lib/store.js | 10 | ||||
| -rw-r--r-- | src/routes/(app)/+layout.server.js | 2 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/dashboard/+page.svelte | 2 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/generate/+page.svelte | 61 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/generate/+server.js | 8 |
8 files changed, 90 insertions, 13 deletions
diff --git a/src/components/RegisterOrLogin.svelte b/src/components/RegisterOrLogin.svelte index 32f046d0..8ee3af4a 100644 --- a/src/components/RegisterOrLogin.svelte +++ b/src/components/RegisterOrLogin.svelte @@ -5,7 +5,7 @@ import { enhance } from '$app/forms'; import { Icon } from '$comp'; import { focus } from '$lib/utils'; - import { loginRedirect } from '$lib/store'; + import { loginRedirect, password } from '$lib/store'; import { t } from '$lib/translations'; import { page } from '$app/stores'; @@ -19,12 +19,12 @@ export let form; export let pageID; - let username, password, email, submit; + let username, email, btn; $: update(form); - let update = (form) => form && ({ username, password } = form); + let update = (form) => form && ({ username, password: $password } = form); - $: token && token?.length === 6 && tick().then(() => submit.click()); + $: token && token?.length === 6 && tick().then(() => btn.click()); let revealPassword = false; @@ -52,7 +52,7 @@ <form class="space-y-5" {action} method="POST" use:enhance> <input type="hidden" name="username" value={username} /> - <input type="hidden" name="password" value={password} /> + <input type="hidden" name="password" value={$password} /> <input type="hidden" name="token" value={token} /> <div> @@ -66,7 +66,7 @@ </Pincode> </div> <button - bind:this={submit} + bind:this={btn} type="submit" class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" >{$t('login.' + pageID)} @@ -107,7 +107,7 @@ type="text" required class="bg-primary" - bind:value={password} + bind:value={$password} autocapitalize="none" /> {:else} @@ -116,7 +116,7 @@ type="password" required class="bg-primary" - bind:value={password} + bind:value={$password} autocapitalize="none" /> {/if} diff --git a/src/hooks.server.js b/src/hooks.server.js index f6e7ff70..4107ec86 100644 --- a/src/hooks.server.js +++ b/src/hooks.server.js @@ -14,8 +14,6 @@ export async function handle({ event, resolve }) { user = await get('/me', auth(event.cookies)); event.locals.user = user; - if (!user.pubkey) throw new Error('missing pubkey'); - if (['/', '/login', '/register'].includes(pathname) && request.method === 'GET') return Response.redirect(origin + `/${user.username}/dashboard`, 307); } catch (e) { diff --git a/src/lib/socket.js b/src/lib/socket.js index 59c2f872..d43af082 100644 --- a/src/lib/socket.js +++ b/src/lib/socket.js @@ -40,7 +40,7 @@ export const messages = (data) => ({ events[data.id] = data; events.q.push(data.id); $events.set(events); - if (events.q.length > 1000) delete events[events.q.shift()]; + if (events.q.length > 500) delete events[events.q.shift()]; }, rate() { diff --git a/src/lib/store.js b/src/lib/store.js index df1525d3..34e8dcca 100644 --- a/src/lib/store.js +++ b/src/lib/store.js @@ -26,7 +26,14 @@ const persistLocal = (key, defaultValue) => { : defaultValue ); - s.subscribe((v) => browser && localStorage.setItem(key, JSON.stringify(v))); + s.subscribe((v) => { + try { + browser && localStorage.setItem(key, JSON.stringify(v)); + } catch (e) { + console.log('problem setting key', v); + console.log(e); + } + }); return s; }; @@ -48,3 +55,4 @@ export const request = writable(); export const invoice = writable(); export const txns = persistLocal('transactions', []); export const events = persistLocal('events', {}); +export const password = writable(); diff --git a/src/routes/(app)/+layout.server.js b/src/routes/(app)/+layout.server.js index d968be70..88ca1539 100644 --- a/src/routes/(app)/+layout.server.js +++ b/src/routes/(app)/+layout.server.js @@ -11,6 +11,8 @@ export async function load({ cookies, locals, request, url, params }) { let { user } = locals; if (user) { + if (!user.pubkey && !url.pathname.includes('gen')) + throw redirect(307, `/${user.username}/generate`); let account = user.accounts.find((a) => a.asset === btc && !a.pubkey); if (account) { let { id } = account; diff --git a/src/routes/(app)/[username]/dashboard/+page.svelte b/src/routes/(app)/[username]/dashboard/+page.svelte index c10518f5..0b49a870 100644 --- a/src/routes/(app)/[username]/dashboard/+page.svelte +++ b/src/routes/(app)/[username]/dashboard/+page.svelte @@ -3,7 +3,7 @@ import { f, s, post, failure, sat, sats } from '$lib/utils'; import { tick } from 'svelte'; import { Avatar, Icon } from '$comp'; - import { rate, selectedRate } from '$lib/store'; + import { rate, password, selectedRate } from '$lib/store'; import { goto } from '$app/navigation'; import { t } from '$lib/translations'; diff --git a/src/routes/(app)/[username]/generate/+page.svelte b/src/routes/(app)/[username]/generate/+page.svelte new file mode 100644 index 00000000..873e336f --- /dev/null +++ b/src/routes/(app)/[username]/generate/+page.svelte @@ -0,0 +1,61 @@ +<script> + import { Buffer } from 'buffer'; + import { onMount } from 'svelte'; + import { BIP32Factory } from 'bip32'; + import { bech32m } from 'bech32'; + import { generateMnemonic, mnemonicToEntropy, mnemonicToSeedSync } from 'bip39'; + import * as ecc from 'tiny-secp256k1'; + import { post } from '$lib/utils'; + import { goto } from '$app/navigation'; + + export let data; + let { user } = data; + + const { encode, decode, fromWords, toWords } = bech32m; + + const stretch = async (password, salt) => + crypto.subtle.deriveKey( + { + name: 'PBKDF2', + salt, + iterations: 100000, + hash: 'SHA-256' + }, + await crypto.subtle.importKey( + 'raw', + new TextEncoder().encode(password), + { name: 'PBKDF2' }, + false, + ['deriveBits', 'deriveKey'] + ), + { name: 'AES-GCM', length: 256 }, + true, + ['encrypt', 'decrypt'] + ); + + let mnemonic, key, password, seed, entropy, cipher, pubkey, salt, child; + + onMount(async () => { + let bip32 = await BIP32Factory(ecc); + mnemonic = generateMnemonic(); + seed = mnemonicToSeedSync(mnemonic); + entropy = mnemonicToEntropy(mnemonic); + key = bip32.fromSeed(seed); + child = key.derivePath("m/44'/1237'/0'/0/0"); + salt = crypto.getRandomValues(new Uint8Array(16)); + + let bytes = new Uint8Array( + await crypto.subtle.encrypt( + { name: 'AES-GCM', iv: new Uint8Array(16) }, + await stretch(password, salt), + Uint8Array.from(Buffer.from(entropy, 'hex')) + ) + ); + + user.pubkey = Buffer.from(ecc.xOnlyPointFromPoint(child.publicKey)).toString('hex'); + user.cipher = encode('encprv', toWords(bytes), 180); + + await post(`/${user.username}/generate`, user); + goto(`/${user.username}/dashboard`); + }); +</script> diff --git a/src/routes/(app)/[username]/generate/+server.js b/src/routes/(app)/[username]/generate/+server.js new file mode 100644 index 00000000..c63ab5a6 --- /dev/null +++ b/src/routes/(app)/[username]/generate/+server.js @@ -0,0 +1,8 @@ +import { auth, post } from '$lib/utils'; +import { json } from '@sveltejs/kit'; + +export async function POST({ cookies, request }) { + let body = await request.json(); + let user = await post(`/user`, body, auth(cookies)); + return json(user); +} |
