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
|
||||
size_bytes Int
|
||||
note EncryptedNote @relation(fields: [note_id], references: [id])
|
||||
|
||||
@@unique([note_id, embed_id], name: "noteId_embedId")
|
||||
}
|
||||
|
||||
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)
|
||||
export function base64ToArrayBuffer(base64: string): ArrayBuffer {
|
||||
export function base64ToBuffer(base64: string): Buffer {
|
||||
return Buffer.from(base64, "base64");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import {
|
||||
addDays,
|
||||
arrayBufferToBase64,
|
||||
base64ToArrayBuffer,
|
||||
BufferToBase64,
|
||||
base64ToBuffer,
|
||||
getConnectingIp,
|
||||
} from "./util";
|
||||
|
||||
@ -18,7 +18,7 @@ describe("converting to/from base64", () => {
|
||||
it("Should convert a base64 string to an array buffer", () => {
|
||||
const base64 = "EjRWeJA=";
|
||||
const expectedBuffer = new Uint8Array([18, 52, 86, 120, 144]);
|
||||
expect(new Uint8Array(base64ToArrayBuffer(base64))).toStrictEqual(
|
||||
expect(new Uint8Array(base64ToBuffer(base64))).toStrictEqual(
|
||||
expectedBuffer
|
||||
);
|
||||
});
|
||||
@ -26,6 +26,6 @@ describe("converting to/from base64", () => {
|
||||
it("Should convert an array buffer to a base64 string", () => {
|
||||
const buffer = new Uint8Array([18, 52, 86, 120, 144]);
|
||||
const expectedBase64 = "EjRWeJA=";
|
||||
expect(arrayBufferToBase64(buffer)).toEqual(expectedBase64);
|
||||
expect(BufferToBase64(buffer)).toEqual(expectedBase64);
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user