Docker, Token-Refresh mit Puppeteer, 401-Hinweise
- Dockerfile + .dockerignore - token-refresh: Chromium öffnet drive.internxt.com, extrahiert Tokens - 401-Antworten: Link zu drive.internxt.com - Docs: Token-Erneuerung Option A (automatisch) / B (manuell) Made-with: Cursor
This commit is contained in:
7
.dockerignore
Normal file
7
.dockerignore
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
node_modules
|
||||||
|
.git
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
*.log
|
||||||
|
docs
|
||||||
|
drive-web
|
||||||
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci --omit=dev
|
||||||
|
|
||||||
|
COPY src ./src
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
EXPOSE 3005
|
||||||
|
|
||||||
|
CMD ["node", "src/server.js"]
|
||||||
21
README.md
21
README.md
@@ -19,6 +19,25 @@ npm start
|
|||||||
|
|
||||||
Server läuft auf `http://127.0.0.1:3005`.
|
Server läuft auf `http://127.0.0.1:3005`.
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Image bauen
|
||||||
|
docker build -t internxt-webdav .
|
||||||
|
|
||||||
|
# Container starten (Umgebungsvariablen aus .env)
|
||||||
|
docker run -d --name internxt-webdav -p 3005:3005 --env-file .env internxt-webdav
|
||||||
|
|
||||||
|
# Oder einzelne Variablen übergeben
|
||||||
|
docker run -d -p 3005:3005 \
|
||||||
|
-e INXT_TOKEN="..." \
|
||||||
|
-e INXT_MNEMONIC="..." \
|
||||||
|
-e CRYPTO_SECRET="6KYQBP847D4ATSFA" \
|
||||||
|
internxt-webdav
|
||||||
|
```
|
||||||
|
|
||||||
|
WebDAV erreichbar unter `http://localhost:3005`.
|
||||||
|
|
||||||
## WebDAV-Funktionen
|
## WebDAV-Funktionen
|
||||||
|
|
||||||
- **PROPFIND** – Verzeichnis auflisten
|
- **PROPFIND** – Verzeichnis auflisten
|
||||||
@@ -50,5 +69,5 @@ Server läuft auf `http://127.0.0.1:3005`.
|
|||||||
|-------|--------------|
|
|-------|--------------|
|
||||||
| `npm start` | WebDAV-Server starten |
|
| `npm start` | WebDAV-Server starten |
|
||||||
| `npm run token-test` | Token prüfen |
|
| `npm run token-test` | Token prüfen |
|
||||||
| `npm run auth-test` | API-Login testen (E-Mail/Passwort) |
|
| `npm run token-refresh` | Browser öffnen, einloggen → Tokens automatisch extrahieren |
|
||||||
| `npm run debug-names` | Namensentschlüsselung testen |
|
| `npm run debug-names` | Namensentschlüsselung testen |
|
||||||
|
|||||||
@@ -87,9 +87,27 @@ robocopy "i:\" "." /NFL /NDL
|
|||||||
# Variante 3: Explorer – Datei per Drag & Drop kopieren
|
# Variante 3: Explorer – Datei per Drag & Drop kopieren
|
||||||
``` Windows Explorer: Netzlaufwerk verbinden → `http://127.0.0.1:3005`.
|
``` Windows Explorer: Netzlaufwerk verbinden → `http://127.0.0.1:3005`.
|
||||||
|
|
||||||
|
## Token erneuern (bei 401 / abgelaufen)
|
||||||
|
|
||||||
|
Tokens laufen nach einiger Zeit ab (typisch Stunden). Bei 401-Fehlern oder „Nicht autorisiert“:
|
||||||
|
|
||||||
|
### Option A: Automatisch (Chromium)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run token-refresh
|
||||||
|
```
|
||||||
|
|
||||||
|
Öffnet einen Browser mit drive.internxt.com. Einloggen – die Tokens werden automatisch extrahiert und in der Konsole ausgegeben. In `.env` eintragen, Server neu starten.
|
||||||
|
|
||||||
|
### Option B: Manuell
|
||||||
|
|
||||||
|
1. **[https://drive.internxt.com](https://drive.internxt.com)** öffnen und erneut einloggen
|
||||||
|
2. Token und Mnemonic wie oben (Schritt 2) aus der Console auslesen
|
||||||
|
3. `.env` mit den neuen Werten aktualisieren
|
||||||
|
4. WebDAV-Server neu starten
|
||||||
|
|
||||||
## Hinweise
|
## Hinweise
|
||||||
|
|
||||||
- **Bridge-API**: Der Download nutzt die Internxt Bridge mit `x-api-version: 2` und den Headern `internxt-version`/`internxt-client`. Ohne diese liefert die Bridge 400.
|
- **Bridge-API**: Der Download nutzt die Internxt Bridge mit `x-api-version: 2` und den Headern `internxt-version`/`internxt-client`. Ohne diese liefert die Bridge 400.
|
||||||
- **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.
|
- **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.
|
- **Nur für Sie**: Die Tokens sind an Ihre Session gebunden. Für andere Nutzer funktioniert dieser Ansatz nicht.
|
||||||
|
|||||||
1378
package-lock.json
generated
1378
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"auth-test": "node src/auth-poc.js",
|
"auth-test": "node src/auth-poc.js",
|
||||||
"token-test": "node src/token-test.js",
|
"token-test": "node src/token-test.js",
|
||||||
|
"token-refresh": "node src/token-refresh.js",
|
||||||
"debug-names": "node src/debug-name-decrypt.js",
|
"debug-names": "node src/debug-name-decrypt.js",
|
||||||
"start": "node src/server.js"
|
"start": "node src/server.js"
|
||||||
},
|
},
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
"bip39": "^3.1.0",
|
"bip39": "^3.1.0",
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"express": "^4.18.0"
|
"express": "^4.18.0",
|
||||||
|
"puppeteer": "^24.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ async function handlePropfind(req, res) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('PROPFIND Fehler:', err.message);
|
console.error('PROPFIND Fehler:', err.message);
|
||||||
if (err.message?.includes('Token') || err.response?.status === 401) {
|
if (err.message?.includes('Token') || err.response?.status === 401) {
|
||||||
res.status(401).send('Nicht autorisiert – Token erneuern');
|
res.status(401).send('Nicht autorisiert – Token abgelaufen. Neu einloggen: https://drive.internxt.com');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
res.status(500).send(err.message || 'Interner Fehler');
|
res.status(500).send(err.message || 'Interner Fehler');
|
||||||
@@ -304,7 +304,7 @@ async function handleMkcol(req, res) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('MKCOL Fehler:', err.message);
|
console.error('MKCOL Fehler:', err.message);
|
||||||
if (err.message?.includes('Token') || err.response?.status === 401) {
|
if (err.message?.includes('Token') || err.response?.status === 401) {
|
||||||
res.status(401).send('Nicht autorisiert');
|
res.status(401).send('Nicht autorisiert – Token erneuern: https://drive.internxt.com');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
res.status(500).send(err.message || 'Interner Fehler');
|
res.status(500).send(err.message || 'Interner Fehler');
|
||||||
@@ -343,7 +343,7 @@ async function handleDelete(req, res) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('DELETE Fehler:', err.message);
|
console.error('DELETE Fehler:', err.message);
|
||||||
if (err.message?.includes('Token') || err.response?.status === 401) {
|
if (err.message?.includes('Token') || err.response?.status === 401) {
|
||||||
res.status(401).send('Nicht autorisiert');
|
res.status(401).send('Nicht autorisiert – Token erneuern: https://drive.internxt.com');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
res.status(500).send(err.message || 'Interner Fehler');
|
res.status(500).send(err.message || 'Interner Fehler');
|
||||||
@@ -429,7 +429,7 @@ async function handleMove(req, res) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('MOVE Fehler:', err.message);
|
console.error('MOVE Fehler:', err.message);
|
||||||
if (err.message?.includes('Token') || err.response?.status === 401) {
|
if (err.message?.includes('Token') || err.response?.status === 401) {
|
||||||
res.status(401).send('Nicht autorisiert');
|
res.status(401).send('Nicht autorisiert – Token erneuern: https://drive.internxt.com');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
res.status(500).send(err.message || 'Interner Fehler');
|
res.status(500).send(err.message || 'Interner Fehler');
|
||||||
@@ -499,7 +499,7 @@ async function handleGet(req, res) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('GET Fehler:', err.message);
|
console.error('GET Fehler:', err.message);
|
||||||
if (err.message?.includes('Token') || err.response?.status === 401) {
|
if (err.message?.includes('Token') || err.response?.status === 401) {
|
||||||
res.status(401).send('Nicht autorisiert');
|
res.status(401).send('Nicht autorisiert – Token erneuern: https://drive.internxt.com');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!res.headersSent) res.status(500).send(err.message || 'Interner Fehler');
|
if (!res.headersSent) res.status(500).send(err.message || 'Interner Fehler');
|
||||||
@@ -666,7 +666,7 @@ async function handlePut(req, res) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('PUT Fehler:', err.message);
|
console.error('PUT Fehler:', err.message);
|
||||||
if (err.message?.includes('Token') || err.response?.status === 401) {
|
if (err.message?.includes('Token') || err.response?.status === 401) {
|
||||||
res.status(401).send('Nicht autorisiert');
|
res.status(401).send('Nicht autorisiert – Token erneuern: https://drive.internxt.com');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!res.headersSent) res.status(500).send(err.message || 'Interner Fehler');
|
if (!res.headersSent) res.status(500).send(err.message || 'Interner Fehler');
|
||||||
|
|||||||
58
src/token-refresh.js
Normal file
58
src/token-refresh.js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* Token-Refresh: Öffnet drive.internxt.com im Browser, wartet auf Login,
|
||||||
|
* extrahiert Token und Mnemonic aus localStorage.
|
||||||
|
*
|
||||||
|
* Aufruf: npm run token-refresh
|
||||||
|
*
|
||||||
|
* Browser öffnet sich (headed). Einloggen, dann werden die Tokens ausgegeben.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import puppeteer from 'puppeteer';
|
||||||
|
|
||||||
|
const DRIVE_URL = 'https://drive.internxt.com';
|
||||||
|
const POLL_MS = 2000;
|
||||||
|
const TIMEOUT_MS = 5 * 60 * 1000; // 5 Min
|
||||||
|
|
||||||
|
async function getTokens(page) {
|
||||||
|
return page.evaluate(() => {
|
||||||
|
const token = localStorage.getItem('xNewToken') || localStorage.getItem('xToken');
|
||||||
|
const mnemonic = localStorage.getItem('xMnemonic');
|
||||||
|
return { token, mnemonic };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log('Starte Browser – bitte auf', DRIVE_URL, 'einloggen.\n');
|
||||||
|
|
||||||
|
const browser = await puppeteer.launch({
|
||||||
|
headless: false,
|
||||||
|
defaultViewport: null,
|
||||||
|
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const page = (await browser.pages())[0] || (await browser.newPage());
|
||||||
|
await page.goto(DRIVE_URL, { waitUntil: 'networkidle2' });
|
||||||
|
|
||||||
|
const start = Date.now();
|
||||||
|
while (Date.now() - start < TIMEOUT_MS) {
|
||||||
|
const { token, mnemonic } = await getTokens(page);
|
||||||
|
if (token && mnemonic) {
|
||||||
|
console.log('\n=== Tokens gefunden – in .env eintragen ===\n');
|
||||||
|
console.log('INXT_TOKEN=' + token);
|
||||||
|
console.log('INXT_MNEMONIC=' + mnemonic);
|
||||||
|
console.log('\n===========================================\n');
|
||||||
|
await browser.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await new Promise((r) => setTimeout(r, POLL_MS));
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Timeout – keine Tokens gefunden. Bitte einloggen und erneut ausführen.');
|
||||||
|
await browser.close();
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((e) => {
|
||||||
|
console.error(e);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user