diff --git a/src/lib/hooks/goto.ts b/src/lib/hooks/goto.ts new file mode 100644 index 0000000..c2cef9c --- /dev/null +++ b/src/lib/hooks/goto.ts @@ -0,0 +1,21 @@ +import { writable } from "svelte/store"; +import { goto as svelteGoto } from "$app/navigation"; + +type Path = "/key/export"; + +interface KeyExportState { + pubKeyBase64: string; + privKeyBase64: string; +} + +export const keyExportState = writable(null); + +export function goto(path: "/key/export", state: KeyExportState): Promise; + +export function goto(path: Path, state: unknown) { + switch (path) { + case "/key/export": + keyExportState.set(state as KeyExportState); + return svelteGoto(path); + } +} diff --git a/src/lib/hooks/index.ts b/src/lib/hooks/index.ts index 54f1be9..48c19b9 100644 --- a/src/lib/hooks/index.ts +++ b/src/lib/hooks/index.ts @@ -1 +1,2 @@ export { default as callAPI } from "./callAPI"; +export { goto } from "./goto"; diff --git a/src/lib/stores/key.ts b/src/lib/stores/key.ts new file mode 100644 index 0000000..e11209c --- /dev/null +++ b/src/lib/stores/key.ts @@ -0,0 +1,4 @@ +import { writable } from "svelte/store"; + +export const pubKey = writable(null); +export const privKey = writable(null); diff --git a/src/routes/(fullscreen)/auth/generateKey/done/+page.svelte b/src/routes/(fullscreen)/auth/generateKey/done/+page.svelte deleted file mode 100644 index fd84277..0000000 --- a/src/routes/(fullscreen)/auth/generateKey/done/+page.svelte +++ /dev/null @@ -1,29 +0,0 @@ - - - - 암호 키 생성하기 - - -
-
- -

암호 키가 생성되었어요!

-
-

모든 디바이스의 암호 키가 유실되면 서버에 저장된 데이터를 영원히 복호화할 수 없게 돼요.

-

복원을 위해 암호 키를 파일로 내보낼 수 있어요.

-
-
- -
- -
-
- 내보내지 않을래요 -
-
-
diff --git a/src/routes/(fullscreen)/key/export/+page.svelte b/src/routes/(fullscreen)/key/export/+page.svelte new file mode 100644 index 0000000..ca53016 --- /dev/null +++ b/src/routes/(fullscreen)/key/export/+page.svelte @@ -0,0 +1,43 @@ + + + + 암호 키 생성하기 + + +
+
+ +
+
+
+

암호 키를 파일로 내보낼까요?

+
+

+ 모든 디바이스의 암호 키가 유실되면, 서버에 저장된 데이터를 영원히 복호화할 수 없게 돼요. +

+

만약의 상황을 위해 암호 키를 파일로 내보낼 수 있어요.

+
+
+ +
+ +
+
+ 내보내지 않을래요 +
+
+
+
diff --git a/src/routes/(fullscreen)/key/export/+page.ts b/src/routes/(fullscreen)/key/export/+page.ts new file mode 100644 index 0000000..994640b --- /dev/null +++ b/src/routes/(fullscreen)/key/export/+page.ts @@ -0,0 +1,14 @@ +import { error } from "@sveltejs/kit"; +import { get } from "svelte/store"; +import { keyExportState } from "$lib/hooks/goto"; +import type { PageLoad } from "./$types"; + +export const load: PageLoad = async () => { + const state = get(keyExportState); + if (!state) { + error(403, "Forbidden"); + } + + keyExportState.set(null); + return state; +}; diff --git a/src/routes/(fullscreen)/auth/generateKey/+page.svelte b/src/routes/(fullscreen)/key/generate/+page.svelte similarity index 88% rename from src/routes/(fullscreen)/auth/generateKey/+page.svelte rename to src/routes/(fullscreen)/key/generate/+page.svelte index 29bb56c..eddcf85 100644 --- a/src/routes/(fullscreen)/auth/generateKey/+page.svelte +++ b/src/routes/(fullscreen)/key/generate/+page.svelte @@ -1,7 +1,9 @@ @@ -49,7 +55,7 @@
- +
키를 갖고 있어요 diff --git a/src/routes/(fullscreen)/auth/generateKey/Order.svelte b/src/routes/(fullscreen)/key/generate/Order.svelte similarity index 100% rename from src/routes/(fullscreen)/auth/generateKey/Order.svelte rename to src/routes/(fullscreen)/key/generate/Order.svelte diff --git a/src/routes/(fullscreen)/auth/generateKey/service.ts b/src/routes/(fullscreen)/key/generate/service.ts similarity index 69% rename from src/routes/(fullscreen)/auth/generateKey/service.ts rename to src/routes/(fullscreen)/key/generate/service.ts index 5653703..aa46c87 100644 --- a/src/routes/(fullscreen)/auth/generateKey/service.ts +++ b/src/routes/(fullscreen)/key/generate/service.ts @@ -1,4 +1,5 @@ import { storeKeyPairIntoIndexedDB } from "$lib/indexedDB"; +import { pubKey, privKey } from "$lib/stores/key"; type KeyType = "public" | "private"; @@ -16,20 +17,6 @@ const generateRSAKeyPair = async () => { return keyPair; }; -const exportKeyAsPem = async (key: CryptoKey, type: KeyType) => { - const exportedKey = await window.crypto.subtle.exportKey( - type === "public" ? "spki" : "pkcs8", - key, - ); - const exportedKeyBase64 = btoa(String.fromCharCode(...new Uint8Array(exportedKey))) - .match(/.{1,64}/g)! - .join("\n"); - - const pemHeader = type === "public" ? "PUBLIC" : "PRIVATE"; - const pem = `-----BEGIN ${pemHeader} KEY-----\n${exportedKeyBase64}\n-----END ${pemHeader} KEY-----\n`; - return pem; -}; - const makeRSAKeyNonextractable = async (key: CryptoKey, type: KeyType) => { const format = type === "public" ? "spki" : "pkcs8"; const keyUsage = type === "public" ? "encrypt" : "decrypt"; @@ -45,13 +32,25 @@ const makeRSAKeyNonextractable = async (key: CryptoKey, type: KeyType) => { ); }; +const exportKeyToBase64 = async (key: CryptoKey, type: KeyType) => { + const exportedKey = await window.crypto.subtle.exportKey( + type === "public" ? "spki" : "pkcs8", + key, + ); + return btoa(String.fromCharCode(...new Uint8Array(exportedKey))); +}; + export const generateKeyPair = async () => { const keyPair = await generateRSAKeyPair(); - const privKeySecure = await makeRSAKeyNonextractable(keyPair.privateKey, "private"); + + pubKey.set(keyPair.publicKey); + privKey.set(privKeySecure); + await storeKeyPairIntoIndexedDB(keyPair.publicKey, privKeySecure); - const pubKeyPem = await exportKeyAsPem(keyPair.publicKey, "public"); - const privKeyPem = await exportKeyAsPem(keyPair.privateKey, "private"); - return { pubKeyPem, privKeyPem }; + return { + pubKeyBase64: await exportKeyToBase64(keyPair.publicKey, "public"), + privKeyBase64: await exportKeyToBase64(keyPair.privateKey, "private"), + }; };