Comparing version 17.0.0-rc8 to 17.0.0-rc9
275
lib/auth.js
@@ -41,6 +41,6 @@ 'use strict'; | ||
_strategy(server, name, scheme, options) { | ||
_strategy(server, name, scheme, options = {}) { | ||
Hoek.assert(name, 'Authentication strategy must have a name'); | ||
Hoek.assert(!options || typeof options === 'object', 'options must be an object'); | ||
Hoek.assert(typeof options === 'object', 'options must be an object'); | ||
Hoek.assert(name !== 'bypass', 'Cannot use reserved strategy name: bypass'); | ||
@@ -105,2 +105,15 @@ Hoek.assert(!this._strategies[name], 'Authentication strategy name already exists'); | ||
static testAccess(request, route) { | ||
const auth = request._core.auth; | ||
try { | ||
auth._access(request, route); | ||
return true; | ||
} | ||
catch (err) { | ||
return false; | ||
} | ||
} | ||
_setupRoute(options, path) { | ||
@@ -187,2 +200,6 @@ | ||
if (type === 'access') { | ||
return !!config.access; | ||
} | ||
for (let i = 0; i < config.strategies.length; ++i) { | ||
@@ -205,22 +222,132 @@ const name = config.strategies[i]; | ||
static access(request, route) { | ||
async _authenticate(request) { | ||
const config = this.lookup(request.route); | ||
const errors = []; | ||
request.auth.mode = config.mode; | ||
// Injection bypass | ||
if (request.auth.credentials) { | ||
internals.validate(null, { credentials: request.auth.credentials, artifacts: request.auth.artifacts }, 'bypass', config, request, errors); | ||
return; | ||
} | ||
// Try each strategy | ||
for (let i = 0; i < config.strategies.length; ++i) { | ||
const name = config.strategies[i]; | ||
const strategy = this._strategies[name]; | ||
const bind = strategy.methods; | ||
const realm = strategy.realm; | ||
const response = await request._core.toolkit.execute(strategy.methods.authenticate, request, { bind, realm, auth: true }); | ||
const message = (response.isAuth ? internals.validate(response.error, response.data, name, config, request, errors) : internals.validate(response, null, name, config, request, errors)); | ||
if (!message) { | ||
return; | ||
} | ||
if (message !== internals.missing) { | ||
return message; | ||
} | ||
} | ||
// No more strategies | ||
const err = Boom.unauthorized('Missing authentication', errors); | ||
if (config.mode !== 'optional' && | ||
config.mode !== 'try') { | ||
throw err; | ||
} | ||
request.auth.isAuthenticated = false; | ||
request.auth.credentials = null; | ||
request.auth.error = err; | ||
request._log(['auth', 'unauthenticated']); | ||
} | ||
static access(request) { | ||
const auth = request._core.auth; | ||
const config = auth.lookup(route); | ||
if (!config) { | ||
return true; | ||
try { | ||
auth._access(request); | ||
request.auth.isAuthorized = true; | ||
} | ||
catch (err) { | ||
request.auth.isAuthorized = false; | ||
throw err; | ||
} | ||
} | ||
_access(request, route) { | ||
const config = this.lookup(route || request.route); | ||
if (!config || | ||
!config.access) { | ||
return; | ||
} | ||
const credentials = request.auth.credentials; | ||
if (!credentials) { | ||
return false; | ||
throw Boom.forbidden('Request is unauthenticated'); | ||
} | ||
return !internals.access(request, config, credentials, 'bypass'); | ||
} | ||
const requestEntity = (credentials.user ? 'user' : 'app'); | ||
_authenticate(request) { | ||
const scopeErrors = []; | ||
for (let i = 0; i < config.access.length; ++i) { | ||
const access = config.access[i]; | ||
const config = this.lookup(request.route); | ||
return internals.authenticate(config, request, this); | ||
// Check entity | ||
const entity = access.entity; | ||
if (entity && | ||
entity !== 'any' && | ||
entity !== requestEntity) { | ||
continue; | ||
} | ||
// Check scope | ||
let scope = access.scope; | ||
if (scope) { | ||
if (!credentials.scope) { | ||
scopeErrors.push(scope); | ||
continue; | ||
} | ||
scope = internals.expandScope(request, scope); | ||
if (!internals.validateScope(credentials, scope, 'required') || | ||
!internals.validateScope(credentials, scope, 'selection') || | ||
!internals.validateScope(credentials, scope, 'forbidden')) { | ||
scopeErrors.push(scope); | ||
continue; | ||
} | ||
} | ||
return; | ||
} | ||
// Scope error | ||
if (scopeErrors.length) { | ||
request._log(['auth', 'scope', 'error']); | ||
throw Boom.forbidden('Insufficient scope', { got: credentials.scope, need: scopeErrors }); | ||
} | ||
// Entity error | ||
if (requestEntity === 'app') { | ||
request._log(['auth', 'entity', 'user', 'error']); | ||
throw Boom.forbidden('Application credentials cannot be used on a user endpoint'); | ||
} | ||
request._log(['auth', 'entity', 'app', 'error']); | ||
throw Boom.forbidden('User credentials cannot be used on an application endpoint'); | ||
} | ||
@@ -313,50 +440,2 @@ | ||
internals.authenticate = async function (config, request, manager) { | ||
const errors = []; | ||
request.auth.mode = config.mode; | ||
// Injection bypass | ||
if (request.auth.credentials) { | ||
internals.validate(null, { credentials: request.auth.credentials, artifacts: request.auth.artifacts }, 'bypass', config, request, errors); | ||
return; | ||
} | ||
// Try each strategy | ||
for (let i = 0; i < config.strategies.length; ++i) { | ||
const name = config.strategies[i]; | ||
const strategy = manager._strategies[name]; | ||
const bind = strategy.methods; | ||
const realm = strategy.realm; | ||
const response = await request._core.toolkit.execute(strategy.methods.authenticate, request, { bind, realm, auth: true }); | ||
const message = (response.isAuth ? internals.validate(response.error, response.data, name, config, request, errors) : internals.validate(response, null, name, config, request, errors)); | ||
if (!message) { | ||
return; | ||
} | ||
if (message !== internals.missing) { | ||
return message; | ||
} | ||
} | ||
// No more strategies | ||
const err = Boom.unauthorized('Missing authentication', errors); | ||
if (config.mode !== 'optional' && | ||
config.mode !== 'try') { | ||
throw err; | ||
} | ||
request.auth.isAuthenticated = false; | ||
request.auth.credentials = null; | ||
request.auth.error = err; | ||
request._log(['auth', 'unauthenticated']); | ||
}; | ||
internals.validate = function (err, result, name, config, request, errors) { // err can be Boom, Error, or a valid response object | ||
@@ -370,3 +449,3 @@ | ||
if (err instanceof Error === false) { | ||
request._log(['auth', 'unauthenticated', 'response', name], err.statusCode); | ||
request._log(['auth', 'unauthenticated', 'response', name], { statusCode: err.statusCode }); | ||
return err; // Non-error response | ||
@@ -404,11 +483,2 @@ } | ||
request.auth.artifacts = result.artifacts; | ||
// Check access rules | ||
const error = internals.access(request, config, credentials, name); | ||
if (error) { | ||
request._log(error.tags, error.data); | ||
throw error.err; | ||
} | ||
request.auth.isAuthenticated = true; | ||
@@ -418,63 +488,2 @@ }; | ||
internals.access = function (request, config, credentials, name) { | ||
if (!config.access) { | ||
return null; | ||
} | ||
const requestEntity = (credentials.user ? 'user' : 'app'); | ||
const scopeErrors = []; | ||
for (let i = 0; i < config.access.length; ++i) { | ||
const access = config.access[i]; | ||
// Check entity | ||
const entity = access.entity; | ||
if (entity && | ||
entity !== 'any' && | ||
entity !== requestEntity) { | ||
continue; | ||
} | ||
// Check scope | ||
let scope = access.scope; | ||
if (scope) { | ||
if (!credentials.scope) { | ||
scopeErrors.push(scope); | ||
continue; | ||
} | ||
scope = internals.expandScope(request, scope); | ||
if (!internals.validateScope(credentials, scope, 'required') || | ||
!internals.validateScope(credentials, scope, 'selection') || | ||
!internals.validateScope(credentials, scope, 'forbidden')) { | ||
scopeErrors.push(scope); | ||
continue; | ||
} | ||
} | ||
return null; | ||
} | ||
// Scope error | ||
if (scopeErrors.length) { | ||
const data = { got: credentials.scope, need: scopeErrors }; | ||
return { err: Boom.forbidden('Insufficient scope', data), tags: ['auth', 'scope', 'error', name], data }; | ||
} | ||
// Entity error | ||
if (requestEntity === 'app') { | ||
return { err: Boom.forbidden('Application credentials cannot be used on a user endpoint'), tags: ['auth', 'entity', 'user', 'error', name] }; | ||
} | ||
return { err: Boom.forbidden('User credentials cannot be used on an application endpoint'), tags: ['auth', 'entity', 'app', 'error', name] }; | ||
}; | ||
internals.expandScope = function (request, scope) { | ||
@@ -507,3 +516,5 @@ | ||
params: request.params, | ||
query: request.query | ||
query: request.query, | ||
payload: request.payload, | ||
credentials: request.auth.credentials | ||
}; | ||
@@ -510,0 +521,0 @@ |
@@ -55,3 +55,4 @@ 'use strict'; | ||
catch (err) { | ||
request.log(['accept-encoding', 'error'], { header, error: err }); | ||
err.header = header; | ||
request._log(['accept-encoding', 'error'], err); | ||
return 'identity'; | ||
@@ -58,0 +59,0 @@ } |
@@ -117,2 +117,3 @@ 'use strict'; | ||
onPreAuth: Joi.array().items(internals.event).single(), | ||
onCredentials: Joi.array().items(internals.event).single(), | ||
onPostAuth: Joi.array().items(internals.event).single(), | ||
@@ -119,0 +120,0 @@ onPreHandler: Joi.array().items(internals.event).single(), |
@@ -31,5 +31,2 @@ 'use strict'; | ||
// process.on('unhandledRejection', (reason, p) => console.log('Unhandled Rejection at: Promise', p, 'reason:', reason)); | ||
// Declare internals | ||
@@ -43,11 +40,10 @@ | ||
events: [ | ||
{ name: 'log', tags: true }, | ||
{ name: 'log', channels: ['app', 'internal'], tags: true }, | ||
{ name: 'request', channels: ['app', 'internal', 'error'], tags: true, spread: true }, | ||
'response', | ||
'route', | ||
'start', | ||
'stop', | ||
{ name: 'route', spread: true }, | ||
{ name: 'request-internal', spread: true, tags: true }, | ||
{ name: 'request', spread: true, tags: true }, | ||
{ name: 'request-error', spread: true }, | ||
'response' | ||
] | ||
'stop' | ||
], | ||
badRequestResponse: new Buffer('HTTP/1.1 400 Bad Request\r\n\r\n', 'ascii') | ||
}; | ||
@@ -104,2 +100,3 @@ | ||
onPreAuth: new Ext('onPreAuth', this), | ||
onCredentials: new Ext('onCredentials', this), | ||
onPostAuth: new Ext('onPostAuth', this), | ||
@@ -118,4 +115,2 @@ onPreHandler: new Ext('onPreHandler', this), | ||
this.info = this._info(); | ||
this.events.on('route', Cors.options); | ||
} | ||
@@ -130,3 +125,3 @@ | ||
const data = event.data; | ||
const data = event.error || event.data; | ||
console.error('Debug:', event.tags.join(', '), (data ? '\n ' + (data.stack || (typeof data === 'object' ? Hoek.stringify(data) : data)) : '')); | ||
@@ -143,3 +138,2 @@ }; | ||
this.events.on({ name: 'request', filter }, debug); | ||
this.events.on({ name: 'request-internal', filter }, debug); | ||
} | ||
@@ -346,5 +340,4 @@ } | ||
async _stop(options) { | ||
async _stop(options = {}) { | ||
options = options || {}; | ||
options.timeout = options.timeout || 5000; // Default timeout to 5 seconds | ||
@@ -440,6 +433,4 @@ | ||
_dispatch(options) { | ||
_dispatch(options = {}) { | ||
options = options || {}; | ||
return (req, res) => { | ||
@@ -484,3 +475,9 @@ | ||
this._log(['connection', 'client', 'error'], err); | ||
socket.destroy(err); | ||
if (socket.writable) { | ||
socket.end(internals.badRequestResponse); | ||
} | ||
else { | ||
socket.destroy(err); | ||
} | ||
}); | ||
@@ -539,19 +536,23 @@ | ||
log(tags, data, timestamp, _internal) { | ||
log(tags, data) { | ||
tags = [].concat(tags); | ||
timestamp = (timestamp ? (timestamp instanceof Date ? timestamp.getTime() : timestamp) : Date.now()); | ||
const internal = !!_internal; | ||
return this._log(tags, data, 'app'); | ||
} | ||
const update = (typeof data !== 'function' ? { timestamp, tags, data, internal } : () => { | ||
_log(tags, data, channel = 'internal') { | ||
return { timestamp, tags, data: data(), internal }; | ||
}); | ||
if (!Array.isArray(tags)) { | ||
tags = [tags]; | ||
} | ||
this.events.emit({ name: 'log', tags }, update); | ||
} | ||
const timestamp = Date.now(); | ||
const field = (data instanceof Error ? 'error' : 'data'); | ||
_log(tags, data) { | ||
let event = { timestamp, tags, [field]: data, channel }; | ||
return this.log(tags, data, null, true); | ||
if (typeof data === 'function') { | ||
event = () => ({ timestamp, tags, data: data(), channel }); | ||
} | ||
this.events.emit({ name: 'log', tags, channel }, event); | ||
} | ||
@@ -561,5 +562,5 @@ }; | ||
internals.setup = function (options) { | ||
internals.setup = function (options = {}) { | ||
let settings = Hoek.cloneWithShallow(options || {}, ['listener', 'routes.bind']); | ||
let settings = Hoek.cloneWithShallow(options, ['listener', 'routes.bind']); | ||
settings.routes = Config.enable(settings.routes); | ||
@@ -566,0 +567,0 @@ settings = Config.apply('server', settings); |
@@ -58,3 +58,3 @@ 'use strict'; | ||
if (response.isBoom) { | ||
request._log(['handler', 'error'], { error: response.message, data: response }); | ||
request._log(['handler', 'error'], response); | ||
throw response; | ||
@@ -69,3 +69,4 @@ } | ||
if (response.isBoom) { | ||
response = await request._core.toolkit.failAction(request, pre.failAction, response, { tags: ['pre', 'error'], log: { assign: pre.assign, error: response }, retain: true }); | ||
response.assign = pre.assign; | ||
response = await request._core.toolkit.failAction(request, pre.failAction, response, { tags: ['pre', 'error'], retain: true }); | ||
} | ||
@@ -72,0 +73,0 @@ |
@@ -48,3 +48,3 @@ 'use strict'; | ||
options = Config.apply('method', options || {}, name); | ||
options = Config.apply('method', options, name); | ||
@@ -51,0 +51,0 @@ const settings = Hoek.cloneWithShallow(options, ['bind']); |
@@ -19,3 +19,3 @@ 'use strict'; | ||
const internals = { | ||
properties: ['server', 'url', 'query', 'path', 'method', 'mime', 'setUrl', 'setMethod', 'headers', 'id', 'app', 'plugins', 'route', 'auth', 'pre', 'preResponses', 'info', 'orig', 'params', 'paramsArray', 'payload', 'state', 'jsonp', 'response', 'raw', 'domain', 'log', 'getLog', 'generateResponse'], | ||
properties: ['server', 'url', 'query', 'path', 'method', 'mime', 'setUrl', 'setMethod', 'headers', 'id', 'app', 'plugins', 'route', 'auth', 'pre', 'preResponses', 'info', 'orig', 'params', 'paramsArray', 'payload', 'state', 'jsonp', 'response', 'raw', 'domain', 'log', 'logs', 'generateResponse'], | ||
events: Podium.validate(['finish', { name: 'peek', spread: true }, 'disconnect']) | ||
@@ -52,5 +52,2 @@ }; | ||
options = options || {}; | ||
Hoek.assert(!this._decorations || this._decorations[property] === undefined, 'Request interface decoration already defined:', property); | ||
Hoek.assert(internals.properties.indexOf(property) === -1, 'Cannot override built-in request interface decoration:', property); | ||
@@ -76,3 +73,2 @@ | ||
this._isReplied = false; // true when response processing started | ||
this._logger = []; | ||
this._route = this._core.router.specials.notFound.route; // Used prior to routing (only settings are used, not the handler) | ||
@@ -86,2 +82,3 @@ this._serverTimeoutId = null; | ||
this.jsonp = null; | ||
this.logs = []; | ||
this.method = req.method.toLowerCase(); | ||
@@ -107,2 +104,3 @@ this.mime = null; | ||
isAuthenticated: false, | ||
isAuthorized: false, | ||
credentials: options.credentials || null, // Special keys: 'app', 'user', 'scope' | ||
@@ -394,4 +392,4 @@ artifacts: options.artifacts || null, // Scheme-specific artifacts | ||
this._core.events.emit('request-error', [this, this.response._error]); | ||
this._log(this.response._error.isDeveloperError ? ['internal', 'implementation', 'error'] : ['internal', 'error'], this.response._error); | ||
const tags = this.response._error.isDeveloperError ? ['internal', 'implementation', 'error'] : ['internal', 'error']; | ||
this._log(tags, this.response._error, 'error'); | ||
} | ||
@@ -446,7 +444,7 @@ | ||
_clearState(name, options) { | ||
_clearState(name, options = {}) { | ||
const state = { name }; | ||
state.options = Hoek.clone(options || {}); | ||
state.options = Hoek.clone(options); | ||
state.options.ttl = 0; | ||
@@ -466,73 +464,36 @@ | ||
generateResponse(source, options) { | ||
log(tags, data) { | ||
return new Response(source, this, options); | ||
return this._log(tags, data, 'app'); | ||
} | ||
log(tags, data, timestamp, _internal) { | ||
_log(tags, data, channel = 'internal') { | ||
tags = [].concat(tags); | ||
timestamp = (timestamp ? (timestamp instanceof Date ? timestamp.getTime() : timestamp) : Date.now()); | ||
const internal = !!_internal; | ||
if (!Array.isArray(tags)) { | ||
tags = [tags]; | ||
} | ||
let update = (typeof data !== 'function' ? [this, { request: this.info.id, timestamp, tags, data, internal }] : () => { | ||
const timestamp = Date.now(); | ||
const field = (data instanceof Error ? 'error' : 'data'); | ||
return [this, { request: this.info.id, timestamp, tags, data: data(), internal }]; | ||
}); | ||
let event = { request: this.info.id, timestamp, tags, [field]: data, channel }; | ||
if (typeof data === 'function') { | ||
event = () => ({ request: this.info.id, timestamp, tags, data: data(), channel }); | ||
} | ||
if (this.route.settings.log.collect) { | ||
if (typeof data === 'function') { | ||
update = update(); | ||
event = event(); | ||
} | ||
this._logger.push(update[1]); // Add to request array | ||
this.logs.push(event); | ||
} | ||
this._core.events.emit({ name: internal ? 'request-internal' : 'request', tags }, update); | ||
this._core.events.emit({ name: 'request', channel, tags }, [this, event]); | ||
} | ||
_log(tags, data) { | ||
generateResponse(source, options) { | ||
return this.log(tags, data, null, true); | ||
return new Response(source, this, options); | ||
} | ||
getLog(tags, internal) { | ||
Hoek.assert(this.route.settings.log.collect, 'Request logging is disabled'); | ||
if (typeof tags === 'boolean') { | ||
internal = tags; | ||
tags = []; | ||
} | ||
tags = [].concat(tags || []); | ||
if (!tags.length && | ||
internal === undefined) { | ||
return this._logger; | ||
} | ||
const filter = tags.length ? Hoek.mapToObject(tags) : null; | ||
const result = []; | ||
for (let i = 0; i < this._logger.length; ++i) { | ||
const event = this._logger[i]; | ||
if (internal === undefined || event.internal === internal) { | ||
if (filter) { | ||
for (let j = 0; j < event.tags.length; ++j) { | ||
const tag = event.tags[j]; | ||
if (filter[tag]) { | ||
result.push(event); | ||
break; | ||
} | ||
} | ||
} | ||
else { | ||
result.push(event); | ||
} | ||
} | ||
} | ||
return result; | ||
} | ||
}; | ||
@@ -539,0 +500,0 @@ |
@@ -23,6 +23,4 @@ 'use strict'; | ||
constructor(source, request, options) { | ||
constructor(source, request, options = {}) { | ||
options = options || {}; | ||
this.app = {}; | ||
@@ -141,5 +139,4 @@ this.headers = {}; // Incomplete as some headers are stored in flags | ||
_header(key, value, options) { | ||
_header(key, value, options = {}) { | ||
options = options || {}; | ||
const append = options.append || false; | ||
@@ -200,6 +197,4 @@ const separator = options.separator || ','; | ||
static entity(tag, options) { | ||
static entity(tag, options = {}) { | ||
options = options || {}; | ||
Hoek.assert(tag !== '*', 'ETag cannot be *'); | ||
@@ -206,0 +201,0 @@ |
@@ -100,3 +100,3 @@ 'use strict'; | ||
auth: { | ||
access: (request) => Auth.access(request, this.public) | ||
access: (request) => Auth.testAccess(request, this.public) | ||
} | ||
@@ -200,2 +200,3 @@ }; | ||
this._extensions.onPreAuth = Ext.combine(this, 'onPreAuth'); | ||
this._extensions.onCredentials = Ext.combine(this, 'onCredentials'); | ||
this._extensions.onPostAuth = Ext.combine(this, 'onPostAuth'); | ||
@@ -250,2 +251,12 @@ this._extensions.onPreHandler = Ext.combine(this, 'onPreHandler'); | ||
if (this._core.auth._enabled(this, 'authenticate') && | ||
this._extensions.onCredentials.nodes) { | ||
this._cycle.push(this._extensions.onCredentials); | ||
} | ||
if (this._core.auth._enabled(this, 'access')) { | ||
this._cycle.push(Auth.access); | ||
} | ||
if (this._extensions.onPostAuth.nodes) { | ||
@@ -362,3 +373,5 @@ this._cycle.push(this._extensions.onPostAuth); | ||
return request._core.toolkit.failAction(request, request.route.settings.state.failAction, parseError, { tags: ['state', 'error'], log: { header: cookies, errors: parseError.data } }); | ||
parseError.header = cookies; | ||
return request._core.toolkit.failAction(request, request.route.settings.state.failAction, parseError, { tags: ['state', 'error'] }); | ||
}; | ||
@@ -365,0 +378,0 @@ |
@@ -10,2 +10,3 @@ 'use strict'; | ||
const Core = require('./core'); | ||
const Cors = require('./cors'); | ||
const Ext = require('./ext'); | ||
@@ -57,2 +58,3 @@ const Package = require('../package.json'); | ||
onPreAuth: new Ext('onPreAuth', core), | ||
onCredentials: new Ext('onCredentials', core), | ||
onPostAuth: new Ext('onPostAuth', core), | ||
@@ -105,3 +107,3 @@ onPreHandler: new Ext('onPreHandler', core), | ||
decorate(type, property, method, options) { | ||
decorate(type, property, method, options = {}) { | ||
@@ -112,8 +114,8 @@ Hoek.assert(this._core.decorations[type], 'Unknown decoration type:', type); | ||
Hoek.assert(property[0] !== '_', 'Property name cannot begin with an underscore:', property); | ||
Hoek.assert(!options || type === 'request', 'Cannot specify options for non-request decoration'); | ||
Hoek.assert(this._core.decorations[type].indexOf(property) === -1, `${type[0].toUpperCase() + type.slice(1)} decoration already defined: ${property}`); | ||
// Handler | ||
if (type === 'handler') { | ||
if (type === 'handler') { | ||
Hoek.assert(!this._core.handlers[property], 'Handler name already exists:', property); | ||
// Handler | ||
Hoek.assert(typeof method === 'function', 'Handler must be a function:', property); | ||
@@ -123,32 +125,29 @@ Hoek.assert(!method.defaults || typeof method.defaults === 'object' || typeof method.defaults === 'function', 'Handler defaults property must be an object or function'); | ||
this._core.handlers[property] = method; | ||
this._core.decorations.handler.push(property); | ||
} | ||
else if (type === 'request') { | ||
// Request | ||
// Request | ||
if (type === 'request') { | ||
this._core.requestor.decorate(property, method, options); | ||
this._core.decorations.request.push(property); | ||
return; | ||
} | ||
else if (type === 'toolkit') { | ||
// Toolkit | ||
// Toolkit | ||
if (type === 'toolkit') { | ||
this._core.toolkit.decorate(property, method); | ||
this._core.decorations.toolkit.push(property); | ||
return; | ||
} | ||
else { | ||
// Server | ||
// Server | ||
Hoek.assert(!this._core.serverDecorations[property], 'Server decoration already defined:', property); | ||
Hoek.assert(this[property] === undefined && this._core[property] === undefined, 'Cannot override the built-in server interface method:', property); | ||
Hoek.assert(this[property] === undefined && this._core[property] === undefined, 'Cannot override the built-in server interface method:', property); | ||
this._core.serverDecorations[property] = method; | ||
this._core.decorations.server.push(property); | ||
this._core.instances.forEach((server) => { | ||
this._core.serverDecorations[property] = method; | ||
this._core.instances.forEach((server) => { | ||
server[property] = method; | ||
}); | ||
server[property] = method; | ||
}); | ||
} | ||
this._core.decorations[type].push(property); | ||
} | ||
@@ -283,5 +282,5 @@ | ||
log(tags, data, timestamp) { | ||
log(tags, data) { | ||
return this._core.log(tags, data, timestamp); | ||
return this._core.log(tags, data); | ||
} | ||
@@ -316,3 +315,3 @@ | ||
method(name, method, options) { | ||
method(name, method, options = {}) { | ||
@@ -453,3 +452,4 @@ return this._core.methods.add(name, method, options, this.realm); | ||
this.events.emit('route', [route.public, server]); | ||
this.events.emit('route', route.public); | ||
Cors.options(route.public, server); | ||
} | ||
@@ -456,0 +456,0 @@ |
@@ -29,3 +29,2 @@ 'use strict'; | ||
Hoek.assert(!this._decorations || !this._decorations[property], 'Reply interface decoration already defined:', property); | ||
Hoek.assert(['abandon', 'authenticated', 'close', 'context', 'continue', 'entity', 'redirect', 'realm', 'request', 'response', 'state', 'unauthenticated', 'unstate'].indexOf(property) === -1, 'Cannot override built-in toolkit decoration:', property); | ||
@@ -47,3 +46,3 @@ | ||
catch (err) { | ||
response = err instanceof Error ? Boom.boomify(err) : Boom.badImplementation('Unhandled rejected promise', err); | ||
response = err instanceof Error ? Boom.boomify(err) : Boom.badImplementation('Cannot throw non-error object', err); | ||
} | ||
@@ -93,3 +92,3 @@ | ||
if (failAction === 'log') { | ||
request._log(options.tags, options.log || err); | ||
request._log(options.tags, err); | ||
return retain; | ||
@@ -96,0 +95,0 @@ } |
@@ -5,3 +5,3 @@ { | ||
"homepage": "http://hapijs.com", | ||
"version": "17.0.0-rc8", | ||
"version": "17.0.0-rc9", | ||
"repository": { | ||
@@ -46,3 +46,3 @@ "type": "git", | ||
"vision": "5.0.0-rc8", | ||
"wreck": "13.x.x" | ||
"wreck": "14.x.x" | ||
}, | ||
@@ -49,0 +49,0 @@ "scripts": { |
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
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
161216
4017