Commit graph

46 commits

Author SHA1 Message Date
jima
7b68e6404b Audit 2026-04-12: C++ hardening, crash fix, dead code, quality
Fifth full codebase audit across all five modules (lib-ssh, lib-terminal-view,
lib-terminal-keyboard, lib-vault-crypto, app).

Security:
- Added cppFlags to lib-vault-crypto build — vault_crypto.cpp JNI bridge was
  missing all compiler hardening flags (-fstack-protector-strong, -D_FORTIFY_SOURCE=2)

Bugs fixed:
- SessionNotifier crash: first{} → firstOrNull to prevent NoSuchElementException
- Keyboard modifiers not consumed on SwitchPage/ToggleNumBlock — armed CTRL/ALT
  would persist and incorrectly modify the next key press
- KeyManagerViewModel silent exception swallow — now logs errors via FileLogger
- TelnetSession.sendTerminalType() variable shadowing fix

Dead code removed:
- Vt100Parser empty class (Vt220Parser now extends BaseTermParser directly)
- XtermParser.sendPrimaryDA() redundant override (identical to parent)
- TerminalKeyboard dead fields: menuPopupActive, menuPopupItems, miniContainer
- SpecialAction.SETTINGS_OPENED never emitted
- Deprecated 3-arg saveHostKeyFingerprint overload (no callers)

Code quality:
- Color(0xFF6E7979) → AppColors.Muted in ConnectionListScreen
- Hardcoded "v1.0.0" → BuildConfig.VERSION_NAME in SettingsScreen
- SubscriptionScreen back button contentDescription for accessibility
- TAG → companion const val in StartupCommandRunner, PortForwardManager, SftpSessionManager
- TerminalRenderer swapped KDoc comments fixed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:09:05 +02:00
jima
56b875b9fc Web platform scaffold, applicationId change to com.roundingmobile.sshwb
ApplicationId changed from com.roundingmobile.sshworkbench to
com.roundingmobile.sshwb (Firebase auto-key blocked Play Console
registration). Namespace stays com.roundingmobile.sshworkbench.
Web platform in www/: Docker stack (nginx+Node.js+MariaDB), landing
page, login (OAuth+email/pw), dashboard (vault sync+session logs),
API routes, MariaDB schema.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 14:47:01 +02:00
jima
c4ead07fa4 Version bump, AppSwitch, cloud backend docs, audit files to docs/, gitignore cleanup
- Bump version 0.0.38 → 0.0.39
- AppSwitch: scaled-down (0.75x) Material3 Switch with full touch target,
  replaces default Switch in KeyboardSettingsDialog for consistent narrow style
- Cloud backend spec: FUTURE.md summary + FUTURE_BACKEND.md full architecture
  (zero-knowledge sync, packs, team sharing, web dashboard, swb CLI) +
  FUTURE_BACKEND_TECH.md implementation details
- Move Audit.md and SecurityAudit.md into docs/ folder
- Add scripts/ to .gitignore (test results, deploy scripts — local only)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 11:47:17 +02:00
jima
e0cbcc6d43 Settings from terminal view, scrollback truncation dialog, drawer about footer
- Add "Settings" item to tab bar and drawer bar kebab menus — opens full
  SettingsScreen from the terminal view via NavHost navigation
- Add Settings row + compact about footer (app icon, version, developer)
  to drawer content panel
- Scrollback truncation: when user lowers scrollback value with active
  SSH/Telnet/Local sessions, confirmation dialog warns about history loss.
  ScreenBuffer.truncateHistory() trims oldest lines and clamps scrollOffset.
- TerminalService.truncateAllScrollback() iterates all session buffers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 11:45:20 +02:00
jima
6c1440e80e Security audit 2026-04-11: PEM/Bearer redaction, telnet warning, host key prefix
Fourth full security audit (prod-only). Fixed 5 findings, deferred 3 high-priority items.

- FileLogger redacts PEM private key blocks and Bearer tokens
- EditConnectionScreen shows persistent telnet cleartext warning card
- SubscriptionRepository.migrateFromProApk made internal + idempotent
- Host key fingerprints stored as <keyType>:<fingerprint> with backward-compat fallback
- MainActivity.onUrlTapped allowlists http/https/ftp schemes only

