Fix XML parsing for WebDav
This was a regression caused by the `@libs/xml` upgrade in v2.6.0
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
website:
|
||||
image: ghcr.io/bewcloud/bewcloud:v2.7.0
|
||||
image: ghcr.io/bewcloud/bewcloud:v2.7.1
|
||||
restart: always
|
||||
ports:
|
||||
- 127.0.0.1:8000:8000
|
||||
|
||||
@@ -12,7 +12,7 @@ export function addDavPrefixToKeys(object: Record<string, any>, prefix = 'D:'):
|
||||
|
||||
if (typeof object === 'object' && object !== null) {
|
||||
return Object.entries(object).reduce((reducedObject, [key, value]) => {
|
||||
const prefixedKey = key === 'xml' || key.startsWith('#') || key.startsWith('@') ? key : `${prefix}${key}`;
|
||||
const prefixedKey = key.startsWith('#') || key.startsWith('@') ? key : `${prefix}${key}`;
|
||||
reducedObject[prefixedKey] = addDavPrefixToKeys(value);
|
||||
return reducedObject;
|
||||
}, {} as Record<string, any>);
|
||||
@@ -105,10 +105,8 @@ export async function buildPropFindResponse(
|
||||
const filePaths = await getFilePaths(join(rootPath, queryPath), depth);
|
||||
|
||||
const response: Record<string, any> = {
|
||||
xml: {
|
||||
'@version': '1.0',
|
||||
'@encoding': 'UTF-8',
|
||||
},
|
||||
multistatus: {
|
||||
'@xmlns:D': 'DAV:',
|
||||
response: [],
|
||||
|
||||
217
lib/utils/webdav_test.ts
Normal file
217
lib/utils/webdav_test.ts
Normal file
@@ -0,0 +1,217 @@
|
||||
import { assertEquals } from '@std/assert';
|
||||
import { parse, stringify } from '@libs/xml';
|
||||
|
||||
import { addDavPrefixToKeys, getProperDestinationPath, getPropertyNames } from './webdav.ts';
|
||||
|
||||
Deno.test('that getProperDestinationPath works', () => {
|
||||
const tests: { input: string; expected?: string }[] = [
|
||||
{
|
||||
input: `http://127.0.0.1/dav/12345-abcde-67890`,
|
||||
expected: 'dav/12345-abcde-67890',
|
||||
},
|
||||
{
|
||||
input: `http://127.0.0.1/dav/spaced-%20uid`,
|
||||
expected: 'dav/spaced- uid',
|
||||
},
|
||||
{
|
||||
input: `http://127.0.0.1/dav/something-deeper/spaced-%C3%A7uid`,
|
||||
expected: 'dav/something-deeper/spaced-çuid',
|
||||
},
|
||||
];
|
||||
|
||||
for (const test of tests) {
|
||||
const output = getProperDestinationPath(test.input);
|
||||
if (test.expected) {
|
||||
assertEquals(output, test.expected);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test('that addDavPrefixToKeys works', () => {
|
||||
const tests: {
|
||||
input: { object: Record<string, any> | Record<string, any>[]; prefix?: string };
|
||||
expected: Record<string, any>;
|
||||
}[] = [
|
||||
{
|
||||
input: {
|
||||
object: {
|
||||
displayname: 'test',
|
||||
},
|
||||
},
|
||||
expected: {
|
||||
'D:displayname': 'test',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: {
|
||||
object: [
|
||||
{ displayname: 'test' },
|
||||
{ color: 'black' },
|
||||
],
|
||||
},
|
||||
expected: [
|
||||
{ 'D:displayname': 'test' },
|
||||
{ 'D:color': 'black' },
|
||||
],
|
||||
},
|
||||
{
|
||||
input: {
|
||||
object: { '@version': '1.0', '@encoding': 'UTF-8', displayname: 'test', color: 'black' },
|
||||
},
|
||||
expected: {
|
||||
'@version': '1.0',
|
||||
'@encoding': 'UTF-8',
|
||||
'D:displayname': 'test',
|
||||
'D:color': 'black',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: {
|
||||
object: { displayname: 'test', color: 'black' },
|
||||
prefix: 'S:',
|
||||
},
|
||||
expected: {
|
||||
'S:displayname': 'test',
|
||||
'S:color': 'black',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (const test of tests) {
|
||||
const output = addDavPrefixToKeys(test.input.object, test.input.prefix);
|
||||
if (test.expected) {
|
||||
assertEquals(output, test.expected);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test('that getPropertyNames works', () => {
|
||||
const tests: {
|
||||
input: Record<string, any>;
|
||||
expected: string[];
|
||||
}[] = [
|
||||
{
|
||||
input: {
|
||||
'D:propfind': {
|
||||
'D:prop': {
|
||||
'D:displayname': 'test',
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: ['displayname'],
|
||||
},
|
||||
{
|
||||
input: {
|
||||
'D:propfind': {
|
||||
'D:prop': {
|
||||
'D:displayname': 'test',
|
||||
'D:color': 'black',
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: ['displayname', 'color'],
|
||||
},
|
||||
{
|
||||
input: {},
|
||||
expected: ['allprop'],
|
||||
},
|
||||
];
|
||||
|
||||
for (const test of tests) {
|
||||
const output = getPropertyNames(test.input);
|
||||
if (test.expected) {
|
||||
assertEquals(output, test.expected);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test('that @libs/xml.parse works', () => {
|
||||
const tests: { input: string; expected: Record<string, any> }[] = [
|
||||
{
|
||||
input: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<propfind xmlns="DAV:">
|
||||
<prop>
|
||||
<displayname>test</displayname>
|
||||
</prop>
|
||||
</propfind>`,
|
||||
expected: {
|
||||
'@version': '1.0',
|
||||
'@encoding': 'UTF-8',
|
||||
propfind: {
|
||||
'@xmlns': 'DAV:',
|
||||
prop: {
|
||||
displayname: 'test',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<D:propfind xmlns:D="DAV:">
|
||||
<D:prop>
|
||||
<D:displayname>test</D:displayname>
|
||||
</D:prop>
|
||||
</D:propfind>`,
|
||||
expected: {
|
||||
'@version': '1.0',
|
||||
'@encoding': 'UTF-8',
|
||||
'D:propfind': {
|
||||
'@xmlns:D': 'DAV:',
|
||||
'D:prop': {
|
||||
'D:displayname': 'test',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (const test of tests) {
|
||||
const output = parse(test.input);
|
||||
assertEquals(output, test.expected);
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test('that @libs/xml.stringify works', () => {
|
||||
const tests: { input: Record<string, any>; expected: string }[] = [
|
||||
{
|
||||
input: {
|
||||
'@version': '1.0',
|
||||
'@encoding': 'UTF-8',
|
||||
'D:propfind': {
|
||||
'D:prop': {
|
||||
'D:displayname': 'test',
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<D:propfind>
|
||||
<D:prop>
|
||||
<D:displayname>test</D:displayname>
|
||||
</D:prop>
|
||||
</D:propfind>`,
|
||||
},
|
||||
{
|
||||
input: {
|
||||
'@version': '1.0',
|
||||
'@encoding': 'UTF-8',
|
||||
'D:propfind': {
|
||||
'@xmlns:D': 'DAV:',
|
||||
'D:prop': {
|
||||
'D:displayname': 'test',
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<D:propfind xmlns:D="DAV:">
|
||||
<D:prop>
|
||||
<D:displayname>test</D:displayname>
|
||||
</D:prop>
|
||||
</D:propfind>`,
|
||||
},
|
||||
];
|
||||
|
||||
for (const test of tests) {
|
||||
const output = stringify(test.input);
|
||||
assertEquals(output, test.expected);
|
||||
}
|
||||
});
|
||||
@@ -168,10 +168,8 @@ export const handler: Handler<Data, FreshContextState> = async (request, context
|
||||
await lock.acquire();
|
||||
|
||||
const responseXml: Record<string, any> = {
|
||||
xml: {
|
||||
'@version': '1.0',
|
||||
'@encoding': 'UTF-8',
|
||||
},
|
||||
prop: {
|
||||
'@xmlns:D': 'DAV:',
|
||||
lockdiscovery: {
|
||||
@@ -218,10 +216,17 @@ export const handler: Handler<Data, FreshContextState> = async (request, context
|
||||
const depthString = request.headers.get('depth');
|
||||
const depth = depthString ? parseInt(depthString, 10) : null;
|
||||
const xml = await request.clone().text();
|
||||
let properties: string[] = [];
|
||||
|
||||
const parsedXml = parse(xml);
|
||||
try {
|
||||
const parsedXml = parse(xml) as Record<string, any>;
|
||||
|
||||
const properties = getPropertyNames(parsedXml);
|
||||
properties = getPropertyNames(parsedXml);
|
||||
} catch (error) {
|
||||
console.error('Error parsing XML: ', error);
|
||||
|
||||
properties = ['allprop'];
|
||||
}
|
||||
|
||||
await ensureUserPathIsValidAndSecurelyAccessible(userId, filePath);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user