aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/invalid/lena
AgeCommit message (Collapse)AuthorFilesLines
7 daysapp: remove duplicated and dead codeLena11-264/+153
upgradeLegacy assembled every remote, folder and schedule twice: once as Remote and Folder objects to validate, and again as a parallel JSON tree to return. Build the objects and serialise them, and drop the dead endpointAllowed branch, the redundant pin emptiness test, and the excludes length pre-check that excludesAllowed already makes. atomicWrite existed verbatim in Config and Keys and was open-coded a third time in LastSync, which then reached into Config's companion for the bounded reader. The same bounded read was open-coded twice more, for the encrypted key and for an imported one. Both are plain file operations on the same private directory and belong in one place, with readText a thin wrapper over readBytes. Generating and importing an identity key ran the same twenty lines of worker thread, error capture, refresh, toast and dialog; only the action and two strings differed. rotateIfBig rotated at length >= MAX_BYTES, which line() already subsumes, and its only caller invoked it immediately before a line(). notifyError and notifyDeleted were the same builder twice. openSettings nested a try/catch and repeated one toast; take the candidates as a vararg. RemoteActivity.save defaulted its argument to current(), which validates and writes the status field, so the default hid that side effect from one of two callers. Dead on arrival: Outcome.deleted's default, which no caller omits; the rsa-sha2-* arms of hostKeyFile, since rsh prints PublicKey.Type() and an RSA host key is always ssh-rsa; and the limit <= 0 branch in SyncLog.text, which tail already handles and handled more accurately. The config recovery note is now written with an explicit charset like every other write here.
7 daysapp: rename RsyncRunner to RsyncLena2-6/+6
Runner names the architecture rather than the thing. The object is the rsync invocation.
7 daysapp: apply the schedule when folders changeLena1-0/+4
Scheduler.apply cancels the periodic job while no folder points at a pinned remote and enqueues it once one does, so adding the first folder or removing the last one changes what should be scheduled. The remote and schedule editors already re-applied on save; this one did not, and a user who left the app from this screen kept a job that could only fire and refuse.
7 daysapp: keep editor state across recreationLena2-5/+11
Browsing restarted at the storage root on every configuration change. The restored path goes through safeDirectory like a typed one, so it still cannot escape the root. A pinned remote wrote its index into both the instance state and the intent. The instance state already survives recreation.
7 daysapp: read the dashboard off the main threadLena2-13/+44
Every value the dashboard draws comes from an app-private file, and it read all of them during layout, on every resume and at the end of every sync. Scheduler.apply did the same at process start, where it also opens WorkManager's database. Read on a worker thread and draw the result; overlapping refreshes are settled by generation, the same way the log viewer already settles its own.
7 daysapp: report config limits instead of crashingLena3-1/+28
The remote and folder counts and the serialized config size are enforced only inside save, which throws. Every other rule an editor can break is reported in the form, so a config that outgrew a limit crashed the activity instead of saying so. overLimit answers before the entry is added, and the editors report the answer. hostKeyAllowed reconstructs the known_hosts address that rsh writes with knownhosts.Normalize, and nothing recorded or tested that coupling. Normalize leaves the host bare on port 22 for IPv6 literals too, so bracketing them here looks right and would reject every IPv6 pin.
14 daysapp: harden backup executionLena17-337/+1478
Validate persisted state and destination boundaries, make interruption and mirror deletion explicit, and keep scheduled work singular.
14 daysapp: support multiple named remotesLena8-93/+317
Let each folder select a named SSH endpoint and migrate the published 0.1.x configuration without discarding its folders or host pin.
2026-07-13app: harden sync execution and persisted stateLena11-144/+188
Persist config, key blob, and host pin via AtomicFile so an interrupted write cannot corrupt state. Validate the port, clear the host pin when the remote changes, cap imported key size, time out native helpers, and escalate rsync termination to destroyForcibly. Serialize manual and scheduled syncs behind a mutex. Replace the chained one-time jobs with plain periodic work: it survives reboots without a boot receiver and cannot silently die like a broken chain. Costs the sub-15-minute interval, which photo backup does not need. Document the floor and that syncs run on any unmetered network, not only WiFi.
2026-07-01app: drop --mkpath for compatibility with old remote rsyncsLena1-4/+8
rsync forwards --mkpath to the remote side when sending, so a remote rsync older than 3.2.3 (notably stock macOS, whose openrsync is "rsync 2.6.9 compatible") rejects every sync with "unrecognized option '--mkpath'". rsync creates the final component of the destination path on its own, so flat remote paths keep working everywhere, including the documented rrsync setup whose root is pre-created. Only a nested remote path with missing parents now needs a one-time mkdir -p on the server; the log shows rsync's error when it is missing. Reported-by: jsvk Link: https://codeberg.org/0xlena/rsend/pulls/1
2026-07-01app: anchor the picker start path at the storage rootLena1-2/+6
The containment check was a bare prefix match, so a sibling such as /storage/emulated/0-evil passed for a root of /storage/emulated/0.
2026-07-01app: write config atomicallyLena1-1/+7
A crash mid-write corrupted config.json, and every later load then threw on parse, crash-looping the app until its data was cleared, losing the key and pinned host. Write to a temp file and rename.
2026-07-01app: kill rsync when a sync is stoppedLena2-4/+19
A stopped worker (schedule replaced, constraints lost) left rsync running detached until its own network timeout, including a window where a WiFi-only sync kept pushing on another network. A watchdog coroutine destroys the process on cancellation, which also closes its pipes and unblocks the log reader; the worker rethrows cancellation instead of logging it as a folder error.
2026-07-01app: refuse folder mappings with empty pathsLena2-4/+16
The trailing-slash fix-up turns an empty local path into /, so a blank folder row would rsync the entire filesystem; an empty remote path pushes into the rrsync root. Reject both when saving a folder, skip and log them at run time in case the config was edited by hand, and log why a sync was skipped when the app is not configured yet.
2026-07-01keys: never write the plaintext private key to diskLena2-11/+23
rsh -keygen printed the pubkey but wrote the key pair into a directory, so generating a key briefly left the plaintext private key on flash, contradicting the documented invariant that it only ever exists in memory. -keygen now emits the private key PEM on stdout and nothing else; the app encrypts it immediately and derives the public key via -pubkey, reusing the validated import path. Keygen failures now surface as an error dialog instead of crashing the app from a bare thread.
2026-06-01app: add a folder picker for local paths0.1.0Lena2-0/+110
Typing absolute paths is error-prone; let the user browse real filesystem folders and pick one. Stays on real paths (no SAF) so rsync keeps operating on POSIX paths.
2026-01-01rsend: push phone folders to a home SSH host over rsyncLena17-0/+1178
A small Android app for one-way folder backup, a KISS alternative to Syncthing. It bundles rsync (built from pinned source via the NDK) and a pure-Go SSH transport, both shipped in the APK as lib*.so and run from the native library directory. rsend pins the host key, stores the ed25519 identity Keystore-encrypted, pushes each folder additively or as a mirror, and runs on demand or on a WiFi-only schedule. The build is self-contained and reproducible: make setup provisions the toolchain, make builds rsync, rsh, and the APK.