embed schema and dao
This commit is contained in:
parent
a2569a2b34
commit
a797aa00e9
@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- A unique constraint covering the columns `[note_id,embed_id]` on the table `EncryptedEmbed` will be added. If there are existing duplicate values, this will fail.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "EncryptedEmbed_note_id_embed_id_key" ON "EncryptedEmbed"("note_id", "embed_id");
|
@ -28,6 +28,8 @@ model EncryptedEmbed {
|
|||||||
hmac String
|
hmac String
|
||||||
size_bytes Int
|
size_bytes Int
|
||||||
note EncryptedNote @relation(fields: [note_id], references: [id])
|
note EncryptedNote @relation(fields: [note_id], references: [id])
|
||||||
|
|
||||||
|
@@unique([note_id, embed_id], name: "noteId_embedId")
|
||||||
}
|
}
|
||||||
|
|
||||||
model event {
|
model event {
|
||||||
|
85
server/src/db/embed.dao.integration.test.ts
Normal file
85
server/src/db/embed.dao.integration.test.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { describe, it, expect } from "vitest";
|
||||||
|
import type { EncryptedEmbed, EncryptedNote } from "@prisma/client";
|
||||||
|
import { getEmbed, createEmbed } from "./embed.dao";
|
||||||
|
import { createNote } from "./note.dao";
|
||||||
|
|
||||||
|
const VALID_CIPHERTEXT = Buffer.from("sample_ciphertext").toString("base64");
|
||||||
|
|
||||||
|
describe("Reading and writing embeds", () => {
|
||||||
|
it("Should write embeds for existing note", async () => {
|
||||||
|
const note = await createNote({
|
||||||
|
ciphertext: "test",
|
||||||
|
hmac: "test",
|
||||||
|
crypto_version: "v2",
|
||||||
|
} as EncryptedNote);
|
||||||
|
|
||||||
|
const embed = {
|
||||||
|
note_id: note.id,
|
||||||
|
embed_id: "embed_id",
|
||||||
|
hmac: "hmac",
|
||||||
|
ciphertext: VALID_CIPHERTEXT,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await createEmbed(embed);
|
||||||
|
|
||||||
|
expect(res.note_id).toEqual(embed.note_id);
|
||||||
|
expect(res.embed_id).toEqual(embed.embed_id);
|
||||||
|
expect(res.hmac).toEqual(embed.hmac);
|
||||||
|
expect(res.id).not.toBeNull();
|
||||||
|
expect(res.id.length).toBeGreaterThan(0);
|
||||||
|
expect(res.ciphertext.byteLength).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should throw if note_id does not refer to existing note", async () => {
|
||||||
|
const embed = {
|
||||||
|
note_id: "note_id",
|
||||||
|
embed_id: "embed_id",
|
||||||
|
hmac: "hmac",
|
||||||
|
ciphertext: VALID_CIPHERTEXT,
|
||||||
|
};
|
||||||
|
|
||||||
|
await expect(createEmbed(embed)).rejects.toThrowError();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should throw if embed_id is not unique", async () => {
|
||||||
|
const note = await createNote({
|
||||||
|
ciphertext: "test",
|
||||||
|
hmac: "test",
|
||||||
|
crypto_version: "v2",
|
||||||
|
} as EncryptedNote);
|
||||||
|
|
||||||
|
const embed = {
|
||||||
|
note_id: note.id,
|
||||||
|
embed_id: "embed_id",
|
||||||
|
hmac: "hmac",
|
||||||
|
ciphertext: VALID_CIPHERTEXT,
|
||||||
|
};
|
||||||
|
|
||||||
|
await createEmbed(embed); // embed 1
|
||||||
|
await expect(createEmbed(embed)).rejects.toThrowError(); // duplicate embed
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should read embeds for existing note", async () => {
|
||||||
|
const note = await createNote({
|
||||||
|
ciphertext: "test",
|
||||||
|
hmac: "test",
|
||||||
|
crypto_version: "v2",
|
||||||
|
} as EncryptedNote);
|
||||||
|
|
||||||
|
const embed = {
|
||||||
|
note_id: note.id,
|
||||||
|
embed_id: "embed_id",
|
||||||
|
hmac: "hmac",
|
||||||
|
ciphertext: VALID_CIPHERTEXT,
|
||||||
|
};
|
||||||
|
|
||||||
|
await createEmbed(embed);
|
||||||
|
const res = await getEmbed(note.id, embed.embed_id);
|
||||||
|
|
||||||
|
expect(res).not.toBeNull();
|
||||||
|
expect(res?.note_id).toEqual(embed.note_id);
|
||||||
|
expect(res?.embed_id).toEqual(embed.embed_id);
|
||||||
|
expect(res?.hmac).toEqual(embed.hmac);
|
||||||
|
expect(res?.ciphertext).toEqual(embed.ciphertext);
|
||||||
|
});
|
||||||
|
});
|
49
server/src/db/embed.dao.ts
Normal file
49
server/src/db/embed.dao.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { EncryptedEmbed } from "@prisma/client";
|
||||||
|
import { BufferToBase64, base64ToBuffer } from "../util";
|
||||||
|
import prisma from "./client";
|
||||||
|
|
||||||
|
export interface EncryptedEmbedDTO {
|
||||||
|
note_id: string;
|
||||||
|
embed_id: string;
|
||||||
|
ciphertext: string; // in base64
|
||||||
|
hmac: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getEmbed(
|
||||||
|
noteId: string,
|
||||||
|
embedId: string
|
||||||
|
): Promise<EncryptedEmbedDTO | null> {
|
||||||
|
const embed = await prisma.encryptedEmbed.findUnique({
|
||||||
|
where: {
|
||||||
|
noteId_embedId: {
|
||||||
|
note_id: noteId,
|
||||||
|
embed_id: embedId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!embed) return null;
|
||||||
|
|
||||||
|
console.log(embed.ciphertext.byteLength, embed.size_bytes);
|
||||||
|
|
||||||
|
return {
|
||||||
|
note_id: embed.note_id,
|
||||||
|
embed_id: embed.embed_id,
|
||||||
|
hmac: embed.hmac,
|
||||||
|
ciphertext: BufferToBase64(embed.ciphertext),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createEmbed(
|
||||||
|
embed: EncryptedEmbedDTO
|
||||||
|
): Promise<EncryptedEmbed> {
|
||||||
|
const cipher_buf = base64ToBuffer(embed.ciphertext);
|
||||||
|
const data = {
|
||||||
|
note_id: embed.note_id,
|
||||||
|
embed_id: embed.embed_id,
|
||||||
|
hmac: embed.hmac,
|
||||||
|
ciphertext: cipher_buf,
|
||||||
|
size_bytes: cipher_buf.byteLength,
|
||||||
|
} as EncryptedEmbed;
|
||||||
|
return prisma.encryptedEmbed.create({ data });
|
||||||
|
}
|
@ -13,11 +13,11 @@ export function getConnectingIp(req: Request): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// base64 to array buffer (Node JS api, so don't use atob or btoa)
|
// base64 to array buffer (Node JS api, so don't use atob or btoa)
|
||||||
export function base64ToArrayBuffer(base64: string): ArrayBuffer {
|
export function base64ToBuffer(base64: string): Buffer {
|
||||||
return Buffer.from(base64, "base64");
|
return Buffer.from(base64, "base64");
|
||||||
}
|
}
|
||||||
|
|
||||||
// array buffer to base64 (Node JS api, so don't use atob or btoa)
|
// array buffer to base64 (Node JS api, so don't use atob or btoa)
|
||||||
export function arrayBufferToBase64(buffer: ArrayBuffer): string {
|
export function BufferToBase64(buffer: Buffer): string {
|
||||||
return Buffer.from(buffer).toString("base64");
|
return Buffer.from(buffer).toString("base64");
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { describe, it, expect } from "vitest";
|
import { describe, it, expect } from "vitest";
|
||||||
import {
|
import {
|
||||||
addDays,
|
addDays,
|
||||||
arrayBufferToBase64,
|
BufferToBase64,
|
||||||
base64ToArrayBuffer,
|
base64ToBuffer,
|
||||||
getConnectingIp,
|
getConnectingIp,
|
||||||
} from "./util";
|
} from "./util";
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ describe("converting to/from base64", () => {
|
|||||||
it("Should convert a base64 string to an array buffer", () => {
|
it("Should convert a base64 string to an array buffer", () => {
|
||||||
const base64 = "EjRWeJA=";
|
const base64 = "EjRWeJA=";
|
||||||
const expectedBuffer = new Uint8Array([18, 52, 86, 120, 144]);
|
const expectedBuffer = new Uint8Array([18, 52, 86, 120, 144]);
|
||||||
expect(new Uint8Array(base64ToArrayBuffer(base64))).toStrictEqual(
|
expect(new Uint8Array(base64ToBuffer(base64))).toStrictEqual(
|
||||||
expectedBuffer
|
expectedBuffer
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -26,6 +26,6 @@ describe("converting to/from base64", () => {
|
|||||||
it("Should convert an array buffer to a base64 string", () => {
|
it("Should convert an array buffer to a base64 string", () => {
|
||||||
const buffer = new Uint8Array([18, 52, 86, 120, 144]);
|
const buffer = new Uint8Array([18, 52, 86, 120, 144]);
|
||||||
const expectedBase64 = "EjRWeJA=";
|
const expectedBase64 = "EjRWeJA=";
|
||||||
expect(arrayBufferToBase64(buffer)).toEqual(expectedBase64);
|
expect(BufferToBase64(buffer)).toEqual(expectedBase64);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user