Example #1
0
internals.Any.prototype.options = function (options) {

    var obj = this.clone();
    obj._settings = Hoek.applyToDefaults(obj._settings || {}, options);
    return obj;
};
Example #2
0
            });
    },

    /**
     * Subscribe to a fanout exchange. Automatic reconnection to a new channel on connection error/lost.
     *
     * @param       {object}        params                  Function params
     * @param       {string}        params.exchange         Exchange name
     * @param       {object}        [params.options]        Exchange/queue settings (same as amqp)
     * @param       {string}        [params.queue]          Queue to send in if no routing key is specified (default to queue '')
     * @param       {function}      [params.waitingFunc]    Function to call on connection to the channel
     * @param       {function}      params.receiveFunc      Function to call on message consumption (take message object in parameter)
     * @returns {*}
     */
    subscribe(params) {
        const settings    = hoek.applyToDefaults(defaultRabbit, params);
        const subFunc     = channel => (
            channel.assertExchange(settings.exchange, 'fanout', _.pick(settings.options, exchangeOpt))
                .then(() => channel.assertQueue(settings.queue, _.pick(settings.options, queueOpt)))
                .then(queueOk => internals._bind(channel, queueOk.queue, settings))
                .then(queue => (
                    internals._consume({
                        channel,
                        queue,
                        options     : settings.options,
                        receiveFunc : settings.receiveFunc,
                    })
                ))
                .then(settings.waitingFunc)
        );
Example #3
0
exports.register = function (server, options, next) {
	internals = Hoek.applyToDefaults(internals, options);
	server.dependency(['bedwetter', 'dogwater'], internals.after);

	next();
};
Example #4
0
exports.register = function (server, options, next) {

    options = Hoek.applyToDefaults({ basePath: '' }, options);


    server.route({
        method: 'GET',
        path: options.basePath + '/sessions',
        config: {
            auth: {
                strategy: 'simple',
                scope: 'admin'
            },
            validate: {
                query: {
                    fields: Joi.string(),
                    sort: Joi.string(),
                    limit: Joi.number().default(20),
                    page: Joi.number().default(1)
                }
            },
            pre: [
                AuthPlugin.preware.ensureAdminGroup('root')
            ]
        },
        handler: function (request, reply) {

            var Session = request.server.plugins['hapi-mongo-models'].Session;
            var query = {};
            var fields = request.query.fields;
            var sort = request.query.sort;
            var limit = request.query.limit;
            var page = request.query.page;

            Session.pagedFind(query, fields, sort, limit, page, function (err, results) {

                if (err) {
                    return reply(err);
                }

                reply(results);
            });
        }
    });


    server.route({
        method: 'GET',
        path: options.basePath + '/sessions/{id}',
        config: {
            auth: {
                strategy: 'simple',
                scope: 'admin'
            },
            pre: [
                AuthPlugin.preware.ensureAdminGroup('root')
            ]
        },
        handler: function (request, reply) {

            var Session = request.server.plugins['hapi-mongo-models'].Session;

            Session.findById(request.params.id, function (err, session) {

                if (err) {
                    return reply(err);
                }

                if (!session) {
                    return reply({ message: 'Document not found.' }).code(404);
                }

                reply(session);
            });
        }
    });


    server.route({
        method: 'DELETE',
        path: options.basePath + '/sessions/{id}',
        config: {
            auth: {
                strategy: 'simple',
                scope: 'admin'
            },
            pre: [
                AuthPlugin.preware.ensureAdminGroup('root')
            ]
        },
        handler: function (request, reply) {

            var Session = request.server.plugins['hapi-mongo-models'].Session;

            Session.findByIdAndRemove(request.params.id, function (err, count) {

                if (err) {
                    return reply(err);
                }

                if (count === 0) {
                    return reply({ message: 'Document not found.' }).code(404);
                }

                reply({ message: 'Success.' });
            });
        }
    });


    next();
};
Example #5
0
var before = lab.before;
var after = lab.after;
var expect = Code.expect;

var StorageMongo = require('../lib/storage-mongo');
var StorageFS = require('../lib/storage-fs');
var mongodb = require('mongodb');
var _ = require('lodash');
var utils = require('../lib/utils');
var Hoek = require('hoek');
var rimraf = require('rimraf');

var configMongo = require('./config.json');
var configFS = Hoek.applyToDefaults(configMongo, {
	"storage": {
		"type": "fs",
		"path": ".scoped-registry-tmp"
	}
});

var fixPublish = require('./fixtures/publish_joi.json');
var fixPublish2 = require('./fixtures/publish_dummy.json');
var fixPublish3 = require('./fixtures/publish_joi_update.json');

describe('storage', function() {
	_.each([{
		store: StorageFS,
		name: 'Filesystem',
		config: configFS
	}, {
		store: StorageMongo,
		name: 'MongoDB',
Example #6
0
exports.register = function (server, options, next) {

    options = Hoek.applyToDefaults({ basePath: '' }, options);


    server.route({
        method: 'GET',
        path: options.basePath + '/admin-groups',
        config: {
            auth: {
                strategy: 'simple',
                scope: 'admin'
            },
            validate: {
                query: {
                    fields: Joi.string(),
                    sort: Joi.string().default('_id'),
                    limit: Joi.number().default(20),
                    page: Joi.number().default(1)
                }
            },
            pre: [
                AuthPlugin.preware.ensureAdminGroup('root')
            ]
        },
        handler: function (request, reply) {

            var AdminGroup = request.server.plugins['hapi-mongo-models'].AdminGroup;
            var query = {};
            var fields = request.query.fields;
            var sort = request.query.sort;
            var limit = request.query.limit;
            var page = request.query.page;

            AdminGroup.pagedFind(query, fields, sort, limit, page, function (err, results) {

                if (err) {
                    return reply(err);
                }

                reply(results);
            });
        }
    });


    server.route({
        method: 'GET',
        path: options.basePath + '/admin-groups/{id}',
        config: {
            auth: {
                strategy: 'simple',
                scope: 'admin'
            },
            pre: [
                AuthPlugin.preware.ensureAdminGroup('root')
            ]
        },
        handler: function (request, reply) {

            var AdminGroup = request.server.plugins['hapi-mongo-models'].AdminGroup;

            AdminGroup.findById(request.params.id, function (err, adminGroup) {

                if (err) {
                    return reply(err);
                }

                if (!adminGroup) {
                    return reply({ message: 'Document not found.' }).code(404);
                }

                reply(adminGroup);
            });
        }
    });


    server.route({
        method: 'POST',
        path: options.basePath + '/admin-groups',
        config: {
            auth: {
                strategy: 'simple',
                scope: 'admin'
            },
            validate: {
                payload: {
                    name: Joi.string().required()
                }
            },
            pre: [
                AuthPlugin.preware.ensureAdminGroup('root')
            ]
        },
        handler: function (request, reply) {

            var AdminGroup = request.server.plugins['hapi-mongo-models'].AdminGroup;
            var name = request.payload.name;

            AdminGroup.create(name, function (err, adminGroup) {

                if (err) {
                    return reply(err);
                }

                reply(adminGroup);
            });
        }
    });


    server.route({
        method: 'PUT',
        path: options.basePath + '/admin-groups/{id}',
        config: {
            auth: {
                strategy: 'simple',
                scope: 'admin'
            },
            validate: {
                payload: {
                    name: Joi.string().required()
                }
            },
            pre: [
                AuthPlugin.preware.ensureAdminGroup('root')
            ]
        },
        handler: function (request, reply) {

            var AdminGroup = request.server.plugins['hapi-mongo-models'].AdminGroup;
            var id = request.params.id;
            var update = {
                $set: {
                    name: request.payload.name
                }
            };

            AdminGroup.findByIdAndUpdate(id, update, function (err, adminGroup) {

                if (err) {
                    return reply(err);
                }

                if (!adminGroup) {
                    return reply({ message: 'Document not found.' }).code(404);
                }

                reply(adminGroup);
            });
        }
    });


    server.route({
        method: 'PUT',
        path: options.basePath + '/admin-groups/{id}/permissions',
        config: {
            auth: {
                strategy: 'simple',
                scope: 'admin'
            },
            validate: {
                payload: {
                    permissions: Joi.object().required()
                }
            },
            pre: [
                AuthPlugin.preware.ensureAdminGroup('root')
            ]
        },
        handler: function (request, reply) {

            var AdminGroup = request.server.plugins['hapi-mongo-models'].AdminGroup;
            var id = request.params.id;
            var update = {
                $set: {
                    permissions: request.payload.permissions
                }
            };

            AdminGroup.findByIdAndUpdate(id, update, function (err, adminGroup) {

                if (err) {
                    return reply(err);
                }

                reply(adminGroup);
            });
        }
    });


    server.route({
        method: 'DELETE',
        path: options.basePath + '/admin-groups/{id}',
        config: {
            auth: {
                strategy: 'simple',
                scope: 'admin'
            },
            pre: [
                AuthPlugin.preware.ensureAdminGroup('root')
            ]
        },
        handler: function (request, reply) {

            var AdminGroup = request.server.plugins['hapi-mongo-models'].AdminGroup;

            AdminGroup.findByIdAndDelete(request.params.id, function (err, adminGroup) {

                if (err) {
                    return reply(err);
                }

                if (!adminGroup) {
                    return reply({ message: 'Document not found.' }).code(404);
                }

                reply({ message: 'Success.' });
            });
        }
    });


    next();
};
Example #7
0
internals.Object.prototype._base = function (value, state, options) {

    let target = value;
    const errors = [];
    const finish = () => {

        return {
            value: target,
            errors: errors.length ? errors : null
        };
    };

    if (typeof value === 'string' &&
        options.convert) {

        try {
            value = JSON.parse(value);
        }
        catch (parseErr) { }
    }

    const type = this._flags.func ? 'function' : 'object';
    if (!value ||
        typeof value !== type ||
        Array.isArray(value)) {

        errors.push(this.createError(type + '.base', null, state, options));
        return finish();
    }

    // Skip if there are no other rules to test

    if (!this._inner.renames.length &&
        !this._inner.dependencies.length &&
        !this._inner.children &&                    // null allows any keys
        !this._inner.patterns.length) {

        target = value;
        return finish();
    }

    // Ensure target is a local copy (parsed) or shallow copy

    if (target === value) {
        if (type === 'object') {
            target = Object.create(Object.getPrototypeOf(value));
        }
        else {
            target = function () {

                return value.apply(this, arguments);
            };

            target.prototype = Hoek.clone(value.prototype);
        }

        const valueKeys = Object.keys(value);
        for (let i = 0; i < valueKeys.length; ++i) {
            target[valueKeys[i]] = value[valueKeys[i]];
        }
    }
    else {
        target = value;
    }

    // Rename keys

    const renamed = {};
    for (let i = 0; i < this._inner.renames.length; ++i) {
        const item = this._inner.renames[i];

        if (item.options.ignoreUndefined && target[item.from] === undefined) {
            continue;
        }

        if (!item.options.multiple &&
            renamed[item.to]) {

            errors.push(this.createError('object.rename.multiple', { from: item.from, to: item.to }, state, options));
            if (options.abortEarly) {
                return finish();
            }
        }

        if (Object.prototype.hasOwnProperty.call(target, item.to) &&
            !item.options.override &&
            !renamed[item.to]) {

            errors.push(this.createError('object.rename.override', { from: item.from, to: item.to }, state, options));
            if (options.abortEarly) {
                return finish();
            }
        }

        if (target[item.from] === undefined) {
            delete target[item.to];
        }
        else {
            target[item.to] = target[item.from];
        }

        renamed[item.to] = true;

        if (!item.options.alias) {
            delete target[item.from];
        }
    }

    // Validate schema

    if (!this._inner.children &&            // null allows any keys
        !this._inner.patterns.length &&
        !this._inner.dependencies.length) {

        return finish();
    }

    const unprocessed = Hoek.mapToObject(Object.keys(target));

    // Children mustn't inherit the current label if it exists
    const childOptions = options.language && options.language.label ?
        Hoek.applyToDefaults(options, { language: { label: null } }, true) :
        options;

    if (this._inner.children) {
        for (let i = 0; i < this._inner.children.length; ++i) {
            const child = this._inner.children[i];
            const key = child.key;
            const item = target[key];

            delete unprocessed[key];

            const localState = { key, path: (state.path || '') + (state.path && key ? '.' : '') + key, parent: target, reference: state.reference };
            const result = child.schema._validate(item, localState, childOptions);
            if (result.errors) {
                errors.push(this.createError('object.child', { key, reason: result.errors }, localState, childOptions));

                if (options.abortEarly) {
                    return finish();
                }
            }

            if (child.schema._flags.strip || (result.value === undefined && result.value !== item)) {
                delete target[key];
            }
            else if (result.value !== undefined) {
                target[key] = result.value;
            }
        }
    }

    // Unknown keys

    let unprocessedKeys = Object.keys(unprocessed);
    if (unprocessedKeys.length &&
        this._inner.patterns.length) {

        for (let i = 0; i < unprocessedKeys.length; ++i) {
            const key = unprocessedKeys[i];

            for (let j = 0; j < this._inner.patterns.length; ++j) {
                const pattern = this._inner.patterns[j];

                if (pattern.regex.test(key)) {
                    delete unprocessed[key];

                    const item = target[key];
                    const localState = { key, path: (state.path ? state.path + '.' : '') + key, parent: target, reference: state.reference };
                    const result = pattern.rule._validate(item, localState, options);
                    if (result.errors) {
                        errors.push(this.createError('object.child', { key, reason: result.errors }, localState, options));

                        if (options.abortEarly) {
                            return finish();
                        }
                    }

                    if (result.value !== undefined) {
                        target[key] = result.value;
                    }
                }
            }
        }

        unprocessedKeys = Object.keys(unprocessed);
    }

    if ((this._inner.children || this._inner.patterns.length) && unprocessedKeys.length) {
        if (options.stripUnknown ||
            options.skipFunctions) {

            for (let i = 0; i < unprocessedKeys.length; ++i) {
                const key = unprocessedKeys[i];

                if (options.stripUnknown) {
                    delete target[key];
                    delete unprocessed[key];
                }
                else if (typeof target[key] === 'function') {
                    delete unprocessed[key];
                }
            }

            unprocessedKeys = Object.keys(unprocessed);
        }

        if (unprocessedKeys.length &&
            (this._flags.allowUnknown !== undefined ? !this._flags.allowUnknown : !options.allowUnknown)) {

            for (let i = 0; i < unprocessedKeys.length; ++i) {
                errors.push(this.createError('object.allowUnknown', null, { key: unprocessedKeys[i], path: state.path + (state.path ? '.' : '') + unprocessedKeys[i] }, childOptions));
            }
        }
    }

    // Validate dependencies

    for (let i = 0; i < this._inner.dependencies.length; ++i) {
        const dep = this._inner.dependencies[i];
        const err = internals[dep.type].call(this, dep.key !== null && value[dep.key], dep.peers, target, { key: dep.key, path: (state.path || '') + (dep.key ? '.' + dep.key : '') }, options);
        if (err) {
            errors.push(err);
            if (options.abortEarly) {
                return finish();
            }
        }
    }

    return finish();
};
Example #8
0
 .then(sealed => super.create(hoek.applyToDefaults(config, { value: sealed })));
Example #9
0
internals.Manager.prototype.render = function (filename, context, options, callback) {

    var self = this;

    context = context || {};
    options = options || {};

    var engine = null;

    var fileExtension = Path.extname(filename).slice(1);
    var extension = fileExtension || self._defaultExtension;
    if (!extension) {
        return callback(Boom.badImplementation('Unknown extension and no defaultExtension configured for view template: ' + filename));
    }

    engine = self._engines[extension];
    if (!engine) {
        return callback(Boom.badImplementation('No view engine found for file: ' + filename));
    }

    var settings = Hoek.applyToDefaults(engine.config, options);

    var templatePath = this._path(filename + (fileExtension ? '' : engine.suffix), settings);
    if (templatePath.isBoom) {
        return callback(templatePath);
    }

    this._compile(templatePath, engine, settings, function (err, compiled) {

        if (err) {
            return callback(err);
        }

        // No layout

        if (!settings.layout) {
            compiled(context, settings.runtimeOptions, function (err, rendered) {

                if (err) {
                    return callback(Boom.badImplementation(err.message, err));
                }

                return callback(null, rendered, settings);
            });

            return;
        }

        // With layout

        if (context.hasOwnProperty(settings.layoutKeyword)) {
            return callback(Boom.badImplementation('settings.layoutKeyword conflict', { context: context, keyword: settings.layoutKeyword }));
        }

        var layoutPath = self._path((settings.layout === true ? 'layout' : settings.layout) + engine.suffix, settings, true);
        if (layoutPath.isBoom) {
            return callback(layoutPath);
        }

        self._compile(layoutPath, engine, settings, function (err, layout) {

            if (err) {
                return callback(err);
            }

            compiled(context, settings.runtimeOptions, function (err, rendered) {

                if (err) {
                    return callback(Boom.badImplementation(err.message, err));
                }

                context[settings.layoutKeyword] = rendered;
                layout(context, settings.runtimeOptions, function (err, rendered) {

                    delete context[settings.layoutKeyword];

                    if (err) {
                        return callback(Boom.badImplementation(err.message, err));
                    }

                    return callback(null, rendered, settings);
                });
            });
        });
    });
};
Example #10
0
exports.register = function (plugin, options, next) {

    let settings = Hoek.applyToDefaults(defaults, options);
    const publicDirPath = __dirname + Path.sep + '..' + Path.sep + 'public';
    const swaggerDirPath = publicDirPath + Path.sep + 'swaggerui';

    // add routing swagger json
    plugin.route([{
        method: 'GET',
        path: settings.jsonPath,
        config: {
            auth: settings.auth,
            handler: (request, reply) => {

                Joi.assert(settings, schema);
                Builder.getSwaggerJSON(settings, request, function (err, json) {

                    reply(json).type('application/json');
                });
            },
            plugins: {
                'hapi-swagger': false
            }
        }
    }]);


    // only add 'inert' and 'vision' based routes if needed
    if (settings.enableDocumentation === true) {

        // make sure we have other plug-in dependencies
        plugin.dependency(['inert', 'vision'], (pluginWithDependencies, nextWithDependencies) => {

            // add routing for swaggerui static assets /swaggerui/
            pluginWithDependencies.views({
                engines: {
                    html: {
                        module: require('handlebars')
                    }
                },
                path: swaggerDirPath
            });

            pluginWithDependencies.route([{
                method: 'GET',
                path: settings.documentationPath,
                config: {
                    auth: settings.auth
                },
                handler: (request, reply) => {

                    reply.view('index.html', {});
                }
            },{
                method: 'GET',
                path: settings.swaggerUIPath + '{path*}',
                config: {
                    auth: settings.auth
                },
                handler: {
                    directory: {
                        path: swaggerDirPath + Path.sep,
                        listing: true,
                        index: false
                    }
                }
            },{
                method: 'GET',
                path: settings.swaggerUIPath + 'extend.js',
                config: {
                    auth: settings.auth
                },
                handler: {
                    file: publicDirPath + Path.sep + 'extend.js'
                }
            }]);

            appendDataContext(pluginWithDependencies, settings);

            nextWithDependencies();

        });
    }

    // TODO: need to work how to test this as it need a request object
    // Undocument API interface, it may change
    /* $lab:coverage:off$ */
    plugin.expose('getJSON', function (exposeOptions, request, callback) {

        // use either options passed to function or plug-in scope options
        let exposeSettings = {};
        if (exposeOptions && Utilities.hasProperties(exposeOptions)) {
            exposeSettings = Hoek.applyToDefaults(defaults, exposeOptions);
            Joi.assert(exposeSettings, schema);
        } else {
            exposeSettings = Hoek.clone(settings);
        }
        Builder.getSwaggerJSON(exposeSettings, request, callback);
    });
    /* $lab:coverage:on$ */


    next();
};
Example #11
0
    /**
     * Instantiate a Secret class
     * @method createClass
     * @param  config
     * @return {Secret}
     */
    createClass(config) {
        const c = hoek.applyToDefaults(config, { password: this[password] });

        return new Secret(c);
    }
Example #12
0
exports.register = function (server, options, next) {

    options = Hoek.applyToDefaults({ basePath: '' }, options);


    server.route({
        method: 'GET',
        path: options.basePath + '/accounts',
        config: {
            auth: {
                strategy: 'session',
                scope: 'admin'
            },
            validate: {
                query: {
                    username: Joi.string().allow(''),
                    fields: Joi.string(),
                    sort: Joi.string().default('_id'),
                    limit: Joi.number().default(20),
                    page: Joi.number().default(1)
                }
            }
        },
        handler: function (request, reply) {

            var Account = request.server.plugins['hapi-mongo-models'].Account;
            var query = {};
            if (request.query.username) {
                query['user.name'] = new RegExp('^.*?' + request.query.username + '.*$', 'i');
            }
            var fields = request.query.fields;
            var sort = request.query.sort;
            var limit = request.query.limit;
            var page = request.query.page;

            Account.pagedFind(query, fields, sort, limit, page, function (err, results) {

                if (err) {
                    return reply(err);
                }

                reply(results);
            });
        }
    });


    server.route({
        method: 'GET',
        path: options.basePath + '/accounts/{id}',
        config: {
            auth: {
                strategy: 'session',
                scope: 'admin'
            }
        },
        handler: function (request, reply) {

            var Account = request.server.plugins['hapi-mongo-models'].Account;

            Account.findById(request.params.id, function (err, account) {

                if (err) {
                    return reply(err);
                }

                if (!account) {
                    return reply({ message: 'Document not found.' }).code(404);
                }

                reply(account);
            });
        }
    });


    server.route({
        method: 'GET',
        path: options.basePath + '/accounts/my',
        config: {
            auth: {
                strategy: 'session',
                scope: 'account'
            }
        },
        handler: function (request, reply) {

            var Account = request.server.plugins['hapi-mongo-models'].Account;
            var id = request.auth.credentials.roles.account._id.toString();
            var fields = Account.fieldsAdapter('user name timeCreated');

            Account.findById(id, fields, function (err, account) {

                if (err) {
                    return reply(err);
                }

                if (!account) {
                    return reply({ message: 'Document not found. That is strange.' }).code(404);
                }

                reply(account);
            });
        }
    });


    server.route({
        method: 'POST',
        path: options.basePath + '/accounts',
        config: {
            auth: {
                strategy: 'session',
                scope: 'admin'
            },
            validate: {
                payload: {
                    name: Joi.string().required()
                }
            }
        },
        handler: function (request, reply) {

            var Account = request.server.plugins['hapi-mongo-models'].Account;
            var name = request.payload.name;

            Account.create(name, function (err, account) {

                if (err) {
                    return reply(err);
                }

                reply(account);
            });
        }
    });


    server.route({
        method: 'PUT',
        path: options.basePath + '/accounts/{id}',
        config: {
            auth: {
                strategy: 'session',
                scope: 'admin'
            },
            validate: {
                payload: {
                    nameFirst: Joi.string().required(),
                    nameMiddle: Joi.string().allow('', null),
                    nameLast: Joi.string().required()
                }
            }
        },
        handler: function (request, reply) {

            var Account = request.server.plugins['hapi-mongo-models'].Account;
            var id = request.params.id;
            var update = {
                $set: {
                    name: {
                        first: request.payload.nameFirst,
                        middle: request.payload.nameMiddle,
                        last: request.payload.nameLast
                    }
                }
            };

            Account.findByIdAndUpdate(id, update, function (err, account) {

                if (err) {
                    return reply(err);
                }

                if (!account) {
                    return reply({ message: 'Document not found.' }).code(404);
                }

                reply(account);
            });
        }
    });


    server.route({
        method: 'PUT',
        path: options.basePath + '/accounts/my',
        config: {
            auth: {
                strategy: 'session',
                scope: 'account'
            },
            validate: {
                payload: {
                    nameFirst: Joi.string().required(),
                    nameMiddle: Joi.string().allow(''),
                    nameLast: Joi.string().required()
                }
            }
        },
        handler: function (request, reply) {

            var Account = request.server.plugins['hapi-mongo-models'].Account;
            var id = request.auth.credentials.roles.account._id.toString();
            var update = {
                $set: {
                    name: {
                        first: request.payload.nameFirst,
                        middle: request.payload.nameMiddle,
                        last: request.payload.nameLast
                    }
                }
            };
            var findOptions = {
                fields: Account.fieldsAdapter('user name timeCreated')
            };

            Account.findByIdAndUpdate(id, update, findOptions, function (err, account) {

                if (err) {
                    return reply(err);
                }

                reply(account);
            });
        }
    });


    server.route({
        method: 'PUT',
        path: options.basePath + '/accounts/{id}/user',
        config: {
            auth: {
                strategy: 'session',
                scope: 'admin'
            },
            validate: {
                payload: {
                    username: Joi.string().lowercase().required()
                }
            },
            pre: [{
                assign: 'account',
                method: function (request, reply) {

                    var Account = request.server.plugins['hapi-mongo-models'].Account;

                    Account.findById(request.params.id, function (err, account) {

                        if (err) {
                            return reply(err);
                        }

                        if (!account) {
                            return reply({ message: 'Document not found.' }).takeover().code(404);
                        }

                        reply(account);
                    });
                }
            }, {
                assign: 'user',
                method: function (request, reply) {

                    var User = request.server.plugins['hapi-mongo-models'].User;

                    User.findByUsername(request.payload.username, function (err, user) {

                        if (err) {
                            return reply(err);
                        }

                        if (!user) {
                            return reply({ message: 'User document not found.' }).takeover().code(404);
                        }

                        if (user.roles &&
                            user.roles.account &&
                            user.roles.account.id !== request.params.id) {

                            var response = {
                                message: 'User is already linked to another account. Unlink first.'
                            };

                            return reply(response).takeover().code(409);
                        }

                        reply(user);
                    });
                }
            }, {
                assign: 'userCheck',
                method: function (request, reply) {

                    if (request.pre.account.user &&
                        request.pre.account.user.id !== request.pre.user._id.toString()) {

                        var response = {
                            message: 'Account is already linked to another user. Unlink first.'
                        };

                        return reply(response).takeover().code(409);
                    }

                    reply(true);
                }
            }]
        },
        handler: function (request, reply) {

            Async.auto({
                account: function (done) {

                    var Account = request.server.plugins['hapi-mongo-models'].Account;
                    var id = request.params.id;
                    var update = {
                        $set: {
                            user: {
                                id: request.pre.user._id.toString(),
                                name: request.pre.user.username
                            }
                        }
                    };

                    Account.findByIdAndUpdate(id, update, done);
                },
                user: function (done) {

                    var User = request.server.plugins['hapi-mongo-models'].User;
                    var id = request.pre.user._id;
                    var update = {
                        $set: {
                            'roles.account': {
                                id: request.pre.account._id.toString(),
                                name: request.pre.account.name.first + ' ' + request.pre.account.name.last
                            }
                        }
                    };

                    User.findByIdAndUpdate(id, update, done);
                }
            }, function (err, results) {

                if (err) {
                    return reply(err);
                }

                reply(results.account);
            });
        }
    });


    server.route({
        method: 'DELETE',
        path: options.basePath + '/accounts/{id}/user',
        config: {
            auth: {
                strategy: 'session',
                scope: 'admin'
            },
            pre: [{
                assign: 'account',
                method: function (request, reply) {

                    var Account = request.server.plugins['hapi-mongo-models'].Account;

                    Account.findById(request.params.id, function (err, account) {

                        if (err) {
                            return reply(err);
                        }

                        if (!account) {
                            return reply({ message: 'Document not found.' }).takeover().code(404);
                        }

                        if (!account.user || !account.user.id) {
                            return reply(account).takeover();
                        }

                        reply(account);
                    });
                }
            }, {
                assign: 'user',
                method: function (request, reply) {

                    var User = request.server.plugins['hapi-mongo-models'].User;

                    User.findById(request.pre.account.user.id, function (err, user) {

                        if (err) {
                            return reply(err);
                        }

                        if (!user) {
                            return reply({ message: 'User document not found.' }).takeover().code(404);
                        }

                        reply(user);
                    });
                }
            }]
        },
        handler: function (request, reply) {

            Async.auto({
                account: function (done) {

                    var Account = request.server.plugins['hapi-mongo-models'].Account;
                    var id = request.params.id;
                    var update = {
                        $unset: {
                            user: undefined
                        }
                    };

                    Account.findByIdAndUpdate(id, update, done);
                },
                user: function (done) {

                    var User = request.server.plugins['hapi-mongo-models'].User;
                    var id = request.pre.user._id.toString();
                    var update = {
                        $unset: {
                            'roles.account': undefined
                        }
                    };

                    User.findByIdAndUpdate(id, update, done);
                }
            }, function (err, results) {

                if (err) {
                    return reply(err);
                }

                reply(results.account);
            });
        }
    });


    server.route({
        method: 'POST',
        path: options.basePath + '/accounts/{id}/notes',
        config: {
            auth: {
                strategy: 'session',
                scope: 'admin'
            },
            validate: {
                payload: {
                    data: Joi.string().required()
                }
            }
        },
        handler: function (request, reply) {

            var Account = request.server.plugins['hapi-mongo-models'].Account;
            var id = request.params.id;
            var update = {
                $push: {
                    notes: {
                        data: request.payload.data,
                        timeCreated: new Date(),
                        userCreated: {
                            id: request.auth.credentials.user._id.toString(),
                            name: request.auth.credentials.user.username
                        }
                    }
                }
            };

            Account.findByIdAndUpdate(id, update, function (err, account) {

                if (err) {
                    return reply(err);
                }

                reply(account);
            });
        }
    });


    server.route({
        method: 'POST',
        path: options.basePath + '/accounts/{id}/status',
        config: {
            auth: {
                strategy: 'session',
                scope: 'admin'
            },
            validate: {
                payload: {
                    status: Joi.string().required()
                }
            },
            pre: [{
                assign: 'status',
                method: function (request, reply) {

                    var Status = request.server.plugins['hapi-mongo-models'].Status;

                    Status.findById(request.payload.status, function (err, status) {

                        if (err) {
                            return reply(err);
                        }

                        reply(status);
                    });
                }
            }]
        },
        handler: function (request, reply) {

            var Account = request.server.plugins['hapi-mongo-models'].Account;
            var id = request.params.id;
            var newStatus = {
                id: request.pre.status._id.toString(),
                name: request.pre.status.name,
                timeCreated: new Date(),
                userCreated: {
                    id: request.auth.credentials.user._id.toString(),
                    name: request.auth.credentials.user.username
                }
            };
            var update = {
                $set: {
                    'status.current': newStatus
                },
                $push: {
                    'status.log': newStatus
                }
            };

            Account.findByIdAndUpdate(id, update, function (err, account) {

                if (err) {
                    return reply(err);
                }

                reply(account);
            });
        }
    });


    server.route({
        method: 'DELETE',
        path: options.basePath + '/accounts/{id}',
        config: {
            auth: {
                strategy: 'session',
                scope: 'admin'
            },
            pre: [
                AuthPlugin.preware.ensureAdminGroup('root')
            ]
        },
        handler: function (request, reply) {

            var Account = request.server.plugins['hapi-mongo-models'].Account;

            Account.findByIdAndDelete(request.params.id, function (err, account) {

                if (err) {
                    return reply(err);
                }

                if (!account) {
                    return reply({ message: 'Document not found.' }).code(404);
                }

                reply({ message: 'Success.' });
            });
        }
    });


    next();
};
Example #13
0
var base = {
  path: '/limited',
  method: 'get',
  handler: function(request, reply) {
    reply();
  }
};

exports.offByDefault = base;

exports.defaults = Hoek.applyToDefaults(base, {
  config: {
    plugins: {
      'hapi-limiter': {
        enable: true
      }
    }
  }
});

exports.overrides = Hoek.applyToDefaults(base, {
  config: {
    plugins: {
      'hapi-limiter': {
        enable: true,
        limit: 5,
        ttl: 8000,
        generateKeyFunc: function(request) {
          return 'customkey';
        }
Example #14
0
                .then((channel) => {
                    const settings    = hoek.applyToDefaults(defaultRabbit, params);
                    const message     = hoek.applyToDefaults(defaultMessage, params.message);

                    let rpcPromise = new Promise((resolve) => {
                        const correlationId = uuid.v1();

                        const replyFunc = (msg) => {
                            if (msg.properties.correlationId === correlationId) {
                                resolve(msg);
                            }
                        };

                        // declare anonyme queue for RPC answer
                        channel.assertQueue('', {
                            exclusive   : true,
                            autoDelete  : true,
                        })
                            .then(queueOk => queueOk.queue)
                            .then((answerQueue) => {
                                internals._consume({
                                    channel,
                                    queue       : answerQueue,
                                    options     : {
                                        exclusive   : true,
                                    },
                                    receiveFunc : replyFunc,
                                });

                                return answerQueue;
                            })
                            .then((queue) => {
                                // sending the message with replyTo set with the anonymous queue
                                const msgOpt = _.extend({}, message.options, {
                                    correlationId,
                                    replyTo         : queue,
                                });

                                return channel.assertQueue(settings.queue, _.pick(settings.options, queueOpt))
                                    .then(queueOk => channel.publish('', queueOk.queue, new Buffer(message.content), _.pick(msgOpt, messageOpt)))
                                    .then(() => queue);
                            });
                    });

                    if (!_.isUndefined(settings.RPCTimeout)) {
                        rpcPromise = rpcPromise.timeout(settings.RPCTimeout)
                            .catch((err) => {
                                channel.close();
                                return Promise.reject(err);
                            });
                    }

                    return rpcPromise
                        .then((msg) => {
                            channel.close();
                            return msg;
                        })
                        .then((msg) => {
                            settings.receiveFunc(msg);
                            return msg;
                        });
                })
Example #15
0
internals.Any.prototype._validate = function (value, state, options, reference) {

    var self = this;

    // Setup state and settings

    state = state || { key: '', path: '', parent: null, reference: reference };

    if (this._settings) {
        options = Hoek.applyToDefaults(options, this._settings);
    }

    var errors = [];
    var finish = function () {

        return {
            value: (value !== undefined) ? value : (Ref.isRef(self._flags.default) ? self._flags.default(state.parent) : self._flags.default),
            errors: errors.length ? errors : null
        };
    };

    // Check allowed and denied values using the original value

    if (this._valids.has(value, state, this._flags.insensitive)) {
        return finish();
    }

    if (this._invalids.has(value, state, this._flags.insensitive)) {
        errors.push(Errors.create(value === '' ? 'any.empty' : (value === undefined ? 'any.required' : 'any.invalid'), null, state, options));
        if (options.abortEarly ||
            value === undefined) {          // No reason to keep validating missing value

            return finish();
        }
    }

    // Convert value and validate type

    if (this._base) {
        var base = this._base.call(this, value, state, options);
        if (base.errors) {
            value = base.value;
            errors = errors.concat(base.errors);
            return finish();                            // Base error always aborts early
        }

        if (base.value !== value) {
            value = base.value;

            // Check allowed and denied values using the converted value

            if (this._valids.has(value, state, this._flags.insensitive)) {
                return finish();
            }

            if (this._invalids.has(value, state, this._flags.insensitive)) {
                errors.push(Errors.create('any.invalid', null, state, options));
                if (options.abortEarly) {
                    return finish();
                }
            }
        }
    }

    // Required values did not match

    if (this._flags.allowOnly) {
        errors.push(Errors.create('any.allowOnly', { valids: this._valids.toString(false) }, state, options));
        if (options.abortEarly) {
            return finish();
        }
    }

    // Validate tests

    for (var i = 0, il = this._tests.length; i < il; ++i) {
        var test = this._tests[i];
        var err = test.func.call(this, value, state, options);
        if (err) {
            errors.push(err);
            if (options.abortEarly) {
                return finish();
            }
        }
    }

    return finish();
};
Example #16
0
 Object.keys(jobs).forEach((jobName) => {
     jobs[jobName].cache = Hoek.applyToDefaults(cache,
         { job: Hoek.reach(cacheConfig, `job.${jobName}`, { default: [] }) });
 });
Example #17
0
exports.register = function (server, options, next) {

    const settings = Hoek.applyToDefaults(internals.defaults, options);

    server.register({

        register: require('hapi-auth-cookie')
    }, (err) => {

        Hoek.assert(!err, err);
        const authCookieOptions = {
            password: settings.session.cookie.password,
            cookie: settings.session.cookie.name,
            redirectTo: settings.viewPath + '/login',
            isSecure: false
        };
        server.auth.strategy('session', 'cookie', authCookieOptions);
    });

    server.register({

        register: require('bell')
    }, (err) => {

        Hoek.assert(!err, err);
        const bellAuthOptions = {
            provider: 'github',
            password: settings.session.bell.github.password,
            scope: ['user', 'repo'],
            clientId: settings.session.bell.github.clientId,
            clientSecret: settings.session.bell.github.clientSecret,
            isSecure: false
        };
        server.auth.strategy('github', 'bell', bellAuthOptions);
    });

    settings.info = server.info;
    const utils = new Utils(settings);
    settings.Utils = utils;
    const ui = new Ui(settings);

    server.register([Inert, Vision], Hoek.ignore);
    server.views({
        path: __dirname + '/../views',
        partialsPath: __dirname + '/../views/partials',
        helpersPath: __dirname + '/../views/helpers',
        engines: {
            html: require('handlebars')
        }
    });

    server.route([

        {
            method: 'GET', path: '/',
            config: {
                //auth: 'session',
                handler: ui.redirectHome,
                description: 'redirect / to /gills/jobs'
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/jobs',
            config: {
                //auth: 'session',
                handler: ui.Job.getJobsView,
                description: 'get jobs'
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job',
            config: {
                //auth: 'session',
                handler: ui.Job.getJobCreateView,
                description: 'get job create view'
            }
        },
        {
            method: 'POST',
            path: settings.viewPath + '/job',
            config: {
                //auth: 'session',
                handler: ui.Job.createJob,
                description: 'create job',
                validate: {
                    payload: Schema.createJobSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}',
            config: {
                //auth: 'session',
                handler: ui.Job.getJobView,
                description: 'get job view',
                validate: {
                    params: Schema.requiredJobSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/queue/{jobId}/add',
            config: {
                //auth: 'session',
                handler: ui.Queue.addJob,
                description: 'add job to queue',
                validate: {
                    params: Schema.requiredJobSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/queue/{jobId}/remove',
            config: {
                //auth: 'session',
                handler: ui.Queue.removeJob,
                description: 'remove job from queue',
                validate: {
                    params: Schema.requiredJobSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/queue/clear',
            config: {
                //auth: 'session',
                handler: ui.Queue.clearQueue,
                description: 'clear jobs from queue'
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/queue/{jobId}/pr/{pr}/remove',
            config: {
                //auth: 'session',
                handler: ui.Queue.removePullRequest,
                description: 'remove pr from queue',
                validate: {
                    params: Schema.prJobSchema
                }
            }
        },
        {
            method: 'POST',
            path: settings.viewPath + '/job/{jobId}',
            config: {
                //auth: 'session',
                handler: ui.Job.updateJob,
                description: 'update job',
                validate: {
                    params: Schema.requiredJobSchema,
                    payload: Schema.updateJobSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/delete',
            config: {
                //auth: 'session',
                handler: ui.Job.deleteJob,
                description: 'delete job',
                validate: {
                    params: Schema.requiredJobSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/workspace/delete',
            config: {
                //auth: 'session',
                handler: ui.Job.deleteWorkspace,
                description: 'delete workspace',
                validate: {
                    params: Schema.requiredJobSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/commits',
            config: {
                //auth: 'session',
                handler: ui.Job.getCommitsView,
                description: 'get commits',
                validate: {
                    params: Schema.requiredJobSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/run/{runId}',
            config: {
                //auth: 'session',
                handler: ui.Run.getRunView,
                description: 'get run view',
                validate: {
                    params: Schema.requiredRunSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/run/{runId}/archive/{file}',
            config: {
                //auth: 'session',
                handler: ui.Run.getFileView,
                description: 'get file view',
                validate: {
                    params: Schema.getFileSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/run/{runId}/test',
            config: {
                //auth: 'session',
                handler: ui.Run.getTestView,
                description: 'get test view',
                validate: {
                    params: Schema.requiredRunSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/run/{runId}/coverage',
            config: {
                //auth: 'session',
                handler: ui.Run.getCoverageView,
                description: 'get coverage view',
                validate: {
                    params: Schema.requiredRunSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/run/{runId}/delete',
            config: {
                //auth: 'session',
                handler: ui.Run.deleteRun,
                description: 'delete run',
                validate: {
                    params: Schema.requiredRunSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/runs/delete',
            config: {
                //auth: 'session',
                handler: ui.Run.deleteRuns,
                description: 'delete runs',
                validate: {
                    params: Schema.requiredJobSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/run/{runId}/cancel',
            config: {
                //auth: 'session',
                handler: ui.Run.cancelRun,
                description: 'cancel run',
                validate: {
                    params: Schema.requiredRunSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/pr/{pr}/merge',
            config: {
                //auth: 'session',
                handler: ui.Job.mergePullRequest,
                description: 'merge pull request',
                validate: {
                    params: Schema.prJobSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/pr/{pr}/retry',
            config: {
                //auth: 'session',
                handler: ui.Job.retryPullRequest,
                description: 'retry pull request',
                validate: {
                    params: Schema.prJobSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/pr/{pr}/start',
            config: {
                //auth: 'session',
                handler: ui.Job.startPullRequest,
                description: 'start pull request',
                validate: {
                    params: Schema.prJobSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/pr/{pr}/run/{runId}',
            config: {
                //auth: 'session',
                handler: ui.Run.getPullRequestRunView,
                description: 'get pull request run view',
                validate: {
                    params: Schema.prRunSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/job/{jobId}/pr/{pr}/run/{runId}/cancel',
            config: {
                //auth: 'session',
                handler: ui.Run.cancelPullRequest,
                description: 'cancel pull request',
                validate: {
                    params: Schema.prRunSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/reel',
            config: {
                //auth: 'session',
                handler: ui.Reel.getReelCreateView,
                description: 'create reel view'
            }
        },
        {
            method: 'POST',
            path: settings.viewPath + '/reel',
            config: {
                //auth: 'session',
                handler: ui.Reel.createReel,
                description: 'create reel',
                validate: {
                    payload: Schema.createReelSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/reel/{reelId}',
            config: {
                //auth: 'session',
                handler: ui.Reel.getReelView,
                description: 'get reel view',
                validate: {
                    params: Schema.requiredReelSchema
                }
            }
        },
        {
            method: 'POST',
            path: settings.viewPath + '/reel/{reelId}',
            config: {
                //auth: 'session',
                handler: ui.Reel.updateReel,
                description: 'update reel',
                validate: {
                    params: Schema.requiredReelSchema,
                    payload: Schema.updateReelSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/reel/{reelId}/delete',
            config: {
                //auth: 'session',
                handler: ui.Reel.deleteReel,
                description: 'delete reel',
                validate: {
                    params: Schema.requiredReelSchema
                }
            }
        },
        {
            method: 'POST',
            path: settings.viewPath + '/user',
            config: {
                //auth: 'session',
                handler: ui.User.createUser,
                description: 'create user',
                validate: {
                    payload: Schema.createUserSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/user',
            config: {
                //auth: 'session',
                handler: ui.User.getUserCreateView,
                description: 'create user view'
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/user/{userId}',
            config: {
                //auth: 'session',
                handler: ui.User.getUserView,
                description: 'get user view',
                validate: {
                    params: Schema.requiredUserSchema
                }
            }
        },
        {
            method: 'POST',
            path: settings.viewPath + '/user/{userId}',
            config: {
                //auth: 'session',
                handler: ui.User.updateUser,
                description: 'update user',
                validate: {
                    params: Schema.requiredUserSchema,
                    payload: Schema.updateUserSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/users',
            config: {
                //auth: 'session',
                handler: ui.User.getUsersView,
                description: 'get users'
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/user/{userId}/delete',
            config: {
                //auth: 'session',
                handler: ui.User.deleteUser,
                description: 'delete user',
                validate: {
                    params: Schema.requiredUserSchema
                }
            }
        },
        {
            method: 'POST',
            path: settings.viewPath + '/login',
            config: {
                auth: false,
                handler: ui.User.loginUser,
                description: 'login user',
                validate: {
                    payload: Schema.loginUserSchema
                }
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/logout',
            config: {
                //auth: 'session',
                handler: ui.User.logoutUser,
                description: 'logout user'
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/login',
            config: {
                auth: false,
                handler: ui.User.getLoginView,
                description: 'login view'
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/login/github',
            config: {
                auth: 'github',
                handler: ui.User.loginGithub,
                description: 'github login'
            }
        },
        {
            method: 'GET',
            path: settings.viewPath + '/css/{path*}',
            config: css
        },
        {
            method: 'GET',
            path: settings.viewPath + '/js/{path*}',
            config: js
        },
        {
            method: 'GET',
            path: settings.viewPath + '/fonts/{path*}',
            config: fonts
        }
    ]);

    next();
};
 var Downloads = function (override) {
     this.options = Hoek.applyToDefaults(internals._defaults, options || {});
 }
Example #19
0
exports.start = function (argv) {

    process.once('SIGUSR2', function () {

        process.exit(0);
    });

    var start = 0;
    var config = internals.getConfig(argv);
    config = Hoek.applyToDefaults(internals.defaults, config);

    internals.requestOptions = Url.parse(config.url);
    internals.requestOptions.method = 'POST';
    internals.requestOptions.headers = { 'content-type': 'application/json' };
    internals.requestOptions.agent = false;

    var determineStart = function (next) {

        if (config.useLastIndex) {
            internals.lastIndexPath += ('_' + Path.basename(config.path));
        }

        if (config.useLastIndex && Fs.existsSync(internals.lastIndexPath)) {
            var lastContents = Fs.readFileSync(internals.lastIndexPath).toString().split('\n');
            start = parseInt(lastContents[lastContents.length - 1]);
            start = isNaN(start) ? 0 : start;
            Fs.truncateSync(internals.lastIndexPath);
            return next();
        }

        if (!config.onlySendNew) {
            return next();
        }

        Fs.exists(config.path, function (exists) {

            if (!exists) {
                return next();
            }

            Fs.stat(config.path, function (err, stat) {

                if (!err) {
                    start = stat.size ? stat.size - 1 : 0;
                }

                next();
            });
        });
    };

    var processLog = function () {

        Fs.exists(config.path, function (exists) {

            if (!exists) {
                return;
            }

            Fs.stat(config.path, function (err, stat) {

                if (err) {
                    console.error(err);
                    return;
                }

                if (stat.size < start) {
                    start = 0;
                }

                internals.getLog(config.path, start, function (bytesRead, log) {

                    start += bytesRead;
                    internals.broadcast(log);
                    if (config.useLastIndex) {
                        internals.logLastIndex(start);
                    }
                });
            });
        });
    };

    determineStart(function () {

        setInterval(processLog, config.interval);
    });
};
Example #20
0
 config.sites.forEach((site, index) => {
   config.sites[index].wait = site.wait || config.wait
   config.sites[index] = Hoek.applyToDefaults(internals.siteDefaults, site);
   config.sites[index].keywords = config.sites[index].keywords.concat(config.keywords)
 })
Example #21
0
File: flute.js Project: rs22/fluffy
internals.fluffy = function (server, options) {

    Hoek.assert(options, 'Invalid options');
    Hoek.assert(options.fluffy, 'Missing required Fluffy configuration');
    Hoek.assert(options.fluffy.oz, 'Missing required Oz configuration');

    const settings = Hoek.applyToDefaults(internals.defaults, options);

    // Add protocol endpoints

    const endpoint = (e, o) => {

        const route = {
            auth: false,                            // Override any defaults
            handler: function (request, reply) {

                e(request.raw.req, request.payload, o, reply);
            }
        };

        return route;
    };

    // Oz routes

    server.route([
        { method: 'POST', path: settings.urls.app, config: endpoint(Oz.endpoints.app, options.fluffy.oz) },
        { method: 'POST', path: settings.urls.reissue, config: endpoint(Oz.endpoints.reissue, options.fluffy.oz) },
        { method: 'POST', path: settings.urls.rsvp, config: endpoint(Oz.endpoints.rsvp, options.fluffy.oz) },
        { method: 'POST', path: settings.urls.delegate, config: endpoint(Oz.endpoints.delegate, options.fluffy.oz) }
    ]);

    // Fluffy routes

    if (options.fluffy.authenticationServer) {

        server.route([
            { method: 'POST', path: settings.urls.fluffyFedereate, config: endpoint(Fluffy.endpoints.authenticationServer.federate, settings.fluffy) },
            { method: 'POST', path: settings.urls.fluffyFederateRsvp, config: endpoint(Fluffy.endpoints.authenticationServer.federateRsvp, settings.fluffy) }
        ]);

    }

    if (options.fluffy.service) {

        server.route([
            { method: 'POST', path: settings.urls.fluffyApp, config: endpoint(Fluffy.endpoints.service.app, settings.fluffy) },
            { method: 'POST', path: settings.urls.fluffyRsvp, config: endpoint(Fluffy.endpoints.service.rsvp, settings.fluffy) }
        ]);

    }

    const scheme = {
        api: { settings },
        authenticate: function (request, reply) {

            Oz.server.authenticate(request.raw.req, settings.fluffy.oz.encryptionPassword, { hawk: settings.fluffy.oz.hawk }, (err, credentials, artifacts) => {

                const result = { credentials: credentials, artifacts: artifacts };
                if (err) {
                    return reply(err, null, result);
                }

                return reply.continue(result);
            });
        }
    };

    return scheme;
};
Example #22
0
const register = (server, options) => {

    Joi.assert(options, internals.schema);

    const settings = Hoek.applyToDefaults(internals.defaults, options);

    const routeDefaults = {
        key: settings.key,
        restful: settings.restful,
        source: 'payload'
    };

    server.state(settings.key, settings.cookieOptions);

    server.ext('onPostAuth', (request, h) => {

        // If skip function enabled. Call it and if returns true, do not attempt to do anything with crumb.

        if (settings.skip && settings.skip(request, h)) {
            return h.continue;
        }

        // Validate incoming crumb

        if (typeof request.route.settings.plugins._crumb === 'undefined') {
            if (request.route.settings.plugins.crumb ||
                !request.route.settings.plugins.hasOwnProperty('crumb') && settings.autoGenerate) {

                request.route.settings.plugins._crumb = Hoek.applyToDefaults(routeDefaults, request.route.settings.plugins.crumb || {});
            }
            else {
                request.route.settings.plugins._crumb = false;
            }
        }

        // Set crumb cookie and calculate crumb

        if ((settings.autoGenerate ||
            request.route.settings.plugins._crumb) &&
            (request.route.settings.cors ? checkCORS(request) : true)) {

            generate(request, h);
        }

        // Validate crumb

        let routeIsRestful;
        if (request.route.settings.plugins._crumb && request.route.settings.plugins._crumb.restful !== undefined) {
            routeIsRestful = request.route.settings.plugins._crumb.restful;
        }
        if (routeIsRestful === false || !routeIsRestful && settings.restful === false) {

            if (request.method !== 'post' ||
                !request.route.settings.plugins._crumb) {

                return h.continue;
            }

            const content = request[request.route.settings.plugins._crumb.source];
            if (!content || content instanceof Stream) {

                throw Boom.forbidden();
            }

            if (content[request.route.settings.plugins._crumb.key] !== request.plugins.crumb) {
                throw Boom.forbidden();
            }

            // Remove crumb

            delete request[request.route.settings.plugins._crumb.source][request.route.settings.plugins._crumb.key];
        }
        else {
            if (request.method !== 'post' && request.method !== 'put' && request.method !== 'patch' && request.method !== 'delete' ||
                !request.route.settings.plugins._crumb) {

                return h.continue;
            }

            const header = request.headers['x-csrf-token'];

            if (!header) {
                throw Boom.forbidden();
            }

            if (header !== request.plugins.crumb) {
                throw Boom.forbidden();
            }

        }

        return h.continue;
    });

    server.ext('onPreResponse', (request, h) => {

        // Add to view context

        const response = request.response;

        if (settings.addToViewContext &&
            request.plugins.crumb &&
            request.route.settings.plugins._crumb &&
            !response.isBoom &&
            response.variety === 'view') {

            response.source.context = response.source.context || {};
            response.source.context[request.route.settings.plugins._crumb.key] = request.plugins.crumb;
        }

        return h.continue;
    });

    const checkCORS = function (request) {

        if (request.headers.origin) {
            return request.info.cors.isOriginMatch;
        }
        return true;
    };

    const generate = function (request, h) {

        let crumb = request.state[settings.key];
        if (!crumb) {
            crumb = Cryptiles.randomString(settings.size);
            h.state(settings.key, crumb, settings.cookieOptions);
        }

        request.plugins.crumb = crumb;
        return request.plugins.crumb;
    };

    server.expose({ generate });
};
Example #23
0
File: route.js Project: Marsup/hapi
exports = module.exports = internals.Route = function (options, connection, plugin) {

    // Apply plugin environment (before schema validation)

    var realm = plugin.realm;
    if (realm.modifiers.route.vhost ||
        realm.modifiers.route.prefix) {

        options = Hoek.cloneWithShallow(options, ['config']);       // config is left unchanged
        options.path = (realm.modifiers.route.prefix ? realm.modifiers.route.prefix + (options.path !== '/' ? options.path : '') : options.path);
        options.vhost = realm.modifiers.route.vhost || options.vhost;
    }

    // Setup and validate route configuration

    Hoek.assert(options.path, 'Route missing path');
    Hoek.assert(options.handler || (options.config && options.config.handler), 'Missing or undefined handler:', options.method, options.path);
    Hoek.assert(!!options.handler ^ !!(options.config && options.config.handler), 'Handler must only appear once:', options.method, options.path);            // XOR
    Hoek.assert(options.path === '/' || options.path[options.path.length - 1] !== '/' || !connection.settings.router.stripTrailingSlash, 'Path cannot end with a trailing slash when connection configured to strip:', options.method, options.path);
    Hoek.assert(/^[a-zA-Z0-9!#\$%&'\*\+\-\.^_`\|~]+$/.test(options.method), 'Invalid method name:', options.method, options.path);

    options = Schema.apply('route', options, options.path);

    var handler = options.handler || options.config.handler;
    var method = options.method.toLowerCase();
    Hoek.assert(method !== 'head', 'Method name not allowed:', options.method, options.path);

    // Apply settings in order: {connection} <- {handler} <- {realm} <- {route}

    var handlerDefaults = Handler.defaults(method, handler, connection.server);
    var base = Hoek.applyToDefaultsWithShallow(connection.settings.routes, handlerDefaults, ['bind']);
    base = Hoek.applyToDefaultsWithShallow(base, realm.settings, ['bind']);
    this.settings = Hoek.applyToDefaultsWithShallow(base, options.config || {}, ['bind']);
    this.settings.handler = handler;
    this.settings = Schema.apply('routeConfig', this.settings, options.path);

    var socketTimeout = (this.settings.timeout.socket === undefined ? 2 * 60 * 1000 : this.settings.timeout.socket);
    Hoek.assert(!this.settings.timeout.server || !socketTimeout || this.settings.timeout.server < socketTimeout, 'Server timeout must be shorter than socket timeout:', options.path);
    Hoek.assert(!this.settings.payload.timeout || !socketTimeout || this.settings.payload.timeout < socketTimeout, 'Payload timeout must be shorter than socket timeout:', options.path);

    this.connection = connection;
    this.server = connection.server;
    this.path = options.path;
    this.method = method;
    this.plugin = plugin;

    this.public = {
        method: this.method,
        path: this.path,
        vhost: this.vhost,
        realm: this.plugin.realm,
        settings: this.settings
    };

    this.settings.vhost = options.vhost;
    this.settings.plugins = this.settings.plugins || {};            // Route-specific plugins settings, namespaced using plugin name
    this.settings.app = this.settings.app || {};                    // Route-specific application settings

    // Path parsing

    this._analysis = this.connection._router.analyze(this.path);
    this.params = this._analysis.params;
    this.fingerprint = this._analysis.fingerprint;

    // Validation

    var validation = this.settings.validate;
    if (this.method === 'get') {

        // Assert on config, not on merged settings

        Hoek.assert(!options.config || !options.config.payload, 'Cannot set payload settings on HEAD or GET request:', options.path);
        Hoek.assert(!options.config || !options.config.validate || !options.config.validate.payload, 'Cannot validate HEAD or GET requests:', options.path);

        validation.payload = null;
    }

    ['headers', 'params', 'query', 'payload'].forEach(function (type) {

        validation[type] = internals.compileRule(validation[type]);
    });

    if (this.settings.response.schema !== undefined ||
        this.settings.response.status) {

        var rule = this.settings.response.schema;
        this.settings.response.status = this.settings.response.status || {};
        var statuses = Object.keys(this.settings.response.status);

        if (rule === true && !statuses.length) {

            this.settings.response = null;
        }
        else {
            this.settings.response.schema = internals.compileRule(rule);
            for (var i = 0, il = statuses.length; i < il; ++i) {
                var code = statuses[i];
                this.settings.response.status[code] = internals.compileRule(this.settings.response.status[code]);
            }
        }
    }
    else {
        this.settings.response = null;
    }

    // Payload parsing

    if (this.method === 'get') {

        this.settings.payload = null;
    }
    else {
        if (this.settings.payload.allow) {
            this.settings.payload.allow = [].concat(this.settings.payload.allow);
        }
    }

    Hoek.assert(!this.settings.validate.payload || this.settings.payload.parse, 'Route payload must be set to \'parse\' when payload validation enabled:', options.method, options.path);
    Hoek.assert(!this.settings.jsonp || typeof this.settings.jsonp === 'string', 'Bad route JSONP parameter name:', options.path);

    // Authentication configuration

    this.settings.auth = this.connection.auth._setupRoute(this.settings.auth, options.path);

    // Cache

    if (this.method === 'get' &&
        (this.settings.cache.expiresIn || this.settings.cache.expiresAt)) {

        this.settings.cache._statuses = Hoek.mapToObject(this.settings.cache.statuses);
        this._cache = new Catbox.Policy({ expiresIn: this.settings.cache.expiresIn, expiresAt: this.settings.cache.expiresAt });
    }

    // CORS

    if (this.settings.cors) {
        this.settings.cors = Hoek.applyToDefaults(Defaults.cors, this.settings.cors);

        var cors = this.settings.cors;
        cors._headers = cors.headers.concat(cors.additionalHeaders).join(',');
        cors._methods = cors.methods.concat(cors.additionalMethods).join(',');
        cors._exposedHeaders = cors.exposedHeaders.concat(cors.additionalExposedHeaders).join(',');

        if (cors.origin.length) {
            cors._origin = {
                any: false,
                qualified: [],
                qualifiedString: '',
                wildcards: []
            };

            if (cors.origin.indexOf('*') !== -1) {
                Hoek.assert(cors.origin.length === 1, 'Cannot specify cors.origin * together with other values');
                cors._origin.any = true;
            }
            else {
                for (var c = 0, cl = cors.origin.length; c < cl; ++c) {
                    var origin = cors.origin[c];
                    if (origin.indexOf('*') !== -1) {
                        cors._origin.wildcards.push(new RegExp('^' + Hoek.escapeRegex(origin).replace(/\\\*/g, '.*').replace(/\\\?/g, '.') + '$'));
                    }
                    else {
                        cors._origin.qualified.push(origin);
                    }
                }

                Hoek.assert(cors.matchOrigin || !cors._origin.wildcards.length, 'Cannot include wildcard origin values with matchOrigin disabled');
                cors._origin.qualifiedString = cors._origin.qualified.join(' ');
            }
        }
    }

    // Security

    if (this.settings.security) {
        this.settings.security = Hoek.applyToDefaults(Defaults.security, this.settings.security);

        var security = this.settings.security;
        if (security.hsts) {
            if (security.hsts === true) {
                security._hsts = 'max-age=15768000';
            }
            else if (typeof security.hsts === 'number') {
                security._hsts = 'max-age=' + security.hsts;
            }
            else {
                security._hsts = 'max-age=' + (security.hsts.maxAge || 15768000);
                if (security.hsts.includeSubdomains || security.hsts.includeSubDomains) {
                    security._hsts += '; includeSubDomains';
                }
                if (security.hsts.preload) {
                    security._hsts += '; preload';
                }
            }
        }

        if (security.xframe) {
            if (security.xframe === true) {
                security._xframe = 'DENY';
            }
            else if (typeof security.xframe === 'string') {
                security._xframe = security.xframe.toUpperCase();
            }
            else if (security.xframe.rule === 'allow-from') {
                if (!security.xframe.source) {
                    security._xframe = 'SAMEORIGIN';
                }
                else {
                    security._xframe = 'ALLOW-FROM ' + security.xframe.source;
                }
            }
            else {
                security._xframe = security.xframe.rule.toUpperCase();
            }
        }
    }

    // Handler

    this.settings.handler = Handler.configure(this.settings.handler, this);
    this._prerequisites = Handler.prerequisites(this.settings.pre, this.server);

    // Route lifecycle

    this._extensions = {
        onPreAuth: this._combineExtensions('onPreAuth'),
        onPostAuth: this._combineExtensions('onPostAuth'),
        onPreHandler: this._combineExtensions('onPreHandler'),
        onPostHandler: this._combineExtensions('onPostHandler'),
        onPreResponse: this._combineExtensions('onPreResponse')
    };

    this._cycle = null;
    this.rebuild();
};
Example #24
0
    server.ext('onPostAuth', (request, h) => {

        // If skip function enabled. Call it and if returns true, do not attempt to do anything with crumb.

        if (settings.skip && settings.skip(request, h)) {
            return h.continue;
        }

        // Validate incoming crumb

        if (typeof request.route.settings.plugins._crumb === 'undefined') {
            if (request.route.settings.plugins.crumb ||
                !request.route.settings.plugins.hasOwnProperty('crumb') && settings.autoGenerate) {

                request.route.settings.plugins._crumb = Hoek.applyToDefaults(routeDefaults, request.route.settings.plugins.crumb || {});
            }
            else {
                request.route.settings.plugins._crumb = false;
            }
        }

        // Set crumb cookie and calculate crumb

        if ((settings.autoGenerate ||
            request.route.settings.plugins._crumb) &&
            (request.route.settings.cors ? checkCORS(request) : true)) {

            generate(request, h);
        }

        // Validate crumb

        let routeIsRestful;
        if (request.route.settings.plugins._crumb && request.route.settings.plugins._crumb.restful !== undefined) {
            routeIsRestful = request.route.settings.plugins._crumb.restful;
        }
        if (routeIsRestful === false || !routeIsRestful && settings.restful === false) {

            if (request.method !== 'post' ||
                !request.route.settings.plugins._crumb) {

                return h.continue;
            }

            const content = request[request.route.settings.plugins._crumb.source];
            if (!content || content instanceof Stream) {

                throw Boom.forbidden();
            }

            if (content[request.route.settings.plugins._crumb.key] !== request.plugins.crumb) {
                throw Boom.forbidden();
            }

            // Remove crumb

            delete request[request.route.settings.plugins._crumb.source][request.route.settings.plugins._crumb.key];
        }
        else {
            if (request.method !== 'post' && request.method !== 'put' && request.method !== 'patch' && request.method !== 'delete' ||
                !request.route.settings.plugins._crumb) {

                return h.continue;
            }

            const header = request.headers['x-csrf-token'];

            if (!header) {
                throw Boom.forbidden();
            }

            if (header !== request.plugins.crumb) {
                throw Boom.forbidden();
            }

        }

        return h.continue;
    });
Example #25
0
exports = module.exports = internals.Server = function (/* host, port, options */) {        // all optional

    Hoek.assert(this.constructor === internals.Server, 'Server must be instantiated using new');

    var Pack = require('./pack');           // Delayed required to avoid circular dependencies

    // Register as event emitter

    Events.EventEmitter.call(this);

    // Validate arguments

    Hoek.assert(arguments.length <= 4, 'Too many arguments');          // 4th is for internal Pack usage

    var argMap = {
        string: 'host',
        number: 'port',
        object: 'options'
    };

    var args = {};
    for (var a = 0, al = arguments.length; a < al; ++a) {
        var argVal = arguments[a];
        if (argVal === undefined) {
            continue;
        }

        if (argVal instanceof Pack) {
            args.pack = arguments[a];
            continue;
        }

        var type = typeof argVal;

        if (type === 'string' && isFinite(+argVal)) {
            type = 'number';
            argVal = +argVal;
        }

        var key = argMap[type];
        Hoek.assert(key, 'Bad server constructor arguments: no match for arg type:', type);
        Hoek.assert(!args[key], 'Bad server constructor arguments: duplicated arg type:', type, '(values: `' + args[key] + '`, `' + argVal + '`)');
        args[key] = argVal;
    }

    this.settings = Hoek.applyToDefaultsWithShallow(Defaults.server, args.options || {}, ['app', 'plugins', 'views']);
    Schema.assert('server', this.settings);

    this.settings.labels = Hoek.unique([].concat(this.settings.labels));       // Convert string to array and removes duplicates

    // Set basic configuration

    this._unixDomainSocket = (args.host && args.host.indexOf('/') !== -1);
    this._windowsNamedPipe = (args.host && args.host.indexOf('\\\\.\\pipe\\') === 0);
    Hoek.assert(!this._unixDomainSocket || args.port === undefined, 'Cannot specify port with a UNIX domain socket');
    Hoek.assert(!this._windowsNamedPipe || args.port === undefined, 'Cannot specify port with a Windows named pipe');
    this._host = (args.host ? (this._unixDomainSocket ? Path.resolve(args.host) : (this._windowsNamedPipe ? args.host : args.host.toLowerCase())) : '');
    this._port = (args.port !== undefined ? args.port : (this.settings.tls ? 443 : 80));
    this._onConnection = null;          // Used to remove event listener on stop

    Hoek.assert(!this.settings.location || this.settings.location.charAt(this.settings.location.length - 1) !== '/', 'Location setting must not contain a trailing \'/\'');

    var socketTimeout = (this.settings.timeout.socket === undefined ? 2 * 60 * 1000 : this.settings.timeout.socket);
    Hoek.assert(!this.settings.timeout.server || !socketTimeout || this.settings.timeout.server < socketTimeout, 'Server timeout must be shorter than socket timeout');
    Hoek.assert(!this.settings.timeout.client || !socketTimeout || this.settings.timeout.client < socketTimeout, 'Client timeout must be shorter than socket timeout');

    // Server facilities

    this._started = false;
    this.auth = new Auth(this);                                                 // Required before _router
    this._router = new Router(this);
    this._etags = (this.settings.files.etagsCacheMaxSize ? LruCache({ max: this.settings.files.etagsCacheMaxSize }) : null);

    // Server load

    Hoek.assert(this.settings.load.sampleInterval || (!this.settings.load.maxEventLoopDelay && !this.settings.load.maxHeapUsedBytes && !this.settings.load.maxRssBytes), 'Load sample interval must be set in enable load limits');

    this._eventLoopTimer = null;
    this._loadBench = new Hoek.Bench();
    this.load = {
        eventLoopDelay: 0,
        heapUsed: 0,
        rss: 0
    };

    /*
        onRequest:      New request, before handing over to the router (allows changes to the request method, url, etc.)
        onPreAuth:      After cookie parse and before authentication (skipped if state error)
        onPostAuth:     After authentication (and payload processing) and before validation (skipped if auth or payload error)
        onPreHandler:   After validation and body parsing, before route handler (skipped if auth or validation error)
        onPostHandler:  After route handler returns, before sending response (skipped if onPreHandler not called)
        onPreResponse:  Before response is sent (always called)
    */

    this._ext = new Ext(['onRequest', 'onPreAuth', 'onPostAuth', 'onPreHandler', 'onPostHandler', 'onPreResponse']);

    this._stateDefinitions = {};
    this._registrations = {};

    if (args.pack) {
        this.pack = args.pack;
    }
    else {
        this.pack = new Pack({ cache: this.settings.cache, debug: this.settings.debug });
        this.pack._server(this);
    }

    this.plugins = {};                                      // Registered plugin APIs by plugin name
    this.app = {};                                          // Place for application-specific state without conflicts with hapi, should not be used by plugins
    this.methods = this.pack._methods.methods;              // Method functions

    // Generate CORS headers

    this.settings.cors = Hoek.applyToDefaults(Defaults.cors, this.settings.cors);
    if (this.settings.cors) {
        this.settings.cors._headers = this.settings.cors.headers.concat(this.settings.cors.additionalHeaders).join(', ');
        this.settings.cors._methods = this.settings.cors.methods.concat(this.settings.cors.additionalMethods).join(', ');
        this.settings.cors._exposedHeaders = this.settings.cors.exposedHeaders.concat(this.settings.cors.additionalExposedHeaders).join(', ');

        if (this.settings.cors.origin.length) {
            this.settings.cors._origin = {
                any: false,
                qualified: [],
                qualifiedString: '',
                wildcards: []
            };

            if (this.settings.cors.origin.indexOf('*') !== -1) {
                Hoek.assert(this.settings.cors.origin.length === 1, 'Cannot specify cors.origin * together with other values');
                this.settings.cors._origin.any = true;
            }
            else {
                for (var c = 0, cl = this.settings.cors.origin.length; c < cl; ++c) {
                    var origin = this.settings.cors.origin[c];
                    if (origin.indexOf('*') !== -1) {
                        this.settings.cors._origin.wildcards.push(new RegExp('^' + Hoek.escapeRegex(origin).replace(/\\\*/g, '.*').replace(/\\\?/g, '.') + '$'));
                    }
                    else {
                        this.settings.cors._origin.qualified.push(origin);
                    }
                }

                Hoek.assert(this.settings.cors.matchOrigin || !this.settings.cors._origin.wildcards.length, 'Cannot include wildcard origin values with matchOrigin disabled');
                this.settings.cors._origin.qualifiedString = this.settings.cors._origin.qualified.join(' ');
            }
        }
    }

    // Generate security headers

    this.settings.security = Hoek.applyToDefaults(Defaults.security, this.settings.security);
    if (this.settings.security) {
        if (this.settings.security.hsts) {
            if (this.settings.security.hsts === true) {
                this.settings.security._hsts = 'max-age=15768000';
            }
            else if (typeof this.settings.security.hsts === 'number') {
                this.settings.security._hsts = 'max-age=' + this.settings.security.hsts;
            }
            else {
                this.settings.security._hsts = 'max-age=' + (this.settings.security.hsts.maxAge || 15768000);
                if (this.settings.security.hsts.includeSubdomains) {
                    this.settings.security._hsts += '; includeSubdomains';
                }
            }
        }

        if (this.settings.security.xframe) {
            if (this.settings.security.xframe === true) {
                this.settings.security._xframe = 'DENY';
            }
            else if (typeof this.settings.security.xframe === 'string') {
                this.settings.security._xframe = this.settings.security.xframe.toUpperCase();
            }
            else {
                if (this.settings.security.xframe.rule === 'allow-from') {
                    if (!this.settings.security.xframe.source) {
                        this.settings.security._xframe = 'SAMEORIGIN';
                    }
                    else {
                        this.settings.security._xframe = 'ALLOW-FROM ' + this.settings.security.xframe.source;
                    }
                }
                else {
                    this.settings.security._xframe = this.settings.security.xframe.rule.toUpperCase();
                }
            }
        }
    }

    // Initialize Views

    this._views = (this.settings.views ? new Views.Manager(this.settings.views) : null);

    // Create server

    if (this.settings.tls) {
        this.listener = Https.createServer(this.settings.tls, this._dispatch());
    }
    else {
        this.listener = Http.createServer(this._dispatch());
    }

    this._agents = {};
    if (this.settings.maxSockets !== false) {
        this._agents.https = new Https.Agent();
        this._agents.https.maxSockets = this.settings.maxSockets;

        this._agents.insecureAgent = new Https.Agent({ rejectUnauthorized: false });
        this._agents.insecureAgent.maxSockets = this.settings.maxSockets;

        this._agents.http = new Http.Agent();
        this._agents.http.maxSockets = this.settings.maxSockets;
    }

    // Server information

    this.info = {
        host: this._host || '0.0.0.0'
    };

    if (this._unixDomainSocket ||
        this._windowsNamedPipe) {

        this.info.port = 0;
        this.info.protocol = (this._unixDomainSocket ? 'unix' : 'windows');
        this.info.uri = this.info.protocol + ':' + this._host;
    }
    else {
        this.info.port = this._port || 0;
        this.info.protocol = (this.settings.tls ? 'https' : 'http');

        if (this.info.port) {
            this.info.uri = this.info.protocol + '://' + (this._host || Os.hostname() || 'localhost') + ':' + this.info.port;
        }
    }
};
Example #26
0
exports.register = function (server, options, next) {

    options = Hoek.applyToDefaults({ basePath: '' }, options);


    server.route({
        method: 'POST',
        path: options.basePath + '/login',
        config: {
            validate: {
                payload: {
                    username: Joi.string().required(),
                    password: Joi.string().required()
                }
            },
            pre: [{
                assign: 'abuseDetected',
                method: function (request, reply) {

                    var AuthAttempt = request.server.plugins['hapi-mongo-models'].AuthAttempt;
                    var ip = request.info.remoteAddress;
                    var username = request.payload.username;

                    AuthAttempt.abuseDetected(ip, username, function (err, detected) {

                        if (err) {
                            return reply(err);
                        }

                        if (detected) {
                            return reply({
                                message: 'Maximum number of auth attempts reached. Please try again later.'
                            }).takeover().code(400);
                        }

                        reply();
                    });
                }
            },{
                assign: 'user',
                method: function (request, reply) {

                    var User = request.server.plugins['hapi-mongo-models'].User;
                    var username = request.payload.username;
                    var password = request.payload.password;

                    User.findByCredentials(username, password, function (err, user) {

                        if (err) {
                            return reply(err);
                        }

                        reply(user);
                    });
                }
            },{
                assign: 'logAttempt',
                method: function (request, reply) {

                    if (request.pre.user) {
                        return reply();
                    }

                    var AuthAttempt = request.server.plugins['hapi-mongo-models'].AuthAttempt;
                    var ip = request.info.remoteAddress;
                    var username = request.payload.username;

                    AuthAttempt.create(ip, username, function (err, authAttempt) {

                        if (err) {
                            return reply(err);
                        }

                        return reply({
                            message: 'Username and password combination not found or account is inactive.'
                        }).takeover().code(400);
                    });
                }
            },{
                assign: 'session',
                method: function (request, reply) {

                    var Session = request.server.plugins['hapi-mongo-models'].Session;

                    Session.create(request.pre.user.username, function (err, session) {

                        if (err) {
                            return reply(err);
                        }

                        return reply(session);
                    });
                }
            }]
        },
        handler: function (request, reply) {

            var credentials = request.pre.user.username + ':' + request.pre.session.key;
            var authHeader = 'Basic ' + new Buffer(credentials).toString('base64');

            reply({
                user: {
                    _id: request.pre.user._id,
                    username: request.pre.user.username,
                    email: request.pre.user.email,
                    roles: request.pre.user.roles
                },
                session: request.pre.session,
                authHeader: authHeader
            });
        }
    });


    server.route({
        method: 'POST',
        path: options.basePath + '/login/forgot',
        config: {
            validate: {
                payload: {
                    email: Joi.string().email().required()
                }
            },
            pre: [{
                assign: 'user',
                method: function (request, reply) {

                    var User = request.server.plugins['hapi-mongo-models'].User;
                    var conditions = {
                        email: request.payload.email.toLowerCase()
                    };

                    User.findOne(conditions, function (err, user) {

                        if (err) {
                            return reply(err);
                        }

                        if (!user) {
                            return reply({ message: 'Success.' }).takeover();
                        }

                        reply(user);
                    });
                }
            }]
        },
        handler: function (request, reply) {

            var Session = request.server.plugins['hapi-mongo-models'].Session;
            var User = request.server.plugins['hapi-mongo-models'].User;
            var mailer = request.server.plugins.mailer;

            Async.auto({
                keyHash: function (done) {

                    Session.generateKeyHash(done);
                },
                user: ['keyHash', function (done, results) {

                    var id = request.pre.user._id.toString();
                    var update = {
                        $set: {
                            resetPassword: {
                                token: results.keyHash.hash,
                                expires: Date.now() + 10000000
                            }
                        }
                    };

                    User.findByIdAndUpdate(id, update, done);
                }],
                email: ['user', function (done, results) {

                    var options = {
                        subject: 'Reset your ' + Config.get('/projectName')    + ' password',
                        to: request.payload.email
                    };
                    var template = 'forgot-password';
                    var context = {
                        key: results.keyHash.key
                    };

                    mailer.sendEmail(options, template, context, done);
                }]
            }, function (err, results) {

                if (err) {
                    return reply(err);
                }

                reply({ message: 'Success.' });
            });
        }
    });


    server.route({
        method: 'POST',
        path: options.basePath + '/login/reset',
        config: {
            validate: {
                payload: {
                    key: Joi.string().required(),
                    email: Joi.string().email().required(),
                    password: Joi.string().required()
                }
            },
            pre: [{
                assign: 'user',
                method: function (request, reply) {

                    var User = request.server.plugins['hapi-mongo-models'].User;
                    var conditions = {
                        email: request.payload.email.toLowerCase(),
                        'resetPassword.expires': { $gt: Date.now() }
                    };

                    User.findOne(conditions, function (err, user) {

                        if (err) {
                            return reply(err);
                        }

                        if (!user) {
                            return reply({ message: 'Invalid email or key.' }).takeover().code(400);
                        }

                        reply(user);
                    });
                }
            }]
        },
        handler: function (request, reply) {

            var User = request.server.plugins['hapi-mongo-models'].User;

            Async.auto({
                keyMatch: function (done) {

                    var key = request.payload.key;
                    var token = request.pre.user.resetPassword.token;
                    Bcrypt.compare(key, token, done);
                },
                passwordHash: ['keyMatch', function (done, results) {

                    if (!results.keyMatch) {
                        return reply({ message: 'Invalid email or key.' }).takeover().code(400);
                    }

                    User.generatePasswordHash(request.payload.password, done);
                }],
                user: ['passwordHash', function (done, results) {

                    var id = request.pre.user._id.toString();
                    var update = {
                        $set: {
                            password: results.passwordHash.hash
                        },
                        $unset: {
                            resetPassword: undefined
                        }
                    };

                    User.findByIdAndUpdate(id, update, done);
                }]
            }, function (err, results) {

                if (err) {
                    return reply(err);
                }

                reply({ message: 'Success.' });
            });
        }
    });


    next();
};