Initial commit: WebDAV-Adapter für Internxt Drive

- Browser-Token-Auth (INXT_TOKEN, INXT_MNEMONIC)
- Phase 1: PROPFIND (Verzeichnis auflisten)
- Drive API + Pfad-Resolver
- Dokumentation: Auth, Architektur, WSL

Made-with: Cursor
This commit is contained in:
2026-02-28 10:54:29 +01:00
commit 7c1866e6fc
15 changed files with 2170 additions and 0 deletions

98
docs/auth-analysis.md Normal file
View File

@@ -0,0 +1,98 @@
# Internxt Auth-Analyse: Web vs CLI vs Rclone
## Kernbefund: Client-Identifikation bestimmt Zugang
Der Backend-Server blockiert bestimmte Account-Tiers basierend auf der **Client-Identifikation**:
| Client | clientName | Login-Methode | Endpoint | Status für eingeschränkte Tiers |
|--------|-----------|---------------|----------|--------------------------------|
| **drive-web** | `drive-web` | `login()` | `/auth/login` | ✅ Erlaubt |
| **drive-desktop** | `drive-desktop` | `login()` | `/auth/login` | ✅ Erlaubt |
| **internxt-cli** | `internxt-cli` | `loginAccess()` | `/auth/login/access` | ❌ Blockiert |
| **rclone** | (rclone-adapter) | loginAccess-ähnlich | `/auth/login/access` | ❌ Blockiert |
## Quellen
### drive-web ([auth.service.ts](drive-web/src/services/auth.service.ts))
```typescript
const getAuthClient = (authType: 'web' | 'desktop') => {
const AUTH_CLIENT = {
web: SdkFactory.getNewApiInstance().createAuthClient(), // clientName: "drive-web"
desktop: SdkFactory.getNewApiInstance().createDesktopAuthClient(), // clientName: "drive-desktop"
};
return AUTH_CLIENT[authType];
};
// Login mit authClient.login() - NICHT loginAccess()
return authClient.login(loginDetails, cryptoProvider)
```
- **createAuthClient()**: `clientName: packageJson.name` = `"drive-web"`
- **createDesktopAuthClient()**: `clientName: "drive-desktop"`
- **Methode**: `login()` (nicht `loginAccess`)
### CLI ([auth.service.ts](https://github.com/internxt/cli/blob/main/src/services/auth.service.ts))
```typescript
const authClient = SdkManager.instance.getAuth();
const data = await authClient.loginAccess(loginDetails, CryptoService.cryptoProvider);
```
- **getAppDetails()**: `clientName: packageJson.clientName` = `"internxt-cli"` (aus [package.json](https://github.com/internxt/cli/blob/main/package.json))
- **Methode**: `loginAccess()` (nicht `login`)
### SDK Factory ([drive-web](drive-web/src/app/core/factory/sdk/index.ts))
```typescript
private static getAppDetails(): AppDetails {
return {
clientName: packageJson.name, // "drive-web"
clientVersion: packageJson.version,
customHeaders,
};
}
private static getDesktopAppDetails(): AppDetails {
return {
clientName: 'drive-desktop',
clientVersion: packageJson.version,
};
}
```
## Lösung für WebDAV-Wrapper
**Strategie:** Den Auth-Client so konfigurieren, dass er sich als `drive-web` ausgibt und `login()` statt `loginAccess()` verwendet.
1. **@internxt/sdk** mit `Auth.client(apiUrl, appDetails, apiSecurity)` verwenden
2. **appDetails** setzen: `{ clientName: "drive-web", clientVersion: "1.0" }`
3. **login()** aufrufen (nicht `loginAccess()`)
4. CryptoProvider wie in drive-web implementieren (passToHash, decryptText, getKeys, parseAndDecryptUserKeys)
## Abhängigkeiten für WebDAV-Wrapper
- `@internxt/sdk` (Version 1.13.x oder kompatibel drive-web nutzt 1.13.2)
- `@internxt/lib` (für aes, Crypto)
- Crypto-Logik aus drive-web: `app/crypto/services/keys.service`, `app/crypto/services/utils`
- Keys-Format: ECC + Kyber (post-quantum)
## Aktueller Status (Stand: Analyse)
- **CRYPTO_SECRET**: Korrekt (Salt-Decryption OK mit `6KYQBP847D4ATSFA`)
- **loginWithoutKeys**: Liefert weiterhin "Wrong login credentials" möglicherweise lehnt das Backend diesen Flow für bestimmte Account-Typen (z.B. mailbox.org-Partner) ab
- **login() mit Keys**: Kyber-WASM schlägt unter Windows fehl (`@dashlane/pqc-kem-kyber512-node`)
## Nächste Schritte
1. **Ansatz B testen**: Browser-basierter Token-Extrakt im Web einloggen, Session-Token aus localStorage/DevTools lesen, im Wrapper verwenden
2. **login() unter Linux**: Kyber-Paket könnte unter Linux funktionieren
3. **Internxt-Support**: Nachfragen, ob Partner-Accounts (mailbox.org) andere Auth-Flows nutzen
## CRYPTO_SECRET und API-URL
Aus [internxt/cli .env.template](https://github.com/internxt/cli/blob/main/.env.template):
- **DRIVE_API_URL**: `https://gateway.internxt.com/drive`
- **APP_CRYPTO_SECRET**: `6KYQBP847D4ATSFA`
Der PoC nutzt diese Werte als Fallback.

View File

@@ -0,0 +1,68 @@
# Browser-Token-Authentifizierung (Ansatz B)
Da der API-Login für Ihren Account-Typ blockiert ist, können Sie sich im Browser einloggen und die Session-Daten für den WebDAV-Wrapper verwenden.
## Ablauf
1. Auf https://drive.internxt.com einloggen
2. Token und Mnemonic aus dem Browser extrahieren
3. In `.env` eintragen
4. WebDAV-Server starten
## Token extrahieren
### Schritt 1: Alle gespeicherten Keys anzeigen
Auf **https://drive.internxt.com** eingeloggt sein. DevTools (F12) → **Console**:
```javascript
// Alle localStorage-Keys anzeigen
Object.keys(localStorage).filter(k => k.includes('x') || k.includes('token') || k.includes('Token')).forEach(k => console.log(k));
```
Damit sehen Sie, welche Keys es gibt (z.B. `xNewToken`, `xMnemonic`, `xUser`).
### Schritt 2: Token und Mnemonic auslesen
```javascript
// Token und Mnemonic anzeigen
console.log('Token:', localStorage.getItem('xNewToken') || localStorage.getItem('xToken') || '(nicht gefunden)');
console.log('Mnemonic:', localStorage.getItem('xMnemonic') || '(nicht gefunden)');
```
### Schritt 3: Falls nichts gefunden wird
- **Application-Tab prüfen:** DevTools → **Application** (oder **Anwendung**) → links **Local Storage****https://drive.internxt.com** auswählen. Dort alle Einträge durchsehen.
- **Richtige URL:** Sie müssen auf `https://drive.internxt.com` sein (nicht internxt.com) und **eingeloggt** sein nach dem Login auf `/drive` oder `/app`.
- **Session vs. Local:** Manche Werte liegen in `sessionStorage`. Testen mit:
```javascript
console.log('sessionStorage:', Object.keys(sessionStorage));
```
- **Alle Keys anzeigen:** Zum Debuggen alle Keys mit Werten:
```javascript
for (let i = 0; i < localStorage.length; i++) {
const k = localStorage.key(i);
console.log(k + ':', localStorage.getItem(k)?.substring(0, 50) + '...');
}
```
## .env eintragen
```
INXT_TOKEN=eyJhbGciOiJIUzI1NiIs...
INXT_MNEMONIC=word1 word2 word3 ...
```
## WebDAV-Server starten
```bash
npm start
```
Server läuft auf `http://127.0.0.1:3005`. Phase 1 (PROPFIND) ist aktiv Verzeichnisinhalt kann aufgelistet werden. Windows Explorer: Netzlaufwerk verbinden → `http://127.0.0.1:3005`.
## Hinweise
- **Token-Ablauf**: Tokens laufen nach einiger Zeit ab (typisch Stunden). Bei 401-Fehlern erneut einloggen und Token aktualisieren.
- **Sicherheit**: Mnemonic und Token sind hochsensibel. Nicht in Git committen, `.env` in `.gitignore` belassen.
- **Nur für Sie**: Die Tokens sind an Ihre Session gebunden. Für andere Nutzer funktioniert dieser Ansatz nicht.

View File

@@ -0,0 +1,35 @@
# CRYPTO_SECRET aus drive.internxt.com ermitteln
Falls der Login mit "Wrong login credentials" fehlschlägt, ist vermutlich der `CRYPTO_SECRET` falsch. drive-web nutzt `REACT_APP_CRYPTO_SECRET`, der CLI-Wert (`6KYQBP847D4ATSFA`) kann abweichen.
## Methode 1: DEBUG-Modus (Salt-Decryption prüfen)
```bash
DEBUG=1 npm run auth-test
```
- **"Salt-Decryption OK"** → CRYPTO_SECRET stimmt, Problem liegt woanders (Passwort, API)
- **"Salt-Decryption fehlgeschlagen"** → CRYPTO_SECRET ist falsch
## Methode 2: Secret im Browser suchen
1. https://drive.internxt.com öffnen
2. DevTools (F12) → **Sources**
3. **Strg+Shift+F** (Suche in allen Dateien)
4. Suchen nach:
- `6KYQBP847D4ATSFA` falls gefunden, wird derselbe Wert wie beim CLI genutzt
- `REACT_APP_CRYPTO_SECRET` oder `CRYPTO_SECRET`
- Hex-Strings (z.B. 16 Zeichen wie `a1b2c3d4e5f6...`)
5. Gefundenen Wert in `.env` eintragen:
```
CRYPTO_SECRET=gefundener_wert
```
## Methode 3: drive-web lokal bauen (mit bekanntem Secret)
Falls Sie Zugriff auf drive-web haben und den korrekten Secret kennen:
1. In `drive-web` eine `.env` mit `REACT_APP_CRYPTO_SECRET=...` anlegen
2. `yarn build` ausführen
3. In den Build-Artefakten nach dem eingebetteten Wert suchen

View File

@@ -0,0 +1,74 @@
# WebDAV-Server Architektur
## Empfohlener Ansatz: Adapter (nicht Proxy)
Der WebDAV-Server ist ein **Adapter**: Er implementiert das WebDAV-Protokoll und übersetzt Anfragen in Internxt Drive API + Network-Aufrufe. Es wird **nicht** zu einem anderen WebDAV-Server weitergeleitet.
```mermaid
flowchart LR
subgraph Client [WebDAV Client]
Finder[Finder/Cyberduck]
Rclone[Rclone]
end
subgraph Adapter [WebDAV Adapter]
WebDAV[WebDAV Server]
Mapping[Path zu UUID]
Crypto[Encrypt/Decrypt]
end
subgraph Internxt [Internxt Backend]
DriveAPI[Drive API]
Network[Bridge/Network]
end
Finder -->|PROPFIND GET PUT| WebDAV
WebDAV --> Mapping
Mapping --> DriveAPI
WebDAV --> Crypto
Crypto --> Network
```
## Datenfluss
| WebDAV-Anfrage | Internxt-Operation |
|----------------|-------------------|
| PROPFIND (Verzeichnisinhalt) | Storage.getFolderContentByUuid |
| GET (Datei lesen) | File-Metadaten → Network.download → Entschlüsseln |
| PUT (Datei schreiben) | Verschlüsseln → Network.upload → createFileEntry |
| MKCOL (Ordner anlegen) | Storage.createFolderByUuid |
| DELETE | Trash oder permanent delete |
| MOVE | Storage.moveFileByUuid / moveFolderByUuid |
## Komplexität
- **Einfach:** PROPFIND, MKCOL nur Drive API, keine Verschlüsselung
- **Mittel:** DELETE, MOVE Drive API
- **Aufwändig:** GET, PUT Bridge/Network + Mnemonic-Verschlüsselung
Die drive-web nutzt `Network.client` (Bridge) und `NetworkFacade` für Up-/Download. Die Bridge-Credentials kommen aus der User-Session.
## Implementierungsreihenfolge
1. **Phase 1:** PROPFIND (Verzeichnis auflisten) ✅ implementiert
2. **Phase 2:** MKCOL, DELETE, MOVE
3. **Phase 3:** GET (Download) Bridge + Entschlüsselung
4. **Phase 4:** PUT (Upload) Verschlüsselung + Bridge
### Hinweis: Ordnernamen
Internxt nutzt Zero-Knowledge-Verschlüsselung. Die API liefert verschlüsselte Namen (`name`). Die Pfadauflösung funktioniert, weil WebDAV-URLs diese Namen enthalten. Eine spätere Phase kann Namensentschlüsselung mit Mnemonic ergänzen (drive-web Crypto-Logik).
## Token vs. Bridge-Credentials
- **Drive API:** Nutzt `xNewToken` (Authorization: Bearer)
- **Network/Bridge:** Braucht `bridgeUser` + `userId` (aus User-Credentials) und Mnemonic für Verschlüsselung
**Bridge-Credentials aus refreshUser:** Der Endpoint `/users/refresh` liefert `user` (UserResponseDto) mit:
- `bridgeUser` E-Mail des Nutzers
- `userId` wird mit SHA256 gehasht und als Bridge-Passwort genutzt
- `bucket` Bucket-ID für Uploads
- `mnemonic` für Dateiverschlüsselung
- `rootFolderId` Root-Ordner-UUID
Damit liefert der Browser-Token (via refreshUser) alle nötigen Daten für Drive API und Bridge.

36
docs/wsl-setup.md Normal file
View File

@@ -0,0 +1,36 @@
# Entwicklung unter WSL (login() mit Keys)
Unter Windows schlägt das Kyber-WASM-Modul fehl. Unter WSL (Ubuntu/Debian) funktioniert es in der Regel.
## Voraussetzungen
- WSL2 mit Ubuntu oder Debian
- Node.js 20+ (`node -v`)
## Setup
```bash
# Im WSL-Terminal
cd /mnt/c/Users/mbusc/source/repos/internxt-webdav
# Abhängigkeiten installieren (inkl. Kyber für login mit Keys)
npm install
# .env mit Credentials (INXT_EMAIL, INXT_PASSWORD)
# Optional: DEBUG=1 für Salt-Check
```
## Auth-PoC mit login() testen
Zuerst den Auth-PoC auf `login()` umstellen (mit Keys):
```bash
npm run auth-test
```
Falls der Fehler "Wrong login credentials" weiterhin auftritt, liegt das Problem nicht am Kyber-WASM, sondern am Backend/Account-Typ.
## Projektpfad
Windows-Pfad: `c:\Users\mbusc\source\repos\internxt-webdav`
WSL-Pfad: `/mnt/c/Users/mbusc/source/repos/internxt-webdav`