diff --git a/.gitea/scripts/fdroid.sh b/.gitea/scripts/fdroid.sh index 750cd6d..acac903 100755 --- a/.gitea/scripts/fdroid.sh +++ b/.gitea/scripts/fdroid.sh @@ -5,12 +5,12 @@ here=$(pwd) root=${PACKAGES_ROOT:-/var/www/packages.arasaka.software} keep=${FDROID_KEEP:-3} url=https://packages.arasaka.software/fdroid/repo -fingerprint=42C47659B699E0B1A8BCF6F9CE2C4972972265B592BE32B5725B8F87C6BD0374 +fingerprint=5F52CFF4F52F4E0B6DA6CD044BFCEAF78D1D42DB24F2470602DB7F19CBFDF846 id=software.arasaka.meweb apk=$here/releases/$version/MeWeb-$version-android.apk test -f "$apk" -if [ -z "${FDROID_KEYSTORE_B64:-}" ] || [ -z "${FDROID_KEYSTORE_PASS:-}" ]; then - echo "::error::the organisation secrets FDROID_KEYSTORE_B64 and FDROID_KEYSTORE_PASS are not set" +if [ -z "${MEWEB_KEYSTORE_B64:-}" ] || [ -z "${MEWEB_KEYSTORE_PASS:-}" ]; then + echo "::error::the repository secrets MEWEB_KEYSTORE_B64 and MEWEB_KEYSTORE_PASS are not set" exit 1 fi major=$(echo "$version" | cut -d. -f1) @@ -37,11 +37,11 @@ flock -w 2700 9 keys=$(mktemp -d) trap 'rm -rf "$keys"' EXIT -(umask 077 && printf '%s' "$FDROID_KEYSTORE_B64" | base64 -d > "$keys/repo.p12") -FDROID_KEYSTORE=$keys/repo.p12 -export FDROID_KEYSTORE FDROID_KEYSTORE_PASS -unset FDROID_KEYSTORE_B64 -held=$(keytool -J-Duser.language=en -list -v -keystore "$FDROID_KEYSTORE" -storepass:env FDROID_KEYSTORE_PASS -alias arasaka | sed -n 's/^.*SHA256: *//p' | tr -d ':') +(umask 077 && printf '%s' "$MEWEB_KEYSTORE_B64" | base64 -d > "$keys/meweb.keystore") +MEWEB_KEYSTORE=$keys/meweb.keystore +export MEWEB_KEYSTORE MEWEB_KEYSTORE_PASS +unset MEWEB_KEYSTORE_B64 +held=$(keytool -J-Duser.language=en -list -v -keystore "$MEWEB_KEYSTORE" -storepass:env MEWEB_KEYSTORE_PASS -alias meweb | sed -n 's/^.*SHA256: *//p' | tr -d ':') test "$held" = "$fingerprint" state=$root/.fdroid diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 92cf916..91a6119 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -58,6 +58,6 @@ jobs: - name: The APK in the F-Droid repository on packages.arasaka.software if: ${{ github.ref_type == 'tag' }} env: - FDROID_KEYSTORE_B64: ${{ secrets.FDROID_KEYSTORE_B64 }} - FDROID_KEYSTORE_PASS: ${{ secrets.FDROID_KEYSTORE_PASS }} + MEWEB_KEYSTORE_B64: ${{ secrets.MEWEB_KEYSTORE_B64 }} + MEWEB_KEYSTORE_PASS: ${{ secrets.MEWEB_KEYSTORE_PASS }} run: .gitea/scripts/fdroid.sh "$VERSION" diff --git a/CLAUDE.md b/CLAUDE.md index fa69d11..ea65c3e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -177,13 +177,14 @@ The Android release key: alias `meweb`, certificate SHA-256 release is published, so the repository can lag the release page but never lead it. `.gitea/scripts/fdroid.sh` installs fdroidserver into `tools/fdroid` (cached like the JDK) with uv from `setup.json` and the hash-locked `packaging/fdroid/requirements.txt`, because the box has no `ensurepip` and the apt package would bring 242 others. - It refuses any repository key but `42C47659…BD0374` (org secrets `FDROID_KEYSTORE_B64` and `FDROID_KEYSTORE_PASS`; - the only other copy is the owner's Nextcloud, `Backups/arasaka-fdroid-repo-key/`), builds a new snapshot in + It signs the repository with the APK's own key (`MEWEB_KEYSTORE_B64` and `MEWEB_KEYSTORE_PASS`, alias `meweb`), so + the F-Droid fingerprint is the certificate's `5F52CFF4…FDF846` and there is no second key to lose; it refuses any + other. It builds a new snapshot in `/var/www/packages.arasaka.software/.fdroid/` from the live one (the APKs as hard links, so `rm` then `cp` as above; the metadata, `apkcache.json` and the previous `index-v2.json`, which is where fdroidserver reads each APK's first date), adds this version, keeps the newest three, runs `fdroid update`, deletes `repo/status/` (it names the - build machine's paths and `/etc/issue.net`), swaps the `fdroid/repo` link and checks the live signature. Never - regenerate the key: everyone who added the repository trusts only its fingerprint. `packaging/fdroid/` holds the + build machine's paths and `/etc/issue.net`), swaps the `fdroid/repo` link and checks the live signature. The key + was already never to be regenerated; now everyone who added the repository trusts only its fingerprint too. `packaging/fdroid/` holds the repository's settings, its icon (the Arasaka emblem) and the app's listing in English and Italian; the download page links to it and to Obtainium (`Endpoints.FDroid`, source `FDroidRepo`). - **The server cannot ping**: `NoNewPrivileges` drops `ping`'s file capability and `ping_group_range` is closed, so diff --git a/Directory.Build.props b/Directory.Build.props index 7ff5b05..c6922a8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 0.15.0 + 0.15.1 me-web? Arasaka di Hvozdikov Yevheniy © 2026 Arasaka di Hvozdikov Yevheniy diff --git a/README.md b/README.md index 2e62455..dbd9616 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,8 @@ is `packaging/arasaka-repository.sh`; it never calls the package manager, leaves files you edited alone, and removes the repository only when no Arasaka package is left (purge or erase). On Android, the same signed APK is also in an F-Droid repository, so F-Droid, a store like it, or Obtainium can bring -the updates: add `https://packages.arasaka.software/fdroid/repo`, whose key has the SHA-256 -`42:C4:76:59:B6:99:E0:B1:A8:BC:F6:F9:CE:2C:49:72:97:22:65:B5:92:BE:32:B5:72:5B:8F:87:C6:BD:03:74`. The download page -links to both. The app is not in F-Droid's own catalogue, which builds every app from source on F-Droid's servers. +the updates: add `https://packages.arasaka.software/fdroid/repo`, which is signed with the same key as the APK. The +download page links to both. The app is not in F-Droid's own catalogue, which builds every app from source on F-Droid's servers. ## Privacy diff --git a/packaging/fdroid/config.yml b/packaging/fdroid/config.yml index f8139f9..b34e364 100644 --- a/packaging/fdroid/config.yml +++ b/packaging/fdroid/config.yml @@ -5,7 +5,7 @@ repo_description: >- Each app here is the same signed file as on its release page. repo_icon: icon.png archive_older: 0 -repo_keyalias: arasaka -keystore: {env: FDROID_KEYSTORE} -keystorepass: {env: FDROID_KEYSTORE_PASS} -keypass: {env: FDROID_KEYSTORE_PASS} +repo_keyalias: meweb +keystore: {env: MEWEB_KEYSTORE} +keystorepass: {env: MEWEB_KEYSTORE_PASS} +keypass: {env: MEWEB_KEYSTORE_PASS} diff --git a/src/MeWeb.Server/DownloadPage.cs b/src/MeWeb.Server/DownloadPage.cs index 8f1f780..0dfe5b9 100644 --- a/src/MeWeb.Server/DownloadPage.cs +++ b/src/MeWeb.Server/DownloadPage.cs @@ -11,7 +11,6 @@ public static class DownloadPage const string Fingerprint = "5F:52:CF:F4:F5:2F:4E:0B:6D:A6:CD:04:4B:FC:EA:F7:8D:1D:42:DB:24:F2:47:06:02:DB:7F:19:CB:FD:F8:46"; const string ObtainiumApp = $$"""{"id":"software.arasaka.meweb","url":"{{Endpoints.FDroid.Repository}}","author":"Arasaka","name":"me-web?","overrideSource":"FDroidRepo","additionalSettings":"{\"appIdOrName\":\"software.arasaka.meweb\"}"}"""; static readonly string Obtainium = Endpoints.FDroid.Obtainium + Uri.EscapeDataString(ObtainiumApp); - static readonly string RepositoryKey = string.Join(":", Enumerable.Range(0, Endpoints.FDroid.Fingerprint.Length / 2).Select(i => Endpoints.FDroid.Fingerprint.Substring(i * 2, 2))); static readonly Dictionary> Words = new() { @@ -27,7 +26,7 @@ public static class DownloadPage ["AddFDroid"] = "Add to F-Droid", ["AddObtainium"] = "Add to Obtainium", ["RepoAddress"] = "The repository's address is", - ["RepoKey"] = "and the SHA-256 of its key is", + ["RepoKey"] = "and it is signed with the same key as the app.", ["Windows"] = "Windows (64-bit)", ["WindowsNote"] = "The file isn't signed with a paid certificate, so Windows may say it protected your PC: choose “More info”, then “Run anyway”.", ["Linux"] = "Linux", @@ -55,7 +54,7 @@ public static class DownloadPage ["AddFDroid"] = "Aggiungere a F-Droid", ["AddObtainium"] = "Aggiungere a Obtainium", ["RepoAddress"] = "L'indirizzo del repository è", - ["RepoKey"] = "e lo SHA-256 della sua chiave è", + ["RepoKey"] = "ed è firmato con la stessa chiave dell'app.", ["Windows"] = "Windows (64 bit)", ["WindowsNote"] = "Il file non è firmato con un certificato a pagamento, quindi Windows può dire di aver protetto il PC: scelga “Ulteriori informazioni”, poi “Esegui comunque”.", ["Linux"] = "Linux", @@ -91,7 +90,7 @@ public static class DownloadPage html.Append($"

