Skip to content

Commit

Permalink
Add download page
Browse files Browse the repository at this point in the history
  • Loading branch information
mrruby committed Nov 6, 2023
1 parent db6eb04 commit cd10e9f
Show file tree
Hide file tree
Showing 15 changed files with 142 additions and 37 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
},
"type": "module",
"dependencies": {
"@tanstack/svelte-query": "^5.4.3",
"clsx": "^2.0.0",
"file-saver": "^2.0.5",
"hcSeedBundle": "git+https://github.com/mrruby/hcSeedBundle",
Expand Down
16 changes: 16 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion src/lib/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from './navigation';
export * from './generate-keys';
20 changes: 20 additions & 0 deletions src/lib/queries/app-queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createMutation, useQueryClient, createQuery } from '@tanstack/svelte-query';
import { generateKeys } from '$lib/services';
import type { GeneratedKeys } from '$types';
import { queryKey } from './query-keys';

export function useGeneratedKeys() {
const queryClient = useQueryClient();

const generateKeysMutation = createMutation({
mutationFn: (passphrase: string) => generateKeys(passphrase),
onSuccess: (data) => {
queryClient.setQueryData([queryKey], data);
}
});

const generatedKeysQuery = createQuery<GeneratedKeys>({
queryKey: [queryKey]
});
return { generateKeysMutation, generatedKeysQuery };
}
2 changes: 2 additions & 0 deletions src/lib/queries/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './app-queries';
export * from './query-keys';
1 change: 1 addition & 0 deletions src/lib/queries/query-keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const queryKey = 'generatedKeys';
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-nocheck
import * as hcSeedBundle from 'hcSeedBundle';

