├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── examples
└── basic
│ ├── home.hbs
│ └── index.js
├── index.js
├── lib
└── index.js
├── package.json
└── test
├── index.js
└── test.hbs
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # Compiled binary addons (http://nodejs.org/api/addons.html)
20 | build/Release
21 |
22 | # Dependency directory
23 | # Commenting this out is preferred by some people, see
24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
25 | node_modules
26 |
27 | # Users Environment Variables
28 | .lock-wscript
29 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - 0.10
5 | - 0.12
6 | - iojs
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Matt Harrison
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # hapi-context-credentials
2 |
3 | [](https://travis-ci.org/mtharrison/hapi-context-credentials)
4 |
5 | hapi.js plugin - Include `request.auth.credentials` in default view context, if user is authenticated.
6 |
7 | ##Install
8 |
9 | `npm install --save hapi-context-credentials`
10 |
11 | ##Background
12 |
13 | For pretty much any website that has a login feature, parts of the page will be rendered conditionally based on the current user's state. Perhaps it will display their username in the header and show a logout button for logged-in users.
14 |
15 | I usually build my sites out at first without any auth and then add auth at a later stage. If I'm using a common layout, I would later need to add something like the following to the handler of every route.
16 |
17 | ```js
18 | handler: function (request, reply) {
19 | ...
20 | reply.view('index', {
21 | credentials: request.auth.credentials
22 | });
23 | }
24 | ```
25 |
26 | And in my template I might have something like:
27 |
28 | {{#if credentials.firstName}}
29 |
Welcome back {{credentials.firstName}}!
30 | {{else}}
31 | Welcome guest!
32 | {{/if}}
33 |
34 | This module saves the work by ensuring `request.auth.credentials` is included in every view context on your server, so you don't need to manually include it in your handlers.
35 |
36 | ##Usage
37 |
38 | Just register like any Hapi plugin:
39 |
40 | ```js
41 | server.register(require('hapi-context-credentials'), (err) => {
42 |
43 | if (err) {
44 | throw err;
45 | }
46 |
47 | server.start(function (err) {
48 |
49 | if (err) {
50 | throw err;
51 | }
52 | console.log('Server started!');
53 | });
54 | });
55 | ```
56 |
57 | You can then output `credentials` in your views.
58 |
59 | ##Credit
60 |
61 | The idea for this plugin came from https://github.com/hapijs/hapi/issues/2419. Credit to @ubaltaci for the preResponse handler idea.
62 |
--------------------------------------------------------------------------------
/examples/basic/home.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hello!
6 |
7 |
8 | {{#if credentials}}
9 | Hello {{credentials.username}}!
10 | {{else}}
11 | Hello guest!
12 | You can login here
13 | {{/if}}
14 |
15 |
--------------------------------------------------------------------------------
/examples/basic/index.js:
--------------------------------------------------------------------------------
1 | var Hapi = require('hapi');
2 | var Path = require('path');
3 |
4 | var server = new Hapi.Server();
5 | server.connection({ port: 4000 });
6 |
7 | server.register([
8 | { register: require('vision') },
9 | { register: require('hapi-auth-basic') },
10 | { register: require('../../index') }
11 | ], function (err) {
12 |
13 | if (err) {
14 | throw err;
15 | }
16 |
17 | server.views({
18 | engines: {
19 | hbs: require('handlebars')
20 | },
21 | path: __dirname,
22 | isCached: false
23 | });
24 |
25 | var validateFunc = function (request, username, password, callback) {
26 |
27 | // Just authenticate everyone and store username
28 | // in credentials
29 |
30 | if (username === 'john' && password === 'secret') {
31 | return callback(null, true, { username: 'john' });
32 | }
33 |
34 | return callback(null, false, {});
35 | };
36 |
37 | server.auth.strategy('simple', 'basic', {
38 | validateFunc: validateFunc
39 | });
40 |
41 | server.route([
42 | {
43 | config: {
44 | auth: {
45 | strategy: 'simple',
46 | mode: 'try'
47 | }
48 | },
49 | method: 'GET',
50 | path: '/',
51 | handler: function (request, reply) {
52 |
53 | reply.view('home');
54 | }
55 | },
56 | {
57 | config: {
58 | auth: {
59 | strategy: 'simple'
60 | }
61 | },
62 | method: 'GET',
63 | path: '/login',
64 | handler: function (request, reply) {
65 |
66 | return reply.redirect('/');
67 | }
68 | }
69 | ]);
70 |
71 | server.start(function () {
72 |
73 | console.log('Started serverx');
74 | });
75 | });
76 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./lib');
2 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | exports.register = function (server, options, next) {
2 |
3 | server.ext('onPreResponse', function (request, reply) {
4 |
5 | var response = request.response;
6 | if (response.variety && response.variety === 'view') {
7 | response.source.context = response.source.context || {};
8 | response.source.context.credentials = request.auth.isAuthenticated ? request.auth.credentials : null;
9 | }
10 | return reply.continue();
11 | });
12 |
13 | next();
14 | };
15 |
16 | exports.register.attributes = {
17 | pkg: require('../package.json')
18 | };
19 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hapi-context-credentials",
3 | "version": "2.0.0",
4 | "description": "Include `request.auth.credentials` in template view context",
5 | "main": "index.js",
6 | "author": "Matt Harrison",
7 | "license": "BSD-3-Clause",
8 | "scripts": {
9 | "test": "lab -a code -t 100 -L",
10 | "test-cov-html": "lab -a code -r html -o coverage.html"
11 | },
12 | "peerDependencies": {
13 | "hapi": ">=8.x.x"
14 | },
15 | "devDependencies": {
16 | "code": "^1.5.0",
17 | "handlebars": "3.x.x",
18 | "hapi": "9.x.x",
19 | "hapi-auth-basic": "3.x.x",
20 | "lab": "^5.15.2",
21 | "vision": "^3.0.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | // Load modules
2 |
3 | var Code = require('code');
4 | var Hapi = require('hapi');
5 | var Lab = require('lab');
6 |
7 |
8 | // Declare internals
9 |
10 | var internals = {};
11 |
12 |
13 | // Test shortcuts
14 |
15 | var lab = exports.lab = Lab.script();
16 | var describe = lab.describe;
17 | var it = lab.it;
18 | var expect = Code.expect;
19 |
20 |
21 | it('doesn\'t interfere with non view responses', function (done) {
22 |
23 | var server = new Hapi.Server();
24 | server.connection();
25 | server.register(require('../'), function (err) {
26 |
27 | expect(err).to.not.exist();
28 |
29 | server.route({
30 | method: 'GET',
31 | path: '/',
32 | handler: function (request, reply) {
33 |
34 | return reply('ok');
35 | }
36 | });
37 |
38 | var request = { method: 'GET', url: '/' };
39 |
40 | server.inject(request, function (res) {
41 |
42 | expect(res.result).to.equal('ok');
43 | done();
44 | });
45 | });
46 | });
47 |
48 | it('doesn\'t include credentials if not authenticated', function (done) {
49 |
50 | var server = new Hapi.Server();
51 | server.connection();
52 | server.register([require('../'), require('vision')], function (err) {
53 |
54 | expect(err).to.not.exist();
55 |
56 | server.views({
57 | engines: {
58 | hbs: require('handlebars')
59 | },
60 | path: __dirname,
61 | isCached: false
62 | });
63 |
64 | server.route({
65 | method: 'GET',
66 | path: '/',
67 | handler: function (request, reply) {
68 |
69 | request.auth.credentials = {};
70 | request.auth.credentials.username = 'john';
71 | return reply.view('test');
72 | }
73 | });
74 |
75 | var request = { method: 'GET', url: '/' };
76 |
77 | server.inject(request, function (res) {
78 |
79 | expect(res.result).to.equal('Hello !');
80 | done();
81 | });
82 | });
83 | });
84 |
85 | it('includes credentials if authenticated', function (done) {
86 |
87 | var server = new Hapi.Server();
88 | server.connection();
89 | server.register([require('../'), require('vision')], function (err) {
90 |
91 | expect(err).to.not.exist();
92 |
93 | server.views({
94 | engines: {
95 | hbs: require('handlebars')
96 | },
97 | path: __dirname,
98 | isCached: false
99 | });
100 |
101 | server.route({
102 | method: 'GET',
103 | path: '/',
104 | handler: function (request, reply) {
105 |
106 | request.auth.isAuthenticated = true;
107 | request.auth.credentials = {};
108 | request.auth.credentials.username = 'john';
109 | return reply.view('test');
110 | }
111 | });
112 |
113 | var request = { method: 'GET', url: '/' };
114 |
115 | server.inject(request, function (res) {
116 |
117 | expect(res.result).to.equal('Hello john!');
118 | done();
119 | });
120 | });
121 | });
122 |
123 | it('merges credentials with existing context', function (done) {
124 |
125 | var server = new Hapi.Server();
126 | server.connection();
127 | server.register([require('../'), require('vision')], function (err) {
128 |
129 | expect(err).to.not.exist();
130 |
131 | server.views({
132 | engines: {
133 | hbs: require('handlebars')
134 | },
135 | path: __dirname,
136 | isCached: false
137 | });
138 |
139 | server.route({
140 | method: 'GET',
141 | path: '/',
142 | handler: function (request, reply) {
143 |
144 | request.auth.isAuthenticated = true;
145 | request.auth.credentials = {};
146 | request.auth.credentials.username = 'john';
147 | return reply.view('test', { a: 1 });
148 | }
149 | });
150 |
151 | var request = { method: 'GET', url: '/' };
152 |
153 | server.inject(request, function (res) {
154 |
155 | expect(res.result).to.equal('Hello john!');
156 | done();
157 | });
158 | });
159 | });
160 |
161 | it('does\'t affect non-variety responses', function (done) {
162 |
163 | var server = new Hapi.Server();
164 | server.connection();
165 | server.register([require('../'), require('vision')], function (err) {
166 |
167 | expect(err).to.not.exist();
168 |
169 | server.route({
170 | method: 'GET',
171 | path: '/',
172 | handler: function (request, reply) {
173 |
174 | reply(new Error('error'));
175 | }
176 | });
177 |
178 | var request = { method: 'GET', url: '/' };
179 |
180 | server.inject(request, function (res) {
181 |
182 | expect(res.statusCode).to.equal(500);
183 | done();
184 | });
185 | });
186 | });
187 |
188 | internals.header = function (username, password) {
189 |
190 | return 'Basic ' + (new Buffer(username + ':' + password, 'utf8')).toString('base64');
191 | };
192 |
--------------------------------------------------------------------------------
/test/test.hbs:
--------------------------------------------------------------------------------
1 | Hello {{credentials.username}}!
--------------------------------------------------------------------------------