{E(string.Format(culture, words["Latest"], version, release.PublishedAt.ToString("d MMMM yyyy", culture)))}

"); Block(html, release, words["Android"], [("android", "APK")], $"{E(words["AndroidNote"])} {Fingerprint}.", $"

{E(words["Updates"])}

{E(words["AddFDroid"])} · {E(words["AddObtainium"])}

" + - $"

{E(words["RepoAddress"])} {Endpoints.FDroid.Repository} {E(words["RepoKey"])} {RepositoryKey}.

"); + $"

{E(words["RepoAddress"])} {Endpoints.FDroid.Repository} {E(words["RepoKey"])}

"); Block(html, release, words["Windows"], [("windows", ".exe")], E(words["WindowsNote"])); var deb = ReleaseFeed.Asset(release, "linux-deb")?.Name; var rpm = ReleaseFeed.Asset(release, "linux-rpm")?.Name; diff --git a/src/MeWeb.Shared/Endpoints.cs b/src/MeWeb.Shared/Endpoints.cs index 6bd4c04..19b802a 100644 --- a/src/MeWeb.Shared/Endpoints.cs +++ b/src/MeWeb.Shared/Endpoints.cs @@ -78,7 +78,7 @@ public static class Endpoints public static class FDroid { public const string Repository = "https://packages.arasaka.software/fdroid/repo"; - public const string Fingerprint = "42C47659B699E0B1A8BCF6F9CE2C4972972265B592BE32B5725B8F87C6BD0374"; + public const string Fingerprint = "5F52CFF4F52F4E0B6DA6CD044BFCEAF78D1D42DB24F2470602DB7F19CBFDF846"; public const string Add = $"{Repository}?fingerprint={Fingerprint}"; public const string Obtainium = "obtainium://app/"; }