diff --git a/packages/app/package.json b/packages/app/package.json index eabb863b..6b487ed1 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -14,6 +14,7 @@ "@scure/bip39": "^1.1.1", "@snort/nostr": "^1.0.0", "@szhsin/react-menu": "^3.3.1", + "@void-cat/api": "^1.0.4", "base32-decode": "^1.0.0", "bech32": "^2.0.0", "dexie": "^3.2.2", diff --git a/packages/app/src/Upload/VoidCat.ts b/packages/app/src/Upload/VoidCat.ts index bc7e014c..9dc7dfd6 100644 --- a/packages/app/src/Upload/VoidCat.ts +++ b/packages/app/src/Upload/VoidCat.ts @@ -1,5 +1,6 @@ -import * as utils from "@noble/curves/abstract/utils"; import { EventKind } from "@snort/nostr"; +import { VoidApi } from "@void-cat/api"; + import { FileExtensionRegex, VoidCatHost } from "Const"; import { EventPublisher } from "System/EventPublisher"; import { UploadResult } from "Upload"; @@ -9,98 +10,54 @@ import { magnetURIDecode } from "Util"; * Upload file to void.cat * https://void.cat/swagger/index.html */ -export default async function VoidCat( +export default async function VoidCatUpload( file: File | Blob, filename: string, publisher?: EventPublisher ): Promise { - const buf = await file.arrayBuffer(); - const digest = await crypto.subtle.digest("SHA-256", buf); + const api = new VoidApi(VoidCatHost); + const uploader = api.getUploader(file); - const req = await fetch(`${VoidCatHost}/upload`, { - mode: "cors", - method: "POST", - body: buf, - headers: { - "Content-Type": "application/octet-stream", - "V-Content-Type": file.type, - "V-Filename": filename, - "V-Full-Digest": utils.bytesToHex(new Uint8Array(digest)), - "V-Description": "Upload from https://snort.social", - "V-Strip-Metadata": "true", - }, + const rsp = await uploader.upload({ + "V-Strip-Metadata": "true", }); - - if (req.ok) { - const rsp: VoidUploadResponse = await req.json(); - if (rsp.ok) { - let ext = filename.match(FileExtensionRegex); - if (rsp.file?.metadata?.mimeType === "image/webp") { - ext = ["", "webp"]; - } - const resultUrl = rsp.file?.metadata?.url ?? `${VoidCatHost}/d/${rsp.file?.id}${ext ? `.${ext[1]}` : ""}`; - - const ret = { - url: resultUrl, - } as UploadResult; - - if (publisher) { - const tags = [ - ["url", resultUrl], - ["x", rsp.file?.metadata?.digest ?? ""], - ["m", rsp.file?.metadata?.mimeType ?? "application/octet-stream"], - ]; - if (rsp.file?.metadata?.size) { - tags.push(["size", rsp.file.metadata.size.toString()]); - } - if (rsp.file?.metadata?.magnetLink) { - tags.push(["magnet", rsp.file.metadata.magnetLink]); - const parsedMagnet = magnetURIDecode(rsp.file.metadata.magnetLink); - if (parsedMagnet?.infoHash) { - tags.push(["i", parsedMagnet?.infoHash]); - } - } - ret.header = await publisher.generic(eb => { - eb.kind(EventKind.FileHeader).content(filename); - tags.forEach(t => eb.tag(t)); - return eb; - }); - } - return ret; - } else { - return { - error: rsp.errorMessage, - }; + if (rsp.ok) { + let ext = filename.match(FileExtensionRegex); + if (rsp.file?.metadata?.mimeType === "image/webp") { + ext = ["", "webp"]; } + const resultUrl = rsp.file?.metadata?.url ?? `${VoidCatHost}/d/${rsp.file?.id}${ext ? `.${ext[1]}` : ""}`; + + const ret = { + url: resultUrl, + } as UploadResult; + + if (publisher) { + const tags = [ + ["url", resultUrl], + ["x", rsp.file?.metadata?.digest ?? ""], + ["m", rsp.file?.metadata?.mimeType ?? "application/octet-stream"], + ]; + if (rsp.file?.metadata?.size) { + tags.push(["size", rsp.file.metadata.size.toString()]); + } + if (rsp.file?.metadata?.magnetLink) { + tags.push(["magnet", rsp.file.metadata.magnetLink]); + const parsedMagnet = magnetURIDecode(rsp.file.metadata.magnetLink); + if (parsedMagnet?.infoHash) { + tags.push(["i", parsedMagnet?.infoHash]); + } + } + ret.header = await publisher.generic(eb => { + eb.kind(EventKind.FileHeader).content(filename); + tags.forEach(t => eb.tag(t)); + return eb; + }); + } + return ret; + } else { + return { + error: rsp.errorMessage, + }; } - return { - error: "Upload failed", - }; } - -export type VoidUploadResponse = { - ok: boolean; - file?: VoidFile; - errorMessage?: string; -}; - -export type VoidFile = { - id: string; - metadata?: VoidFileMeta; -}; - -export type VoidFileMeta = { - version: number; - id: string; - name?: string; - size: number; - uploaded: Date; - description?: string; - mimeType?: string; - digest?: string; - url?: string; - expires?: Date; - storage?: string; - encryptionParams?: string; - magnetLink?: string; -}; diff --git a/yarn.lock b/yarn.lock index 6878ed60..1b09ee9f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2587,6 +2587,13 @@ "@typescript-eslint/types" "5.59.0" eslint-visitor-keys "^3.3.0" +"@void-cat/api@^1.0.4": + version "1.0.4" + resolved "https://git.v0l.io/api/packages/Kieran/npm/%40void-cat%2Fapi/-/1.0.4/api-1.0.4.tgz#2e2f6eddc198fcf64d7e8b1fe7326641a6ce0d43" + integrity sha512-xGAGTWrra1UxoCAvbHLUQc/ibp7/tzgUay/F3fOklVpRPzFs8bdgc35v+EEQKHT7U5RXzCkdWjyfs+5NMESlxg== + dependencies: + sjcl "^1.0.8" + "@webassemblyjs/ast@1.11.1": version "1.11.1" resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz" @@ -8209,6 +8216,11 @@ sirv@^1.0.7: mrmime "^1.0.0" totalist "^1.0.0" +sjcl@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/sjcl/-/sjcl-1.0.8.tgz#f2ec8d7dc1f0f21b069b8914a41a8f236b0e252a" + integrity sha512-LzIjEQ0S0DpIgnxMEayM1rq9aGwGRG4OnZhCdjx7glTaJtf4zRfpg87ImfjSJjoW9vKpagd82McDOwbRT5kQKQ== + slash@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"