'use strict'; const { requestBuffer } = require('./http-client'); const { normalizeNcPath, filenameFromPath } = require('./utils'); function authHeader(config) { const token = Buffer.from(`${config.username}:${config.password}`).toString('base64'); return `Basic ${token}`; } function webDavBase(config) { const base = config.nextcloudUrl.replace(/\/$/, ''); return `${base}/remote.php/dav/files/${encodeURIComponent(config.username)}`; } function encodePathSegments(ncPath) { const normalized = normalizeNcPath(ncPath); return normalized .split('/') .filter(Boolean) .map((segment) => encodeURIComponent(segment)) .join('/'); } function webDavUrl(config, ncPath) { const rel = encodePathSegments(ncPath); return rel ? `${webDavBase(config)}/${rel}` : webDavBase(config); } function tlsOptions(config) { return { rejectUnauthorized: config.verifyTls !== false && config.verifyTls !== 'false' }; } async function webdavGet(config, ncPath) { const url = webDavUrl(config, ncPath); const res = await requestBuffer({ url, method: 'GET', headers: { Authorization: authHeader(config) }, rejectUnauthorized: tlsOptions(config).rejectUnauthorized }); if (res.statusCode === 404) { throw new Error(`WebDAV 404: filen finns inte: ${normalizeNcPath(ncPath)}`); } if (res.statusCode === 401 || res.statusCode === 403) { throw new Error(`WebDAV ${res.statusCode}: kontrollera app-lösenord och användare`); } if (res.statusCode < 200 || res.statusCode >= 300) { throw new Error(`WebDAV GET misslyckades (${res.statusCode}) för ${normalizeNcPath(ncPath)}`); } return { buffer: res.body, filename: filenameFromPath(ncPath), ncPath: normalizeNcPath(ncPath), contentType: res.headers['content-type'] }; } async function ensureFolder(config, folderPath) { const normalized = normalizeNcPath(folderPath); if (!normalized || normalized === '/') { return; } const parts = normalized.split('/').filter(Boolean); let current = ''; for (const part of parts) { current += '/' + part; const url = webDavUrl(config, current); const res = await requestBuffer({ url, method: 'MKCOL', headers: { Authorization: authHeader(config) }, rejectUnauthorized: tlsOptions(config).rejectUnauthorized }); if (res.statusCode !== 201 && res.statusCode !== 405 && res.statusCode !== 301) { if (res.statusCode >= 400) { throw new Error(`WebDAV MKCOL misslyckades (${res.statusCode}) för ${current}`); } } } } async function webdavPut(config, ncPath, buffer, contentType) { const dest = normalizeNcPath(ncPath); const folder = dest.substring(0, dest.lastIndexOf('/')) || '/'; await ensureFolder(config, folder); const url = webDavUrl(config, dest); const res = await requestBuffer({ url, method: 'PUT', headers: { Authorization: authHeader(config), 'Content-Type': contentType || 'application/octet-stream', 'Content-Length': buffer.length }, body: buffer, rejectUnauthorized: tlsOptions(config).rejectUnauthorized }); if (res.statusCode === 401 || res.statusCode === 403) { throw new Error(`WebDAV ${res.statusCode}: kontrollera app-lösenord`); } if (res.statusCode < 200 || res.statusCode >= 300) { throw new Error(`WebDAV PUT misslyckades (${res.statusCode}) för ${dest}`); } return { statusCode: res.statusCode, destNcPath: dest, filename: filenameFromPath(dest) }; } async function webdavPropfindFileId(config, ncPath) { const url = webDavUrl(config, ncPath); const body = ` `; const res = await requestBuffer({ url, method: 'PROPFIND', headers: { Authorization: authHeader(config), Depth: '0', 'Content-Type': 'application/xml; charset=utf-8' }, body, rejectUnauthorized: tlsOptions(config).rejectUnauthorized }); if (res.statusCode < 200 || res.statusCode >= 300) { throw new Error(`PROPFIND misslyckades (${res.statusCode}) för ${normalizeNcPath(ncPath)}`); } const text = res.body.toString('utf8'); const match = text.match(/(\d+)<\/oc:fileid>/i) || text.match(/(\d+)<\/nc:fileid>/i); if (!match) { throw new Error(`Kunde inte hitta fileId för ${normalizeNcPath(ncPath)}`); } return parseInt(match[1], 10); } module.exports = { webDavUrl, webdavGet, webdavPut, webdavPropfindFileId, ensureFolder };