Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
}
// Error if not https but cookie is secure
if (protocol !== 'https' &&
settings.isSecure) {
return h.unauthenticated(Boom.internal('Invalid setting - isSecure must be set to false for non-https server'), { credentials });
}
// Sign-in Initialization
if (!request.query.code) {
credentials.query = request.query;
const nonce = Cryptiles.randomString(internals.nonceLength);
const query = internals.resolveProviderParams(request, settings.providerParams);
if (settings.allowRuntimeProviderParams) {
Hoek.merge(query, request.query);
}
query.client_id = settings.clientId;
query.response_type = 'code';
query.redirect_uri = internals.location(request, protocol, settings.location);
query.state = nonce;
if (settings.runtimeStateCallback) {
const runtimeState = settings.runtimeStateCallback(request);
if (runtimeState) {
query.state += runtimeState;
}
!credentials.id ||
!credentials.key ||
!credentials.algorithm) {
throw new Boom('Invalid credentials');
}
if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
throw new Boom('Unknown algorithm');
}
// Calculate signature
const artifacts = {
ts: timestamp,
nonce: options.nonce || Cryptiles.randomString(6),
host,
port,
hash: Crypto.calculatePayloadHash(message, credentials.algorithm)
};
// Construct authorization
const result = {
id: credentials.id,
ts: artifacts.ts,
nonce: artifacts.nonce,
hash: artifacts.hash,
mac: Crypto.calculateMac('message', credentials, artifacts)
};
return result;
if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
throw new Boom('Unknown algorithm');
}
// Parse URI
if (typeof uri === 'string') {
uri = Url.parse(uri);
}
// Calculate signature
const artifacts = {
ts: timestamp,
nonce: options.nonce || Cryptiles.randomString(6),
method,
resource: uri.pathname + (uri.search || ''), // Maintain trailing '?'
host: uri.hostname,
port: uri.port || (uri.protocol === 'http:' ? 80 : 443),
hash: options.hash,
ext: options.ext,
app: options.app,
dlg: options.dlg
};
// Calculate payload hash
if (!artifacts.hash &&
(options.payload || options.payload === '')) {
artifacts.hash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
internals.Client.prototype._request = async function (method, uri, params, oauth, options) {
method = method.toLowerCase();
// Prepare generic OAuth parameters
oauth.oauth_nonce = Cryptiles.randomString(internals.nonceLength);
oauth.oauth_timestamp = Math.floor(Date.now() / 1000).toString();
oauth.oauth_consumer_key = this.settings.clientId;
oauth.oauth_signature_method = this.settings.signatureMethod;
oauth.oauth_signature = this.signature(method, uri, params, oauth, options.secret);
// Calculate OAuth header
const requestOptions = {
headers: {
Authorization: internals.Client.header(oauth)
}
};
if (params) {
const paramsString = internals.queryString(params);
if (method === 'get') {
host,
port,
hash: authorization.hash
};
// Calculate MAC
const mac = Crypto.calculateMac('message', credentials, artifacts);
if (!Cryptiles.fixedTimeComparison(mac, authorization.mac)) {
throw Object.assign(Utils.unauthorized('Bad mac'), result);
}
// Check payload hash
const hash = Crypto.calculatePayloadHash(message, credentials.algorithm);
if (!Cryptiles.fixedTimeComparison(hash, authorization.hash)) {
throw Object.assign(Utils.unauthorized('Bad message hash'), result);
}
// Check nonce
if (options.nonceFunc) {
try {
await options.nonceFunc(credentials.key, authorization.nonce, authorization.ts);
}
catch (err) {
throw Object.assign(Utils.unauthorized('Invalid nonce'), result);
}
}
// Check timestamp staleness
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 {
const result = { credentials, artifacts };
if (!credentials.key ||
!credentials.algorithm) {
throw new Boom('Invalid credentials', { decorate: result });
}
if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
throw new Boom('Unknown algorithm', { decorate: result });
}
// Calculate MAC
const mac = Crypto.calculateMac('header', credentials, artifacts);
if (!Cryptiles.fixedTimeComparison(mac, attributes.mac)) {
throw Object.assign(Utils.unauthorized('Bad mac'), result);
}
// Check payload hash
if (options.payload ||
options.payload === '') {
if (!attributes.hash) {
throw Object.assign(Utils.unauthorized('Missing required payload hash'), result);
}
const hash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, request.contentType);
if (!Cryptiles.fixedTimeComparison(hash, attributes.hash)) {
throw Object.assign(Utils.unauthorized('Bad payload hash'), result);
}
throw new Boom('Unknown algorithm', { decorate: result });
}
// Calculate MAC
const mac = Crypto.calculateMac('bewit', credentials, {
ts: bewit.exp,
nonce: '',
method: 'GET',
resource: url,
host: request.host,
port: request.port,
ext: bewit.ext
});
if (!Cryptiles.fixedTimeComparison(mac, bewit.mac)) {
throw Object.assign(Utils.unauthorized('Bad mac'), result);
}
// Successful authentication
return result;
};
it('fails to turn object into a ticket (failed to stringify object)', async () => {
const cyclic = [];
cyclic[0] = cyclic;
const key = Cryptiles.randomBits(128);
const err = await expect(Iron.seal(cyclic, key, Iron.defaults)).to.reject(/Failed to stringify object: Converting circular structure to JSON/);
expect(err.isBoom).to.be.true();
});
it('formats a header with server definition (iron + options, buffer password)', async () => {
const definitions = new Statehood.Definitions();
definitions.add('sid', { encoding: 'iron', password: Cryptiles.randomBits(256), iron: Iron.defaults });
const header = await definitions.format({ name: 'sid', value: { a: 1, b: 2, c: 3 } });
expect(header[0]).to.have.string('sid=Fe26.2*');
});