export async function generateKeys(passphrase: string) {
export async function generateKeys(passphrase: string): Promise<GeneratedKeys> {
await hcSeedBundle.seedBundleReady;

const master = hcSeedBundle.UnlockedSeedBundle.newRandom({
Expand Down
1 change: 1 addition & 0 deletions src/lib/services/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './generate-keys';
6 changes: 6 additions & 0 deletions src/lib/types/password.ts
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
export type SetPassphrase = 'set' | 'confirm';

export type GeneratedKeys = {
master: Uint8Array;
device: Uint8Array;
revocation: Uint8Array;
};
8 changes: 7 additions & 1 deletion src/routes/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
<script>
import '../app.css';
import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query';
const queryClient = new QueryClient();
</script>

<slot />
<QueryClientProvider client={queryClient}>
<slot />
</QueryClientProvider>
10 changes: 6 additions & 4 deletions src/routes/setup/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@
import { setContext } from 'svelte';
import { passphrase, passphraseStore } from '$stores';
function dismissExtensionWindow() {
window.history.back();
}
const dismissExtensionWindow = () => window.history.back();
setContext(passphrase, passphraseStore);
$: allowGoBack = !(
$page.url.pathname.includes('start') || $page.url.pathname.includes('download')
);
</script>

<div
class="flex flex-col items-center mt-20 w-[576px] border border-light-gray rounded-xl mx-auto py-8"
>
{#if !$page.url.pathname.includes('start')}
{#if allowGoBack}
<button class="self-start ml-6 mb-4 flex items-center" on:click={dismissExtensionWindow}>
<img src="/img/arrow-left.svg" alt="Arrow" />
<span class="ml-2 text-base">Back</span></button
Expand Down
50 changes: 50 additions & 0 deletions src/routes/setup/download/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<script lang="ts">
import { getContext, onMount } from 'svelte';
import { passphrase } from '$stores';
import JSZip from 'jszip';
import fileSaver from 'file-saver';
import type { Writable } from 'svelte/store';
import { goto } from '$app/navigation';
import Button from '$components/Button.svelte';
import { useGeneratedKeys } from '$queries';
import Title from '$components/Title.svelte';
import AppParagraph from '$components/AppParagraph.svelte';
const passphraseStore = getContext<Writable<string>>(passphrase);
const { generatedKeysQuery } = useGeneratedKeys();
onMount(() => {
if ($passphraseStore === '') {
goto('/setup/start');
}
});
async function download(): Promise<void> {
const { saveAs } = fileSaver;
const files = [
{ name: 'master.txt', data: new TextDecoder().decode($generatedKeysQuery.data?.master) },
{ name: 'device.txt', data: new TextDecoder().decode($generatedKeysQuery.data?.device) },
{
name: 'revocation.txt',
data: new TextDecoder().decode($generatedKeysQuery.data?.revocation)
}
];
const zip = new JSZip();
files.forEach((file) => zip.file(file.name, file.data));
const content = await zip.generateAsync({ type: 'blob' });
saveAs(content, 'keys.zip');
}
</script>

<img src="/img/check.svg" alt="check" class="w-12 my-4" />

<Title>Save Seed Files and Keys</Title>
<AppParagraph
extraProps="mx-auto text-center max-w-md"
text="All done, please save your files. Remember to back them up an external drive you store in a secure location."
/>

<img src="/img/padlock.svg" alt="Padlock" class="my-6" />
<Button label="Save" onClick={download} />
53 changes: 24 additions & 29 deletions src/routes/setup/generate-keys/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,49 +1,44 @@
<script lang="ts">
import { getContext, onMount } from 'svelte';
import { passphrase } from '$stores';
import JSZip from 'jszip';
import fileSaver from 'file-saver';
import type { Writable } from 'svelte/store';
import { goto } from '$app/navigation';
import AppParagraph from '$components/AppParagraph.svelte';
import Title from '$components/Title.svelte';
import Button from '$components/Button.svelte';
import { generateKeys } from '$helpers/generate-keys';
import { useGeneratedKeys } from '$queries';
const passphraseStore = getContext<Writable<string>>(passphrase);
const { generateKeysMutation } = useGeneratedKeys();
onMount(() => {
if ($passphraseStore === '') {
goto('/setup/start');
}
});
async function download(): Promise<void> {
const { saveAs } = fileSaver;
const { master, device, revocation } = await generateKeys($passphraseStore);
const files = [
{ name: 'master.txt', data: new TextDecoder().decode(master) },
{ name: 'device.txt', data: new TextDecoder().decode(device) },
{ name: 'revocation.txt', data: new TextDecoder().decode(revocation) }
];
const zip = new JSZip();
files.forEach((file) => zip.file(file.name, file.data));
const content = await zip.generateAsync({ type: 'blob' });
saveAs(content, 'keys.zip');
function generate() {
$generateKeysMutation.mutate($passphraseStore, {
onSuccess: () => goto('/setup/download')
});
}
</script>

<img src="/img/download.svg" alt="Download" class="w-12 my-4" />
<Title>Generate Seed & Key files</Title>
<AppParagraph
extraProps="mx-auto text-center max-w-md"
text="Click the button below to generate and save your seed and key files. Please save this on your external hard drive or USB drive."
/>
<p class="text-secondary text-base font-bold text-center mt-4">Context:</p>
<AppParagraph
extraProps="mx-auto text-center"
text="Remember, you will need BOTH the seed and your passphrase to restore any keys that are created from this seed. Remember to store your drives in save places like a safe, you can also save copies of this on digital drives"
/>
<img src="/img/padlock.svg" alt="Padlock" class="my-6" />
<Button label="Generate" onClick={download} />
{#if $generateKeysMutation.isPending}
<span>Loading</span>
{:else}
<img src="/img/download.svg" alt="Download" class="w-12 my-4" />
<Title>Generate Seed & Key files</Title>
<AppParagraph
extraProps="mx-auto text-center max-w-md"
text="Click the button below to generate and save your seed and key files. Please save this on your external hard drive or USB drive."
/>
<p class="text-secondary text-base font-bold text-center mt-4">Context:</p>
<AppParagraph
extraProps="mx-auto text-center"
text="Remember, you will need BOTH the seed and your passphrase to restore any keys that are created from this seed. Remember to store your drives in save places like a safe, you can also save copies of this on digital drives"
/>
<img src="/img/padlock.svg" alt="Padlock" class="my-6" />
<Button label="Generate" onClick={generate} />
{/if}
4 changes: 4 additions & 0 deletions static/img/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion svelte.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ const config = {
$components: path.resolve('./src/lib/components'),
$helpers: path.resolve('./src/lib/helpers'),
$stores: path.resolve('./src/lib/stores'),
$types: path.resolve('./src/lib/types')
$types: path.resolve('./src/lib/types'),
$queries: path.resolve('./src/lib/queries'),
$services: path.resolve('./src/lib/services')
}
}
};
Expand Down

0 comments on commit cd10e9f

Please sign in to comment.