diff --git a/lib/server/MethodCallArgs.d.ts b/lib/server/MethodCallArgs.d.ts index d27fba83..a1b84555 100644 --- a/lib/server/MethodCallArgs.d.ts +++ b/lib/server/MethodCallArgs.d.ts @@ -23,6 +23,8 @@ export declare class MethodCallArgs { static create(server: WebDAVServer, request: http.IncomingMessage, response: http.ServerResponse, callback: (error: Error, mca: MethodCallArgs) => void): void; requireCustomPrivilege(privileges: string | string[], resource: IResource, callback: () => void): void; requirePrivilege(privileges: BasicPrivilege | BasicPrivilege[], resource: IResource, callback: () => void): void; + requireErCustomPrivilege(privileges: string | string[], resource: IResource, callback: (error: Error, can: boolean) => void): void; + requireErPrivilege(privileges: BasicPrivilege | BasicPrivilege[], resource: IResource, callback: (error: Error, can: boolean) => void): void; askForAuthentication(checkForUser: boolean, callback: (error: Error) => void): void; accept(regex: RegExp[]): number; findHeader(name: string, defaultValue?: string): string; diff --git a/lib/server/MethodCallArgs.js b/lib/server/MethodCallArgs.js index d8fafe95..5500d2cc 100644 --- a/lib/server/MethodCallArgs.js +++ b/lib/server/MethodCallArgs.js @@ -56,6 +56,12 @@ var MethodCallArgs = (function () { MethodCallArgs.prototype.requirePrivilege = function (privileges, resource, callback) { this.requireCustomPrivilege(privileges, resource, callback); }; + MethodCallArgs.prototype.requireErCustomPrivilege = function (privileges, resource, callback) { + IPrivilegeManager_1.requirePrivilege(privileges, this, resource, callback); + }; + MethodCallArgs.prototype.requireErPrivilege = function (privileges, resource, callback) { + this.requireErCustomPrivilege(privileges, resource, callback); + }; MethodCallArgs.prototype.askForAuthentication = function (checkForUser, callback) { if (checkForUser && this.user !== null && !this.user.isDefaultUser) { callback(new Error('Already authenticated')); diff --git a/lib/server/commands/Head.js b/lib/server/commands/Head.js index a629f2dc..10985f80 100644 --- a/lib/server/commands/Head.js +++ b/lib/server/commands/Head.js @@ -8,12 +8,14 @@ function default_1(arg, callback) { callback(); return; } - r.read(function (e, c) { - if (e) - arg.setCode(WebDAVRequest_1.HTTPCodes.MethodNotAllowed); - else - arg.setCode(WebDAVRequest_1.HTTPCodes.OK); - callback(); + arg.requirePrivilege(['canRead'], r, function () { + r.read(function (e, c) { + if (e) + arg.setCode(WebDAVRequest_1.HTTPCodes.MethodNotAllowed); + else + arg.setCode(WebDAVRequest_1.HTTPCodes.OK); + callback(); + }); }); }); } diff --git a/lib/server/commands/Lock.js b/lib/server/commands/Lock.js index 5eb2ce91..f5e3ebab 100644 --- a/lib/server/commands/Lock.js +++ b/lib/server/commands/Lock.js @@ -26,27 +26,29 @@ function default_1(arg, callback) { callback(); return; } - r.setLock(lock_1, function (e) { - if (e) { - arg.setCode(WebDAVRequest_1.HTTPCodes.Locked); + arg.requirePrivilege(['canSetLock'], r, function () { + r.setLock(lock_1, function (e) { + if (e) { + arg.setCode(WebDAVRequest_1.HTTPCodes.Locked); + callback(); + return; + } + var prop = XML_1.XML.createElement('D:prop', { + 'xmlns:D': 'DAV:' + }); + var activelock = prop.ele('D:lockdiscovery').ele('D:activelock'); + activelock.ele('D:locktype').ele(type_1.value); + activelock.ele('D:lockscope').ele(type_1.value); + activelock.ele('D:locktoken').ele('D:href').add(lock_1.uuid); + activelock.ele('D:lockroot').add(arg.fullUri()); + activelock.ele('D:depth').add('infinity'); + activelock.ele('D:owner').add(owner_1); + activelock.ele('D:timeout').add('Second-' + lock_1.lockKind.timeout); + arg.response.setHeader('Lock-Token', lock_1.uuid); + arg.setCode(WebDAVRequest_1.HTTPCodes.OK); + arg.writeXML(prop); callback(); - return; - } - var prop = XML_1.XML.createElement('D:prop', { - 'xmlns:D': 'DAV:' }); - var activelock = prop.ele('D:lockdiscovery').ele('D:activelock'); - activelock.ele('D:locktype').ele(type_1.value); - activelock.ele('D:lockscope').ele(type_1.value); - activelock.ele('D:locktoken').ele('D:href').add(lock_1.uuid); - activelock.ele('D:lockroot').add(arg.fullUri()); - activelock.ele('D:depth').add('infinity'); - activelock.ele('D:owner').add(owner_1); - activelock.ele('D:timeout').add('Second-' + lock_1.lockKind.timeout); - arg.response.setHeader('Lock-Token', lock_1.uuid); - arg.setCode(WebDAVRequest_1.HTTPCodes.OK); - arg.writeXML(prop); - callback(); }); }); } diff --git a/lib/server/commands/Mkcol.js b/lib/server/commands/Mkcol.js index 68266cda..11ad798d 100644 --- a/lib/server/commands/Mkcol.js +++ b/lib/server/commands/Mkcol.js @@ -10,24 +10,28 @@ function default_1(arg, callback) { callback(); return; } - if (!r.fsManager) { - arg.setCode(WebDAVRequest_1.HTTPCodes.InternalServerError); - callback(); - return; - } - var resource = r.fsManager.newResource(arg.uri, path.basename(arg.uri), IResource_1.ResourceType.Directory, r); - resource.create(function (e) { - if (e) { + arg.requirePrivilege(['canAddChild'], r, function () { + if (!r.fsManager) { arg.setCode(WebDAVRequest_1.HTTPCodes.InternalServerError); callback(); return; } - r.addChild(resource, function (e) { - if (e) - arg.setCode(WebDAVRequest_1.HTTPCodes.InternalServerError); - else - arg.setCode(WebDAVRequest_1.HTTPCodes.Created); - callback(); + var resource = r.fsManager.newResource(arg.uri, path.basename(arg.uri), IResource_1.ResourceType.Directory, r); + arg.requirePrivilege(['canCreate'], resource, function () { + resource.create(function (e) { + if (e) { + arg.setCode(WebDAVRequest_1.HTTPCodes.InternalServerError); + callback(); + return; + } + r.addChild(resource, function (e) { + if (e) + arg.setCode(WebDAVRequest_1.HTTPCodes.InternalServerError); + else + arg.setCode(WebDAVRequest_1.HTTPCodes.Created); + callback(); + }); + }); }); }); }); diff --git a/lib/server/commands/Move.js b/lib/server/commands/Move.js index 27a27a7a..b1c261c6 100644 --- a/lib/server/commands/Move.js +++ b/lib/server/commands/Move.js @@ -9,23 +9,27 @@ function default_1(arg, callback) { callback(); return; } - var override = arg.findHeader('overwrite') === 'T'; - var destination = arg.findHeader('destination'); - if (!destination) { - arg.setCode(WebDAVRequest_1.HTTPCodes.BadRequest); - callback(); - return; - } - destination = destination.substring(destination.indexOf('://') + '://'.length); - destination = destination.substring(destination.indexOf('/')); - destination = new FSManager_1.FSPath(destination); - arg.server.getResourceFromPath(destination.getParent(), function (e, rDest) { - r.moveTo(rDest, destination.fileName(), override, function (e) { - if (e) - arg.setCode(WebDAVRequest_1.HTTPCodes.InternalServerError); - else - arg.setCode(WebDAVRequest_1.HTTPCodes.Created); + arg.requirePrivilege(['canMove'], r, function () { + var override = arg.findHeader('overwrite') === 'T'; + var destination = arg.findHeader('destination'); + if (!destination) { + arg.setCode(WebDAVRequest_1.HTTPCodes.BadRequest); callback(); + return; + } + destination = destination.substring(destination.indexOf('://') + '://'.length); + destination = destination.substring(destination.indexOf('/')); + destination = new FSManager_1.FSPath(destination); + arg.server.getResourceFromPath(destination.getParent(), function (e, rDest) { + arg.requirePrivilege(['canAddChild'], rDest, function () { + r.moveTo(rDest, destination.fileName(), override, function (e) { + if (e) + arg.setCode(WebDAVRequest_1.HTTPCodes.InternalServerError); + else + arg.setCode(WebDAVRequest_1.HTTPCodes.Created); + callback(); + }); + }); }); }); }); diff --git a/lib/server/commands/Propfind.js b/lib/server/commands/Propfind.js index e30aaf0d..334980cd 100644 --- a/lib/server/commands/Propfind.js +++ b/lib/server/commands/Propfind.js @@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); var WebDAVRequest_1 = require("../WebDAVRequest"); var IResource_1 = require("../../resource/IResource"); var XML_1 = require("../../helper/XML"); +var http = require("http"); function default_1(arg, callback) { arg.getResource(function (e, resource) { if (e || !resource) { @@ -40,89 +41,101 @@ function default_1(arg, callback) { function addXMLInfo(resource, multistatus, callback) { var response = multistatus.ele('D:response'); var propstat = response.ele('D:propstat'); - propstat.ele('D:status').add('HTTP/1.1 200 OK'); - var prop = propstat.ele('D:prop'); - var nb = 7; - function nbOut(error) { - if (nb > 0 && error) { - nb = -1; - callback(error); + arg.requireErPrivilege(['canMove'], resource, function (e, can) { + if (e) { + propstat.ele('D:status').add('HTTP/1.1 ' + WebDAVRequest_1.HTTPCodes.InternalServerError + ' ' + http.STATUS_CODES[WebDAVRequest_1.HTTPCodes.InternalServerError]); + callback(); return; } - --nb; - if (nb === 0) + if (!can) { + propstat.ele('D:status').add('HTTP/1.1 ' + WebDAVRequest_1.HTTPCodes.Unauthorized + ' ' + http.STATUS_CODES[WebDAVRequest_1.HTTPCodes.Unauthorized]); callback(); - } - resource.creationDate(function (e, ticks) { - if (!e) - prop.ele('D:creationdate').add(arg.dateISO8601(ticks)); - nbOut(e); - }); - arg.getResourcePath(resource, function (e, path) { - if (!e) - response.ele('D:href').add(arg.fullUri(path).replace(' ', '%20')); - nbOut(e); - }); - resource.webName(function (e, name) { - if (!e) - prop.ele('D:displayname').add(name ? name : ''); - nbOut(e); - }); - var supportedlock = prop.ele('D:supportedlock'); - resource.getAvailableLocks(function (e, lockKinds) { - if (e) { - nbOut(e); return; } - lockKinds.forEach(function (lockKind) { - var lockentry = supportedlock.ele('D:lockentry'); - var lockscope = lockentry.ele('D:lockscope'); - lockscope.ele('D:' + lockKind.scope.value.toLowerCase()); - var locktype = lockentry.ele('D:locktype'); - locktype.ele('D:' + lockKind.type.value.toLowerCase()); + propstat.ele('D:status').add('HTTP/1.1 200 OK'); + var prop = propstat.ele('D:prop'); + var nb = 7; + function nbOut(error) { + if (nb > 0 && error) { + nb = -1; + callback(error); + return; + } + --nb; + if (nb === 0) + callback(); + } + resource.creationDate(function (e, ticks) { + if (!e) + prop.ele('D:creationdate').add(arg.dateISO8601(ticks)); + nbOut(e); }); - nbOut(); - }); - resource.getProperties(function (e, properties) { - if (e) { + arg.getResourcePath(resource, function (e, path) { + if (!e) + response.ele('D:href').add(arg.fullUri(path).replace(' ', '%20')); nbOut(e); - return; - } - for (var name_1 in properties) { - var value = properties[name_1]; - prop.ele(name_1).add(value); - } - nbOut(); - }); - resource.type(function (e, type) { - if (e) { + }); + resource.webName(function (e, name) { + if (!e) + prop.ele('D:displayname').add(name ? name : ''); nbOut(e); - return; - } - var resourcetype = prop.ele('D:resourcetype'); - if (type.isDirectory) - resourcetype.ele('D:collection'); - if (type.isFile) { - nb += 2; - resource.mimeType(function (e, mimeType) { - if (!e) - prop.ele('D:getcontenttype').add(mimeType); + }); + var supportedlock = prop.ele('D:supportedlock'); + resource.getAvailableLocks(function (e, lockKinds) { + if (e) { nbOut(e); + return; + } + lockKinds.forEach(function (lockKind) { + var lockentry = supportedlock.ele('D:lockentry'); + var lockscope = lockentry.ele('D:lockscope'); + lockscope.ele('D:' + lockKind.scope.value.toLowerCase()); + var locktype = lockentry.ele('D:locktype'); + locktype.ele('D:' + lockKind.type.value.toLowerCase()); }); - resource.size(function (e, size) { - if (!e) - prop.ele('D:getcontentlength').add(size); + nbOut(); + }); + resource.getProperties(function (e, properties) { + if (e) { nbOut(e); - }); - } - nbOut(); - }); - resource.lastModifiedDate(function (e, lastModifiedDate) { - if (!e) { - prop.ele('D:getetag').add(IResource_1.ETag.createETag(lastModifiedDate)); - prop.ele('D:getlastmodified').add(new Date(lastModifiedDate).toUTCString()); - } - nbOut(e); + return; + } + for (var name_1 in properties) { + var value = properties[name_1]; + prop.ele(name_1).add(value); + } + nbOut(); + }); + resource.type(function (e, type) { + if (e) { + nbOut(e); + return; + } + var resourcetype = prop.ele('D:resourcetype'); + if (type.isDirectory) + resourcetype.ele('D:collection'); + if (type.isFile) { + nb += 2; + resource.mimeType(function (e, mimeType) { + if (!e) + prop.ele('D:getcontenttype').add(mimeType); + nbOut(e); + }); + resource.size(function (e, size) { + if (!e) + prop.ele('D:getcontentlength').add(size); + nbOut(e); + }); + } + nbOut(); + }); + resource.lastModifiedDate(function (e, lastModifiedDate) { + if (!e) { + prop.ele('D:getetag').add(IResource_1.ETag.createETag(lastModifiedDate)); + prop.ele('D:getlastmodified').add(new Date(lastModifiedDate).toUTCString()); + } + nbOut(e); + }); }); } function done(multistatus) { diff --git a/lib/server/commands/Proppatch.js b/lib/server/commands/Proppatch.js index 0f5f8018..300bb248 100644 --- a/lib/server/commands/Proppatch.js +++ b/lib/server/commands/Proppatch.js @@ -10,55 +10,57 @@ function default_1(arg, callback) { callback(); return; } - var multistatus = XML_1.XML.createElement('D:multistatus', { - 'xmlns:D': 'DAV:' - }); - var response = multistatus.ele('D:response'); - response.ele('D:href').add(arg.fullUri()); - var xml = XML_1.XML.parse(arg.data); - var root = xml.find('DAV:propertyupdate'); - var finalize = function () { - finalize = function () { - arg.setCode(WebDAVRequest_1.HTTPCodes.MultiStatus); - arg.writeXML(multistatus); - callback(); + arg.requirePrivilege(['canSetProperty', 'canRemoveProperty'], r, function () { + var multistatus = XML_1.XML.createElement('D:multistatus', { + 'xmlns:D': 'DAV:' + }); + var response = multistatus.ele('D:response'); + response.ele('D:href').add(arg.fullUri()); + var xml = XML_1.XML.parse(arg.data); + var root = xml.find('DAV:propertyupdate'); + var finalize = function () { + finalize = function () { + arg.setCode(WebDAVRequest_1.HTTPCodes.MultiStatus); + arg.writeXML(multistatus); + callback(); + }; }; - }; - function notify(el, error) { - var code = error ? WebDAVRequest_1.HTTPCodes.Conflict : WebDAVRequest_1.HTTPCodes.OK; - var propstat = response.ele('D:propstat'); - propstat.ele('D:prop').ele(el.name); - propstat.ele('D:status').add('HTTP/1.1 ' + code + ' ' + http_1.STATUS_CODES[code]); - } - execute('DAV:set', function (el, callback) { - r.setProperty(el.name, el.elements, callback); - }); - execute('DAV:remove', function (el, callback) { - r.removeProperty(el.name, callback); - }); - function execute(name, fnProp) { - var list = root.findMany(name); - if (list.length === 0) { - finalize(); - return; + function notify(el, error) { + var code = error ? WebDAVRequest_1.HTTPCodes.Conflict : WebDAVRequest_1.HTTPCodes.OK; + var propstat = response.ele('D:propstat'); + propstat.ele('D:prop').ele(el.name); + propstat.ele('D:status').add('HTTP/1.1 ' + code + ' ' + http_1.STATUS_CODES[code]); } - list.forEach(function (el) { - var els = el.find('DAV:prop').elements; - if (els.length === 0) { + execute('DAV:set', function (el, callback) { + r.setProperty(el.name, el.elements, callback); + }); + execute('DAV:remove', function (el, callback) { + r.removeProperty(el.name, callback); + }); + function execute(name, fnProp) { + var list = root.findMany(name); + if (list.length === 0) { finalize(); return; } - var nb = els.length; - els.forEach(function (el) { - fnProp(el, function (e) { - notify(el, e); - --nb; - if (nb === 0) - finalize(); + list.forEach(function (el) { + var els = el.find('DAV:prop').elements; + if (els.length === 0) { + finalize(); + return; + } + var nb = els.length; + els.forEach(function (el) { + fnProp(el, function (e) { + notify(el, e); + --nb; + if (nb === 0) + finalize(); + }); }); }); - }); - } + } + }); }); } exports.default = default_1; diff --git a/lib/server/commands/Unlock.js b/lib/server/commands/Unlock.js index 8aebaf6f..81b08cb7 100644 --- a/lib/server/commands/Unlock.js +++ b/lib/server/commands/Unlock.js @@ -21,23 +21,25 @@ function default_1(arg, callback) { callback(); return; } - r.getLock(token, function (e, lock) { - if (e || !lock) { - arg.setCode(WebDAVRequest_1.HTTPCodes.BadRequest); - callback(); - return; - } - if (lock.user !== arg.user) { - arg.setCode(WebDAVRequest_1.HTTPCodes.Forbidden); - callback(); - return; - } - r.removeLock(lock.uuid, function (e, done) { - if (e || !done) + arg.requirePrivilege(['canGetLock', 'canRemoveLock'], r, function () { + r.getLock(token, function (e, lock) { + if (e || !lock) { + arg.setCode(WebDAVRequest_1.HTTPCodes.BadRequest); + callback(); + return; + } + if (lock.user !== arg.user) { arg.setCode(WebDAVRequest_1.HTTPCodes.Forbidden); - else - arg.setCode(WebDAVRequest_1.HTTPCodes.NoContent); - callback(); + callback(); + return; + } + r.removeLock(lock.uuid, function (e, done) { + if (e || !done) + arg.setCode(WebDAVRequest_1.HTTPCodes.Forbidden); + else + arg.setCode(WebDAVRequest_1.HTTPCodes.NoContent); + callback(); + }); }); }); }); diff --git a/src/server/MethodCallArgs.ts b/src/server/MethodCallArgs.ts index 3e28d221..9671c67b 100644 --- a/src/server/MethodCallArgs.ts +++ b/src/server/MethodCallArgs.ts @@ -88,6 +88,15 @@ export class MethodCallArgs this.requireCustomPrivilege(privileges, resource, callback); } + requireErCustomPrivilege(privileges : string | string[], resource : IResource, callback : (error : Error, can : boolean) => void) + { + requirePrivilege(privileges, this, resource, callback); + } + requireErPrivilege(privileges : BasicPrivilege | BasicPrivilege[], resource : IResource, callback : (error : Error, can : boolean) => void) + { + this.requireErCustomPrivilege(privileges, resource, callback); + } + askForAuthentication(checkForUser : boolean, callback : (error : Error) => void) { if(checkForUser && this.user !== null && !this.user.isDefaultUser) diff --git a/src/server/commands/Head.ts b/src/server/commands/Head.ts index 55fa5072..b1582524 100644 --- a/src/server/commands/Head.ts +++ b/src/server/commands/Head.ts @@ -11,12 +11,14 @@ export default function(arg : MethodCallArgs, callback) return; } - r.read((e, c) => { - if(e) - arg.setCode(HTTPCodes.MethodNotAllowed) - else - arg.setCode(HTTPCodes.OK); - callback(); + arg.requirePrivilege([ 'canRead' ], r, () => { + r.read((e, c) => { + if(e) + arg.setCode(HTTPCodes.MethodNotAllowed) + else + arg.setCode(HTTPCodes.OK); + callback(); + }) }) }) } diff --git a/src/server/commands/Lock.ts b/src/server/commands/Lock.ts index 9cdc8e52..0a574cb4 100644 --- a/src/server/commands/Lock.ts +++ b/src/server/commands/Lock.ts @@ -36,31 +36,33 @@ export default function(arg : MethodCallArgs, callback) return; } - r.setLock(lock, (e) => { - if(e) - { - arg.setCode(HTTPCodes.Locked); - callback(); - return; - } - - const prop = XML.createElement('D:prop', { - 'xmlns:D': 'DAV:' - }); - const activelock = prop.ele('D:lockdiscovery').ele('D:activelock'); + arg.requirePrivilege([ 'canSetLock' ], r, () => { + r.setLock(lock, (e) => { + if(e) + { + arg.setCode(HTTPCodes.Locked); + callback(); + return; + } + + const prop = XML.createElement('D:prop', { + 'xmlns:D': 'DAV:' + }); + const activelock = prop.ele('D:lockdiscovery').ele('D:activelock'); - activelock.ele('D:locktype').ele(type.value); - activelock.ele('D:lockscope').ele(type.value); - activelock.ele('D:locktoken').ele('D:href').add(lock.uuid); - activelock.ele('D:lockroot').add(arg.fullUri()); - activelock.ele('D:depth').add('infinity'); - activelock.ele('D:owner').add(owner); - activelock.ele('D:timeout').add('Second-' + lock.lockKind.timeout); + activelock.ele('D:locktype').ele(type.value); + activelock.ele('D:lockscope').ele(type.value); + activelock.ele('D:locktoken').ele('D:href').add(lock.uuid); + activelock.ele('D:lockroot').add(arg.fullUri()); + activelock.ele('D:depth').add('infinity'); + activelock.ele('D:owner').add(owner); + activelock.ele('D:timeout').add('Second-' + lock.lockKind.timeout); - arg.response.setHeader('Lock-Token', lock.uuid); - arg.setCode(HTTPCodes.OK); - arg.writeXML(prop); - callback(); + arg.response.setHeader('Lock-Token', lock.uuid); + arg.setCode(HTTPCodes.OK); + arg.writeXML(prop); + callback(); + }) }) }) } diff --git a/src/server/commands/Mkcol.ts b/src/server/commands/Mkcol.ts index 5faac573..3eebd667 100644 --- a/src/server/commands/Mkcol.ts +++ b/src/server/commands/Mkcol.ts @@ -12,29 +12,33 @@ export default function(arg : MethodCallArgs, callback) callback(); return; } - - if(!r.fsManager) - { - arg.setCode(HTTPCodes.InternalServerError) - callback(); - return; - } - const resource = r.fsManager.newResource(arg.uri, path.basename(arg.uri), ResourceType.Directory, r); - resource.create((e) => { - if(e) + arg.requirePrivilege([ 'canAddChild' ], r, () => { + if(!r.fsManager) { arg.setCode(HTTPCodes.InternalServerError) callback(); return; } - - r.addChild(resource, (e) => { - if(e) - arg.setCode(HTTPCodes.InternalServerError) - else - arg.setCode(HTTPCodes.Created) - callback(); + + const resource = r.fsManager.newResource(arg.uri, path.basename(arg.uri), ResourceType.Directory, r); + arg.requirePrivilege([ 'canCreate' ], resource, () => { + resource.create((e) => { + if(e) + { + arg.setCode(HTTPCodes.InternalServerError) + callback(); + return; + } + + r.addChild(resource, (e) => { + if(e) + arg.setCode(HTTPCodes.InternalServerError) + else + arg.setCode(HTTPCodes.Created) + callback(); + }) + }) }) }) }) diff --git a/src/server/commands/Move.ts b/src/server/commands/Move.ts index c17b3922..163c2e32 100644 --- a/src/server/commands/Move.ts +++ b/src/server/commands/Move.ts @@ -12,27 +12,31 @@ export default function(arg : MethodCallArgs, callback) return; } - const override = arg.findHeader('overwrite') === 'T'; + arg.requirePrivilege([ 'canMove' ], r, () => { + const override = arg.findHeader('overwrite') === 'T'; - let destination : any = arg.findHeader('destination'); - if(!destination) - { - arg.setCode(HTTPCodes.BadRequest); - callback(); - return; - } - - destination = destination.substring(destination.indexOf('://') + '://'.length) - destination = destination.substring(destination.indexOf('/')) - destination = new FSPath(destination) + let destination : any = arg.findHeader('destination'); + if(!destination) + { + arg.setCode(HTTPCodes.BadRequest); + callback(); + return; + } + + destination = destination.substring(destination.indexOf('://') + '://'.length) + destination = destination.substring(destination.indexOf('/')) + destination = new FSPath(destination) - arg.server.getResourceFromPath(destination.getParent(), (e, rDest) => { - r.moveTo(rDest, destination.fileName(), override, (e) => { - if(e) - arg.setCode(HTTPCodes.InternalServerError) - else - arg.setCode(HTTPCodes.Created) - callback() + arg.server.getResourceFromPath(destination.getParent(), (e, rDest) => { + arg.requirePrivilege([ 'canAddChild' ], rDest, () => { + r.moveTo(rDest, destination.fileName(), override, (e) => { + if(e) + arg.setCode(HTTPCodes.InternalServerError) + else + arg.setCode(HTTPCodes.Created) + callback() + }) + }) }) }) }) diff --git a/src/server/commands/Propfind.ts b/src/server/commands/Propfind.ts index fd3befc3..a411ad4e 100644 --- a/src/server/commands/Propfind.ts +++ b/src/server/commands/Propfind.ts @@ -1,6 +1,7 @@ import { HTTPCodes, MethodCallArgs, WebDAVRequest } from '../WebDAVRequest' import { IResource, ETag } from '../../resource/IResource' import { XML } from '../../helper/XML' +import * as http from 'http' export default function(arg : MethodCallArgs, callback) { @@ -55,113 +56,129 @@ export default function(arg : MethodCallArgs, callback) const propstat = response.ele('D:propstat') - propstat.ele('D:status').add('HTTP/1.1 200 OK') - - const prop = propstat.ele('D:prop') - - let nb = 7; - function nbOut(error?) - { - if(nb > 0 && error) + arg.requireErPrivilege([ 'canMove' ], resource, (e, can) => { + if(e) { - nb = -1; - callback(error); + propstat.ele('D:status').add('HTTP/1.1 ' + HTTPCodes.InternalServerError + ' ' + http.STATUS_CODES[HTTPCodes.InternalServerError]); + callback(); return; } - --nb; - if(nb === 0) - callback(); - } - - resource.creationDate((e, ticks) => { - if(!e) - prop.ele('D:creationdate').add(arg.dateISO8601(ticks)); - nbOut(e); - }) - - arg.getResourcePath(resource, (e, path) => { - if(!e) - response.ele('D:href').add(arg.fullUri(path).replace(' ', '%20')); - nbOut(e); - }) - - resource.webName((e, name) => { - if(!e) - prop.ele('D:displayname').add(name ? name : ''); - nbOut(e); - }) - - const supportedlock = prop.ele('D:supportedlock') - resource.getAvailableLocks((e, lockKinds) => { - if(e) + + if(!can) { - nbOut(e); + propstat.ele('D:status').add('HTTP/1.1 ' + HTTPCodes.Unauthorized + ' ' + http.STATUS_CODES[HTTPCodes.Unauthorized]); + callback(); return; } - lockKinds.forEach((lockKind) => { - const lockentry = supportedlock.ele('D:lockentry') + propstat.ele('D:status').add('HTTP/1.1 200 OK') - const lockscope = lockentry.ele('D:lockscope') - lockscope.ele('D:' + lockKind.scope.value.toLowerCase()) + const prop = propstat.ele('D:prop') + + let nb = 7; + function nbOut(error?) + { + if(nb > 0 && error) + { + nb = -1; + callback(error); + return; + } + --nb; + if(nb === 0) + callback(); + } - const locktype = lockentry.ele('D:locktype') - locktype.ele('D:' + lockKind.type.value.toLowerCase()) + resource.creationDate((e, ticks) => { + if(!e) + prop.ele('D:creationdate').add(arg.dateISO8601(ticks)); + nbOut(e); }) - nbOut(); - }) - resource.getProperties((e, properties) => { - if(e) - { + arg.getResourcePath(resource, (e, path) => { + if(!e) + response.ele('D:href').add(arg.fullUri(path).replace(' ', '%20')); nbOut(e); - return; - } - - for(const name in properties) - { - const value = properties[name]; - prop.ele(name).add(value) - } - nbOut(); - }) + }) - resource.type((e, type) => { - if(e) - { + resource.webName((e, name) => { + if(!e) + prop.ele('D:displayname').add(name ? name : ''); nbOut(e); - return; - } + }) - const resourcetype = prop.ele('D:resourcetype') - if(type.isDirectory) - resourcetype.ele('D:collection') - - if(type.isFile) - { - nb += 2; - resource.mimeType((e, mimeType) => { - if(!e) - prop.ele('D:getcontenttype').add(mimeType) + const supportedlock = prop.ele('D:supportedlock') + resource.getAvailableLocks((e, lockKinds) => { + if(e) + { nbOut(e); + return; + } + + lockKinds.forEach((lockKind) => { + const lockentry = supportedlock.ele('D:lockentry') + + const lockscope = lockentry.ele('D:lockscope') + lockscope.ele('D:' + lockKind.scope.value.toLowerCase()) + + const locktype = lockentry.ele('D:locktype') + locktype.ele('D:' + lockKind.type.value.toLowerCase()) }) - resource.size((e, size) => { - if(!e) - prop.ele('D:getcontentlength').add(size) + nbOut(); + }) + + resource.getProperties((e, properties) => { + if(e) + { nbOut(e); - }) - } + return; + } - nbOut(); - }) + for(const name in properties) + { + const value = properties[name]; + prop.ele(name).add(value) + } + nbOut(); + }) - resource.lastModifiedDate((e, lastModifiedDate) => { - if(!e) - { - prop.ele('D:getetag').add(ETag.createETag(lastModifiedDate)) - prop.ele('D:getlastmodified').add(new Date(lastModifiedDate).toUTCString()) - } - nbOut(e); + resource.type((e, type) => { + if(e) + { + nbOut(e); + return; + } + + const resourcetype = prop.ele('D:resourcetype') + if(type.isDirectory) + resourcetype.ele('D:collection') + + if(type.isFile) + { + nb += 2; + resource.mimeType((e, mimeType) => { + if(!e) + prop.ele('D:getcontenttype').add(mimeType) + nbOut(e); + }) + resource.size((e, size) => { + if(!e) + prop.ele('D:getcontentlength').add(size) + nbOut(e); + }) + } + + nbOut(); + }) + + resource.lastModifiedDate((e, lastModifiedDate) => { + if(!e) + { + prop.ele('D:getetag').add(ETag.createETag(lastModifiedDate)) + prop.ele('D:getlastmodified').add(new Date(lastModifiedDate).toUTCString()) + } + nbOut(e); + }) }) } diff --git a/src/server/commands/Proppatch.ts b/src/server/commands/Proppatch.ts index f52593fe..004295b4 100644 --- a/src/server/commands/Proppatch.ts +++ b/src/server/commands/Proppatch.ts @@ -12,68 +12,70 @@ export default function(arg : MethodCallArgs, callback) callback(); return; } + + arg.requirePrivilege([ 'canSetProperty', 'canRemoveProperty' ], r, () => { + const multistatus = XML.createElement('D:multistatus', { + 'xmlns:D': 'DAV:' + }); + const response = multistatus.ele('D:response'); + response.ele('D:href').add(arg.fullUri()); - const multistatus = XML.createElement('D:multistatus', { - 'xmlns:D': 'DAV:' - }); - const response = multistatus.ele('D:response'); - response.ele('D:href').add(arg.fullUri()); + const xml = XML.parse(arg.data); + const root = xml.find('DAV:propertyupdate'); - const xml = XML.parse(arg.data); - const root = xml.find('DAV:propertyupdate'); - - let finalize = function() - { - finalize = function() + let finalize = function() { - arg.setCode(HTTPCodes.MultiStatus); - arg.writeXML(multistatus); - callback(); + finalize = function() + { + arg.setCode(HTTPCodes.MultiStatus); + arg.writeXML(multistatus); + callback(); + } } - } - - function notify(el : any, error : any) - { - const code = error ? HTTPCodes.Conflict : HTTPCodes.OK; - const propstat = response.ele('D:propstat'); - propstat.ele('D:prop').ele(el.name); - propstat.ele('D:status').add('HTTP/1.1 ' + code + ' ' + STATUS_CODES[code]); - } - - execute('DAV:set', (el, callback) => { - r.setProperty(el.name, el.elements, callback) - }) - execute('DAV:remove', (el, callback) => { - r.removeProperty(el.name, callback) - }) - function execute(name, fnProp) - { - const list = root.findMany(name); - if(list.length === 0) + function notify(el : any, error : any) { - finalize(); - return; + const code = error ? HTTPCodes.Conflict : HTTPCodes.OK; + const propstat = response.ele('D:propstat'); + propstat.ele('D:prop').ele(el.name); + propstat.ele('D:status').add('HTTP/1.1 ' + code + ' ' + STATUS_CODES[code]); } - list.forEach(function(el) { - const els = el.find('DAV:prop').elements; - if(els.length === 0) + execute('DAV:set', (el, callback) => { + r.setProperty(el.name, el.elements, callback) + }) + execute('DAV:remove', (el, callback) => { + r.removeProperty(el.name, callback) + }) + + function execute(name, fnProp) + { + const list = root.findMany(name); + if(list.length === 0) { finalize(); return; } - let nb = els.length; - els.forEach(function(el) { - fnProp(el, (e) => { - notify(el, e); - --nb; - if(nb === 0) - finalize(); + list.forEach(function(el) { + const els = el.find('DAV:prop').elements; + if(els.length === 0) + { + finalize(); + return; + } + + let nb = els.length; + els.forEach(function(el) { + fnProp(el, (e) => { + notify(el, e); + --nb; + if(nb === 0) + finalize(); + }) }) }) - }) - } + } + }) }) } diff --git a/src/server/commands/Unlock.ts b/src/server/commands/Unlock.ts index b21da3f9..738aac3e 100644 --- a/src/server/commands/Unlock.ts +++ b/src/server/commands/Unlock.ts @@ -34,27 +34,29 @@ export default function(arg : MethodCallArgs, callback) return; } - r.getLock(token, (e, lock) => { - if(e || !lock) - { - arg.setCode(HTTPCodes.BadRequest); - callback(); - return; - } + arg.requirePrivilege([ 'canGetLock', 'canRemoveLock' ], r, () => { + r.getLock(token, (e, lock) => { + if(e || !lock) + { + arg.setCode(HTTPCodes.BadRequest); + callback(); + return; + } - if(lock.user !== arg.user) - { - arg.setCode(HTTPCodes.Forbidden); - callback(); - return; - } - - r.removeLock(lock.uuid, (e, done) => { - if(e || !done) + if(lock.user !== arg.user) + { arg.setCode(HTTPCodes.Forbidden); - else - arg.setCode(HTTPCodes.NoContent); - callback(); + callback(); + return; + } + + r.removeLock(lock.uuid, (e, done) => { + if(e || !done) + arg.setCode(HTTPCodes.Forbidden); + else + arg.setCode(HTTPCodes.NoContent); + callback(); + }) }) }) })