184 lines
5.6 KiB
HTML
184 lines
5.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>route96</title>
|
|
<style>
|
|
html {
|
|
background-color: black;
|
|
color: white;
|
|
font-size: 15px;
|
|
font-weight: 400;
|
|
font-family: Arial, serif;
|
|
}
|
|
|
|
.flex {
|
|
display: flex;
|
|
}
|
|
|
|
.flex-col {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.gap-2 {
|
|
gap: 0.5rem;
|
|
}
|
|
</style>
|
|
<script>
|
|
async function dumpToLog(rsp) {
|
|
console.debug(rsp);
|
|
const text = await rsp.text();
|
|
if (rsp.ok) {
|
|
document.querySelector("#log").append(JSON.stringify(JSON.parse(text), undefined, 2));
|
|
} else {
|
|
document.querySelector("#log").append(text);
|
|
}
|
|
document.querySelector("#log").append("\n");
|
|
}
|
|
|
|
async function listFiles() {
|
|
try {
|
|
const auth_event = await window.nostr.signEvent({
|
|
kind: 27235,
|
|
created_at: Math.floor(new Date().getTime() / 1000),
|
|
content: "",
|
|
tags: [
|
|
["u", `${window.location.protocol}//${window.location.host}/n96`],
|
|
["method", "GET"]
|
|
]
|
|
});
|
|
const rsp = await fetch("/n96?page=0&count=100", {
|
|
method: "GET",
|
|
headers: {
|
|
accept: "application/json",
|
|
authorization: `Nostr ${btoa(JSON.stringify(auth_event))}`,
|
|
},
|
|
});
|
|
await dumpToLog(rsp);
|
|
} catch (e) {
|
|
|
|
}
|
|
}
|
|
|
|
async function uploadFiles(e) {
|
|
try {
|
|
const input = document.querySelector("#file");
|
|
const file = input.files[0];
|
|
console.debug(file);
|
|
|
|
const r_nip96 = document.querySelector("#method-nip96").checked;
|
|
const r_blossom = document.querySelector("#method-blossom").checked;
|
|
if (r_nip96) {
|
|
await uploadFilesNip96(file)
|
|
} else if (r_blossom) {
|
|
await uploadBlossom(file);
|
|
}
|
|
} catch (ex) {
|
|
if (ex instanceof Error) {
|
|
alert(ex.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
function buf2hex(buffer) { // buffer is an ArrayBuffer
|
|
return [...new Uint8Array(buffer)]
|
|
.map(x => x.toString(16).padStart(2, '0'))
|
|
.join('');
|
|
}
|
|
|
|
async function uploadBlossom(file) {
|
|
const hash = await window.crypto.subtle.digest("SHA-256", await file.arrayBuffer());
|
|
|
|
const now = Math.floor(new Date().getTime() / 1000);
|
|
const auth_event = await window.nostr.signEvent({
|
|
kind: 24242,
|
|
created_at: now,
|
|
content: `Upload ${file.name}`,
|
|
tags: [
|
|
["t", "upload"],
|
|
["u", `${window.location.protocol}//${window.location.host}/upload`],
|
|
["x", buf2hex(hash)],
|
|
["method", "PUT"],
|
|
["expiration", (now + 10).toString()]
|
|
]
|
|
});
|
|
const rsp = await fetch("/upload", {
|
|
body: file,
|
|
method: "PUT",
|
|
headers: {
|
|
accept: "application/json",
|
|
authorization: `Nostr ${btoa(JSON.stringify(auth_event))}`,
|
|
},
|
|
});
|
|
await dumpToLog(rsp);
|
|
}
|
|
|
|
async function uploadFilesNip96(file) {
|
|
const fd = new FormData();
|
|
fd.append("size", file.size.toString());
|
|
fd.append("caption", file.name);
|
|
fd.append("media_type", file.type);
|
|
fd.append("file", file);
|
|
fd.append("no_transform", document.querySelector("#no_transform").checked.toString())
|
|
|
|
const auth_event = await window.nostr.signEvent({
|
|
kind: 27235,
|
|
created_at: Math.floor(new Date().getTime() / 1000),
|
|
content: "",
|
|
tags: [
|
|
["u", `${window.location.protocol}//${window.location.host}/n96`],
|
|
["method", "POST"]
|
|
]
|
|
});
|
|
const rsp = await fetch("/n96", {
|
|
body: fd,
|
|
method: "POST",
|
|
headers: {
|
|
accept: "application/json",
|
|
authorization: `Nostr ${btoa(JSON.stringify(auth_event))}`,
|
|
},
|
|
});
|
|
await dumpToLog(rsp);
|
|
}
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<h1>
|
|
Welcome to route96
|
|
</h1>
|
|
<div class="flex flex-col gap-2">
|
|
<div>
|
|
<label>
|
|
NIP-96
|
|
<input type="radio" name="method" id="method-nip96"/>
|
|
</label>
|
|
<label>
|
|
Blossom
|
|
<input type="radio" name="method" id="method-blossom"/>
|
|
</label>
|
|
</div>
|
|
<div style="color: #ff8383;">
|
|
You must have a nostr extension for this to work
|
|
</div>
|
|
<input type="file" id="file">
|
|
<div>
|
|
<input type="checkbox" id="no_transform">
|
|
<label for="no_transform">
|
|
Disable compression (images)
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<button type="submit" onclick="uploadFiles(event)">
|
|
Upload
|
|
</button>
|
|
</div>
|
|
|
|
<div>
|
|
<button type="submit" onclick="listFiles()">
|
|
List Uploads
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<pre id="log"></pre>
|
|
</body>
|
|
</html> |