Socket
Socket
Sign inDemoInstall

hapi-auth-cookie

Package Overview
Dependencies
Maintainers
5
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

hapi-auth-cookie - npm Package Compare versions

Comparing version 7.0.0 to 8.0.0

test/helpers.js

82

example/index.js
'use strict';
const Hapi = require('hapi');
const internals = {};

@@ -15,15 +16,15 @@ let uuid = 1; // Use seq instead of proper unique identifiers for demo only

const home = function (request, reply) {
const home = (request, h) => {
reply('<html><head><title>Login page</title></head><body><h3>Welcome ' +
return '<html><head><title>Login page</title></head><body><h3>Welcome ' +
request.auth.credentials.name +
'!</h3><br/><form method="get" action="/logout">' +
'<input type="submit" value="Logout">' +
'</form></body></html>');
'</form></body></html>';
};
const login = function (request, reply) {
const login = async (request, h) => {
if (request.auth.isAuthenticated) {
return reply.redirect('/');
return h.redirect('/');
}

@@ -54,3 +55,3 @@

return reply('<html><head><title>Login page</title></head><body>' +
return '<html><head><title>Login page</title></head><body>' +
(message ? '<h3>' + message + '</h3><br/>' : '') +

@@ -60,31 +61,24 @@ '<form method="post" action="/login">' +

'Password: <input type="password" name="password"><br/>' +
'<input type="submit" value="Login"></form></body></html>');
'<input type="submit" value="Login"></form></body></html>';
}
const sid = String(++uuid);
request.server.app.cache.set(sid, { account: account }, 0, (err) => {
if (err) {
return reply(err);
}
await request.server.app.cache.set(sid, { account }, 0);
request.cookieAuth.set({ sid });
request.cookieAuth.set({ sid: sid });
return reply.redirect('/');
});
return h.redirect('/');
};
const logout = function (request, reply) {
const logout = (request, h) => {
request.cookieAuth.clear();
return reply.redirect('/');
return h.redirect('/');
};
const server = new Hapi.Server();
server.connection({ port: 8000 });
const server = Hapi.server({ port: 8000 });
server.register(require('../'), (err) => {
exports.start = async () => {
if (err) {
throw err;
}
await server.register(require('../'));

@@ -94,3 +88,3 @@ const cache = server.cache({ segment: 'sessions', expiresIn: 3 * 24 * 60 * 60 * 1000 });

server.auth.strategy('session', 'cookie', true, {
server.auth.strategy('session', 'cookie', {
password: 'password-should-be-32-characters',

@@ -100,19 +94,19 @@ cookie: 'sid-example',

isSecure: false,
validateFunc: function (request, session, callback) {
validateFunc: async (request, session) => {
cache.get(session.sid, (err, cached) => {
const cached = await cache.get(session.sid);
const out = {
valid: !!cached
};
if (err) {
return callback(err, false);
}
if (out.valid) {
out.credentials = cached.account;
}
if (!cached) {
return callback(null, false);
}
return callback(null, true, cached.account);
});
return out;
}
});
server.auth.default('session');
server.route([

@@ -124,6 +118,18 @@ { method: 'GET', path: '/', config: { handler: home } },

server.start(() => {
await server.start();
console.log('Server ready');
});
});
console.log(`Server started at: ${server.info.uri}`);
};
internals.start = async function () {
try {
await exports.start();
}
catch (err) {
console.error(err.stack);
process.exit(1);
}
};
internals.start();

@@ -8,2 +8,3 @@ 'use strict';

const Joi = require('joi');
const Bounce = require('bounce');

@@ -14,14 +15,10 @@ // Declare internals

module.exports = {
pkg: require('../package.json'),
register: (server, options) => {
exports.register = function (server, options, next) {
server.auth.scheme('cookie', internals.implementation);
next();
server.auth.scheme('cookie', internals.implementation);
}
};
exports.register.attributes = {
pkg: require('../package.json')
};
internals.schema = Joi.object({

@@ -46,4 +43,56 @@ cookie: Joi.string().default('sid'),

internals.implementation = function (server, options) {
internals.CookieAuth = class {
constructor(request, settings) {
this.request = request;
this.settings = settings;
}
set(session, value) {
const { h, request, settings } = this;
if (arguments.length > 1) {
const key = session;
Hoek.assert(key && typeof key === 'string', 'Invalid session key');
session = request.auth.artifacts;
Hoek.assert(session, 'No active session to apply key to');
session[key] = value;
return h.state(settings.cookie, session);
}
Hoek.assert(session && typeof session === 'object', 'Invalid session');
request.auth.artifacts = session;
h.state(settings.cookie, session);
}
clear(key) {
const { h, request, settings } = this;
if (arguments.length) {
Hoek.assert(key && typeof key === 'string', 'Invalid session key');
const session = request.auth.artifacts;
Hoek.assert(session, 'No active session to clear key from');
delete session[key];
return h.state(settings.cookie, session);
}
request.auth.artifacts = null;
h.unstate(settings.cookie);
}
ttl(msecs) {
const { h, request, settings } = this;
const session = request.auth.artifacts;
Hoek.assert(session, 'No active session to modify ttl on');
h.state(settings.cookie, session, { ttl: msecs });
}
};
internals.implementation = (server, options) => {
const results = Joi.validate(options, internals.schema);

@@ -79,58 +128,9 @@ Hoek.assert(!results.error, results.error);

const decoration = function (request) {
const decoration = (request) => {
const CookieAuth = function () {
const self = this;
this.set = function (session, value) {
const reply = self.reply;
if (arguments.length > 1) {
const key = session;
Hoek.assert(key && typeof key === 'string', 'Invalid session key');
session = request.auth.artifacts;
Hoek.assert(session, 'No active session to apply key to');
session[key] = value;
return reply.state(settings.cookie, session);
}
Hoek.assert(session && typeof session === 'object', 'Invalid session');
request.auth.artifacts = session;
reply.state(settings.cookie, session);
};
this.clear = function (key) {
const reply = self.reply;
if (arguments.length) {
Hoek.assert(key && typeof key === 'string', 'Invalid session key');
const session = request.auth.artifacts;
Hoek.assert(session, 'No active session to clear key from');
delete session[key];
return reply.state(settings.cookie, session);
}
request.auth.artifacts = null;
reply.unstate(settings.cookie);
};
this.ttl = function (msecs) {
const reply = self.reply;
const session = request.auth.artifacts;
Hoek.assert(session, 'No active session to modify ttl on');
reply.state(settings.cookie, session, { ttl: msecs });
};
};
return new CookieAuth();
return new internals.CookieAuth(request, settings);
};
// Check if the request object should be decorated
const decorations = server.root._requestor._decorations || {};
const isDecorated = decorations[settings.requestDecoratorName];
const isDecorated = server.decorations.request.indexOf(settings.requestDecoratorName) >= 0;

@@ -141,14 +141,14 @@ if (!settings.ignoreIfDecorated || !isDecorated) {

server.ext('onPreAuth', (request, reply) => {
server.ext('onPreAuth', (request, h) => {
// Used for setting and unsetting state, not for replying to request
request[settings.requestDecoratorName].reply = reply;
request[settings.requestDecoratorName].h = h;
return reply.continue();
return h.continue;
});
const scheme = {
authenticate: function (request, reply) {
authenticate: async (request, h) => {
const validate = function () {
const validate = async () => {

@@ -164,29 +164,41 @@ // Check cookie

if (settings.keepAlive) {
reply.state(settings.cookie, session);
h.state(settings.cookie, session);
}
return reply.continue({ credentials: session, artifacts: session });
return h.authenticated({ credentials: session, artifacts: session });
}
settings.validateFunc(request, session, (err, isValid, credentials) => {
let credentials = session;
if (err ||
!isValid) {
try {
const result = await settings.validateFunc(request, session);
if (settings.clearInvalid) {
reply.unstate(settings.cookie);
}
Hoek.assert(typeof result === 'object', 'Invalid return from validateFunc');
Hoek.assert(Object.prototype.hasOwnProperty.call(result, 'valid'), 'validateFunc must have valid property in return');
return unauthenticated(Boom.unauthorized('Invalid cookie'), { credentials: credentials || session, artifacts: session });
if (!result.valid) {
throw Boom.unauthorized(null, 'cookie');
}
credentials = result.credentials || credentials;
if (settings.keepAlive) {
reply.state(settings.cookie, session);
h.state(settings.cookie, session);
}
return reply.continue({ credentials: credentials || session, artifacts: session });
});
return h.authenticated({ credentials, artifacts: session });
}
catch (err) {
Bounce.rethrow(err, 'system');
if (settings.clearInvalid) {
h.unstate(settings.cookie);
}
return unauthenticated(Boom.unauthorized('Invalid cookie'), { credentials, artifacts: session });
}
};
const unauthenticated = function (err, result) {
const unauthenticated = (err, result) => {

@@ -196,3 +208,3 @@ if (settings.redirectOnTry === false && // Defaults to true

return reply(err, null, result);
return h.unauthenticated(err);
}

@@ -208,3 +220,3 @@

if (!redirectTo) {
return reply(err, null, result);
return h.unauthenticated(err);
}

@@ -224,6 +236,6 @@

return reply('You are being redirected...', null, result).redirect(uri);
return h.response('You are being redirected...').takeover().redirect(uri);
};
validate();
return await validate();
}

@@ -230,0 +242,0 @@ };

{
"name": "hapi-auth-cookie",
"description": "Cookie authentication plugin",
"version": "7.0.0",
"version": "8.0.0",
"repository": "git://github.com/hapijs/hapi-auth-cookie",

@@ -15,16 +15,17 @@ "main": "lib/index.js",

"engines": {
"node": ">=4.x.x"
"node": ">=8.9.x"
},
"dependencies": {
"boom": "3.x.x",
"hoek": "4.x.x",
"joi": "8.x.x"
"boom": "7.x.x",
"bounce": "1.x.x",
"hoek": "5.x.x",
"joi": "13.x.x"
},
"peerDependencies": {
"hapi": ">=11.x.x"
"hapi": ">=17.x.x"
},
"devDependencies": {
"code": "2.x.x",
"hapi": "15.x.x",
"lab": "10.x.x"
"code": "5.x.x",
"hapi": "17.x.x",
"lab": "15.x.x"
},

@@ -31,0 +32,0 @@ "scripts": {

@@ -7,3 +7,3 @@ ### hapi-auth-cookie

Lead Maintainer: [James Weston](https://github.com/jaw187)
Lead Maintainer: [Julian Lannigan](https://github.com/mrlannigan)

@@ -46,16 +46,15 @@ Cookie authentication provides simple cookie-based session management. The user has to be

- `redirectOnTry` - if `false` and route authentication mode is `'try'`, authentication errors will
not trigger a redirection. Requires **hapi** version 6.2.0 or newer. Defaults to `true`;
- `validateFunc` - an optional session validation function used to validate the content of the
not trigger a redirection. Defaults to `true`;
- `async validateFunc` - an optional session validation function used to validate the content of the
session cookie on each request. Used to verify that the internal session state is still valid
(e.g. user account still exists). The function has the signature `function(request, session, callback)`
(e.g. user account still exists). The function has the signature `function(request, session)`
where:
- `request` - is the Hapi request object of the request which is being authenticated.
- `session` - is the session object set via `request.cookieAuth.set()`.
- `callback` - a callback function with the signature `function(err, isValid, credentials)`
where:
- `err` - an internal error.
- `isValid` - `true` if the content of the session is valid, otherwise `false`.
- `credentials` - a credentials object passed back to the application in
`request.auth.credentials`. If value is `null` or `undefined`, defaults to `session`. If
set, will override the current cookie as if `request.cookieAuth.set()` was called.
Must return an object that contains:
- `valid` - `true` if the content of the session is valid, otherwise `false`.
- `credentials` - a credentials object passed back to the application in
`request.auth.credentials`. If value is `null` or `undefined`, defaults to `session`. If
set, will override the current cookie as if `request.cookieAuth.set()` was called.
- `requestDecoratorName` - *USE WITH CAUTION* an optional name to use with decorating the `request` object. Defaults to `'cookieAuth'`. Using multiple decorator names for separate authentication strategies could allow a developer to call the methods for the wrong strategy. Potentially resulting in unintended authorized access.

@@ -86,2 +85,3 @@

const Hapi = require('hapi');
const internals = {};

@@ -98,15 +98,15 @@ let uuid = 1; // Use seq instead of proper unique identifiers for demo only

const home = function (request, reply) {
const home = (request, h) => {
reply('<html><head><title>Login page</title></head><body><h3>Welcome ' +
return '<html><head><title>Login page</title></head><body><h3>Welcome ' +
request.auth.credentials.name +
'!</h3><br/><form method="get" action="/logout">' +
'<input type="submit" value="Logout">' +
'</form></body></html>');
'</form></body></html>';
};
const login = function (request, reply) {
const login = async (request, h) => {
if (request.auth.isAuthenticated) {
return reply.redirect('/');
return h.redirect('/');
}

@@ -137,3 +137,3 @@

return reply('<html><head><title>Login page</title></head><body>' +
return '<html><head><title>Login page</title></head><body>' +
(message ? '<h3>' + message + '</h3><br/>' : '') +

@@ -143,31 +143,24 @@ '<form method="post" action="/login">' +

'Password: <input type="password" name="password"><br/>' +
'<input type="submit" value="Login"></form></body></html>');
'<input type="submit" value="Login"></form></body></html>';
}
const sid = String(++uuid);
request.server.app.cache.set(sid, { account: account }, 0, (err) => {
if (err) {
reply(err);
}
await request.server.app.cache.set(sid, { account }, 0);
request.cookieAuth.set({ sid });
request.cookieAuth.set({ sid: sid });
return reply.redirect('/');
});
return h.redirect('/');
};
const logout = function (request, reply) {
const logout = (request, h) => {
request.cookieAuth.clear();
return reply.redirect('/');
return h.redirect('/');
};
const server = new Hapi.Server();
server.connection({ port: 8000 });
const server = Hapi.server({ port: 8000 });
server.register(require('../'), (err) => {
exports.start = async () => {
if (err) {
throw err;
}
await server.register(require('../'));

@@ -177,3 +170,3 @@ const cache = server.cache({ segment: 'sessions', expiresIn: 3 * 24 * 60 * 60 * 1000 });

server.auth.strategy('session', 'cookie', true, {
server.auth.strategy('session', 'cookie', {
password: 'password-should-be-32-characters',

@@ -183,19 +176,19 @@ cookie: 'sid-example',

isSecure: false,
validateFunc: function (request, session, callback) {
validateFunc: async (request, session) => {
cache.get(session.sid, (err, cached) => {
const cached = await cache.get(session.sid);
const out = {
valid: !!cached
};
if (err) {
return callback(err, false);
}
if (out.valid) {
out.credentials = cached.account;
}
if (!cached) {
return callback(null, false);
}
return callback(null, true, cached.account);
});
return out;
}
});
server.auth.default('session');
server.route([

@@ -207,7 +200,19 @@ { method: 'GET', path: '/', config: { handler: home } },

server.start(() => {
await server.start();
console.log('Server ready');
});
});
console.log(`Server started at: ${server.info.uri}`);
};
internals.start = async function () {
try {
await exports.start();
}
catch (err) {
console.error(err.stack);
process.exit(1);
}
};
internals.start();
```

@@ -5,3 +5,2 @@ 'use strict';

const Code = require('code');
const Hapi = require('hapi');

@@ -20,446 +19,617 @@ const Hoek = require('hoek');

const lab = exports.lab = Lab.script();
const describe = lab.describe;
const it = lab.it;
const expect = Code.expect;
const { describe, it, expect } = lab;
// Helpers
const Helpers = require('./helpers');
describe('scheme', () => {
it('fails with no plugin options', (done) => {
it('fails with no plugin options', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
expect(() => {
expect(() => {
server.auth.strategy('session', 'cookie', {});
}).to.throw(Error);
});
server.auth.strategy('default', 'cookie', true, {});
}).to.throw(Error);
it('passes with a password configured', async () => {
done();
});
const server = Hapi.server();
await server.register(require('../'));
expect(() => {
server.auth.strategy('session', 'cookie', { password: 'password-should-be-32-characters' });
server.auth.default('session');
}).to.not.throw();
});
it('passes with a password configured', (done) => {
it('passes with a password configured which is a Buffer', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
expect(() => {
expect(() => {
server.auth.strategy('session', 'cookie', { password: Buffer.from('foobar') });
}).to.not.throw();
});
server.auth.strategy('default', 'cookie', true, { password: 'password-should-be-32-characters' });
}).to.not.throw();
it('fails if validateFunc is not a function', async () => {
done();
});
const server = Hapi.server();
await server.register(require('../'));
expect(() => {
server.auth.strategy('session', 'cookie', { validateFunc: 'not a function' });
}).to.throw(Error);
});
it('passes with a password configured which is a Buffer', (done) => {
it('fails if keepAlive is configured but not ttl', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
expect(() => {
expect(() => {
server.auth.strategy('session', 'cookie', {
password: 'password-should-be-32-characters',
keepAlive: true
});
}).to.throw(Error);
});
server.auth.strategy('default', 'cookie', true, { password: new Buffer('foobar') });
}).to.not.throw();
it('authenticates a request', async () => {
done();
const server = Hapi.server();
await server.register(require('../'));
server.auth.strategy('session', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
clearInvalid: true,
validateFunc: function (request, session) {
const override = Hoek.clone(session);
override.something = 'new';
return {
valid: session.user === 'valid',
credentials: override
};
}
});
server.auth.default('session');
Helpers.loginWithResourceEndpoint(server);
const res = await server.inject('/login/valid');
expect(res.result).to.equal('valid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
const res2 = await server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } });
expect(res2.statusCode).to.equal(200);
expect(res2.headers['set-cookie']).to.not.exist();
expect(res2.result).to.equal('resource');
});
it('fails if validateFunc is not a function', (done) => {
it('fails over to another strategy if not present', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const extraSchemePlugin = {
register: function (server, options) {
expect(err).to.not.exist();
const simpleTestSchema = function () {
expect(() => {
return {
authenticate: function (request, h) {
server.auth.strategy('default', 'cookie', true, { validateFunc: 'not a function' });
}).to.throw(Error);
return h.authenticated({ credentials: { test: 'valid' } });
}
};
};
done();
server.auth.scheme('simpleTest', simpleTestSchema);
},
name: 'simpleTestAuth'
};
const server = Hapi.server();
await server.register(require('../'));
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
clearInvalid: true,
validateFunc: function (request, session) {
const override = Hoek.clone(session);
override.something = 'new';
return {
valid: session.user === 'valid',
credentials: override
};
}
});
});
server.auth.default('default');
it('fails if keepAlive is configured but not ttl', (done) => {
server.register(extraSchemePlugin);
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
server.auth.strategy('simple', 'simpleTest');
expect(err).to.not.exist();
server.route({
method: 'GET',
path: '/multiple',
config: {
auth: {
mode: 'try',
strategies: ['default', 'simple']
},
handler: function (request, h) {
expect(() => {
const credentialsTest = (request.auth.credentials && request.auth.credentials.test) || 'NOT AUTH';
return h.response('multiple ' + credentialsTest);
}
}
});
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
keepAlive: true
});
}).to.throw(Error);
const res = await server.inject('/multiple');
done();
});
expect(res.statusCode).to.equal(200);
expect(res.result).to.equal('multiple valid');
});
it('authenticates a request', (done) => {
it('ends a session', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
clearInvalid: true,
validateFunc: function (request, session) {
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
clearInvalid: true,
validateFunc: function (request, session, callback) {
const override = Hoek.clone(session);
override.something = 'new';
const override = Hoek.clone(session);
override.something = 'new';
return {
valid: session.user === 'valid',
credentials: override
};
}
});
server.auth.default('default');
return callback(null, session.user === 'valid', override);
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, h) {
request.cookieAuth.set({ user: request.params.user });
return h.response(request.params.user);
}
});
}
});
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
server.route({
method: 'GET', path: '/logout', handler: function (request, h) {
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
}
}
});
request.cookieAuth.clear();
return h.response('logged-out');
}
});
server.route({
method: 'GET', path: '/resource', handler: function (request, reply) {
const res = await server.inject('/login/valid');
expect(request.auth.credentials.something).to.equal('new');
return reply('resource');
}
});
expect(res.result).to.equal('valid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
server.inject('/login/valid', (res) => {
const res2 = await server.inject({ method: 'GET', url: '/logout', headers: { cookie: 'special=' + cookie[1] } });
expect(res.result).to.equal('valid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
expect(res2.statusCode).to.equal(200);
expect(res2.result).to.equal('logged-out');
expect(res2.headers['set-cookie'][0]).to.equal('special=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; HttpOnly; SameSite=Strict; Domain=example.com; Path=/');
});
/* eslint-disable hapi/no-shadow-relaxed */
server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } }, (res2) => {
it('fails a request with invalid session', async () => {
expect(res2.statusCode).to.equal(200);
expect(res2.headers['set-cookie']).to.not.exist();
expect(res2.result).to.equal('resource');
done();
});
/* eslint-enable hapi/no-shadow-relaxed */
});
const server = Hapi.server();
await server.register(require('../'));
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
clearInvalid: true,
validateFunc: function (request, session) {
const override = Hoek.clone(session);
override.something = 'new';
return {
valid: session.user === 'valid',
credentials: override
};
}
});
server.auth.default('default');
Helpers.loginWithResourceEndpoint(server);
const res = await server.inject('/login/invalid');
expect(res.result).to.equal('invalid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
const res2 = await server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } });
expect(res2.headers['set-cookie'][0]).to.equal('special=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; HttpOnly; SameSite=Strict; Domain=example.com; Path=/');
expect(res2.statusCode).to.equal(401);
});
it('fails over to another strategy if not present', (done) => {
it('does not clear a request with invalid session (clearInvalid not set)', async () => {
const extraSchemePlugin = function (plugin, options, next) {
const server = Hapi.server();
await server.register(require('../'));
const simpleTestSchema = function () {
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
clearInvalid: false,
validateFunc: function (request, session) {
const override = Hoek.clone(session);
override.something = 'new';
return {
authenticate: function (request, reply) {
return reply.continue({ credentials: { test: 'valid' } });
}
valid: session.user === 'valid',
credentials: override
};
};
}
});
server.auth.default('default');
plugin.auth.scheme('simpleTest', simpleTestSchema);
return next();
};
Helpers.loginWithResourceEndpoint(server);
extraSchemePlugin.attributes = {
name: 'simpleTestAuth'
};
const res = await server.inject('/login/invalid');
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
expect(res.result).to.equal('invalid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
expect(err).to.not.exist();
const res2 = await server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } });
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
clearInvalid: true,
validateFunc: function (request, session, callback) {
expect(res2.headers['set-cookie']).to.not.exist();
expect(res2.statusCode).to.equal(401);
});
const override = Hoek.clone(session);
override.something = 'new';
it('logs in and authenticates a request', async () => {
return callback(null, session.user === 'valid', override);
}
});
const server = Hapi.server();
await server.register(require('../'));
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true
});
server.auth.default('default');
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
}
}
});
Helpers.loginWithResourceEndpoint(server);
server.register(extraSchemePlugin, (err) => {
const res = await server.inject('/login/steve');
expect(err).to.not.exist();
expect(res.result).to.equal('steve');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
server.auth.strategy('simple', 'simpleTest');
const res2 = await server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } });
server.route({
method: 'GET',
path: '/multiple',
config: {
auth: {
mode: 'try',
strategies: ['default', 'simple']
},
handler: function (request, reply) {
expect(res2.statusCode).to.equal(200);
expect(res2.result).to.equal('resource');
});
const credentialsTest = (request.auth.credentials && request.auth.credentials.test) || 'NOT AUTH';
return reply('multiple ' + credentialsTest);
}
}
});
it('errors in validation function', async () => {
server.inject('/multiple', (res) => {
const server = Hapi.server();
await server.register(require('../'));
expect(res.statusCode).to.equal(200);
expect(res.result).to.equal('multiple valid');
done();
});
});
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true,
validateFunc: function (request, session) {
throw new Error('boom');
}
});
server.auth.default('default');
Helpers.loginWithResourceEndpoint(server);
const res = await server.inject('/login/steve');
expect(res.result).to.equal('steve');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
const res2 = await server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } });
expect(res2.statusCode).to.equal(401);
});
it('ends a session', (done) => {
it('authenticates a request (no ttl)', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
domain: 'example.com',
cookie: 'special',
clearInvalid: true,
validateFunc: function (request, session) {
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
clearInvalid: true,
validateFunc: function (request, session, callback) {
const override = Hoek.clone(session);
override.something = 'new';
const override = Hoek.clone(session);
override.something = 'new';
return {
valid: session.user === 'valid',
credentials: override
};
}
});
server.auth.default('default');
return callback(null, session.user === 'valid', override);
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, h) {
request.cookieAuth.set({ user: request.params.user });
return h.response(request.params.user);
}
});
}
});
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
const res = await server.inject('/login/valid');
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
}
}
});
expect(res.result).to.equal('valid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.not.contain('Max-Age');
});
server.route({
method: 'GET', path: '/logout', handler: function (request, reply) {
it('authenticates a request (no session override)', async () => {
request.cookieAuth.clear();
return reply('logged-out');
}
});
const server = Hapi.server();
await server.register(require('../'));
server.inject('/login/valid', (res) => {
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
path: '/example-path',
clearInvalid: true,
validateFunc: function (request, session) {
expect(res.result).to.equal('valid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
return {
valid: session.user === 'valid'
};
}
});
server.auth.default('default');
/* eslint-disable hapi/no-shadow-relaxed */
server.inject({ method: 'GET', url: '/logout', headers: { cookie: 'special=' + cookie[1] } }, (res2) => {
Helpers.loginWithResourceEndpoint(server);
expect(res2.statusCode).to.equal(200);
expect(res2.result).to.equal('logged-out');
expect(res2.headers['set-cookie'][0]).to.equal('special=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; HttpOnly; SameSite=Strict; Domain=example.com; Path=/');
done();
});
/* eslint-enable hapi/no-shadow-relaxed */
});
});
const res = await server.inject('/login/valid');
expect(res.result).to.equal('valid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
const res2 = await server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } });
expect(res2.statusCode).to.equal(200);
expect(res2.result).to.equal('resource');
});
it('fails a request with invalid session', (done) => {
it('authenticates a request (no session override) on a sub-path', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
path: '/subpath',
clearInvalid: true,
validateFunc: function (request, session) {
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
clearInvalid: true,
validateFunc: function (request, session, callback) {
return {
valid: session.user === 'valid'
};
}
});
server.auth.default('default');
const override = Hoek.clone(session);
override.something = 'new';
server.route({
method: 'GET', path: '/subpath/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, h) {
return callback(null, session.user === 'valid', override);
request.cookieAuth.set({ user: request.params.user });
return h.response(request.params.user);
}
});
}
});
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
server.route({
method: 'GET', path: '/subpath/resource', handler: function (request, h) {
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
}
}
});
return h.response('resource');
}
});
server.route({
method: 'GET', path: '/resource', handler: function (request, reply) {
const res = await server.inject('/subpath/login/valid');
expect(request.auth.credentials.something).to.equal('new');
return reply('resource');
}
});
expect(res.result).to.equal('valid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
expect(header[0]).to.contain('Path=/subpath');
server.inject('/login/invalid', (res) => {
const res2 = await server.inject({ method: 'GET', url: '/subpath/resource', headers: { cookie: 'special=' + cookie[1] } });
expect(res.result).to.equal('invalid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
expect(res2.statusCode).to.equal(200);
expect(res2.result).to.equal('resource');
});
/* eslint-disable hapi/no-shadow-relaxed */
server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } }, (res2) => {
it('extends ttl automatically', async () => {
expect(res2.headers['set-cookie'][0]).to.equal('special=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; HttpOnly; SameSite=Strict; Domain=example.com; Path=/');
expect(res2.statusCode).to.equal(401);
done();
});
/* eslint-enable hapi/no-shadow-relaxed */
});
const server = Hapi.server();
await server.register(require('../'));
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
clearInvalid: true,
keepAlive: true
});
server.auth.default('default');
Helpers.loginWithResourceEndpoint(server);
const res = await server.inject('/login/valid');
let header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
const res2 = await server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } });
expect(res2.statusCode).to.equal(200);
header = res2.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
});
it('does not clear a request with invalid session (clearInvalid not set)', (done) => {
it('extends ttl automatically (validateFunc)', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
clearInvalid: true,
keepAlive: true,
validateFunc: function (request, session) {
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
validateFunc: function (request, session, callback) {
const override = Hoek.clone(session);
override.something = 'new';
const override = Hoek.clone(session);
override.something = 'new';
return {
valid: session.user === 'valid',
credentials: override
};
}
});
server.auth.default('default');
return callback(null, session.user === 'valid', override);
}
});
Helpers.loginWithResourceEndpoint(server);
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
const res = await server.inject('/login/valid');
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
}
}
});
expect(res.result).to.equal('valid');
let header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
server.route({
method: 'GET', path: '/resource', handler: function (request, reply) {
const res2 = await server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } });
expect(request.auth.credentials.something).to.equal('new');
return reply('resource');
}
});
expect(res2.statusCode).to.equal(200);
expect(res2.result).to.equal('resource');
server.inject('/login/invalid', (res) => {
header = res2.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
});
expect(res.result).to.equal('invalid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
it('errors if ignoreIfDecorated is false and the request object is already decorated', async () => {
/* eslint-disable hapi/no-shadow-relaxed */
server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } }, (res2) => {
const password = 'password-should-be-32-characters';
const ignoreIfDecorated = false;
const options = { password, ignoreIfDecorated };
expect(res2.headers['set-cookie']).to.not.exist();
expect(res2.statusCode).to.equal(401);
done();
});
/* eslint-enable hapi/no-shadow-relaxed */
});
});
const server = Hapi.server();
await server.register(require('../'));
server.auth.strategy('default', 'cookie', options);
expect(() => {
server.auth.strategy('default', 'cookie', options);
}).to.throw(Error);
});
it('logs in and authenticates a request', (done) => {
describe('set()', () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
it('errors on missing session in set()', async () => {
expect(err).to.not.exist();
const server = Hapi.server();
await server.register(require('../'));
server.auth.strategy('default', 'cookie', true, {
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',

@@ -470,2 +640,3 @@ ttl: 60 * 1000,

});
server.auth.default('default');

@@ -476,6 +647,12 @@ server.route({

auth: { mode: 'try' },
handler: function (request, reply) {
handler: function (request, h) {
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
try {
request.cookieAuth.set();
}
catch (error) {
return h.response(error.message);
}
return h.response('ok');
}

@@ -485,48 +662,19 @@ }

server.route({
method: 'GET', path: '/resource', handler: function (request, reply) {
const res = await server.inject('/login/steve');
expect(request.auth.credentials.user).to.equal('steve');
return reply('resource');
}
});
server.inject('/login/steve', (res) => {
expect(res.result).to.equal('steve');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
/* eslint-disable hapi/no-shadow-relaxed */
server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } }, (res2) => {
expect(res2.statusCode).to.equal(200);
expect(res2.result).to.equal('resource');
done();
});
/* eslint-enable hapi/no-shadow-relaxed */
});
expect(res.result).to.equal('Invalid session');
});
});
it('errors in validation function', (done) => {
it('sets individual cookie key', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true,
validateFunc: function (request, session, callback) {
return callback(new Error('boom'));
}
clearInvalid: true
});
server.auth.default('default');

@@ -537,6 +685,6 @@ server.route({

auth: { mode: 'try' },
handler: function (request, reply) {
handler: function (request, h) {
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
return h.response(request.params.user);
}

@@ -547,49 +695,35 @@ }

server.route({
method: 'GET', path: '/resource', handler: function (request, reply) {
method: 'GET', path: '/setKey', handler: function (request, h) {
expect(request.auth.credentials.user).to.equal('steve');
return reply('resource');
request.cookieAuth.set('key', 'value');
return null;
}
});
/* eslint-disable hapi/no-shadow-relaxed */
server.inject('/login/steve', (res) => {
const res = await server.inject('/login/steve');
expect(res.result).to.equal('steve');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
const pattern = /(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/;
expect(res.result).to.equal('steve');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(pattern);
server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } }, (res2) => {
const res2 = await server.inject({ method: 'GET', url: '/setKey', headers: { cookie: 'special=' + cookie[1] } });
expect(res2.statusCode).to.equal(401);
done();
});
});
/* eslint-enable hapi/no-shadow-relaxed */
expect(res2.statusCode).to.equal(200);
});
});
it('authenticates a request (no ttl)', (done) => {
it('throws on missing session when trying to set key', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
domain: 'example.com',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true,
validateFunc: function (request, session, callback) {
const override = Hoek.clone(session);
override.something = 'new';
return callback(null, session.user === 'valid', override);
}
clearInvalid: true
});
server.auth.default('default');

@@ -600,6 +734,12 @@ server.route({

auth: { mode: 'try' },
handler: function (request, reply) {
handler: function (request, h) {
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
try {
request.cookieAuth.set('key', 'value');
}
catch (error) {
return h.response(error.message);
}
return h.response('ok');
}

@@ -609,33 +749,19 @@ }

server.inject('/login/valid', (res) => {
const res = await server.inject('/login/steve');
expect(res.result).to.equal('valid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.not.contain('Max-Age');
done();
});
expect(res.result).to.equal('No active session to apply key to');
});
});
it('authenticates a request (no session override)', (done) => {
it('throws when trying to set key with invalid input', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
path: '/example-path',
clearInvalid: true,
validateFunc: function (request, session, callback) {
return callback(null, session.user === 'valid');
}
clearInvalid: true
});
server.auth.default('default');

@@ -646,6 +772,12 @@ server.route({

auth: { mode: 'try' },
handler: function (request, reply) {
handler: function (request, h) {
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
try {
request.cookieAuth.set({}, 'value');
}
catch (error) {
return h.response(error.message);
}
return h.response('ok');
}

@@ -655,58 +787,34 @@ }

server.route({
method: 'GET', path: '/resource', handler: function (request, reply) {
const res = await server.inject('/login/steve');
return reply('resource');
}
});
server.inject('/login/valid', (res) => {
expect(res.result).to.equal('valid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
/* eslint-disable hapi/no-shadow-relaxed */
server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } }, (res2) => {
expect(res2.statusCode).to.equal(200);
expect(res2.result).to.equal('resource');
done();
});
/* eslint-enable hapi/no-shadow-relaxed */
});
expect(res.result).to.equal('Invalid session key');
});
});
it('authenticates a request (no session override) on a sub-path', (done) => {
it('throws when trying to set key with null key', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
path: '/subpath',
clearInvalid: true,
validateFunc: function (request, session, callback) {
return callback(null, session.user === 'valid');
}
clearInvalid: true
});
server.auth.default('default');
server.route({
method: 'GET', path: '/subpath/login/{user}',
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
handler: function (request, h) {
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
try {
request.cookieAuth.set(null, 'value');
}
catch (error) {
return h.response(error.message);
}
return h.response('ok');
}

@@ -716,46 +824,22 @@ }

server.route({
method: 'GET', path: '/subpath/resource', handler: function (request, reply) {
const res = await server.inject('/login/steve');
return reply('resource');
}
});
server.inject('/subpath/login/valid', (res) => {
expect(res.result).to.equal('valid');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
expect(header[0]).to.contain('Path=/subpath');
/* eslint-disable hapi/no-shadow-relaxed */
server.inject({ method: 'GET', url: '/subpath/resource', headers: { cookie: 'special=' + cookie[1] } }, (res2) => {
expect(res2.statusCode).to.equal(200);
expect(res2.result).to.equal('resource');
done();
});
/* eslint-enable hapi/no-shadow-relaxed */
});
expect(res.result).to.equal('Invalid session key');
});
});
it('extends ttl automatically', (done) => {
describe('clear()', () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
it('clear a specific session key', async (done) => {
expect(err).to.not.exist();
const server = Hapi.server();
await server.register(require('../'));
server.auth.strategy('default', 'cookie', true, {
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
clearInvalid: true,
keepAlive: true
clearInvalid: true
});
server.auth.default('default');

@@ -766,6 +850,6 @@ server.route({

auth: { mode: 'try' },
handler: function (request, reply) {
handler: function (request, h) {
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
return h.response(request.params.user);
}

@@ -776,52 +860,35 @@ }

server.route({
method: 'GET', path: '/resource', handler: function (request, reply) {
method: 'GET', path: '/clearKey', handler: function (request, h) {
return reply('resource');
request.cookieAuth.clear('key');
return null;
}
});
server.inject('/login/valid', (res) => {
const res = await server.inject('/login/steve');
let header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
const pattern = /(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/;
expect(res.result).to.equal('steve');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(pattern);
/* eslint-disable hapi/no-shadow-relaxed */
server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } }, (res2) => {
const res2 = await server.inject({ method: 'GET', url: '/clearKey', headers: { cookie: 'special=' + cookie[1] } });
expect(res2.statusCode).to.equal(200);
header = res2.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
done();
});
/* eslint-enable hapi/no-shadow-relaxed */
});
expect(res2.statusCode).to.equal(200);
});
});
it('extends ttl automatically (validateFunc)', (done) => {
it('throws when trying to clear a key on missing session', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
domain: 'example.com',
cookie: 'special',
clearInvalid: true,
keepAlive: true,
validateFunc: function (request, session, callback) {
const override = Hoek.clone(session);
override.something = 'new';
return callback(null, session.user === 'valid', override);
}
clearInvalid: true
});
server.auth.default('default');

@@ -832,6 +899,12 @@ server.route({

auth: { mode: 'try' },
handler: function (request, reply) {
handler: function (request, h) {
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
try {
request.cookieAuth.clear('key');
}
catch (error) {
return h.response(error.message);
}
return h.response('ok');
}

@@ -841,514 +914,128 @@ }

server.route({
method: 'GET', path: '/resource', handler: function (request, reply) {
const res = await server.inject('/login/steve');
expect(request.auth.credentials.something).to.equal('new');
return reply('resource');
}
});
server.inject('/login/valid', (res) => {
expect(res.result).to.equal('valid');
let header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(/(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/);
/* eslint-disable hapi/no-shadow-relaxed */
server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } }, (res2) => {
expect(res2.statusCode).to.equal(200);
expect(res2.result).to.equal('resource');
header = res2.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
done();
});
/* eslint-enable hapi/no-shadow-relaxed */
});
expect(res.result).to.equal('No active session to clear key from');
});
});
it('errors if ignoreIfDecorated is false and the request object is already decorated', (done) => {
it('throws when trying to clear a key with invalid input', async () => {
const password = 'password-should-be-32-characters';
const ignoreIfDecorated = false;
const options = { password, ignoreIfDecorated };
const server = Hapi.server();
await server.register(require('../'));
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, options);
expect(err).to.not.exist();
expect(() => {
server.auth.strategy('default', 'cookie', true, options);
}).to.throw(Error);
done();
});
});
describe('set()', () => {
it('errors on missing session in set()', (done) => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true
});
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
try {
request.cookieAuth.set();
}
catch (error) {
return reply(error.message);
}
return reply('ok');
}
}
});
server.inject('/login/steve', (res) => {
expect(res.result).to.equal('Invalid session');
done();
});
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true
});
});
server.auth.default('default');
it('sets individual cookie key', (done) => {
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, h) {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true
});
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
try {
request.cookieAuth.clear({});
}
}
});
catch (error) {
return h.response(error.message);
}
server.route({
method: 'GET', path: '/setKey', handler: function (request, reply) {
request.cookieAuth.set('key', 'value');
done();
return h.response('ok');
}
});
server.inject('/login/steve', (res) => {
const pattern = /(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/;
expect(res.result).to.equal('steve');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(pattern);
/* eslint-disable hapi/no-shadow-relaxed */
server.inject({ method: 'GET', url: '/setKey', headers: { cookie: 'special=' + cookie[1] } }, (res2) => {
expect(res2.statusCode).to.equal(200);
});
/* eslint-enable hapi/no-shadow-relaxed */
});
}
});
});
it('throws on missing session when trying to set key', (done) => {
const res = await server.inject('/login/steve');
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true
});
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
try {
request.cookieAuth.set('key', 'value');
}
catch (error) {
return reply(error.message);
}
return reply('ok');
}
}
});
server.inject('/login/steve', (res) => {
expect(res.result).to.equal('No active session to apply key to');
done();
});
});
expect(res.result).to.equal('Invalid session key');
});
it('throws when trying to set key with invalid input', (done) => {
it('throws when trying to clear a key with null input', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true
});
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
try {
request.cookieAuth.set({}, 'value');
}
catch (error) {
return reply(error.message);
}
return reply('ok');
}
}
});
server.inject('/login/steve', (res) => {
expect(res.result).to.equal('Invalid session key');
done();
});
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true
});
});
server.auth.default('default');
it('throws when trying to set key with null key', (done) => {
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, h) {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true
});
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
try {
request.cookieAuth.set(null, 'value');
}
catch (error) {
return reply(error.message);
}
return reply('ok');
try {
request.cookieAuth.clear(null);
}
}
});
server.inject('/login/steve', (res) => {
expect(res.result).to.equal('Invalid session key');
done();
});
});
});
});
describe('clear()', () => {
it('clear a specific session key', (done) => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true
});
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
request.cookieAuth.set({ user: request.params.user });
return reply(request.params.user);
catch (error) {
return h.response(error.message);
}
}
});
server.route({
method: 'GET', path: '/clearKey', handler: function (request, reply) {
request.cookieAuth.clear('key');
done();
return h.response('ok');
}
});
}
});
server.inject('/login/steve', (res) => {
const res = await server.inject('/login/steve');
const pattern = /(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/;
expect(res.result).to.equal('steve');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(pattern);
/* eslint-disable hapi/no-shadow-relaxed */
server.inject({ method: 'GET', url: '/clearKey', headers: { cookie: 'special=' + cookie[1] } }, (res2) => {
expect(res2.statusCode).to.equal(200);
});
/* eslint-enable hapi/no-shadow-relaxed */
});
});
expect(res.result).to.equal('Invalid session key');
});
});
it('throws when trying to clear a key on missing session', (done) => {
describe('ttl()', () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
it('overrides ttl', async () => {
expect(err).to.not.exist();
const server = Hapi.server();
await server.register(require('../'));
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true
});
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
try {
request.cookieAuth.clear('key');
}
catch (error) {
return reply(error.message);
}
return reply('ok');
}
}
});
server.inject('/login/steve', (res) => {
expect(res.result).to.equal('No active session to clear key from');
done();
});
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 1000,
cookie: 'special',
clearInvalid: true
});
});
server.auth.default('default');
it('throws when trying to clear a key with invalid input', (done) => {
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, h) {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true
});
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
try {
request.cookieAuth.clear({});
}
catch (error) {
return reply(error.message);
}
return reply('ok');
}
request.cookieAuth.set({ user: request.params.user });
request.cookieAuth.ttl(60 * 1000);
return h.response(request.params.user);
}
});
server.inject('/login/steve', (res) => {
expect(res.result).to.equal('Invalid session key');
done();
});
}
});
});
it('throws when trying to clear a key with null input', (done) => {
server.route({
method: 'GET', path: '/ttl', handler: function (request, h) {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
cookie: 'special',
clearInvalid: true
});
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
try {
request.cookieAuth.clear(null);
}
catch (error) {
return reply(error.message);
}
return reply('ok');
}
}
});
server.inject('/login/steve', (res) => {
expect(res.result).to.equal('Invalid session key');
done();
});
request.cookieAuth.set('key', 'value');
return null;
}
});
});
});
describe('ttl()', () => {
const res = await server.inject('/login/steve');
it('overrides ttl', (done) => {
const pattern = /(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/;
expect(res.result).to.equal('steve');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(pattern);
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const res2 = await server.inject({ method: 'GET', url: '/ttl', headers: { cookie: 'special=' + cookie[1] } });
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 1000,
cookie: 'special',
clearInvalid: true
});
server.route({
method: 'GET', path: '/login/{user}',
config: {
auth: { mode: 'try' },
handler: function (request, reply) {
request.cookieAuth.set({ user: request.params.user });
request.cookieAuth.ttl(60 * 1000);
return reply(request.params.user);
}
}
});
server.route({
method: 'GET', path: '/ttl', handler: function (request, reply) {
request.cookieAuth.set('key', 'value');
done();
}
});
server.inject('/login/steve', (res) => {
const pattern = /(?:[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)\s*=\s*(?:([^\x00-\x20\"\,\;\\\x7F]*))/;
expect(res.result).to.equal('steve');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(pattern);
/* eslint-disable hapi/no-shadow-relaxed */
server.inject({ method: 'GET', url: '/ttl', headers: { cookie: 'special=' + cookie[1] } }, (res2) => {
expect(res2.statusCode).to.equal(200);
});
/* eslint-enable hapi/no-shadow-relaxed */
});
});
expect(res2.statusCode).to.equal(200);
});

@@ -1359,354 +1046,299 @@ });

it('sends to login page (uri without query)', (done) => {
it('sends to login page (uri without query)', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: 'http://example.com/login',
appendNext: true
});
server.auth.default('default');
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: 'http://example.com/login',
appendNext: true
});
server.route({
method: 'GET', path: '/', handler: function (request, h) {
server.route({
method: 'GET', path: '/', handler: function (request, reply) {
return h.response('never');
}
});
return reply('never');
}
});
const res = await server.inject('/');
server.inject('/', (res) => {
expect(res.statusCode).to.equal(302);
expect(res.headers.location).to.equal('http://example.com/login?next=%2F');
done();
});
});
expect(res.statusCode).to.equal(302);
expect(res.headers.location).to.equal('http://example.com/login?next=%2F');
});
it('sends to login page when redirectTo is a function', (done) => {
it('sends to login page when redirectTo is a function', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: (request) => 'http://example.com/login?widget=' + request.query.widget,
appendNext: true
});
server.auth.default('default');
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: (request) => 'http://example.com/login?widget=' + request.query.widget,
appendNext: true
});
server.route({
method: 'GET', path: '/', handler: function (request, h) {
server.route({
method: 'GET', path: '/', handler: function (request, reply) {
return h.response('never');
}
});
return reply('never');
}
});
const res = await server.inject('/?widget=foo');
server.inject('/?widget=foo', (res) => {
expect(res.statusCode).to.equal(302);
expect(res.headers.location).to.equal('http://example.com/login?widget=foo&next=%2F%3Fwidget%3Dfoo');
done();
});
});
expect(res.statusCode).to.equal(302);
expect(res.headers.location).to.equal('http://example.com/login?widget=foo&next=%2F%3Fwidget%3Dfoo');
});
it('skips when redirectTo is set to false', (done) => {
it('skips when redirectTo is set to false', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: false,
appendNext: true
});
server.auth.default('default');
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: false,
appendNext: true
});
server.route({
method: 'GET',
path: '/',
handler: function (request, h) {
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
return h.response('never');
}
});
return reply('never');
}
});
const res = await server.inject('/');
server.inject('/', (res) => {
expect(res.statusCode).to.equal(401);
done();
});
});
expect(res.statusCode).to.equal(401);
});
it('skips when route override', (done) => {
it('skips when route override', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: 'http://example.com/login',
appendNext: true
});
server.auth.default('default');
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: 'http://example.com/login',
appendNext: true
});
server.route({
method: 'GET',
path: '/',
handler: function (request, h) {
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
return reply('never');
},
config: {
plugins: {
'hapi-auth-cookie': {
redirectTo: false
}
return h.response('never');
},
config: {
plugins: {
'hapi-auth-cookie': {
redirectTo: false
}
}
});
}
});
server.inject('/', (res) => {
const res = await server.inject('/');
expect(res.statusCode).to.equal(401);
done();
});
});
expect(res.statusCode).to.equal(401);
});
it('skips when redirectOnTry is false in try mode', (done) => {
it('skips when redirectOnTry is false in try mode', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectOnTry: false,
redirectTo: 'http://example.com/login',
appendNext: true
});
server.auth.default({
mode: 'try',
strategy: 'default'
});
server.auth.strategy('default', 'cookie', 'try', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectOnTry: false,
redirectTo: 'http://example.com/login',
appendNext: true
});
server.route({
method: 'GET',
path: '/',
handler: function (request, h) {
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
return h.response(request.auth.isAuthenticated);
}
});
return reply(request.auth.isAuthenticated);
}
});
const res = await server.inject('/');
server.inject('/', (res) => {
expect(res.statusCode).to.equal(200);
expect(res.result).to.equal(false);
done();
});
});
expect(res.statusCode).to.equal(200);
expect(res.result).to.equal(false);
});
it('sends to login page (uri with query)', (done) => {
it('sends to login page (uri with query)', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: 'http://example.com/login?mode=1',
appendNext: true
});
server.auth.default('default');
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: 'http://example.com/login?mode=1',
appendNext: true
});
server.route({
method: 'GET', path: '/', handler: function (request, reply) {
server.route({
method: 'GET', path: '/', handler: function (request, reply) {
return reply('never');
}
});
return reply('never');
}
});
const res = await server.inject('/');
server.inject('/', (res) => {
expect(res.statusCode).to.equal(302);
expect(res.headers.location).to.equal('http://example.com/login?mode=1&next=%2F');
done();
});
});
expect(res.statusCode).to.equal(302);
expect(res.headers.location).to.equal('http://example.com/login?mode=1&next=%2F');
});
it('sends to login page and does not append the next query when appendNext is false', (done) => {
it('sends to login page and does not append the next query when appendNext is false', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: 'http://example.com/login?mode=1',
appendNext: false
});
server.auth.default('default');
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: 'http://example.com/login?mode=1',
appendNext: false
});
server.route({
method: 'GET', path: '/', handler: function (request, h) {
server.route({
method: 'GET', path: '/', handler: function (request, reply) {
return h.response('never');
}
});
return reply('never');
}
});
const res = await server.inject('/');
server.inject('/', (res) => {
expect(res.statusCode).to.equal(302);
expect(res.headers.location).to.equal('http://example.com/login?mode=1');
done();
});
});
expect(res.statusCode).to.equal(302);
expect(res.headers.location).to.equal('http://example.com/login?mode=1');
});
it('appends the custom query when appendNext is string', (done) => {
it('appends the custom query when appendNext is string', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: 'http://example.com/login?mode=1',
appendNext: 'done'
});
server.auth.default('default');
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: 'http://example.com/login?mode=1',
appendNext: 'done'
});
server.route({
method: 'GET', path: '/', handler: function (request, h) {
server.route({
method: 'GET', path: '/', handler: function (request, reply) {
return reply('never');
}
});
server.inject('/', (res) => {
expect(res.statusCode).to.equal(302);
expect(res.headers.location).to.equal('http://example.com/login?mode=1&done=%2F');
done();
});
return h.response('never');
}
});
});
it('redirect on try', (done) => {
const res = await server.inject('/');
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
redirectTo: 'http://example.com/login',
appendNext: true
});
server.route({
method: 'GET', path: '/', config: { auth: { mode: 'try' } }, handler: function (request, reply) {
return reply('try');
}
});
server.inject('/', (res) => {
expect(res.statusCode).to.equal(302);
done();
});
});
expect(res.statusCode).to.equal(302);
expect(res.headers.location).to.equal('http://example.com/login?mode=1&done=%2F');
});
});
it('clear cookie on invalid', (done) => {
it('redirect on try', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', true, {
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
clearInvalid: true
redirectTo: 'http://example.com/login',
appendNext: true
});
server.auth.default('default');
server.route({
method: 'GET', path: '/', handler: function (request, reply) {
method: 'GET', path: '/', config: { auth: { mode: 'try' } }, handler: function (request, h) {
return reply();
return h.response('try');
}
});
server.inject({ url: '/', headers: { cookie: 'sid=123456' } }, (res) => {
const res = await server.inject('/');
expect(res.statusCode).to.equal(401);
expect(res.headers['set-cookie'][0]).to.equal('sid=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; HttpOnly; SameSite=Strict; Path=/');
done();
});
expect(res.statusCode).to.equal(302);
});
});
it('supports many strategies', (done) => {
it('clear cookie on invalid', async () => {
const server = new Hapi.Server();
server.connection();
server.register(require('../'), (err) => {
const server = Hapi.server();
await server.register(require('../'));
expect(err).to.not.exist();
server.auth.strategy('default', 'cookie', {
password: 'password-should-be-32-characters',
ttl: 60 * 1000,
clearInvalid: true
});
server.auth.default('default');
expect(() => {
server.route({
method: 'GET', path: '/', handler: () => null
});
const options = {
cookie: 'cookieAuth',
requestDecoratorName: 'cookieAuth',
password: 'password-should-be-32-characters'
};
server.auth.strategy('default', 'cookie', options);
}).to.not.throw();
const res = await server.inject({ url: '/', headers: { cookie: 'sid=123456' } });
expect(() => {
expect(res.statusCode).to.equal(401);
expect(res.headers['set-cookie'][0]).to.equal('sid=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; HttpOnly; SameSite=Strict; Path=/');
});
const options = {
cookie: 'anotherCookieAuth',
requestDecoratorName: 'anotherCookieAuth',
password: 'password-should-be-32-characters'
};
server.auth.strategy('notDefault', 'cookie', options);
}).to.not.throw();
it('supports many strategies', async () => {
done();
});
const server = Hapi.server();
await server.register(require('../'));
expect(() => {
const options = {
cookie: 'cookieAuth',
requestDecoratorName: 'cookieAuth',
password: 'password-should-be-32-characters'
};
server.auth.strategy('default', 'cookie', options);
}).to.not.throw();
expect(() => {
const options = {
cookie: 'anotherCookieAuth',
requestDecoratorName: 'anotherCookieAuth',
password: 'password-should-be-32-characters'
};
server.auth.strategy('notDefault', 'cookie', options);
}).to.not.throw();
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc