aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/components/Account.svelte6
-rw-r--r--src/components/Items.svelte2
-rw-r--r--src/lib/parse.ts6
-rw-r--r--src/routes/(app)/+layout.server.ts4
-rw-r--r--src/routes/(app)/account/cash/+page.svelte46
-rw-r--r--src/routes/(app)/account/mints/+page.svelte1
-rw-r--r--src/routes/(app)/account/pass/+page.svelte (renamed from src/routes/(app)/account/setup/step2/+page.svelte)49
-rw-r--r--src/routes/(app)/account/savings/+page.svelte31
-rw-r--r--src/routes/(app)/account/seed/+page.svelte85
-rw-r--r--src/routes/(app)/account/self/+page.svelte59
-rw-r--r--src/routes/(app)/account/setup/+page.svelte41
11 files changed, 209 insertions, 121 deletions
diff --git a/src/components/Account.svelte b/src/components/Account.svelte
index ab24f56a..d52c4f52 100644
--- a/src/components/Account.svelte
+++ b/src/components/Account.svelte
@@ -9,10 +9,10 @@
$: type = seed ? "Savings" : "Cash";
$: refresh(account);
- let refresh = (a) => ({ seed, balance, id } = a)
+ let refresh = (a) => ({ seed, balance, id } = a);
- let setAccount = () =>
- document.cookie = `account=${id}; path=/; max-age=86400`;
+ let setAccount = () =>
+ (document.cookie = `account=${id}; path=/; max-age=86400`);
</script>
<a href={`/payments`} class="block" on:click={setAccount}>
diff --git a/src/components/Items.svelte b/src/components/Items.svelte
index 47966d8e..2916721d 100644
--- a/src/components/Items.svelte
+++ b/src/components/Items.svelte
@@ -15,7 +15,7 @@
import DeleteItem from "$comp/DeleteItem.svelte";
import Icon from "$comp/Icon.svelte";
- export let subject, user, items, rate, currency, total;
+ export let subject, user, items, rate, currency, total;
let flipDurationMs = 200;
let dropTargetStyle = {};
diff --git a/src/lib/parse.ts b/src/lib/parse.ts
index 5bf5ffb0..781c7087 100644
--- a/src/lib/parse.ts
+++ b/src/lib/parse.ts
@@ -45,9 +45,9 @@ export default async (t, host) => {
// bitcoin
if (validate(t) || isLiquid(t)) {
- let r = `/send/bitcoin/${t}`;
- if (amount) r += "/" + amount;
- redirect(307, r);
+ let r = `/send/bitcoin/${t}`;
+ if (amount) r += "/" + amount;
+ redirect(307, r);
}
if (t.startsWith("cashu")) {
diff --git a/src/routes/(app)/+layout.server.ts b/src/routes/(app)/+layout.server.ts
index e4105fb8..0901cb5d 100644
--- a/src/routes/(app)/+layout.server.ts
+++ b/src/routes/(app)/+layout.server.ts
@@ -39,12 +39,12 @@ export async function load({ cookies, request, url, params }) {
redirect(307, `/${user.username}`);
}
- if ( protectedRoutes.find((p) => pathname.match(p)) && (!user)) {
+ if (protectedRoutes.find((p) => pathname.match(p)) && !user) {
redirect(307, "/login");
}
if (user && !user.pubkey && !pathname.includes("generate")) {
- console.log("user missing pubkey", user)
+ console.log("user missing pubkey", user);
redirect(303, `/${user.username}/generate`);
}
diff --git a/src/routes/(app)/account/cash/+page.svelte b/src/routes/(app)/account/cash/+page.svelte
index de0092a4..b0e2e757 100644
--- a/src/routes/(app)/account/cash/+page.svelte
+++ b/src/routes/(app)/account/cash/+page.svelte
@@ -1,29 +1,37 @@
<script>
import { t } from "$lib/translations";
+ import Icon from "$comp/Icon.svelte";
</script>
<div class="space-y-5">
<h1 class="text-center text-3xl font-semibold">Choose your custodian</h1>
- <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5">
- <a href="/account/cash">
- <div class="shadow p-8 rounded-xl flex gap-4">
- <img src="/icons/logo-symbol.svg" class="w-20" />
- <div>
- <div class="text-xl">Coinos</div>
- <div class="text-secondary">
- https://mint.coinos.io
- </div>
- </div>
- </div>
- <div class="shadow p-8 rounded-xl flex gap-4">
- <img src="/images/minibits.png" class="w-20" />
- <div>
- <div class="text-xl">Minibits</div>
- <div class="text-secondary">
- https://mint.minibits.cash/bitcoin
- </div>
- </div>
+ <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-2">
+ <div class="space-y-5">
+ <a href="/account/cash" class="block">
+ <div class="shadow p-8 rounded-xl flex gap-4 hover:bg-primary">
+ <img src="/icons/logo-symbol.svg" class="w-20" />
+ <div>
+ <div class="text-xl">Coinos</div>
+ <div class="text-secondary">https://mint.coinos.io</div>
+ </div>
+ </div>
+ </a>
+ <a href="/account/cash" class="block">
+ <div class="shadow p-8 rounded-xl flex gap-4 hover:bg-primary">
+ <img src="/images/minibits.png" class="w-20" />
+ <div>
+ <div class="text-xl">Minibits</div>
+ <div class="text-secondary">https://mint.minibits.cash/bitcoin</div>
+ </div>
+ </div>
+ </a>
</div>
+ <!-- <a href="/account/mints" class="block"> -->
+ <!-- <div class="p-4 border rounded-xl flex justify-center gap-2"> -->
+ <!-- <Icon icon="plus" style="w-8 my-auto" /> -->
+ <!-- <div class="text-xl my-auto">More</div> -->
+ <!-- </div> -->
+ <!-- </a> -->
</div>
</div>
diff --git a/src/routes/(app)/account/mints/+page.svelte b/src/routes/(app)/account/mints/+page.svelte
new file mode 100644
index 00000000..1080269e
--- /dev/null
+++ b/src/routes/(app)/account/mints/+page.svelte
@@ -0,0 +1 @@
+mints
diff --git a/src/routes/(app)/account/setup/step2/+page.svelte b/src/routes/(app)/account/pass/+page.svelte
index 221e545e..b6c7f339 100644
--- a/src/routes/(app)/account/setup/step2/+page.svelte
+++ b/src/routes/(app)/account/pass/+page.svelte
@@ -1,4 +1,5 @@
<script lang="ts">
+ import { onMount } from "svelte";
import { t } from "$lib/translations";
import { mnemonic } from "$lib/store";
import Icon from "$comp/Icon.svelte";
@@ -17,25 +18,37 @@
let { user } = data;
- let password;
+ let confirm, password;
+
+ onMount(() => {
+ if (!$mnemonic) goto("/account/savings");
+ });
let submit = async () => {
- let seed = await encrypt(mnemonicToEntropy($mnemonic, wordlist), password);
- let master = HDKey.fromMasterSeed(
- await mnemonicToSeed($mnemonic),
- versions
- );
- let child = master.derive("m/84'/0'/0'");
- let pubkey = child.publicExtendedKey;
- let fingerprint = child.fingerprint.toString(16).padStart(8, "0");
+ if (!password || password !== confirm) {
+ fail("Passwords don't match");
+ return;
+ }
- let receiving = child.deriveChild(0);
try {
+ let seed = await encrypt(
+ mnemonicToEntropy($mnemonic, wordlist),
+ password
+ );
+ let master = HDKey.fromMasterSeed(
+ await mnemonicToSeed($mnemonic, password),
+ versions
+ );
+ let child = master.derive("m/84'/0'/0'");
+ let pubkey = child.publicExtendedKey;
+ let fingerprint = child.fingerprint.toString(16).padStart(8, "0");
+
+ let receiving = child.deriveChild(0);
await post("/api/accounts", { fingerprint, pubkey, seed });
goto(`/${user.username}`);
} catch (e) {
console.log(e);
- fail("Something went wrong");
+ fail(e.message);
}
$mnemonic = "";
@@ -44,8 +57,7 @@
<div class="space-y-5">
<div>
- <h1 class="text-center text-3xl font-semibold">Account setup</h1>
- <h2 class="text-center text-2xl text-secondary">Step 2</h2>
+ <h1 class="text-center text-3xl font-semibold">Account password</h1>
</div>
<form
@@ -53,11 +65,18 @@
class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5"
>
<p class="text-secondary mb-1">
- Add an additional password to your seed phrase. It should be different
- than your login password. We can't reset it if you lose it.
+ Please add a password to the account. It should be different than your
+ login password. <b class="text-red-700">We won't be able to reset it.</b> You'll
+ need it to make withdrawals.
</p>
<input use:focus type="text" placeholder="Password" bind:value={password} />
+ <input
+ use:focus
+ type="text"
+ placeholder="Confirm password"
+ bind:value={confirm}
+ />
<button
class="bg-black text-white w-full px-5 py-6 text-xl rounded-2xl font-bold"
diff --git a/src/routes/(app)/account/savings/+page.svelte b/src/routes/(app)/account/savings/+page.svelte
new file mode 100644
index 00000000..8d52f997
--- /dev/null
+++ b/src/routes/(app)/account/savings/+page.svelte
@@ -0,0 +1,31 @@
+<script>
+ import { t } from "$lib/translations";
+ import Icon from "$comp/Icon.svelte";
+</script>
+
+<div class="space-y-5">
+ <h1 class="text-center text-3xl font-semibold">Wallet setup</h1>
+
+ <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-2">
+ <div class="space-y-5">
+ <a href="/account/seed" class="block">
+ <div class="shadow p-8 rounded-xl flex gap-4 hover:bg-primary">
+ <img src="/icons/random.svg" class="w-20" />
+ <div>
+ <div class="text-xl">Create</div>
+ <div class="text-secondary">Generate a new seed phrase in your browser</div>
+ </div>
+ </div>
+ </a>
+ <a href="/account/import" class="block">
+ <div class="shadow p-8 rounded-xl flex gap-4 hover:bg-primary">
+ <img src="/images/keys.png" class="w-20" />
+ <div>
+ <div class="text-xl">Import</div>
+ <div class="text-secondary">Enter an existing seed phrase or wallet key</div>
+ </div>
+ </div>
+ </a>
+ </div>
+ </div>
+</div>
diff --git a/src/routes/(app)/account/seed/+page.svelte b/src/routes/(app)/account/seed/+page.svelte
new file mode 100644
index 00000000..9c19e820
--- /dev/null
+++ b/src/routes/(app)/account/seed/+page.svelte
@@ -0,0 +1,85 @@
+<script>
+ import { browser } from "$app/environment";
+ import { tick, onMount } from "svelte";
+ import { copy } from "$lib/utils";
+ import { t } from "$lib/translations";
+ import Icon from "$comp/Icon.svelte";
+ import { mnemonic } from "$lib/store";
+ import { generateMnemonic } from "@scure/bip39";
+ import { wordlist } from "@scure/bip39/wordlists/english";
+
+ export let data;
+ let { user } = data;
+
+ onMount(async () => {
+ if (!browser) return;
+ await generate();
+ });
+
+ let generate = async () => {
+ $mnemonic = "- - - - - - - - - - - -";
+ await tick();
+ await new Promise((r) => setTimeout(r, 250));
+ $mnemonic = await generateMnemonic(wordlist);
+ };
+</script>
+
+<div class="space-y-5">
+ <h1 class="text-center text-3xl font-semibold">Seed phrase</h1>
+
+ <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5">
+ {#if $mnemonic}
+ <div
+ class="text-2xl border p-4 rounded-2xl text-secondary grid grid-rows-6 grid-flow-col gap-2 justify-center gap-x-40"
+ >
+ {#each $mnemonic.split(" ") as w, i}
+ <div>
+ <span class="select-none text-sm text-black">{i + 1}.</span>
+ <span>{@html w === "-" ? "&mdash;" : w}</span>
+ </div>
+ {/each}
+ </div>
+ {/if}
+
+ <div>
+ <button
+ type="button"
+ class="flex gap-2 text-center break-all rounded-2xl hover:opacity-80 py-5 px-6 w-full mx-auto justify-center border whitespace-nowrap mb-2"
+ on:click={generate}
+ >
+ <Icon icon="random" style="w-8 my-auto" />
+ <div class="my-auto">Regenerate</div>
+ </button>
+
+ <button
+ type="button"
+ class="flex gap-2 text-center break-all rounded-2xl hover:opacity-80 py-5 px-6 w-full mx-auto justify-center border whitespace-nowrap mb-2"
+ on:click={() => copy($mnemonic)}
+ >
+ <Icon icon="copy" style="w-8 my-auto" />
+ <div class="my-auto">
+ {$t("payments.copy")}
+ </div>
+ </button>
+ </div>
+
+ <div class="flex gap-2">
+ <a href={`/account/savings`} class="contents">
+ <button
+ type="button"
+ class="bg-black text-white w-full px-5 py-6 text-xl rounded-2xl font-bold"
+ >
+ Back
+ </button>
+ </a>
+ <a href={`/account/pass`} class="contents">
+ <button
+ type="button"
+ class="bg-black text-white w-full px-5 py-6 text-xl rounded-2xl font-bold"
+ >
+ Next
+ </button>
+ </a>
+ </div>
+ </div>
+</div>
diff --git a/src/routes/(app)/account/self/+page.svelte b/src/routes/(app)/account/self/+page.svelte
deleted file mode 100644
index 833def87..00000000
--- a/src/routes/(app)/account/self/+page.svelte
+++ /dev/null
@@ -1,59 +0,0 @@
-<script>
- import { copy } from "$lib/utils";
- import { t } from "$lib/translations";
- import Icon from "$comp/Icon.svelte";
- import { mnemonic } from "$lib/store";
- import { generateMnemonic } from "@scure/bip39";
- import { wordlist } from "@scure/bip39/wordlists/english";
-
- export let data;
- let { user } = data;
-
- let reveal;
-
- let toggleSeed = async () => {
- try {
- $mnemonic = await generateMnemonic(wordlist);
- reveal = !reveal;
- } catch (e) {
- console.log(e);
- }
- };
-</script>
-
-<div class="space-y-5">
- <h1 class="text-center text-3xl font-semibold">Account setup</h1>
- <h2 class="text-center text-2xl text-secondary">Step 1</h2>
-
- <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5">
- <p class="text-secondary mb-1">
- Whoever knows these words in the correct order can withdraw funds from the account. We can't
- recover them if you lose them.
- </p>
-
- {#if reveal}
- <div class="text-2xl border p-4 text-center rounded-2xl">
- {$mnemonic}
- </div>
-
- <div>
- <a href={`/account/setup/step2`} class="contents">
- <button
- type="button"
- class="bg-black text-white w-full px-5 py-6 text-xl rounded-2xl font-bold"
- on:click={toggleSeed}
- >
- I've written down my seed phrase
- </button>
- </a>
- </div>
- {:else}
- <div class="flex justify-center">
- <button type="button" class="primary" on:click={toggleSeed}>
- <Icon icon="warning" style="mr-2 w-6 my-auto" />
- {$t("user.settings.revealSeed")}
- </button>
- </div>
- {/if}
- </div>
-</div>
diff --git a/src/routes/(app)/account/setup/+page.svelte b/src/routes/(app)/account/setup/+page.svelte
index f19c4c96..8304c5ed 100644
--- a/src/routes/(app)/account/setup/+page.svelte
+++ b/src/routes/(app)/account/setup/+page.svelte
@@ -6,26 +6,29 @@
<h1 class="text-center text-3xl font-semibold">Choose account type</h1>
<div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5">
- <a href="/account/cash">
- <div class="shadow p-8 rounded-xl flex gap-4">
- <img src="/images/cash.png" class="w-20" />
- <div>
- <div class="text-xl">Cash</div>
- <div class="text-secondary">
- Your balance is held with a custodian. Payments are faster and
- cheaper.
+ <a href="/account/cash" class="block">
+ <div class="shadow p-8 rounded-xl flex gap-4 hover:bg-primary">
+ <img src="/images/cash.png" class="w-20" />
+ <div>
+ <div class="text-xl">Cash</div>
+ <div class="text-secondary">
+ Your balance is held with a custodian. Payments are fast and
+ free.
+ </div>
+ </div>
</div>
+ </a>
+ <a href="/account/savings" class="block">
+ <div class="shadow p-8 rounded-xl flex gap-4 hover:bg-primary">
+ <img src="/images/keys.png" class="w-20" />
+ <div>
+ <div class="text-xl">Savings</div>
+ <div class="text-secondary">
+ You hold the keys to the account and are responsible for
+ safeguarding them.
+ </div>
+ </div>
</div>
- </div>
- <div class="shadow p-8 rounded-xl flex gap-4">
- <img src="/images/keys.png" class="w-20" />
- <div>
- <div class="text-xl">Savings</div>
- <div class="text-secondary">
- You hold the keys to the account and are responsible for safeguarding
- them.
- </div>
- </div>
- </div>
+ </a>
</div>
</div>