No description
Find a file
Tronax 084fec3948
chore: clean up .gitignore, track gradle-wrapper.jar, drop .zcode/
- Rewrite .gitignore with proper sections; add ignores for common
  Android/IDE/OS artifacts (*.so, *.hprof, app/release/, Thumbs.db,
  .vscode/, *.swp).
- Track gradle/wrapper/gradle-wrapper.jar so ./gradlew works after a
  fresh clone (the previous negation rule was a no-op without a prior
  *.jar ignore, so the jar was never committed).
- Stop tracking the local .zcode/ tooling directory (kept on disk).
2026-08-03 18:10:41 +02:00
app feat: initialize Android SSH manager app with terminal and crypto 2026-08-03 18:04:29 +02:00
gradle chore: clean up .gitignore, track gradle-wrapper.jar, drop .zcode/ 2026-08-03 18:10:41 +02:00
.gitignore chore: clean up .gitignore, track gradle-wrapper.jar, drop .zcode/ 2026-08-03 18:10:41 +02:00
build.gradle.kts feat: initialize Android SSH manager app with terminal and crypto 2026-08-03 18:04:29 +02:00
gradle.properties feat: initialize Android SSH manager app with terminal and crypto 2026-08-03 18:04:29 +02:00
gradlew feat: initialize Android SSH manager app with terminal and crypto 2026-08-03 18:04:29 +02:00
README.md feat: initialize Android SSH manager app with terminal and crypto 2026-08-03 18:04:29 +02:00
settings.gradle.kts feat: initialize Android SSH manager app with terminal and crypto 2026-08-03 18:04:29 +02:00

Mobile SSH Manager

Android-App (Kotlin + Jetpack Compose) zum Verwalten von SSH-Verbindungen und zum interaktiven Arbeiten auf Servern über ein eingebautes Terminal.

Stand / 1Password-Hinweis (bitte lesen)

Der ursprüngliche Wunsch war 1Password SSH Key Support. Das ist auf Android aktuell technisch nicht möglich:

  • Der 1Password SSH Agent ist Desktop-only (macOS, Windows, Linux).
  • Es gibt keine Kotlin/Java-SDK und keinen Android-Agent, nur Go/JS/Python-SDKs (Desktop/Server) und einen offenen Feature-Request für Android.
  • Drittanbieter-Apps können 1Password-Schlüssel auf Android nicht einbinden.

Stattdessen unterstützt diese App den realistischen Workflow: Private Keys werden als Datei importiert (Storage Access Framework) und AES-GCM-verschlüsselt via Android Keystore gespeichert. Der praktische Weg mit 1Password ist also: Key am Desktop aus 1Password exportieren → aufs Handy übertragen → in der App importieren. Kein 1Password-Bezug im UI, weil er ehrlicherweise nicht eingehalten werden könnte.

Funktionen

  • Hosts anlegen/bearbeiten/löschen (Name, Host, Port, User, Auth-Art)
  • Authentifizierung per Passwort oder per importiertem Private Key
  • Keys importieren (OpenSSH-/PEM-/PKCS8-/Ed25519-Formate via sshj + Bouncy Castle)
  • Verbindung testen direkt aus dem Host-Editor
  • Interaktives Terminal: Compose-Canvas-Renderer auf der Termux-terminal-emulator Engine (VT100/xterm, ANSI-Farben, Bold/Italic/Underline, Cursor, Alt-Buffer)
  • Tastatur-Erweiterungsleiste (ESC, Tab, Backspace, Pfeile)
  • Dunkles, terminal-orientiertes Theme

Sicherheit

  • Sensitive DB-Felder (Passwörter, private Keys) werden mit einem AES-GCM-Schlüssel aus dem Android Keystore ver- und entschlüsselt.
  • Klartext steht nur transient im Arbeitsspeicher (während Editieren/Verbinden).
  • Host-Verifikation ist aktuell promiscuous (MVP) — Known-Hosts-Speicher ist ein todo.

Architektur

core/crypto       KeystoreCrypto (AES-GCM, Android Keystore)
data              Room (Host, SshKey, Group) + DAOs + Repositories + DI
domain/model      AuthType
ssh               SshConnectionManager (sshj), SshKeyParser, SshSupport (Bouncy Castle)
terminal          SshTerminalBridge (sshj <-> TerminalEmulator), TerminalTextStyle, KeyEncoder
terminal/ui       TerminalCanvas (Compose-Renderer), TerminalViewModel, TerminalScreen
com.termux.terminal.TerminalBufferAccess  Adapter auf package-private Buffer-Felder
ui                theme, nav, hostlist, hosteditor, keylist, keyimport, components

Terminal-Pipeline

SSH-Server ──► sshj Shell.getInputStream()
                 │  (Reader-Thread)
                 ▼
          TerminalEmulator.append(bytes)   ← aktualisiert TerminalBuffer
                 │
                 ▼ (Revision-Signal)
          TerminalCanvas (Compose) liest über TerminalBufferAccess
                 │
Tastatur ──► KeyEncoder ──► SshTerminalBridge.send() ──► sshj Shell.getOutputStream()

Die Termux-Engine wird direkt (ohne TerminalSession, das lokale Prozesse startet) genutzt. Da TerminalBuffer.mLines/TerminalRow.mText package-private sind, greift TerminalBufferAccess als Klasse im com.termux.terminal-Package darauf zu.

Stack

Teil Technologie
Sprache Kotlin 2.0.21 (K2)
UI Jetpack Compose (BOM 2024.10), Material 3
DI Hilt
DB Room 2.6
SSH sshj 0.39
Krypto Bouncy Castle 1.78 (Key-Parsing) + Android Keystore (Feldverschlüsselung)
Terminal-Engine Termux terminal-emulator 0.118.3 (via JitPack)
Build AGP 8.7.3, Gradle 8.11.1, JDK 17 target / JDK 21 zum Bauen
SDK compileSdk 34, minSdk 26

Bauen

Voraussetzung: Android SDK mit platforms;android-34 und build-tools sowie JDK 17/21.

# Mit dem Gradle-Wrapper (JDK 21 empfohlen):
JAVA_HOME=/pfad/zum/jdk-21 ./gradlew assembleDebug

# APK liegt dann hier:
app/build/outputs/apk/debug/app-debug.apk

Installieren auf einem verbundenen Gerät/Emulator:

./gradlew installDebug
# oder
adb install app/build/outputs/apk/debug/app-debug.apk

Bekannte Einschränkungen / Todos

  • Passphrase-geschützte Keys: Beim Import wird die Passphrase geprüft, für das Login müssen Keys aktuell unverschlüsselt gespeichert werden (MVP).
  • Known-Hosts: Host-Keys werden noch nicht verifiziert.
  • Hintergrund-Persistenz: Sessions überleben Konfigurationswechsel (die Activity fängt configChanges ab), aber für echtes Background-Keeping ist ein Foreground-Service nötig (Folgearchitektur).
  • Terminal-Fidelity: Ziel ist robuste Shell/vim/htop-Nutzung; exotische Features (Sixel, Maus-Reporting, Unicode-Width-Polierung) sind nicht Teil des MVP.
  • Echtes 1Password: erst möglich, wenn 1Password Android-Support anbietet.