mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-16 15:08:46 +00:00
파일 생성 시각 및 파일 마지막 수정 시각을 저장하도록 변경
파일 마지막 수정 시각은 반드시 지정되어야 하며, 파일 시스템에서 읽어옵니다. 파일 생성 시각은 선택적으로 지정될 수 있으며, 이미지일 경우 EXIF에서 추출을 시도합니다. 두 값 모두 클라이언트에서 암호화되어 서버에 저장됩니다.
This commit is contained in:
@@ -53,6 +53,10 @@ export const getDirectoryInfo = (directoryId: "root" | number, masterKey: Crypto
|
||||
return info;
|
||||
};
|
||||
|
||||
const decryptDate = async (ciphertext: string, iv: string, dataKey: CryptoKey) => {
|
||||
return new Date(parseInt(await decryptString(ciphertext, iv, dataKey), 10));
|
||||
};
|
||||
|
||||
const fetchFileInfo = async (
|
||||
fileId: number,
|
||||
masterKey: CryptoKey,
|
||||
@@ -70,6 +74,11 @@ const fetchFileInfo = async (
|
||||
contentType: metadata.contentType,
|
||||
contentIv: metadata.contentIv,
|
||||
name: await decryptString(metadata.name, metadata.nameIv, dataKey),
|
||||
createdAt:
|
||||
metadata.createdAt && metadata.createdAtIv
|
||||
? await decryptDate(metadata.createdAt, metadata.createdAtIv, dataKey)
|
||||
: undefined,
|
||||
lastModifiedAt: await decryptDate(metadata.lastModifiedAt, metadata.lastModifiedAtIv, dataKey),
|
||||
};
|
||||
|
||||
infoStore.update(() => newInfo);
|
||||
|
||||
@@ -28,6 +28,10 @@ export interface NewFileParams {
|
||||
encContentIv: string;
|
||||
encName: string;
|
||||
encNameIv: string;
|
||||
encCreatedAt: string | null;
|
||||
encCreatedAtIv: string | null;
|
||||
encLastModifiedAt: string;
|
||||
encLastModifiedAtIv: string;
|
||||
}
|
||||
|
||||
export const registerDirectory = async (params: NewDirectoryParams) => {
|
||||
@@ -154,7 +158,12 @@ export const unregisterDirectory = async (userId: number, directoryId: number) =
|
||||
};
|
||||
|
||||
export const registerFile = async (params: NewFileParams) => {
|
||||
if ((params.hskVersion && !params.contentHmac) || (!params.hskVersion && params.contentHmac)) {
|
||||
if (
|
||||
(params.hskVersion && !params.contentHmac) ||
|
||||
(!params.hskVersion && params.contentHmac) ||
|
||||
(params.encCreatedAt && !params.encCreatedAtIv) ||
|
||||
(!params.encCreatedAt && params.encCreatedAtIv)
|
||||
) {
|
||||
throw new Error("Invalid arguments");
|
||||
}
|
||||
|
||||
@@ -194,6 +203,14 @@ export const registerFile = async (params: NewFileParams) => {
|
||||
dekVersion: params.dekVersion,
|
||||
encContentIv: params.encContentIv,
|
||||
encName: { ciphertext: params.encName, iv: params.encNameIv },
|
||||
encCreatedAt:
|
||||
params.encCreatedAt && params.encCreatedAtIv
|
||||
? { ciphertext: params.encCreatedAt, iv: params.encCreatedAtIv }
|
||||
: null,
|
||||
encLastModifiedAt: {
|
||||
ciphertext: params.encLastModifiedAt,
|
||||
iv: params.encLastModifiedAtIv,
|
||||
},
|
||||
})
|
||||
.returning({ id: file.id });
|
||||
const { id: fileId } = newFiles[0]!;
|
||||
|
||||
@@ -61,6 +61,8 @@ export const file = sqliteTable(
|
||||
contentType: text("content_type").notNull(),
|
||||
encContentIv: text("encrypted_content_iv").notNull(), // Base64
|
||||
encName: ciphertext("encrypted_name").notNull(),
|
||||
encCreatedAt: ciphertext("encrypted_created_at"),
|
||||
encLastModifiedAt: ciphertext("encrypted_last_modified_at").notNull(),
|
||||
},
|
||||
(t) => ({
|
||||
ref1: foreignKey({
|
||||
|
||||
@@ -12,6 +12,10 @@ export const fileInfoResponse = z.object({
|
||||
contentIv: z.string().base64().nonempty(),
|
||||
name: z.string().base64().nonempty(),
|
||||
nameIv: z.string().base64().nonempty(),
|
||||
createdAt: z.string().base64().nonempty().optional(),
|
||||
createdAtIv: z.string().base64().nonempty().optional(),
|
||||
lastModifiedAt: z.string().base64().nonempty(),
|
||||
lastModifiedAtIv: z.string().base64().nonempty(),
|
||||
});
|
||||
export type FileInfoResponse = z.infer<typeof fileInfoResponse>;
|
||||
|
||||
@@ -47,5 +51,9 @@ export const fileUploadRequest = z.object({
|
||||
contentIv: z.string().base64().nonempty(),
|
||||
name: z.string().base64().nonempty(),
|
||||
nameIv: z.string().base64().nonempty(),
|
||||
createdAt: z.string().base64().nonempty().optional(),
|
||||
createdAtIv: z.string().base64().nonempty().optional(),
|
||||
lastModifiedAt: z.string().base64().nonempty(),
|
||||
lastModifiedAtIv: z.string().base64().nonempty(),
|
||||
});
|
||||
export type FileUploadRequest = z.infer<typeof fileUploadRequest>;
|
||||
|
||||
@@ -28,6 +28,8 @@ export const getFileInformation = async (userId: number, fileId: number) => {
|
||||
contentType: file.contentType,
|
||||
encContentIv: file.encContentIv,
|
||||
encName: file.encName,
|
||||
encCreatedAt: file.encCreatedAt,
|
||||
encLastModifiedAt: file.encLastModifiedAt,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -25,7 +25,10 @@ export interface FileInfo {
|
||||
contentType: string;
|
||||
contentIv: string;
|
||||
name: string;
|
||||
createdAt?: Date;
|
||||
lastModifiedAt: Date;
|
||||
}
|
||||
|
||||
export const directoryInfoStore = new Map<"root" | number, Writable<DirectoryInfo | null>>();
|
||||
|
||||
export const fileInfoStore = new Map<number, Writable<FileInfo | null>>();
|
||||
|
||||
Reference in New Issue
Block a user