mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-14 22:08:45 +00:00
파일/디렉터리 생성/이름 변경시 로그를 남기도록 변경
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
import db from "./drizzle";
|
||||
import { IntegrityError } from "./error";
|
||||
import { directory, file, mek } from "./schema";
|
||||
import { directory, directoryLog, file, fileLog, mek } from "./schema";
|
||||
|
||||
type DirectoryId = "root" | number;
|
||||
|
||||
export interface NewDirectoryParams {
|
||||
userId: number;
|
||||
parentId: DirectoryId;
|
||||
userId: number;
|
||||
mekVersion: number;
|
||||
encDek: string;
|
||||
dekVersion: Date;
|
||||
@@ -16,9 +16,9 @@ export interface NewDirectoryParams {
|
||||
}
|
||||
|
||||
export interface NewFileParams {
|
||||
path: string;
|
||||
parentId: DirectoryId;
|
||||
userId: number;
|
||||
path: string;
|
||||
mekVersion: number;
|
||||
encDek: string;
|
||||
dekVersion: Date;
|
||||
@@ -40,14 +40,23 @@ export const registerDirectory = async (params: NewDirectoryParams) => {
|
||||
throw new IntegrityError("Inactive MEK version");
|
||||
}
|
||||
|
||||
await tx.insert(directory).values({
|
||||
createdAt: new Date(),
|
||||
parentId: params.parentId === "root" ? null : params.parentId,
|
||||
userId: params.userId,
|
||||
mekVersion: params.mekVersion,
|
||||
encDek: params.encDek,
|
||||
dekVersion: params.dekVersion,
|
||||
encName: { ciphertext: params.encName, iv: params.encNameIv },
|
||||
const newDirectories = await tx
|
||||
.insert(directory)
|
||||
.values({
|
||||
parentId: params.parentId === "root" ? null : params.parentId,
|
||||
userId: params.userId,
|
||||
mekVersion: params.mekVersion,
|
||||
encDek: params.encDek,
|
||||
dekVersion: params.dekVersion,
|
||||
encName: { ciphertext: params.encName, iv: params.encNameIv },
|
||||
})
|
||||
.returning({ id: directory.id });
|
||||
const { id: directoryId } = newDirectories[0]!;
|
||||
await tx.insert(directoryLog).values({
|
||||
directoryId,
|
||||
timestamp: new Date(),
|
||||
action: "create",
|
||||
newName: { ciphertext: params.encName, iv: params.encNameIv },
|
||||
});
|
||||
},
|
||||
{ behavior: "exclusive" },
|
||||
@@ -99,6 +108,12 @@ export const setDirectoryEncName = async (
|
||||
.update(directory)
|
||||
.set({ encName: { ciphertext: encName, iv: encNameIv } })
|
||||
.where(and(eq(directory.userId, userId), eq(directory.id, directoryId)));
|
||||
await tx.insert(directoryLog).values({
|
||||
directoryId,
|
||||
timestamp: new Date(),
|
||||
action: "rename",
|
||||
newName: { ciphertext: encName, iv: encNameIv },
|
||||
});
|
||||
},
|
||||
{ behavior: "exclusive" },
|
||||
);
|
||||
@@ -148,17 +163,26 @@ export const registerFile = async (params: NewFileParams) => {
|
||||
throw new IntegrityError("Inactive MEK version");
|
||||
}
|
||||
|
||||
await tx.insert(file).values({
|
||||
path: params.path,
|
||||
parentId: params.parentId === "root" ? null : params.parentId,
|
||||
createdAt: new Date(),
|
||||
userId: params.userId,
|
||||
mekVersion: params.mekVersion,
|
||||
contentType: params.contentType,
|
||||
encDek: params.encDek,
|
||||
dekVersion: params.dekVersion,
|
||||
encContentIv: params.encContentIv,
|
||||
encName: { ciphertext: params.encName, iv: params.encNameIv },
|
||||
const newFiles = await tx
|
||||
.insert(file)
|
||||
.values({
|
||||
path: params.path,
|
||||
parentId: params.parentId === "root" ? null : params.parentId,
|
||||
userId: params.userId,
|
||||
mekVersion: params.mekVersion,
|
||||
contentType: params.contentType,
|
||||
encDek: params.encDek,
|
||||
dekVersion: params.dekVersion,
|
||||
encContentIv: params.encContentIv,
|
||||
encName: { ciphertext: params.encName, iv: params.encNameIv },
|
||||
})
|
||||
.returning({ id: file.id });
|
||||
const { id: fileId } = newFiles[0]!;
|
||||
await tx.insert(fileLog).values({
|
||||
fileId,
|
||||
timestamp: new Date(),
|
||||
action: "create",
|
||||
newName: { ciphertext: params.encName, iv: params.encNameIv },
|
||||
});
|
||||
},
|
||||
{ behavior: "exclusive" },
|
||||
@@ -210,6 +234,12 @@ export const setFileEncName = async (
|
||||
.update(file)
|
||||
.set({ encName: { ciphertext: encName, iv: encNameIv } })
|
||||
.where(and(eq(file.userId, userId), eq(file.id, fileId)));
|
||||
await tx.insert(fileLog).values({
|
||||
fileId,
|
||||
timestamp: new Date(),
|
||||
action: "rename",
|
||||
newName: { ciphertext: encName, iv: encNameIv },
|
||||
});
|
||||
},
|
||||
{ behavior: "exclusive" },
|
||||
);
|
||||
|
||||
@@ -12,7 +12,6 @@ export const directory = sqliteTable(
|
||||
"directory",
|
||||
{
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull(),
|
||||
parentId: integer("parent_id"),
|
||||
userId: integer("user_id")
|
||||
.notNull()
|
||||
@@ -34,16 +33,25 @@ export const directory = sqliteTable(
|
||||
}),
|
||||
);
|
||||
|
||||
export const directoryLog = sqliteTable("directory_log", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
directoryId: integer("directory_id")
|
||||
.notNull()
|
||||
.references(() => directory.id, { onDelete: "cascade" }),
|
||||
timestamp: integer("timestamp", { mode: "timestamp_ms" }).notNull(),
|
||||
action: text("action", { enum: ["create", "rename"] }).notNull(),
|
||||
newName: ciphertext("new_name"),
|
||||
});
|
||||
|
||||
export const file = sqliteTable(
|
||||
"file",
|
||||
{
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
path: text("path").notNull().unique(),
|
||||
parentId: integer("parent_id").references(() => directory.id),
|
||||
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull(),
|
||||
userId: integer("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id),
|
||||
path: text("path").notNull().unique(),
|
||||
mekVersion: integer("master_encryption_key_version").notNull(),
|
||||
encDek: text("encrypted_data_encryption_key").notNull().unique(), // Base64
|
||||
dekVersion: integer("data_encryption_key_version", { mode: "timestamp_ms" }).notNull(),
|
||||
@@ -58,3 +66,13 @@ export const file = sqliteTable(
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
export const fileLog = sqliteTable("file_log", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
fileId: integer("file_id")
|
||||
.notNull()
|
||||
.references(() => file.id, { onDelete: "cascade" }),
|
||||
timestamp: integer("timestamp", { mode: "timestamp_ms" }).notNull(),
|
||||
action: text("action", { enum: ["create", "rename"] }).notNull(),
|
||||
newName: ciphertext("new_name"),
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@ import { z } from "zod";
|
||||
export const directoryInfoResponse = z.object({
|
||||
metadata: z
|
||||
.object({
|
||||
createdAt: z.string().datetime(),
|
||||
mekVersion: z.number().int().positive(),
|
||||
dek: z.string().base64().nonempty(),
|
||||
dekVersion: z.string().datetime(),
|
||||
|
||||
@@ -2,7 +2,6 @@ import mime from "mime";
|
||||
import { z } from "zod";
|
||||
|
||||
export const fileInfoResponse = z.object({
|
||||
createdAt: z.string().datetime(),
|
||||
mekVersion: z.number().int().positive(),
|
||||
dek: z.string().base64().nonempty(),
|
||||
dekVersion: z.string().datetime(),
|
||||
|
||||
@@ -22,7 +22,6 @@ export const getDirectoryInformation = async (userId: number, directoryId: "root
|
||||
|
||||
return {
|
||||
metadata: directory && {
|
||||
createdAt: directory.createdAt,
|
||||
mekVersion: directory.mekVersion,
|
||||
encDek: directory.encDek,
|
||||
dekVersion: directory.dekVersion,
|
||||
|
||||
@@ -21,7 +21,6 @@ export const getFileInformation = async (userId: number, fileId: number) => {
|
||||
}
|
||||
|
||||
return {
|
||||
createdAt: file.createdAt,
|
||||
mekVersion: file.mekVersion,
|
||||
encDek: file.encDek,
|
||||
dekVersion: file.dekVersion,
|
||||
|
||||
@@ -20,7 +20,6 @@ export const GET: RequestHandler = async ({ locals, params }) => {
|
||||
return json(
|
||||
directoryInfoResponse.parse({
|
||||
metadata: metadata && {
|
||||
createdAt: metadata.createdAt.toISOString(),
|
||||
mekVersion: metadata.mekVersion,
|
||||
dek: metadata.encDek,
|
||||
dekVersion: metadata.dekVersion.toISOString(),
|
||||
|
||||
@@ -16,11 +16,10 @@ export const GET: RequestHandler = async ({ locals, params }) => {
|
||||
if (!zodRes.success) error(400, "Invalid path parameters");
|
||||
const { id } = zodRes.data;
|
||||
|
||||
const { createdAt, mekVersion, encDek, dekVersion, contentType, encContentIv, encName } =
|
||||
const { mekVersion, encDek, dekVersion, contentType, encContentIv, encName } =
|
||||
await getFileInformation(userId, id);
|
||||
return json(
|
||||
fileInfoResponse.parse({
|
||||
createdAt: createdAt.toISOString(),
|
||||
mekVersion,
|
||||
dek: encDek,
|
||||
dekVersion: dekVersion.toISOString(),
|
||||
|
||||
Reference in New Issue
Block a user