Source-Tag: v1.0.3 Manifest-SHA256: b7b09bf48f9e092ed8ad82f99c0319d6c3837d0a1549bd0cc4a374276c0f3896
143 lines
5.0 KiB
JavaScript
143 lines
5.0 KiB
JavaScript
"use strict";
|
|
(function() {
|
|
var pendingRegistration = null;
|
|
var busy = false;
|
|
var $ = function(id) { return document.getElementById(id); };
|
|
|
|
function formatSize(value) {
|
|
var units = ["B", "KiB", "MiB", "GiB"];
|
|
var size = Number(value);
|
|
var index = 0;
|
|
while (size >= 1024 && index < units.length - 1) { size /= 1024; index++; }
|
|
return size.toFixed(index ? 1 : 0) + " " + units[index];
|
|
}
|
|
|
|
function setStatus(message, error) {
|
|
$("status").textContent = message;
|
|
$("status").classList.toggle("error", Boolean(error));
|
|
}
|
|
|
|
async function api(path, options) {
|
|
var response = await fetch(path, Object.assign({cache: "no-store"}, options || {}));
|
|
var value;
|
|
try { value = await response.json(); } catch (_) { value = null; }
|
|
if (!response.ok) throw new Error("Management request failed.");
|
|
return value;
|
|
}
|
|
|
|
async function copyUrl(url) {
|
|
await navigator.clipboard.writeText(url);
|
|
setStatus("Share URL copied.", false);
|
|
}
|
|
|
|
function actionButton(label, handler, className) {
|
|
var button = document.createElement("button");
|
|
button.type = "button";
|
|
button.textContent = label;
|
|
if (className) button.className = className;
|
|
button.addEventListener("click", handler);
|
|
return button;
|
|
}
|
|
|
|
function render(rows) {
|
|
var body = $("drops");
|
|
body.textContent = "";
|
|
$("empty").classList.toggle("hidden", rows.length !== 0);
|
|
rows.forEach(function(row) {
|
|
var tr = document.createElement("tr");
|
|
[row.name, row.type || "application/octet-stream", formatSize(row.size),
|
|
new Date(row.expiresAt * 1000).toLocaleString()].forEach(function(value) {
|
|
var td = document.createElement("td");
|
|
td.textContent = value;
|
|
tr.appendChild(td);
|
|
});
|
|
var actions = document.createElement("td");
|
|
actions.className = "actions";
|
|
actions.appendChild(actionButton("Copy", function() { copyUrl(row.readUrl).catch(function() {
|
|
setStatus("Unable to copy the share URL.", true);
|
|
}); }));
|
|
actions.appendChild(actionButton("Open", function() {
|
|
window.open(row.readUrl, "_blank", "noopener,noreferrer");
|
|
}));
|
|
actions.appendChild(actionButton("Delete", async function() {
|
|
if (!window.confirm("Permanently delete " + row.name + "?")) return;
|
|
try {
|
|
await api("/manage/api/v1/drops/" + row.id, {method: "DELETE"});
|
|
await load();
|
|
setStatus("Drop deleted.", false);
|
|
} catch (_) { setStatus("Delete failed.", true); }
|
|
}, "danger"));
|
|
tr.appendChild(actions);
|
|
body.appendChild(tr);
|
|
});
|
|
}
|
|
|
|
async function load() {
|
|
var value = await api("/manage/api/v1/list", {
|
|
method: "POST", headers: {"Content-Type": "application/json"}, body: "{}"
|
|
});
|
|
render(Array.isArray(value.drops) ? value.drops : []);
|
|
}
|
|
|
|
async function register(result) {
|
|
await api("/manage/api/v1/register", {
|
|
method: "POST",
|
|
headers: {"Content-Type": "application/json"},
|
|
body: JSON.stringify({readUrl: result.readUrl, deleteCapability: result.deleteCapability})
|
|
});
|
|
pendingRegistration = null;
|
|
$("retry").classList.add("hidden");
|
|
await load();
|
|
}
|
|
|
|
$("upload-form").addEventListener("submit", async function(event) {
|
|
event.preventDefault();
|
|
if (busy) return;
|
|
var file = $("file").files[0];
|
|
if (!file) return setStatus("Select a file.", true);
|
|
busy = true;
|
|
$("upload").disabled = true;
|
|
$("progress").style.width = "0";
|
|
setStatus("Encrypting and uploading...", false);
|
|
try {
|
|
var result = await NeoDropCrypto.upload(file, {
|
|
base: location.origin,
|
|
profile: Number($("profile").value),
|
|
onProgress: function(value) { $("progress").style.width = Math.round(value * 100) + "%"; }
|
|
});
|
|
pendingRegistration = result;
|
|
setStatus("Upload complete. Registering encrypted catalog entry...", false);
|
|
try {
|
|
await register(result);
|
|
$("upload-form").reset();
|
|
setStatus("Encrypted drop uploaded and registered.", false);
|
|
} catch (_) {
|
|
$("retry").classList.remove("hidden");
|
|
setStatus("Upload succeeded, but catalog registration must be retried in this tab.", true);
|
|
}
|
|
} catch (error) {
|
|
if (error.name !== "AbortError") setStatus(error.message || "Encrypted upload failed.", true);
|
|
} finally {
|
|
busy = false;
|
|
$("upload").disabled = false;
|
|
}
|
|
});
|
|
|
|
$("retry").addEventListener("click", async function() {
|
|
if (!pendingRegistration || busy) return;
|
|
busy = true;
|
|
try {
|
|
await register(pendingRegistration);
|
|
setStatus("Catalog registration completed.", false);
|
|
} catch (_) { setStatus("Catalog registration failed; retry from this tab.", true); }
|
|
finally { busy = false; }
|
|
});
|
|
|
|
$("refresh").addEventListener("click", function() {
|
|
load().then(function() { setStatus("Managed drops refreshed.", false); })
|
|
.catch(function() { setStatus("Unable to load managed drops.", true); });
|
|
});
|
|
|
|
load().catch(function() { setStatus("Unable to load managed drops.", true); });
|
|
}());
|