me-web? 0.15.1: the F-Droid repository is signed with the app's own key
Build / Desktop, server and tools (push) Successful in 1m6s
Release / Every platform, the server, the release (push) Failing after 8m5s

- The Arasaka F-Droid repository, packages.arasaka.software/fdroid/repo, is signed with the same key as the app, so
  the fingerprint F-Droid or Obtainium checks is the one already on the download page for the APK.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T9uhaCTSycTh1r8At679Pz
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-31 09:24:50 +01:00
1 parent b38f50ee5e
commit 94cc74bb95
8 files changed
+26 -27

No files matched your search

+8 -8
View File
@@ -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
+2 -2
View File
@@ -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"
+5 -4
View File
@@ -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
+1 -1
View File
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>0.15.0</Version>
<Version>0.15.1</Version>
<Product>me-web?</Product>
<Company>Arasaka di Hvozdikov Yevheniy</Company>
<Copyright>© 2026 Arasaka di Hvozdikov Yevheniy</Copyright>
+2 -3
View File
@@ -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
+4 -4
View File
@@ -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}
+3 -4
View File
@@ -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<string, Dictionary<string, string>> 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($"<p class=\"soft\">{E(string.Format(culture, words["Latest"], version, release.PublishedAt.ToString("d MMMM yyyy", culture)))}</p>");
Block(html, release, words["Android"], [("android", "APK")], $"{E(words["AndroidNote"])} <code>{Fingerprint}</code>.",
$"<p>{E(words["Updates"])}</p><p><a href=\"{E(Endpoints.FDroid.Add)}\">{E(words["AddFDroid"])}</a> · <a href=\"{E(Obtainium)}\">{E(words["AddObtainium"])}</a></p>" +
$"<p class=\"soft\">{E(words["RepoAddress"])} <code>{Endpoints.FDroid.Repository}</code> {E(words["RepoKey"])} <code>{RepositoryKey}</code>.</p>");
$"<p class=\"soft\">{E(words["RepoAddress"])} <code>{Endpoints.FDroid.Repository}</code> {E(words["RepoKey"])}</p>");
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;
+1 -1
View File
@@ -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/";
}