import { Request } from "express"; import { WebDAVClient } from "webdav"; import { DIRS } from "./server"; import fetch from 'node-fetch' import { XMLParser } from 'fast-xml-parser'; export async function statOne(fpath: string, client: WebDAVClient) { const parent = fpath.replace(/\/[^/]+$/, '') || '/', base = fpath.split('/').filter(Boolean).pop(), list = await client.getDirectoryContents(parent, { deep: false }).catch(err => { console.error(`error for "${parent}":`); console.error(err); if (err.response?.status === 404) { throw `Path "${fpath}" not found`; } throw err; }), entry = Array.isArray(list) ? list.find((e: any) => e.basename === base) : undefined; if (!entry) throw `Path "${fpath}" not found`; return { etag: entry.etag as string, size: Number(entry.size), mime: entry.mime as string | undefined }; } export const toRegExp = (spec: string): RegExp | null => { // slash-delimited form: /pattern/flags const m = spec.match(/^\/(.+)\/([a-z]*)$/i); try { if (m) { const [, source, flags] = m; return new RegExp(source, flags); } // raw pattern form: "pattern" return new RegExp(spec); } catch { return null; } } export function checkIfHasPerms(req: Request | string) { try { if (typeof req === 'string') { if (req.includes('..')) return false; return !DIRS || DIRS.find(r => req.match(r)); } else if (!req.body) { return false; } const { fpath, obj_type, deep, usecache } = req.body, o = { fpath, obj_type, deep, usecache }; if (!fpath) return false; if (!DIRS) return o; if (fpath.includes('..')) return false; return DIRS.find(r => fpath.match(r)) ? o : false; } catch (err) { console.error(err); return false; } } function buildCountPropfindXml() { return ` `; } const authHeaders = (() => { const u = process.env.NEXTCLOUD_APP_ID!, p = process.env.NEXTCLOUD_APP_PASS!, token = Buffer.from(`${u}:${p}`).toString("base64"); return `Basic ${token}`; })(); export async function getDirectoryFileCount(dirPath: string, client: WebDAVClient) { const url = client.getFileDownloadLink(dirPath), xml = buildCountPropfindXml(); const resp = await fetch(url, { method: "PROPFIND", headers: { "Content-Type": "text/xml", "Depth": "0", "Authorization": authHeaders }, body: xml }); if (!resp.ok) { throw resp; } // parse XML const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: "@_", allowBooleanAttributes: true, numberParseOptions: { hex: false, leadingZeros: false } }), text = await resp.text(), doc = parser.parse(text), objs = doc['d:multistatus']['d:response']['d:propstat'], obj = objs.find((o: any) => o['d:status'].includes("200"))['d:prop']; return { file_count: obj['nc:contained-file-count'], folder: obj['nc:contained-folder-count'] }; }