mirror of
https://github.com/kmc7468/arkvault.git
synced 2026-11-04 08:10:28 +09:00
키 관리 로직을 Keyring으로 통합하여 하드코딩된 MEK 및 HSK 버전을 제거하고 Svelte Store를 Rune으로 대체
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
aee87fd9b6
commit
2ce73aa331
50 files changed
+633
-641
No files matched your search
@@ -5,7 +5,6 @@
|
||||
import { CategoryCreateModal } from "#lib/components/organisms/index.js";
|
||||
import { updateCategoryInfo } from "#lib/client/storage/indexedDB/index.js";
|
||||
import { getCategoryInfo, type MaybeCategoryInfo } from "#lib/modules/filesystem/index.js";
|
||||
import { masterKeyStore } from "#lib/stores/index.js";
|
||||
import { HybridPromise, sortEntries } from "#lib/utils/index.js";
|
||||
import CategoryDeleteModal from "./CategoryDeleteModal.svelte";
|
||||
import CategoryMenuBottomSheet from "./CategoryMenuBottomSheet.svelte";
|
||||
@@ -56,13 +55,11 @@
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
HybridPromise.resolve(getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!)).then(
|
||||
(result) => {
|
||||
if (data.id === result.id) {
|
||||
info = result;
|
||||
}
|
||||
},
|
||||
);
|
||||
HybridPromise.resolve(getCategoryInfo(data.id)).then((result) => {
|
||||
if (data.id === result.id) {
|
||||
info = result;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -114,7 +111,7 @@
|
||||
onRemoveClick={!details.isRecursive
|
||||
? async ({ id }) => {
|
||||
await requestFileRemovalFromCategory(id, data.id as number);
|
||||
void getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
|
||||
void getCategoryInfo(data.id); // TODO: FIXME
|
||||
}
|
||||
: undefined}
|
||||
/>
|
||||
@@ -132,8 +129,8 @@
|
||||
<CategoryCreateModal
|
||||
bind:isOpen={isCategoryCreateModalOpen}
|
||||
onCreateClick={async (name: string) => {
|
||||
if (await requestCategoryCreation(name, data.id, $masterKeyStore?.get(1)!)) {
|
||||
void getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
|
||||
if (await requestCategoryCreation(name, data.id)) {
|
||||
void getCategoryInfo(data.id); // TODO: FIXME
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -155,7 +152,7 @@
|
||||
bind:isOpen={isCategoryRenameModalOpen}
|
||||
onRenameClick={async (newName: string) => {
|
||||
if (await requestCategoryRename(context.selectedCategory!, newName)) {
|
||||
void getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
|
||||
void getCategoryInfo(data.id); // TODO: FIXME
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -165,7 +162,7 @@
|
||||
bind:isOpen={isCategoryDeleteModalOpen}
|
||||
onDeleteClick={async () => {
|
||||
if (await requestCategoryDeletion(context.selectedCategory!)) {
|
||||
void getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
|
||||
void getCategoryInfo(data.id); // TODO: FIXME
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
>
|
||||
<DirectoryEntryLabel
|
||||
type="file"
|
||||
thumbnail={$thumbnail}
|
||||
thumbnail={thumbnail?.url}
|
||||
name={info.name}
|
||||
subtext={formatDateTime(info.createdAt ?? info.lastModifiedAt)}
|
||||
isFavorite={info.isFavorite}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
import { page } from "$app/state";
|
||||
import { FloatingButton } from "#lib/components/atoms/index.js";
|
||||
import { TopBar } from "#lib/components/molecules/index.js";
|
||||
import { getDirectoryInfo, type MaybeDirectoryInfo } from "#lib/modules/filesystem/index.js";
|
||||
import { masterKeyStore, hmacSecretStore } from "#lib/stores/index.js";
|
||||
import { HybridPromise } from "#lib/utils/index.js";
|
||||
import DirectoryCreateModal from "./DirectoryCreateModal.svelte";
|
||||
import DirectoryEntries from "./DirectoryEntries";
|
||||
@@ -18,7 +16,6 @@
|
||||
import UploadStatusCard from "./UploadStatusCard.svelte";
|
||||
import {
|
||||
createContext,
|
||||
requestHmacSecretDownload,
|
||||
requestDirectoryCreation,
|
||||
requestFileUpload,
|
||||
requestEntryRename,
|
||||
@@ -64,7 +61,7 @@
|
||||
if (!files || files.length === 0) return;
|
||||
|
||||
for (const file of files) {
|
||||
requestFileUpload(file, data.id, $masterKeyStore?.get(1)!, $hmacSecretStore?.get(1)!, () => {
|
||||
requestFileUpload(file, data.id, () => {
|
||||
return new Promise((resolve) => {
|
||||
duplicatedFile = file;
|
||||
resolveForDuplicateFileModal = resolve;
|
||||
@@ -74,7 +71,7 @@
|
||||
.then((res) => {
|
||||
if (!res) return;
|
||||
// TODO: FIXME
|
||||
void getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!);
|
||||
void getDirectoryInfo(data.id);
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// TODO: FIXME
|
||||
@@ -85,20 +82,12 @@
|
||||
fileInput!.value = "";
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
if (!$hmacSecretStore && !(await requestHmacSecretDownload($masterKeyStore?.get(1)?.key!))) {
|
||||
throw new Error("Failed to download hmac secrets");
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
HybridPromise.resolve(getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!)).then(
|
||||
(result) => {
|
||||
if (data.id === result.id) {
|
||||
info = result;
|
||||
}
|
||||
},
|
||||
);
|
||||
HybridPromise.resolve(getDirectoryInfo(data.id)).then((result) => {
|
||||
if (data.id === result.id) {
|
||||
info = result;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -162,8 +151,8 @@
|
||||
<DirectoryCreateModal
|
||||
bind:isOpen={isDirectoryCreateModalOpen}
|
||||
onCreateClick={async (name) => {
|
||||
if (await requestDirectoryCreation(name, data.id, $masterKeyStore?.get(1)!)) {
|
||||
void getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
|
||||
if (await requestDirectoryCreation(name, data.id)) {
|
||||
void getDirectoryInfo(data.id); // TODO: FIXME
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -195,7 +184,7 @@
|
||||
onFavoriteClick={async () => {
|
||||
if (await requestFavoriteToggle(context.selectedEntry!)) {
|
||||
isEntryMenuBottomSheetOpen = false;
|
||||
void getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
|
||||
void getDirectoryInfo(data.id); // TODO: FIXME
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -203,7 +192,7 @@
|
||||
bind:isOpen={isEntryRenameModalOpen}
|
||||
onRenameClick={async (newName: string) => {
|
||||
if (await requestEntryRename(context.selectedEntry!, newName)) {
|
||||
void getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
|
||||
void getDirectoryInfo(data.id); // TODO: FIXME
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -213,7 +202,7 @@
|
||||
bind:isOpen={isEntryDeleteModalOpen}
|
||||
onDeleteClick={async () => {
|
||||
if (await requestEntryDeletion(context.selectedEntry!)) {
|
||||
void getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
|
||||
void getDirectoryInfo(data.id); // TODO: FIXME
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
>
|
||||
<DirectoryEntryLabel
|
||||
type="file"
|
||||
thumbnail={$thumbnail}
|
||||
thumbnail={thumbnail?.url}
|
||||
name={info.name}
|
||||
subtext={formatDateTime(info.createdAt ?? info.lastModifiedAt)}
|
||||
isFavorite={info.isFavorite}
|
||||
|
||||
@@ -5,16 +5,10 @@ import {
|
||||
storeFileThumbnailCache,
|
||||
deleteFileThumbnailCache,
|
||||
} from "#lib/client/cache/index.js";
|
||||
import { storeHmacSecrets } from "#lib/client/storage/indexedDB/index.js";
|
||||
import { keyring } from "#lib/client/keys/index.js";
|
||||
import { uploadFile } from "#lib/client/transfer/index.js";
|
||||
import type { DataKey } from "#lib/modules/filesystem/index.js";
|
||||
import {
|
||||
generateDataKey,
|
||||
wrapDataKey,
|
||||
unwrapHmacSecret,
|
||||
encryptString,
|
||||
} from "#lib/shared/crypto/index.js";
|
||||
import { hmacSecretStore, type MasterKey, type HmacSecret } from "#lib/stores/index.js";
|
||||
import { generateDataKey, wrapDataKey, encryptString } from "#lib/shared/crypto/index.js";
|
||||
import { trpc } from "#trpc/client.js";
|
||||
|
||||
export interface SelectedEntry {
|
||||
@@ -36,35 +30,8 @@ export const useContext = () => {
|
||||
return getContext<ReturnType<typeof createContext>>("context");
|
||||
};
|
||||
|
||||
export const requestHmacSecretDownload = async (masterKey: CryptoKey) => {
|
||||
// TODO: MEK rotation
|
||||
|
||||
let hmacSecretsWrapped;
|
||||
try {
|
||||
hmacSecretsWrapped = await trpc.hsk.list.query();
|
||||
} catch {
|
||||
// TODO: Error Handling
|
||||
return false;
|
||||
}
|
||||
|
||||
const hmacSecrets = await Promise.all(
|
||||
hmacSecretsWrapped.map(async ({ version, state, hsk: hmacSecretWrapped }) => {
|
||||
const { hmacSecret } = await unwrapHmacSecret(hmacSecretWrapped, masterKey);
|
||||
return { version, state, secret: hmacSecret };
|
||||
}),
|
||||
);
|
||||
|
||||
await storeHmacSecrets(hmacSecrets);
|
||||
hmacSecretStore.set(new Map(hmacSecrets.map((hmacSecret) => [hmacSecret.version, hmacSecret])));
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
export const requestDirectoryCreation = async (
|
||||
name: string,
|
||||
parentId: "root" | number,
|
||||
masterKey: MasterKey,
|
||||
) => {
|
||||
export const requestDirectoryCreation = async (name: string, parentId: "root" | number) => {
|
||||
const masterKey = keyring.activeMasterKey;
|
||||
const { dataKey, dataKeyVersion } = await generateDataKey();
|
||||
const nameEncrypted = await encryptString(name, dataKey);
|
||||
|
||||
@@ -87,11 +54,9 @@ export const requestDirectoryCreation = async (
|
||||
export const requestFileUpload = async (
|
||||
file: File,
|
||||
parentId: "root" | number,
|
||||
masterKey: MasterKey,
|
||||
hmacSecret: HmacSecret,
|
||||
onDuplicate: () => Promise<boolean>,
|
||||
) => {
|
||||
const res = await uploadFile(file, parentId, masterKey, hmacSecret, onDuplicate);
|
||||
const res = await uploadFile(file, parentId, onDuplicate);
|
||||
if (!res) return false;
|
||||
|
||||
if (res.fileBuffer) {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { goto } from "$app/navigation";
|
||||
import { RowVirtualizer } from "#lib/components/atoms/index.js";
|
||||
import { TopBar } from "#lib/components/molecules/index.js";
|
||||
import { masterKeyStore } from "#lib/stores/index.js";
|
||||
import Directory from "./Directory.svelte";
|
||||
import File from "./File.svelte";
|
||||
import { requestFavoriteEntries, requestRemoveFavorite, type FavoriteEntry } from "./service";
|
||||
@@ -16,10 +15,7 @@
|
||||
let isLoading = $state(true);
|
||||
|
||||
onMount(async () => {
|
||||
const masterKey = $masterKeyStore?.get(1)?.key;
|
||||
if (masterKey) {
|
||||
entries = await requestFavoriteEntries(data.favorites, masterKey);
|
||||
}
|
||||
entries = await requestFavoriteEntries(data.favorites);
|
||||
isLoading = false;
|
||||
});
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
>
|
||||
<DirectoryEntryLabel
|
||||
type="file"
|
||||
thumbnail={$thumbnail}
|
||||
thumbnail={thumbnail?.url}
|
||||
name={info.name}
|
||||
subtext={formatDateTime(info.createdAt ?? info.lastModifiedAt)}
|
||||
isFavorite
|
||||
|
||||
@@ -13,21 +13,18 @@ export type FavoriteEntry =
|
||||
| { type: "directory"; name: string; details: SubDirectoryInfo }
|
||||
| { type: "file"; name: string; details: SummarizedFileInfo };
|
||||
|
||||
export const requestFavoriteEntries = async (
|
||||
favorites: RouterOutputs["favorites"]["get"],
|
||||
masterKey: CryptoKey,
|
||||
) => {
|
||||
export const requestFavoriteEntries = async (favorites: RouterOutputs["favorites"]["get"]) => {
|
||||
const [directories, files] = await HybridPromise.all([
|
||||
HybridPromise.all(
|
||||
favorites.directories.map((directory) =>
|
||||
getDirectoryInfo(directory.id, masterKey, {
|
||||
getDirectoryInfo(directory.id, {
|
||||
serverResponse: { ...directory, isFavorite: true },
|
||||
}),
|
||||
),
|
||||
),
|
||||
HybridPromise.all(
|
||||
favorites.files.map((file) =>
|
||||
getFileInfo(file.id, masterKey, { serverResponse: { ...file, isFavorite: true } }),
|
||||
getFileInfo(file.id, { serverResponse: { ...file, isFavorite: true } }),
|
||||
),
|
||||
),
|
||||
]);
|
||||
|
||||
Reference in new issue
Block a user