Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
exports.unseal = async function (sealed, password, options) {
options = Object.assign({}, options); // Shallow cloned to prevent changes during async operations
const now = Date.now() + (options.localtimeOffsetMsec || 0); // Measure now before any other processing
// Break string into components
const parts = sealed.split('*');
if (parts.length !== 8) {
throw new Boom.Boom('Incorrect number of sealed components');
}
const macPrefix = parts[0];
const passwordId = parts[1];
const encryptionSalt = parts[2];
const encryptionIv = parts[3];
const encryptedB64 = parts[4];
const expiration = parts[5];
const hmacSalt = parts[6];
const hmac = parts[7];
const macBaseString = macPrefix + '*' + passwordId + '*' + encryptionSalt + '*' + encryptionIv + '*' + encryptedB64 + '*' + expiration;
// Check prefix
if (macPrefix !== exports.macPrefix) {
throw new Boom.Boom('Wrong mac prefix');
// Check prefix
if (macPrefix !== exports.macPrefix) {
throw new Boom.Boom('Wrong mac prefix');
}
// Check expiration
if (expiration) {
if (!expiration.match(/^\d+$/)) {
throw new Boom.Boom('Invalid expiration');
}
const exp = parseInt(expiration, 10);
if (exp <= (now - (options.timestampSkewSec * 1000))) {
throw new Boom.Boom('Expired seal');
}
}
// Obtain password
if (!password) {
throw new Boom.Boom('Empty password');
}
if (typeof password === 'object' &&
!Buffer.isBuffer(password)) {
password = password[passwordId || 'default'];
if (!password) {
throw new Boom.Boom('Cannot find password: ' + passwordId);
}
const expiration = parts[5];
const hmacSalt = parts[6];
const hmac = parts[7];
const macBaseString = macPrefix + '*' + passwordId + '*' + encryptionSalt + '*' + encryptionIv + '*' + encryptedB64 + '*' + expiration;
// Check prefix
if (macPrefix !== exports.macPrefix) {
throw new Boom.Boom('Wrong mac prefix');
}
// Check expiration
if (expiration) {
if (!expiration.match(/^\d+$/)) {
throw new Boom.Boom('Invalid expiration');
}
const exp = parseInt(expiration, 10);
if (exp <= (now - (options.timestampSkewSec * 1000))) {
throw new Boom.Boom('Expired seal');
}
}
// Obtain password
if (!password) {
throw new Boom.Boom('Empty password');
}
if (typeof password === 'object' &&
!Buffer.isBuffer(password)) {
if (request.raw.res.finished) {
if (event !== 'aborted') {
request.info.responded = Date.now();
}
team.attend();
return;
}
if (err) {
request.raw.res.destroy();
Response.drain(stream);
}
err = err || new Boom.Boom(`Request ${event}`, { statusCode: request.route.settings.response.disconnectStatusCode });
const error = internals.error(request, Boom.boomify(err));
request._setResponse(error);
if (request.raw.res[Config.symbol]) {
request.raw.res.statusCode = error.statusCode;
request.raw.res[Config.symbol].result = error.source; // Force injected response to error
}
if (event) {
request._log(['response', 'error', event]);
}
else {
request._log(['response', 'error'], err);
}
request.raw.res.end(); // Triggers injection promise resolve
password = password[passwordId || 'default'];
if (!password) {
throw new Boom.Boom('Cannot find password: ' + passwordId);
}
}
password = internals.normalizePassword(password);
// Check hmac
const macOptions = Hoek.clone(options.integrity);
macOptions.salt = hmacSalt;
const mac = await exports.hmacWithPassword(password.integrity, macOptions, macBaseString);
if (!Cryptiles.fixedTimeComparison(mac.digest, hmac)) {
throw new Boom.Boom('Bad hmac value');
}
// Decrypt
try {
var encrypted = B64.base64urlDecode(encryptedB64, 'buffer');
}
catch (err) {
throw Boom.boomify(err);
}
const decryptOptions = Hoek.clone(options.encryption);
decryptOptions.salt = encryptionSalt;
try {
decryptOptions.iv = B64.base64urlDecode(encryptionIv, 'buffer');
if (expiration) {
if (!expiration.match(/^\d+$/)) {
throw new Boom.Boom('Invalid expiration');
}
const exp = parseInt(expiration, 10);
if (exp <= (now - (options.timestampSkewSec * 1000))) {
throw new Boom.Boom('Expired seal');
}
}
// Obtain password
if (!password) {
throw new Boom.Boom('Empty password');
}
if (typeof password === 'object' &&
!Buffer.isBuffer(password)) {
password = password[passwordId || 'default'];
if (!password) {
throw new Boom.Boom('Cannot find password: ' + passwordId);
}
}
password = internals.normalizePassword(password);
// Check hmac
const macOptions = Hoek.clone(options.integrity);
module.exports.createError = function (statusCode, message, data) {
return new Boom.Boom(message, { statusCode, data })
}
return async (payload, request, ast) => {
const url = `${prefix}/${ast.fieldName}`;
const res = await request.server.inject({
method,
url,
payload,
headers: request.headers
});
if (res.statusCode < 400) {
return res.result;
}
return new Boom.Boom(res.result.message, {
statusCode: res.statusCode,
data: {
error: res.result.error,
url
}
});
};
};
exports.generateKey = async function (password, options) {
if (!password) {
throw new Boom.Boom('Empty password');
}
if (!options ||
typeof options !== 'object') {
throw new Boom.Boom('Bad options');
}
const algorithm = exports.algorithms[options.algorithm];
if (!algorithm) {
throw new Boom.Boom('Unknown algorithm: ' + options.algorithm);
}
const result = {};
if (Buffer.isBuffer(password)) {
if (password.length < algorithm.keyBits / 8) {
throw new Boom.Boom('Key buffer (password) too small');
}
result.key = password;
result.salt = '';
if (password.length < algorithm.keyBits / 8) {
throw new Boom.Boom('Key buffer (password) too small');
}
result.key = password;
result.salt = '';
}
else {
if (password.length < options.minPasswordlength) {
throw new Boom.Boom('Password string too short (min ' + options.minPasswordlength + ' characters required)');
}
let salt = options.salt;
if (!salt) {
if (!options.saltBits) {
throw new Boom.Boom('Missing salt and saltBits options');
}
const randomSalt = Cryptiles.randomBits(options.saltBits);
salt = randomSalt.toString('hex');
}
const derivedKey = await internals.pbkdf2(password, salt, options.iterations, algorithm.keyBits / 8, 'sha1');
result.key = derivedKey;
result.salt = salt;
}
if (options.iv) {
result.iv = options.iv;
}
else if (algorithm.ivBits) {