Restic-Kompatibilität, POST, rekursives MKCOL, findstr /C: Fix
- Server: POST für Uploads, rekursives MKCOL/PUT, ensureFolderExists - PUT: fehlende Elternordner werden erstellt - Scripts: findstr /C: für Literalsuche (Punkt-Konflikt behoben) - Docs: Restic + rclone Hinweis Made-with: Cursor
This commit is contained in:
@@ -81,6 +81,14 @@ C:\Pfad\zu\internxt-webdav\scripts\stop-webdav.cmd 8080
|
||||
|
||||
Der Server startet im Hintergrund und ist nach ~5 Sekunden bereit.
|
||||
|
||||
## Restic + rclone
|
||||
|
||||
```bash
|
||||
restic -r rclone:internxt-webdav:repo-name init
|
||||
```
|
||||
|
||||
Der Server erstellt fehlende Ordner rekursiv (MKCOL). Bei 500-Fehlern: Server-Log prüfen (`PUT Fehler:`), Token mit `npm run token-refresh` erneuern.
|
||||
|
||||
## WebDAV-Credentials (für Duplicati, Explorer)
|
||||
|
||||
Der Server erwartet **Basic Auth**. Ohne `WEBDAV_USER`/`WEBDAV_PASS` in `.env` akzeptiert er **beliebige** Credentials – Sie können in Duplicati z.B. Benutzername `backup` und Passwort `geheim` eintragen. Mit `WEBDAV_USER` und `WEBDAV_PASS` werden nur diese Credentials akzeptiert.
|
||||
|
||||
@@ -19,8 +19,8 @@ if %errorlevel% neq 0 (
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM Pruefen ob Server bereits laeuft (0.0.0.0:0 = Listening, sprachunabhaengig)
|
||||
netstat -an | findstr ":%PORT% " | findstr "0.0.0.0:0" > nul 2>&1
|
||||
REM Pruefen ob Server bereits laeuft (0.0.0.0:0 = Listening)
|
||||
netstat -an | findstr /C:":%PORT% " | findstr /C:"0.0.0.0:0" > nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
echo WebDAV-Server laeuft bereits.
|
||||
exit /b 0
|
||||
|
||||
@@ -8,9 +8,9 @@ if "%1"=="" (set PORT=3005) else (set PORT=%1)
|
||||
|
||||
REM Prozess auf Port finden und beenden
|
||||
REM Filter: Port + "0.0.0.0:0" = Listening (sprachunabhaengig)
|
||||
for /f "tokens=5" %%a in ('netstat -ano 2^>nul ^| findstr ":%PORT% " ^| findstr "0.0.0.0:0"') do (
|
||||
for /f "tokens=5" %%a in ('netstat -ano 2^>nul ^| findstr /C:":%PORT% " ^| findstr /C:"0.0.0.0:0"') do (
|
||||
taskkill /PID %%a /F > nul 2>&1
|
||||
echo WebDAV-Server beendet (PID %%a).
|
||||
echo WebDAV-Server beendet - PID %%a
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
|
||||
@@ -67,8 +67,8 @@ function basicAuth(req, res, next) {
|
||||
|
||||
app.use(basicAuth);
|
||||
|
||||
// Request-Body: PUT als Raw (Datei-Upload), PROPFIND als Text
|
||||
app.use(express.raw({ type: (req) => req.method === 'PUT', limit: '1gb' }));
|
||||
// Request-Body: PUT/POST als Raw (Datei-Upload), PROPFIND als Text
|
||||
app.use(express.raw({ type: (req) => req.method === 'PUT' || req.method === 'POST', limit: '1gb' }));
|
||||
app.use(express.text({ type: 'application/xml', limit: '1kb' }));
|
||||
|
||||
/**
|
||||
@@ -254,7 +254,37 @@ async function getContext() {
|
||||
}
|
||||
|
||||
/**
|
||||
* MKCOL Handler – Ordner anlegen
|
||||
* Stellt sicher, dass ein Ordnerpfad existiert (erstellt fehlende Eltern rekursiv).
|
||||
* @returns {Promise<{ uuid: string } | null>} Ordner oder null
|
||||
*/
|
||||
async function ensureFolderExists(storage, rootUuid, path) {
|
||||
const segments = pathToSegments(path);
|
||||
let currentUuid = rootUuid;
|
||||
|
||||
for (const segment of segments) {
|
||||
const [contentPromise] = storage.getFolderContentByUuid({ folderUuid: currentUuid });
|
||||
const content = await contentPromise;
|
||||
const child = content?.children?.find((c) => {
|
||||
const name = getPlainName(c.name, c.plain_name ?? c.plainName, c.parent_id ?? c.parentId, null);
|
||||
return sanitizeForPath(name).toLowerCase() === sanitizeForPath(segment).toLowerCase();
|
||||
});
|
||||
if (child) {
|
||||
currentUuid = child.uuid;
|
||||
} else {
|
||||
const [createPromise] = storage.createFolderByUuid({
|
||||
parentFolderUuid: currentUuid,
|
||||
plainName: segment,
|
||||
});
|
||||
const created = await createPromise;
|
||||
currentUuid = created?.uuid;
|
||||
if (!currentUuid) return null;
|
||||
}
|
||||
}
|
||||
return { uuid: currentUuid };
|
||||
}
|
||||
|
||||
/**
|
||||
* MKCOL Handler – Ordner anlegen (rekursiv: fehlende Eltern werden erstellt)
|
||||
*/
|
||||
async function handleMkcol(req, res) {
|
||||
let path = req.url || '/';
|
||||
@@ -279,7 +309,10 @@ async function handleMkcol(req, res) {
|
||||
|
||||
try {
|
||||
const { storage, rootUuid } = await getContext();
|
||||
const parent = await resolveFolder(storage, rootUuid, parentPath);
|
||||
const parent =
|
||||
parentPath && parentPath !== '/'
|
||||
? await ensureFolderExists(storage, rootUuid, parentPath)
|
||||
: { uuid: rootUuid };
|
||||
if (!parent) {
|
||||
res.status(409).send('Übergeordneter Ordner existiert nicht');
|
||||
return;
|
||||
@@ -582,7 +615,10 @@ async function handlePut(req, res) {
|
||||
const parentPath = segmentsToPath(segments.slice(0, -1));
|
||||
const fileName = segments[segments.length - 1];
|
||||
|
||||
const parent = await resolveFolder(storage, rootUuid, parentPath);
|
||||
let parent = await resolveFolder(storage, rootUuid, parentPath);
|
||||
if (!parent && parentPath && parentPath !== '/') {
|
||||
parent = await ensureFolderExists(storage, rootUuid, parentPath);
|
||||
}
|
||||
if (!parent) {
|
||||
res.status(409).send('Zielordner existiert nicht');
|
||||
return;
|
||||
@@ -664,7 +700,7 @@ async function handlePut(req, res) {
|
||||
|
||||
res.status(201).send();
|
||||
} catch (err) {
|
||||
console.error('PUT Fehler:', err.message);
|
||||
console.error('PUT Fehler:', path, err.message);
|
||||
if (err.message?.includes('Token') || err.response?.status === 401) {
|
||||
res.status(401).send('Nicht autorisiert – Token erneuern: https://drive.internxt.com');
|
||||
return;
|
||||
@@ -676,7 +712,7 @@ async function handlePut(req, res) {
|
||||
// WebDAV Endpoints
|
||||
app.options('*', (req, res) => {
|
||||
res.set('DAV', '1, 2');
|
||||
res.set('Allow', 'OPTIONS, PROPFIND, GET, HEAD, PUT, DELETE, MKCOL, MOVE');
|
||||
res.set('Allow', 'OPTIONS, PROPFIND, GET, HEAD, PUT, POST, DELETE, MKCOL, MOVE');
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
@@ -700,7 +736,7 @@ app.use((req, res, next) => {
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (req.method === 'PUT') {
|
||||
if (req.method === 'PUT' || req.method === 'POST') {
|
||||
handlePut(req, res).catch((err) => {
|
||||
console.error('PUT unhandled:', err);
|
||||
if (!res.headersSent) res.status(500).send(err.message);
|
||||
|
||||
Reference in New Issue
Block a user