scratch-www/src/lib/jar.js

108 lines
3.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const cookie = require('cookie');
const defaults = require('lodash.defaults');
const xhr = require('xhr');
const pako = require('pako');
/**
* Module that handles coookie interactions.
* (Cookies?!?! Jar?!?! Get it?!?! WE'RE AMAZING!!!!)
*
* get(name, callback) can be sync or async, as callback is optional
* set(name, value) synchronously sets the cookie
* use(name, uri, callback) can by sync or async, gets cookie from the uri if not there.
*/
const Jar = {
unsign: (value, callback) => {
// Return the usable content portion of a signed, compressed cookie generated by
// Django's signing module
// https://github.com/django/django/blob/stable/1.8.x/django/core/signing.py
if (typeof value === 'undefined') return callback(null, value);
try {
let b64Data = value.split(':')[0];
let decompress = false;
if (b64Data[0] === '.') {
decompress = true;
b64Data = b64Data.substring(1);
}
// Django makes its base64 strings url safe by replacing + and / with - and _ respectively
// using base64.urlsafe_b64encode
// https://docs.python.org/2/library/base64.html#base64.b64encode
b64Data = b64Data.replace(
/[-_]/g,
c => ({
'-': '+',
'_': '/'
}[c])
);
let strData = atob(b64Data);
if (decompress) {
const charData = strData.split('').map(c => (c.charCodeAt(0)));
const binData = new Uint8Array(charData);
const data = pako.inflate(binData);
strData = String.fromCharCode.apply(null, new Uint16Array(data));
}
return callback(null, strData);
} catch (e) {
return callback(e);
}
},
get: (name, callback) => {
// Get cookie by name
const obj = cookie.parse(document.cookie) || {};
// Handle optional callback
if (typeof callback === 'function') {
if (typeof obj === 'undefined') return callback('Cookie not found.');
return callback(null, obj[name]);
}
return obj[name];
},
use: (name, uri, callback) => {
// Attempt to get cookie
Jar.get(name, (err, obj) => {
if (typeof obj !== 'undefined') return callback(null, obj);
// Make XHR request to cookie setter uri
xhr({
uri: uri
}, e => {
if (e) return callback(e);
Jar.get(name, callback);
});
});
},
set: (name, value, opts) => {
opts = opts || {};
defaults(opts, {
expires: new Date(new Date().setYear(new Date().getFullYear() + 1)),
sameSite: 'Lax' // cookie library requires this capitialization of sameSite
});
opts.path = '/';
const obj = cookie.serialize(name, value, opts);
document.cookie = obj;
},
getUnsignedValue: (cookieName, signedValue, callback) => {
// Get a value from a signed object
Jar.get(cookieName, (err, value) => {
if (err) return callback(err);
if (typeof value === 'undefined') return callback(null, value);
Jar.unsign(value, (e, contents) => {
if (e) return callback(e);
try {
const data = JSON.parse(contents);
return callback(null, data[signedValue]);
} catch (error) {
return callback(error);
}
});
});
}
};
module.exports = Jar;