UNPKG

@sync-in/server

Version:

The secure, open-source platform for file storage, sharing, collaboration, and sync

545 lines (544 loc) 28.2 kB
/* * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com> * This file is part of Sync-in | The open source file sync and share solution * See the LICENSE file for licensing details */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "WebDAVMethods", { enumerable: true, get: function() { return WebDAVMethods; } }); const _common = require("@nestjs/common"); const _fastify = require("fastify"); const _shared = require("../../../common/shared"); const _fileerror = require("../../files/models/file-error"); const _filelockerror = require("../../files/models/file-lock-error"); const _fileslockmanagerservice = require("../../files/services/files-lock-manager.service"); const _filesmanagerservice = require("../../files/services/files-manager.service"); const _files = require("../../files/utils/files"); const _spaces = require("../../spaces/constants/spaces"); const _paths = require("../../spaces/utils/paths"); const _permissions = require("../../spaces/utils/permissions"); const _webdav = require("../constants/webdav"); const _ifheaderdecorator = require("../decorators/if-header.decorator"); const _webdavinterface = require("../interfaces/webdav.interface"); const _ifheader = require("../utils/if-header"); const _webdav1 = require("../utils/webdav"); const _xml = require("../utils/xml"); const _webdavspacesservice = require("./webdav-spaces.service"); function _ts_decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function _ts_metadata(k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); } let WebDAVMethods = class WebDAVMethods { async headOrGet(req, res, repository) { if (repository === _spaces.SPACE_REPOSITORY.FILES && !req.space.inSharesList) { if (await (0, _files.isPathExists)(req.space.realPath) && await (0, _files.isPathIsDir)(req.space.realPath)) { // Directory case return res.header('DAV', _webdav.OPTIONS_HEADERS.DAV).header('Content-Type', 'httpd/unix-directory').header('Content-Length', '0').status(_common.HttpStatus.OK).send(); } const sendFile = this.filesManager.sendFileFromSpace(req.space); try { await sendFile.checks(); return await sendFile.stream(req, res); } catch (e) { return this.handleError(req, res, e); } } this.logger.warn(`Not allowed on this resource : ${repository}`); return res.status(_common.HttpStatus.FORBIDDEN).send('Not allowed on this resource'); } async lock(req, res) { const isLockRefresh = !req.dav.body; const rExists = await (0, _files.isPathExists)(req.space.realPath); if (isLockRefresh) { // if the body has no content, the request must refresh the lock if (!rExists) { this.logger.warn('Lock refresh must specify an existing resource'); return res.status(_common.HttpStatus.BAD_REQUEST).send('Lock refresh must specify an existing resource'); } return this.lockRefresh(req, res, req.space.dbFile.path); } if (!rExists) { if (!(0, _permissions.haveSpaceEnvPermissions)(req.space, _spaces.SPACE_OPERATION.ADD)) { this.logger.warn(`is not allowed to create on this space : *${req.space.alias}* (${req.space.id}) : ${req.space.url}`); return res.status(_common.HttpStatus.FORBIDDEN).send('You are not allowed to do this action'); } if (!await (0, _files.isPathExists)((0, _files.dirName)(req.space.realPath))) { return res.status(_common.HttpStatus.CONFLICT).send('Parent must exists'); } } const lockOptions = { lockRoot: req.dav.url, lockToken: this.filesLockManager.genDAVToken(), lockScope: req.dav.lock.lockscope, lockInfo: req.dav.lock?.owner }; const [ok, fileLock] = await this.filesLockManager.create(req.user, req.space.dbFile, _webdav.WEBDAV_APP_LOCK, req.dav.depth, lockOptions, req.dav.lock.timeout); if (ok) { // Locking unmapped URLs: must create an empty resource (that is not a collection) if (!rExists) { // checkLocks set to false because the conflicts are already checked in the `filesLockManager.create` method await this.filesManager.mkFile(req.user, req.space, false, false, false); } const lockProp = (0, _webdav1.LOCK_PROP)([ fileLock ]); return res.header(_webdav.HEADER.LOCK_TOKEN, `<${lockOptions.lockToken}>`).type(_webdav.XML_CONTENT_TYPE).status(rExists ? _common.HttpStatus.OK : _common.HttpStatus.CREATED).send((0, _xml.xmlBuild)(lockProp)); } if (fileLock) { const lockProp = (0, _webdav1.LOCK_PROP)([ fileLock ]); return res.type(_webdav.XML_CONTENT_TYPE).status(_common.HttpStatus.LOCKED).send((0, _xml.xmlBuild)(lockProp)); } return (0, _webdav1.DAV_ERROR_RES)(_common.HttpStatus.LOCKED, _webdav.PRECONDITION.LOCK_CONFLICT, res, fileLock.options?.lockRoot || fileLock.dbFilePath); } async unlock(req, res) { if (!await (0, _files.isPathExists)(req.space.realPath)) { this.logger.warn(`Unable to unlock: ${req.dav.url} - resource does not exist`); return res.status(_common.HttpStatus.NOT_FOUND).send(req.dav.url); } const lock = await this.filesLockManager.isLockedWithToken(req.dav.lock.token, req.space.dbFile.path); if (!lock) { this.logger.warn(`Lock token does not exist or not match URL : ${req.dav.lock.token}`); return (0, _webdav1.DAV_ERROR_RES)(_common.HttpStatus.CONFLICT, _webdav.PRECONDITION.LOCK_TOKEN_MISMATCH, res); } if (req.user.id !== lock.owner.id) { return res.status(_common.HttpStatus.FORBIDDEN).send('Token was created by another user'); } await this.filesLockManager.removeLock(lock.key); return res.status(_common.HttpStatus.NO_CONTENT).send(); } async propfind(req, res, repository) { if (repository === _spaces.SPACE_REPOSITORY.FILES && !req.space.inSharesList) { if (!await (0, _files.isPathExists)(req.space.realPath)) { return res.status(_common.HttpStatus.NOT_FOUND).send(req.dav.url); } } const responses = []; let requestedProps; let locks = {}; if (req.dav.propfindMode === _webdav.PROPSTAT.PROP) { // ignores all unknown properties (non-RFC compliant but avoids generating too much content, faster) requestedProps = Object.keys(req.dav.body.propfind.prop).filter((prop)=>_webdav.STANDARD_PROPS.indexOf(prop) > -1); } else { requestedProps = _webdav.STANDARD_PROPS; } // Searches all child locks (only for real files) & ignores /webdav/shares endpoint (special case) if (req.dav.propfindMode !== _webdav.PROPSTAT.PROPNAME && repository === _spaces.SPACE_REPOSITORY.FILES && !req.space.inSharesList) { if (req.dav.depth === _webdav.DEPTH.RESOURCE) { // match depth '0' locks = await this.filesLockManager.browseLocks(req.space.dbFile); } else { // match depth '1' or 'infinity' locks = await this.filesLockManager.browseParentChildLocks(req.space.dbFile); } } for await (const f of this.webDAVHandler.propfind(req, repository)){ let prop; if (req.dav.propfindMode === _webdav.PROPSTAT.PROPNAME) { prop = { ...Object.fromEntries(requestedProps.map((x)=>[ `${_webdav.NS_PREFIX}:${x}`, '' ])) }; } else { prop = {}; for (const p of requestedProps){ let fP; if (p === _webdav.LOCK_DISCOVERY_PROP) { let lockDiscovery = null; if (repository === _spaces.SPACE_REPOSITORY.FILES) { if (f.name in locks) { lockDiscovery = (0, _webdav1.LOCK_DISCOVERY)([ locks[f.name] ]); } else { // The lock name may correspond to the original file at the space root. const fName = (0, _files.fileName)(req.space.dbFile.path); if (fName in locks) { lockDiscovery = (0, _webdav1.LOCK_DISCOVERY)([ locks[fName] ]); } } } fP = lockDiscovery; } else { fP = f[p]; } if (fP !== undefined) prop[`${_webdav.NS_PREFIX}:${p}`] = fP; } } responses.push((0, _webdav1.PROP_STAT)(f.href, (0, _webdav1.PROP)(prop, req.dav.httpVersion, _common.HttpStatus.OK))); } const propfind = (0, _xml.xmlBuild)((0, _webdav1.MULTI_STATUS)(responses)); return res.type(_webdav.XML_CONTENT_TYPE).status(_common.HttpStatus.MULTI_STATUS).send(propfind); } async put(req, res) { let rExists; try { rExists = await this.filesManager.saveStream(req.user, req.space, req, { dav: { depth: req.dav.depth, lockTokens: (0, _ifheader.extractAllTokens)(req.dav.ifHeaders) } }); } catch (e) { return this.handleError(req, res, e); } return res.header('etag', (0, _files.genEtag)(null, req.space.realPath)).status(rExists ? _common.HttpStatus.NO_CONTENT : _common.HttpStatus.CREATED).send(); } async delete(req, res) { try { await this.filesManager.delete(req.user, req.space, { lockTokens: (0, _ifheader.extractAllTokens)(req.dav.ifHeaders) }); } catch (e) { return this.handleError(req, res, e); } return res.status(_common.HttpStatus.NO_CONTENT).send(); } async proppatch(req, res) { /* only support 'time modifications' */ if (!await (0, _files.isPathExists)(req.space.realPath)) { return res.status(_common.HttpStatus.NOT_FOUND).send(req.dav.url); } // check locks try { await this.filesLockManager.checkConflicts(req.space.dbFile, req.dav.depth, { userId: req.user.id, lockTokens: (0, _ifheader.extractAllTokens)(req.dav.ifHeaders) }); } catch (e) { return this.handleError(req, res, e); } // evaluate props and return multistatus if errors req.dav.proppatch = { props: {}, errors: [] }; for (const action of Object.keys(req.dav.body[_webdav.PROPPATCH_PROP_UPDATE])){ if (Object.values(_webdav.PROPPATCH_METHOD).indexOf(action) === -1) { const msg = `Unknown tag : expected ${_webdav.PROPPATCH_METHOD.SET} or ${_webdav.PROPPATCH_METHOD.REMOVE}`; this.logger.debug(msg); return res.status(_common.HttpStatus.BAD_REQUEST).send(msg); } if (Array.isArray(req.dav.body[_webdav.PROPPATCH_PROP_UPDATE][action])) { if (Object.keys(req.dav.body[_webdav.PROPPATCH_PROP_UPDATE][action][0])[0] === _webdav.PROPSTAT.PROP) { req.dav.body[_webdav.PROPPATCH_PROP_UPDATE][action] = { [_webdav.PROPSTAT.PROP]: req.dav.body[_webdav.PROPPATCH_PROP_UPDATE][action].map((e)=>e[_webdav.PROPSTAT.PROP]) }; } } if (Object.keys(req.dav.body[_webdav.PROPPATCH_PROP_UPDATE][action])[0] !== _webdav.PROPSTAT.PROP) { const msg = `Unknown tag : expected ${_webdav.PROPSTAT.PROP}`; this.logger.debug(msg); return res.status(_common.HttpStatus.BAD_REQUEST).send(msg); } if (!Array.isArray(req.dav.body[_webdav.PROPPATCH_PROP_UPDATE][action][_webdav.PROPSTAT.PROP])) { req.dav.body[_webdav.PROPPATCH_PROP_UPDATE][action][_webdav.PROPSTAT.PROP] = [ req.dav.body[_webdav.PROPPATCH_PROP_UPDATE][action][_webdav.PROPSTAT.PROP] ]; } for (const prop of req.dav.body[_webdav.PROPPATCH_PROP_UPDATE][action][_webdav.PROPSTAT.PROP]){ for (let [name, value] of Object.entries(prop)){ if (action === _webdav.PROPPATCH_METHOD.REMOVE) { value = null; this.logger.debug(`Proppatch remove method not handled : ${name} -> ${value}`); } if (_webdav.PROPPATCH_SUPPORTED_PROPS.indexOf(name) === -1) { req.dav.proppatch.errors.push((0, _webdav1.PROP)({ [`${_webdav.NS_PREFIX}:${name}`]: null }, req.dav.httpVersion, _common.HttpStatus.FORBIDDEN, _webdav.STANDARD_PROPS.indexOf(name) > -1 ? _webdav.PRECONDITION.PROTECTED_PROPERTY : undefined)); continue; } req.dav.proppatch.props[name] = value; } } } if (req.dav.proppatch.errors.length) { // convert all passed props to failed dependency for (const name of Object.keys(req.dav.proppatch.props)){ req.dav.proppatch.errors.push((0, _webdav1.PROP)({ [`${_webdav.NS_PREFIX}:${name}`]: null }, req.dav.httpVersion, _common.HttpStatus.FAILED_DEPENDENCY)); } const proppatch = (0, _xml.xmlBuild)((0, _webdav1.MULTI_STATUS)((0, _webdav1.PROP_STAT)((0, _shared.encodeUrl)(req.dav.url), req.dav.proppatch.errors))); return res.status(_common.HttpStatus.MULTI_STATUS).type(_webdav.XML_CONTENT_TYPE).send(proppatch); } // apply modifications let atLeastOneError = false; const states = {}; for (const [name, value] of Object.entries(req.dav.proppatch.props)){ if (_webdav.PROPPATCH_MODIFIED_PROPS.indexOf(name) > -1) { try { await this.filesManager.touch(req.user, req.space, (0, _shared.currentTimeStamp)(new Date(value)), false); } catch (e) { this.logger.error(`${this.proppatch.name} - unable to modify mtime on ${req.dav.url} : ${e}`); states[name] = false; atLeastOneError = true; } } // hook: we let the known Win32* properties pass to return a consistent result states[name] = true; } const props = []; for (const [name, state] of Object.entries(states)){ props.push((0, _webdav1.PROP)({ [`${_webdav.NS_PREFIX}:${name}`]: null }, req.dav.httpVersion, state ? atLeastOneError ? _common.HttpStatus.FAILED_DEPENDENCY : _common.HttpStatus.OK : _common.HttpStatus.BAD_REQUEST)); } const proppatch = (0, _xml.xmlBuild)((0, _webdav1.MULTI_STATUS)((0, _webdav1.PROP_STAT)((0, _shared.encodeUrl)(req.dav.url), props))); return res.type(_webdav.XML_CONTENT_TYPE).status(_common.HttpStatus.MULTI_STATUS).send(proppatch); } async mkcol(req, res) { try { await this.filesManager.mkDir(req.user, req.space, false, { depth: req.dav.depth, lockTokens: (0, _ifheader.extractAllTokens)(req.dav.ifHeaders) }); } catch (e) { return this.handleError(req, res, e); } return res.status(_common.HttpStatus.CREATED).send(); } async copyMove(req, res) { const dstSpace = await this.webDAVHandler.spaceEnv(req.user, req.dav.copyMove.destination); if (!dstSpace) { this.logger.warn(`Space not found for destination : ${req.dav.copyMove.destination}`); return res.status(_common.HttpStatus.NOT_FOUND).send(req.dav.copyMove.destination); } const dstExisted = await (0, _files.isPathExists)(dstSpace.realPath); // We must evaluate the if-headers on the destination const fakeDstReq = { dav: { ...req.dav, url: req.dav.copyMove.destination }, user: req.user, space: dstSpace }; if (!await this.evaluateIfHeaders(fakeDstReq, res)) { // if there is an error, the response is generated inside the `evaluateIfHeaders` function return; } try { await this.filesManager.copyMove(req.user, req.space, dstSpace, req.dav.copyMove.isMove, req.dav.copyMove.overwrite, false, { depth: req.dav.depth, lockTokens: (0, _ifheader.extractAllTokens)(req.dav.ifHeaders) }); } catch (e) { return this.handleError(req, res, e, dstSpace.url); } return res.status(dstExisted ? _common.HttpStatus.NO_CONTENT : _common.HttpStatus.CREATED).send(); } async evaluateIfHeaders(req, res) { if (!req.dav.ifHeaders) return true; const errors = []; let lastPath = null; let lastSpaceEnv; let lastRPath = undefined; let lastEtag = undefined // for now, we only generate one etag type (weak) ; let atLeastOneOk = false; for (const condition of req.dav.ifHeaders){ if (condition.path) { if (condition.path !== lastPath) { lastPath = condition.path; lastSpaceEnv = await this.webDAVHandler.spaceEnv(req.user, lastPath); } // the path will be the same across conditions if (!lastSpaceEnv) { this.logger.warn(`If Header : path mismatch (${condition.path})`); return false; } } else { lastPath = req.dav.url; lastSpaceEnv = req.space; } if (condition.haveLock) { try { const dbFile = (0, _paths.dbFileFromSpace)(req.user.id, lastSpaceEnv); const match = !!(await this.filesLockManager.getLocksByPath(dbFile)).length; if (condition.haveLock.mustMatch !== match) { errors.push(`have lock condition mismatch (${condition.haveLock.mustMatch} != ${match})`); continue; } } catch (e) { errors.push(`have lock condition mismatch : ${e.message}`); continue; } } if (condition.token) { const token = await this.filesLockManager.getLockByToken(condition.token.value); const match = token && lastPath.startsWith(token.options?.lockRoot); if (condition.token.mustMatch !== match) { if (!token) { errors.push(`lock token not found`); } else { errors.push(`lock token url mismatch (${lastPath} is not a child of ${token.options?.lockRoot})`); } continue; } } if (condition.etag) { if (lastEtag === undefined) { if (lastRPath === undefined) { lastRPath = await (0, _files.isPathExists)(req.space.realPath) ? req.space.realPath : null; } lastEtag = lastRPath ? (0, _files.genEtag)(null, lastRPath) : null; } const match = lastEtag === condition.etag.value; if (condition.etag.mustMatch !== match) { errors.push(`etag mismatch (${condition.etag.value} != ${lastEtag})`); continue; } } atLeastOneOk = true; break; } if (!atLeastOneOk) { this.logger.warn(`If header condition failed : ${errors.join(', ')}`); res.status(_common.HttpStatus.PRECONDITION_FAILED).send('If header condition failed'); } return atLeastOneOk; } async lockRefresh(req, res, dbFilePath) { if (req.dav?.ifHeaders?.length !== 1) { this.logger.warn('Expected a lock token (only one lock may be refreshed at a time)'); return res.status(_common.HttpStatus.BAD_REQUEST).send('Expected a lock token (only one lock may be refreshed at a time)'); } let token; try { token = (0, _ifheader.extractOneToken)(req.dav.ifHeaders); } catch (e) { this.logger.warn(`${this.lockRefresh.name} - unable to extract token : ${JSON.stringify(req.dav.ifHeaders)} (${e})`); return res.status(_common.HttpStatus.BAD_REQUEST).send('Unable to extract token'); } const lock = await this.filesLockManager.isLockedWithToken(token, dbFilePath); if (!lock) { this.logger.warn(`Lock token does not exist or not match URL : ${token}`); return (0, _webdav1.DAV_ERROR_RES)(_common.HttpStatus.PRECONDITION_FAILED, _webdav.PRECONDITION.LOCK_TOKEN_MISMATCH, res); } if (lock.owner.id !== req.user.id) { this.logger.warn(`Lock token does not match owner : ${lock.owner.login} != ${req.user.login}`); return res.status(_common.HttpStatus.FORBIDDEN).send('Lock token does not match owner'); } await this.filesLockManager.refreshLockTimeout(lock, req.dav.lock.timeout); const lockProp = (0, _webdav1.LOCK_PROP)([ lock ]); return res.type(_webdav.XML_CONTENT_TYPE).status(_common.HttpStatus.OK).send((0, _xml.xmlBuild)(lockProp)); } handleError(req, res, e, toUrl) { this.logger.error(`Unable to ${req.method} ${req.dav.url}${toUrl ? ` -> ${toUrl}` : ''} : ${e.message}`); // Remove the last part to avoid exposing the path const errorMsg = e.message.split(',')[0]; if (e instanceof _filelockerror.LockConflict) { return (0, _webdav1.DAV_ERROR_RES)(_common.HttpStatus.LOCKED, _webdav.PRECONDITION.LOCK_CONFLICT, res, e.lock.options?.lockRoot || e.lock.dbFilePath); } else if (e instanceof _fileerror.FileError) { return res.status(e.httpCode).send(errorMsg); } throw new _common.HttpException(errorMsg, _common.HttpStatus.INTERNAL_SERVER_ERROR); } constructor(webDAVHandler, filesManager, filesLockManager){ this.webDAVHandler = webDAVHandler; this.filesManager = filesManager; this.filesLockManager = filesLockManager; this.logger = new _common.Logger(WebDAVMethods.name); } }; _ts_decorate([ (0, _ifheaderdecorator.IfHeaderDecorator)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ typeof _webdavinterface.FastifyDAVRequest === "undefined" ? Object : _webdavinterface.FastifyDAVRequest, typeof _fastify.FastifyReply === "undefined" ? Object : _fastify.FastifyReply ]), _ts_metadata("design:returntype", Promise) ], WebDAVMethods.prototype, "lock", null); _ts_decorate([ (0, _ifheaderdecorator.IfHeaderDecorator)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ typeof _webdavinterface.FastifyDAVRequest === "undefined" ? Object : _webdavinterface.FastifyDAVRequest, typeof _fastify.FastifyReply === "undefined" ? Object : _fastify.FastifyReply ]), _ts_metadata("design:returntype", Promise) ], WebDAVMethods.prototype, "unlock", null); _ts_decorate([ (0, _ifheaderdecorator.IfHeaderDecorator)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ typeof _webdavinterface.FastifyDAVRequest === "undefined" ? Object : _webdavinterface.FastifyDAVRequest, typeof _fastify.FastifyReply === "undefined" ? Object : _fastify.FastifyReply, String ]), _ts_metadata("design:returntype", Promise) ], WebDAVMethods.prototype, "propfind", null); _ts_decorate([ (0, _ifheaderdecorator.IfHeaderDecorator)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ typeof _webdavinterface.FastifyDAVRequest === "undefined" ? Object : _webdavinterface.FastifyDAVRequest, typeof _fastify.FastifyReply === "undefined" ? Object : _fastify.FastifyReply ]), _ts_metadata("design:returntype", Promise) ], WebDAVMethods.prototype, "put", null); _ts_decorate([ (0, _ifheaderdecorator.IfHeaderDecorator)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ typeof _webdavinterface.FastifyDAVRequest === "undefined" ? Object : _webdavinterface.FastifyDAVRequest, typeof _fastify.FastifyReply === "undefined" ? Object : _fastify.FastifyReply ]), _ts_metadata("design:returntype", Promise) ], WebDAVMethods.prototype, "delete", null); _ts_decorate([ (0, _ifheaderdecorator.IfHeaderDecorator)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ typeof _webdavinterface.FastifyDAVRequest === "undefined" ? Object : _webdavinterface.FastifyDAVRequest, typeof _fastify.FastifyReply === "undefined" ? Object : _fastify.FastifyReply ]), _ts_metadata("design:returntype", Promise) ], WebDAVMethods.prototype, "proppatch", null); _ts_decorate([ (0, _ifheaderdecorator.IfHeaderDecorator)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ typeof _webdavinterface.FastifyDAVRequest === "undefined" ? Object : _webdavinterface.FastifyDAVRequest, typeof _fastify.FastifyReply === "undefined" ? Object : _fastify.FastifyReply ]), _ts_metadata("design:returntype", Promise) ], WebDAVMethods.prototype, "mkcol", null); _ts_decorate([ (0, _ifheaderdecorator.IfHeaderDecorator)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ typeof _webdavinterface.FastifyDAVRequest === "undefined" ? Object : _webdavinterface.FastifyDAVRequest, typeof _fastify.FastifyReply === "undefined" ? Object : _fastify.FastifyReply ]), _ts_metadata("design:returntype", Promise) ], WebDAVMethods.prototype, "copyMove", null); WebDAVMethods = _ts_decorate([ (0, _common.Injectable)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ typeof _webdavspacesservice.WebDAVSpaces === "undefined" ? Object : _webdavspacesservice.WebDAVSpaces, typeof _filesmanagerservice.FilesManager === "undefined" ? Object : _filesmanagerservice.FilesManager, typeof _fileslockmanagerservice.FilesLockManager === "undefined" ? Object : _fileslockmanagerservice.FilesLockManager ]) ], WebDAVMethods); //# sourceMappingURL=webdav-methods.service.js.map