refactor: extract payload pack/unpack pipeline into @cryptgeon/shared

This commit is contained in:
2026-09-12 10:01:49 +02:00
parent 77b7ae1de6
commit 82900adef8
7 changed files with 133 additions and 60 deletions
+24 -29
View File
@@ -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<string> {
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<FileDTO[]> {
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,
}
})
)
}