I have a server I built with Hapi.js. I created a plugin to restrict access to some local network IP addresses, like this:
exports.register = function (server, options, next) {
server.ext({
type: 'onRequest',
method: function (request, reply) {
console.log(request);
if (
request.info.remoteAddress.indexOf("192.") !== 0 &&
request.info.remoteAddress.indexOf("127.") !== 0
) {
return reply.view('error', {
error: "I DON'T LIKE YOU"
});
}
return reply.continue();
}
});
next();
};
exports.register.attributes = {
pkg: { "name": "localOnly" }
};
I want to apply this plugin to only "/pathA", while keeping "/pathB" and "/pathC" accessible to all users. Therefore I tried doing this:
const server = new Hapi.Server();
server.connection({ port: 8000 });
server.register(require('vision'), err => {
if (err) throw err;
server.views(/* removed for brevity */);
server.route({ method: 'GET', path: '/pathB', handler: handlerB });
server.route({ method: 'GET', path: '/pathC', handler: handlerC });
server.register(require('./plugins/localOnly.js'), err => {
if (err) throw err;
server.route({ method: 'GET', path: '/pathA', handler: handlerA });
server.start(/* removed for brevity */);
});
});
However, it seems that my plugin intercepts all connections. Can anyone please tell me what am I doing wrong? It's OK if you suggest me to make a plete refactor. I'm just planning the app at this stage and wanted to give Hapi.js a shot.
I have a server I built with Hapi.js. I created a plugin to restrict access to some local network IP addresses, like this:
exports.register = function (server, options, next) {
server.ext({
type: 'onRequest',
method: function (request, reply) {
console.log(request);
if (
request.info.remoteAddress.indexOf("192.") !== 0 &&
request.info.remoteAddress.indexOf("127.") !== 0
) {
return reply.view('error', {
error: "I DON'T LIKE YOU"
});
}
return reply.continue();
}
});
next();
};
exports.register.attributes = {
pkg: { "name": "localOnly" }
};
I want to apply this plugin to only "/pathA", while keeping "/pathB" and "/pathC" accessible to all users. Therefore I tried doing this:
const server = new Hapi.Server();
server.connection({ port: 8000 });
server.register(require('vision'), err => {
if (err) throw err;
server.views(/* removed for brevity */);
server.route({ method: 'GET', path: '/pathB', handler: handlerB });
server.route({ method: 'GET', path: '/pathC', handler: handlerC });
server.register(require('./plugins/localOnly.js'), err => {
if (err) throw err;
server.route({ method: 'GET', path: '/pathA', handler: handlerA });
server.start(/* removed for brevity */);
});
});
However, it seems that my plugin intercepts all connections. Can anyone please tell me what am I doing wrong? It's OK if you suggest me to make a plete refactor. I'm just planning the app at this stage and wanted to give Hapi.js a shot.
Share Improve this question asked May 24, 2016 at 21:17 nopotatonopotato 851 silver badge6 bronze badges2 Answers
Reset to default 13Does it need to be in a plugin? If not, you could use a route level extension point. For example:
Route-level extension
const restrict = function (request, reply) {
if (/^(192|127)/.test(request.info.remoteAddress)) {
return reply('Blocked');
}
return reply.continue();
};
server.route({
config: {
ext: {
onPreAuth: { method: restrict }
}
},
method: 'GET',
path: '/pathA',
handler: function (request, reply) {
reply('Hello!');
}
});
Another approach using a plugin:
Add route inside plugin using sandbox: plugin
const plugin = function (server, options, next) {
const restrict = function (request, reply) {
if (/^(192|127)/.test(request.info.remoteAddress)) {
return reply('Blocked');
}
return reply.continue();
};
// only applies to route in this plugin
server.ext('onPreAuth', restrict, { sandbox: 'plugin' });
server.route({
method: 'GET',
path: '/pathA',
handler: function (request, reply) {
reply('Hello!');
}
});
return next();
};
For newer versions of Hapi (currently v17) then you will need to pass route options as route.options.plugins['myPluginName']
e.g.
{
method: 'GET',
path: '/home',
options: {
plugins: {
myPluginName: true
}
}
}
This can be picked up in the plugin under ext
hooked into onPreAuth
or later. e.g.
register: async (server, options) => {
server.ext({
type: 'onPreAuth',
method: async (request, h) => {
// Exit early if the route is not configured for this route
if (!request.route.settings.plugins.myPluginName) { return h.continue }
// ... runs before the route handler ...
}
})
}
Note that the hook must be later than onRequest
in the Hapi lifecycle since the route has not been loaded at that point. If you want to access authentication stuff then you will have to use onPostAuth
.
This approach has the benefit of being loosely coupled between routes and plugin.