oidc-provider
Advanced tools
Comparing version 1.2.0 to 2.0.0-alpha.1.2.0
@@ -7,5 +7,5 @@ 'use strict'; | ||
*/ | ||
module.exports = function* assignDefaults(next) { | ||
const params = this.oidc.params; | ||
const client = this.oidc.client; | ||
module.exports = async function assignDefaults(ctx, next) { | ||
const params = ctx.oidc.params; | ||
const client = ctx.oidc.client; | ||
@@ -20,3 +20,3 @@ if (!params.acr_values && client.defaultAcrValues) { | ||
yield next; | ||
await next(); | ||
}; |
'use strict'; | ||
module.exports = provider => function* authorizationEmit(next) { | ||
if (this.oidc.result) { | ||
provider.emit('interaction.ended', this); | ||
module.exports = provider => async function authorizationEmit(ctx, next) { | ||
if (ctx.oidc.result) { | ||
provider.emit('interaction.ended', ctx); | ||
} else { | ||
provider.emit('authorization.accepted', this); | ||
provider.emit('authorization.accepted', ctx); | ||
} | ||
yield next; | ||
await next(); | ||
}; |
@@ -20,7 +20,7 @@ 'use strict'; | ||
*/ | ||
module.exports = provider => function* checkClaims(next) { | ||
const params = this.oidc.params; | ||
module.exports = provider => async function checkClaims(ctx, next) { | ||
const params = ctx.oidc.params; | ||
if (params.claims !== undefined && instance(provider).configuration('features.claimsParameter')) { | ||
this.assert(params.response_type !== 'none', new errors.InvalidRequestError( | ||
ctx.assert(params.response_type !== 'none', new errors.InvalidRequestError( | ||
'claims parameter should not be combined with response_type none')); | ||
@@ -32,28 +32,28 @@ | ||
} catch (err) { | ||
return this.throw(new errors.InvalidRequestError('could not parse the claims parameter JSON')); | ||
return ctx.throw(new errors.InvalidRequestError('could not parse the claims parameter JSON')); | ||
} | ||
})(); | ||
this.assert(_.isPlainObject(claims), | ||
ctx.assert(_.isPlainObject(claims), | ||
new errors.InvalidRequestError('claims parameter should be a JSON object')); | ||
this.assert(claims.userinfo !== undefined || claims.id_token !== undefined, | ||
ctx.assert(claims.userinfo !== undefined || claims.id_token !== undefined, | ||
new errors.InvalidRequestError( | ||
'claims parameter should have userinfo or id_token properties')); | ||
this.assert(claims.userinfo === undefined || _.isPlainObject(claims.userinfo), | ||
ctx.assert(claims.userinfo === undefined || _.isPlainObject(claims.userinfo), | ||
new errors.InvalidRequestError('claims.userinfo should be an object')); | ||
this.assert(claims.id_token === undefined || _.isPlainObject(claims.id_token), | ||
ctx.assert(claims.id_token === undefined || _.isPlainObject(claims.id_token), | ||
new errors.InvalidRequestError('claims.id_token should be an object')); | ||
this.assert(params.response_type !== 'id_token' || !claims.userinfo, | ||
ctx.assert(params.response_type !== 'id_token' || !claims.userinfo, | ||
new errors.InvalidRequestError( | ||
'claims.userinfo should not be used if access_token is not issued')); | ||
this.oidc.claims = claims; | ||
ctx.oidc.claims = claims; | ||
} | ||
if (params.max_age || this.oidc.client.requireAuthTime) { | ||
_.merge(this.oidc.claims, { id_token: { auth_time: { essential: true } } }); | ||
if (params.max_age || ctx.oidc.client.requireAuthTime) { | ||
_.merge(ctx.oidc.claims, { id_token: { auth_time: { essential: true } } }); | ||
} | ||
@@ -64,6 +64,6 @@ | ||
if (acrValues) { | ||
_.merge(this.oidc.claims, { id_token: { acr: { values: acrValues.split(' ') } } }); | ||
_.merge(ctx.oidc.claims, { id_token: { acr: { values: acrValues.split(' ') } } }); | ||
} | ||
yield next; | ||
await next(); | ||
}; |
@@ -13,14 +13,14 @@ 'use strict'; | ||
*/ | ||
module.exports = provider => function* checkClient(next) { | ||
const clientId = this.oidc.params.client_id; | ||
this.assert(clientId, new errors.InvalidRequestError('missing required parameter client_id')); | ||
module.exports = provider => async function checkClient(ctx, next) { | ||
const clientId = ctx.oidc.params.client_id; | ||
ctx.assert(clientId, new errors.InvalidRequestError('missing required parameter client_id')); | ||
const Client = provider.Client; | ||
const client = yield Client.find(String(clientId)); | ||
const client = await Client.find(String(clientId)); | ||
this.assert(client, new errors.InvalidClientError()); | ||
ctx.assert(client, new errors.InvalidClientError()); | ||
this.oidc.client = client; | ||
ctx.oidc.client = client; | ||
yield next; | ||
await next(); | ||
}; |
@@ -10,9 +10,9 @@ 'use strict'; | ||
*/ | ||
module.exports = function* checkOpenIdPresent(next) { | ||
const scopes = this.oidc.params.scope.split(' '); | ||
module.exports = async function checkOpenIdPresent(ctx, next) { | ||
const scopes = ctx.oidc.params.scope.split(' '); | ||
this.assert(scopes.indexOf('openid') !== -1, | ||
ctx.assert(scopes.indexOf('openid') !== -1, | ||
new errors.InvalidRequestError('openid is required scope')); | ||
yield next; | ||
await next(); | ||
}; |
@@ -11,10 +11,10 @@ 'use strict'; | ||
*/ | ||
module.exports = function* checkPixy(next) { | ||
const params = this.oidc.params; | ||
module.exports = async function checkPixy(ctx, next) { | ||
const params = ctx.oidc.params; | ||
if (params.code_challenge_method) { | ||
this.assert(ALLOWED.indexOf(params.code_challenge_method) !== -1, | ||
ctx.assert(ALLOWED.indexOf(params.code_challenge_method) !== -1, | ||
new errors.InvalidRequestError('not supported value of code_challenge_method')); | ||
this.assert(params.code_challenge, | ||
ctx.assert(params.code_challenge, | ||
new errors.InvalidRequestError('code_challenge must be provided with code_challenge_method')); | ||
@@ -27,3 +27,3 @@ } | ||
yield next; | ||
await next(); | ||
}; |
@@ -13,15 +13,15 @@ 'use strict'; | ||
*/ | ||
module.exports = provider => function* checkPrompt(next) { | ||
if (this.oidc.params.prompt !== undefined) { | ||
const prompts = this.oidc.prompts; | ||
module.exports = provider => async function checkPrompt(ctx, next) { | ||
if (ctx.oidc.params.prompt !== undefined) { | ||
const prompts = ctx.oidc.prompts; | ||
const unsupported = _.difference(prompts, instance(provider).configuration('prompts')); | ||
this.assert(_.isEmpty(unsupported), new errors.InvalidRequestError( | ||
ctx.assert(_.isEmpty(unsupported), new errors.InvalidRequestError( | ||
`invalid prompt value(s) provided. (${unsupported.join(',')})`)); | ||
this.assert(prompts.indexOf('none') === -1 || prompts.length === 1, | ||
ctx.assert(prompts.indexOf('none') === -1 || prompts.length === 1, | ||
new errors.InvalidRequestError('prompt none must only be used alone')); | ||
} | ||
yield next; | ||
await next(); | ||
}; |
@@ -10,8 +10,8 @@ 'use strict'; | ||
*/ | ||
module.exports = function* checkRedirectUri(next) { | ||
this.oidc.redirectUriCheckPerformed = true; | ||
this.assert(this.oidc.client.redirectUriAllowed(this.oidc.params.redirect_uri), | ||
module.exports = async function checkRedirectUri(ctx, next) { | ||
ctx.oidc.redirectUriCheckPerformed = true; | ||
ctx.assert(ctx.oidc.client.redirectUriAllowed(ctx.oidc.params.redirect_uri), | ||
new errors.RedirectUriMismatchError()); | ||
yield next; | ||
await next(); | ||
}; |
@@ -22,4 +22,4 @@ 'use strict'; | ||
*/ | ||
module.exports = function* checkResponseMode(next) { | ||
const params = this.oidc.params; | ||
module.exports = async function checkResponseMode(ctx, next) { | ||
const params = ctx.oidc.params; | ||
@@ -31,3 +31,3 @@ if (params.response_mode === undefined) { | ||
this.assert(!invalid, new errors.InvalidRequestError( | ||
ctx.assert(!invalid, new errors.InvalidRequestError( | ||
'response_mode not allowed for this response_type')); | ||
@@ -37,3 +37,3 @@ } | ||
yield next; | ||
await next(); | ||
}; |
@@ -12,12 +12,12 @@ 'use strict'; | ||
*/ | ||
module.exports = provider => function* checkResponseType(next) { | ||
const params = this.oidc.params; | ||
module.exports = provider => async function checkResponseType(ctx, next) { | ||
const params = ctx.oidc.params; | ||
const supported = instance(provider).configuration('responseTypes'); | ||
const valid = supported.indexOf(params.response_type) !== -1; | ||
this.assert(valid, 400, 'unsupported_response_type', { | ||
ctx.assert(valid, 400, 'unsupported_response_type', { | ||
error_description: `response_type not supported. (${params.response_type})`, | ||
}); | ||
this.assert(this.oidc.client.responseTypeAllowed(params.response_type), | ||
ctx.assert(ctx.oidc.client.responseTypeAllowed(params.response_type), | ||
400, 'restricted_response_type', { | ||
@@ -27,3 +27,3 @@ error_description: 'response_type not allowed for this client', | ||
yield next; | ||
await next(); | ||
}; |
@@ -12,12 +12,12 @@ 'use strict'; | ||
*/ | ||
module.exports = provider => function* checkScope(next) { | ||
const scopes = this.oidc.params.scope.split(' '); | ||
const responseType = this.oidc.params.response_type; | ||
const prompts = this.oidc.prompts; | ||
module.exports = provider => async function checkScope(ctx, next) { | ||
const scopes = ctx.oidc.params.scope.split(' '); | ||
const responseType = ctx.oidc.params.response_type; | ||
const prompts = ctx.oidc.prompts; | ||
const unsupported = _.difference(scopes, instance(provider).configuration('scopes')); | ||
this.assert(_.isEmpty(unsupported), new errors.InvalidRequestError( | ||
ctx.assert(_.isEmpty(unsupported), new errors.InvalidRequestError( | ||
`invalid scope value(s) provided. (${unsupported.join(',')})`)); | ||
this.assert(scopes.indexOf('openid') !== -1, | ||
ctx.assert(scopes.indexOf('openid') !== -1, | ||
new errors.InvalidRequestError('openid is required scope')); | ||
@@ -35,6 +35,6 @@ | ||
if (responseType.includes('code')) { | ||
this.assert(prompts.indexOf('consent') !== -1, | ||
ctx.assert(prompts.indexOf('consent') !== -1, | ||
new errors.InvalidRequestError('offline_access scope requires consent prompt')); | ||
} else { | ||
this.oidc.params.scope = _.pull(scopes, 'offline_access').join(' '); | ||
ctx.oidc.params.scope = _.pull(scopes, 'offline_access').join(' '); | ||
} | ||
@@ -44,3 +44,3 @@ } | ||
yield next; | ||
await next(); | ||
}; |
@@ -14,7 +14,7 @@ 'use strict'; | ||
*/ | ||
module.exports = provider => function* decodeRequest(next) { | ||
const params = this.oidc.params; | ||
module.exports = provider => async function decodeRequest(ctx, next) { | ||
const params = ctx.oidc.params; | ||
if (params.request === undefined) { | ||
yield next; | ||
await next(); | ||
return; | ||
@@ -28,3 +28,3 @@ } | ||
params.request.split('.').length === 5) { | ||
const decrypted = yield JWT.decrypt(params.request, instance(provider).keystore); | ||
const decrypted = await JWT.decrypt(params.request, instance(provider).keystore); | ||
params.request = decrypted.payload.toString('utf8'); | ||
@@ -34,3 +34,3 @@ } | ||
} catch (err) { | ||
this.throw(400, 'invalid_request_object', { | ||
ctx.throw(400, 'invalid_request_object', { | ||
error_description: `could not parse request_uri as valid JWT (${err.message})`, | ||
@@ -42,3 +42,3 @@ }); | ||
this.assert(payload.request === undefined && | ||
ctx.assert(payload.request === undefined && | ||
payload.request_uri === undefined, 400, 'invalid_request_object', { | ||
@@ -50,3 +50,3 @@ error_description: 'request object must not contain request or request_uri properties', | ||
this.assert(payload.response_type === undefined || | ||
ctx.assert(payload.response_type === undefined || | ||
payload.response_type === params.response_type, 400, | ||
@@ -57,3 +57,3 @@ 'invalid_request_object', { | ||
this.assert(payload.client_id === undefined || | ||
ctx.assert(payload.client_id === undefined || | ||
payload.client_id === params.client_id, 400, 'invalid_request_object', { | ||
@@ -63,7 +63,7 @@ error_description: 'request client_id must equal the one in request parameters', | ||
const client = this.oidc.client; | ||
const client = ctx.oidc.client; | ||
const alg = decoded.header.alg; | ||
if (client.requestObjectSigningAlg) { | ||
this.assert(client.requestObjectSigningAlg === alg, 400, | ||
ctx.assert(client.requestObjectSigningAlg === alg, 400, | ||
'invalid_request_object', { | ||
@@ -76,5 +76,5 @@ error_description: 'the preregistered alg must be used in request or request_uri', | ||
try { | ||
yield JWT.verify(params.request, client.keystore); | ||
await JWT.verify(params.request, client.keystore); | ||
} catch (err) { | ||
this.throw(400, 'invalid_request_object', { | ||
ctx.throw(400, 'invalid_request_object', { | ||
error_description: `could not validate request object signature (${err.message})`, | ||
@@ -88,3 +88,3 @@ }); | ||
yield next; | ||
await next(); | ||
}; |
@@ -18,14 +18,14 @@ 'use strict'; | ||
return function* fetchRequestUri(next) { | ||
const params = this.oidc.params; | ||
return async function fetchRequestUri(ctx, next) { | ||
const params = ctx.oidc.params; | ||
if (params.request_uri !== undefined) { | ||
this.assert(params.request_uri.length <= 512, 400, 'invalid_request_uri', { | ||
ctx.assert(params.request_uri.length <= 512, 400, 'invalid_request_uri', { | ||
error_description: 'the request_uri MUST NOT exceed 512 characters' }); | ||
this.assert(params.request_uri.startsWith('https://'), 400, | ||
ctx.assert(params.request_uri.startsWith('https://'), 400, | ||
'invalid_request_uri', { error_description: 'request_uri must use https scheme' }); | ||
if (this.oidc.client.requestUris) { | ||
this.assert(this.oidc.client.requestUriAllowed(params.request_uri), 400, | ||
if (ctx.oidc.client.requestUris) { | ||
ctx.assert(ctx.oidc.client.requestUriAllowed(params.request_uri), 400, | ||
'invalid_request_uri', { error_description: 'not registered request_uri provided' }); | ||
@@ -35,6 +35,6 @@ } | ||
try { | ||
params.request = yield cache.resolve(params.request_uri); | ||
params.request = await cache.resolve(params.request_uri); | ||
params.request_uri = undefined; | ||
} catch (err) { | ||
this.throw(400, 'invalid_request_uri', { | ||
ctx.throw(400, 'invalid_request_uri', { | ||
error_description: `could not load or parse request_uri (${err.message})` }); | ||
@@ -44,4 +44,4 @@ } | ||
yield next; | ||
await next(); | ||
}; | ||
}; |
@@ -14,5 +14,4 @@ 'use strict'; | ||
return function* interactions(next) { | ||
const ctx = this.oidc; | ||
const clientName = _.get(ctx.client, 'name', 'Client'); | ||
return async function interactions(ctx, next) { | ||
const clientName = _.get(ctx.oidc.client, 'name', 'Client'); | ||
@@ -23,3 +22,3 @@ const interactionChecks = [ | ||
() => { | ||
if (!ctx.session.accountId()) { | ||
if (!ctx.oidc.session.accountId()) { | ||
return { | ||
@@ -37,3 +36,3 @@ error: 'login_required', | ||
() => { | ||
if (ctx.prompted('login')) { | ||
if (ctx.oidc.prompted('login')) { | ||
return { | ||
@@ -51,3 +50,3 @@ error: 'login_required', | ||
() => { | ||
if (ctx.session.past(ctx.params.max_age)) { | ||
if (ctx.oidc.session.past(ctx.oidc.params.max_age)) { | ||
return { | ||
@@ -65,5 +64,5 @@ error: 'login_required', | ||
() => { | ||
if (_.has(ctx.claims, 'id_token.sub.value')) { | ||
const subject = Claims.sub(ctx.session.accountId(), ctx.client.sectorIdentifier); | ||
if (ctx.claims.id_token.sub.value !== subject) { | ||
if (_.has(ctx.oidc.claims, 'id_token.sub.value')) { | ||
const subject = Claims.sub(ctx.oidc.session.accountId(), ctx.oidc.client.sectorIdentifier); // eslint-disable-line max-len | ||
if (ctx.oidc.claims.id_token.sub.value !== subject) { | ||
return { | ||
@@ -84,5 +83,5 @@ error: 'login_required', | ||
() => { | ||
const request = _.get(ctx.claims, 'id_token.acr', {}); | ||
const request = _.get(ctx.oidc.claims, 'id_token.acr', {}); | ||
if (request && request.essential && request.values) { | ||
if (request.values.indexOf(ctx.acr) === -1) { | ||
if (request.values.indexOf(ctx.oidc.acr) === -1) { | ||
return { | ||
@@ -101,5 +100,5 @@ error: 'login_required', | ||
() => { | ||
const request = _.get(ctx.claims, 'id_token.acr', {}); | ||
const request = _.get(ctx.oidc.claims, 'id_token.acr', {}); | ||
if (request && request.essential && request.value) { | ||
if (request.value !== ctx.acr) { | ||
if (request.value !== ctx.oidc.acr) { | ||
return { | ||
@@ -118,4 +117,4 @@ error: 'login_required', | ||
() => { | ||
const missed = _.find(ctx.prompts, (prompt) => { | ||
if (prompt !== 'none' && ctx.prompted(prompt)) { | ||
const missed = _.find(ctx.oidc.prompts, (prompt) => { | ||
if (prompt !== 'none' && ctx.oidc.prompted(prompt)) { | ||
return true; | ||
@@ -143,3 +142,3 @@ } | ||
() => { | ||
if (!ctx.session.sidFor(ctx.client.clientId)) { | ||
if (!ctx.oidc.session.sidFor(ctx.oidc.client.clientId)) { | ||
return { | ||
@@ -156,7 +155,7 @@ error: 'consent_required', | ||
() => { | ||
if (ctx.params.id_token_hint !== undefined) { | ||
const actualSub = Claims.sub(ctx.session.accountId(), ctx.client.sectorIdentifier); | ||
if (ctx.oidc.params.id_token_hint !== undefined) { | ||
const actualSub = Claims.sub(ctx.oidc.session.accountId(), ctx.oidc.client.sectorIdentifier); // eslint-disable-line max-len | ||
const IdToken = provider.IdToken; | ||
return IdToken.validate(ctx.params.id_token_hint, ctx.client).then((decoded) => { | ||
return IdToken.validate(ctx.oidc.params.id_token_hint, ctx.oidc.client).then((decoded) => { // eslint-disable-line max-len | ||
if (decoded.payload.sub !== actualSub) { | ||
@@ -186,3 +185,3 @@ return { | ||
interaction = fn(); | ||
if (interaction instanceof Promise) interaction = yield interaction; | ||
if (interaction instanceof Promise) interaction = await interaction; | ||
if (interaction) break; | ||
@@ -198,26 +197,26 @@ } | ||
// if interaction needed but prompt=none => throw; | ||
this.assert(!ctx.prompted('none'), 302, interaction.error, { | ||
ctx.assert(!ctx.oidc.prompted('none'), 302, interaction.error, { | ||
error_description: interaction.error_description, | ||
}); | ||
const destination = instance(provider).configuration('interactionUrl').call(this, interaction); | ||
const destination = instance(provider).configuration('interactionUrl').call(ctx, interaction); | ||
const cookieOptions = instance(provider).configuration('cookies.short'); | ||
this.cookies.set('_grant', j({ | ||
ctx.cookies.set('_grant', j({ | ||
interaction, | ||
uuid: ctx.uuid, | ||
returnTo: ctx.urlFor('resume', { grant: ctx.uuid }), | ||
params: ctx.params, | ||
uuid: ctx.oidc.uuid, | ||
returnTo: ctx.oidc.urlFor('resume', { grant: ctx.oidc.uuid }), | ||
params: ctx.oidc.params, | ||
}), Object.assign({ path: url.parse(destination).pathname }, cookieOptions)); | ||
this.cookies.set('_grant', j(ctx.params), Object.assign({ | ||
path: provider.pathFor('resume', { grant: ctx.uuid }), | ||
ctx.cookies.set('_grant', j(ctx.oidc.params), Object.assign({ | ||
path: provider.pathFor('resume', { grant: ctx.oidc.uuid }), | ||
}, cookieOptions)); | ||
provider.emit('interaction.started', interaction, this); | ||
return this.redirect(destination); | ||
provider.emit('interaction.started', interaction, ctx); | ||
return ctx.redirect(destination); | ||
} | ||
return yield next; | ||
return await next(); | ||
}; | ||
}; |
@@ -6,11 +6,11 @@ 'use strict'; | ||
*/ | ||
module.exports = provider => function* loadAccount(next) { | ||
const accountId = this.oidc.session.accountId(); | ||
module.exports = provider => async function loadAccount(ctx, next) { | ||
const accountId = ctx.oidc.session.accountId(); | ||
if (accountId) { | ||
const Account = provider.Account; | ||
this.oidc.account = yield Account.findById(accountId); | ||
ctx.oidc.account = await Account.findById(accountId); | ||
} | ||
yield next; | ||
await next(); | ||
}; |
@@ -7,4 +7,4 @@ 'use strict'; | ||
*/ | ||
module.exports = function* noRedirectUriClients(next) { | ||
const oidc = this.oidc; | ||
module.exports = async function noRedirectUriClients(ctx, next) { | ||
const oidc = ctx.oidc; | ||
@@ -15,3 +15,3 @@ if (oidc.params.redirect_uri === undefined && oidc.client.redirectUris.length === 1) { | ||
yield next; | ||
await next(); | ||
}; |
@@ -11,5 +11,5 @@ 'use strict'; | ||
*/ | ||
module.exports = function* oauthRequired(next) { | ||
module.exports = async function oauthRequired(ctx, next) { | ||
// Validate: required oauth params | ||
const params = this.oidc.params; | ||
const params = ctx.oidc.params; | ||
const missing = _.difference([ | ||
@@ -21,6 +21,6 @@ 'response_type', | ||
this.assert(_.isEmpty(missing), new errors.InvalidRequestError( | ||
ctx.assert(_.isEmpty(missing), new errors.InvalidRequestError( | ||
`missing required parameter(s) ${missing.join(',')}`)); | ||
yield next; | ||
await next(); | ||
}; |
@@ -12,5 +12,5 @@ 'use strict'; | ||
*/ | ||
module.exports = function* oidcRequired(next) { | ||
module.exports = async function oidcRequired(ctx, next) { | ||
// Validate: required params | ||
const params = this.oidc.params; | ||
const params = ctx.oidc.params; | ||
const missing = []; | ||
@@ -25,6 +25,6 @@ | ||
this.assert(_.isEmpty(missing), new errors.InvalidRequestError( | ||
ctx.assert(_.isEmpty(missing), new errors.InvalidRequestError( | ||
`missing required parameter(s) ${missing.join(',')}`)); | ||
yield next; | ||
await next(); | ||
}; |
@@ -12,3 +12,3 @@ 'use strict'; | ||
function* tokenHandler() { | ||
async function tokenHandler() { | ||
const at = new AccessToken({ | ||
@@ -24,3 +24,3 @@ accountId: this.oidc.session.accountId(), | ||
return { | ||
access_token: yield at.save(), | ||
access_token: await at.save(), | ||
expires_in: AccessToken.expiresIn, | ||
@@ -31,3 +31,3 @@ token_type: 'Bearer', | ||
function* codeHandler() { | ||
async function codeHandler() { | ||
const ac = new AuthorizationCode({ | ||
@@ -52,8 +52,8 @@ accountId: this.oidc.session.accountId(), | ||
return { code: yield ac.save() }; | ||
return { code: await ac.save() }; | ||
} | ||
function* idTokenHandler() { | ||
async function idTokenHandler() { | ||
const token = new IdToken( | ||
Object.assign({}, yield Promise.resolve(this.oidc.account.claims()), { | ||
Object.assign({}, await Promise.resolve(this.oidc.account.claims()), { | ||
acr: this.oidc.acr, | ||
@@ -100,5 +100,5 @@ amr: this.oidc.amr, | ||
*/ | ||
return function* processResponseTypes() { | ||
const responses = this.oidc.params.response_type.split(' '); | ||
const out = Object.assign.apply({}, yield responses.map(callHandlers.bind(this))); | ||
return async function processResponseTypes(ctx) { | ||
const responses = ctx.oidc.params.response_type.split(' '); | ||
const out = Object.assign.apply({}, await Promise.all(responses.map(callHandlers.bind(ctx)))); | ||
@@ -114,3 +114,3 @@ if (out.access_token && out.id_token) { | ||
if (out.id_token) { | ||
out.id_token = yield out.id_token.sign(this.oidc.client); | ||
out.id_token = await out.id_token.sign(ctx.oidc.client); | ||
} | ||
@@ -117,0 +117,0 @@ |
@@ -27,17 +27,17 @@ 'use strict'; | ||
*/ | ||
module.exports = provider => function* respond(next) { | ||
const out = yield next; | ||
module.exports = provider => async function respond(ctx, next) { | ||
const out = await next(); | ||
if (this.oidc.params.state !== undefined) out.state = this.oidc.params.state; | ||
if (ctx.oidc.params.state !== undefined) out.state = ctx.oidc.params.state; | ||
provider.emit('authorization.success', this); | ||
provider.emit('authorization.success', ctx); | ||
if (instance(provider).configuration('features.sessionManagement')) { | ||
const salt = crypto.randomBytes(8).toString('hex'); | ||
const state = String(this.oidc.session.authTime()); | ||
const state = String(ctx.oidc.session.authTime()); | ||
const shasum = crypto.createHash('sha256') | ||
.update(this.oidc.params.client_id) | ||
.update(ctx.oidc.params.client_id) | ||
.update(' ') | ||
.update(locationOrigin(this.oidc.params.redirect_uri)) | ||
.update(locationOrigin(ctx.oidc.params.redirect_uri)) | ||
.update(' ') | ||
@@ -50,4 +50,4 @@ .update(state) | ||
const stateCookieName = `_state.${this.oidc.params.client_id}`; | ||
this.cookies.set(stateCookieName, state, | ||
const stateCookieName = `_state.${ctx.oidc.params.client_id}`; | ||
ctx.cookies.set(stateCookieName, state, | ||
Object.assign({}, instance(provider).configuration('cookies.long'), { httpOnly: false })); | ||
@@ -58,11 +58,11 @@ | ||
if (instance(provider).responseModes.has(this.oidc.params.response_mode)) { | ||
instance(provider).responseModes.get(this.oidc.params.response_mode) | ||
.call(this, this.oidc.params.redirect_uri, out); | ||
} else if (this.oidc.params.response_mode === 'form_post') { | ||
formPost.call(this, this.oidc.params.redirect_uri, out); | ||
if (instance(provider).responseModes.has(ctx.oidc.params.response_mode)) { | ||
instance(provider).responseModes.get(ctx.oidc.params.response_mode) | ||
.call(ctx, ctx.oidc.params.redirect_uri, out); | ||
} else if (ctx.oidc.params.response_mode === 'form_post') { | ||
formPost.call(ctx, ctx.oidc.params.redirect_uri, out); | ||
} else { | ||
const uri = redirectUri(this.oidc.params.redirect_uri, out, this.oidc.params.response_mode); | ||
this.redirect(uri); | ||
const uri = redirectUri(ctx.oidc.params.redirect_uri, out, ctx.oidc.params.response_mode); | ||
ctx.redirect(uri); | ||
} | ||
}; |
@@ -15,8 +15,8 @@ 'use strict'; | ||
*/ | ||
module.exports = provider => function* throwNotSupported(next) { | ||
const params = this.oidc.params; | ||
module.exports = provider => async function throwNotSupported(ctx, next) { | ||
const params = ctx.oidc.params; | ||
const feature = instance(provider).configuration('features'); | ||
if (!feature.request && params.request !== undefined) { | ||
this.throw(400, 'request_not_supported', { | ||
ctx.throw(400, 'request_not_supported', { | ||
error_description: 'request parameter provided but not supported', | ||
@@ -27,3 +27,3 @@ }); | ||
if (!feature.requestUri && params.request_uri !== undefined) { | ||
this.throw(400, 'request_uri_not_supported', { | ||
ctx.throw(400, 'request_uri_not_supported', { | ||
error_description: 'request_uri parameter provided but not supported', | ||
@@ -34,3 +34,3 @@ }); | ||
if (params.registration !== undefined) { | ||
this.throw(400, 'registration_not_supported', { | ||
ctx.throw(400, 'registration_not_supported', { | ||
error_description: 'registration parameter provided but not supported', | ||
@@ -40,7 +40,7 @@ }); | ||
this.assert(params.request === undefined || | ||
ctx.assert(params.request === undefined || | ||
params.request_uri === undefined, new errors.InvalidRequestError( | ||
'request and request_uri parameters MUST NOT be used together')); | ||
yield next; | ||
await next(); | ||
}; |
@@ -6,7 +6,7 @@ 'use strict'; | ||
module.exports = function certificatesAction(provider) { | ||
return function* renderCertificates(next) { | ||
this.body = instance(provider).keystore.toJSON(); | ||
return async function renderCertificates(ctx, next) { | ||
ctx.body = instance(provider).keystore.toJSON(); | ||
yield next; | ||
await next(); | ||
}; | ||
}; |
'use strict'; | ||
module.exports = function checkSessionAction() { | ||
return function* checkSessionIframe(next) { | ||
const debug = this.query.debug !== undefined; | ||
this.type = 'html'; | ||
this.body = `<!DOCTYPE html> | ||
return async function checkSessionIframe(ctx, next) { | ||
const debug = ctx.query.debug !== undefined; | ||
ctx.type = 'html'; | ||
ctx.body = `<!DOCTYPE html> | ||
<html> | ||
@@ -69,4 +69,4 @@ <head lang="en"> | ||
</html>`; | ||
yield next; | ||
await next(); | ||
}; | ||
}; |
@@ -9,6 +9,6 @@ 'use strict'; | ||
return function* renderConfiguration(next) { | ||
this.body = { | ||
return async function renderConfiguration(ctx, next) { | ||
ctx.body = { | ||
acr_values_supported: config.acrValues.length ? config.acrValues : undefined, | ||
authorization_endpoint: this.oidc.urlFor('authorization'), | ||
authorization_endpoint: ctx.oidc.urlFor('authorization'), | ||
claims_parameter_supported: !!config.features.claimsParameter, | ||
@@ -19,5 +19,5 @@ claims_supported: config.claimsSupported, | ||
issuer: provider.issuer, | ||
jwks_uri: this.oidc.urlFor('certificates'), | ||
jwks_uri: ctx.oidc.urlFor('certificates'), | ||
registration_endpoint: config.features.registration ? | ||
this.oidc.urlFor('registration') : undefined, | ||
ctx.oidc.urlFor('registration') : undefined, | ||
request_object_signing_alg_values_supported: | ||
@@ -38,10 +38,10 @@ config.features.request || config.features.requestUri ? | ||
subject_types_supported: config.subjectTypes, | ||
token_endpoint: this.oidc.urlFor('token'), | ||
token_endpoint: ctx.oidc.urlFor('token'), | ||
token_endpoint_auth_methods_supported: config.tokenEndpointAuthMethods, | ||
token_endpoint_auth_signing_alg_values_supported: config.tokenEndpointAuthSigningAlgValues, | ||
token_introspection_endpoint: config.features.introspection ? | ||
this.oidc.urlFor('introspection') : undefined, | ||
ctx.oidc.urlFor('introspection') : undefined, | ||
token_revocation_endpoint: config.features.revocation ? | ||
this.oidc.urlFor('revocation') : undefined, | ||
userinfo_endpoint: this.oidc.urlFor('userinfo'), | ||
ctx.oidc.urlFor('revocation') : undefined, | ||
userinfo_endpoint: ctx.oidc.urlFor('userinfo'), | ||
userinfo_signing_alg_values_supported: config.userinfoSigningAlgValues, | ||
@@ -51,11 +51,11 @@ }; | ||
if (config.features.encryption) { | ||
this.body.id_token_encryption_alg_values_supported = config.idTokenEncryptionAlgValues; | ||
this.body.id_token_encryption_enc_values_supported = config.idTokenEncryptionEncValues; | ||
this.body.userinfo_encryption_alg_values_supported = config.userinfoEncryptionAlgValues; | ||
this.body.userinfo_encryption_enc_values_supported = config.userinfoEncryptionEncValues; | ||
ctx.body.id_token_encryption_alg_values_supported = config.idTokenEncryptionAlgValues; | ||
ctx.body.id_token_encryption_enc_values_supported = config.idTokenEncryptionEncValues; | ||
ctx.body.userinfo_encryption_alg_values_supported = config.userinfoEncryptionAlgValues; | ||
ctx.body.userinfo_encryption_enc_values_supported = config.userinfoEncryptionEncValues; | ||
if (config.features.request || config.features.requestUri) { | ||
this.body.request_object_encryption_alg_values_supported = | ||
ctx.body.request_object_encryption_alg_values_supported = | ||
config.requestObjectEncryptionAlgValues; | ||
this.body.request_object_encryption_enc_values_supported = | ||
ctx.body.request_object_encryption_enc_values_supported = | ||
config.requestObjectEncryptionEncValues; | ||
@@ -66,15 +66,15 @@ } | ||
if (config.features.sessionManagement) { | ||
this.body.check_session_iframe = this.oidc.urlFor('check_session'); | ||
this.body.end_session_endpoint = this.oidc.urlFor('end_session'); | ||
ctx.body.check_session_iframe = ctx.oidc.urlFor('check_session'); | ||
ctx.body.end_session_endpoint = ctx.oidc.urlFor('end_session'); | ||
if (config.features.backchannelLogout) { | ||
this.body.backchannel_logout_supported = true; | ||
this.body.backchannel_logout_session_supported = true; | ||
ctx.body.backchannel_logout_supported = true; | ||
ctx.body.backchannel_logout_session_supported = true; | ||
} | ||
} | ||
_.defaults(this.body, config.discovery); | ||
_.defaults(ctx.body, config.discovery); | ||
yield next; | ||
await next(); | ||
}; | ||
}; |
@@ -20,5 +20,5 @@ 'use strict'; | ||
module.exports = function endSessionAction(provider) { | ||
const loadClient = function* loadClient(clientId) { | ||
async function loadClient(clientId) { | ||
// Validate: client_id param | ||
const client = yield provider.Client.find(clientId); | ||
const client = await provider.Client.find(clientId); | ||
@@ -28,3 +28,3 @@ this.assert(client, new errors.InvalidClientError('unrecognized azp or aud claims')); | ||
return client; | ||
}; | ||
} | ||
@@ -37,4 +37,4 @@ return { | ||
function* endSessionChecks(next) { | ||
const params = this.oidc.params; | ||
async function endSessionChecks(ctx, next) { | ||
const params = ctx.oidc.params; | ||
@@ -49,3 +49,3 @@ if (params.id_token_hint) { | ||
} catch (err) { | ||
return this.throw(new errors.InvalidRequestError( | ||
return ctx.throw(new errors.InvalidRequestError( | ||
`could not decode id_token_hint (${err.message})`)); | ||
@@ -56,6 +56,6 @@ } | ||
try { | ||
client = yield loadClient.call(this, clientId); | ||
yield provider.IdToken.validate(params.id_token_hint, client); | ||
client = await loadClient.call(ctx, clientId); | ||
await provider.IdToken.validate(params.id_token_hint, client); | ||
} catch (err) { | ||
this.throw(new errors.InvalidRequestError( | ||
ctx.throw(new errors.InvalidRequestError( | ||
`could not validate id_token_hint (${err.message})`)); | ||
@@ -65,7 +65,7 @@ } | ||
if (params.post_logout_redirect_uri) { | ||
this.assert(client.postLogoutRedirectUriAllowed(params.post_logout_redirect_uri), | ||
ctx.assert(client.postLogoutRedirectUriAllowed(params.post_logout_redirect_uri), | ||
new errors.InvalidRequestError('post_logout_redirect_uri not registered')); | ||
} | ||
this.oidc.client = client; | ||
ctx.oidc.client = client; | ||
} else { | ||
@@ -75,22 +75,22 @@ params.post_logout_redirect_uri = undefined; | ||
yield next; | ||
await next(); | ||
}, | ||
function* renderLogout(next) { | ||
async function renderLogout(ctx, next) { | ||
const secret = crypto.randomBytes(24).toString('hex'); | ||
this.oidc.session.logout = { | ||
ctx.oidc.session.logout = { | ||
secret, | ||
clientId: this.oidc.client ? this.oidc.client.clientId : undefined, | ||
postLogoutRedirectUri: this.oidc.params.post_logout_redirect_uri || | ||
clientId: ctx.oidc.client ? ctx.oidc.client.clientId : undefined, | ||
postLogoutRedirectUri: ctx.oidc.params.post_logout_redirect_uri || | ||
instance(provider).configuration('postLogoutRedirectUri'), | ||
}; | ||
this.type = 'html'; | ||
this.status = 200; | ||
ctx.type = 'html'; | ||
ctx.status = 200; | ||
const formhtml = `<form id="op.logoutForm" method="post" action="${provider.pathFor('end_session')}"><input type="hidden" name="xsrf" value="${secret}"/></form>`; | ||
instance(provider).configuration('logoutSource').call(this, formhtml); | ||
instance(provider).configuration('logoutSource').call(ctx, formhtml); | ||
yield next; | ||
await next(); | ||
}, | ||
@@ -106,25 +106,25 @@ ]), | ||
function* checkLogoutToken(next) { | ||
this.assert(this.oidc.session.logout, new errors.InvalidRequestError( | ||
async function checkLogoutToken(ctx, next) { | ||
ctx.assert(ctx.oidc.session.logout, new errors.InvalidRequestError( | ||
'could not find logout details')); | ||
this.assert(this.oidc.session.logout.secret === this.oidc.params.xsrf, | ||
ctx.assert(ctx.oidc.session.logout.secret === ctx.oidc.params.xsrf, | ||
new errors.InvalidRequestError('xsrf token invalid')); | ||
yield next; | ||
await next(); | ||
}, | ||
function* endSession(next) { | ||
const params = this.oidc.session.logout; | ||
async function endSession(ctx, next) { | ||
const params = ctx.oidc.session.logout; | ||
const cookieOpts = _.omit(instance(provider).configuration('cookies.long'), 'maxAge', 'signed'); | ||
if (this.oidc.params.logout) { | ||
if (ctx.oidc.params.logout) { | ||
if (instance(provider).configuration('features.backchannelLogout')) { | ||
try { | ||
const Client = provider.Client; | ||
const clientIds = Object.keys(this.oidc.session.authorizations); | ||
const clientIds = Object.keys(ctx.oidc.session.authorizations); | ||
const logouts = clientIds.map(visitedClientId => Client.find(visitedClientId) | ||
.then((visitedClient) => { | ||
if (visitedClient && visitedClient.backchannelLogoutUri) { | ||
return visitedClient.backchannelLogout(this.oidc.session.accountId(), | ||
this.oidc.session.sidFor(visitedClient.clientId)); | ||
return visitedClient.backchannelLogout(ctx.oidc.session.accountId(), | ||
ctx.oidc.session.sidFor(visitedClient.clientId)); | ||
} | ||
@@ -134,18 +134,18 @@ return undefined; | ||
yield logouts; | ||
await Promise.all(logouts); | ||
} catch (err) {} | ||
} | ||
yield this.oidc.session.destroy(); | ||
await ctx.oidc.session.destroy(); | ||
// get all cookies matching _state.[clientId](.sig) and drop them | ||
this.get('cookie').match(STATES).forEach(val => this.cookies.set(val.slice(0, -1), null, | ||
ctx.get('cookie').match(STATES).forEach(val => ctx.cookies.set(val.slice(0, -1), null, | ||
cookieOpts)); | ||
this.cookies.set('_session', null, cookieOpts); | ||
this.cookies.set('_session.sig', null, cookieOpts); | ||
ctx.cookies.set('_session', null, cookieOpts); | ||
ctx.cookies.set('_session.sig', null, cookieOpts); | ||
} else if (params.clientId) { | ||
delete this.oidc.session.authorizations[params.clientId]; | ||
this.cookies.set(`_state.${params.clientId}`, null, cookieOpts); | ||
this.cookies.set(`_state.${params.clientId}.sig`, null, cookieOpts); | ||
delete ctx.oidc.session.authorizations[params.clientId]; | ||
ctx.cookies.set(`_state.${params.clientId}`, null, cookieOpts); | ||
ctx.cookies.set(`_state.${params.clientId}.sig`, null, cookieOpts); | ||
} | ||
@@ -156,5 +156,5 @@ | ||
this.redirect(uri); | ||
ctx.redirect(uri); | ||
yield next; | ||
await next(); | ||
}, | ||
@@ -161,0 +161,0 @@ ]), |
@@ -10,13 +10,13 @@ 'use strict'; | ||
function* parseCookie(next) { | ||
const cookie = this.cookies.get('_grant'); | ||
this.assert(cookie, 400); | ||
async function parseCookie(ctx, next) { | ||
const cookie = ctx.cookies.get('_grant'); | ||
ctx.assert(cookie, 400); | ||
const fads = JSON.parse(cookie); | ||
this.uuid = this.params.grant; | ||
ctx.uuid = ctx.params.grant; | ||
['interaction', 'params', 'returnTo'].forEach((detail) => { | ||
Object.defineProperty(this, detail, { get() { return fads[detail]; } }); | ||
Object.defineProperty(ctx, detail, { get() { return fads[detail]; } }); | ||
}); | ||
yield next; | ||
await next(); | ||
} | ||
@@ -34,9 +34,9 @@ | ||
parseCookie, | ||
function* interactionRender() { | ||
const client = yield provider.Client.find(this.params.client_id); | ||
this.assert(client, 400); | ||
async function interactionRender(ctx, next) { | ||
const client = await provider.Client.find(ctx.params.client_id); | ||
ctx.assert(client, 400); | ||
const action = router.url('interaction', { grant: this.uuid }); | ||
const action = router.url('interaction', { grant: ctx.uuid }); | ||
const view = (() => { | ||
switch (this.interaction.reason) { | ||
switch (ctx.interaction.reason) { | ||
case 'consent_prompt': | ||
@@ -49,13 +49,14 @@ case 'client_not_authorized': | ||
})(); | ||
const locals = { | ||
action, | ||
client, | ||
returnTo: this.returnTo, | ||
params: this.params, | ||
returnTo: ctx.returnTo, | ||
params: ctx.params, | ||
}; | ||
locals.body = views[view](locals); | ||
this.type = 'html'; | ||
this.body = views.layout(locals); | ||
ctx.type = 'html'; | ||
ctx.body = views.layout(locals); | ||
await next(); | ||
}, | ||
@@ -66,10 +67,10 @@ ]), | ||
parseCookie, | ||
function* interactionSubmit(next) { | ||
switch (this.request.body.view) { // eslint-disable-line default-case | ||
async function interactionSubmit(ctx, next) { | ||
switch (ctx.request.body.view) { // eslint-disable-line default-case | ||
case 'login': | ||
provider.resume(this, this.uuid, { | ||
provider.resume(ctx, ctx.uuid, { | ||
login: { | ||
account: this.request.body.login, | ||
account: ctx.request.body.login, | ||
acr: '1', | ||
remember: !!this.request.body.remember, | ||
remember: !!ctx.request.body.remember, | ||
ts: Math.floor(Date.now() / 1000), | ||
@@ -81,7 +82,7 @@ }, | ||
case 'interaction': | ||
provider.resume(this, this.uuid, { consent: {} }); | ||
provider.resume(ctx, ctx.uuid, { consent: {} }); | ||
break; | ||
} | ||
yield next; | ||
await next(); | ||
}, | ||
@@ -88,0 +89,0 @@ ]), |
@@ -44,12 +44,12 @@ 'use strict'; | ||
function* validateTokenPresence(next) { | ||
presence.call(this, ['token']); | ||
yield next; | ||
async function validateTokenPresence(ctx, next) { | ||
presence.call(ctx, ['token']); | ||
await next(); | ||
}, | ||
function* renderTokenResponse(next) { | ||
async function renderTokenResponse(ctx, next) { | ||
let token; | ||
const params = this.oidc.params; | ||
const params = ctx.oidc.params; | ||
this.body = { active: false }; | ||
ctx.body = { active: false }; | ||
@@ -98,13 +98,13 @@ let tryhard; | ||
try { | ||
token = yield tryhard; | ||
token = await tryhard; | ||
switch (token && token.kind) { | ||
case 'AccessToken': | ||
this.body.token_type = 'access_token'; | ||
ctx.body.token_type = 'access_token'; | ||
break; | ||
case 'ClientCredentials': | ||
this.body.token_type = 'client_credentials'; | ||
ctx.body.token_type = 'client_credentials'; | ||
break; | ||
case 'RefreshToken': | ||
this.body.token_type = 'refresh_token'; | ||
ctx.body.token_type = 'refresh_token'; | ||
break; | ||
@@ -116,14 +116,14 @@ default: | ||
if (!this.body.token_type) { | ||
if (!ctx.body.token_type) { | ||
return; | ||
} | ||
if (token.clientId !== this.oidc.client.clientId) { | ||
this.body.sub = Claims.sub(token.accountId, | ||
(yield provider.Client.find(token.clientId)).sectorIdentifier); | ||
if (token.clientId !== ctx.oidc.client.clientId) { | ||
ctx.body.sub = Claims.sub(token.accountId, | ||
(await provider.Client.find(token.clientId)).sectorIdentifier); | ||
} else { | ||
this.body.sub = Claims.sub(token.accountId, this.oidc.client.sectorIdentifier); | ||
ctx.body.sub = Claims.sub(token.accountId, ctx.oidc.client.sectorIdentifier); | ||
} | ||
Object.assign(this.body, { | ||
Object.assign(ctx.body, { | ||
active: token.isValid, | ||
@@ -139,5 +139,5 @@ client_id: token.clientId, | ||
yield next; | ||
await next(); | ||
}, | ||
]); | ||
}; |
@@ -30,8 +30,8 @@ 'use strict'; | ||
module.exports = function registrationAction(provider) { | ||
function* validateInitialAccessToken(next) { | ||
async function validateInitialAccessToken(ctx, next) { | ||
const setup = instance(provider).configuration('features.registration'); | ||
switch (setup.initialAccessToken && typeof setup.initialAccessToken) { | ||
case 'boolean': { | ||
const initialAccessToken = yield provider.InitialAccessToken.find(this.oidc.bearer); | ||
this.assert(initialAccessToken, new errors.InvalidTokenError()); | ||
const initialAccessToken = await provider.InitialAccessToken.find(ctx.oidc.bearer); | ||
ctx.assert(initialAccessToken, new errors.InvalidTokenError()); | ||
break; | ||
@@ -42,5 +42,5 @@ } | ||
new Buffer(setup.initialAccessToken, 'utf8'), | ||
new Buffer(this.oidc.bearer, 'utf8'), | ||
new Buffer(ctx.oidc.bearer, 'utf8'), | ||
1000); | ||
this.assert(valid, new errors.InvalidTokenError()); | ||
ctx.assert(valid, new errors.InvalidTokenError()); | ||
break; | ||
@@ -51,19 +51,19 @@ } | ||
yield next; | ||
await next(); | ||
} | ||
function* validateRegistrationAccessToken(next) { | ||
const regAccessToken = yield provider.RegistrationAccessToken.find(this.oidc.bearer); | ||
this.assert(regAccessToken, new errors.InvalidTokenError()); | ||
async function validateRegistrationAccessToken(ctx, next) { | ||
const regAccessToken = await provider.RegistrationAccessToken.find(ctx.oidc.bearer); | ||
ctx.assert(regAccessToken, new errors.InvalidTokenError()); | ||
const client = yield provider.Client.find(this.params.clientId); | ||
const client = await provider.Client.find(ctx.params.clientId); | ||
if (!client || client.clientId !== regAccessToken.clientId) { | ||
yield regAccessToken.destroy(); | ||
this.throw(new errors.InvalidTokenError()); | ||
await regAccessToken.destroy(); | ||
ctx.throw(new errors.InvalidTokenError()); | ||
} | ||
this.oidc.client = client; | ||
ctx.oidc.client = client; | ||
yield next; | ||
await next(); | ||
} | ||
@@ -76,3 +76,3 @@ | ||
validateInitialAccessToken, | ||
function* registrationResponse() { | ||
async function registrationResponse(ctx, next) { | ||
const properties = {}; | ||
@@ -83,3 +83,3 @@ const clientId = uuid.v4(); | ||
Object.assign(properties, this.request.body, { | ||
Object.assign(properties, ctx.request.body, { | ||
client_id: clientId, | ||
@@ -98,16 +98,18 @@ client_id_issued_at: epochTime(), | ||
const client = yield instance(provider).clientAdd(properties, true); | ||
const client = await instance(provider).clientAdd(properties, true); | ||
this.body = client.metadata(); | ||
ctx.body = client.metadata(); | ||
Object.assign(this.body, { | ||
registration_client_uri: this.oidc.urlFor('registration_client', { | ||
Object.assign(ctx.body, { | ||
registration_client_uri: ctx.oidc.urlFor('registration_client', { | ||
clientId: properties.client_id, | ||
}), | ||
registration_access_token: yield rat.save(), | ||
registration_access_token: await rat.save(), | ||
}); | ||
this.status = 201; | ||
ctx.status = 201; | ||
provider.emit('registration_create.success', client, this); | ||
provider.emit('registration_create.success', client, ctx); | ||
await next(); | ||
}, | ||
@@ -120,13 +122,13 @@ ]), | ||
function* clientReadResponse(next) { | ||
this.body = this.oidc.client.metadata(); | ||
async function clientReadResponse(ctx, next) { | ||
ctx.body = ctx.oidc.client.metadata(); | ||
Object.assign(this.body, { | ||
registration_access_token: this.oidc.bearer, | ||
registration_client_uri: this.oidc.urlFor('registration_client', { | ||
clientId: this.params.clientId, | ||
Object.assign(ctx.body, { | ||
registration_access_token: ctx.oidc.bearer, | ||
registration_client_uri: ctx.oidc.urlFor('registration_client', { | ||
clientId: ctx.params.clientId, | ||
}), | ||
}); | ||
yield next; | ||
await next(); | ||
}, | ||
@@ -140,37 +142,37 @@ ]), | ||
function* forbiddenFields(next) { | ||
const hit = FORBIDDEN.find(field => this.request.body[field] !== undefined); | ||
async function forbiddenFields(ctx, next) { | ||
const hit = FORBIDDEN.find(field => ctx.request.body[field] !== undefined); | ||
this.assert(!hit, new errors.InvalidRequestError( | ||
ctx.assert(!hit, new errors.InvalidRequestError( | ||
`request MUST NOT include the "${hit}" field`)); | ||
yield next; | ||
await next(); | ||
}, | ||
function* metaChecks(next) { | ||
const hit = _.findKey(this.oidc.client.metadata(), findMissingKey.bind(this)); | ||
async function metaChecks(ctx, next) { | ||
const hit = _.findKey(ctx.oidc.client.metadata(), findMissingKey.bind(ctx)); | ||
this.assert(!hit, new errors.InvalidRequestError(`${hit} must be provided`)); | ||
yield next; | ||
ctx.assert(!hit, new errors.InvalidRequestError(`${hit} must be provided`)); | ||
await next(); | ||
}, | ||
function* equalChecks(next) { | ||
this.assert(this.request.body.client_id === this.oidc.client.clientId, | ||
async function equalChecks(ctx, next) { | ||
ctx.assert(ctx.request.body.client_id === ctx.oidc.client.clientId, | ||
new errors.InvalidRequestError( | ||
'provided client_id does not match the authenticated client\'s one')); | ||
if (this.request.body.client_secret) { | ||
if (ctx.request.body.client_secret) { | ||
const clientSecretValid = constantEquals( | ||
new Buffer(this.request.body.client_secret, 'utf8'), | ||
new Buffer(this.oidc.client.clientSecret, 'utf8'), | ||
new Buffer(ctx.request.body.client_secret, 'utf8'), | ||
new Buffer(ctx.oidc.client.clientSecret, 'utf8'), | ||
1000); | ||
this.assert(clientSecretValid, new errors.InvalidRequestError( | ||
ctx.assert(clientSecretValid, new errors.InvalidRequestError( | ||
'provided client_secret does not match the authenticated client\'s one')); | ||
} | ||
yield next; | ||
await next(); | ||
}, | ||
function* clientUpdateResponse(next) { | ||
if (this.oidc.client.noManage) { | ||
async function clientUpdateResponse(ctx, next) { | ||
if (ctx.oidc.client.noManage) { | ||
throw new errors.InvalidRequestError('this client is not allowed to update its records', | ||
@@ -180,13 +182,13 @@ 403); | ||
provider.emit('registration_update.success', this.oidc.client, this); | ||
provider.emit('registration_update.success', ctx.oidc.client, ctx); | ||
const properties = {}; | ||
Object.assign(properties, this.request.body, { | ||
client_id: this.oidc.client.clientId, | ||
client_id_issued_at: this.oidc.client.clientIdIssuedAt, | ||
Object.assign(properties, ctx.request.body, { | ||
client_id: ctx.oidc.client.clientId, | ||
client_id_issued_at: ctx.oidc.client.clientIdIssuedAt, | ||
}); | ||
const Client = provider.Client; | ||
const secretRequired = !this.oidc.client.clientSecret && Client.needsSecret(properties); | ||
const secretRequired = !ctx.oidc.client.clientSecret && Client.needsSecret(properties); | ||
@@ -200,19 +202,19 @@ if (secretRequired) { | ||
Object.assign(properties, { | ||
client_secret: this.oidc.client.clientSecret, | ||
client_secret_expires_at: this.oidc.client.clientSecretExpiresAt, | ||
client_secret: ctx.oidc.client.clientSecret, | ||
client_secret_expires_at: ctx.oidc.client.clientSecretExpiresAt, | ||
}); | ||
} | ||
const client = yield instance(provider).clientAdd(properties, true); | ||
const client = await instance(provider).clientAdd(properties, true); | ||
this.body = client.metadata(); | ||
ctx.body = client.metadata(); | ||
Object.assign(this.body, { | ||
registration_access_token: this.oidc.bearer, | ||
registration_client_uri: this.oidc.urlFor('registration_client', { | ||
clientId: this.params.clientId, | ||
Object.assign(ctx.body, { | ||
registration_access_token: ctx.oidc.bearer, | ||
registration_client_uri: ctx.oidc.urlFor('registration_client', { | ||
clientId: ctx.params.clientId, | ||
}), | ||
}); | ||
yield next; | ||
await next(); | ||
}, | ||
@@ -225,14 +227,14 @@ ]), | ||
function* clientRemoveResponse(next) { | ||
if (this.oidc.client.noManage) { | ||
async function clientRemoveResponse(ctx, next) { | ||
if (ctx.oidc.client.noManage) { | ||
throw new errors.InvalidRequestError('this client is not allowed to delete itself', 403); | ||
} | ||
yield instance(provider).clientRemove(this.oidc.client.clientId); | ||
await instance(provider).clientRemove(ctx.oidc.client.clientId); | ||
this.status = 204; | ||
ctx.status = 204; | ||
provider.emit('registration_delete.success', this.oidc.client, this); | ||
provider.emit('registration_delete.success', ctx.oidc.client, ctx); | ||
yield next; | ||
await next(); | ||
}, | ||
@@ -239,0 +241,0 @@ ]), |
@@ -32,15 +32,15 @@ 'use strict'; | ||
function* validateTokenPresence(next) { | ||
presence.call(this, ['token']); | ||
yield next; | ||
async function validateTokenPresence(ctx, next) { | ||
presence.call(ctx, ['token']); | ||
await next(); | ||
}, | ||
function* renderTokenResponse(next) { | ||
this.body = {}; | ||
yield next; | ||
async function renderTokenResponse(ctx, next) { | ||
ctx.body = {}; | ||
await next(); | ||
}, | ||
function* revokeToken() { | ||
async function revokeToken(ctx, next) { | ||
let tryhard; | ||
const params = this.oidc.params; | ||
const params = ctx.oidc.params; | ||
@@ -88,3 +88,3 @@ switch (params.token_type_hint) { | ||
try { | ||
token = yield tryhard; | ||
token = await tryhard; | ||
} catch (err) { | ||
@@ -102,15 +102,17 @@ if (err.message === 'invalid_token') { | ||
this.assert(token.clientId === this.oidc.client.clientId, | ||
ctx.assert(token.clientId === ctx.oidc.client.clientId, | ||
new errors.InvalidRequestError('this token does not belong to you')); | ||
yield token.destroy(); | ||
await token.destroy(); | ||
break; | ||
default: | ||
this.throw(400, 'unsupported_token_type', { | ||
ctx.throw(400, 'unsupported_token_type', { | ||
error_description: 'revocation of the presented token type is not supported', | ||
}); | ||
} | ||
await next(); | ||
}, | ||
]); | ||
}; |
@@ -17,18 +17,16 @@ 'use strict'; | ||
function* supportedGrantTypeCheck(next) { | ||
presence.call(this, ['grant_type']); | ||
async function supportedGrantTypeCheck(ctx, next) { | ||
presence.call(ctx, ['grant_type']); | ||
const supported = instance(provider).configuration('grantTypes'); | ||
this.assert(supported.has(this.oidc.params.grant_type), 400, 'unsupported_grant_type', { | ||
error_description: `unsupported grant_type requested (${this.oidc.params.grant_type})`, | ||
ctx.assert(supported.has(ctx.oidc.params.grant_type), 400, 'unsupported_grant_type', { | ||
error_description: `unsupported grant_type requested (${ctx.oidc.params.grant_type})`, | ||
}); | ||
yield next; | ||
await next(); | ||
}, | ||
function* allowedGrantTypeCheck(next) { | ||
const oidc = this.oidc; | ||
this.assert(oidc.client.grantTypeAllowed(oidc.params.grant_type), 400, | ||
async function allowedGrantTypeCheck(ctx, next) { | ||
ctx.assert(ctx.oidc.client.grantTypeAllowed(ctx.oidc.params.grant_type), 400, | ||
'restricted_grant_type', { | ||
@@ -38,7 +36,7 @@ error_description: 'requested grant type is restricted to this client', | ||
yield next; | ||
await next(); | ||
}, | ||
function* callTokenHandler(next) { | ||
const grantType = this.oidc.params.grant_type; | ||
async function callTokenHandler(ctx, next) { | ||
const grantType = ctx.oidc.params.grant_type; | ||
@@ -48,6 +46,6 @@ const grantTypeHandlers = instance(provider).grantTypeHandlers; | ||
if (grantTypeHandlers.has(grantType)) { | ||
yield grantTypeHandlers.get(grantType).call(this, next); | ||
provider.emit('grant.success', this); | ||
await grantTypeHandlers.get(grantType)(ctx, next); | ||
provider.emit('grant.success', ctx); | ||
} else { | ||
this.throw(500, 'server_error', { | ||
ctx.throw(500, 'server_error', { | ||
error_description: 'not implemented grant type', | ||
@@ -54,0 +52,0 @@ }); |
@@ -12,11 +12,11 @@ 'use strict'; | ||
module.exports.handler = function getAuthorizationCodeHandler(provider) { | ||
return function* authorizationCodeResponse(next) { | ||
presence.call(this, ['code', 'redirect_uri']); | ||
return async function authorizationCodeResponse(ctx, next) { | ||
presence.call(ctx, ['code', 'redirect_uri']); | ||
const code = yield provider.AuthorizationCode.find(this.oidc.params.code, { | ||
const code = await provider.AuthorizationCode.find(ctx.oidc.params.code, { | ||
ignoreExpiration: true, | ||
}); | ||
this.assert(code, new errors.InvalidGrantError('authorization code not found')); | ||
this.assert(!code.isExpired, new errors.InvalidGrantError('authorization code is expired')); | ||
ctx.assert(code, new errors.InvalidGrantError('authorization code not found')); | ||
ctx.assert(!code.isExpired, new errors.InvalidGrantError('authorization code is expired')); | ||
@@ -26,4 +26,4 @@ // PKCE check | ||
try { | ||
assert(this.oidc.params.code_verifier); | ||
let expected = this.oidc.params.code_verifier; | ||
assert(ctx.oidc.params.code_verifier); | ||
let expected = ctx.oidc.params.code_verifier; | ||
@@ -36,3 +36,3 @@ if (code.codeChallengeMethod === 'S256') { | ||
} catch (err) { | ||
this.throw(new errors.InvalidGrantError('PKCE verification failed')); | ||
ctx.throw(new errors.InvalidGrantError('PKCE verification failed')); | ||
} | ||
@@ -42,20 +42,20 @@ } | ||
try { | ||
this.assert(!code.consumed, | ||
ctx.assert(!code.consumed, | ||
new errors.InvalidGrantError('authorization code already consumed')); | ||
yield code.consume(); | ||
await code.consume(); | ||
} catch (err) { | ||
yield code.destroy(); | ||
await code.destroy(); | ||
throw err; | ||
} | ||
this.assert(code.clientId === this.oidc.client.clientId, | ||
ctx.assert(code.clientId === ctx.oidc.client.clientId, | ||
new errors.InvalidGrantError('authorization code client mismatch')); | ||
this.assert(code.redirectUri === this.oidc.params.redirect_uri, | ||
ctx.assert(code.redirectUri === ctx.oidc.params.redirect_uri, | ||
new errors.InvalidGrantError('authorization code redirect_uri mismatch')); | ||
const account = yield provider.Account.findById(code.accountId); | ||
const account = await provider.Account.findById(code.accountId); | ||
this.assert(account, | ||
ctx.assert(account, | ||
new errors.InvalidGrantError('authorization code invalid (referenced account not found)')); | ||
@@ -67,3 +67,3 @@ | ||
claims: code.claims, | ||
clientId: this.oidc.client.clientId, | ||
clientId: ctx.oidc.client.clientId, | ||
grantId: code.grantId, | ||
@@ -74,3 +74,3 @@ scope: code.scope, | ||
const accessToken = yield at.save(); | ||
const accessToken = await at.save(); | ||
const tokenType = 'Bearer'; | ||
@@ -80,3 +80,3 @@ const expiresIn = AccessToken.expiresIn; | ||
let refreshToken; | ||
const grantPresent = this.oidc.client.grantTypes.indexOf('refresh_token') !== -1; | ||
const grantPresent = ctx.oidc.client.grantTypes.indexOf('refresh_token') !== -1; | ||
const shouldIssue = instance(provider).configuration('features.refreshToken') || | ||
@@ -93,3 +93,3 @@ code.scope.split(' ').indexOf('offline_access') !== -1; | ||
claims: code.claims, | ||
clientId: this.oidc.client.clientId, | ||
clientId: ctx.oidc.client.clientId, | ||
grantId: code.grantId, | ||
@@ -101,11 +101,11 @@ nonce: code.nonce, | ||
refreshToken = yield rt.save(); | ||
refreshToken = await rt.save(); | ||
} | ||
const IdToken = provider.IdToken; | ||
const token = new IdToken(Object.assign({}, yield Promise.resolve(account.claims()), { | ||
const token = new IdToken(Object.assign({}, await Promise.resolve(account.claims()), { | ||
acr: code.acr, | ||
amr: code.amr, | ||
auth_time: code.authTime, | ||
}), this.oidc.client.sectorIdentifier); | ||
}), ctx.oidc.client.sectorIdentifier); | ||
@@ -120,5 +120,5 @@ token.scope = code.scope; | ||
const idToken = yield token.sign(this.oidc.client); | ||
const idToken = await token.sign(ctx.oidc.client); | ||
this.body = { | ||
ctx.body = { | ||
access_token: accessToken, | ||
@@ -131,3 +131,3 @@ expires_in: expiresIn, | ||
yield next; | ||
await next(); | ||
}; | ||
@@ -134,0 +134,0 @@ }; |
'use strict'; | ||
module.exports.handler = function getClientCredentialsHandler(provider) { | ||
return function* clientCredentialsResponse(next) { | ||
return async function clientCredentialsResponse(ctx, next) { | ||
const ClientCredentials = provider.ClientCredentials; | ||
const at = new ClientCredentials({ | ||
clientId: this.oidc.client.clientId, | ||
scope: this.oidc.params.scope, | ||
clientId: ctx.oidc.client.clientId, | ||
scope: ctx.oidc.params.scope, | ||
}); | ||
const token = yield at.save(); | ||
const token = await at.save(); | ||
const tokenType = 'Bearer'; | ||
const expiresIn = ClientCredentials.expiresIn; | ||
this.body = { access_token: token, expires_in: expiresIn, token_type: tokenType }; | ||
ctx.body = { access_token: token, expires_in: expiresIn, token_type: tokenType }; | ||
yield next; | ||
await next(); | ||
}; | ||
@@ -19,0 +19,0 @@ }; |
@@ -9,4 +9,4 @@ 'use strict'; | ||
module.exports.handler = function getRefreshTokenHandler(provider) { | ||
return function* refreshTokenResponse(next) { | ||
presence.call(this, ['refresh_token']); | ||
return async function refreshTokenResponse(ctx, next) { | ||
presence.call(ctx, ['refresh_token']); | ||
@@ -18,10 +18,10 @@ const RefreshToken = provider.RefreshToken; | ||
const refreshToken = yield RefreshToken.find( | ||
this.oidc.params.refresh_token, { | ||
const refreshToken = await RefreshToken.find( | ||
ctx.oidc.params.refresh_token, { | ||
ignoreExpiration: true, | ||
}); | ||
this.assert(refreshToken, new errors.InvalidGrantError('refresh token not found')); | ||
this.assert(!refreshToken.isExpired, new errors.InvalidGrantError('refresh token is expired')); | ||
this.assert(refreshToken.clientId === this.oidc.client.clientId, | ||
ctx.assert(refreshToken, new errors.InvalidGrantError('refresh token not found')); | ||
ctx.assert(!refreshToken.isExpired, new errors.InvalidGrantError('refresh token is expired')); | ||
ctx.assert(refreshToken.clientId === ctx.oidc.client.clientId, | ||
new errors.InvalidGrantError('refresh token client mismatch')); | ||
@@ -31,6 +31,6 @@ | ||
if (this.oidc.params.scope) { | ||
const missing = _.difference(this.oidc.params.scope.split(' '), refreshTokenScopes); | ||
if (ctx.oidc.params.scope) { | ||
const missing = _.difference(ctx.oidc.params.scope.split(' '), refreshTokenScopes); | ||
this.assert(_.isEmpty(missing), 400, 'invalid_scope', { | ||
ctx.assert(_.isEmpty(missing), 400, 'invalid_scope', { | ||
error_description: 'refresh token missing requested scope', | ||
@@ -41,5 +41,5 @@ scope: missing.join(' '), | ||
const account = yield Account.findById(refreshToken.accountId); | ||
const account = await Account.findById(refreshToken.accountId); | ||
this.assert(account, | ||
ctx.assert(account, | ||
new errors.InvalidGrantError('refresh token invalid (referenced account not found)')); | ||
@@ -50,17 +50,17 @@ | ||
claims: refreshToken.claims, | ||
clientId: this.oidc.client.clientId, | ||
clientId: ctx.oidc.client.clientId, | ||
grantId: refreshToken.grantId, | ||
scope: this.oidc.params.scope || refreshToken.scope, | ||
scope: ctx.oidc.params.scope || refreshToken.scope, | ||
sid: refreshToken.sid, | ||
}); | ||
const accessToken = yield at.save(); | ||
const accessToken = await at.save(); | ||
const tokenType = 'Bearer'; | ||
const expiresIn = AccessToken.expiresIn; | ||
const token = new IdToken(Object.assign({}, yield Promise.resolve(account.claims()), { | ||
const token = new IdToken(Object.assign({}, await Promise.resolve(account.claims()), { | ||
acr: refreshToken.acr, | ||
amr: refreshToken.amr, | ||
auth_time: refreshToken.authTime, | ||
}), this.oidc.client.sectorIdentifier); | ||
}), ctx.oidc.client.sectorIdentifier); | ||
@@ -72,16 +72,16 @@ token.scope = refreshToken.scope; | ||
token.set('at_hash', accessToken); | ||
token.set('rt_hash', this.oidc.params.refresh_token); | ||
token.set('rt_hash', ctx.oidc.params.refresh_token); | ||
token.set('sid', refreshToken.sid); | ||
const idToken = yield token.sign(this.oidc.client); | ||
const idToken = await token.sign(ctx.oidc.client); | ||
this.body = { | ||
ctx.body = { | ||
access_token: accessToken, | ||
expires_in: expiresIn, | ||
id_token: idToken, | ||
refresh_token: this.oidc.params.refresh_token, | ||
refresh_token: ctx.oidc.params.refresh_token, | ||
token_type: tokenType, | ||
}; | ||
yield next; | ||
await next(); | ||
}; | ||
@@ -88,0 +88,0 @@ }; |
@@ -27,9 +27,9 @@ 'use strict'; | ||
return compose([ | ||
function* setAuthenticate(next) { | ||
yield next; | ||
if (this.status === 401) { | ||
async function setAuthenticate(ctx, next) { | ||
await next(); | ||
if (ctx.status === 401) { | ||
const wwwAuth = _.chain({ | ||
realm: provider.issuer, | ||
}) | ||
.merge(this.body) | ||
.merge(ctx.body) | ||
.map((val, key) => `${key}="${val}"`) | ||
@@ -39,3 +39,3 @@ .value() | ||
this.set('WWW-Authenticate', `Bearer ${wwwAuth}`); | ||
ctx.set('WWW-Authenticate', `Bearer ${wwwAuth}`); | ||
} | ||
@@ -52,17 +52,17 @@ }, | ||
function* validateBearer(next) { | ||
const accessToken = yield provider.AccessToken.find(this.oidc.bearer); | ||
this.assert(accessToken, new errors.InvalidTokenError()); | ||
async function validateBearer(ctx, next) { | ||
const accessToken = await provider.AccessToken.find(ctx.oidc.bearer); | ||
ctx.assert(accessToken, new errors.InvalidTokenError()); | ||
this.oidc.accessToken = accessToken; | ||
yield next; | ||
ctx.oidc.accessToken = accessToken; | ||
await next(); | ||
}, | ||
function* validateScope(next) { | ||
if (this.oidc.params.scope) { | ||
const accessTokenScopes = this.oidc.accessToken.scope.split(' '); | ||
const missing = _.difference(this.oidc.params.scope.split(' '), | ||
async function validateScope(ctx, next) { | ||
if (ctx.oidc.params.scope) { | ||
const accessTokenScopes = ctx.oidc.accessToken.scope.split(' '); | ||
const missing = _.difference(ctx.oidc.params.scope.split(' '), | ||
accessTokenScopes); | ||
this.assert(_.isEmpty(missing), 400, 'invalid_scope', { | ||
ctx.assert(_.isEmpty(missing), 400, 'invalid_scope', { | ||
error_description: 'access token missing requested scope', | ||
@@ -72,32 +72,32 @@ scope: missing.join(' '), | ||
} | ||
yield next; | ||
await next(); | ||
}, | ||
function* loadClient(next) { | ||
const client = yield provider.Client.find(this.oidc.accessToken.clientId); | ||
this.assert(client, new errors.InvalidTokenError()); | ||
async function loadClient(ctx, next) { | ||
const client = await provider.Client.find(ctx.oidc.accessToken.clientId); | ||
ctx.assert(client, new errors.InvalidTokenError()); | ||
this.oidc.client = client; | ||
ctx.oidc.client = client; | ||
yield next; | ||
await next(); | ||
}, | ||
function* loadAccount(next) { | ||
const account = yield provider.Account.findById(this.oidc.accessToken.accountId); | ||
async function loadAccount(ctx, next) { | ||
const account = await provider.Account.findById(ctx.oidc.accessToken.accountId); | ||
this.assert(account, new errors.InvalidTokenError()); | ||
ctx.assert(account, new errors.InvalidTokenError()); | ||
this.oidc.account = account; | ||
ctx.oidc.account = account; | ||
yield next; | ||
await next(); | ||
}, | ||
function* respond() { | ||
const claims = _.get(this.oidc.accessToken, 'claims.userinfo', {}); | ||
const scope = this.oidc.params.scope || this.oidc.accessToken.scope; | ||
const client = this.oidc.client; | ||
async function respond(ctx, next) { | ||
const claims = _.get(ctx.oidc.accessToken, 'claims.userinfo', {}); | ||
const scope = ctx.oidc.params.scope || ctx.oidc.accessToken.scope; | ||
const client = ctx.oidc.client; | ||
if (client.userinfoSignedResponseAlg || client.userinfoEncryptedResponseAlg) { | ||
const IdToken = provider.IdToken; | ||
const token = new IdToken(yield Promise.resolve(this.oidc.account.claims()), | ||
const token = new IdToken(await Promise.resolve(ctx.oidc.account.claims()), | ||
client.sectorIdentifier); | ||
@@ -108,9 +108,9 @@ | ||
this.body = yield token.sign(client, { | ||
expiresAt: this.oidc.accessToken.exp, | ||
ctx.body = await token.sign(client, { | ||
expiresAt: ctx.oidc.accessToken.exp, | ||
use: 'userinfo', | ||
}); | ||
this.type = 'application/jwt; charset=utf-8'; | ||
ctx.type = 'application/jwt; charset=utf-8'; | ||
} else { | ||
const mask = new Claims(yield Promise.resolve(this.oidc.account.claims()), | ||
const mask = new Claims(await Promise.resolve(ctx.oidc.account.claims()), | ||
client.sectorIdentifier); | ||
@@ -121,6 +121,8 @@ | ||
this.body = mask.result(); | ||
ctx.body = mask.result(); | ||
} | ||
await next(); | ||
}, | ||
]); | ||
}; |
'use strict'; | ||
module.exports = function webfingerAction(provider) { | ||
return function* renderWebfingerResponse(next) { | ||
this.body = { | ||
return async function renderWebfingerResponse(ctx, next) { | ||
ctx.body = { | ||
links: [{ | ||
@@ -10,7 +10,7 @@ href: provider.issuer, | ||
}], | ||
subject: this.query.resource, | ||
subject: ctx.query.resource, | ||
}; | ||
this.type = 'application/jrd+json'; | ||
yield next; | ||
ctx.type = 'application/jrd+json'; | ||
await next(); | ||
}; | ||
}; |
'use strict'; | ||
const koa = require('koa'); | ||
const Koa = require('koa'); | ||
const Router = require('koa-router'); | ||
@@ -34,3 +34,3 @@ const getCors = require('kcors'); | ||
const configuration = instance(this).configuration(); | ||
const app = koa(); | ||
const app = new Koa(); | ||
@@ -133,2 +133,3 @@ instance(this).app = app; | ||
const interaction = getInteraction(this); | ||
get('/interaction/:grant', error(this), interaction.get); | ||
@@ -135,0 +136,0 @@ post('interaction', '/interaction/:grant/submit', error(this), interaction.post); |
@@ -8,5 +8,5 @@ 'use strict'; | ||
module.exports = provider => function* authorizationErrorHandler(next) { // eslint-disable-line consistent-return, max-len | ||
module.exports = provider => async function authorizationErrorHandler(ctx, next) { // eslint-disable-line consistent-return, max-len | ||
try { | ||
yield next; | ||
await next(); | ||
} catch (caught) { | ||
@@ -17,8 +17,8 @@ let err = caught; | ||
let params; | ||
params = this.oidc.params; | ||
params = params || (this.method === 'POST' ? this.request.body : this.query) || | ||
params = ctx.oidc.params; | ||
params = params || (ctx.method === 'POST' ? ctx.request.body : ctx.query) || | ||
/* istanbul ignore next */ {}; | ||
if (this.oidc.client && params.redirect_uri && !this.oidc.redirectUriCheckPerformed) { | ||
if (!this.oidc.client.redirectUriAllowed(params.redirect_uri)) { | ||
if (ctx.oidc.client && params.redirect_uri && !ctx.oidc.redirectUriCheckPerformed) { | ||
if (!ctx.oidc.client.redirectUriAllowed(params.redirect_uri)) { | ||
err = new errors.RedirectUriMismatchError(); | ||
@@ -28,3 +28,3 @@ } | ||
this.status = err.statusCode || 500; | ||
ctx.status = err.statusCode || 500; | ||
@@ -41,3 +41,3 @@ if (err.expose) { | ||
provider.emit(out.error === 'server_error' ? | ||
'server_error' : 'authorization.error', err, this); | ||
'server_error' : 'authorization.error', err, ctx); | ||
@@ -48,3 +48,3 @@ // redirect uri error should render instead of redirect to uri | ||
const renderError = instance(provider).configuration('renderError'); | ||
return renderError.call(this, out); | ||
return renderError.call(ctx, out); | ||
} | ||
@@ -55,10 +55,10 @@ | ||
instance(provider).responseModes.get(params.response_mode) | ||
.call(this, params.redirect_uri, out); | ||
.call(ctx, params.redirect_uri, out); | ||
} else if (params.response_mode === 'form_post') { | ||
formPost.call(this, params.redirect_uri, out); | ||
formPost.call(ctx, params.redirect_uri, out); | ||
} else { | ||
const uri = redirectUri(params.redirect_uri, out, params.response_mode); | ||
this.redirect(uri); | ||
ctx.redirect(uri); | ||
} | ||
} | ||
}; |
@@ -6,10 +6,10 @@ 'use strict'; | ||
module.exports = function* checkDupes(next) { | ||
const dupes = _.chain(this.oidc.params).pickBy(Array.isArray).keys().value(); | ||
module.exports = async function checkDupes(ctx, next) { | ||
const dupes = _.chain(ctx.oidc.params).pickBy(Array.isArray).keys().value(); | ||
// Validate: no dup params | ||
this.assert(_.isEmpty(dupes), | ||
ctx.assert(_.isEmpty(dupes), | ||
new errors.InvalidRequestError(`parameters must not be provided twice. ${dupes.join(',')}`)); | ||
yield next; | ||
await next(); | ||
}; |
@@ -8,9 +8,9 @@ 'use strict'; | ||
return function* parseBodyIfPost(next) { | ||
if (this.method === 'POST') { | ||
yield parseBody.call(this, next); | ||
return async function parseBodyIfPost(ctx, next) { | ||
if (ctx.method === 'POST') { | ||
await parseBody(ctx, next); | ||
} else { | ||
yield next; | ||
await next(); | ||
} | ||
}; | ||
}; |
@@ -7,6 +7,6 @@ 'use strict'; | ||
const OIDCContext = getContext(provider); | ||
return function* contextEnsureOidc(next) { | ||
Object.defineProperty(this, 'oidc', { value: new OIDCContext(this) }); | ||
yield next; | ||
return async function contextEnsureOidc(ctx, next) { | ||
Object.defineProperty(ctx, 'oidc', { value: new OIDCContext(ctx) }); | ||
await next(); | ||
}; | ||
}; |
@@ -6,8 +6,8 @@ 'use strict'; | ||
module.exports = function getErrorHandler(provider, eventName) { | ||
return function* apiErrorHandler(next) { | ||
return async function apiErrorHandler(ctx, next) { | ||
try { | ||
yield next; | ||
await next(); | ||
} catch (err) { | ||
const out = {}; | ||
this.status = err.statusCode || 500; | ||
ctx.status = err.statusCode || 500; | ||
@@ -24,13 +24,13 @@ if (err.expose) { | ||
// browser requests end up rendering the html error instead | ||
if (this.accepts('json', 'html') === 'html') { | ||
if (ctx.accepts('json', 'html') === 'html') { | ||
const renderError = instance(provider).configuration('renderError'); | ||
renderError.call(this, out); | ||
renderError.call(ctx, out); | ||
} else { | ||
this.body = out; | ||
ctx.body = out; | ||
} | ||
if (out.error === 'server_error') { | ||
provider.emit('server_error', err, this); | ||
provider.emit('server_error', err, ctx); | ||
} else if (eventName) { | ||
provider.emit(eventName, err, this); | ||
provider.emit(eventName, err, ctx); | ||
} | ||
@@ -37,0 +37,0 @@ } |
@@ -6,12 +6,12 @@ 'use strict'; | ||
module.exports = function* findClientId(next) { | ||
this.oidc.authorization = {}; | ||
module.exports = async function findClientId(ctx, next) { | ||
ctx.oidc.authorization = {}; | ||
if (this.headers.authorization) { | ||
if (ctx.headers.authorization) { | ||
// client_secret_basic | ||
this.assert(!this.oidc.params.client_id, new errors.InvalidRequestError( | ||
ctx.assert(!ctx.oidc.params.client_id, new errors.InvalidRequestError( | ||
'combining multiple client authentication mechanism is no good')); | ||
const parts = this.headers.authorization.split(' '); | ||
this.assert(parts.length === 2 && parts[0] === 'Basic', | ||
const parts = ctx.headers.authorization.split(' '); | ||
ctx.assert(parts.length === 2 && parts[0] === 'Basic', | ||
new errors.InvalidRequestError('invalid authorization header value format')); | ||
@@ -22,30 +22,30 @@ | ||
this.assert(i !== -1, | ||
ctx.assert(i !== -1, | ||
new errors.InvalidRequestError('invalid authorization header value format')); | ||
this.oidc.authorization.clientId = basic.slice(0, i); | ||
this.oidc.authorization.clientSecret = basic.slice(i + 1); | ||
} else if (this.oidc.params.client_id && !this.oidc.params.client_assertion) { | ||
ctx.oidc.authorization.clientId = basic.slice(0, i); | ||
ctx.oidc.authorization.clientSecret = basic.slice(i + 1); | ||
} else if (ctx.oidc.params.client_id && !ctx.oidc.params.client_assertion) { | ||
// client_secret_post | ||
this.oidc.authorization.clientId = this.oidc.params.client_id; | ||
} else if (this.oidc.params.client_assertion) { | ||
ctx.oidc.authorization.clientId = ctx.oidc.params.client_id; | ||
} else if (ctx.oidc.params.client_assertion) { | ||
// client_secret_jwt and private_key_jwt | ||
const assertionSub = (() => { | ||
try { | ||
return JSON.parse(base64url(this.oidc.params.client_assertion.split('.')[1])).sub; | ||
return JSON.parse(base64url(ctx.oidc.params.client_assertion.split('.')[1])).sub; | ||
} catch (err) { | ||
return this.throw(new errors.InvalidRequestError('invalid client_assertion')); | ||
return ctx.throw(new errors.InvalidRequestError('invalid client_assertion')); | ||
} | ||
})(); | ||
this.assert(!this.oidc.params.client_id || assertionSub === this.oidc.params.client_id, | ||
ctx.assert(!ctx.oidc.params.client_id || assertionSub === ctx.oidc.params.client_id, | ||
new errors.InvalidRequestError('subject of client_assertion must be the same as client_id')); | ||
this.oidc.authorization.clientId = assertionSub; | ||
ctx.oidc.authorization.clientId = assertionSub; | ||
} | ||
this.assert(this.oidc.authorization.clientId, | ||
ctx.assert(ctx.oidc.authorization.clientId, | ||
new errors.InvalidClientError('no client authentication mechanism provided')); | ||
yield next; | ||
await next(); | ||
}; |
@@ -15,7 +15,7 @@ 'use strict'; | ||
return function* assembleParams(next) { | ||
const params = this.method === 'POST' ? this.request.body : this.query; | ||
this.oidc.params = new Params(params); | ||
yield next; | ||
return async function assembleParams(ctx, next) { | ||
const params = ctx.method === 'POST' ? ctx.request.body : ctx.query; | ||
ctx.oidc.params = new Params(params); | ||
await next(); | ||
}; | ||
}; |
@@ -5,7 +5,7 @@ 'use strict'; | ||
module.exports = function* invalidRoute(next) { | ||
yield next; | ||
if (this.status === 404 && this.message === 'Not Found') { | ||
this.throw(new errors.InvalidRequestError('unrecognized route', 404)); | ||
module.exports = async function invalidRoute(ctx, next) { | ||
await next(); | ||
if (ctx.status === 404 && ctx.message === 'Not Found') { | ||
ctx.throw(new errors.InvalidRequestError('unrecognized route', 404)); | ||
} | ||
}; |
@@ -6,12 +6,12 @@ 'use strict'; | ||
module.exports = function getLoadClient(provider) { | ||
return function* loadClient(next) { | ||
const client = yield provider.Client.find(this.oidc.authorization.clientId); | ||
return async function loadClient(ctx, next) { | ||
const client = await provider.Client.find(ctx.oidc.authorization.clientId); | ||
this.assert(client, new errors.InvalidClientError( | ||
ctx.assert(client, new errors.InvalidClientError( | ||
'invalid client authentication provided (client not found)')); | ||
this.oidc.client = client; | ||
ctx.oidc.client = client; | ||
yield next; | ||
await next(); | ||
}; | ||
}; |
'use strict'; | ||
module.exports = function* noCache(next) { | ||
this.set('Pragma', 'no-cache'); | ||
this.set('Cache-Control', 'no-cache, no-store'); | ||
yield next; | ||
module.exports = async function noCache(ctx, next) { | ||
ctx.set('Pragma', 'no-cache'); | ||
ctx.set('Cache-Control', 'no-cache, no-store'); | ||
await next(); | ||
}; |
@@ -11,4 +11,4 @@ 'use strict'; | ||
module.exports = function getResumeAction(provider) { | ||
return function* resumeAction(next) { | ||
this.oidc.uuid = this.params.grant; | ||
return async function resumeAction(ctx, next) { | ||
ctx.oidc.uuid = ctx.params.grant; | ||
@@ -18,3 +18,3 @@ const cookieOptions = instance(provider).configuration('cookies.short'); | ||
try { | ||
this.query = j(this.cookies.get('_grant', cookieOptions)); | ||
ctx.query = j(ctx.cookies.get('_grant', cookieOptions)); | ||
} catch (err) { | ||
@@ -26,3 +26,3 @@ throw new errors.InvalidRequestError('authorization request has expired'); | ||
try { | ||
return j(this.cookies.get('_grant_result', cookieOptions)); | ||
return j(ctx.cookies.get('_grant_result', cookieOptions)); | ||
} catch (err) { | ||
@@ -32,27 +32,27 @@ return {}; | ||
})(); | ||
this.cookies.set('_grant_result', null, cookieOptions); | ||
ctx.cookies.set('_grant_result', null, cookieOptions); | ||
if (result.login) { | ||
if (!result.login.remember) this.oidc.session.transient = true; | ||
if (!result.login.remember) ctx.oidc.session.transient = true; | ||
if (this.oidc.session.account !== result.login.account) { | ||
delete this.oidc.session.authorizations; | ||
if (ctx.oidc.session.account !== result.login.account) { | ||
delete ctx.oidc.session.authorizations; | ||
} | ||
this.oidc.session.account = result.login.account; | ||
this.oidc.session.loginTs = result.login.ts; | ||
ctx.oidc.session.account = result.login.account; | ||
ctx.oidc.session.loginTs = result.login.ts; | ||
} | ||
if (result.consent && result.consent.scope !== undefined) { | ||
this.query.scope = String(result.consent.scope); | ||
ctx.query.scope = String(result.consent.scope); | ||
} | ||
if (!_.isEmpty(result) && !this.oidc.session.sidFor(this.query.client_id)) { | ||
this.oidc.session.sidFor(this.query.client_id, uuid()); | ||
if (!_.isEmpty(result) && !ctx.oidc.session.sidFor(ctx.query.client_id)) { | ||
ctx.oidc.session.sidFor(ctx.query.client_id, uuid()); | ||
} | ||
this.oidc.result = result; | ||
ctx.oidc.result = result; | ||
yield next; | ||
await next(); | ||
}; | ||
}; |
@@ -11,10 +11,10 @@ 'use strict'; | ||
return function* selectiveBody(next) { | ||
if (this.is(only)) { | ||
yield bodyParser.call(this, next); | ||
return async function selectiveBody(ctx, next) { | ||
if (ctx.is(only)) { | ||
await bodyParser(ctx, next); | ||
} else { | ||
const msg = `only ${only} content-type ${this.method} bodies are supported`; | ||
this.throw(new errors.InvalidRequestError(msg)); | ||
const msg = `only ${only} content-type ${ctx.method} bodies are supported`; | ||
ctx.throw(new errors.InvalidRequestError(msg)); | ||
} | ||
}; | ||
}; |
'use strict'; | ||
module.exports = function getSessionHandler(provider) { | ||
return function* sessionHandler(next) { | ||
this.oidc.session = yield provider.Session.get(this); | ||
yield next; | ||
return async function sessionHandler(ctx, next) { | ||
ctx.oidc.session = await provider.Session.get(ctx); | ||
await next(); | ||
if (this.oidc.session.transient) { | ||
this.response.get('set-cookie').forEach((cookie, index, ary) => { | ||
if (ctx.oidc.session.transient) { | ||
ctx.response.get('set-cookie').forEach((cookie, index, ary) => { | ||
if (cookie.startsWith('_session') && !cookie.includes('expires=Thu, 01 Jan 1970')) { | ||
@@ -16,4 +16,4 @@ ary[index] = cookie.replace(/(; ?expires=([\w\d:, ]+))/, ''); // eslint-disable-line no-param-reassign | ||
yield this.oidc.session.save(); | ||
await ctx.oidc.session.save(); | ||
}; | ||
}; |
@@ -11,7 +11,7 @@ 'use strict'; | ||
return function* tokenAuth(next) { | ||
switch (this.oidc.client.tokenEndpointAuthMethod) { | ||
return async function tokenAuth(ctx, next) { | ||
switch (ctx.oidc.client.tokenEndpointAuthMethod) { | ||
case 'none': | ||
this.throw(new errors.InvalidRequestError('client not supposed to access token endpoint')); | ||
ctx.throw(new errors.InvalidRequestError('client not supposed to access token endpoint')); | ||
@@ -21,11 +21,11 @@ /* istanbul ignore next */ | ||
case 'client_secret_post': { | ||
const params = this.oidc.params; | ||
const params = ctx.oidc.params; | ||
this.assert(params.client_id, new errors.InvalidRequestError( | ||
ctx.assert(params.client_id, new errors.InvalidRequestError( | ||
'client_id must be provided in the body')); | ||
this.assert(params.client_secret, new errors.InvalidRequestError( | ||
ctx.assert(params.client_secret, new errors.InvalidRequestError( | ||
'client_secret must be provided in the body')); | ||
tokenCredentialAuth.call(this, this.oidc.client.clientSecret, params.client_secret); | ||
tokenCredentialAuth.call(ctx, ctx.oidc.client.clientSecret, params.client_secret); | ||
@@ -36,5 +36,5 @@ break; | ||
yield tokenJwtAuth.call(this, this.oidc.client.keystore, | ||
this.oidc.client.tokenEndpointAuthSigningAlg ? | ||
[this.oidc.client.tokenEndpointAuthSigningAlg] : ['HS256', 'HS384', 'HS512']); | ||
await tokenJwtAuth.call(ctx, ctx.oidc.client.keystore, | ||
ctx.oidc.client.tokenEndpointAuthSigningAlg ? | ||
[ctx.oidc.client.tokenEndpointAuthSigningAlg] : ['HS256', 'HS384', 'HS512']); | ||
@@ -44,5 +44,5 @@ break; | ||
yield tokenJwtAuth.call(this, this.oidc.client.keystore, | ||
this.oidc.client.tokenEndpointAuthSigningAlg ? | ||
[this.oidc.client.tokenEndpointAuthSigningAlg] : ['ES256', 'ES384', 'ES512', 'RS256', | ||
await tokenJwtAuth.call(ctx, ctx.oidc.client.keystore, | ||
ctx.oidc.client.tokenEndpointAuthSigningAlg ? | ||
[ctx.oidc.client.tokenEndpointAuthSigningAlg] : ['ES256', 'ES384', 'ES512', 'RS256', | ||
'RS384', 'RS512', 'PS256', 'PS384', 'PS512']); | ||
@@ -52,16 +52,16 @@ | ||
default: { // Client_secret_basic | ||
const auth = this.oidc.authorization; | ||
const auth = ctx.oidc.authorization; | ||
this.assert(auth.clientId, new errors.InvalidRequestError( | ||
ctx.assert(auth.clientId, new errors.InvalidRequestError( | ||
'client_id must be provided in the Authorization header')); | ||
this.assert(auth.clientSecret, new errors.InvalidRequestError( | ||
ctx.assert(auth.clientSecret, new errors.InvalidRequestError( | ||
'client_secret must be provided in the Authorization header')); | ||
tokenCredentialAuth.call(this, this.oidc.client.clientSecret, auth.clientSecret); | ||
tokenCredentialAuth.call(ctx, ctx.oidc.client.clientSecret, auth.clientSecret); | ||
} | ||
} | ||
yield next; | ||
await next(); | ||
}; | ||
}; |
@@ -10,3 +10,3 @@ 'use strict'; | ||
return function* tokenJwtAuth(keystore, algorithms) { | ||
return async function tokenJwtAuth(keystore, algorithms) { | ||
const tokenUri = this.oidc.urlFor('token'); | ||
@@ -68,7 +68,7 @@ | ||
const unique = yield uniqueCheck.call(this, payload.jti, payload.exp); | ||
const unique = await uniqueCheck.call(this, payload.jti, payload.exp); | ||
this.assert(unique, new errors.InvalidRequestError('jwt-bearer tokens must only be used once')); | ||
try { | ||
yield JWT.verify(this.oidc.params.client_assertion, keystore, { | ||
await JWT.verify(this.oidc.params.client_assertion, keystore, { | ||
audience: tokenUri, | ||
@@ -75,0 +75,0 @@ issuer: this.oidc.client.clientId, |
@@ -7,10 +7,10 @@ { | ||
"buffer-equals-constant": "^1.0.0", | ||
"ejs": "^2.5.2", | ||
"got": "^6.1.1", | ||
"http-errors": "^1.4.0", | ||
"kcors": "^1.2.1", | ||
"koa": "^1.0.0", | ||
"koa-body": "^1.2.1", | ||
"koa-compose": "^2.3.0", | ||
"koa-router": "^5.2.3", | ||
"kcors": "next", | ||
"koa": "next", | ||
"koa-body": "next", | ||
"koa-compose": "next", | ||
"ejs": "^2.5.2", | ||
"koa-router": "next", | ||
"lodash": "^4.5.0", | ||
@@ -26,3 +26,2 @@ "lru-cache": "^4.0.0", | ||
"chai": "^3.5.0", | ||
"co-mocha": "^1.1.2", | ||
"cookiejar": "*", | ||
@@ -34,6 +33,5 @@ "eslint": "^3.0.0", | ||
"koa-ejs": "^3.0.0", | ||
"koa-mount": "^1.3.0", | ||
"koa-rewrite": "^1.1.1", | ||
"koa-mount": "next", | ||
"koa-rewrite": "next", | ||
"mocha": "^3.0.0", | ||
"mocha-generators": "^1.2.0", | ||
"moment": "^2.14.1", | ||
@@ -48,3 +46,3 @@ "nock": "^9.0.2", | ||
"engines": { | ||
"node": ">=4" | ||
"node": ">=7" | ||
}, | ||
@@ -70,6 +68,9 @@ "license": "MIT", | ||
}, | ||
"version": "1.2.0", | ||
"version": "2.0.0-alpha.1.2.0", | ||
"files": [ | ||
"lib" | ||
] | ||
], | ||
"publishConfig": { | ||
"tag": "next" | ||
} | ||
} |
@@ -17,2 +17,3 @@ # oidc-provider | ||
<!-- TOC START min:2 max:2 link:true update:true --> | ||
- ['next' branch/release](#next-branchrelease) | ||
- [Implemented specs & features](#implemented-specs--features) | ||
@@ -26,2 +27,15 @@ - [Get started](#get-started) | ||
## 'next' branch/release | ||
This branch is being kept up to date with the latest master only having the internal dependencies | ||
being koa2 based, therefore requiring ES7 async/await capable node runtime (or live transpile). | ||
There are no extra features or master-unreleased features. 2.0.0 of this library will come when koa2 | ||
releases as latest and when ES7 async/await lands in LTS nodejs release (probably LTSv8). | ||
You can use this library if you already use node stable with `--harmony_async_await`, just declare | ||
your dependency in package.json with the @next distribution tag. | ||
The published versions also use pre-release version scheme 2.0.0-alpha.x.y.z with xyz being the same | ||
as the corresponding latest release. i.e. 2.0.0-alpha.1.2.0 is essentially version 1.2.0 only with | ||
the updated dependencies. | ||
## Implemented specs & features | ||
@@ -61,6 +75,6 @@ | ||
```bash | ||
$ git clone https://github.com/panva/node-oidc-provider.git oidc-provider | ||
$ git clone -b next https://github.com/panva/node-oidc-provider.git oidc-provider | ||
$ cd oidc-provider | ||
$ npm install | ||
$ node example | ||
$ node --harmony_async_await example | ||
``` | ||
@@ -77,3 +91,3 @@ Visiting `http://localhost:3000/.well-known/openid-configuration` will help you to discover how the | ||
``` | ||
$ npm install oidc-provider --save | ||
$ npm install oidc-provider@next --save | ||
``` | ||
@@ -80,0 +94,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
200177
14
4817
153
1
+ Addedcache-content-type@1.0.1(transitive)
+ Addedcookies@0.9.1(transitive)
+ Addeddebug@3.2.74.3.7(transitive)
+ Addedencodeurl@1.0.2(transitive)
+ Addedhas-tostringtag@1.0.2(transitive)
+ Addedis-generator-function@1.0.10(transitive)
+ Addedkcors@2.2.1(transitive)
+ Addedkoa@2.15.3(transitive)
+ Addedkoa-compose@3.2.14.2.0(transitive)
+ Addedkoa-convert@2.0.0(transitive)
+ Addedkoa-router@8.0.0-alpha.1(transitive)
+ Addedms@2.1.3(transitive)
+ Addedpath-to-regexp@1.7.0(transitive)
+ Addedylru@1.4.0(transitive)
- Removedbytes@3.1.2(transitive)
- Removedcall-bind@1.0.7(transitive)
- Removedco-body@5.2.0(transitive)
- Removedcomposition@2.3.0(transitive)
- Removedcookies@0.8.0(transitive)
- Removedcopy-to@2.0.1(transitive)
- Removeddebug@2.6.9(transitive)
- Removeddefine-data-property@1.1.4(transitive)
- Removederror-inject@1.0.0(transitive)
- Removedes-define-property@1.0.0(transitive)
- Removedes-errors@1.3.0(transitive)
- Removedextend@1.3.0(transitive)
- Removedformidable@1.0.17(transitive)
- Removedfunction-bind@1.1.2(transitive)
- Removedget-intrinsic@1.2.4(transitive)
- Removedgopd@1.0.1(transitive)
- Removedhas-property-descriptors@1.0.2(transitive)
- Removedhas-proto@1.0.3(transitive)
- Removedhasown@2.0.2(transitive)
- Removedhttp-errors@2.0.0(transitive)
- Removediconv-lite@0.4.24(transitive)
- Removedinflation@2.1.0(transitive)
- Removedkcors@1.3.3(transitive)
- Removedkoa@1.7.0(transitive)
- Removedkoa-body@1.7.0(transitive)
- Removedkoa-compose@2.5.1(transitive)
- Removedkoa-is-json@1.0.0(transitive)
- Removedkoa-router@5.4.2(transitive)
- Removedms@2.0.0(transitive)
- Removedobject-inspect@1.13.3(transitive)
- Removedpath-to-regexp@1.9.0(transitive)
- Removedqs@6.13.0(transitive)
- Removedraw-body@2.5.2(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedset-function-length@1.2.2(transitive)
- Removedside-channel@1.0.6(transitive)
- Removedstatuses@2.0.1(transitive)
- Removedunpipe@1.0.0(transitive)
Updatedkcors@next
Updatedkoa@next
Updatedkoa-body@next
Updatedkoa-compose@next
Updatedkoa-router@next