forked from coracle/flotilla
Use new editor uploads
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
<script lang="ts">
|
||||
import {onMount, onDestroy} from "svelte"
|
||||
import {displayUrl} from "@welshman/lib"
|
||||
import {getTags, getTagValue, tagsFromIMeta} from "@welshman/util"
|
||||
import {decryptFile} from "@welshman/editor"
|
||||
import {getTags, decryptFile, getTagValue, tagsFromIMeta} from "@welshman/util"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import {imgproxy} from "@app/state"
|
||||
|
||||
@@ -16,7 +15,7 @@
|
||||
|
||||
const key = getTagValue("decryption-key", meta)
|
||||
const nonce = getTagValue("decryption-nonce", meta)
|
||||
const encryptionAlgorithm = getTagValue("encryption-algorithm", meta)
|
||||
const algorithm = getTagValue("encryption-algorithm", meta)
|
||||
|
||||
const onError = () => {
|
||||
hasError = true
|
||||
@@ -26,14 +25,14 @@
|
||||
let src = $state(imgproxy(url))
|
||||
|
||||
onMount(async () => {
|
||||
if (encryptionAlgorithm === "aes-gcm" && key && nonce) {
|
||||
if (algorithm === "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})
|
||||
const decryptedData = await decryptFile({ciphertext, key, nonce, algorithm})
|
||||
|
||||
src = URL.createObjectURL(new Blob([new Uint8Array(decryptedData)]))
|
||||
src = URL.createObjectURL(new Blob([decryptedData]))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import {encrypt} from "nostr-tools/nip49"
|
||||
import {hexToBytes} from "@noble/hashes/utils"
|
||||
import {hexToBytes} from "@welshman/lib"
|
||||
import {makeSecret} from "@welshman/signer"
|
||||
import {preventDefault, downloadText} from "@lib/html"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
|
||||
+78
-13
@@ -1,15 +1,25 @@
|
||||
import {mount} from "svelte"
|
||||
import type {Writable} from "svelte/store"
|
||||
import {get} from "svelte/store"
|
||||
import type {StampedEvent} from "@welshman/util"
|
||||
import {getTagValues, getListTags} from "@welshman/util"
|
||||
import {sha256} from "@welshman/lib"
|
||||
import {
|
||||
getTagValues,
|
||||
getTagValue,
|
||||
encryptFile,
|
||||
uploadBlob,
|
||||
makeBlossomAuthEvent,
|
||||
getListTags,
|
||||
} from "@welshman/util"
|
||||
import {Router} from "@welshman/router"
|
||||
import {Nip01Signer} from "@welshman/signer"
|
||||
import {signer, profileSearch, userBlossomServers} from "@welshman/app"
|
||||
import type {FileAttributes} from "@welshman/editor"
|
||||
import {Editor, MentionSuggestion, WelshmanExtension} from "@welshman/editor"
|
||||
import {makeMentionNodeView} from "./MentionNodeView"
|
||||
import ProfileSuggestion from "./ProfileSuggestion.svelte"
|
||||
import {pushToast} from "@app/toast"
|
||||
|
||||
export const getUploadUrl = () => {
|
||||
export const getBlossomServer = () => {
|
||||
const userUrls = getTagValues("server", getListTags(userBlossomServers.get()))
|
||||
|
||||
for (const url of userUrls) {
|
||||
@@ -19,12 +29,6 @@ export const getUploadUrl = () => {
|
||||
return "https://cdn.satellite.earth"
|
||||
}
|
||||
|
||||
export const signWithAssert = async (template: StampedEvent) => {
|
||||
const event = await signer.get().sign(template)
|
||||
|
||||
return event!
|
||||
}
|
||||
|
||||
export const makeEditor = async ({
|
||||
aggressive = false,
|
||||
autofocus = false,
|
||||
@@ -53,9 +57,6 @@ export const makeEditor = async ({
|
||||
extensions: [
|
||||
WelshmanExtension.configure({
|
||||
submit,
|
||||
sign: signWithAssert,
|
||||
defaultUploadType: "blossom",
|
||||
defaultUploadUrl: getUploadUrl(),
|
||||
extensions: {
|
||||
placeholder: {
|
||||
config: {
|
||||
@@ -69,13 +70,77 @@ export const makeEditor = async ({
|
||||
},
|
||||
fileUpload: {
|
||||
config: {
|
||||
encryptionAlgorithm: "aes-gcm",
|
||||
upload: async (attrs: FileAttributes) => {
|
||||
let file: Blob = attrs.file
|
||||
|
||||
if (!file.type.match("image/(webp|gif)")) {
|
||||
const {default: Compressor} = await import("compressorjs")
|
||||
|
||||
file = await new Promise((resolve, _reject) => {
|
||||
new Compressor(file, {
|
||||
maxWidth: 1024,
|
||||
maxHeight: 1024,
|
||||
convertSize: 2 * 1024 * 1024,
|
||||
success: resolve,
|
||||
error: e => {
|
||||
// Non-images break compressor
|
||||
if (e.toString().includes("File or Blob")) {
|
||||
return resolve(file)
|
||||
}
|
||||
|
||||
_reject(e)
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const {ciphertext, key, nonce, algorithm} = await encryptFile(file)
|
||||
const tags = [
|
||||
["decryption-key", key],
|
||||
["decryption-nonce", nonce],
|
||||
["encryption-algorithm", algorithm],
|
||||
]
|
||||
|
||||
file = new File([new Blob([ciphertext])], attrs.file.name, {type: attrs.file.type})
|
||||
|
||||
const server = getBlossomServer()
|
||||
const hashes = [await sha256(await file.arrayBuffer())]
|
||||
const $signer = signer.get() || Nip01Signer.ephemeral()
|
||||
const authTemplate = makeBlossomAuthEvent({action: "upload", server, hashes})
|
||||
const authEvent = await $signer.sign(authTemplate)
|
||||
|
||||
try {
|
||||
const res = await uploadBlob(server, file, {authEvent})
|
||||
let {uploaded, url, ...task} = await res.json()
|
||||
|
||||
if (!uploaded) {
|
||||
return {error: "Server refused to process the file"}
|
||||
}
|
||||
|
||||
// Always append file extension if missing
|
||||
if (new URL(url).pathname.split(".").length === 1) {
|
||||
url += "." + attrs.file.type.split("/")[1]
|
||||
}
|
||||
|
||||
const result = {...task, tags, url}
|
||||
|
||||
return {result}
|
||||
} catch (e: any) {
|
||||
console.error(e)
|
||||
return {error: e.toString()}
|
||||
}
|
||||
},
|
||||
onDrop() {
|
||||
uploading?.set(true)
|
||||
},
|
||||
onComplete() {
|
||||
uploading?.set(false)
|
||||
},
|
||||
onUploadError(currentEditor, task) {
|
||||
currentEditor.commands.removeFailedUploads()
|
||||
pushToast({theme: "error", message: "Failed to upload file"})
|
||||
uploading?.set(false)
|
||||
},
|
||||
},
|
||||
},
|
||||
nprofile: {
|
||||
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
import {hexToBytes, bytesToHex} from "@noble/hashes/utils"
|
||||
import * as nip19 from "nostr-tools/nip19"
|
||||
import {range, DAY} from "@welshman/lib"
|
||||
import {range, DAY, hexToBytes, bytesToHex} from "@welshman/lib"
|
||||
|
||||
export const nsecEncode = (secret: string) => nip19.nsecEncode(hexToBytes(secret))
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
import {App} from "@capacitor/app"
|
||||
import {dev} from "$app/environment"
|
||||
import {goto} from "$app/navigation"
|
||||
import {bytesToHex, hexToBytes} from "@noble/hashes/utils"
|
||||
import {identity, memoize, sleep, defer, ago, WEEK, TaskQueue} from "@welshman/lib"
|
||||
import type {TrustedEvent, StampedEvent} from "@welshman/util"
|
||||
import {
|
||||
@@ -80,8 +79,6 @@
|
||||
Object.assign(window, {
|
||||
get,
|
||||
nip19,
|
||||
bytesToHex,
|
||||
hexToBytes,
|
||||
...lib,
|
||||
...welshmanSigner,
|
||||
...util,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import * as nip19 from "nostr-tools/nip19"
|
||||
import {hexToBytes} from "@noble/hashes/utils"
|
||||
import {hexToBytes} from "@welshman/lib"
|
||||
import {displayPubkey, displayProfile} from "@welshman/util"
|
||||
import {pubkey, session, displayNip05, deriveProfile} from "@welshman/app"
|
||||
import {slideAndFade} from "@lib/transition"
|
||||
|
||||
Reference in New Issue
Block a user