UNPKG

@nodefony/http-bundle

Version:

Nodefony Framework Bundle HTTP

275 lines (251 loc) 6.93 kB
const cookieLib = require('cookie'); const MS = require('ms'); nodefony.register("cookies", function() { const encode = encodeURIComponent; const decode = decodeURIComponent; const cookieDefaultSettings = { maxAge: 0, //24*60*60, path: "/", domain: null, secure: false, sameSite: null, // "Lax" || "Strict" httpOnly: true, signed: false, secret: "!nodefony.secret!" }; const parse = function(strToParse) { return cookieLib.parse(strToParse); }; const getRequestcookies = function(context) { let cookies = null; switch (context.type) { case "HTTP": case "HTTPS": case "HTTP2": if (context.request.request && context.request.request.headers.cookie) { cookies = context.request.request.headers.cookie; } break; case "WEBSOCKET": case "WEBSOCKET SECURE": if (context.request.cookies) { cookies = context.request.cookies; } break; } return parse(cookies); }; const cookiesParser = function(context) { let cookies = null; let co = null; switch (context.type) { case "HTTP": case "HTTPS": case "HTTP2": if (context.request.request && context.request.request.headers.cookie) { cookies = context.request.request.headers.cookie; } if (cookies) { let obj = parse(cookies); for (let cookie in obj) { co = new Cookie(cookie, obj[cookie]); context.addCookie(co); } context.request.request.cookies = context.cookies; } break; case "WEBSOCKET": case "WEBSOCKET SECURE": if (context.request.cookies) { cookies = context.request.cookies; } if (cookies) { for (let i = 0; i < cookies.length; i++) { co = new Cookie(cookies[i].name, cookies[i].value); context.addCookie(co); } } break; } }; const Cookie = class Cookie { constructor(name, value, settings) { if (typeof name === "object") { this.settings = name.settings; this.name = name.name; this.signed = name.signed; this.value = name.value; this.originalMaxAge = name.originalMaxAge; this.expires = name.expires; this.path = name.path; this.domain = name.domain; this.httpOnly = name.httpOnly; this.secure = name.secure; this.maxAge = name.maxAge; this.sameSite = name.sameSite; } else { this.settings = nodefony.extend({}, cookieDefaultSettings, settings); if (!name) { throw new Error("cookie must have name"); } this.name = name; this.signed = this.settings.signed; this.value = this.setValue(value); this.originalMaxAge = this.setOriginalMaxAge(this.settings.maxAge); this.expires = this.setExpires(this.settings.expires); this.path = this.setPath(this.settings.path); this.domain = this.setDomain(); this.httpOnly = this.setHttpOnly(this.settings.httpOnly); this.secure = this.setSecure(this.settings.secure); this.sameSite = this.setSameSite(this.settings.sameSite); } } clearCookie() { this.setExpires(1); this.path = "/"; } setValue(value) { if (value) { value = decode(value); } if (this.signed) { this.value = this.sign(value, this.settings.secret); } else { this.value = value; } return this.value; } setSecure(val) { return val; } setDomain() { return this.settings.domain; } setHttpOnly(val) { return val; } setPath(val) { return val; } setSameSite(val) { return val; } setExpires(date) { if (date) { try { if (date instanceof Date) { this.expires = date; } else { this.expires = new Date(date); } } catch (e) { this.expires = null; } } else { let maxage = this.getMaxAge(); if (maxage === 0) { this.expires = null; } else { let res = new Date().getTime() + (maxage * 1000); this.expires = new Date(res); } return this.expires; } this.getMaxAge(); return this.expires; } setOriginalMaxAge(ms) { let res = null; switch (typeof ms) { case "number": return ms; case "string": try { res = MS(ms) / 1000; } catch (e) { res = ms; } return parseInt(res, 10); default: throw new Error("cookie class error maxage bad type " + typeof ms); } } getMaxAge() { if (this.expires && this.expires instanceof Date) { let ms = (this.expires.getTime() - new Date().getTime()); let s = (ms / 1000); if (s > 0) { this.maxAge = s; // en seconde } else { throw new Error("Espires / Max-Age : " + s + " Error Espires"); } } else { this.maxAge = this.originalMaxAge; } return this.maxAge; } toString() { return this.name + "=" + encode(this.value); } sign(val, secret) { if ('string' !== typeof val) { throw new TypeError('cookie required'); } if ('string' !== typeof secret) { throw new TypeError('secret required'); } return crypto .createHmac('sha256', val + '.' + secret) .update(val) .digest('base64') .replace(/\=+$/, ''); } unsign(val, secret) { if (val && 'string' !== typeof val) { throw new Error('unsign cookie value bad type !! '); } if (secret && 'string' !== typeof secret) { throw new Error('unsign cookie secret bad type'); } if (!val) { val = this.value; } if (!secret) { secret = this.settings.secret; } return this.sign(val, secret) === val ? val : false; } serialize() { let tab = []; tab.push(this.toString()); if (this.maxAge) { tab.push('Max-Age=' + this.maxAge); } if (this.domain) { tab.push('Domain=' + this.domain); } if (this.path) { tab.push('Path=' + this.path); } if (this.sameSite) { tab.push('SameSite=' + this.sameSite); } if (this.expires) { tab.push('Expires=' + this.expires.toUTCString()); } if (this.httpOnly) { tab.push('HttpOnly'); } if (this.secure) { tab.push('Secure'); } return tab.join('; '); } }; return { cookie: Cookie, cookiesParser: cookiesParser, parser: parse, getRequestcookies: getRequestcookies }; });