Skip to content

feat(controller): validate sync credentials to close rsync injection (S1)#9

Merged
luisguzman-adfa merged 1 commit into
mainfrom
feat/phase1-security-sync-credential-validation
Jun 18, 2026
Merged

feat(controller): validate sync credentials to close rsync injection (S1)#9
luisguzman-adfa merged 1 commit into
mainfrom
feat/phase1-security-sync-credential-validation

Conversation

@luisguzman-adfa

Copy link
Copy Markdown
Collaborator

Summary

Starts Phase 1 (security hardening) with a small, layered slice. The peer-to-peer sync handshake transports host / port / user / password inside a scanned QR code. Those untrusted values were interpolated with no validation into the server-side rsyncd.conf and the client-side rsync://user@host:port/... URL, allowing config-directive / URL injection — tech-debt item S1.

Changes

  • sync/domain/SyncCredentialValidator (new, pure JVM — no Android deps): the single rule for a "safe" sync credential — strict charsets for username/host, TCP port range, control-char-free password, and isSafeConfigValue() for rsyncd.conf lines. Reusable contract for the remaining injection fixes (S4, D2).
  • SyncHandshakeHelper.parsePayload(): validates at the QR parse boundary and returns null on invalid (reuses the existing "invalid QR" toast — no new UI wiring).
  • RsyncManager: defence in depth — refuses to write the daemon config or build the client URL when credentials/share path are unsafe, failing closed with a new rsync_error_invalid_credentials string (en + es).
  • Tests: SyncCredentialValidatorTest (charset/range/injection cases + a property check that app-generated passwords are always accepted) and three malicious-payload cases added to SyncHandshakeHelperTest.
  • Docs: CLAUDE.md design map + controller/docs/TECH_DEBT_PLAN.md progress log (S1 done; Phase 1 now in progress).

Testing

  • ./gradlew :app:testDebugUnitTest — new JVM unit tests (Phase 0 CI gate already blocks on this). All logic is pure JVM; no emulator needed. Existing SyncHandshakeHelperTest round-trip/legacy cases still pass.

Notes

Follows CLAUDE.md: new code is a feature package split by layer (sync/domain), domain stays pure JVM, legacy classes touched only through a narrow additive seam. Independent of the other in-flight branches.

…(S1)

Start Phase 1 (security) with a refactor-by-feature slice. The peer-to-peer
sync handshake transports host/port/user/pass inside a scanned QR code; those
untrusted values were interpolated into rsyncd.conf (server) and a rsync://
URL (client) with no validation, allowing config-directive and URL injection
(tech-debt item S1).

- domain: new pure, unit-tested SyncCredentialValidator
  (org.iiab.controller.sync.domain) — the single rule for a "safe" sync
  credential: strict user/host charsets, port range, control-char-free
  password, and isSafeConfigValue() for rsyncd.conf lines. No Android deps.
- seam: SyncHandshakeHelper.parsePayload() validates at the QR parse boundary
  (returns null -> existing "invalid QR" toast); RsyncManager re-checks
  defensively before writing the daemon config and before building the client
  URL, failing closed with a new rsync_error_invalid_credentials string (en+es).
- tests: SyncCredentialValidatorTest (charset/range/injection cases, and that
  generated passwords are always accepted) + three malicious-payload cases in
  SyncHandshakeHelperTest.
- docs: CLAUDE.md design map + controller/docs/TECH_DEBT_PLAN.md progress log
  (S1 done; Phase 1 now in progress). Validator is the reusable contract for
  the remaining injection fixes (S4, D2).
@luisguzman-adfa luisguzman-adfa force-pushed the feat/phase1-security-sync-credential-validation branch from 6538b67 to bf8b621 Compare June 18, 2026 06:47
@luisguzman-adfa luisguzman-adfa merged commit 882f32f into main Jun 18, 2026
2 checks passed
@luisguzman-adfa luisguzman-adfa deleted the feat/phase1-security-sync-credential-validation branch June 18, 2026 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant