Use encrypted uploads

This commit is contained in:
Jon Staab 2025-06-03 10:41:38 -07:00
parent c4a1ad2e33
commit 55efb3fdfd
4 changed files with 52 additions and 18 deletions

Binary file not shown.

View file

@ -20,6 +20,8 @@
export const focus = () => editor.then(ed => ed.chain().focus().run()) export const focus = () => editor.then(ed => ed.chain().focus().run())
const uploadFiles = () => editor.then(ed => ed.chain().selectFiles().run())
const submit = async () => { const submit = async () => {
if ($uploading) return if ($uploading) return
@ -40,11 +42,21 @@
submit, submit,
uploading, uploading,
aggressive: true, aggressive: true,
disableFileUpload: true,
}) })
</script> </script>
<form class="relative z-feature flex gap-2 p-2" onsubmit={preventDefault(submit)}> <form class="relative z-feature flex gap-2 p-2" onsubmit={preventDefault(submit)}>
<Button
data-tip="Add an image"
class="center tooltip tooltip-right h-10 w-10 min-w-10 rounded-box bg-base-300 transition-colors hover:bg-base-200"
disabled={$uploading}
onclick={uploadFiles}>
{#if $uploading}
<span class="loading loading-spinner loading-xs"></span>
{:else}
<Icon icon="gallery-send" />
{/if}
</Button>
<div class="chat-editor flex-grow overflow-hidden"> <div class="chat-editor flex-grow overflow-hidden">
<EditorContent {editor} /> <EditorContent {editor} />
</div> </div>

View file

@ -1,14 +1,39 @@
<script lang="ts"> <script lang="ts">
import {onMount, onDestroy} from "svelte"
import {getTags, getTagValue, tagsFromIMeta} from "@welshman/util" import {getTags, getTagValue, tagsFromIMeta} from "@welshman/util"
import {decryptFile} from "@welshman/editor"
import {imgproxy} from "@app/state" import {imgproxy} from "@app/state"
const {value, event, ...props} = $props() const {value, event, ...props} = $props()
const url = value.url.toString() const url = value.url.toString()
const meta = getTags("imeta", event.tags) const meta =
.map(tagsFromIMeta) getTags("imeta", event.tags)
.find(meta => getTagValue("url", meta) === url) .map(tagsFromIMeta)
const src = imgproxy(url) .find(meta => getTagValue("url", meta) === url) || []
const key = getTagValue("decryption-key", meta)
const nonce = getTagValue("decryption-nonce", meta)
const encryptionAlgorithm = getTagValue("encryption-algorithm", meta)
let src = $state(imgproxy(url))
onMount(async () => {
if (encryptionAlgorithm === "aes-gcm" && key && nonce) {
const response = await fetch(url)
if (response.ok) {
const ciphertext = new Uint8Array(await response.arrayBuffer())
const decryptedData = decryptFile({ciphertext, key, nonce, encryptionAlgorithm})
src = URL.createObjectURL(new Blob([new Uint8Array(decryptedData)]))
}
}
})
onDestroy(() => {
URL.revokeObjectURL(src)
})
</script> </script>
<img alt="" {src} {...props} /> <img alt="" {src} {...props} />

View file

@ -35,7 +35,6 @@ export const makeEditor = async ({
submit, submit,
uploading, uploading,
wordCount, wordCount,
disableFileUpload,
}: { }: {
aggressive?: boolean aggressive?: boolean
autofocus?: boolean autofocus?: boolean
@ -46,7 +45,6 @@ export const makeEditor = async ({
submit: () => void submit: () => void
uploading?: Writable<boolean> uploading?: Writable<boolean>
wordCount?: Writable<number> wordCount?: Writable<number>
disableFileUpload?: boolean
}) => { }) => {
return new Editor({ return new Editor({
content, content,
@ -69,18 +67,17 @@ export const makeEditor = async ({
aggressive, aggressive,
}, },
}, },
fileUpload: disableFileUpload fileUpload: {
? false config: {
: { encryptionAlgorithm: "aes-gcm",
config: { onDrop() {
onDrop() { uploading?.set(true)
uploading?.set(true)
},
onComplete() {
uploading?.set(false)
},
},
}, },
onComplete() {
uploading?.set(false)
},
},
},
nprofile: { nprofile: {
extend: { extend: {
addNodeView: () => makeMentionNodeView(url), addNodeView: () => makeMentionNodeView(url),