feat: initialize Android SSH manager app with terminal and crypto
This commit is contained in:
commit
66417cc194
55 changed files with 3711 additions and 0 deletions
119
README.md
Normal file
119
README.md
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
# 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][1p-fr].
|
||||
- Drittanbieter-Apps können 1Password-Schlüssel auf Android nicht einbinden.
|
||||
|
||||
[1p-fr]: https://www.1password.community/developers-69/feature-request-android-and-ssh-19991
|
||||
|
||||
**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.
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
./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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue