Sicherheits-Härtung (v1.1.1) und aktuelle README
- nur http(s)-Links, Validierung/Limits für Remote-, Storage- und Importdaten - HTTP-Sync nur im lokalen Netz, keine Zugangsdaten in der URL - Berechtigung bei Serverwechsel entziehen, explizite CSP, UUID-IDs Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
bb7ee831a8
commit
a04aaae859
@@ -7,12 +7,12 @@ let editId = null;
|
||||
let syncOn = false;
|
||||
let syncState = ""; // "", "busy", "ok", "err"
|
||||
|
||||
const uid = () => Math.random().toString(36).slice(2, 10);
|
||||
const uid = () => crypto.randomUUID();
|
||||
|
||||
function normalizeUrl(raw) {
|
||||
raw = raw.trim();
|
||||
if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) raw = "http://" + raw;
|
||||
try { return new URL(raw).href; } catch { return null; }
|
||||
return LabSync.safeUrl(raw);
|
||||
}
|
||||
|
||||
async function load() {
|
||||
@@ -135,7 +135,11 @@ function closeForm() {
|
||||
$("form").addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
const url = normalizeUrl($("fUrl").value);
|
||||
if (!url) { $("fUrl").focus(); return; }
|
||||
if (!url) {
|
||||
$("fUrl").setCustomValidity("Nur gültige http(s)-URLs");
|
||||
$("fUrl").reportValidity();
|
||||
return;
|
||||
}
|
||||
const entry = { name: $("fName").value.trim(), url, icon: $("fIcon").value.trim(), updated: Date.now() };
|
||||
if (editId === "new") links.push({ id: uid(), ...entry });
|
||||
else Object.assign(links.find((l) => l.id === editId), entry);
|
||||
@@ -143,6 +147,7 @@ $("form").addEventListener("submit", async (e) => {
|
||||
closeForm();
|
||||
});
|
||||
|
||||
$("fUrl").addEventListener("input", () => $("fUrl").setCustomValidity(""));
|
||||
$("cancel").addEventListener("click", closeForm);
|
||||
$("add").addEventListener("click", () => openForm());
|
||||
$("search").addEventListener("input", render);
|
||||
@@ -172,9 +177,11 @@ $("file").addEventListener("change", async (e) => {
|
||||
try {
|
||||
const arr = JSON.parse(await file.text());
|
||||
const now = Date.now();
|
||||
if (!Array.isArray(arr)) throw new Error("kein Array");
|
||||
const imported = arr
|
||||
.filter((x) => x && x.name && x.url)
|
||||
.map((x) => ({ id: uid(), name: String(x.name), url: normalizeUrl(String(x.url)) || String(x.url), icon: x.icon || "", updated: now }));
|
||||
.slice(0, 500)
|
||||
.map((x) => LabSync.cleanLink({ ...x, id: uid(), url: x && normalizeUrl(String(x.url ?? "")), updated: now }))
|
||||
.filter(Boolean);
|
||||
deleted = [...deleted, ...links.map((l) => ({ id: l.id, updated: now }))];
|
||||
links = imported;
|
||||
await save();
|
||||
|
||||
Reference in New Issue
Block a user