1 /++ 2 A module containing the configuration structures used to setup your auth process 3 4 Copyright: © 2018 Szabo Bogdan 5 License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 6 Authors: Szabo Bogdan 7 +/ 8 module vibeauth.configuration; 9 10 import vibe.data.json; 11 import std.file; 12 13 version(unittest) { 14 import fluent.asserts; 15 } 16 17 /// Structure used to define a service 18 struct ServiceConfiguration { 19 /// The service name 20 string name = "Unknown App"; 21 22 /// A custom style file embedded in the auth html files 23 string style; 24 25 /// Login cookie expiration time 26 ulong loginTimeoutSeconds = 86_400; 27 28 /// 29 Paths paths; 30 31 /// 32 Templates templates; 33 34 /// Load configuration from a Json object 35 void load(Json data) { 36 if("name" in data) { 37 name = data["name"].to!string; 38 } 39 40 if("style" in data) { 41 style = data["style"].to!string; 42 } 43 44 if("loginTimeoutSeconds" in data) { 45 loginTimeoutSeconds = data["loginTimeoutSeconds"].to!ulong; 46 } 47 48 if("paths" in data && data["paths"].type == Json.Type.object) { 49 paths.load(data["paths"]); 50 } 51 52 if("templates" in data && data["templates"].type == Json.Type.object) { 53 templates.load(data["templates"]); 54 } 55 } 56 } 57 58 /// load configuration 59 unittest { 60 auto config = `{ 61 "name": "demo", 62 "style": "some style", 63 "loginTimeoutSeconds": 100, 64 "paths": { 65 "location": "location" 66 } 67 }`.parseJsonString; 68 69 ServiceConfiguration configuration; 70 configuration.load(config); 71 72 configuration.name.should.equal("demo"); 73 configuration.style.should.equal("some style"); 74 configuration.loginTimeoutSeconds.should.equal(100); 75 configuration.paths.location.should.equal("location"); 76 } 77 78 /// 79 struct Paths { 80 /// The service base URL. Url used for redireaction and email links 81 string location = "http://localhost"; 82 83 /// 84 RegistrationPaths registration; 85 86 /// 87 LoginPaths login; 88 89 /// 90 UserManagementPaths userManagement; 91 92 /// 93 ResourcePaths resources; 94 95 /// Load configuration from a Json object 96 void load(Json data) { 97 if("location" in data) { 98 location = data["location"].to!string; 99 } 100 101 if("registration" in data) { 102 registration.load(data["registration"]); 103 } 104 105 if("registration" in data) { 106 login.load(data["login"]); 107 } 108 109 if("registration" in data) { 110 userManagement.load(data["userManagement"]); 111 } 112 } 113 } 114 115 /// 116 struct Templates { 117 mixin ObjectLoader; 118 119 /// 120 RegistrationTemplates registration; 121 122 /// 123 LoginTemplates login; 124 125 /// 126 UserManagementTemplates userManagement; 127 } 128 129 struct ResourcePaths { 130 /// 131 string bootstrapStyle = "/assets/bootstrap.min.css"; 132 /// 133 string bootstrapJs = "/assets/bootstrap.min.js"; 134 /// 135 string jquery = "/assets/jquery.min.js"; 136 } 137 138 /// Registration process url paths 139 struct RegistrationPaths { 140 mixin StringLoader; 141 142 /// 143 string register = "/register"; 144 /// 145 string addUser = "/register/user"; 146 /// 147 string activation = "/register/activation"; 148 /// 149 string challange = "/register/challenge"; 150 /// 151 string confirmation = "/register/confirmation"; 152 /// 153 string activationRedirect = "/"; 154 } 155 156 /// Html templaes used in the registration process 157 struct RegistrationTemplates { 158 mixin FileLoader; 159 160 /// 161 string formTemplate = import("register/formTemplate.html"); 162 163 /// 164 string form = import("register/form.html"); 165 166 /// 167 string confirmationTemplate = import("register/confirmationTemplate.html"); 168 /// 169 string confirmation = import("register/confirmation.html");; 170 171 /// 172 string successTemplate = import("register/successTemplate.html"); 173 /// 174 string success = import("register/success.html"); 175 } 176 177 /// Paths for the login process 178 struct LoginPaths { 179 mixin StringLoader; 180 181 /// 182 string form = "/login"; 183 184 /// 185 string login = "/login/check"; 186 187 /// 188 string resetForm = "/login/reset"; 189 190 /// 191 string reset = "/login/reset/send"; 192 193 /// 194 string changePassword = "/login/reset/change"; 195 196 /// 197 string redirect = "/"; 198 } 199 200 /// Html templates for the login process 201 struct LoginTemplates { 202 mixin FileLoader; 203 204 /// 205 string formTemplate = import("login/formTemplate.html"); 206 /// 207 string form = import("login/form.html"); 208 209 /// 210 string resetTemplate = import("login/resetTemplate.html"); 211 /// 212 string reset = import("login/reset.html"); 213 /// 214 string resetPassword = import("login/resetPasswordForm.html"); 215 } 216 217 struct UserManagementPaths { 218 mixin StringLoader; 219 220 /// 221 string list = "/admin/users"; 222 223 /// 224 string profile = "/admin/users/:id"; 225 /// 226 string updateProfile = "/admin/users/:id/update"; 227 228 /// 229 string account = "/admin/users/:id/account"; 230 /// 231 string updateAccount = "/admin/users/:id/account/update"; 232 /// 233 string deleteAccount = "/admin/users/:id/delete"; 234 235 /// 236 string security = "/admin/users/:id/security"; 237 /// 238 string securityMakeAdmin = "/admin/users/:id/security/make-admin"; 239 /// 240 string securityRevokeAdmin = "/admin/users/:id/security/revoke-admin"; 241 /// 242 string updateSecurity = "/admin/users/:id/security/update"; 243 } 244 245 struct UserManagementTemplates { 246 mixin FileLoader; 247 248 /// 249 string listTemplate = import("userManagement/template.html"); 250 251 /// 252 string userTemplate = import("userManagement/userTemplate.html"); 253 254 /// 255 string profileForm = import("userManagement/profileForm.html"); 256 257 /// 258 string accountForm = import("userManagement/accountForm.html"); 259 260 /// 261 string question = import("userManagement/question.html"); 262 263 /// 264 string securityForm = import("userManagement/securityForm.html"); 265 /// 266 string adminRights = import("userManagement/adminRights.html"); 267 /// 268 string otherRights = import("userManagement/otherRights.html"); 269 } 270 271 mixin template FileLoader() { 272 /// Load configuration from a Json object 273 void load(Json data) { 274 static foreach(member; __traits(allMembers, typeof(this))) { 275 static if(member != "load") { 276 if(member in data && data[member].type == Json.Type..string) { 277 string fileName = data[member].to!string; 278 mixin("this." ~ member ~ " = readText(fileName);"); 279 } 280 } 281 } 282 } 283 } 284 285 mixin template ObjectLoader() { 286 /// Load configuration from a Json object 287 void load(Json data) { 288 static foreach(member; __traits(allMembers, typeof(this))) { 289 static if(member != "load") { 290 if(member in data && data[member].type == Json.Type.object) { 291 mixin("this." ~ member ~ ".load(data[\"" ~ member ~ "\"]);"); 292 } 293 } 294 } 295 } 296 } 297 298 mixin template StringLoader() { 299 /// Load configuration from a Json object 300 void load(Json data) { 301 static foreach(member; __traits(allMembers, typeof(this))) { 302 static if(member != "load") { 303 if(member in data && data[member].type == Json.Type.object) { 304 mixin("this." ~ member ~ " = data[\"" ~ member ~ "\"].to!string;"); 305 } 306 } 307 } 308 } 309 }