<feed xmlns='http://www.w3.org/2005/Atom'>
<title>android/rsend/rsh, branch 0.2.1</title>
<subtitle>[no description]</subtitle>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/rsend/'/>
<entry>
<title>doc: correct drift and move the build notes to the root</title>
<updated>2026-08-23T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-08-23T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/rsend/commit/?id=780d3167a427d6964806694ef5282be0c6f4cd33'/>
<id>780d3167a427d6964806694ef5282be0c6f4cd33</id>
<content type='text'>
The Rsync comment about draining a hostile remote's pipe sat on the
Tally type, where it means nothing; it describes boundedLines. Scheduler
explained itself with what happened during development instead of the
constraint that WorkManager persists unique names across upgrades, and
MainActivity and SyncLog did the same. Keys pointed at a pin() that does
not exist. The App header restated the class name and omitted half of
what onCreate does. OUT_FORMAT had no caller outside its file.

The README layout list omitted fastlane. The e2e test hardcodes a copy
of the app's rsync vector with nothing saying so. useradd already writes
a locked password field, so "skip passwd -l" does not leave a non-locked
one and key auth is still refused; verified against sshd with UsePAM no.
The CI file also runs verify-repro on a tag, and the NDK and build-tools
are pinned by revision and verified against Google's manifest rather
than a checksum this repository owns, which the reproducibility notes
claimed for every input.

metadata/ held one document and nothing else, and reads as a store
metadata directory beside fastlane/metadata. Root, extensionless,
beside THIRD_PARTY.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The Rsync comment about draining a hostile remote's pipe sat on the
Tally type, where it means nothing; it describes boundedLines. Scheduler
explained itself with what happened during development instead of the
constraint that WorkManager persists unique names across upgrades, and
MainActivity and SyncLog did the same. Keys pointed at a pin() that does
not exist. The App header restated the class name and omitted half of
what onCreate does. OUT_FORMAT had no caller outside its file.

The README layout list omitted fastlane. The e2e test hardcodes a copy
of the app's rsync vector with nothing saying so. useradd already writes
a locked password field, so "skip passwd -l" does not leave a non-locked
one and key auth is still refused; verified against sshd with UsePAM no.
The CI file also runs verify-repro on a tag, and the NDK and build-tools
are pinned by revision and verified against Google's manifest rather
than a checksum this repository owns, which the reproducibility notes
claimed for every input.

metadata/ held one document and nothing else, and reads as a store
metadata directory beside fastlane/metadata. Root, extensionless,
beside THIRD_PARTY.
</pre>
</div>
</content>
</entry>
<entry>
<title>build: pin the build host and the shipped ABIs</title>
<updated>2026-08-23T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-08-23T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/rsend/commit/?id=174521e494159bb0e65c551b440fe732767bdd6d'/>
<id>174521e494159bb0e65c551b440fe732767bdd6d</id>
<content type='text'>
The native scripts picked an NDK host tag for macOS as well, but
ci/setup-toolchain.sh provisions nothing outside Linux x86_64 and no
pipeline exercises the other branch. Fail with the message setup already
gives instead of naming a toolchain nobody can obtain here.

The armeabi-v7a and x86 cases were never reachable either: ABIS ships
arm64-v8a and x86_64, and ci/verify-apk.sh has no machine check for the
other two, so adding one to ABIS failed the build it was meant to
enable. Record what a new ABI actually costs instead of inviting a
one-line edit that cannot work.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The native scripts picked an NDK host tag for macOS as well, but
ci/setup-toolchain.sh provisions nothing outside Linux x86_64 and no
pipeline exercises the other branch. Fail with the message setup already
gives instead of naming a toolchain nobody can obtain here.

The armeabi-v7a and x86 cases were never reachable either: ABIS ships
arm64-v8a and x86_64, and ci/verify-apk.sh has no machine check for the
other two, so adding one to ABIS failed the build it was meant to
enable. Record what a new ABI actually costs instead of inviting a
one-line edit that cannot work.
</pre>
</div>
</content>
</entry>
<entry>
<title>rsh: pass the resolved port to dial</title>
<updated>2026-08-23T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-08-23T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/rsend/commit/?id=8a3746d71661df97615d004c353a183408c3e910'/>
<id>8a3746d71661df97615d004c353a183408c3e910</id>
<content type='text'>
Both callers already read and used RSH_PORT before dialling. Reading it
a third time inside dial hid the data flow and duplicated the error
path.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Both callers already read and used RSH_PORT before dialling. Reading it
a third time inside dial hid the data flow and duplicated the error
path.
</pre>
</div>
</content>
</entry>
<entry>
<title>native: harden rsync and SSH transport</title>
<updated>2026-08-16T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-08-16T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/rsend/commit/?id=beaa0c970d6c3538119b8a34a3f2f754b45e54cf'/>
<id>beaa0c970d6c3538119b8a34a3f2f754b45e54cf</id>
<content type='text'>
Update rsync to 3.5.0 and Go to 1.26.6. Bound SSH handshakes, pin
host-key types, and build 16 KB-aligned hardened executables.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Update rsync to 3.5.0 and Go to 1.26.6. Bound SSH handshakes, pin
host-key types, and build 16 KB-aligned hardened executables.
</pre>
</div>
</content>
</entry>
<entry>
<title>ci: pin toolchains and verify release artifacts</title>
<updated>2026-07-13T22:00:29+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/rsend/commit/?id=2aa6920fb1568249d2466fa1b13760d1a51c0e8f'/>
<id>2aa6920fb1568249d2466fa1b13760d1a51c0e8f</id>
<content type='text'>
Checksum-pin every downloaded toolchain archive. Before publishing,
verify the APK was built from HEAD, the tag matches versionName,
apksigner passes, and the tree is clean; publish a sha256 sidecar
and treat published assets as immutable. Compare full unsigned APKs
in verify-repro and run the Android unit tests in CI.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Checksum-pin every downloaded toolchain archive. Before publishing,
verify the APK was built from HEAD, the tag matches versionName,
apksigner passes, and the tree is clean; publish a sha256 sidecar
and treat published assets as immutable. Compare full unsigned APKs
in verify-repro and run the Android unit tests in CI.
</pre>
</div>
</content>
</entry>
<entry>
<title>rsh: bound the SSH handshake</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/rsend/commit/?id=a6640c603b7a15d3531980116fdce15d1743c865'/>
<id>a6640c603b7a15d3531980116fdce15d1743c865</id>
<content type='text'>
ssh.Dial applies its Timeout only to the TCP connect, so a host that
accepts the connection and then stalls the SSH handshake hangs the
sync forever. Dial with a timeout, run the handshake under a deadline,
and clear the deadline once the connection is established.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
ssh.Dial applies its Timeout only to the TCP connect, so a host that
accepts the connection and then stalls the SSH handshake hangs the
sync forever. Dial with a timeout, run the handshake under a deadline,
and clear the deadline once the connection is established.
</pre>
</div>
</content>
</entry>
<entry>
<title>native: pick the NDK host toolchain tag by build host</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>jsvk</name>
<email>850037+jsvk@users.noreply.github.com</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/rsend/commit/?id=977629ec3effeaeab698fcc4f42c7827c2b181ed'/>
<id>977629ec3effeaeab698fcc4f42c7827c2b181ed</id>
<content type='text'>
The NDK names its prebuilt toolchain directory after the build host,
not the target. Hardcoding linux-x86_64 broke rsync/build.sh and
rsh/build.sh on macOS, which ships the toolchain under darwin-x86_64
(x86_64 binaries, run under Rosetta on Apple Silicon). Detect the
host with uname and fail loud on anything else.

Link: https://codeberg.org/0xlena/rsend/pulls/1
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The NDK names its prebuilt toolchain directory after the build host,
not the target. Hardcoding linux-x86_64 broke rsync/build.sh and
rsh/build.sh on macOS, which ships the toolchain under darwin-x86_64
(x86_64 binaries, run under Rosetta on Apple Silicon). Detect the
host with uname and fail loud on anything else.

Link: https://codeberg.org/0xlena/rsend/pulls/1
</pre>
</div>
</content>
</entry>
<entry>
<title>rsh: reject an invalid RSH_PORT</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/rsend/commit/?id=0d8ef6c605ab646cb6fc7e5eaaefe40ef1de95ee'/>
<id>0d8ef6c605ab646cb6fc7e5eaaefe40ef1de95ee</id>
<content type='text'>
A garbage or out-of-range port silently fell back to 22 and connected
to the wrong place; fail loud instead.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
A garbage or out-of-range port silently fell back to 22 and connected
to the wrong place; fail loud instead.
</pre>
</div>
</content>
</entry>
<entry>
<title>keys: never write the plaintext private key to disk</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/rsend/commit/?id=1da5637997e7971cbde77dbf642ea734fbb2f4cc'/>
<id>1da5637997e7971cbde77dbf642ea734fbb2f4cc</id>
<content type='text'>
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.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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.
</pre>
</div>
</content>
</entry>
<entry>
<title>rsend: push phone folders to a home SSH host over rsync</title>
<updated>2026-01-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-01-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/rsend/commit/?id=7e04941bccb2683f8a6e3ee38a99c50129234dd1'/>
<id>7e04941bccb2683f8a6e3ee38a99c50129234dd1</id>
<content type='text'>
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.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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.
</pre>
</div>
</content>
</entry>
</feed>
