me-web? 0.15.1: the F-Droid repository is signed with the app's own key
- 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:
1 parent
b38f50ee5e
commit
618a6782cd
8 files changed
+26
-27
No files matched your search
@@ -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
|
||||
|
||||
@@ -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"
|
||||
@@ -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,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>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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}
|
||||
@@ -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;
|
||||
|
||||
@@ -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/";
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user