Add an Android uploader app
Native single-photo uploader for POST /upload. Lives in android/ with its own flake, so the root flake stays Go-only and NixOS consumers of nixosModules.default do not pull the Android SDK into their lock. The server is untouched, so the app closes every gap client side: - The slug is the enqueue-time timestamp, persisted in the work input. server.go derives the stored slug from the uploaded filename, so reusing that filename across WorkManager retries overwrites the same post rather than creating a duplicate. That stands in for an idempotency key. - EXIF is stripped before upload. The gallery publishes the uploaded file verbatim as its full-size download, and phone photos carry GPS. JPEG and PNG drop metadata at marker and chunk level with the compressed pixels untouched; HEIC is decoded to JPEG because the extension check rejects it. - Photos flagged for rotation are rotated into the pixels instead of relying on the orientation tag, which cannot survive the strip and which the thumbnailer ignores regardless. - Anything over 18 MiB steps quality, then resolution, to stay inside nginx's client_max_body_size 20M. - Credentials are sealed with an AES-GCM key in the Android Keystore. The key deliberately does not require user authentication, or background retries could not read it. Basic auth is attached by an interceptor rather than an Authenticator, which reacts to a 401 by replaying a multipart body that is not reliably replayable. - The connection test uses GET /upload. /health is unreachable from outside because the nginx vhost only proxies location /upload. WorkManager's SystemForegroundService needs foregroundServiceType declared on the service entry, not just as a permission, or setForeground throws on Android 14+. Only lintVitalRelease catches that, never a debug build. Also anchors the .gitignore patterns. Unanchored, "photogallery" matched the Kotlin package directory ws/inflo/photogallery/ and silently swallowed every source file on git add.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
{
|
||||
description = "photogallery Android uploader dev shell";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
|
||||
# Reproducible Android SDK across NixOS + macOS without the nixpkgs
|
||||
# androidenv read-only-SDK-root quirks.
|
||||
android-nixpkgs = {
|
||||
url = "github:tadfisher/android-nixpkgs/stable";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, android-nixpkgs }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
config.allowUnfree = true; # Android SDK is unfree
|
||||
};
|
||||
|
||||
buildToolsVersion = "36.0.0";
|
||||
|
||||
# SDK components for the Compose app. Pinned to the exact versions
|
||||
# the Gradle config requests — adding extras only inflates the
|
||||
# closure. When AGP bumps any of these, the build error names the
|
||||
# exact missing version: look it up in `android-nixpkgs` and replace
|
||||
# the line. No NDK or CMake: there is no native code in this app.
|
||||
androidSdk = android-nixpkgs.sdk.${system} (sdkPkgs: with sdkPkgs; [
|
||||
cmdline-tools-latest # sdkmanager, avdmanager
|
||||
platform-tools # adb, for sideloading to the phone
|
||||
platforms-android-36 # compileSdk / targetSdk
|
||||
build-tools-36-0-0 # aapt2, d8, zipalign
|
||||
build-tools-35-0-0 # AGP 8.x resolves this one too, and the
|
||||
# nix store is read-only so it cannot
|
||||
# download it itself
|
||||
]);
|
||||
in {
|
||||
devShells.default = pkgs.mkShell {
|
||||
packages = [
|
||||
pkgs.jdk17 # AGP 8.x toolchain
|
||||
pkgs.gradle # bootstraps ./gradlew, then the wrapper takes over
|
||||
androidSdk
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
export ANDROID_HOME="${androidSdk}/share/android-sdk"
|
||||
export ANDROID_SDK_ROOT="$ANDROID_HOME"
|
||||
export JAVA_HOME="${pkgs.jdk17.home}"
|
||||
|
||||
# AGP downloads aapt2 from Maven by default. The Maven binary is
|
||||
# generic-linux ELF and won't run on NixOS. Force Gradle to use the
|
||||
# patchelfed aapt2 shipped in our pinned build-tools instead.
|
||||
export GRADLE_OPTS="-Dorg.gradle.project.android.aapt2FromMavenOverride=$ANDROID_HOME/build-tools/${buildToolsVersion}/aapt2"
|
||||
'';
|
||||
};
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user