diff options
| author | Adam Soltys <[email protected]> | 2026-03-07 08:54:47 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-03-07 08:54:47 -0800 |
| commit | ad0b4009b2b2ae9173fffb41f0cfa7b35edcb303 (patch) | |
| tree | 49c2eceb273b73ce5b9c0aba74dafbf6fddce442 /src/lib | |
| parent | 13b2a17e6f6ed1697c51a6650874313a6da4aa8f (diff) | |
| download | coinos-ui-ad0b4009b2b2ae9173fffb41f0cfa7b35edcb303.tar.gz coinos-ui-ad0b4009b2b2ae9173fffb41f0cfa7b35edcb303.zip | |
image upload
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/messaging.ts | 1 | ||||
| -rw-r--r-- | src/lib/mls-relay.ts | 60 |
2 files changed, 61 insertions, 0 deletions
diff --git a/src/lib/messaging.ts b/src/lib/messaging.ts index ba2d21ad..4cebd2b0 100644 --- a/src/lib/messaging.ts +++ b/src/lib/messaging.ts @@ -12,6 +12,7 @@ export { getGroups, getGroupRumours, sendGroupMessage, + sendGroupMediaMessage, findOrCreateDmGroup, subscribeToMessages, fetchGroupHistory, diff --git a/src/lib/mls-relay.ts b/src/lib/mls-relay.ts index 5eb8dbe3..d29cd535 100644 --- a/src/lib/mls-relay.ts +++ b/src/lib/mls-relay.ts @@ -10,8 +10,12 @@ import { SimplePool } from "nostr-tools/pool"; import { Relay } from "nostr-tools/relay"; import { getMarmotClient, getInviteReader, DM_RELAYS } from "$lib/marmot"; import { parseMediaImetaTag } from "@internet-privacy/marmot-ts"; +import { BlossomClient } from "nostr-tools/nipb7"; +import { ensureSigner } from "$lib/nip07"; import { post } from "$lib/utils"; +const BLOSSOM_SERVER = "https://blossom.primal.net"; + const pool = new SimplePool(); /** Extract member pubkeys from an MLS group's ratchet tree (pass group.state). */ @@ -412,6 +416,62 @@ export async function sendGroupMessage( cacheGroupRumour(groupId, rumour); } +/** Send a media message (image/video/audio) to a group. */ +export async function sendGroupMediaMessage( + user: any, + groupId: string, + file: File | Blob, +): Promise<void> { + const client = getMarmotClient(user.pubkey); + const group = await client.getGroup(groupId); + + const mime = file.type || "application/octet-stream"; + const filename = file instanceof File ? file.name : "file"; + + // Encrypt with MLS group key + const { encrypted, attachment } = await group.encryptMedia(file, { + type: mime, + filename, + }); + + // Upload encrypted blob to blossom + const sk = await ensureSigner(user.pubkey); + const signer = sk + ? { + getPublicKey: () => user.pubkey, + signEvent: async (draft: any) => { + const { finalizeEvent } = await import("nostr-tools/pure"); + return finalizeEvent(draft, sk); + }, + } + : (window as any).nostr; + + const blossom = new BlossomClient(BLOSSOM_SERVER, signer); + const encryptedBlob = new Blob([encrypted as BlobPart], { type: "application/octet-stream" }); + const desc = await blossom.uploadBlob(encryptedBlob); + + // Build imeta tag with the upload URL and MIP-04 fields + const imetaTag = [ + "imeta", + `url ${desc.url}`, + `m ${attachment.type}`, + `x ${attachment.sha256}`, + `filename ${attachment.filename}`, + `n ${attachment.nonce}`, + `v ${attachment.version}`, + ]; + if (attachment.size) imetaTag.push(`size ${attachment.size}`); + + // Pre-cache plaintext so the image renders instantly for us + await putCachedMedia(attachment.sha256, file, mime); + + // Send as chat message with the imeta tag + await group.sendChatMessage("", [imetaTag]); + + const rumour = makeRumour("", user.pubkey, groupId, [imetaTag]); + cacheGroupRumour(groupId, rumour); +} + // --------------------------------------------------------------------------- // Dynamic group subscription // --------------------------------------------------------------------------- |
