From 91a83f21dd36650c463b162dde903d4bbdbf3ac5 Mon Sep 17 00:00:00 2001 From: LiHaohua Date: Thu, 23 Jul 2026 18:32:41 +0800 Subject: [PATCH] feat(portal): hide uploader email by default The Maintainer address shown in the preview is read straight from the uploaded .deb's control file (dpkg publishes it into the APT index); it is not derived from the GitHub login, and OAuth already retrieves the user's verified emails via the user:email scope. Add a privacy control so uploaders aren't surprised to see an address: - New "don't publicly show my email" checkbox on the upload form, checked by default (zh-CN / en / ja). - When checked, the preview masks the Maintainer email, and the Worker forwards only the noreply form so the packages-repo Action records a noreply uploader email. Unchecking publishes the verified GitHub email as the recorded contact instead. - No new client_payload property (stays within the 10-key dispatch limit): the choice is expressed by reordering/filtering the existing emails array. Co-authored-by: Cursor --- site/app.js | 24 +++++++++++++++++++++++- site/i18n/en.json | 2 ++ site/i18n/ja.json | 2 ++ site/i18n/zh-CN.json | 2 ++ site/index.html | 8 ++++++++ worker/src/index.js | 16 +++++++++++++++- 6 files changed, 52 insertions(+), 2 deletions(-) diff --git a/site/app.js b/site/app.js index e71a938..0417cdd 100644 --- a/site/app.js +++ b/site/app.js @@ -274,6 +274,25 @@ async function pick(f) { /* -------------------------------- preview -------------------------------- */ +// The deb's own Maintainer field is what dpkg-scanpackages publishes into the +// APT index. When "hide my email" is checked (default) we mask the address in +// the preview so the developer isn't surprised to see it; the published record +// (release manifest) is separately kept to a noreply form by the Worker. +function maintainerDisplay(maintainer) { + const m = (maintainer || "").trim(); + if (!m) return t("preview.maintainerMissing"); + if (!$("hide-email").checked) return m; + const name = m.split("<")[0].trim(); + const masked = t("preview.emailHiddenTag"); + return name ? `${name} ${masked}` : masked; +} + +// Re-mask the preview when the checkbox is toggled (only meaningful once a deb +// has been parsed). +$("hide-email").addEventListener("change", () => { + if (parsed && file) $("p-maint").textContent = maintainerDisplay(parsed.control.Maintainer); +}); + async function renderPreview() { const c = parsed.control; $("drop-text").innerHTML = t("upload.chosen", { name: file.name, size: (file.size / 1048576).toFixed(1) }); @@ -282,7 +301,7 @@ async function renderPreview() { $("p-version").textContent = c.Version || "?"; $("p-arch").textContent = c.Architecture || "?"; $("p-size").textContent = `${(parsed.totalInstalledSize / 1048576).toFixed(1)} MB`; - $("p-maint").textContent = c.Maintainer || t("preview.maintainerMissing"); + $("p-maint").textContent = maintainerDisplay(c.Maintainer); $("s-title").placeholder = (parsed.desktop && parsed.desktop.Name) || c.Package || t("preview.titlePlaceholder"); @@ -461,6 +480,9 @@ $("submit-btn").addEventListener("click", async () => { body.append("arch", parsed.control.Architecture); const repo = $("source-repo").value.trim(); if (repo) body.append("source_repo", repo); + // Privacy: when checked (default) the Worker records a noreply address; when + // unchecked it publishes the developer's verified GitHub email instead. + body.append("hide_email", $("hide-email").checked ? "true" : "false"); // Optional store metadata (empty strings + no images ⇒ Worker treats it as // "not supplied" and falls back to source_repo/deb-derived metadata). diff --git a/site/i18n/en.json b/site/i18n/en.json index 408a00c..0279f3a 100644 --- a/site/i18n/en.json +++ b/site/i18n/en.json @@ -23,6 +23,7 @@ "version": "Version", "installSize": "Installed size", "maintainerMissing": "(missing)", + "emailHiddenTag": "