From 82900adef8d093cf41c238230578610ae4050467 Mon Sep 17 00:00:00 2001 From: cupcakearmy Date: Sat, 12 Sep 2026 09:57:54 +0200 Subject: [PATCH] refactor: extract payload pack/unpack pipeline into @cryptgeon/shared --- packages/cli/src/actions/download.ts | 5 +- packages/cli/src/actions/upload.ts | 53 +++++++++---------- packages/frontend/src/lib/views/Create.svelte | 49 +++++++++-------- .../src/routes/note/[id]/+page.svelte | 5 +- packages/shared/src/index.ts | 1 + packages/shared/src/payload.test.ts | 31 +++++++++++ packages/shared/src/payload.ts | 49 +++++++++++++++++ 7 files changed, 133 insertions(+), 60 deletions(-) create mode 100644 packages/shared/src/payload.test.ts create mode 100644 packages/shared/src/payload.ts diff --git a/packages/cli/src/actions/download.ts b/packages/cli/src/actions/download.ts index 6953786..f96a643 100644 --- a/packages/cli/src/actions/download.ts +++ b/packages/cli/src/actions/download.ts @@ -3,7 +3,7 @@ import { access, constants, writeFile } from 'node:fs/promises' import { basename, resolve } from 'node:path' import { decode } from '@msgpack/msgpack' import pretty from 'pretty-bytes' -import { decrypt, deriveKey, setServer, info, get, decompress } from '@cryptgeon/shared' +import { deriveKey, setServer, info, get, unpackContent } from '@cryptgeon/shared' export async function download(url: URL, all: boolean, suggestedPassword?: string) { setServer(url.origin) @@ -32,8 +32,7 @@ export async function download(url: URL, all: boolean, suggestedPassword?: strin const note = await get(id) if (!note) throw new Error('Could not load note') - const decrypted = decrypt(note.data, key) - const content = decode(decompress(decrypted)) as any + const content = unpackContent(note.data, key) switch (content.type) { case 'files': diff --git a/packages/cli/src/actions/upload.ts b/packages/cli/src/actions/upload.ts index 7cbccc3..ff25662 100644 --- a/packages/cli/src/actions/upload.ts +++ b/packages/cli/src/actions/upload.ts @@ -1,43 +1,38 @@ import { readFile } from 'node:fs/promises' import { basename } from 'node:path' -import { encode } from '@msgpack/msgpack' import mime from 'mime' -import { encrypt, generateKey, deriveKey, randomBytes, getServer, create, compress } from '@cryptgeon/shared' +import { getServer, create, packContent, type FileDTO } from '@cryptgeon/shared' export type UploadOptions = { views?: number; expiration?: number; password?: string } export async function upload(input: string | string[], options: UploadOptions): Promise { const { password, ...noteOptions } = options - let key: Uint8Array - let extra = new Uint8Array() - if (password) { - const salt = randomBytes(16) - key = deriveKey(password, salt) - extra = encode({ salt, N: 32768, r: 8, p: 1 }) - } else { - key = generateKey() - } + const payload = packContent( + typeof input === 'string' + ? { type: 'text', text: input } + : { type: 'files', files: await fileDTOSfromPaths(input) }, + password + ) - let inner: Uint8Array - if (typeof input === 'string') { - inner = encode({ type: 'text', data: input }) - } else { - const files = await Promise.all( - input.map(async (path) => { - const data = new Uint8Array(await readFile(path)) - const extension = path.substring(path.indexOf('.') + 1) - const type = mime.getType(extension) ?? 'application/octet-stream' - return { name: basename(path), mime: type, size: data.length, data } - }) - ) - inner = encode({ type: 'files', data: files }) - } - - const data = encrypt(compress(inner), key) - const result = await create({ meta: { ...noteOptions, extra }, data }) + const result = await create({ meta: { ...noteOptions, extra: payload.extra }, data: payload.data }) let url = `${getServer()}/note/${result.id}` - if (!password) url += `#${Buffer.from(key).toString('hex')}` + if (!password) url += `#${Buffer.from(payload.key).toString('hex')}` return url +} + +async function fileDTOSfromPaths(paths: string[]): Promise { + return Promise.all( + paths.map(async (path) => { + const extension = path.substring(path.indexOf('.') + 1) + const data = new Uint8Array(await readFile(path)) + return { + name: basename(path), + mime: mime.getType(extension) ?? 'application/octet-stream', + size: data.length, + data, + } + }) + ) } \ No newline at end of file diff --git a/packages/frontend/src/lib/views/Create.svelte b/packages/frontend/src/lib/views/Create.svelte index 6f53b6b..d45d9c1 100644 --- a/packages/frontend/src/lib/views/Create.svelte +++ b/packages/frontend/src/lib/views/Create.svelte @@ -1,9 +1,9 @@