clawvault 2.6.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/command-registration.test.js +1 -3
- package/bin/register-core-commands.js +10 -23
- package/bin/register-maintenance-commands.js +3 -20
- package/bin/register-query-commands.js +23 -0
- package/bin/register-task-commands.js +1 -18
- package/bin/register-task-commands.test.js +0 -16
- package/bin/register-vault-operations-commands.js +1 -29
- package/dist/{chunk-QVMXF7FY.js → chunk-3D6BCTP6.js} +39 -1
- package/dist/{chunk-R2MIW5G7.js → chunk-3DHXQHYG.js} +1 -1
- package/dist/{chunk-Q2J5YTUF.js → chunk-3NSBOUT3.js} +73 -36
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/{chunk-AZYOKJYC.js → chunk-62YTUT6J.js} +2 -2
- package/dist/chunk-6U6MK36V.js +205 -0
- package/dist/{chunk-4QYGFWRM.js → chunk-7R7O6STJ.js} +4 -4
- package/dist/{chunk-VXEOHTSL.js → chunk-C7OK5WKP.js} +4 -4
- package/dist/chunk-CMB7UL7C.js +327 -0
- package/dist/chunk-DEFFDRVP.js +938 -0
- package/dist/{chunk-K3CDT7IH.js → chunk-E7MFQB6D.js} +61 -20
- package/dist/{chunk-ME37YNW3.js → chunk-F2JEUD4J.js} +6 -4
- package/dist/chunk-GAJV4IGR.js +82 -0
- package/dist/chunk-GQSLDZTS.js +560 -0
- package/dist/{chunk-4OXMU5S2.js → chunk-GUKMRGM7.js} +1 -1
- package/dist/{chunk-YOSEUUNB.js → chunk-H34S76MB.js} +6 -6
- package/dist/{chunk-4TE4JMLA.js → chunk-JY6FYXIT.js} +10 -5
- package/dist/chunk-K234IDRJ.js +1073 -0
- package/dist/{chunk-IEVLHNLU.js → chunk-LNJA2UGL.js} +86 -9
- package/dist/{chunk-MFAWT5O5.js → chunk-LYHGEHXG.js} +1 -0
- package/dist/chunk-MFM6K7PU.js +374 -0
- package/dist/{chunk-QWQ3TIKS.js → chunk-N2AXRYLC.js} +1 -1
- package/dist/chunk-PAH27GSN.js +108 -0
- package/dist/{chunk-OIWVQYQF.js → chunk-QBLMXKF2.js} +1 -1
- package/dist/{chunk-FHFUXL6G.js → chunk-QK3UCXWL.js} +2 -2
- package/dist/{chunk-2YDBJS7M.js → chunk-SJSFRIYS.js} +1 -1
- package/dist/{chunk-GSD4ALSI.js → chunk-U55BGUAU.js} +2 -2
- package/dist/{chunk-PBEE567J.js → chunk-VGLOTGAS.js} +1 -1
- package/dist/{chunk-F55HGNU4.js → chunk-WAZ3NLWL.js} +47 -0
- package/dist/{chunk-KL4NAOMO.js → chunk-WGRQ6HDV.js} +1 -1
- package/dist/{chunk-UEOUADMO.js → chunk-YKTA5JOJ.js} +13 -10
- package/dist/{chunk-XAVB4GB4.js → chunk-ZVVFWOLW.js} +4 -4
- package/dist/cli/index.cjs +10033 -0
- package/dist/cli/index.d.cts +5 -0
- package/dist/cli/index.js +20 -18
- package/dist/commands/archive.cjs +287 -0
- package/dist/commands/archive.d.cts +11 -0
- package/dist/commands/archive.js +1 -0
- package/dist/commands/backlog.cjs +721 -0
- package/dist/commands/backlog.d.cts +53 -0
- package/dist/commands/backlog.js +3 -2
- package/dist/commands/blocked.cjs +204 -0
- package/dist/commands/blocked.d.cts +26 -0
- package/dist/commands/blocked.js +3 -2
- package/dist/commands/checkpoint.cjs +244 -0
- package/dist/commands/checkpoint.d.cts +41 -0
- package/dist/commands/checkpoint.js +2 -1
- package/dist/commands/compat.cjs +369 -0
- package/dist/commands/compat.d.cts +28 -0
- package/dist/commands/compat.js +2 -1
- package/dist/commands/context.cjs +2989 -0
- package/dist/commands/context.d.cts +2 -0
- package/dist/commands/context.js +5 -4
- package/dist/commands/doctor.cjs +3062 -0
- package/dist/commands/doctor.d.cts +21 -0
- package/dist/commands/doctor.d.ts +6 -1
- package/dist/commands/doctor.js +13 -11
- package/dist/commands/embed.cjs +232 -0
- package/dist/commands/embed.d.cts +17 -0
- package/dist/commands/embed.js +5 -2
- package/dist/commands/entities.cjs +141 -0
- package/dist/commands/entities.d.cts +7 -0
- package/dist/commands/entities.js +1 -0
- package/dist/commands/graph.cjs +501 -0
- package/dist/commands/graph.d.cts +21 -0
- package/dist/commands/graph.js +1 -0
- package/dist/commands/inject.cjs +1636 -0
- package/dist/commands/inject.d.cts +2 -0
- package/dist/commands/inject.d.ts +1 -1
- package/dist/commands/inject.js +4 -2
- package/dist/commands/kanban.cjs +884 -0
- package/dist/commands/kanban.d.cts +63 -0
- package/dist/commands/kanban.js +4 -3
- package/dist/commands/link.cjs +965 -0
- package/dist/commands/link.d.cts +11 -0
- package/dist/commands/link.js +1 -0
- package/dist/commands/migrate-observations.cjs +362 -0
- package/dist/commands/migrate-observations.d.cts +19 -0
- package/dist/commands/migrate-observations.js +3 -2
- package/dist/commands/observe.cjs +4099 -0
- package/dist/commands/observe.d.cts +23 -0
- package/dist/commands/observe.d.ts +1 -0
- package/dist/commands/observe.js +11 -9
- package/dist/commands/project.cjs +1341 -0
- package/dist/commands/project.d.cts +85 -0
- package/dist/commands/project.js +5 -4
- package/dist/commands/rebuild.cjs +3136 -0
- package/dist/commands/rebuild.d.cts +11 -0
- package/dist/commands/rebuild.js +10 -8
- package/dist/commands/recover.cjs +361 -0
- package/dist/commands/recover.d.cts +38 -0
- package/dist/commands/recover.js +3 -2
- package/dist/commands/reflect.cjs +1008 -0
- package/dist/commands/reflect.d.cts +11 -0
- package/dist/commands/reflect.js +6 -4
- package/dist/commands/repair-session.cjs +457 -0
- package/dist/commands/repair-session.d.cts +38 -0
- package/dist/commands/repair-session.js +1 -0
- package/dist/commands/replay.cjs +4103 -0
- package/dist/commands/replay.d.cts +16 -0
- package/dist/commands/replay.js +12 -10
- package/dist/commands/session-recap.cjs +353 -0
- package/dist/commands/session-recap.d.cts +27 -0
- package/dist/commands/session-recap.js +1 -0
- package/dist/commands/setup.cjs +1345 -0
- package/dist/commands/setup.d.cts +100 -0
- package/dist/commands/setup.d.ts +90 -2
- package/dist/commands/setup.js +21 -2
- package/dist/commands/shell-init.cjs +75 -0
- package/dist/commands/shell-init.d.cts +7 -0
- package/dist/commands/shell-init.js +2 -0
- package/dist/commands/sleep.cjs +6028 -0
- package/dist/commands/sleep.d.cts +36 -0
- package/dist/commands/sleep.d.ts +1 -1
- package/dist/commands/sleep.js +17 -15
- package/dist/commands/status.cjs +2736 -0
- package/dist/commands/status.d.cts +52 -0
- package/dist/commands/status.js +12 -10
- package/dist/commands/tailscale.cjs +1532 -0
- package/dist/commands/tailscale.d.cts +52 -0
- package/dist/commands/tailscale.js +1 -0
- package/dist/commands/task.cjs +1236 -0
- package/dist/commands/task.d.cts +97 -0
- package/dist/commands/task.js +4 -3
- package/dist/commands/template.cjs +457 -0
- package/dist/commands/template.d.cts +36 -0
- package/dist/commands/template.js +2 -1
- package/dist/commands/wake.cjs +2626 -0
- package/dist/commands/wake.d.cts +22 -0
- package/dist/commands/wake.d.ts +1 -1
- package/dist/commands/wake.js +12 -11
- package/dist/context-BUGaWpyL.d.cts +46 -0
- package/dist/index.cjs +14526 -0
- package/dist/index.d.cts +858 -0
- package/dist/index.d.ts +192 -7
- package/dist/index.js +101 -75
- package/dist/{inject-x65KXWPk.d.ts → inject-Bzi5E-By.d.cts} +1 -1
- package/dist/inject-Bzi5E-By.d.ts +137 -0
- package/dist/lib/auto-linker.cjs +176 -0
- package/dist/lib/auto-linker.d.cts +26 -0
- package/dist/lib/auto-linker.js +1 -0
- package/dist/lib/canvas-layout.cjs +136 -0
- package/dist/lib/canvas-layout.d.cts +31 -0
- package/dist/lib/canvas-layout.d.ts +16 -100
- package/dist/lib/canvas-layout.js +78 -20
- package/dist/lib/config.cjs +78 -0
- package/dist/lib/config.d.cts +11 -0
- package/dist/lib/config.js +1 -0
- package/dist/lib/entity-index.cjs +84 -0
- package/dist/lib/entity-index.d.cts +26 -0
- package/dist/lib/entity-index.js +1 -0
- package/dist/lib/project-utils.cjs +864 -0
- package/dist/lib/project-utils.d.cts +97 -0
- package/dist/lib/project-utils.js +4 -3
- package/dist/lib/session-repair.cjs +239 -0
- package/dist/lib/session-repair.d.cts +110 -0
- package/dist/lib/session-repair.js +1 -0
- package/dist/lib/session-utils.cjs +209 -0
- package/dist/lib/session-utils.d.cts +63 -0
- package/dist/lib/session-utils.js +1 -0
- package/dist/lib/tailscale.cjs +1183 -0
- package/dist/lib/tailscale.d.cts +225 -0
- package/dist/lib/tailscale.js +1 -0
- package/dist/lib/task-utils.cjs +1137 -0
- package/dist/lib/task-utils.d.cts +208 -0
- package/dist/lib/task-utils.js +3 -2
- package/dist/lib/template-engine.cjs +47 -0
- package/dist/lib/template-engine.d.cts +11 -0
- package/dist/lib/template-engine.js +1 -0
- package/dist/lib/webdav.cjs +568 -0
- package/dist/lib/webdav.d.cts +109 -0
- package/dist/lib/webdav.js +1 -0
- package/dist/plugin/index.cjs +1907 -0
- package/dist/plugin/index.d.cts +36 -0
- package/dist/plugin/index.d.ts +36 -0
- package/dist/plugin/index.js +572 -0
- package/dist/plugin/inject.cjs +356 -0
- package/dist/plugin/inject.d.cts +54 -0
- package/dist/plugin/inject.d.ts +54 -0
- package/dist/plugin/inject.js +17 -0
- package/dist/plugin/observe.cjs +631 -0
- package/dist/plugin/observe.d.cts +39 -0
- package/dist/plugin/observe.d.ts +39 -0
- package/dist/plugin/observe.js +18 -0
- package/dist/plugin/templates.cjs +593 -0
- package/dist/plugin/templates.d.cts +52 -0
- package/dist/plugin/templates.d.ts +52 -0
- package/dist/plugin/templates.js +25 -0
- package/dist/plugin/types.cjs +18 -0
- package/dist/plugin/types.d.cts +209 -0
- package/dist/plugin/types.d.ts +209 -0
- package/dist/plugin/types.js +0 -0
- package/dist/plugin/vault.cjs +927 -0
- package/dist/plugin/vault.d.cts +68 -0
- package/dist/plugin/vault.d.ts +68 -0
- package/dist/plugin/vault.js +22 -0
- package/dist/{types-C74wgGL1.d.ts → types-Y2_Um2Ls.d.cts} +44 -1
- package/dist/types-Y2_Um2Ls.d.ts +205 -0
- package/hooks/clawvault/handler.js +70 -7
- package/hooks/clawvault/handler.test.js +91 -0
- package/openclaw.plugin.json +56 -0
- package/package.json +17 -7
- package/templates/memory-event.md +67 -0
- package/templates/party.md +63 -0
- package/templates/primitive-registry.yaml +551 -0
- package/templates/run.md +68 -0
- package/templates/trigger.md +68 -0
- package/templates/workspace.md +50 -0
- package/dashboard/lib/graph-diff.js +0 -104
- package/dashboard/lib/graph-diff.test.js +0 -75
- package/dashboard/lib/vault-parser.js +0 -556
- package/dashboard/lib/vault-parser.test.js +0 -254
- package/dashboard/public/app.js +0 -796
- package/dashboard/public/index.html +0 -52
- package/dashboard/public/styles.css +0 -221
- package/dashboard/server.js +0 -374
- package/dist/chunk-HA5M6KJB.js +0 -33
- package/dist/chunk-MAKNAHAW.js +0 -375
- package/dist/chunk-MDIH26GC.js +0 -183
- package/dist/chunk-MGDEINGP.js +0 -99
- package/dist/chunk-RVYA52PY.js +0 -363
- package/dist/commands/canvas.d.ts +0 -15
- package/dist/commands/canvas.js +0 -199
- package/dist/commands/sync-bd.d.ts +0 -10
- package/dist/commands/sync-bd.js +0 -9
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/lib/webdav.ts
|
|
31
|
+
var webdav_exports = {};
|
|
32
|
+
__export(webdav_exports, {
|
|
33
|
+
WEBDAV_PREFIX: () => WEBDAV_PREFIX,
|
|
34
|
+
checkAuth: () => checkAuth,
|
|
35
|
+
createWebDAVHandler: () => createWebDAVHandler,
|
|
36
|
+
generatePropfindResponse: () => generatePropfindResponse,
|
|
37
|
+
handleCopy: () => handleCopy,
|
|
38
|
+
handleDelete: () => handleDelete,
|
|
39
|
+
handleGet: () => handleGet,
|
|
40
|
+
handleHead: () => handleHead,
|
|
41
|
+
handleMkcol: () => handleMkcol,
|
|
42
|
+
handleMove: () => handleMove,
|
|
43
|
+
handleOptions: () => handleOptions,
|
|
44
|
+
handlePropfind: () => handlePropfind,
|
|
45
|
+
handlePut: () => handlePut,
|
|
46
|
+
isPathSafe: () => isPathSafe,
|
|
47
|
+
resolveWebDAVPath: () => resolveWebDAVPath
|
|
48
|
+
});
|
|
49
|
+
module.exports = __toCommonJS(webdav_exports);
|
|
50
|
+
var fs = __toESM(require("fs"), 1);
|
|
51
|
+
var path = __toESM(require("path"), 1);
|
|
52
|
+
var WEBDAV_PREFIX = "/webdav";
|
|
53
|
+
var BLOCKED_PATHS = [
|
|
54
|
+
".clawvault",
|
|
55
|
+
".git",
|
|
56
|
+
".obsidian",
|
|
57
|
+
"node_modules"
|
|
58
|
+
];
|
|
59
|
+
var SUPPORTED_METHODS = ["GET", "PUT", "DELETE", "MKCOL", "PROPFIND", "OPTIONS", "HEAD", "MOVE", "COPY"];
|
|
60
|
+
function toRequestSegments(requestPath) {
|
|
61
|
+
return requestPath.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
62
|
+
}
|
|
63
|
+
function isWithinRoot(fullPath, rootPath) {
|
|
64
|
+
const resolvedRoot = path.resolve(rootPath);
|
|
65
|
+
const relative2 = path.relative(resolvedRoot, fullPath);
|
|
66
|
+
return !(relative2.startsWith("..") || path.isAbsolute(relative2));
|
|
67
|
+
}
|
|
68
|
+
function isPathSafe(requestPath, rootPath) {
|
|
69
|
+
const pathParts = toRequestSegments(requestPath);
|
|
70
|
+
if (pathParts.includes("..")) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
const normalizedRelativePath = path.normalize(pathParts.join(path.sep));
|
|
74
|
+
const fullPath = path.resolve(rootPath, normalizedRelativePath);
|
|
75
|
+
if (!isWithinRoot(fullPath, rootPath)) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
for (const part of pathParts) {
|
|
79
|
+
if (BLOCKED_PATHS.includes(part)) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
function resolveWebDAVPath(requestPath, rootPath) {
|
|
86
|
+
const pathParts = toRequestSegments(requestPath);
|
|
87
|
+
if (pathParts.includes("..")) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const normalizedRelativePath = path.normalize(pathParts.join(path.sep));
|
|
91
|
+
const fullPath = path.resolve(rootPath, normalizedRelativePath);
|
|
92
|
+
if (!isWithinRoot(fullPath, rootPath)) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
return fullPath;
|
|
96
|
+
}
|
|
97
|
+
function checkAuth(req, auth) {
|
|
98
|
+
if (!auth) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
const authHeader = req.headers.authorization;
|
|
102
|
+
if (!authHeader || !authHeader.startsWith("Basic ")) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
const base64Credentials = authHeader.slice(6);
|
|
106
|
+
const credentials = Buffer.from(base64Credentials, "base64").toString("utf-8");
|
|
107
|
+
const [username, password] = credentials.split(":");
|
|
108
|
+
return username === auth.username && password === auth.password;
|
|
109
|
+
}
|
|
110
|
+
function escapeXml(str) {
|
|
111
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
112
|
+
}
|
|
113
|
+
function formatWebDAVDate(date) {
|
|
114
|
+
return date.toUTCString();
|
|
115
|
+
}
|
|
116
|
+
function generatePropfindEntry(href, stats, isCollection) {
|
|
117
|
+
const resourceType = isCollection ? "<D:resourcetype><D:collection/></D:resourcetype>" : "<D:resourcetype/>";
|
|
118
|
+
const contentLength = stats && !isCollection ? `<D:getcontentlength>${stats.size}</D:getcontentlength>` : "";
|
|
119
|
+
const lastModified = stats ? `<D:getlastmodified>${formatWebDAVDate(stats.mtime)}</D:getlastmodified>` : "";
|
|
120
|
+
const etag = stats ? `<D:getetag>"${stats.mtime.getTime().toString(16)}-${stats.size.toString(16)}"</D:getetag>` : "";
|
|
121
|
+
const contentType = !isCollection ? "<D:getcontenttype>application/octet-stream</D:getcontenttype>" : "";
|
|
122
|
+
return ` <D:response>
|
|
123
|
+
<D:href>${escapeXml(href)}</D:href>
|
|
124
|
+
<D:propstat>
|
|
125
|
+
<D:prop>
|
|
126
|
+
${resourceType}
|
|
127
|
+
${contentLength}
|
|
128
|
+
${lastModified}
|
|
129
|
+
${etag}
|
|
130
|
+
${contentType}
|
|
131
|
+
</D:prop>
|
|
132
|
+
<D:status>HTTP/1.1 200 OK</D:status>
|
|
133
|
+
</D:propstat>
|
|
134
|
+
</D:response>`;
|
|
135
|
+
}
|
|
136
|
+
function generatePropfindResponse(entries) {
|
|
137
|
+
const responseEntries = entries.map(
|
|
138
|
+
(e) => generatePropfindEntry(e.href, e.stats, e.isCollection)
|
|
139
|
+
).join("\n");
|
|
140
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
141
|
+
<D:multistatus xmlns:D="DAV:">
|
|
142
|
+
${responseEntries}
|
|
143
|
+
</D:multistatus>`;
|
|
144
|
+
}
|
|
145
|
+
function handleOptions(res, prefix) {
|
|
146
|
+
res.writeHead(200, {
|
|
147
|
+
"Allow": SUPPORTED_METHODS.join(", "),
|
|
148
|
+
"DAV": "1, 2",
|
|
149
|
+
"Content-Length": "0",
|
|
150
|
+
"Access-Control-Allow-Origin": "*",
|
|
151
|
+
"Access-Control-Allow-Methods": SUPPORTED_METHODS.join(", "),
|
|
152
|
+
"Access-Control-Allow-Headers": "Content-Type, Depth, Destination, Overwrite, Authorization",
|
|
153
|
+
"MS-Author-Via": "DAV"
|
|
154
|
+
});
|
|
155
|
+
res.end();
|
|
156
|
+
}
|
|
157
|
+
function handleHead(res, filePath) {
|
|
158
|
+
try {
|
|
159
|
+
const stats = fs.statSync(filePath);
|
|
160
|
+
if (stats.isDirectory()) {
|
|
161
|
+
res.writeHead(200, {
|
|
162
|
+
"Content-Type": "httpd/unix-directory",
|
|
163
|
+
"Last-Modified": formatWebDAVDate(stats.mtime),
|
|
164
|
+
"ETag": `"${stats.mtime.getTime().toString(16)}"`,
|
|
165
|
+
"Access-Control-Allow-Origin": "*"
|
|
166
|
+
});
|
|
167
|
+
} else {
|
|
168
|
+
res.writeHead(200, {
|
|
169
|
+
"Content-Type": "application/octet-stream",
|
|
170
|
+
"Content-Length": stats.size.toString(),
|
|
171
|
+
"Last-Modified": formatWebDAVDate(stats.mtime),
|
|
172
|
+
"ETag": `"${stats.mtime.getTime().toString(16)}-${stats.size.toString(16)}"`,
|
|
173
|
+
"Access-Control-Allow-Origin": "*"
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
res.end();
|
|
177
|
+
} catch (err) {
|
|
178
|
+
res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
179
|
+
res.end("Not Found");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function handleGet(res, filePath) {
|
|
183
|
+
try {
|
|
184
|
+
const stats = fs.statSync(filePath);
|
|
185
|
+
if (stats.isDirectory()) {
|
|
186
|
+
const entries = fs.readdirSync(filePath);
|
|
187
|
+
const listing = entries.join("\n");
|
|
188
|
+
res.writeHead(200, {
|
|
189
|
+
"Content-Type": "text/plain",
|
|
190
|
+
"Content-Length": Buffer.byteLength(listing).toString(),
|
|
191
|
+
"Access-Control-Allow-Origin": "*"
|
|
192
|
+
});
|
|
193
|
+
res.end(listing);
|
|
194
|
+
} else {
|
|
195
|
+
const content = fs.readFileSync(filePath);
|
|
196
|
+
res.writeHead(200, {
|
|
197
|
+
"Content-Type": "application/octet-stream",
|
|
198
|
+
"Content-Length": content.length.toString(),
|
|
199
|
+
"Last-Modified": formatWebDAVDate(stats.mtime),
|
|
200
|
+
"ETag": `"${stats.mtime.getTime().toString(16)}-${stats.size.toString(16)}"`,
|
|
201
|
+
"Access-Control-Allow-Origin": "*"
|
|
202
|
+
});
|
|
203
|
+
res.end(content);
|
|
204
|
+
}
|
|
205
|
+
} catch (err) {
|
|
206
|
+
res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
207
|
+
res.end("Not Found");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function handlePut(res, filePath, body) {
|
|
211
|
+
try {
|
|
212
|
+
const exists = fs.existsSync(filePath);
|
|
213
|
+
const dir = path.dirname(filePath);
|
|
214
|
+
if (!fs.existsSync(dir)) {
|
|
215
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
216
|
+
}
|
|
217
|
+
fs.writeFileSync(filePath, body);
|
|
218
|
+
const status = exists ? 204 : 201;
|
|
219
|
+
res.writeHead(status, {
|
|
220
|
+
"Content-Length": "0",
|
|
221
|
+
"Access-Control-Allow-Origin": "*"
|
|
222
|
+
});
|
|
223
|
+
res.end();
|
|
224
|
+
} catch (err) {
|
|
225
|
+
res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
226
|
+
res.end(`Error: ${err}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function handleDelete(res, filePath) {
|
|
230
|
+
try {
|
|
231
|
+
if (!fs.existsSync(filePath)) {
|
|
232
|
+
res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
233
|
+
res.end("Not Found");
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const stats = fs.statSync(filePath);
|
|
237
|
+
if (stats.isDirectory()) {
|
|
238
|
+
fs.rmSync(filePath, { recursive: true });
|
|
239
|
+
} else {
|
|
240
|
+
fs.unlinkSync(filePath);
|
|
241
|
+
}
|
|
242
|
+
res.writeHead(204, {
|
|
243
|
+
"Content-Length": "0",
|
|
244
|
+
"Access-Control-Allow-Origin": "*"
|
|
245
|
+
});
|
|
246
|
+
res.end();
|
|
247
|
+
} catch (err) {
|
|
248
|
+
res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
249
|
+
res.end(`Error: ${err}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function handleMkcol(res, filePath) {
|
|
253
|
+
try {
|
|
254
|
+
if (fs.existsSync(filePath)) {
|
|
255
|
+
res.writeHead(405, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
256
|
+
res.end("Resource already exists");
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const parent = path.dirname(filePath);
|
|
260
|
+
if (!fs.existsSync(parent)) {
|
|
261
|
+
res.writeHead(409, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
262
|
+
res.end("Parent directory does not exist");
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
fs.mkdirSync(filePath);
|
|
266
|
+
res.writeHead(201, {
|
|
267
|
+
"Content-Length": "0",
|
|
268
|
+
"Access-Control-Allow-Origin": "*"
|
|
269
|
+
});
|
|
270
|
+
res.end();
|
|
271
|
+
} catch (err) {
|
|
272
|
+
res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
273
|
+
res.end(`Error: ${err}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function handlePropfind(res, filePath, webdavPath, prefix, depth) {
|
|
277
|
+
try {
|
|
278
|
+
if (!fs.existsSync(filePath)) {
|
|
279
|
+
res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
280
|
+
res.end("Not Found");
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const stats = fs.statSync(filePath);
|
|
284
|
+
const entries = [];
|
|
285
|
+
const normalizedWebdavPath = webdavPath.startsWith("/") ? webdavPath : "/" + webdavPath;
|
|
286
|
+
const href = prefix + normalizedWebdavPath;
|
|
287
|
+
entries.push({
|
|
288
|
+
href: href.endsWith("/") || stats.isDirectory() ? href : href,
|
|
289
|
+
stats,
|
|
290
|
+
isCollection: stats.isDirectory()
|
|
291
|
+
});
|
|
292
|
+
if (stats.isDirectory() && depth !== "0") {
|
|
293
|
+
try {
|
|
294
|
+
const children = fs.readdirSync(filePath);
|
|
295
|
+
for (const child of children) {
|
|
296
|
+
if (BLOCKED_PATHS.includes(child)) {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
const childPath = path.join(filePath, child);
|
|
300
|
+
const childWebdavPath = normalizedWebdavPath.endsWith("/") ? normalizedWebdavPath + child : normalizedWebdavPath + "/" + child;
|
|
301
|
+
try {
|
|
302
|
+
const childStats = fs.statSync(childPath);
|
|
303
|
+
entries.push({
|
|
304
|
+
href: prefix + childWebdavPath,
|
|
305
|
+
stats: childStats,
|
|
306
|
+
isCollection: childStats.isDirectory()
|
|
307
|
+
});
|
|
308
|
+
} catch {
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
} catch {
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
const xml = generatePropfindResponse(entries);
|
|
315
|
+
res.writeHead(207, {
|
|
316
|
+
"Content-Type": "application/xml; charset=utf-8",
|
|
317
|
+
"Content-Length": Buffer.byteLength(xml).toString(),
|
|
318
|
+
"Access-Control-Allow-Origin": "*"
|
|
319
|
+
});
|
|
320
|
+
res.end(xml);
|
|
321
|
+
} catch (err) {
|
|
322
|
+
res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
323
|
+
res.end(`Error: ${err}`);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
function handleMove(res, sourcePath, destinationPath, overwrite) {
|
|
327
|
+
try {
|
|
328
|
+
if (!fs.existsSync(sourcePath)) {
|
|
329
|
+
res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
330
|
+
res.end("Source not found");
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (!destinationPath) {
|
|
334
|
+
res.writeHead(400, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
335
|
+
res.end("Destination header required");
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const destExists = fs.existsSync(destinationPath);
|
|
339
|
+
if (destExists && !overwrite) {
|
|
340
|
+
res.writeHead(412, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
341
|
+
res.end("Destination exists and Overwrite is F");
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
const destDir = path.dirname(destinationPath);
|
|
345
|
+
if (!fs.existsSync(destDir)) {
|
|
346
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
347
|
+
}
|
|
348
|
+
if (destExists) {
|
|
349
|
+
const destStats = fs.statSync(destinationPath);
|
|
350
|
+
if (destStats.isDirectory()) {
|
|
351
|
+
fs.rmSync(destinationPath, { recursive: true });
|
|
352
|
+
} else {
|
|
353
|
+
fs.unlinkSync(destinationPath);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
fs.renameSync(sourcePath, destinationPath);
|
|
357
|
+
const status = destExists ? 204 : 201;
|
|
358
|
+
res.writeHead(status, {
|
|
359
|
+
"Content-Length": "0",
|
|
360
|
+
"Access-Control-Allow-Origin": "*"
|
|
361
|
+
});
|
|
362
|
+
res.end();
|
|
363
|
+
} catch (err) {
|
|
364
|
+
res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
365
|
+
res.end(`Error: ${err}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
function handleCopy(res, sourcePath, destinationPath, overwrite) {
|
|
369
|
+
try {
|
|
370
|
+
if (!fs.existsSync(sourcePath)) {
|
|
371
|
+
res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
372
|
+
res.end("Source not found");
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
if (!destinationPath) {
|
|
376
|
+
res.writeHead(400, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
377
|
+
res.end("Destination header required");
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
const destExists = fs.existsSync(destinationPath);
|
|
381
|
+
if (destExists && !overwrite) {
|
|
382
|
+
res.writeHead(412, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
383
|
+
res.end("Destination exists and Overwrite is F");
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const destDir = path.dirname(destinationPath);
|
|
387
|
+
if (!fs.existsSync(destDir)) {
|
|
388
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
389
|
+
}
|
|
390
|
+
const sourceStats = fs.statSync(sourcePath);
|
|
391
|
+
if (sourceStats.isDirectory()) {
|
|
392
|
+
copyDirRecursive(sourcePath, destinationPath);
|
|
393
|
+
} else {
|
|
394
|
+
fs.copyFileSync(sourcePath, destinationPath);
|
|
395
|
+
}
|
|
396
|
+
const status = destExists ? 204 : 201;
|
|
397
|
+
res.writeHead(status, {
|
|
398
|
+
"Content-Length": "0",
|
|
399
|
+
"Access-Control-Allow-Origin": "*"
|
|
400
|
+
});
|
|
401
|
+
res.end();
|
|
402
|
+
} catch (err) {
|
|
403
|
+
res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
404
|
+
res.end(`Error: ${err}`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function copyDirRecursive(src, dest) {
|
|
408
|
+
if (!fs.existsSync(dest)) {
|
|
409
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
410
|
+
}
|
|
411
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
412
|
+
for (const entry of entries) {
|
|
413
|
+
const srcPath = path.join(src, entry.name);
|
|
414
|
+
const destPath = path.join(dest, entry.name);
|
|
415
|
+
if (entry.isDirectory()) {
|
|
416
|
+
copyDirRecursive(srcPath, destPath);
|
|
417
|
+
} else {
|
|
418
|
+
fs.copyFileSync(srcPath, destPath);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
function parseDestinationHeader(destinationHeader, prefix, rootPath) {
|
|
423
|
+
if (!destinationHeader) {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
try {
|
|
427
|
+
let destPath;
|
|
428
|
+
if (destinationHeader.startsWith("http://") || destinationHeader.startsWith("https://")) {
|
|
429
|
+
const url = new URL(destinationHeader);
|
|
430
|
+
destPath = decodeURIComponent(url.pathname);
|
|
431
|
+
} else {
|
|
432
|
+
destPath = decodeURIComponent(destinationHeader);
|
|
433
|
+
}
|
|
434
|
+
if (destPath.startsWith(prefix)) {
|
|
435
|
+
destPath = destPath.slice(prefix.length);
|
|
436
|
+
}
|
|
437
|
+
return resolveWebDAVPath(destPath, rootPath);
|
|
438
|
+
} catch {
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
function createWebDAVHandler(config) {
|
|
443
|
+
const { rootPath, prefix = WEBDAV_PREFIX, auth } = config;
|
|
444
|
+
return async (req, res) => {
|
|
445
|
+
const rawUrl = req.url || "/";
|
|
446
|
+
if (rawUrl.includes("..")) {
|
|
447
|
+
if (rawUrl.startsWith(prefix)) {
|
|
448
|
+
res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
449
|
+
res.end("Forbidden");
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
const url = new URL(rawUrl, `http://${req.headers.host || "localhost"}`);
|
|
454
|
+
const pathname = decodeURIComponent(url.pathname);
|
|
455
|
+
if (!pathname.startsWith(prefix)) {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
let webdavPath = pathname.slice(prefix.length);
|
|
459
|
+
if (!webdavPath.startsWith("/")) {
|
|
460
|
+
webdavPath = "/" + webdavPath;
|
|
461
|
+
}
|
|
462
|
+
if (req.method === "OPTIONS") {
|
|
463
|
+
handleOptions(res, prefix);
|
|
464
|
+
return true;
|
|
465
|
+
}
|
|
466
|
+
if (!checkAuth(req, auth)) {
|
|
467
|
+
res.writeHead(401, {
|
|
468
|
+
"WWW-Authenticate": 'Basic realm="ClawVault WebDAV"',
|
|
469
|
+
"Content-Type": "text/plain",
|
|
470
|
+
"Access-Control-Allow-Origin": "*"
|
|
471
|
+
});
|
|
472
|
+
res.end("Unauthorized");
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
475
|
+
if (!isPathSafe(webdavPath, rootPath)) {
|
|
476
|
+
res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
477
|
+
res.end("Forbidden");
|
|
478
|
+
return true;
|
|
479
|
+
}
|
|
480
|
+
const filePath = resolveWebDAVPath(webdavPath, rootPath);
|
|
481
|
+
if (!filePath) {
|
|
482
|
+
res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
483
|
+
res.end("Forbidden");
|
|
484
|
+
return true;
|
|
485
|
+
}
|
|
486
|
+
const depth = req.headers.depth || "infinity";
|
|
487
|
+
const overwrite = req.headers.overwrite?.toUpperCase() !== "F";
|
|
488
|
+
const destinationHeader = req.headers.destination;
|
|
489
|
+
switch (req.method) {
|
|
490
|
+
case "HEAD":
|
|
491
|
+
handleHead(res, filePath);
|
|
492
|
+
return true;
|
|
493
|
+
case "GET":
|
|
494
|
+
handleGet(res, filePath);
|
|
495
|
+
return true;
|
|
496
|
+
case "PUT": {
|
|
497
|
+
const chunks = [];
|
|
498
|
+
for await (const chunk of req) {
|
|
499
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
500
|
+
}
|
|
501
|
+
const body = Buffer.concat(chunks);
|
|
502
|
+
handlePut(res, filePath, body);
|
|
503
|
+
return true;
|
|
504
|
+
}
|
|
505
|
+
case "DELETE":
|
|
506
|
+
handleDelete(res, filePath);
|
|
507
|
+
return true;
|
|
508
|
+
case "MKCOL":
|
|
509
|
+
handleMkcol(res, filePath);
|
|
510
|
+
return true;
|
|
511
|
+
case "PROPFIND":
|
|
512
|
+
handlePropfind(res, filePath, webdavPath, prefix, depth);
|
|
513
|
+
return true;
|
|
514
|
+
case "MOVE": {
|
|
515
|
+
const destPath = parseDestinationHeader(destinationHeader, prefix, rootPath);
|
|
516
|
+
if (destPath && destinationHeader) {
|
|
517
|
+
const destWebdavPath = destinationHeader.includes(prefix) ? destinationHeader.slice(destinationHeader.indexOf(prefix) + prefix.length) : destinationHeader;
|
|
518
|
+
if (!isPathSafe(destWebdavPath, rootPath)) {
|
|
519
|
+
res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
520
|
+
res.end("Forbidden");
|
|
521
|
+
return true;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
handleMove(res, filePath, destPath, overwrite);
|
|
525
|
+
return true;
|
|
526
|
+
}
|
|
527
|
+
case "COPY": {
|
|
528
|
+
const destPath = parseDestinationHeader(destinationHeader, prefix, rootPath);
|
|
529
|
+
if (destPath && destinationHeader) {
|
|
530
|
+
const destWebdavPath = destinationHeader.includes(prefix) ? destinationHeader.slice(destinationHeader.indexOf(prefix) + prefix.length) : destinationHeader;
|
|
531
|
+
if (!isPathSafe(destWebdavPath, rootPath)) {
|
|
532
|
+
res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
|
|
533
|
+
res.end("Forbidden");
|
|
534
|
+
return true;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
handleCopy(res, filePath, destPath, overwrite);
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
default:
|
|
541
|
+
res.writeHead(405, {
|
|
542
|
+
"Allow": SUPPORTED_METHODS.join(", "),
|
|
543
|
+
"Content-Type": "text/plain",
|
|
544
|
+
"Access-Control-Allow-Origin": "*"
|
|
545
|
+
});
|
|
546
|
+
res.end("Method Not Allowed");
|
|
547
|
+
return true;
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
552
|
+
0 && (module.exports = {
|
|
553
|
+
WEBDAV_PREFIX,
|
|
554
|
+
checkAuth,
|
|
555
|
+
createWebDAVHandler,
|
|
556
|
+
generatePropfindResponse,
|
|
557
|
+
handleCopy,
|
|
558
|
+
handleDelete,
|
|
559
|
+
handleGet,
|
|
560
|
+
handleHead,
|
|
561
|
+
handleMkcol,
|
|
562
|
+
handleMove,
|
|
563
|
+
handleOptions,
|
|
564
|
+
handlePropfind,
|
|
565
|
+
handlePut,
|
|
566
|
+
isPathSafe,
|
|
567
|
+
resolveWebDAVPath
|
|
568
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import { IncomingMessage, ServerResponse } from 'http';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* WebDAV Handler for ClawVault
|
|
6
|
+
*
|
|
7
|
+
* Implements WebDAV protocol support for Obsidian mobile sync via Remotely Save plugin.
|
|
8
|
+
* Uses only Node built-in modules (http, fs, path) - zero external dependencies.
|
|
9
|
+
*
|
|
10
|
+
* Supported methods:
|
|
11
|
+
* - GET: Serve file contents
|
|
12
|
+
* - PUT: Write/create file (creates parent dirs if needed)
|
|
13
|
+
* - DELETE: Delete file or directory
|
|
14
|
+
* - MKCOL: Create directory
|
|
15
|
+
* - PROPFIND: List directory contents or file properties (XML response)
|
|
16
|
+
* - OPTIONS: Return allowed methods + DAV header
|
|
17
|
+
* - HEAD: File metadata without body
|
|
18
|
+
* - MOVE: Rename/move file (uses Destination header)
|
|
19
|
+
* - COPY: Copy file
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
interface WebDAVConfig {
|
|
23
|
+
/** Root path for WebDAV files (vault path) */
|
|
24
|
+
rootPath: string;
|
|
25
|
+
/** URL prefix for WebDAV routes (default: /webdav) */
|
|
26
|
+
prefix?: string;
|
|
27
|
+
/** Optional Basic Auth credentials */
|
|
28
|
+
auth?: {
|
|
29
|
+
username: string;
|
|
30
|
+
password: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
interface WebDAVRequest {
|
|
34
|
+
method: string;
|
|
35
|
+
path: string;
|
|
36
|
+
headers: Record<string, string | string[] | undefined>;
|
|
37
|
+
body?: string;
|
|
38
|
+
}
|
|
39
|
+
interface WebDAVResponse {
|
|
40
|
+
status: number;
|
|
41
|
+
headers: Record<string, string>;
|
|
42
|
+
body?: string;
|
|
43
|
+
}
|
|
44
|
+
declare const WEBDAV_PREFIX = "/webdav";
|
|
45
|
+
/**
|
|
46
|
+
* Check if a path is safe (no traversal attacks, not blocked)
|
|
47
|
+
*/
|
|
48
|
+
declare function isPathSafe(requestPath: string, rootPath: string): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Resolve a WebDAV path to filesystem path
|
|
51
|
+
*/
|
|
52
|
+
declare function resolveWebDAVPath(requestPath: string, rootPath: string): string | null;
|
|
53
|
+
/**
|
|
54
|
+
* Check Basic Auth credentials
|
|
55
|
+
*/
|
|
56
|
+
declare function checkAuth(req: IncomingMessage, auth?: {
|
|
57
|
+
username: string;
|
|
58
|
+
password: string;
|
|
59
|
+
}): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Generate full PROPFIND response XML
|
|
62
|
+
*/
|
|
63
|
+
declare function generatePropfindResponse(entries: Array<{
|
|
64
|
+
href: string;
|
|
65
|
+
stats: fs.Stats | null;
|
|
66
|
+
isCollection: boolean;
|
|
67
|
+
}>): string;
|
|
68
|
+
/**
|
|
69
|
+
* Handle OPTIONS request
|
|
70
|
+
*/
|
|
71
|
+
declare function handleOptions(res: ServerResponse, prefix: string): void;
|
|
72
|
+
/**
|
|
73
|
+
* Handle HEAD request
|
|
74
|
+
*/
|
|
75
|
+
declare function handleHead(res: ServerResponse, filePath: string): void;
|
|
76
|
+
/**
|
|
77
|
+
* Handle GET request
|
|
78
|
+
*/
|
|
79
|
+
declare function handleGet(res: ServerResponse, filePath: string): void;
|
|
80
|
+
/**
|
|
81
|
+
* Handle PUT request
|
|
82
|
+
*/
|
|
83
|
+
declare function handlePut(res: ServerResponse, filePath: string, body: Buffer): void;
|
|
84
|
+
/**
|
|
85
|
+
* Handle DELETE request
|
|
86
|
+
*/
|
|
87
|
+
declare function handleDelete(res: ServerResponse, filePath: string): void;
|
|
88
|
+
/**
|
|
89
|
+
* Handle MKCOL request (create directory)
|
|
90
|
+
*/
|
|
91
|
+
declare function handleMkcol(res: ServerResponse, filePath: string): void;
|
|
92
|
+
/**
|
|
93
|
+
* Handle PROPFIND request
|
|
94
|
+
*/
|
|
95
|
+
declare function handlePropfind(res: ServerResponse, filePath: string, webdavPath: string, prefix: string, depth: string): void;
|
|
96
|
+
/**
|
|
97
|
+
* Handle MOVE request
|
|
98
|
+
*/
|
|
99
|
+
declare function handleMove(res: ServerResponse, sourcePath: string, destinationPath: string | null, overwrite: boolean): void;
|
|
100
|
+
/**
|
|
101
|
+
* Handle COPY request
|
|
102
|
+
*/
|
|
103
|
+
declare function handleCopy(res: ServerResponse, sourcePath: string, destinationPath: string | null, overwrite: boolean): void;
|
|
104
|
+
/**
|
|
105
|
+
* Create WebDAV request handler
|
|
106
|
+
*/
|
|
107
|
+
declare function createWebDAVHandler(config: WebDAVConfig): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
|
|
108
|
+
|
|
109
|
+
export { WEBDAV_PREFIX, type WebDAVConfig, type WebDAVRequest, type WebDAVResponse, checkAuth, createWebDAVHandler, generatePropfindResponse, handleCopy, handleDelete, handleGet, handleHead, handleMkcol, handleMove, handleOptions, handlePropfind, handlePut, isPathSafe, resolveWebDAVPath };
|