diff --git a/background.js b/background.js index a10964b..6d3d83e 100644 --- a/background.js +++ b/background.js @@ -14,7 +14,7 @@ import { PaperlessClient, PaperlessError } from "./lib/client.js"; import { ladeEinstellungen, vollstaendig, sichererName, versionslabel, - titelAusBetreff, t + titelAusBetreff, zugriffsmuster, t } from "./lib/settings.js"; /** @@ -90,6 +90,12 @@ function alsDatum(wert) { return Number.isNaN(d.getTime()) ? undefined : d.toISOString().slice(0, 10); } +// Beim Laden eine Zeile ausgeben. Fehlt sie in der Konsole, ist das +// Skript gar nicht erst gestartet - und dann kommt bei jedem Aufruf aus +// einem Dialog nur "An unexpected error occurred". +console.info("[paperless] Hintergrundskript geladen", + browser.runtime.getManifest().version); + // Offene Dialoge, damit sie ihre Aufgabe abholen können. const auftraege = new Map(); let naechsteAuftragsnummer = 1; @@ -322,7 +328,7 @@ async function client() { // Fehlersuche beim Netzwerk. let origin; try { - origin = new URL(s.baseUrl).origin + "/*"; + origin = zugriffsmuster(s.baseUrl); } catch { throw new PaperlessError(t("errBadUrl")); } @@ -333,7 +339,7 @@ async function client() { + `In den Einstellungen erneut auf Speichern klicken - die Abfrage ` + `kann nur aus einer Benutzeraktion heraus erscheinen.`); } - return new PaperlessClient(s.baseUrl, s.token); + return new PaperlessClient(s.baseUrl, s.token, s.shareBaseUrl); } /** @@ -347,7 +353,7 @@ async function client() { async function berechtigungPruefen() { const s = await ladeEinstellungen(); if (!vollstaendig(s)) return { noetig: false, erteilt: false }; - const muster = new URL(s.baseUrl).origin + "/*"; + const muster = zugriffsmuster(s.baseUrl); const erteilt = await browser.permissions.contains({ origins: [muster] }); return { noetig: true, erteilt, muster }; } diff --git a/lib/client.js b/lib/client.js index e87d1dc..5135863 100644 --- a/lib/client.js +++ b/lib/client.js @@ -34,7 +34,7 @@ const TASK_POLL = 1500; export class PaperlessError extends Error {} export class PaperlessClient { - constructor(baseUrl, token) { + constructor(baseUrl, token, shareBaseUrl = "") { let parsed; try { parsed = new URL(String(baseUrl || "").trim()); @@ -48,6 +48,13 @@ export class PaperlessClient { } this.base = String(baseUrl).trim().replace(/\/+$/, ""); this.token = String(token || "").trim(); + + // Adresse für Freigabelinks. Paperless liefert nur den Slug, die + // vollständige Adresse wird hier zusammengesetzt. Führt der interne + // Zugang über einen abweichenden Port, wäre ein daraus gebauter Link + // für den Empfänger wertlos - deshalb getrennt konfigurierbar. + this.shareBase = String(shareBaseUrl || "").trim().replace(/\/+$/, "") + || this.base; } get origin() { @@ -313,7 +320,7 @@ export class PaperlessClient { headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); - if (res?.slug) return `${this.base}/share/${res.slug}`; + if (res?.slug) return `${this.shareBase}/share/${res.slug}`; return null; } catch (err) { last = err; diff --git a/lib/settings.js b/lib/settings.js index a751d86..d5079ba 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -10,9 +10,23 @@ const VORGABEN = { baseUrl: "", token: "", + // Adresse, unter der das Archiv von aussen erreichbar ist. + // + // Wird nur für Freigabelinks verwendet. Paperless liefert in der + // Antwort lediglich den Slug; die vollständige Adresse setzt die + // Erweiterung zusammen. Führt der interne Zugang über einen + // abweichenden Port oder einen anderen Namen, wäre ein daraus gebauter + // Link für den Empfänger wertlos. + // + // Leer = baseUrl verwenden. + shareBaseUrl: "", versionLabel: "Thunderbird {datum}", shareDays: 7, shareTag: "Sharelink", + // Beschriftung der eingefügten Linkblöcke. Leer lassen für keine + // Nummerierung ist nicht vorgesehen - eine Nummer hilft beim Bezugnehmen + // im Fließtext ("siehe Datei 2"). + linkBezeichner: "", // Anhänge, die üblicherweise keine Dokumente sind. Sie werden im // Auswahldialog vorab abgewählt, lassen sich aber anhaken. ignorierteTypen: ["image/gif", "image/png", "image/jpeg", "text/vcard", @@ -34,6 +48,21 @@ export function vollstaendig(s) { return Boolean(s?.baseUrl) && Boolean(s?.token); } +/** + * Zugriffsmuster für browser.permissions aus einer Basisadresse. + * + * WICHTIG: Muster dürfen KEINEN Port enthalten. "https://rechner:8443/*" + * ist ungültig, und permissions.request wirft dann eine Ausnahme mit + * einer Meldung, die nichts über die Ursache verrät. + * + * Ein Zugriffsrecht gilt ohnehin für alle Ports desselben Rechners - die + * Einschränkung kostet also nichts. + */ +export function zugriffsmuster(baseUrl) { + const u = new URL(String(baseUrl).trim()); + return `${u.protocol}//${u.hostname}/*`; +} + /** * Beliebige Zeichenkette in einen unbedenklichen Dateinamen überführen. * diff --git a/manifest.json b/manifest.json index 2b45633..1578aed 100644 --- a/manifest.json +++ b/manifest.json @@ -2,13 +2,13 @@ "manifest_version": 3, "name": "__MSG_extName__", "description": "__MSG_extDescription__", - "version": "1.5.1", - "author": "Marco Morath", - "homepage_url": "https://gitea.cloud.mmorath.de/marco.morath/thunderbird-paperless-connector", + "version": "1.6.1", + "author": "Name des Herausgebers", + "homepage_url": "https://example.org/paperless-thunderbird", "default_locale": "de", "browser_specific_settings": { "gecko": { - "id": "webmaster@mmorath.de", + "id": "paperless@example.org", "strict_min_version": "128.0" } }, diff --git a/ui/gemeinsam.js b/ui/gemeinsam.js index d2d23c4..2d4b240 100644 --- a/ui/gemeinsam.js +++ b/ui/gemeinsam.js @@ -2,9 +2,33 @@ * gemeinsam.js - Hilfsmittel für alle Dialogseiten. */ -/** Ruft die Ereignisseite und wirft bei Fehlern eine Ausnahme. */ +/** + * Ruft die Ereignisseite und wirft bei Fehlern eine Ausnahme. + * + * Unterscheidet zwei Fälle, die sonst dieselbe nichtssagende Meldung + * ergeben ("An unexpected error occurred"): + * + * * Die Nachricht erreicht keinen Empfänger - das Hintergrundskript + * ist nicht geladen oder abgestürzt. + * * Der Empfänger meldet einen Fehler zurück. + */ export async function ruf(befehl, daten = {}) { - const antwort = await browser.runtime.sendMessage({ befehl, ...daten }); + let antwort; + try { + antwort = await browser.runtime.sendMessage({ befehl, ...daten }); + } catch (err) { + console.error("[paperless] sendMessage", befehl, err); + throw new Error( + `Das Hintergrundskript antwortet nicht (${befehl}).\n` + + `Ursprüngliche Meldung: ${err?.message || err}\n\n` + + `Einzelheiten in der Konsole: Extras -> Entwicklerwerkzeuge -> ` + + `Debuggen von Add-ons -> Inspizieren.`); + } + if (antwort === undefined) { + throw new Error( + `Keine Antwort auf ${befehl}. Das Hintergrundskript ist ` + + `vermutlich nicht geladen.`); + } if (!antwort?.ok) { throw new Error(antwort?.fehler || `Aufruf ${befehl} fehlgeschlagen`); } diff --git a/ui/options.html b/ui/options.html index b30e1da..860043d 100644 --- a/ui/options.html +++ b/ui/options.html @@ -18,6 +18,17 @@ Ohne abschließenden Schrägstrich. Nur http und https. + + +