Kysely 및 PostgreSQL 도입 (WiP)

This commit is contained in:
static
2025-01-20 10:56:58 +09:00
parent 0002b4e5f2
commit 63eacbb1b3
10 changed files with 399 additions and 2 deletions

View File

@@ -0,0 +1,15 @@
import { Kysely, PostgresDialect } from "kysely";
import { Pool } from "pg";
import type { Database } from "./schema";
const dialect = new PostgresDialect({
pool: new Pool({
// TODO
}),
});
const db = new Kysely<Database>({ dialect });
// TODO: Migration
export default db;

View File

@@ -6,6 +6,7 @@ import {
foreignKey,
unique,
} from "drizzle-orm/sqlite-core";
import type { ColumnType, Generated } from "kysely";
import { user } from "./user";
export const client = sqliteTable(
@@ -59,3 +60,32 @@ export const userClientChallenge = sqliteTable(
}),
}),
);
interface ClientTable {
id: Generated<number>;
encryption_public_key: string; // Base64
signature_public_key: string; // Base64
}
interface UserClientTable {
user_id: number;
client_id: number;
state: "challenging" | "pending" | "active";
}
interface UserClientChallengeTable {
id: Generated<number>;
user_id: number;
client_id: number;
answer: string; // Base64
allowed_ip: string;
expires_at: ColumnType<Date, Date, never>;
}
declare module "./index" {
interface Database {
client: ClientTable;
user_client: UserClientTable;
user_client_challenge: UserClientChallengeTable;
}
}

View File

@@ -1,4 +1,5 @@
import { sqliteTable, text, integer, foreignKey } from "drizzle-orm/sqlite-core";
import type { ColumnType, Generated, JSONColumnType } from "kysely";
import { hsk } from "./hsk";
import { mek } from "./mek";
import { user } from "./user";
@@ -86,3 +87,61 @@ export const fileLog = sqliteTable("file_log", {
action: text("action", { enum: ["create", "rename"] }).notNull(),
newName: ciphertext("new_name"),
});
type Ciphertext = JSONColumnType<{
ciphertext: string; // Base64
iv: string; // Base64
}>;
interface DirectoryTable {
id: Generated<number>;
parent_id: number | null;
user_id: number;
master_encryption_key_version: number;
encrypted_data_encryption_key: string; // Base64
data_encryption_key_version: Date;
encrypted_name: Ciphertext;
}
interface DirectoryLogTable {
id: Generated<number>;
directory_id: number;
timestamp: ColumnType<Date, Date, never>;
action: "create" | "rename";
new_name: Ciphertext | null;
}
interface FileTable {
id: Generated<number>;
parent_id: number | null;
user_id: number;
path: string;
master_encryption_key_version: number;
encrypted_data_encryption_key: string; // Base64
data_encryption_key_version: Date;
hmac_secret_key_version: number | null;
content_hmac: string | null; // Base64
content_type: string;
encrypted_content_iv: string; // Base64
encrypted_content_hash: string; // Base64
encrypted_name: Ciphertext;
encrypted_created_at: Ciphertext | null;
encrypted_last_modified_at: Ciphertext;
}
interface FileLogTable {
id: Generated<number>;
file_id: number;
timestamp: ColumnType<Date, Date, never>;
action: "create" | "rename";
new_name: Ciphertext | null;
}
declare module "./index" {
interface Database {
directory: DirectoryTable;
directory_log: DirectoryLogTable;
file: FileTable;
file_log: FileLogTable;
}
}

View File

@@ -1,4 +1,5 @@
import { sqliteTable, text, integer, primaryKey, foreignKey } from "drizzle-orm/sqlite-core";
import type { ColumnType, Generated } from "kysely";
import { client } from "./client";
import { mek } from "./mek";
import { user } from "./user";
@@ -42,3 +43,27 @@ export const hskLog = sqliteTable(
}),
}),
);
interface HskTable {
user_id: number;
version: number;
state: "active";
master_encryption_key_version: number;
encrypted_key: string; // Base64
}
interface HskLogTable {
id: Generated<number>;
user_id: number;
hmac_secret_key_version: number;
timestamp: ColumnType<Date, Date, never>;
action: "create";
action_by: number | null;
}
declare module "./index" {
interface Database {
hmac_secret_key: HskTable;
hmac_secret_key_log: HskLogTable;
}
}

View File

@@ -4,3 +4,5 @@ export * from "./hsk";
export * from "./mek";
export * from "./session";
export * from "./user";
export interface Database {}

View File

@@ -1,4 +1,5 @@
import { sqliteTable, text, integer, primaryKey, foreignKey } from "drizzle-orm/sqlite-core";
import type { ColumnType, Generated } from "kysely";
import { client } from "./client";
import { user } from "./user";
@@ -58,3 +59,34 @@ export const clientMek = sqliteTable(
}),
}),
);
interface MekTable {
user_id: number;
version: number;
state: "active" | "retired" | "dead";
}
interface MekLogTable {
id: Generated<number>;
user_id: number;
master_encryption_key_version: number;
timestamp: ColumnType<Date, Date, never>;
action: "create";
action_by: number | null;
}
interface ClientMekTable {
user_id: number;
client_id: number;
version: number;
encrypted_key: string; // Base64
encrypted_key_signature: string; // Base64
}
declare module "./index" {
interface Database {
master_encryption_key: MekTable;
master_encryption_key_log: MekLogTable;
client_master_encryption_key: ClientMekTable;
}
}

View File

@@ -1,4 +1,5 @@
import { sqliteTable, text, integer, unique } from "drizzle-orm/sqlite-core";
import type { ColumnType, Generated } from "kysely";
import { client } from "./client";
import { user } from "./user";
@@ -33,3 +34,29 @@ export const sessionUpgradeChallenge = sqliteTable("session_upgrade_challenge",
allowedIp: text("allowed_ip").notNull(),
expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(),
});
interface SessionTable {
id: string;
user_id: number;
client_id: number | null;
created_at: ColumnType<Date, Date, never>;
last_used_at: Date;
last_used_by_ip: string | null;
last_used_by_agent: string | null;
}
interface SessionUpgradeChallengeTable {
id: Generated<number>;
session_id: string;
client_id: number;
answer: string; // Base64
allowed_ip: string;
expires_at: ColumnType<Date, Date, never>;
}
declare module "./index" {
interface Database {
session: SessionTable;
session_upgrade_challenge: SessionUpgradeChallengeTable;
}
}

View File

@@ -1,4 +1,5 @@
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
import type { Generated } from "kysely";
export const user = sqliteTable("user", {
id: integer("id").primaryKey({ autoIncrement: true }),
@@ -6,3 +7,16 @@ export const user = sqliteTable("user", {
password: text("password").notNull(),
nickname: text("nickname").notNull(),
});
interface UserTable {
id: Generated<number>;
email: string;
nickname: string;
password: string;
}
declare module "./index" {
interface Database {
user: UserTable;
}
}