Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
if (password.id) {
if (!/^\w+$/.test(password.id)) {
throw new Boom.Boom('Invalid password id');
}
passwordId = password.id;
}
// Encrypt object string
const { encrypted, key } = await exports.encrypt(password.encryption, options.encryption, objectString);
// Base64url the encrypted value
const encryptedB64 = B64.base64urlEncode(encrypted);
const iv = B64.base64urlEncode(key.iv);
const expiration = (options.ttl ? now + options.ttl : '');
const macBaseString = exports.macPrefix + '*' + passwordId + '*' + key.salt + '*' + iv + '*' + encryptedB64 + '*' + expiration;
// Mac the combined values
const mac = await exports.hmacWithPassword(password.integrity, options.integrity, macBaseString);
// Put it all together
// prefix*[password-id]*encryption-salt*encryption-iv*encrypted*[expiration]*hmac-salt*hmac
// Allowed URI query name/value characters: *-. \d \w
const sealed = macBaseString + '*' + mac.salt + '*' + mac.digest;
return sealed;
};
password = internals.normalizePassword(password);
if (password.id) {
if (!/^\w+$/.test(password.id)) {
throw new Boom.Boom('Invalid password id');
}
passwordId = password.id;
}
// Encrypt object string
const { encrypted, key } = await exports.encrypt(password.encryption, options.encryption, objectString);
// Base64url the encrypted value
const encryptedB64 = B64.base64urlEncode(encrypted);
const iv = B64.base64urlEncode(key.iv);
const expiration = (options.ttl ? now + options.ttl : '');
const macBaseString = exports.macPrefix + '*' + passwordId + '*' + key.salt + '*' + iv + '*' + encryptedB64 + '*' + expiration;
// Mac the combined values
const mac = await exports.hmacWithPassword(password.integrity, options.integrity, macBaseString);
// Put it all together
// prefix*[password-id]*encryption-salt*encryption-iv*encrypted*[expiration]*hmac-salt*hmac
// Allowed URI query name/value characters: *-. \d \w
const sealed = macBaseString + '*' + mac.salt + '*' + mac.digest;
return sealed;
};
if (request.method !== 'GET' &&
request.method !== 'HEAD') {
throw Utils.unauthorized('Invalid method');
}
// No other authentication
if (request.authorization) {
throw Boom.badRequest('Multiple authentications');
}
// Parse bewit
try {
var bewitString = B64.base64urlDecode(resource[3]);
}
catch (err) {
throw Boom.badRequest('Invalid bewit encoding');
}
// Bewit format: id\exp\mac\ext ('\' is used because it is a reserved header attribute character)
const bewitParts = bewitString.split('\\');
if (bewitParts.length !== 4) {
throw Boom.badRequest('Invalid bewit structure');
}
const bewit = {
id: bewitParts[0],
exp: parseInt(bewitParts[1], 10),
mac: bewitParts[2],
const exp = Math.floor(now / 1000) + options.ttlSec;
const mac = Crypto.calculateMac('bewit', credentials, {
ts: exp,
nonce: '',
method: 'GET',
resource: uri.pathname + (uri.search || ''), // Maintain trailing '?'
host: uri.hostname,
port: uri.port || (uri.protocol === 'http:' ? 80 : 443),
ext
});
// Construct bewit: id\exp\mac\ext
const bewit = credentials.id + '\\' + exp + '\\' + mac + '\\' + ext;
return B64.base64urlEncode(bewit);
};
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');
}
catch (err) {
throw Boom.boomify(err);
}
const decrypted = await exports.decrypt(password.encryption, decryptOptions, encrypted);
}
// 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');
}
catch (err) {
throw Boom.boomify(err);
}
const decrypted = await exports.decrypt(password.encryption, decryptOptions, encrypted);
// Parse JSON
try {
return Bourne.parse(decrypted);
}
catch (err) {
throw new Boom.Boom('Failed parsing sealed object JSON: ' + err.message);
}
};
it('returns an error when decrypted object is invalid', async () => {
const badJson = '{asdasd';
const { encrypted, key } = await Iron.encrypt(password, Iron.defaults.encryption, badJson);
const encryptedB64 = B64.base64urlEncode(encrypted);
const iv = B64.base64urlEncode(key.iv);
const macBaseString = Iron.macPrefix + '**' + key.salt + '*' + iv + '*' + encryptedB64 + '*';
const mac = await Iron.hmacWithPassword(password, Iron.defaults.integrity, macBaseString);
const ticket = macBaseString + '*' + mac.salt + '*' + mac.digest;
const err = await expect(Iron.unseal(ticket, password, Iron.defaults)).to.reject(/Failed parsing sealed object JSON: Unexpected token a/);
expect(err.isBoom).to.be.true();
});
it('returns an error when decrypted object is invalid', async () => {
const badJson = '{asdasd';
const { encrypted, key } = await Iron.encrypt(password, Iron.defaults.encryption, badJson);
const encryptedB64 = B64.base64urlEncode(encrypted);
const iv = B64.base64urlEncode(key.iv);
const macBaseString = Iron.macPrefix + '**' + key.salt + '*' + iv + '*' + encryptedB64 + '*';
const mac = await Iron.hmacWithPassword(password, Iron.defaults.integrity, macBaseString);
const ticket = macBaseString + '*' + mac.salt + '*' + mac.digest;
const err = await expect(Iron.unseal(ticket, password, Iron.defaults)).to.reject(/Failed parsing sealed object JSON: Unexpected token a/);
expect(err.isBoom).to.be.true();
});
it('parses b64 file', async () => {
const payload =
'--AaB03x\r\n' +
'content-disposition: form-data; name="field"; filename="file.txt"\r\n' +
'content-transfer-encoding: base64\r\n' +
'\r\n' +
B64.encode(Buffer.from('this is the content of the file')) + '\r\n' +
'--AaB03x--';
const data = await simulate(payload, 'AaB03x');
expect(data).to.equal({
field: {
value: 'this is the content of the file',
headers: {
'content-disposition': 'form-data; name="field"; filename="file.txt"',
'content-transfer-encoding': 'base64'
},
filename: 'file.txt'
}
});
});
it('handles unusual filename', async () => {
const blankgif = Fs.readFileSync('./test/files/blank.gif');
const filename = ': \\ ? % * | %22 < > . ? ; \' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt';
const payload =
'--AaB03x\r\n' +
'content-disposition: form-data; name="file"; filename="' + filename + '"\r\n' +
'content-transfer-encoding: base64\r\n' +
'Content-Type: image/gif\r\n' +
'\r\n' +
B64.encode(blankgif) + '\r\n' +
'--AaB03x--\r\n';
const data = await simulate(payload, 'AaB03x');
expect(data).to.equal({
file: {
value: blankgif.toString(),
headers: {
'content-disposition': 'form-data; name="file"; filename="' + filename + '"',
'content-transfer-encoding': 'base64',
'content-type': 'image/gif'
},
filename
}
});
});
});