@sync-in/server 1.4.0 → 1.5.1
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/CHANGELOG.md +26 -0
- package/README.md +2 -1
- package/package.json +5 -5
- package/server/applications/comments/comments.controller.spec.js +103 -4
- package/server/applications/comments/comments.controller.spec.js.map +1 -1
- package/server/applications/comments/services/comments-manager.service.spec.js +409 -9
- package/server/applications/comments/services/comments-manager.service.spec.js.map +1 -1
- package/server/applications/files/adapters/files-indexer-mysql.service.spec.js +333 -0
- package/server/applications/files/adapters/files-indexer-mysql.service.spec.js.map +1 -0
- package/server/applications/files/constants/routes.js +6 -1
- package/server/applications/files/constants/routes.js.map +1 -1
- package/server/applications/files/files-only-office.controller.js +11 -0
- package/server/applications/files/files-only-office.controller.js.map +1 -1
- package/server/applications/files/files-only-office.controller.spec.js +97 -3
- package/server/applications/files/files-only-office.controller.spec.js.map +1 -1
- package/server/applications/files/files-tasks.controller.spec.js +91 -1
- package/server/applications/files/files-tasks.controller.spec.js.map +1 -1
- package/server/applications/files/files.controller.spec.js +268 -46
- package/server/applications/files/files.controller.spec.js.map +1 -1
- package/server/applications/files/guards/files-only-office.guard.spec.js +77 -1
- package/server/applications/files/guards/files-only-office.guard.spec.js.map +1 -1
- package/server/applications/files/services/files-only-office-manager.service.js +5 -0
- package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
- package/server/applications/links/links.controller.spec.js +91 -58
- package/server/applications/links/links.controller.spec.js.map +1 -1
- package/server/applications/links/services/links-manager.service.js +4 -6
- package/server/applications/links/services/links-manager.service.js.map +1 -1
- package/server/applications/links/services/links-manager.service.spec.js +378 -14
- package/server/applications/links/services/links-manager.service.spec.js.map +1 -1
- package/server/applications/links/services/links-queries.service.js +1 -1
- package/server/applications/links/services/links-queries.service.js.map +1 -1
- package/server/applications/notifications/notifications.controller.spec.js +56 -1
- package/server/applications/notifications/notifications.controller.spec.js.map +1 -1
- package/server/applications/notifications/services/notifications-manager.service.spec.js +461 -5
- package/server/applications/notifications/services/notifications-manager.service.spec.js.map +1 -1
- package/server/applications/shares/services/shares-manager.service.spec.js +590 -14
- package/server/applications/shares/services/shares-manager.service.spec.js.map +1 -1
- package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js +120 -0
- package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js.map +1 -0
- package/server/applications/sync/services/sync-clients-manager.service.spec.js +548 -8
- package/server/applications/sync/services/sync-clients-manager.service.spec.js.map +1 -1
- package/server/applications/sync/services/sync-manager.service.spec.js +837 -5
- package/server/applications/sync/services/sync-manager.service.spec.js.map +1 -1
- package/server/applications/sync/services/sync-paths-manager.service.spec.js +900 -7
- package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.js +22 -24
- package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.spec.js +763 -17
- package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/users-manager.service.js +1 -1
- package/server/applications/users/services/users-manager.service.js.map +1 -1
- package/server/applications/users/services/users-manager.service.spec.js +938 -49
- package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
- package/server/applications/webdav/decorators/if-header.decorator.js +4 -1
- package/server/applications/webdav/decorators/if-header.decorator.js.map +1 -1
- package/server/applications/webdav/filters/webdav.filter.spec.js +77 -0
- package/server/applications/webdav/filters/webdav.filter.spec.js.map +1 -0
- package/server/applications/webdav/guards/webdav-protocol.guard.js +3 -7
- package/server/applications/webdav/guards/webdav-protocol.guard.js.map +1 -1
- package/server/applications/webdav/guards/webdav-protocol.guard.spec.js +580 -0
- package/server/applications/webdav/guards/webdav-protocol.guard.spec.js.map +1 -0
- package/server/applications/webdav/services/webdav-methods.service.spec.js +1582 -3
- package/server/applications/webdav/services/webdav-methods.service.spec.js.map +1 -1
- package/server/applications/webdav/services/webdav-spaces.service.spec.js +390 -2
- package/server/applications/webdav/services/webdav-spaces.service.spec.js.map +1 -1
- package/server/applications/webdav/webdav.controller.js +2 -2
- package/server/applications/webdav/webdav.controller.js.map +1 -1
- package/server/authentication/guards/auth-basic.guard.js.map +1 -1
- package/server/authentication/guards/auth-digest.guard.js +1 -2
- package/server/authentication/guards/auth-digest.guard.js.map +1 -1
- package/server/authentication/guards/auth-local.guard.js.map +1 -1
- package/server/infrastructure/context/interceptors/context.interceptor.spec.js +135 -0
- package/server/infrastructure/context/interceptors/context.interceptor.spec.js.map +1 -0
- package/static/3rdpartylicenses.txt +26 -26
- package/static/assets/pdfjs/build/pdf.mjs +1177 -255
- package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
- package/static/assets/pdfjs/build/pdf.sandbox.mjs +25 -2
- package/static/assets/pdfjs/build/pdf.sandbox.mjs.map +1 -1
- package/static/assets/pdfjs/build/pdf.worker.mjs +140 -16
- package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
- package/static/assets/pdfjs/version +1 -1
- package/static/assets/pdfjs/web/debugger.css +31 -0
- package/static/assets/pdfjs/web/debugger.mjs +144 -2
- package/static/assets/pdfjs/web/images/comment-editButton.svg +6 -1
- package/static/assets/pdfjs/web/locale/ach/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/af/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/an/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ast/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/az/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/be/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/bg/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/bn/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/bo/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/br/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/brx/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/bs/viewer.ftl +22 -0
- package/static/assets/pdfjs/web/locale/ca/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/cak/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/ckb/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/cs/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/cy/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/da/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/de/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/el/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +25 -0
- package/static/assets/pdfjs/web/locale/eo/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -6
- package/static/assets/pdfjs/web/locale/et/viewer.ftl +0 -57
- package/static/assets/pdfjs/web/locale/fa/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/ff/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/fi/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/fr/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/ga-IE/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/gd/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/gl/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/gn/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/gu-IN/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/he/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hi-IN/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hu/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +0 -49
- package/static/assets/pdfjs/web/locale/hye/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/ia/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/is/viewer.ftl +0 -3
- package/static/assets/pdfjs/web/locale/it/viewer.ftl +31 -0
- package/static/assets/pdfjs/web/locale/ja/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/ka/viewer.ftl +48 -10
- package/static/assets/pdfjs/web/locale/kab/viewer.ftl +5 -0
- package/static/assets/pdfjs/web/locale/kk/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/km/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/kn/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/ko/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/lij/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/lo/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/lt/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/ltg/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/lv/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/meh/viewer.ftl +0 -75
- package/static/assets/pdfjs/web/locale/mk/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ml/viewer.ftl +0 -3
- package/static/assets/pdfjs/web/locale/mr/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ms/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/my/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +44 -6
- package/static/assets/pdfjs/web/locale/ne-NP/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/nl/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +45 -1
- package/static/assets/pdfjs/web/locale/oc/viewer.ftl +0 -31
- package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/pl/viewer.ftl +39 -1
- package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/ro/viewer.ftl +355 -1
- package/static/assets/pdfjs/web/locale/ru/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/sat/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/sc/viewer.ftl +0 -38
- package/static/assets/pdfjs/web/locale/scn/viewer.ftl +0 -92
- package/static/assets/pdfjs/web/locale/sco/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/si/viewer.ftl +0 -51
- package/static/assets/pdfjs/web/locale/sk/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/skr/viewer.ftl +0 -27
- package/static/assets/pdfjs/web/locale/sl/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/son/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/sr/viewer.ftl +0 -33
- package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/szl/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ta/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/te/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/tg/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/tl/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/tr/viewer.ftl +40 -2
- package/static/assets/pdfjs/web/locale/trs/viewer.ftl +0 -72
- package/static/assets/pdfjs/web/locale/ur/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/uz/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/vi/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/wo/viewer.ftl +0 -77
- package/static/assets/pdfjs/web/locale/xh/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/viewer.css +649 -120
- package/static/assets/pdfjs/web/viewer.html +19 -0
- package/static/assets/pdfjs/web/viewer.mjs +489 -38
- package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
- package/static/chunk-22EANI6R.js +1 -0
- package/static/{chunk-N2LYWNTC.js → chunk-2456KVFZ.js} +1 -1
- package/static/{chunk-YCINY2YI.js → chunk-2LVCLKCK.js} +1 -1
- package/static/{chunk-5YKWZT33.js → chunk-2V5S7DWD.js} +1 -1
- package/static/{chunk-3GC2BQZD.js → chunk-44YDXGNZ.js} +1 -1
- package/static/{chunk-W3QXNDI5.js → chunk-4LSJLWYV.js} +1 -1
- package/static/{chunk-T55FAU2O.js → chunk-4UT5VH7R.js} +1 -1
- package/static/{chunk-VMQMD36Z.js → chunk-5GOMMRRE.js} +1 -1
- package/static/{chunk-TXPODW5Q.js → chunk-5J4VRDKB.js} +1 -1
- package/static/{chunk-FQ4AFNGE.js → chunk-6PVKNZ7Q.js} +1 -1
- package/static/{chunk-XE5YHU5J.js → chunk-BIUNUYZ5.js} +1 -1
- package/static/{chunk-X43VWRFP.js → chunk-DFQKHCDR.js} +1 -1
- package/static/{chunk-TDQAEVZN.js → chunk-EE2TDTY4.js} +1 -1
- package/static/{chunk-MOVWEZ7J.js → chunk-ESNDJ5T6.js} +1 -1
- package/static/{chunk-TCFKH6K6.js → chunk-GDKKLLEU.js} +1 -1
- package/static/{chunk-VHYIXL7R.js → chunk-GSR2MCQG.js} +1 -1
- package/static/{chunk-LJIGRUEF.js → chunk-HR7KS5BR.js} +1 -1
- package/static/chunk-HW2H3ISM.js +559 -0
- package/static/{chunk-HZA7R43P.js → chunk-IMB3C547.js} +1 -1
- package/static/{chunk-B2Y2RNFP.js → chunk-J4ALHUDX.js} +1 -1
- package/static/{chunk-PF4K7MVG.js → chunk-KP6LSQTK.js} +1 -1
- package/static/{chunk-C23BPTJZ.js → chunk-LUZCOHFN.js} +1 -1
- package/static/{chunk-GBCYYDCI.js → chunk-MHSCCXVL.js} +1 -1
- package/static/{chunk-PY3BGNJN.js → chunk-OMRQYBXV.js} +1 -1
- package/static/chunk-P7CTJ5BG.js +27 -0
- package/static/{chunk-Y2CDUS4J.js → chunk-P7PX67IR.js} +4 -4
- package/static/{chunk-VMUOUCEI.js → chunk-PPO7DBVO.js} +1 -1
- package/static/{chunk-TTQ37MUV.js → chunk-RSS6GYNE.js} +1 -1
- package/static/{chunk-WWIC7UW3.js → chunk-SLGGINMR.js} +1 -1
- package/static/{chunk-KZQCFEPT.js → chunk-UHD5XD3G.js} +1 -1
- package/static/{chunk-TNW2CGK6.js → chunk-UPYYAJCJ.js} +1 -1
- package/static/{chunk-6F55D74O.js → chunk-VHYPQ3D4.js} +1 -1
- package/static/{chunk-DGVNNICG.js → chunk-YQSDS6BO.js} +1 -1
- package/static/{chunk-MTRNPGS4.js → chunk-ZC5NIT55.js} +1 -1
- package/static/index.html +1 -1
- package/static/main-FYD34UEC.js +7 -0
- package/static/chunk-RSNLYAN6.js +0 -560
- package/static/chunk-WHMS3PJ3.js +0 -24
- package/static/chunk-ZZ3LHYOY.js +0 -1
- package/static/main-7LDKYVXO.js +0 -10
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _common = require("@nestjs/common");
|
|
6
|
+
const _testing = require("@nestjs/testing");
|
|
7
|
+
const _functions = require("../../../common/functions");
|
|
8
|
+
const _shared = require("../../../common/shared");
|
|
9
|
+
const _applicationsconstants = require("../../applications.constants");
|
|
10
|
+
const _fileslockmanagerservice = require("../../files/services/files-lock-manager.service");
|
|
11
|
+
const _webdav = require("../constants/webdav");
|
|
12
|
+
const _webdav1 = require("../utils/webdav");
|
|
13
|
+
const _webdavprotocolguard = require("./webdav-protocol.guard");
|
|
14
|
+
const _ifheader = /*#__PURE__*/ _interop_require_wildcard(require("../utils/if-header"));
|
|
15
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
16
|
+
if (typeof WeakMap !== "function") return null;
|
|
17
|
+
var cacheBabelInterop = new WeakMap();
|
|
18
|
+
var cacheNodeInterop = new WeakMap();
|
|
19
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
20
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
21
|
+
})(nodeInterop);
|
|
22
|
+
}
|
|
23
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
24
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
25
|
+
return obj;
|
|
26
|
+
}
|
|
27
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
28
|
+
return {
|
|
29
|
+
default: obj
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
33
|
+
if (cache && cache.has(obj)) {
|
|
34
|
+
return cache.get(obj);
|
|
35
|
+
}
|
|
36
|
+
var newObj = {
|
|
37
|
+
__proto__: null
|
|
38
|
+
};
|
|
39
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
40
|
+
for(var key in obj){
|
|
41
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
42
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
43
|
+
if (desc && (desc.get || desc.set)) {
|
|
44
|
+
Object.defineProperty(newObj, key, desc);
|
|
45
|
+
} else {
|
|
46
|
+
newObj[key] = obj[key];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
newObj.default = obj;
|
|
51
|
+
if (cache) {
|
|
52
|
+
cache.set(obj, newObj);
|
|
53
|
+
}
|
|
54
|
+
return newObj;
|
|
55
|
+
}
|
|
56
|
+
// Keep these mocks to control path transforms in COPY/MOVE tests
|
|
57
|
+
jest.mock('../../../common/shared', ()=>({
|
|
58
|
+
decodeUrl: jest.fn((s)=>s)
|
|
59
|
+
}));
|
|
60
|
+
jest.mock('../../../common/functions', ()=>({
|
|
61
|
+
urlToPath: jest.fn((s)=>s)
|
|
62
|
+
}));
|
|
63
|
+
describe(_webdavprotocolguard.WebDAVProtocolGuard.name, ()=>{
|
|
64
|
+
let guard;
|
|
65
|
+
const makeUser = (hasPerm = true)=>({
|
|
66
|
+
havePermission: jest.fn(()=>hasPerm),
|
|
67
|
+
fullName: 'John Doe',
|
|
68
|
+
email: 'john@doe.tld'
|
|
69
|
+
});
|
|
70
|
+
const makeRes = ()=>({
|
|
71
|
+
headers: jest.fn()
|
|
72
|
+
});
|
|
73
|
+
const baseReq = (method, overrides = {})=>({
|
|
74
|
+
method,
|
|
75
|
+
headers: {},
|
|
76
|
+
// undefined body allows to hit the "allowed empty body" branch for PROPFIND/LOCK
|
|
77
|
+
body: undefined,
|
|
78
|
+
originalUrl: '/webdav/base/path',
|
|
79
|
+
protocol: 'http',
|
|
80
|
+
raw: {
|
|
81
|
+
httpVersion: '1.1'
|
|
82
|
+
},
|
|
83
|
+
user: makeUser(),
|
|
84
|
+
...overrides
|
|
85
|
+
});
|
|
86
|
+
const makeCtx = (req, res)=>({
|
|
87
|
+
switchToHttp: ()=>({
|
|
88
|
+
getRequest: ()=>req,
|
|
89
|
+
getResponse: ()=>res
|
|
90
|
+
})
|
|
91
|
+
});
|
|
92
|
+
const expectIfHeadersParsed = (req)=>{
|
|
93
|
+
expect(Array.isArray(req.dav.ifHeaders)).toBe(true);
|
|
94
|
+
expect(req.dav.ifHeaders.length).toBeGreaterThan(0);
|
|
95
|
+
};
|
|
96
|
+
beforeEach(async ()=>{
|
|
97
|
+
jest.clearAllMocks();
|
|
98
|
+
const module = await _testing.Test.createTestingModule({
|
|
99
|
+
providers: [
|
|
100
|
+
_webdavprotocolguard.WebDAVProtocolGuard
|
|
101
|
+
]
|
|
102
|
+
}).compile();
|
|
103
|
+
guard = module.get(_webdavprotocolguard.WebDAVProtocolGuard);
|
|
104
|
+
});
|
|
105
|
+
describe('Permissions', ()=>{
|
|
106
|
+
it('allows OPTIONS even without WEBDAV permission (responds headers + 200)', async ()=>{
|
|
107
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.OPTIONS, {
|
|
108
|
+
user: makeUser(false)
|
|
109
|
+
});
|
|
110
|
+
const res = makeRes();
|
|
111
|
+
const ctx = makeCtx(req, res);
|
|
112
|
+
await expect(guard.canActivate(ctx)).rejects.toThrow(_common.HttpException);
|
|
113
|
+
try {
|
|
114
|
+
await guard.canActivate(ctx);
|
|
115
|
+
} catch (e) {
|
|
116
|
+
const ex = e;
|
|
117
|
+
expect(res.headers).toHaveBeenCalledWith(_webdav.OPTIONS_HEADERS);
|
|
118
|
+
expect(ex.getStatus()).toBe(_common.HttpStatus.OK);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
it('forbids non-OPTIONS when the user lacks WEBDAV permission', async ()=>{
|
|
122
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.GET, {
|
|
123
|
+
user: makeUser(false)
|
|
124
|
+
});
|
|
125
|
+
const res = makeRes();
|
|
126
|
+
const ctx = makeCtx(req, res);
|
|
127
|
+
await expect(guard.canActivate(ctx)).rejects.toMatchObject({
|
|
128
|
+
status: _common.HttpStatus.FORBIDDEN
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
it('falls through for a method not handled by the switch', async ()=>{
|
|
132
|
+
const req = baseReq('VIEW', {});
|
|
133
|
+
const res = makeRes();
|
|
134
|
+
const ctx = makeCtx(req, res);
|
|
135
|
+
const spy = jest.spyOn(guard, 'setDAVContext');
|
|
136
|
+
const result = await guard.canActivate(ctx);
|
|
137
|
+
expect(result).toBe(true);
|
|
138
|
+
expect(spy).toHaveBeenCalled();
|
|
139
|
+
spy.mockRestore();
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
describe('PROPFIND', ()=>{
|
|
143
|
+
it('defaults depth=1 (members) when header is missing, and sets ALLPROP with empty body', async ()=>{
|
|
144
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.PROPFIND, {
|
|
145
|
+
headers: {},
|
|
146
|
+
body: undefined
|
|
147
|
+
});
|
|
148
|
+
const res = makeRes();
|
|
149
|
+
const ctx = makeCtx(req, res);
|
|
150
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
151
|
+
expect(req.dav.url).toBe(req.originalUrl);
|
|
152
|
+
expect(req.dav.depth).toBe(_webdav.DEPTH.MEMBERS);
|
|
153
|
+
expect(req.dav.body).toBe(_webdav1.PROPFIND_ALL_PROP);
|
|
154
|
+
expect(req.dav.propfindMode).toBe(_webdav.PROPSTAT.ALLPROP);
|
|
155
|
+
expect(req.dav.ifHeaders === undefined || req.dav.ifHeaders.length === 0).toBe(true);
|
|
156
|
+
});
|
|
157
|
+
it.each([
|
|
158
|
+
{
|
|
159
|
+
title: 'depth "infinity" normalized to 1 (members)',
|
|
160
|
+
depth: _webdav.DEPTH.INFINITY
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
title: 'invalid depth normalized to 1 (members)',
|
|
164
|
+
depth: 'bad'
|
|
165
|
+
}
|
|
166
|
+
])('depth normalization: $title', async ({ depth })=>{
|
|
167
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.PROPFIND, {
|
|
168
|
+
headers: {
|
|
169
|
+
[_webdav.HEADER.DEPTH]: depth
|
|
170
|
+
},
|
|
171
|
+
body: undefined
|
|
172
|
+
});
|
|
173
|
+
const res = makeRes();
|
|
174
|
+
const ctx = makeCtx(req, res);
|
|
175
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
176
|
+
expect(req.dav.depth).toBe(_webdav.DEPTH.MEMBERS);
|
|
177
|
+
});
|
|
178
|
+
it('valid XML body with propname and parses If header', async ()=>{
|
|
179
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.PROPFIND, {
|
|
180
|
+
headers: {
|
|
181
|
+
[_webdav.HEADER.DEPTH]: _webdav.DEPTH.RESOURCE,
|
|
182
|
+
[_webdav.HEADER.IF]: '(<urn:uuid:abc> ["W/\\"ETag\\""])'
|
|
183
|
+
},
|
|
184
|
+
body: '<propfind xmlns="DAV:"><propname/></propfind>'
|
|
185
|
+
});
|
|
186
|
+
const res = makeRes();
|
|
187
|
+
const ctx = makeCtx(req, res);
|
|
188
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
189
|
+
expect(req.dav.depth).toBe(_webdav.DEPTH.RESOURCE);
|
|
190
|
+
expect(req.dav.propfindMode).toBe(_webdav.PROPSTAT.PROPNAME);
|
|
191
|
+
expectIfHeadersParsed(req);
|
|
192
|
+
});
|
|
193
|
+
it('invalid propfind mode -> 400', async ()=>{
|
|
194
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.PROPFIND, {
|
|
195
|
+
headers: {},
|
|
196
|
+
body: '<propfind xmlns="DAV:"><unknown/></propfind>'
|
|
197
|
+
});
|
|
198
|
+
const res = makeRes();
|
|
199
|
+
const ctx = makeCtx(req, res);
|
|
200
|
+
await expect(guard.canActivate(ctx)).rejects.toMatchObject({
|
|
201
|
+
status: _common.HttpStatus.BAD_REQUEST
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
it('invalid XML (with code) -> 400', async ()=>{
|
|
205
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.PROPFIND, {
|
|
206
|
+
headers: {},
|
|
207
|
+
body: '<bad'
|
|
208
|
+
});
|
|
209
|
+
const res = makeRes();
|
|
210
|
+
const ctx = makeCtx(req, res);
|
|
211
|
+
await expect(guard.canActivate(ctx)).rejects.toMatchObject({
|
|
212
|
+
status: _common.HttpStatus.BAD_REQUEST
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
it('specific XML validation error handled -> 400', async ()=>{
|
|
216
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.PROPFIND, {
|
|
217
|
+
headers: {},
|
|
218
|
+
body: 'this is not XML at all'
|
|
219
|
+
});
|
|
220
|
+
const res = makeRes();
|
|
221
|
+
const ctx = makeCtx(req, res);
|
|
222
|
+
await expect(guard.canActivate(ctx)).rejects.toHaveProperty('status', _common.HttpStatus.BAD_REQUEST);
|
|
223
|
+
});
|
|
224
|
+
it('skips body when parseBody returns false, still parses If header', async ()=>{
|
|
225
|
+
const spyParse = jest.spyOn(guard, 'parseBody').mockReturnValue(false);
|
|
226
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.PROPFIND, {
|
|
227
|
+
headers: {
|
|
228
|
+
[_webdav.HEADER.IF]: '(<urn:uuid:abc>)'
|
|
229
|
+
},
|
|
230
|
+
body: undefined
|
|
231
|
+
});
|
|
232
|
+
const res = makeRes();
|
|
233
|
+
const ctx = makeCtx(req, res);
|
|
234
|
+
try {
|
|
235
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
236
|
+
expect(req.dav.body).toBeUndefined();
|
|
237
|
+
expect(req.dav.propfindMode).toBeUndefined();
|
|
238
|
+
expectIfHeadersParsed(req);
|
|
239
|
+
} finally{
|
|
240
|
+
spyParse.mockRestore();
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
describe('PROPPATCH', ()=>{
|
|
245
|
+
it('requires "propertyupdate" in body', async ()=>{
|
|
246
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.PROPPATCH, {
|
|
247
|
+
headers: {},
|
|
248
|
+
body: '<xml/>'
|
|
249
|
+
});
|
|
250
|
+
const res = makeRes();
|
|
251
|
+
const ctx = makeCtx(req, res);
|
|
252
|
+
await expect(guard.canActivate(ctx)).rejects.toMatchObject({
|
|
253
|
+
status: _common.HttpStatus.BAD_REQUEST
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
it('valid body and parses If header', async ()=>{
|
|
257
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.PROPPATCH, {
|
|
258
|
+
headers: {
|
|
259
|
+
[_webdav.HEADER.IF]: '(<urn:uuid:abc>)',
|
|
260
|
+
[_webdav.HEADER.DEPTH]: _webdav.DEPTH.RESOURCE
|
|
261
|
+
},
|
|
262
|
+
body: '<propertyupdate xmlns="DAV:"><set/></propertyupdate>'
|
|
263
|
+
});
|
|
264
|
+
const res = makeRes();
|
|
265
|
+
const ctx = makeCtx(req, res);
|
|
266
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
267
|
+
expect(req.dav.depth).toBe(_webdav.DEPTH.RESOURCE);
|
|
268
|
+
expectIfHeadersParsed(req);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
describe('LOCK', ()=>{
|
|
272
|
+
it('timeout=Infinite -> default timeout, owner from string, depth=resource', async ()=>{
|
|
273
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.LOCK, {
|
|
274
|
+
headers: {
|
|
275
|
+
[_webdav.HEADER.TIMEOUT]: 'Infinite',
|
|
276
|
+
[_webdav.HEADER.DEPTH]: _webdav.DEPTH.RESOURCE
|
|
277
|
+
},
|
|
278
|
+
body: '<lockinfo xmlns="DAV:"><lockscope><exclusive/></lockscope><owner>Custom Owner</owner></lockinfo>'
|
|
279
|
+
});
|
|
280
|
+
const res = makeRes();
|
|
281
|
+
const ctx = makeCtx(req, res);
|
|
282
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
283
|
+
expect(req.dav.lock.timeout).toBe(_fileslockmanagerservice.FilesLockManager.defaultLockTimeoutSeconds);
|
|
284
|
+
expect(req.dav.lock.lockscope).toBe(_webdav.LOCK_SCOPE.EXCLUSIVE);
|
|
285
|
+
expect(req.dav.lock.owner).toContain('Custom Owner');
|
|
286
|
+
expect(req.dav.depth).toBe(_webdav.DEPTH.RESOURCE);
|
|
287
|
+
});
|
|
288
|
+
it('timeout Second-10 + non-string owner -> default WebDAV owner, depth=infinity', async ()=>{
|
|
289
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.LOCK, {
|
|
290
|
+
headers: {
|
|
291
|
+
[_webdav.HEADER.TIMEOUT]: 'Second-10',
|
|
292
|
+
[_webdav.HEADER.DEPTH]: _webdav.DEPTH.INFINITY
|
|
293
|
+
},
|
|
294
|
+
body: '<lockinfo xmlns="DAV:"><lockscope><shared/></lockscope><owner><href>me</href></owner></lockinfo>'
|
|
295
|
+
});
|
|
296
|
+
const res = makeRes();
|
|
297
|
+
const ctx = makeCtx(req, res);
|
|
298
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
299
|
+
expect(req.dav.lock.timeout).toBe(10);
|
|
300
|
+
expect(req.dav.lock.lockscope).toBe(_webdav.LOCK_SCOPE.SHARED);
|
|
301
|
+
expect(req.dav.lock.owner).toMatch(/^WebDAV - /);
|
|
302
|
+
expect(req.dav.depth).toBe(_webdav.DEPTH.INFINITY);
|
|
303
|
+
});
|
|
304
|
+
it('clamps timeout Second-N to default when N exceeds default', async ()=>{
|
|
305
|
+
const big = _fileslockmanagerservice.FilesLockManager.defaultLockTimeoutSeconds + 1000;
|
|
306
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.LOCK, {
|
|
307
|
+
headers: {
|
|
308
|
+
[_webdav.HEADER.TIMEOUT]: `Second-${big}`
|
|
309
|
+
},
|
|
310
|
+
body: '<lockinfo xmlns="DAV:"><lockscope><exclusive/></lockscope></lockinfo>'
|
|
311
|
+
});
|
|
312
|
+
const res = makeRes();
|
|
313
|
+
const ctx = makeCtx(req, res);
|
|
314
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
315
|
+
expect(req.dav.lock.timeout).toBe(_fileslockmanagerservice.FilesLockManager.defaultLockTimeoutSeconds);
|
|
316
|
+
});
|
|
317
|
+
it('invalid timeout -> NaN (no fallback), depth=infinity', async ()=>{
|
|
318
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.LOCK, {
|
|
319
|
+
headers: {
|
|
320
|
+
[_webdav.HEADER.TIMEOUT]: 'Bad-Token',
|
|
321
|
+
[_webdav.HEADER.DEPTH]: 'x'
|
|
322
|
+
},
|
|
323
|
+
body: '<lockinfo xmlns="DAV:"><lockscope><exclusive/></lockscope></lockinfo>'
|
|
324
|
+
});
|
|
325
|
+
const res = makeRes();
|
|
326
|
+
const ctx = makeCtx(req, res);
|
|
327
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
328
|
+
expect(Number.isNaN(req.dav.lock.timeout)).toBe(true);
|
|
329
|
+
expect(req.dav.depth).toBe(_webdav.DEPTH.INFINITY);
|
|
330
|
+
});
|
|
331
|
+
it('handles parseInt exception during timeout parsing', async ()=>{
|
|
332
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.LOCK, {
|
|
333
|
+
headers: {
|
|
334
|
+
[_webdav.HEADER.TIMEOUT]: 'Second-'
|
|
335
|
+
},
|
|
336
|
+
body: '<lockinfo xmlns="DAV:"><lockscope><exclusive/></lockscope></lockinfo>'
|
|
337
|
+
});
|
|
338
|
+
const res = makeRes();
|
|
339
|
+
const ctx = makeCtx(req, res);
|
|
340
|
+
const originalParseInt = global.parseInt;
|
|
341
|
+
global.parseInt = jest.fn().mockImplementation(()=>{
|
|
342
|
+
throw new Error('Forced parseInt error');
|
|
343
|
+
});
|
|
344
|
+
try {
|
|
345
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
346
|
+
expect(req.dav.lock).toBeDefined();
|
|
347
|
+
} finally{
|
|
348
|
+
global.parseInt = originalParseInt;
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
it('timeout Infinite + empty IfHeader -> default timeout and ifHeaders undefined', async ()=>{
|
|
352
|
+
const spyIf = jest.spyOn(_ifheader, 'parseIfHeader').mockReturnValue([]);
|
|
353
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.LOCK, {
|
|
354
|
+
headers: {
|
|
355
|
+
[_webdav.HEADER.TIMEOUT]: 'Infinite',
|
|
356
|
+
[_webdav.HEADER.IF]: '(<any>)'
|
|
357
|
+
},
|
|
358
|
+
body: '<lockinfo xmlns="DAV:"><lockscope><exclusive/></lockscope></lockinfo>'
|
|
359
|
+
});
|
|
360
|
+
const res = makeRes();
|
|
361
|
+
const ctx = makeCtx(req, res);
|
|
362
|
+
try {
|
|
363
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
364
|
+
expect(req.dav.lock.timeout).toBe(_fileslockmanagerservice.FilesLockManager.defaultLockTimeoutSeconds);
|
|
365
|
+
expect(req.dav.ifHeaders).toBeUndefined();
|
|
366
|
+
} finally{
|
|
367
|
+
spyIf.mockRestore();
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
it('missing lockinfo -> 400', async ()=>{
|
|
371
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.LOCK, {
|
|
372
|
+
headers: {},
|
|
373
|
+
body: '<notlockinfo xmlns="DAV:"/>'
|
|
374
|
+
});
|
|
375
|
+
const res = makeRes();
|
|
376
|
+
const ctx = makeCtx(req, res);
|
|
377
|
+
await expect(guard.canActivate(ctx)).rejects.toMatchObject({
|
|
378
|
+
status: _common.HttpStatus.BAD_REQUEST
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
it('invalid lockscope -> 400', async ()=>{
|
|
382
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.LOCK, {
|
|
383
|
+
headers: {},
|
|
384
|
+
body: '<lockinfo xmlns="DAV:"><lockscope><invalid/></lockscope></lockinfo>'
|
|
385
|
+
});
|
|
386
|
+
const res = makeRes();
|
|
387
|
+
const ctx = makeCtx(req, res);
|
|
388
|
+
await expect(guard.canActivate(ctx)).rejects.toMatchObject({
|
|
389
|
+
status: _common.HttpStatus.BAD_REQUEST
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
it('handles Object.keys(lockscope) exception with malformed lockscope -> 400', async ()=>{
|
|
393
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.LOCK, {
|
|
394
|
+
headers: {},
|
|
395
|
+
body: '<lockinfo xmlns="DAV:"><lockscope><exclusive/></lockscope></lockinfo>'
|
|
396
|
+
});
|
|
397
|
+
const res = makeRes();
|
|
398
|
+
const ctx = makeCtx(req, res);
|
|
399
|
+
jest.spyOn(guard, 'parseBody').mockImplementation(()=>{
|
|
400
|
+
req.dav.body = {
|
|
401
|
+
lockinfo: {
|
|
402
|
+
lockscope: null
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
return true;
|
|
406
|
+
});
|
|
407
|
+
await expect(guard.canActivate(ctx)).rejects.toMatchObject({
|
|
408
|
+
status: _common.HttpStatus.BAD_REQUEST,
|
|
409
|
+
message: 'Invalid or undefined lockscope'
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
it('refresh (no body) -> dav.depth = null', async ()=>{
|
|
413
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.LOCK, {
|
|
414
|
+
headers: {
|
|
415
|
+
[_webdav.HEADER.DEPTH]: _webdav.DEPTH.RESOURCE
|
|
416
|
+
},
|
|
417
|
+
body: undefined
|
|
418
|
+
});
|
|
419
|
+
const res = makeRes();
|
|
420
|
+
const ctx = makeCtx(req, res);
|
|
421
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
422
|
+
expect(req.dav.depth).toBeNull();
|
|
423
|
+
});
|
|
424
|
+
it('no timeout header -> lock.timeout is undefined', async ()=>{
|
|
425
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.LOCK, {
|
|
426
|
+
headers: {},
|
|
427
|
+
body: '<lockinfo xmlns="DAV:"><lockscope><exclusive/></lockscope></lockinfo>'
|
|
428
|
+
});
|
|
429
|
+
const res = makeRes();
|
|
430
|
+
const ctx = makeCtx(req, res);
|
|
431
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
432
|
+
expect(req.dav.lock).toBeDefined();
|
|
433
|
+
expect(req.dav.lock.timeout).toBeUndefined();
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
describe('UNLOCK', ()=>{
|
|
437
|
+
it('missing lock-token -> 400', async ()=>{
|
|
438
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.UNLOCK);
|
|
439
|
+
const res = makeRes();
|
|
440
|
+
const ctx = makeCtx(req, res);
|
|
441
|
+
await expect(guard.canActivate(ctx)).rejects.toMatchObject({
|
|
442
|
+
status: _common.HttpStatus.BAD_REQUEST
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
it('sets token in dav.lock and parses If header', async ()=>{
|
|
446
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.UNLOCK, {
|
|
447
|
+
headers: {
|
|
448
|
+
[_webdav.HEADER.LOCK_TOKEN]: ' <abc> ',
|
|
449
|
+
[_webdav.HEADER.IF]: '(<urn:uuid:abc>)'
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
const res = makeRes();
|
|
453
|
+
const ctx = makeCtx(req, res);
|
|
454
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
455
|
+
expect(req.dav.lock.token).toBe('abc');
|
|
456
|
+
expectIfHeadersParsed(req);
|
|
457
|
+
});
|
|
458
|
+
});
|
|
459
|
+
describe('PUT / DELETE', ()=>{
|
|
460
|
+
it('PUT: depth=0 and parses If header', async ()=>{
|
|
461
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.PUT, {
|
|
462
|
+
headers: {
|
|
463
|
+
[_webdav.HEADER.IF]: '(<urn:uuid:abc>)'
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
const res = makeRes();
|
|
467
|
+
const ctx = makeCtx(req, res);
|
|
468
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
469
|
+
expect(req.dav.depth).toBe(_webdav.DEPTH.RESOURCE);
|
|
470
|
+
expectIfHeadersParsed(req);
|
|
471
|
+
});
|
|
472
|
+
it('DELETE: parses If header', async ()=>{
|
|
473
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.DELETE, {
|
|
474
|
+
headers: {
|
|
475
|
+
[_webdav.HEADER.IF]: '(<urn:uuid:abc>)'
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
const res = makeRes();
|
|
479
|
+
const ctx = makeCtx(req, res);
|
|
480
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
481
|
+
expectIfHeadersParsed(req);
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
describe('MKCOL', ()=>{
|
|
485
|
+
it('non-zero content-length -> 415', async ()=>{
|
|
486
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.MKCOL, {
|
|
487
|
+
headers: {
|
|
488
|
+
'content-length': '3'
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
const res = makeRes();
|
|
492
|
+
const ctx = makeCtx(req, res);
|
|
493
|
+
await expect(guard.canActivate(ctx)).rejects.toMatchObject({
|
|
494
|
+
status: _common.HttpStatus.UNSUPPORTED_MEDIA_TYPE
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
it('zero/absent content-length -> depth=0 and parses If header', async ()=>{
|
|
498
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.MKCOL, {
|
|
499
|
+
headers: {
|
|
500
|
+
'content-length': '0',
|
|
501
|
+
[_webdav.HEADER.IF]: '(<urn:uuid:abc>)'
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
const res = makeRes();
|
|
505
|
+
const ctx = makeCtx(req, res);
|
|
506
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
507
|
+
expect(req.dav.depth).toBe(_webdav.DEPTH.RESOURCE);
|
|
508
|
+
expectIfHeadersParsed(req);
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
describe('COPY / MOVE', ()=>{
|
|
512
|
+
it('COPY: missing Destination -> 400', async ()=>{
|
|
513
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.COPY);
|
|
514
|
+
const res = makeRes();
|
|
515
|
+
const ctx = makeCtx(req, res);
|
|
516
|
+
await expect(guard.canActivate(ctx)).rejects.toMatchObject({
|
|
517
|
+
status: _common.HttpStatus.BAD_REQUEST
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
it('COPY: invalid Destination base path -> 400', async ()=>{
|
|
521
|
+
;
|
|
522
|
+
_shared.decodeUrl.mockImplementation((s)=>s);
|
|
523
|
+
_functions.urlToPath.mockImplementation((s)=>'/not-webdav' + s);
|
|
524
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.COPY, {
|
|
525
|
+
headers: {
|
|
526
|
+
[_webdav.HEADER.DESTINATION]: '/wrong'
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
const res = makeRes();
|
|
530
|
+
const ctx = makeCtx(req, res);
|
|
531
|
+
await expect(guard.canActivate(ctx)).rejects.toMatchObject({
|
|
532
|
+
status: _common.HttpStatus.BAD_REQUEST
|
|
533
|
+
});
|
|
534
|
+
});
|
|
535
|
+
it('COPY: valid Destination -> overwrite=true, move=false, depth=infinity and parses If header', async ()=>{
|
|
536
|
+
;
|
|
537
|
+
_shared.decodeUrl.mockImplementation((s)=>s);
|
|
538
|
+
_functions.urlToPath.mockImplementation((_s)=>'/webdav/base/path/target');
|
|
539
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.COPY, {
|
|
540
|
+
headers: {
|
|
541
|
+
[_webdav.HEADER.DESTINATION]: '/webdav/base/path/target',
|
|
542
|
+
[_webdav.HEADER.IF]: '(<urn:uuid:abc>)'
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
const res = makeRes();
|
|
546
|
+
const ctx = makeCtx(req, res);
|
|
547
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
548
|
+
expect(req.dav.depth).toBe(_webdav.DEPTH.INFINITY);
|
|
549
|
+
expect(req.dav.copyMove).toEqual({
|
|
550
|
+
overwrite: true,
|
|
551
|
+
destination: '/webdav/base/path/target',
|
|
552
|
+
isMove: false
|
|
553
|
+
});
|
|
554
|
+
expectIfHeadersParsed(req);
|
|
555
|
+
});
|
|
556
|
+
it('MOVE: isMove=true and overwrite=false when OVERWRITE header is "f", respects depth header', async ()=>{
|
|
557
|
+
;
|
|
558
|
+
_shared.decodeUrl.mockImplementation((s)=>s);
|
|
559
|
+
_functions.urlToPath.mockImplementation((_s)=>'/webdav/base/path/target2');
|
|
560
|
+
const req = baseReq(_applicationsconstants.HTTP_METHOD.MOVE, {
|
|
561
|
+
headers: {
|
|
562
|
+
[_webdav.HEADER.DESTINATION]: '/webdav/base/path/target2',
|
|
563
|
+
[_webdav.HEADER.OVERWRITE]: 'f',
|
|
564
|
+
[_webdav.HEADER.DEPTH]: _webdav.DEPTH.RESOURCE
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
const res = makeRes();
|
|
568
|
+
const ctx = makeCtx(req, res);
|
|
569
|
+
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
570
|
+
expect(req.dav.depth).toBe(_webdav.DEPTH.RESOURCE);
|
|
571
|
+
expect(req.dav.copyMove).toEqual({
|
|
572
|
+
overwrite: false,
|
|
573
|
+
destination: '/webdav/base/path/target2',
|
|
574
|
+
isMove: true
|
|
575
|
+
});
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
//# sourceMappingURL=webdav-protocol.guard.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/webdav/guards/webdav-protocol.guard.spec.ts"],"sourcesContent":["import { HttpException, HttpStatus } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { FastifyReply } from 'fastify'\nimport { urlToPath } from '../../../common/functions'\nimport { decodeUrl } from '../../../common/shared'\nimport { HTTP_METHOD } from '../../applications.constants'\nimport { FilesLockManager } from '../../files/services/files-lock-manager.service'\nimport { DEPTH, HEADER, LOCK_SCOPE, OPTIONS_HEADERS, PROPSTAT } from '../constants/webdav'\nimport { FastifyDAVRequest } from '../interfaces/webdav.interface'\nimport { PROPFIND_ALL_PROP } from '../utils/webdav'\nimport { WebDAVProtocolGuard } from './webdav-protocol.guard'\nimport * as IfHeaderUtils from '../utils/if-header'\n\n// Keep these mocks to control path transforms in COPY/MOVE tests\njest.mock('../../../common/shared', () => ({\n decodeUrl: jest.fn((s: string) => s)\n}))\njest.mock('../../../common/functions', () => ({\n urlToPath: jest.fn((s: string) => s)\n}))\n\ndescribe(WebDAVProtocolGuard.name, () => {\n let guard: WebDAVProtocolGuard\n\n const makeUser = (hasPerm = true) => ({\n havePermission: jest.fn(() => hasPerm),\n fullName: 'John Doe',\n email: 'john@doe.tld'\n })\n\n const makeRes = (): FastifyReply =>\n ({\n headers: jest.fn()\n }) as unknown as FastifyReply\n\n const baseReq = (method: string, overrides: Partial<FastifyDAVRequest> = {}): FastifyDAVRequest =>\n ({\n method,\n headers: {},\n // undefined body allows to hit the \"allowed empty body\" branch for PROPFIND/LOCK\n body: undefined as any,\n originalUrl: '/webdav/base/path',\n protocol: 'http',\n raw: { httpVersion: '1.1' } as any,\n user: makeUser(),\n ...overrides\n }) as unknown as FastifyDAVRequest\n\n const makeCtx = (req: FastifyDAVRequest, res: FastifyReply) =>\n ({\n switchToHttp: () => ({\n getRequest: () => req,\n getResponse: () => res\n })\n }) as any\n\n const expectIfHeadersParsed = (req: FastifyDAVRequest) => {\n expect(Array.isArray(req.dav.ifHeaders)).toBe(true)\n expect(req.dav.ifHeaders.length).toBeGreaterThan(0)\n }\n\n beforeEach(async () => {\n jest.clearAllMocks()\n const module: TestingModule = await Test.createTestingModule({\n providers: [WebDAVProtocolGuard]\n }).compile()\n\n guard = module.get(WebDAVProtocolGuard)\n })\n\n describe('Permissions', () => {\n it('allows OPTIONS even without WEBDAV permission (responds headers + 200)', async () => {\n const req = baseReq(HTTP_METHOD.OPTIONS, { user: makeUser(false) as any })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n await expect(guard.canActivate(ctx)).rejects.toThrow(HttpException)\n try {\n await guard.canActivate(ctx)\n } catch (e) {\n const ex = e as HttpException\n expect(res.headers).toHaveBeenCalledWith(OPTIONS_HEADERS)\n expect(ex.getStatus()).toBe(HttpStatus.OK)\n }\n })\n\n it('forbids non-OPTIONS when the user lacks WEBDAV permission', async () => {\n const req = baseReq(HTTP_METHOD.GET, { user: makeUser(false) as any })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.FORBIDDEN })\n })\n\n it('falls through for a method not handled by the switch', async () => {\n const req = baseReq('VIEW', {})\n const res = makeRes()\n const ctx = makeCtx(req, res)\n const spy = jest.spyOn(guard as any, 'setDAVContext')\n\n const result = await guard.canActivate(ctx)\n expect(result).toBe(true)\n expect(spy).toHaveBeenCalled()\n spy.mockRestore()\n })\n })\n\n describe('PROPFIND', () => {\n it('defaults depth=1 (members) when header is missing, and sets ALLPROP with empty body', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: {},\n body: undefined\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.url).toBe(req.originalUrl)\n expect(req.dav.depth).toBe(DEPTH.MEMBERS)\n expect(req.dav.body).toBe(PROPFIND_ALL_PROP)\n expect(req.dav.propfindMode).toBe(PROPSTAT.ALLPROP)\n expect(req.dav.ifHeaders === undefined || req.dav.ifHeaders.length === 0).toBe(true)\n })\n\n it.each([\n { title: 'depth \"infinity\" normalized to 1 (members)', depth: DEPTH.INFINITY as any },\n { title: 'invalid depth normalized to 1 (members)', depth: 'bad' as any }\n ])('depth normalization: $title', async ({ depth }) => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: { [HEADER.DEPTH]: depth },\n body: undefined\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.MEMBERS)\n })\n\n it('valid XML body with propname and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: { [HEADER.DEPTH]: DEPTH.RESOURCE, [HEADER.IF]: '(<urn:uuid:abc> [\"W/\\\\\"ETag\\\\\"\"])' },\n body: '<propfind xmlns=\"DAV:\"><propname/></propfind>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expect(req.dav.propfindMode).toBe(PROPSTAT.PROPNAME)\n expectIfHeadersParsed(req)\n })\n\n it('invalid propfind mode -> 400', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: {},\n body: '<propfind xmlns=\"DAV:\"><unknown/></propfind>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('invalid XML (with code) -> 400', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: {},\n body: '<bad'\n } as any)\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('specific XML validation error handled -> 400', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: {},\n body: 'this is not XML at all'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toHaveProperty('status', HttpStatus.BAD_REQUEST)\n })\n\n it('skips body when parseBody returns false, still parses If header', async () => {\n const spyParse = jest.spyOn(guard as any, 'parseBody').mockReturnValue(false as any)\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: { [HEADER.IF]: '(<urn:uuid:abc>)' },\n body: undefined\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n try {\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.body).toBeUndefined()\n expect(req.dav.propfindMode).toBeUndefined()\n expectIfHeadersParsed(req)\n } finally {\n spyParse.mockRestore()\n }\n })\n })\n\n describe('PROPPATCH', () => {\n it('requires \"propertyupdate\" in body', async () => {\n const req = baseReq(HTTP_METHOD.PROPPATCH, {\n headers: {},\n body: '<xml/>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('valid body and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.PROPPATCH, {\n headers: { [HEADER.IF]: '(<urn:uuid:abc>)', [HEADER.DEPTH]: DEPTH.RESOURCE },\n body: '<propertyupdate xmlns=\"DAV:\"><set/></propertyupdate>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expectIfHeadersParsed(req)\n })\n })\n\n describe('LOCK', () => {\n it('timeout=Infinite -> default timeout, owner from string, depth=resource', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Infinite', [HEADER.DEPTH]: DEPTH.RESOURCE },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope><owner>Custom Owner</owner></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.timeout).toBe(FilesLockManager.defaultLockTimeoutSeconds)\n expect(req.dav.lock.lockscope).toBe(LOCK_SCOPE.EXCLUSIVE)\n expect(req.dav.lock.owner).toContain('Custom Owner')\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n })\n\n it('timeout Second-10 + non-string owner -> default WebDAV owner, depth=infinity', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Second-10', [HEADER.DEPTH]: DEPTH.INFINITY },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><shared/></lockscope><owner><href>me</href></owner></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.timeout).toBe(10)\n expect(req.dav.lock.lockscope).toBe(LOCK_SCOPE.SHARED)\n expect(req.dav.lock.owner).toMatch(/^WebDAV - /)\n expect(req.dav.depth).toBe(DEPTH.INFINITY)\n })\n\n it('clamps timeout Second-N to default when N exceeds default', async () => {\n const big = FilesLockManager.defaultLockTimeoutSeconds + 1000\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: `Second-${big}` },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.timeout).toBe(FilesLockManager.defaultLockTimeoutSeconds)\n })\n\n it('invalid timeout -> NaN (no fallback), depth=infinity', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Bad-Token', [HEADER.DEPTH]: 'x' as any },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(Number.isNaN(req.dav.lock.timeout)).toBe(true)\n expect(req.dav.depth).toBe(DEPTH.INFINITY)\n })\n\n it('handles parseInt exception during timeout parsing', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Second-' },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n const originalParseInt = global.parseInt\n global.parseInt = jest.fn().mockImplementation(() => {\n throw new Error('Forced parseInt error')\n })\n\n try {\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock).toBeDefined()\n } finally {\n global.parseInt = originalParseInt\n }\n })\n\n it('timeout Infinite + empty IfHeader -> default timeout and ifHeaders undefined', async () => {\n const spyIf = jest.spyOn(IfHeaderUtils, 'parseIfHeader').mockReturnValue([] as any)\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Infinite', [HEADER.IF]: '(<any>)' },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n try {\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.timeout).toBe(FilesLockManager.defaultLockTimeoutSeconds)\n expect(req.dav.ifHeaders).toBeUndefined()\n } finally {\n spyIf.mockRestore()\n }\n })\n\n it('missing lockinfo -> 400', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: {},\n body: '<notlockinfo xmlns=\"DAV:\"/>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('invalid lockscope -> 400', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: {},\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><invalid/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('handles Object.keys(lockscope) exception with malformed lockscope -> 400', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: {},\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n jest.spyOn(guard as any, 'parseBody').mockImplementation(() => {\n req.dav.body = {\n lockinfo: {\n lockscope: null\n }\n }\n return true\n })\n\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'Invalid or undefined lockscope'\n })\n })\n\n it('refresh (no body) -> dav.depth = null', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.DEPTH]: DEPTH.RESOURCE },\n body: undefined\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBeNull()\n })\n\n it('no timeout header -> lock.timeout is undefined', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: {},\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock).toBeDefined()\n expect(req.dav.lock.timeout).toBeUndefined()\n })\n })\n\n describe('UNLOCK', () => {\n it('missing lock-token -> 400', async () => {\n const req = baseReq(HTTP_METHOD.UNLOCK)\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('sets token in dav.lock and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.UNLOCK, {\n headers: { [HEADER.LOCK_TOKEN]: ' <abc> ', [HEADER.IF]: '(<urn:uuid:abc>)' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.token).toBe('abc')\n expectIfHeadersParsed(req)\n })\n })\n\n describe('PUT / DELETE', () => {\n it('PUT: depth=0 and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.PUT, {\n headers: { [HEADER.IF]: '(<urn:uuid:abc>)' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expectIfHeadersParsed(req)\n })\n\n it('DELETE: parses If header', async () => {\n const req = baseReq(HTTP_METHOD.DELETE, {\n headers: { [HEADER.IF]: '(<urn:uuid:abc>)' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expectIfHeadersParsed(req)\n })\n })\n\n describe('MKCOL', () => {\n it('non-zero content-length -> 415', async () => {\n const req = baseReq(HTTP_METHOD.MKCOL, {\n headers: { 'content-length': '3' }\n } as any)\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.UNSUPPORTED_MEDIA_TYPE })\n })\n\n it('zero/absent content-length -> depth=0 and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.MKCOL, {\n headers: { 'content-length': '0', [HEADER.IF]: '(<urn:uuid:abc>)' } as any\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expectIfHeadersParsed(req)\n })\n })\n\n describe('COPY / MOVE', () => {\n it('COPY: missing Destination -> 400', async () => {\n const req = baseReq(HTTP_METHOD.COPY)\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('COPY: invalid Destination base path -> 400', async () => {\n ;(decodeUrl as jest.Mock).mockImplementation((s: string) => s)\n ;(urlToPath as jest.Mock).mockImplementation((s: string) => '/not-webdav' + s)\n\n const req = baseReq(HTTP_METHOD.COPY, {\n headers: { [HEADER.DESTINATION]: '/wrong' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('COPY: valid Destination -> overwrite=true, move=false, depth=infinity and parses If header', async () => {\n ;(decodeUrl as jest.Mock).mockImplementation((s: string) => s)\n ;(urlToPath as jest.Mock).mockImplementation((_s: string) => '/webdav/base/path/target')\n\n const req = baseReq(HTTP_METHOD.COPY, {\n headers: { [HEADER.DESTINATION]: '/webdav/base/path/target', [HEADER.IF]: '(<urn:uuid:abc>)' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.INFINITY)\n expect(req.dav.copyMove).toEqual({\n overwrite: true,\n destination: '/webdav/base/path/target',\n isMove: false\n })\n expectIfHeadersParsed(req)\n })\n\n it('MOVE: isMove=true and overwrite=false when OVERWRITE header is \"f\", respects depth header', async () => {\n ;(decodeUrl as jest.Mock).mockImplementation((s: string) => s)\n ;(urlToPath as jest.Mock).mockImplementation((_s: string) => '/webdav/base/path/target2')\n\n const req = baseReq(HTTP_METHOD.MOVE, {\n headers: {\n [HEADER.DESTINATION]: '/webdav/base/path/target2',\n [HEADER.OVERWRITE]: 'f',\n [HEADER.DEPTH]: DEPTH.RESOURCE\n }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expect(req.dav.copyMove).toEqual({\n overwrite: false,\n destination: '/webdav/base/path/target2',\n isMove: true\n })\n })\n })\n})\n"],"names":["jest","mock","decodeUrl","fn","s","urlToPath","describe","WebDAVProtocolGuard","name","guard","makeUser","hasPerm","havePermission","fullName","email","makeRes","headers","baseReq","method","overrides","body","undefined","originalUrl","protocol","raw","httpVersion","user","makeCtx","req","res","switchToHttp","getRequest","getResponse","expectIfHeadersParsed","expect","Array","isArray","dav","ifHeaders","toBe","length","toBeGreaterThan","beforeEach","clearAllMocks","module","Test","createTestingModule","providers","compile","get","it","HTTP_METHOD","OPTIONS","ctx","canActivate","rejects","toThrow","HttpException","e","ex","toHaveBeenCalledWith","OPTIONS_HEADERS","getStatus","HttpStatus","OK","GET","toMatchObject","status","FORBIDDEN","spy","spyOn","result","toHaveBeenCalled","mockRestore","PROPFIND","resolves","url","depth","DEPTH","MEMBERS","PROPFIND_ALL_PROP","propfindMode","PROPSTAT","ALLPROP","each","title","INFINITY","HEADER","RESOURCE","IF","PROPNAME","BAD_REQUEST","toHaveProperty","spyParse","mockReturnValue","toBeUndefined","PROPPATCH","LOCK","TIMEOUT","lock","timeout","FilesLockManager","defaultLockTimeoutSeconds","lockscope","LOCK_SCOPE","EXCLUSIVE","owner","toContain","SHARED","toMatch","big","Number","isNaN","originalParseInt","global","parseInt","mockImplementation","Error","toBeDefined","spyIf","IfHeaderUtils","lockinfo","message","toBeNull","UNLOCK","LOCK_TOKEN","token","PUT","DELETE","MKCOL","UNSUPPORTED_MEDIA_TYPE","COPY","DESTINATION","_s","copyMove","toEqual","overwrite","destination","isMove","MOVE","OVERWRITE"],"mappings":"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"}
|