Also bundled from this session:
- SFTP back button no longer navigates up folders
- Vault local save requires strong password (12+ chars, mixed)
- SSHSession cancel-on-auth stops retry loop immediately
- Version bump to 0.0.38

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 01:02:00 +02:00
jima
338f4085b0 Hardware Key Actions: volume keys + shake, single + double press, custom sequences
- New ActionsScreen (Settings → Terminal → Hardware Key Actions): collapsible accordion cards mapping Volume Up/Down + Shake to terminal actions
- HardwareActionHandler.kt extracted from MainActivity (~284 lines): owns volume key state, double-press detection, shake sensor lifecycle, action execution
- Actions: disabled, close session, font up/down, next/prev session, scroll up/down, custom key sequence
- Double press for volume keys with configurable 200-500ms delay (default 300ms)
- Single-disabled + double-enabled = volume still works, replayed via AudioManager after delay
- Custom key sequences parsed via QuickBar's textToMenuItemAction (supports [Ctrl]x, [Alt]x, [Esc], [F1]-[F12], 0xHH)
- Layered overlapping icons for double press cards
- Accordion: only one card open at a time
- SessionEntry callbacks (onFontSizeRequest, onScrollRequest) for external view updates from Compose tree
- Shake sensor only registers when enabled and Activity resumed (zero battery cost when disabled)
- Settings: section headers in teal Space Grotesk uppercase 13sp, About section with cropped pro launcher icon
- Language moved from General to Display section, value subtitles use mono muted style
- Translated in EN/ES/SV/FR/DE
- FUTURE.md: detect remote OS, automatic session logging, opt-in diagnostic data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 00:20:51 +02:00
jima
d591291c28 Time format setting, protocol-aware card colors, local shell proper IDs, startup commands fix
- Time Format setting (Device default / 12h / 24h) under Display
- Protocol-aware connection card accents: green SSH, amber SFTP, violet Telnet, sky blue Local
- Local shell uses generated sessionId/savedConnectionId (was hardcoded 0)
- Local shell startup commands + lastOutputTimeNs silence detection
- SFTP updates lastConnected for sort order; SFTP option hidden for non-SSH
- Quick connect bar colors unified with lock/key (#7A8888), purged #3E4949
- Pulse animation tuned to 100%→60% over 2s

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:07:34 +02:00
jima
7f4aa15830 Server-driven auth, 3-attempt retry, remember-on-success, legacy test lab doc
Auth flow rewritten to be fully server-driven: no pre-connect password
dialog. TCP + KEX + host key verification happen first; password prompt
only appears when the server actually asks via keyboard-interactive or
the new prompted-password fallback (for servers that only accept the
"password" SSH method). Up to 3 password attempts per connection,
matching OpenSSH's NumberOfPasswordPrompts default.

"Remember password" checkbox now functional: AuthPromptResult threads
the remember flag through the callback chain; SSHSession stashes the
typed password in pendingRememberPassword; TerminalService persists it
to CredentialStore only after session.connect() succeeds — wrong
passwords are never saved.

Removed dead pre-connect dialog code: PasswordDialog composable,
PasswordResult, TerminalDialogRequest.PasswordPrompt, and
passwordPromptHandler.

Added docs/LEGACY_TEST_LAB.md: self-contained 2100-line guide for
building a dedicated server with 56 historical/modern Unix systems
for terminal parser conformance testing (Docker, QEMU/KVM, SIMH,
polarhome, IBM PowerVS). Includes all Dockerfiles, compose.yml,
SIMH configs, systemd units, and helper scripts inline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:50:18 +02:00
jima
e243b8e1e5 VP2 rotation fix, NumBlok mini toggle, HW keyboard auto-hide, audit
ViewPager2 rotation phantom (Google Issue 175796502):
- KeyboardView.onSizeChanged rebuilds buildPages() on any width
  transition including initial 0→actual layout, not just on resize.
  The first buildPages() from setup() runs at width=0 (view still
  detached), VP2's internal RecyclerView can't reliably re-anchor to
  the real dimensions that arrive later, leaving a fractional scroll
  offset that leaks the neighbor page on the right edge. A second
  buildPages() once the real size is known produces a clean result.
- KeyboardView.lastModifierStates caches CTRL/ALT/SHIFT state so it
  survives the rebuild.
- Works around an unfixed VP2 1.1.0 bug for non-FragmentStateAdapter
  usage. Fresh launches and all rotation paths confirmed clean on S23.

NumBlok toggle on mini numpad:
- KeyDefinition gains numLabel/numAction optional fields
- KeyAction gains ToggleNumBlock data object
- LayoutParser understands "numLabel"/"numAction" JSON and the
  "toggle_numblock" action type
- KeyboardPageView.numBlockActive swaps label rendering; toggle key
  gets LOCKED-style amber glow while active
- TerminalKeyboard.numBlockActive state; handleKeyAction swaps
  action→numAction; attachMiniTo carries state across rotation rebuilds
- Mini last row: Num 0 \ (base) → Num Ins ~ (numblock)
- Rows 1-3 map to PC-keypad nav: Home/↑/PgUp, ←/Esc/→, End/↓/PgDn
- QuickBarCustomizer serializer/deserializer learned toggle_numblock

Hardware keyboard auto-hide:
- MainActivity derives hasHwKeyboard from LocalConfiguration.current.
  keyboard != KEYBOARD_NOKEYS && hardKeyboardHidden != HARDKEYBOARDHIDDEN_YES
- LaunchedEffect(hasHwKeyboard) { ckbHidden = hasHwKeyboard } seeds
  the toggle on every HW kb connect/disconnect
- In HW kb mode the kebab Show/Hide controls both CKB and QuickBar as
  a pair: val qbShownByUser = if (hasHwKeyboard) !ckbHidden else
  quickBarVisible
- Normal mode unchanged (QB follows its own quickBarVisible pref)

Number row dropdown:
- KeyboardSettingsDialog now shows all four options (top/left/right/
  hidden) in both orientations. Previously left/right were filtered
  out in portrait, preventing the user from setting the mini mode
  without first rotating into landscape.
- Portrait-override on the effective numberRowMode stays in place
  (mini is landscape-only by design — documented in CLAUDE.md and
  auto-memory).

Audit fixes:
- KeyboardPageView: removed key.hint!! by capturing into a local
  hintText val so smart-cast flows through the render branches
- SSHKeyLoader.loadEd25519FromPkcs8: require(seed.size == 32) so a
  malformed PKCS#8 blob fails fast with a clear message instead of
  crashing deep inside EdDSAPrivateKeySpec
- vault_crypto.cpp nativeEncrypt: secure_zero(ptPtr, ptLen) before
  ReleaseByteArrayElements on all three paths (success + two error
  paths), matching the existing key-handling pattern for plaintext
  defence-in-depth through the JNI boundary

Docs:
- TECHNICAL.md: NumBlok, VP2 rebuild workaround, HW keyboard auto-hide,
  portrait mini override notes
- CLAUDE.md: lib-terminal-keyboard module description updated with
  the same invariants
- TODO.md: recently-completed items through 2026-04-06
- Audit.md: investigation log including false positives for future
  reference

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 13:23:13 +02:00
jima
bda8967ab1 Key import validation, 20 themes, 10 fonts, settings redesign, cursor speed/blink, terminal type
Key Import:
- SSHKeyLoader validates imported keys, extracts real pubkey/fingerprint
- ZIP file support with password handling (zip4j)
- Import chooser dialog: ZIP or single file
- Results dialog: valid/encrypted/invalid sections

Theme & Font:
- 20 color themes (10 new: Ayu Dark, Catppuccin Mocha, Everforest Dark, etc.)
- 10 bundled monospace fonts (JetBrains Mono, Fira Mono, Hack, etc.)
- Combined ThemePickerSheet: color scheme combo, font combo, font size slider
- Live preview with scrollable terminal output, adapts to landscape
- Typeface support in TerminalRenderer/TerminalSurfaceView

Settings:
- Material 3 grouped card layout (7 sections)
- Cursor speed: Slow/Normal/Fast/Rapid with key repeat acceleration
- Cursor blink: 530ms toggle, 15s idle auto-stop
- Keep screen on wired to FLAG_KEEP_SCREEN_ON
- Removed Show session tab bar toggle (always visible)
- Font size stepper replaced slider in settings

Terminal:
- Per-connection terminal type (TERM env var) in Edit Connection
- DB migration v1→v2 for termType column
- configChanges prevents activity recreation on rotation

Fixes:
- Vault import hosted in-place (no popBackStack)
- Clickable radio/checkbox/switch rows (text tappable)
- Password rules shown above field in vault export
- Deploy script cleans all stale APKs
- Telnet uses per-connection termType

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 02:01:06 +02:00
jima
84e71b2517 Dev/prod split, local vault, Keys & Vault screen, FLAG_SECURE settings
- Dev flavor: .dev applicationId suffix (coexists with prod), yellow icon,
  all pro features via flavor ProFeaturesModule, no FLAG_SECURE
- Prod flavor: subscription-gated ProFeaturesModule, teal/gold icons
- FLAG_SECURE: three granular settings (Full App / Vault / Terminal),
  biometric-gated, all default OFF, replaces single toggle
- Keys & Vault screen: combines SSH Keys, Save Vault Locally, Export/Import
- Local vault (mode 0x03): device-bound backup with DeviceFingerprint,
  password-only, verified on import via ANDROID_ID + brand + model
- Free users see "Import Local Vault", pro users can import both types
- Connection list: kebab menu replaced with direct Settings gear icon
- singleTask launch mode fixes Home→icon returning to connection list
- QR scanner locked to portrait orientation
- Deploy script deletes older APK versions on duero before uploading
- Test scripts updated for .dev package name

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:35:08 +02:00
jima
ca16651d69 Security audit: TOFU hardening, FLAG_SECURE, paste sanitization, compiler hardening
Production security audit (OWASP-aligned, prod-only scope):
- Default TOFU to REJECT when no UI handler (prevents silent accept during service-start window)
- Add FLAG_SECURE with preventScreenCapture preference (default ON, Settings → Security)
- Sanitize bracketed paste content (strip \e[200~/\e[201~ to prevent paste-escape injection)
- Add VaultCrypto ProGuard keep rule (prevents R8 stripping JNI methods in release)
- Create network_security_config.xml (system CAs only, cleartext disabled)
- Add compiler hardening flags to both native modules (-fstack-protector-strong, -D_FORTIFY_SOURCE=2)
- Set EXTRA_IS_SENSITIVE on all clipboard writes (terminal copy, key copy, SFTP path copy)
- Remove file:// from URL detection (prevents local file access via crafted terminal output)
- Verify signing certificate in pro APK migration (prevents fake APK granting free features)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:04:05 +02:00
jima
17250598b1 Subscription model, dev/prod flavors, vault import fix, font default
Major architecture change: single APK with Google Play Billing
subscriptions (monthly/yearly/lifetime) replacing free/pro build
flavors. Runtime feature gating via SubscriptionProFeatures with
grandfathering support. Dev/prod flavor split isolates all debug
infrastructure (ADB receiver, test profiles, log icons) from
production builds via DevConfig with const val dead code elimination.

- billing/: BillingManager, SubscriptionRepository, SubscriptionStore, SubscriptionState
- SubscriptionProFeatures replaces FreeProFeatures/FullProFeatures
- SubscriptionScreen for in-app purchase UI
- Activity-alias icon switching (teal free / gold pro)
- Pro APK migration detection
- Vault import: fix credential/key/jumpHost re-linking (id=0 bug)
- DB reset to v1 (new package, no migrations needed)
- Default font 10sp (was 14sp in library), global pref applied to new sessions
- Log download no longer clears the log (only Clear does)
- Active session timer always visible (not gated behind sessionTracking)
- Build timestamp shows version number (dev only)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 15:01:26 +02:00
jima
379d2e0677 Edge-to-edge layout, SFTP footer at nav bar, cleanup
- enableEdgeToEdge() before super.onCreate() for proper inset handling
- SFTP rendered at Box level (outside terminal Column) so Scaffold
  bottomBar with navigationBarsPadding() reaches the nav bar edge
- SFTP only composed when active tab (prevents invisible touch blocking)
- Status bar + 41dp top padding on SFTP overlay for tab bar visibility
- Removed windowInsetsPadding from terminal Column (edge-to-edge handles it)
- Cleaned unused imports and debug parameters
- docs: number row modes in KEYBOARD.md, SFTP folder reconnect done in FUTURE.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:36:19 +02:00
jima
ea98dafad1 QB re-attach, SFTP compact header, back button nav, slider fix, hint colors
- QB re-attaches when keyboard is recreated (number row mode change)
- LaunchedEffect keys include keyboard for settings re-apply
- Page indicators applied synchronously in update block (no flash)
- SFTP: compact header (Row instead of TopAppBar), tight breadcrumbs
- SFTP: system back button navigates up one folder (BackHandler)
- SFTP: bottomBar footer, reconnect remembers last folder
- SFTP: --ez sftp true launch param opens SFTP-only (no terminal)
- Slider: commit-on-drag-end prevents accidental changes while scrolling
- Hidden number hints: top-right corner position, light blue (#99CCFF)
- hintColor field on KeyDefinition for per-key hint color override
- Glossary: back button = OS nav bar back button

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 21:49:07 +02:00
jima
293fbcba1e Number row modes, mini numpad, font scaling, tablet defaults
- Number row setting: top (legacy), left/right (mini numpad), hidden (long-press)
- Mini numpad: JSON-defined side section (3x3+1 grid), separate KeyboardPageView
  with touch handling, LinearLayout split in AndroidView, clipChildren fix for
  SurfaceView rendering
- Font scaling: proportional 45%/25% of tallest key height, 10sp/7sp floor
  (was 13sp/8sp clamping to theme minimum, too big on small keyboards)
- Tablet defaults: sameSizeBoth=false, landscape height min 20% (phones 30%)
- Disconnect notification tap navigates to session, red badge on connection cards
- CKB hide/show via tab bar kebab menu
- KeyboardDisplaySettings Eagerly shared to avoid stale initial values

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 20:32:19 +02:00
jima
d2f925cc4d QB Customizer overhaul: view-swap pattern, 55-key pool, app editor, sequential action parser
QuickBar Customizer:
- Keys tab: view-swap pattern (Your Keys ↔ Available Keys full-screen)
- 55 keys in 4 sections (Modifiers/Navigation/Symbols/F-Keys) with OutlinedButton style
- App Shortcuts: list with undo-on-delete snackbar, tap to open editor
- App Shortcut Editor: editable name, maxCols stepper (2-6), key map drag-reorder
- Action format: sequential parser with [Ctrl]x, [Alt]x, [Esc], [F1]-[F12], 0xHH, \n, \t
- Validate/OK two-step flow, modifier insert buttons, auto-close tokens, case normalization
- Reset dialog with "also reset key order" checkbox

Connection list & tabs:
- Duplicate connection appears below original with 10s blue flash highlight
- Tab labels show end of name (start-ellipsis) for long names
- Duplicate nickname validation in EditConnectionScreen
- Save button in EditConnection title bar, Save & Connect full width

Naming & quality:
- "Quick Bar" → "QuickBar" (one word) across all UI, docs, locales
- All hardcoded strings moved to strings.xml (EN/ES/SV)
- StateFlow atomic .update{} for thread safety (20 sites in MainViewModel)
- Removed dead code: unused imports, variables, parameters
- Fixed localized string truncation (.take(60) → TextOverflow.Ellipsis)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 15:10:10 +02:00
jima
8e59db01f4 QB Customizer: drag-and-drop reorder, trashcan delete, grid for available keys
Replace up/down arrows with drag handles (Modifier.draggable) for reordering
in both Keys and App Shortcuts tabs. Replace ✕ with trashcan icon positioned
left of drag handle. Available keys now shown in a compact 4-column grid
instead of a vertical list. App shortcuts auto-collapse when drag starts.
Menu items within expanded apps also use drag-and-drop reorder.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:27:55 +02:00
jima
21d96b71f0 QB Customizer: reorder/add/remove keys and app shortcuts, CQB/AQB independent
Two-tab Compose dialog (Keys + App Shortcuts) accessible from KB Settings →
Quick Bar tab → Customize, or AQB Settings → Customize. Pro-gated.
Keys tab: 29-key pool, up/down reorder, remove, add from available.
App Shortcuts tab: reorder/add/remove apps, expand to edit individual key
maps with label + action (hex bytes, escape sequences, or text macros).
Independent DataStore prefs for CQB and AQB configurations.
ADB test (06_qb_customizer.py) verifies full flow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:56:15 +02:00
jima
f41d9298f6 Full codebase audit: security fixes, bug fixes, dead code, Compose migration
Security: QR key bytes zeroed in vault export/import, Socks5 null-safety fix.
Bugs: SSH auth cascade no longer silently succeeds without callback, stderr
readLoop no longer causes premature disconnect, dimension overlay cols×rows,
cursorUp/Down respects scroll region boundaries.
Quality: runBlocking→StateFlow (27 calls), MaterialAlertDialogBuilder→Compose
dialog, SSHJ stderr capture race serialized, dead code cleanup across all
modules, string resources for hardcoded text, doc updates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 22:32:03 +02:00
jima
a439e577a1 QB position/color/CTRL wiring, tab bar kebab menu, connect debounce
QB positioning:
- All 5 positions work: top, above_keyboard, vertical_left, vertical_right, none (hidden)
- Compose layout restructured: Row for vertical, Column for horizontal
- Orientation set in update block (not LaunchedEffect) for reliable timing
- Popup direction: RIGHT for top/left, LEFT for right, UP for bottom
- Popup item order reverses based on direction so vim stays closest to W
- Minimum 56dp width for vertical mode
- Scroll over W/snippets buttons no longer triggers them

QB color:
- Custom colors applied via setCustomColors(keyBg, keyText) on QuickBarView
- Reads CQB or AQB color prefs based on keyboard mode

CTRL modifier:
- AKB input intercepted: armed CTRL → Ctrl+key (a-z → 0x01-0x1A), ALT → ESC+key
- getActiveModifiers() exposed from TerminalKeyboard

Tab bar:
- + button replaced with kebab menu (New Session + KB/QB Settings)
- Session label duplicate numbering: SSHTest, SSHTest (2), SSHTest (3)
- Long labels show suffix: "…kap (2)" instead of "Nordka..."

Other:
- Connect debounce (1s) prevents rapid multi-tap opening multiple sessions
- Quick-connect independent: no saved connection lookup, shows user@host as label
- W glossary entry added

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 20:00:11 +02:00
jima
256d059d51 QB app shortcuts, Canvas key icons, bounded scroll, alt buffer reflow fix
Quick Bar:
- App shortcuts button (W icon, far-left) opens two-level popup:
  vim/nano/tmux/scr/F1-12 → 3-column key map grid
- AppShortcutsPopupView: Canvas-based, direction-aware, tap-to-select
- PopupWindow replaced with DecorView overlay + onBackPressedDispatcher
  + layout listener for AKB close detection (one BACK closes both)
- W button toggles popup; toggle_mod actions keep popup open
- Canvas-drawn key icons (tab, backtab, arrows, pgup, pgdn) via labelIcon
- Bounded scroll mode (infiniteScroll=false default)
- CTRL, HOME, END, PGUP, PGDN added to QB scrollable keys
- Menu keys (vim/nano/tmux/screen) removed from scrollable area

Tab bar:
- + button replaced with kebab menu (New Session + KB/QB Settings)
- KB Settings label adapts to keyboard mode (CKB vs AKB)

Bug fixes:
- Alt buffer reflow: main screen content preserved during resize when
  vim/htop is active (was lost on navigate away + return)
- Quick-connect: no saved connection lookup for connectionId=0, tab
  label shows user@host instead of saved connection nickname
- ADB broadcast: enter fires independently from text

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 18:53:54 +02:00
jima
2a87fb58d1 100% Compose migration, AQB/CQB separation, password prompt, ADB test framework
Compose migration (4 files, 2059 lines of View code → Compose):
- ThemePickerDialog: Compose Canvas preview, LazyColumn theme list
- TerminalDialogs: 6 dead dialogs deleted, 2 migrated (hostKey, authPrompt)
  with TerminalDialogRequest sealed interface on MainViewModel for
  imperative→declarative bridge. Added PasswordDialog for no-stored-pw case.
- SnippetDialogs: full-screen Compose dialog with LazyColumn, search,
  inline create form, context menu
- KeyboardSettingsDialog: TabRow, Slider, Canvas preview, color picker.
  Data classes extracted to KeyboardModels.kt

AQB/CQB separation:
- Independent Quick Bar preferences for AKB vs CKB modes
- Settings UI mode-aware: CKB shows full keyboard dialog, AKB shows QB-only
- AQB positions filtered (no above/below keyboard)
- New docs: KEYBOARD.md, GLOSSARY.md (TV, AKB, CKB, AQB, CQB)

Password prompt:
- TerminalService prompts for password when no stored auth (SSHAuth.None)
- Compose PasswordDialog with remember checkbox
- clearPassword ADB broadcast for test cleanup

ADB test framework (Python):
- test.py runner with menu, --all, single test modes
- AI visual verification via claude -p reading screenshots
- 5 tests, 52 checks: connect, htop, vim, password prompt, multi-session
- Timestamped results with manifest.json for cross-run comparison

Coding conventions updated: 100% Compose mandated, no programmatic Views.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 15:00:35 +02:00
jima
bb7662ca63 Audit: security hardening, bug fixes, dead code cleanup across all modules
vault-crypto: secure_zero for all sensitive buffers (Argon2 core, BLAKE2b,
GCM tag/lengths), JNI NewByteArray null checks, Kotlin input validation.
lib-ssh: SSHSession thread safety (debugLogBuffer sync), EOF check fix,
session reuse guard, stderr restoration in finally block.
lib-terminal-view: italic rendering (faux skew), hidden text (fg=bg),
DECCKM reset fix, reflowResize mode preservation, render thread TOCTOU fix.
lib-terminal-keyboard: dead code removal, kotlin.math migration, touch
allocation elimination in KeyboardPageView.
app: Hilt-injected CredentialStore (was duplicate instance), hardcoded
strings to resources (BiometricAuthManager, VaultImportViewModel),
null safety (!! elimination in 5 files), deprecated API fixes, unused
imports/strings cleanup, test API drift fixes, migration 10→11 test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 08:44:45 +02:00
jima
429ad179ec SFTP: ProxyJump, keepalive, disconnect UI, Connect to Terminal; fling fix, callback audit
SFTP standalone sessions now use shared buildJumpChain for ProxyJump support,
start keepalive monitor for zombie detection, and have full disconnect/reconnect
UI with SSH state monitoring. Tab overflow menu adds "Connect to Terminal".

Fling scroll removes hard distance cap (flingMaxRows) so momentum decays
naturally. Selection toolbar Google button wired. Mouse reporting gated by
pro feature. Dead code (onSaveSnippet) removed. Write logging for paste debug.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 00:39:03 +02:00
jima
2fd8308056 Mouse tap-only, ProxyJump probe fix, Ed25519 key loading, jump tunnel monitor
Mouse mode: only taps forwarded as clicks, scroll/select/fling always work.
Active pane zIndex ensures touch events reach correct session.
SSHKeyLoader: auto-detect key format, Ed25519 PKCS#8 via net.i2p.crypto.eddsa.
ProxyJump probe: tunneled connections trust isConnected (no raw socket).
Jump monitor: watches tunnel state, force-disconnects on tunnel death.
Copy Private Key works without biometric lock enabled.
KeyLoadingTest: 9 tests covering all key formats.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 22:55:29 +02:00
jima
9c980bbea7 Session lifecycle: fix service death on unbind, ProxyJump ID, quick-connect history
Critical fixes:
- ensureStarted() counteracts previous stopSelf() before creating any session,
  preventing service destruction when Activity unbinds (screen off, Home, task switch)
- onTaskRemoved() re-starts service to survive swipe-from-recents
- Auto-reconnect no longer removes session from map (prevents empty-map window)
- Auto-reconnect clones password CharArray before disconnect zeroes the original
- checkStopSelf() now includes SFTP sessions in the empty check

ProxyJump fix:
- onConnect callback now passes savedConnectionId directly instead of re-looking
  up by host/port/username (LIMIT 1 picked wrong duplicate connection)
- Threaded through ConnectionListScreen → NavGraph → MainActivity → MainViewModel

UX improvements:
- Quick-connect history (pro): stores 100 entries with timestamps, shows 20 in
  dropdown with relative dates, X to remove, dismiss on focus loss
- Disconnect snackbar suppressed for active session (user already sees the bar)
- DisconnectedBar: muted dark background with teal/grey buttons instead of
  red/green/blue Christmas lights
- Session auto-switch works for Idle state (ProxyJump sessions start in Idle
  during jump chain build)

Refactoring:
- SshConnectionHelper extracted: shared auth lookup, TOFU, session factory
  (eliminates duplication between connectSSH, buildJumpChain, openSftpSession)
- Remove redundant stopForeground call from updateNotification

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 16:33:45 +02:00
jima
8cf34f7a8b Tab bar: type-specific colors, SFTP auto-close, connection list SFTP menu
- Tab colors preserve type identity in all states: teal (SSH), amber (SFTP),
  violet (Telnet). Disconnected tabs show dimmed type color + red dot instead
  of uniform red, so you can tell session types apart at a glance.
- SFTP tabs auto-close when parent SSH disconnects (fixes frozen SFTP tab
  after overnight disconnect).
- SFTP tab labels use connection alias without "SFTP" suffix (amber color
  already identifies type), with host/username fallback to avoid "Session N".
- New SFTP Session option in connection list context menu and session picker
  bottom sheet (amber folder icon, requires connected SSH session).
- i18n: new_sftp_session string in EN/ES/SV.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 10:46:50 +02:00
jima
34325f7119 Full codebase audit: crypto hardening, 6 critical bugs, i18n, dead code cleanup
Security:
- lib-vault-crypto: secure_zero (volatile memset ptr) replaces memset for all
  sensitive memory zeroing, null checks on JNI array access, key/password
  buffers zeroed before release, input validation on Kotlin API
- lib-ssh: keyboard-interactive auth no longer falls back to empty password

Critical bugs fixed:
- SFTP multi-select delete now handles all selected files (was only first)
- reconnectSession() handles Telnet and Local shell types (was always SSH)
- _activeSessions StateFlow updates now atomic via .update{}
- Telnet sessions now execute startup commands
- Clipboard queries cached on UI thread (render thread crash risk on some OEMs)
- TextAttr color mask fixed from 20-bit to 24-bit

Thread safety: @Volatile on SftpSession.sftpClient, SftpViewModel._allEntries;
synchronized debugLogBuffer; onViewRecycled prevents allPageViews leak

i18n: 37 new string resources (EN/ES/SV) for disconnect reasons, network
status, terminal banners, port forward errors, toolbar labels, toast messages

Dead code: removed boilerplate tests, tautological assertions, unused
StateFlows/functions, redundant night theme, unused string resources

Tests: fixed startupCommands mock (false→true), updated stale test names

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 10:00:26 +02:00
jima
5b07e2d686 SFTP: fix SSH disconnect, file type icons, multi-select, hidden files
Critical fix: SFTPClient.close() kills the parent SSH transport by
sending a channel EOF. Removed the close() call — just null out the
reference, SFTP subsystem cleans up when SSH connection closes.

Other SFTP fixes:
- Single SFTP session open (was opening twice — race corrupted transport)
- SftpSessionManager.open() is now suspend (no 500ms guesswork delay)
- SftpScreen always composed (preserves SAF launchers across picker)
- Keyboard/QuickBar hidden on SFTP tabs (tab type check)
- Disconnect notifications suppressed when app in foreground
- Title shows connection name (titleSmall style)

New SFTP features:
- File type icons (32dp): APK, image, video, audio, archive, PDF, code,
  shell, keys, text — color-coded per type
- Multi-select: tap icon to select, batch download/delete bar
- Hidden files hidden by default, toggle in overflow menu
- i18n strings for hidden files toggle (EN/ES/SV)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 02:53:25 +02:00
jima
678295b03b CKB hide/show, keyboard hints, QB fixes, nav fix, logcat in log export
- CKB: temporary hide via ckbHidden state (not pref change), tap terminal to reshow
- CKB/QB input now scrolls terminal to bottom (was IME-only)
- Keyboard hints: all keys get hints (removed label length filter), smart
  positioning (above by default, flips below if off-screen, clamped to edges)
- Long-press popup: auto-shrinks cells to fit screen width
- QB: hints on all keys (onKeyDown on ACTION_DOWN for all, not just repeatable),
  scroll cancels key repeat
- PICK_HOST Back returns to terminal when sessions are open
- Copy Log ZIP now includes logcat.txt (last 5000 lines)
- TerminalKeyboard.attachTo() safe for re-attachment
- SFTP: long-press context menu, settings detail expansion, i18n additions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 01:12:38 +02:00
jima
1a35a9b57f Post-audit cleanup: i18n, Hilt DI, oversized file extractions
- Extract 40+ hardcoded strings from TerminalDialogs, FreeProFeatures,
  KeyboardSettingsDialog, VaultExportSheet, VaultImportSheet to strings.xml
  with EN/ES/SV translations. SSH technical labels kept in English.
- Add StringResolver interface for ViewModel localization (injected via Hilt)
  — fixes hardcoded strings in VaultExport/Import, Main, KeyManager ViewModels.
- TerminalService: replace duplicate Room instance with @AndroidEntryPoint
  Hilt-injected DAOs. Extract SftpSessionManager, PortForwardManager,
  StartupCommandRunner into standalone classes.
- EditConnectionScreen: extract PortForwardSection (bottom sheet, rows, dialogs).
- ConnectionListScreen: extract ConnectionItemCard and TimeFormatUtils.
- TerminalSurfaceView: extract MouseReporter.
- Delete TODO2.md (all items completed). Update TODO.md, TECHNICAL.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 22:17:44 +02:00
jima
1d3b4b053c Full codebase audit: 7 critical bugs, DECSCNM rendering, UTF-8 chunk buffering, i18n
Critical bugs fixed:
- Missing MIGRATION_10_11 in TerminalService (crash on upgrade)
- jumpHostSessions was global (multi-session corruption) — moved to SessionEntry
- KeyboardSettings reset skipped every other view (forward-remove loop)
- DCS parser leaked backslash (ESC \ consumed 1 byte instead of 2)
- SOCKS5 clientThreads grew unbounded (memory leak)
- TelnetSession scope leaked on connect failure
- Host key + auth dialogs never wired up — silent TOFU, broken 2FA

Parser/renderer:
- DECSCNM (reverse screen mode) now rendered — swaps fg/bg screen-wide
- UTF-8 partial sequences buffered across chunk boundaries (11 new tests)

Hardcoded strings → string resources (EN/ES/SV):
- KeyManagerScreen (~22 strings), ConnectionListScreen (~24 strings)
- TerminalService/SessionNotifier notifications, SftpScreen, SftpViewModel
- SessionTabBar fallback label

Dead code removed:
- showSaveSnippet, qrDerivedKey, LANGUAGE_OPTIONS, LightColorScheme
- notifyOnReconnect preference, setPreviewTextColor, markActionTime
- anchorX/anchorY, production Log.d calls, 7 dead string resources

Code quality:
- SftpSession streams wrapped in .use{}, FileLogger.getLogFile respects
  useDownloads, FastSSHConfig unused keepalive removed, var→val fixes
- TabTypeAndLabelTest updated for TELNET/LOCAL enum values

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:55:28 +02:00
jima
9e5c3100e2 Session stability, logging, disconnect notifications, save output, pinch-zoom in mouse mode
- Fix foreground service lifecycle: keep service alive while disconnected sessions exist,
  preventing Android from killing sessions when app is backgrounded during WiFi drops
- Fix cleanupDisconnectedSession: keep sessions in _activeSessions map so UI shows
  disconnect bar and tab indicator instead of silently removing them
- FileLogger: append mode (persists across app opens), fallback to app-private dir,
  ZIP export with .bin recordings, comprehensive trace logging across all components
- SessionNotifier: batched disconnect notifications (5s window), auto-cancel on reconnect,
  smart handling of partial reconnects (5 disconnect, 3 reconnect → shows 2 remaining)
- Save Output: export scrollback + screen to Download/<alias>_<timestamp>.txt
- Disconnect bar: styled pill buttons, timestamps on all disconnect/reconnect messages
- Session tab bar: red accent + dark red background for disconnected tabs
- In-app snackbar: brief "Duero disconnected" alert when session drops while in app
- Pinch-zoom in mouse mode: scale detector fed before mouse intercept, multi-finger
  gestures bypass mouse reporting so htop/vim resize works
- Snippet manager: duplicate action, list refreshes after edit/delete/duplicate
- Notify on disconnect setting (default on), build timestamp on connection list
- Deploy script fix, SessionRecorder rolling reset at 1MB

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 15:13:15 +02:00
jima
40650286dc VT52 compatibility mode with DEC Special Graphics charset
Implement VT52 mode as a standalone delegate class (Vt52Parser), activated
via CSI ?2l (DECANM reset) and exited via ESC <. Supports all VT52 escape
sequences: cursor movement (A-D), direct addressing (ESC Y row col), erase
(J/K), reverse index (I), home (H), and DECID response (ESC /Z).

Graphics character mode (ESC F/G) maps ASCII 0x5F-0x7E to DEC Special
Graphics glyphs (box-drawing, math symbols) — same charset as VT100's G0 '0'.

37 unit tests, all vttest tests 1-11 now pass including test 7 (VT52 mode).
New docs/TERMINAL_PARSER.md with full parser architecture, state machine,
DECCOLM quirks, VT52 implementation details, and graphics charset table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:47:40 +02:00
jima
2a3d18cd9c Vault export/import: encrypted backup with password or QR code
New lib-vault-crypto module with Argon2id + AES-256-GCM in C via JNI.
Export screen (full Scaffold) with item selection, password mode (min 12
chars, upper/lower/digit/special), and QR mode (background generation,
save/share gating, confirmation dialog). Import via bottom sheet with
SAF file picker, password/QR decryption, and conflict resolution.
Kebab menu replaces settings icon in ConnectionListScreen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 23:22:31 +02:00
jima
2958d422c6 Docs update, dead code cleanup, new tests, consolidate markdown files
- Remove dead code: MainViewModel.switchToPreviousSession(),
  getConnectionIdForSession(), unused DisposableEffect import
- Fix RefactorPhase1Test: remove tests referencing deleted Routes.SFTP
- Add 32 unit tests for TabType, SftpTabInfo, duplicate label logic
- Update CLAUDE.md: SDK 27/36, Room v11, single-Activity UI section,
  SFTP+port forwarding now implemented
- Update TECHNICAL.md: Room v11, MIGRATION_10_11, SessionEntry fields,
  MainViewModel SFTP tabs, TerminalPane softInputEnabled, SftpScreen
  in Layer 1
- Move FULL_AUDIT.md and AUDIT_LOG.md to docs/, add architecture notes
- Delete TERMINAL_KEYBOARD_LIBRARY.md and MEGA_TASK.md (redundant)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 22:04:02 +02:00
jima
dc1cfa6a0f Persist font size to Room for single-session hosts, copy on duplicate
Three-tier zoom persistence:
- View: live fontSizeSp on TerminalSurfaceView (view lifetime)
- Service: SessionEntry.fontSizeSp (survives Activity death)
- Room: SavedConnection.fontSizeSp (survives app restart)

Rules:
- Zoom always saves to SessionEntry
- If only 1 session for the host: also saves to Room (permanent)
- If 2+ sessions for same host: SessionEntry only (per-session)
- New connection: reads default from Room, seeds SessionEntry
- Duplicate: copies fontSizeSp from source SessionEntry
- View recreation: factory reads from SessionEntry before surface fires

Added Room migration 10→11 (fontSizeSp REAL column).
Documented three-tier model in TECHNICAL.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:26:09 +02:00
jima
7fa4d7c380 Final audit pass: AUDIT_LOG updated, TECHNICAL.md modernized
- AUDIT_LOG: added Final Audit Pass section with all 20 checklist items,
  6/9 Phase 3 gaps resolved, fixes summary table, remaining gaps noted
- TECHNICAL.md: replaced TerminalActivity/SftpActivity sections with
  single-Activity architecture (MainActivity, MainViewModel, TerminalPane,
  SessionTabBar, three-layer Box). Updated SDK versions. Removed references
  to deleted files (TerminalConnectionHelper, TerminalSessionNav, etc.)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 23:35:00 +01:00
jima
a8ab99ffae SFTP file browser: full implementation replacing stub
lib-ssh — SftpSession:
- Wraps SSHJ SFTPClient with coroutines API on single-threaded dispatcher
- listDirectory (folders first, sort by name/size/date), downloadFile,
  uploadFile (64KB streaming with progress), createDirectory, rename,
  delete, canonicalize
- SftpEntry data class with Unix permissions string formatting
- Reuses existing SSHClient via newSFTPClient() — no second TCP connection

app — SftpViewModel:
- Directory browsing with currentPath/entries/isLoading/error StateFlows
- Transfer tracking: TransferState with ACTIVE/COMPLETE/FAILED/CANCELLED
- Large file confirmation (≥5MB) via confirmLargeDownload SharedFlow
- Upload, download, mkdir, rename, delete, sort order, download URI prefs

app — SftpActivity (replaces stub):
- Dark terminal aesthetic, programmatic layout
- Path breadcrumb bar with tappable segments
- File list: folder/file icons, name, permissions, size, date
- Tap folder to navigate, tap file to download, long-press context menu
- Bottom action bar: Upload (SAF multi-file) + Download folder (SAF tree)
- Transfer progress cards with direction badges, cancel, retry, auto-dismiss
- SAF integration: persistable URI permissions, stale URI recovery

app — TerminalService SFTP session management:
- openSftpSession/getSftpSession/closeSftpSession methods
- Auto-cleanup on parent SSH session disconnect

22 new unit tests (SftpSession, SftpViewModel, SftpEntrySort)
25 new SFTP string resources in EN/ES/SV

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 18:21:03 +01:00
jima
902ff21417 Session navigation: top bar tabs + side drawer, SFTP stub, SOCKS5 test docs
Dual-mode session navigation for TerminalActivity:
- Top bar mode: 36dp tab strip with scrollable session tabs (teal accent),
  SFTP tab (amber), + popup menu (New session / Open SFTP / Switch to drawer)
- Drawer mode: 260dp left DrawerLayout with session list (teal dot indicators),
  SFTP section, hamburger button on quick bar, footer to switch back
- In-session switching via popup/drawer footer; global default in Settings
- Session switching rebinds TerminalSurfaceView.screenBuffer to target session

New files:
- TerminalSessionNav.kt — tab bar, drawer, session switching, hamburger button
- SftpActivity.kt — stub ("SFTP — coming soon"), registered in manifest
- SessionNavTest.kt — 8 unit tests for NavMode enum and label truncation

Settings:
- Session navigation preference (Top bar / Drawer) in Appearance section
- Show session tab bar toggle (when top bar mode selected)
- sessionNavStyle + showSessionTabBar in TerminalPreferences + SettingsViewModel

Also: rewrote docs/SOCKS5_TEST.md to use adb forward from dev machine

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 17:27:50 +01:00
jima
ece519d768 Security audit, dead code sweep, SOCKS5 dynamic forwarding, 120+ tests
Security fixes:
- Password zeroing in connectSSHInternal catch block (jump chain failures)
- API level guard for TelephonyManager.signalStrength (min SDK 27 vs API 28)
- Port forward delete confirmation dialog added to EditConnectionScreen

Dead code removal (95 entries):
- 88 unused string resources from EN/ES/SV
- 5 unused color resources (Android template defaults)
- 2 unused XML resources (backup_rules, data_extraction_rules)

DRY refactoring:
- EditConnectionViewModel: buildSavedConnection(), saveOrDeletePassword()
- TerminalDisconnectedMode: createBarActionButton()

SOCKS5 dynamic port forwarding (new feature):
- Socks5Proxy.kt: RFC 1928 + RFC 1929 SOCKS5 proxy server
- CONNECT command with IPv4/IPv6/domain, NO_AUTH + username/password auth
- 64KB relay buffers, thread-per-connection, proper half-close
- Specific error codes: ConnectException→0x05, UnknownHostException→0x04
- TerminalService DYNAMIC branch now opens real SOCKS5 tunnel via
  SSHClient.newDirectConnection() per SOCKS5 CONNECT request
- UI: default port 1080 pre-fill, SOCKS5 hint text

Port forwarding verification:
- Schema, DAO, UI, ViewModel, tunnel activation all verified
- Confirmed NOT gated by ProFeatures (free + pro both have access)

Test coverage (120+ new tests):
- Unit: CredentialStore, KeyGenerator, ScreenBuffer, VtParser,
  ModifierStateManager, TelnetSession, JumpChain, AutoReconnect,
  ProFeatures, PortForwardDao, TunnelLifecycle, Socks5Proxy,
  FieldVisibility, FreeGate
- Instrumented: CredentialStore on-device, Room migrations 1-10,
  BiometricAuthManager timeout, ConnectionManager launch,
  CASCADE delete, port forward CRUD, SOCKS5 flow
- docs/SOCKS5_TEST.md: manual smoke test commands

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 16:32:17 +01:00
jima
169cb0c5e3 Update TECHNICAL.md: comprehensive docs for all recent features
Added/updated: password auth flow, dialog system, Firebase, ADB testing,
network-aware reconnect, selection snap, quick bar enhancements, port
forwarding schema, launcher icons, permissions, string resources.
Expanded security section with credential storage, TOFU, biometric,
auth cascade, and redaction details. DB version 7→10, removed ExtraKeysBar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 14:30:15 +01:00
jima
73e7629a5a Password auth dialog, credential fixes, dialog icons, Firebase, ADB testing
- Password auth: server-driven flow (try connect first, prompt on auth failure),
  IME Done key triggers Connect, masked by default, keyboard focus/show
- Credential fixes: deletePassword when cleared in edit screen, no auto-save
  of password in autoSaveConnection (only explicit "Remember" saves)
- Dialog icons: moved from centered body to title bar (setIcon) across all dialogs
- Keyboard: defer terminalView focus until Connected state, show AKB explicitly
  after auth retry succeeds
- Password dialog: ADJUST_PAN soft input mode, requestFocus + showSoftInput
- Firebase Analytics + Crashlytics integration (BoM, plugins, .gitignore)
- ADB testing: broadcast receiver enhancements, test script, docs/TESTING.md
- Quick bar: double-tap word jump, CTRL modifier for system keyboard,
  key repeat on quick bar, green highlight for active modifiers
- Snippet hint colors lightened (#BBBBBB)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 13:06:39 +01:00
jima
fcd57c82e1 SSH port forwarding, Swedish/Spanish keyboard layouts, language selector
Port Forwarding:
- PortForward Room entity + DAO + DB v10 migration
- Full-screen add/edit dialog with type selector (Local/Remote/Dynamic)
- Validation: local port ≥ 1024 hard error, 0.0.0.0 warning
- EADDRINUSE shows red error in terminal, no crash
- Runtime: LOCAL and REMOTE via SSHJ after shell starts
- WiFi lock forced when port forwards active
- All forwards closed on disconnect, notification shows count
- 13 unit tests for entity fields and validation

Keyboard Languages:
- Swedish layout (layout_qwerty_sv.json): å after p, ö ä after l
- Spanish layout (layout_qwerty_es.json): ñ after l
- Swedish language pack (lang_sv.json): å ä ö accents, Swedish symbols
- Language selector in keyboard settings dialog
- Per-connection language saved, rebuilds keyboard on change
- Language loaded synchronously before keyboard setup

Strings:
- All EditConnectionScreen hardcoded strings → stringResource
- Port forwarding strings in EN/ES/SV
- startup_commands, one_command_per_line added

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:11:38 +01:00
jima
3a07b5532a Keyboard settings dialog, disconnect info, render loop fix, WiFi-off crash fix
Keyboard settings (long-press space → gear):
- Tabbed dialog: Keyboard tab (size portrait/landscape, page indicators,
  color presets + hex picker, haptic, hints, repeat/longpress delays)
  and Quick Bar tab (position, size, color)
- Vertical QB overlays terminal from top to above KB
- Separate colors for KB and QB, custom hex input
- Pro gate: free users see settings read-only with upgrade banner
- Preview widget showing phone layout

Quick bar auto-repeat on long-press (arrows, Tab, PgUp/PgDn).

Disconnect info banner: shows classified reason (Socket lost,
Disconnected by host, etc.) + WiFi/mobile signal % in terminal.

Render loop: idle wait 500ms (was 16ms) — stops 60fps spin when idle.

WiFi-off crash: added SSHJ DisconnectListener on transport to catch
reader thread crashes. Wrapped WiFi lock + network status in try-catch.

Reconnect auth fix: password fallback to entry.password when
CredentialStore returns null. Added diagnostic logging.

Technical docs: docs/TECHNICAL.md (20KB, all modules).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 10:27:25 +01:00