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.http.cookies; 7 8 import diamond.core.apptype; 9 10 static if (isWeb) 11 { 12 import vibe.d : Cookie; 13 14 import diamond.errors.checks; 15 import diamond.core.senc; 16 import diamond.http.client; 17 18 /// Collection of standard cookies used within Diamond. 19 private CookieInformation[] _cookieInformation; 20 21 /// Wrapper around cookie information. 22 class CookieInformation 23 { 24 private: 25 /// The cookie name. 26 string _cookieName; 27 /// The cookie description. 28 string _cookieDescription; 29 30 /** 31 * Creates a new cookie information wrapper. 32 * Params: 33 * cookieName = The name of the cookie. 34 * cookieDescription = The description of the cookie. 35 */ 36 this(string cookieName, string cookieDescription) 37 { 38 _cookieName = cookieName; 39 _cookieDescription = cookieDescription; 40 } 41 42 public: 43 /// Gets the name of the cookie. 44 string cookieName() { return _cookieName; } 45 46 /// Gets the description of the cookie. 47 string cookieDescription() { return _cookieDescription; } 48 } 49 50 /// Gets information about all standard cookies used within Diamond. 51 CookieInformation[] getCookieInformation() 52 { 53 if (!_cookieInformation) 54 { 55 _cookieInformation = [ 56 new CookieInformation("__D_AUTH_TOKEN", "This cookie is used to store the authentication token used by Diamond."), 57 new CookieInformation("__D_COOKIE_CONSENT", "This cookie is used to store the cookie consent used by Diamond."), 58 new CookieInformation("__D_SESSION", "This cookie is used to store the Diamond session id of a client.") 59 ]; 60 } 61 62 return _cookieInformation; 63 } 64 65 /// Enumeration of http cookie consent types. 66 enum HttpCookieConsent : string 67 { 68 /// All cookies are allowed. 69 all = "all", 70 /// No third-party cookies are allowed. 71 noThirdParty = "noThirdParty", 72 /// Only functional required cookies are allowed. Third-party cookies etc. are not allowed. 73 functional = "functional", 74 /// No cookies are allowed. 75 none = "none" 76 } 77 78 /// The type of cookie added. 79 enum HttpCookieType 80 { 81 /// A general cookie used for miscellaneous functionality. 82 general, 83 /// A cookie required for minimum functionality. 84 functional, 85 /// A third-party cookie. 86 thirdParty, 87 /// A session cookie. Session cookies cannot be disabled. 88 session 89 } 90 91 /// Wrapper around a http cookie collections. 92 final class HttpCookies 93 { 94 private: 95 /// The client. 96 HttpClient _client; 97 98 public: 99 final: 100 /** 101 * Creates a new http cookie collection. 102 * Params: 103 * client = The client. 104 */ 105 package(diamond) this(HttpClient client) 106 { 107 _client = enforceInput(client, "Cannot create a cookie collection without a client."); 108 } 109 110 /** 111 * Checks whether a user has consent for a specific cookie type. 112 * Params: 113 * cookieType = The type of the cookie. 114 * Returns: 115 * True if the user accepts the cookie, false otherwise. 116 */ 117 private bool hasConsent(HttpCookieType cookieType) 118 { 119 switch (cookieType) 120 { 121 case HttpCookieType.general: 122 { 123 if 124 ( 125 _client.cookieConsent != HttpCookieConsent.all && 126 _client.cookieConsent != HttpCookieConsent.noThirdParty 127 ) 128 { 129 return false; 130 } 131 132 break; 133 } 134 135 case HttpCookieType.functional: 136 { 137 if 138 ( 139 _client.cookieConsent == HttpCookieConsent.none 140 ) 141 { 142 return false; 143 } 144 145 break; 146 } 147 148 case HttpCookieType.thirdParty: 149 { 150 if 151 ( 152 _client.cookieConsent != HttpCookieConsent.all 153 ) 154 { 155 return false; 156 } 157 158 break; 159 } 160 161 default: break; 162 } 163 164 return _client.cookieConsent != HttpCookieConsent.none; 165 } 166 167 /** 168 * Creates a cookie. 169 * Params: 170 * cookieType = The type of the cookie. 171 * name = The name of the cookie. 172 * value = The value of the cookie. 173 * maxAge = The max-age of the cookie. (Seconds the cookie will be alive.) 174 * path = The path of the cookie. (Default: "/") 175 */ 176 void create 177 ( 178 HttpCookieType cookieType, 179 string name, string value, 180 long maxAge, 181 string path = "/" 182 ) 183 { 184 if (!hasConsent(cookieType)) 185 { 186 return; 187 } 188 189 auto cookie = new Cookie; 190 cookie.path = path; 191 cookie.maxAge = maxAge; 192 cookie.setValue(value, Cookie.Encoding.none); 193 194 _client.rawResponse.cookies[name] = cookie; 195 } 196 197 /** 198 * Creates a cookie. 199 * Params: 200 * cookieType = The type of the cookie. 201 * name = The name of the cookie. 202 * buffer = The buffer to encode into a SENC encoded cookie string. 203 * maxAge = The max-age of the cookie. (Seconds the cookie will be alive.) 204 * path = The path of the cookie. (Default: "/") 205 */ 206 void createBuffered 207 ( 208 HttpCookieType cookieType, 209 string name, ubyte[] buffer, 210 long maxAge, 211 string path = "/" 212 ) 213 { 214 if (!hasConsent(cookieType)) 215 { 216 return; 217 } 218 219 create(cookieType, name, SENC.encode(buffer), maxAge, path); 220 } 221 222 /** 223 * Gets a cookie. 224 * Params: 225 * name = The name of the cookie. 226 * Returns: 227 * Returns the cookie if found, null otherwise. 228 */ 229 string get(string name) 230 { 231 return _client.rawRequest.cookies.get(name); 232 } 233 234 /** 235 * Gets a buffered cookie encoded as a SENC encoded string. 236 * Params: 237 * name = The name. 238 * Returns: 239 * Returns the buffer. 240 */ 241 ubyte[] getBuffered(string name) 242 { 243 return SENC.decode(get(name)); 244 } 245 246 /** 247 * Removes a cookie. 248 * Params: 249 * name = The name of the cookie to remove. 250 */ 251 void remove(string name) 252 { 253 auto cookie = new Cookie; 254 cookie.path = "/"; 255 cookie.maxAge = 1; 256 cookie.setValue(null, Cookie.Encoding.none); 257 258 _client.rawResponse.cookies[name] = cookie; 259 } 260 261 /** 262 * Checks whether a request has a cookie or not. 263 * Params: 264 * name = The name of the cookie to check for existence. 265 * Returns: 266 * True if the cookie exists, false otherwise. 267 */ 268 bool has(string name) 269 { 270 return get(name) !is null; 271 } 272 273 /** 274 * Gets the auth cookie. 275 * Returns: 276 * Returns the auth cookie. 277 */ 278 string getAuthCookie() 279 { 280 import diamondauth = diamond.authentication; 281 282 return diamondauth.getAuthCookie(_client); 283 } 284 285 /** 286 * Checks whether the auth cookie is present or not. 287 * Returns: 288 * True if the auth cookie is present, false otherwise. 289 */ 290 @property bool hasAuthCookie() 291 { 292 import diamondauth = diamond.authentication; 293 294 return diamondauth.hasAuthCookie(_client); 295 } 296 } 297 }