1 /** 2 * Copyright © DiamondMVC 2019 3 * License: MIT (https://github.com/DiamondMVC/Diamond/blob/master/LICENSE) 4 * Author: Jacob Jensen (bausshf) 5 */ 6 module diamond.security.csrf; 7 8 import diamond.core.apptype; 9 10 static if (isWeb) 11 { 12 import diamond.http; 13 import diamond.errors.checks; 14 15 /// The key of the token's storage in the session. 16 private static const __gshared CSRFTokenKey = "__D_CSRFTOKEN"; 17 18 /** 19 * Generates a CSRF token. 20 * Params: 21 * client = The client. 22 * Returns: 23 * The generated csrf token. If a token already exist, the existing token is returned. 24 */ 25 string generateCSRFToken(HttpClient client) 26 { 27 auto token = client.session.getValue!string(CSRFTokenKey); 28 29 if (token) 30 { 31 return token; 32 } 33 34 import diamond.security.tokens.generictoken; 35 36 token = genericToken.generate()[0 .. 64]; 37 38 client.session.setValue(CSRFTokenKey, token); 39 40 return token; 41 } 42 43 /** 44 * Clears the csrf token. 45 * Params: 46 * client = The client. 47 */ 48 void clearCSRFToken(HttpClient client) 49 { 50 client.session.removeValue(CSRFTokenKey); 51 } 52 53 /** 54 * Checks whether a token is a valid csrf token for the request. 55 * Params: 56 * client = The client. 57 * token = The token to validate. 58 * removeToken = Boolean determining whether the token should be cleared after validation. 59 * Returns: 60 * Returns true if the token is valid, false otherwise. 61 */ 62 bool isValidCSRFToken 63 ( 64 HttpClient client, 65 string token, bool removeToken 66 ) 67 { 68 enforce(token && token.length == 64, "Invalid csrf token."); 69 70 auto csrfToken = client.session.getValue!string(CSRFTokenKey); 71 72 if (csrfToken && removeToken) 73 { 74 client.session.removeValue(CSRFTokenKey); 75 } 76 77 return csrfToken !is null && token == csrfToken; 78 } 79 }