1 /** 2 * Authors: Szabo Bogdan <szabobogdan@yahoo.com> 3 * Date: 2 25, 2015 4 * License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 5 * Copyright: Public Domain 6 */ 7 module vibedav.plugins.acldav; 8 9 public import vibedav.base; 10 11 import vibe.core.file; 12 import vibe.inet.mimetypes; 13 import vibe.http.server; 14 15 interface ACLDavProperties { 16 @property { 17 /// rfc5397 - 3 18 @ResourceProperty("current-user-principal", "DAV:") 19 @ResourcePropertyTagText("href", "DAV:") 20 string currentUserPrincipal(DavResource resource); 21 22 /// rfc3744 - 4.2 23 @ResourceProperty("principal-URL", "DAV:") 24 @ResourcePropertyTagText("href", "DAV:") 25 string principalURL(DavResource resource); 26 27 /// rfc3744 - 5.8 28 @ResourceProperty("principal-collection-set", "DAV:") 29 @ResourcePropertyTagText("href", "DAV:") 30 string[] principalCollectionSet(DavResource resource); 31 32 @ResourceProperty("owner", "DAV:") 33 @ResourcePropertyTagText("href", "DAV:") 34 string owner(DavResource resource); 35 } 36 } 37 38 private bool matchPluginUrl(Path path) { 39 string strPath = path.toString; 40 enum len = "principals/".length; 41 42 return strPath.length >= len && strPath[0..len] == "principals/"; 43 } 44 45 class ACLDavResourcePlugin : ACLDavProperties, IDavResourcePlugin, IDavReportSetProperties { 46 47 string currentUserPrincipal(DavResource resource) { 48 if(matchPluginUrl(resource.path)) 49 return "/" ~ resource.rootURL ~ "principals/" ~ resource.username ~ "/"; 50 51 throw new DavException(HTTPStatus.notFound, "not found"); 52 } 53 54 string principalURL(DavResource resource) { 55 if(matchPluginUrl(resource.path)) 56 return "/" ~ resource.rootURL ~ "principals/" ~ resource.username ~ "/"; 57 58 throw new DavException(HTTPStatus.notFound, "not found"); 59 } 60 61 string owner(DavResource resource) { 62 return principalURL(resource); 63 } 64 65 string[] principalCollectionSet(DavResource resource) { 66 if(matchPluginUrl(resource.path)) 67 return [ "/" ~ resource.rootURL ~ "principals/" ]; 68 69 throw new DavException(HTTPStatus.notFound, "not found"); 70 } 71 72 string[] supportedReportSet(DavResource resource) { 73 if(matchPluginUrl(resource.path)) 74 return ["expand-property:DAV:", "principal-property-search:DAV:", "principal-search-property-set:DAV:"]; 75 76 return []; 77 } 78 79 bool canSetContent(DavResource resource) { 80 return false; 81 } 82 83 bool canGetStream(DavResource resource) { 84 return false; 85 } 86 87 bool canSetProperty(DavResource resource, string name) { 88 return false; 89 } 90 91 bool canRemoveProperty(DavResource resource, string name) { 92 return false; 93 } 94 95 bool canGetProperty(DavResource resource, string name) { 96 if(!matchPluginUrl(resource.path)) 97 return false; 98 99 if(hasDavInterfaceProperty!ACLDavProperties(name)) 100 return true; 101 102 if(hasDavInterfaceProperty!IDavReportSetProperties(name)) 103 return true; 104 105 return false; 106 } 107 108 bool[string] getChildren(DavResource resource) { 109 bool[string] list; 110 return list; 111 } 112 113 void setContent(DavResource resource, const ubyte[] content) { 114 throw new DavException(HTTPStatus.internalServerError, "Can't set content."); 115 } 116 117 void setContent(DavResource resource, InputStream content, ulong size) { 118 throw new DavException(HTTPStatus.internalServerError, "Can't set content."); 119 } 120 121 InputStream stream(DavResource resource) { 122 throw new DavException(HTTPStatus.internalServerError, "Can't get stream."); 123 } 124 125 void copyPropertiesTo(URL source, URL destination) { } 126 127 DavProp property(DavResource resource, string name) { 128 if(!matchPluginUrl(resource.path)) 129 throw new DavException(HTTPStatus.internalServerError, "Can't get property."); 130 131 if(hasDavInterfaceProperty!ACLDavProperties(name)) 132 return getDavInterfaceProperty!ACLDavProperties(name, this, resource); 133 134 if(hasDavInterfaceProperty!IDavReportSetProperties(name)) 135 return getDavInterfaceProperty!IDavReportSetProperties(name, this, resource); 136 137 throw new DavException(HTTPStatus.internalServerError, "Can't get property."); 138 } 139 140 HTTPStatus setProperty(DavResource resource, string name, DavProp prop) { 141 throw new DavException(HTTPStatus.internalServerError, "Can't set property."); 142 } 143 144 HTTPStatus removeProperty(DavResource resource, string name) { 145 throw new DavException(HTTPStatus.internalServerError, "Can't remove property."); 146 } 147 148 @property { 149 string name() { 150 return "ACLDavResourcePlugin"; 151 } 152 } 153 } 154 155 class ACLDavPlugin : BaseDavPlugin { 156 157 private IDav _dav; 158 159 this(IDav dav) { 160 super(dav); 161 } 162 163 bool isPrincipalsCollection(Path path) { 164 return matchPluginUrl(path) && path.length == 1; 165 } 166 167 bool isUserCollection(Path path, string username) { 168 return matchPluginUrl(path) && path.head == username && path.length == 2; 169 } 170 171 bool isRootCollection(Path path) { 172 return path.length == 0; 173 } 174 175 override { 176 bool exists(URL url, string username) { 177 return isPrincipalsCollection(dav.path(url)) || isUserCollection(dav.path(url), username); 178 } 179 180 Path[] childList(URL url, string username) { 181 Path[] list; 182 183 if(dav.path(url).length == 0) { 184 list = [ Path("principals/") ]; 185 } 186 187 if(isPrincipalsCollection(dav.path(url))) { 188 list = [ Path("principals/" ~ username ~ "/") ]; 189 } 190 191 return list; 192 } 193 194 void bindResourcePlugins(DavResource resource) { 195 resource.registerPlugin(new ACLDavResourcePlugin); 196 } 197 198 DavResource getResource(URL url, string username) { 199 if(isPrincipalsCollection(dav.path(url)) || isUserCollection(dav.path(url), username)) { 200 DavResource resource = super.getResource(url, username); 201 resource.resourceType ~= "collection:DAV:"; 202 203 return resource; 204 } 205 206 throw new DavException(HTTPStatus.internalServerError, "Can't get resource."); 207 } 208 } 209 210 @property { 211 string name() { 212 return "ACLDavPlugin"; 213 } 214 215 override string[] support(URL url, string username) { 216 return matchPluginUrl(dav.path(url)) ? [ "access-control" ] : []; 217 } 218 } 219 }