Skip to content

Commit 205461e

Browse files
author
Hans Kristian Flaatten
committed
feat(api): depend on @turbasen/db-redis and @turbasen/db-mongo
BREAKING CHANGE: Middleware constructor no longer takes a `redis` and `mongo` option when instanciating the middleware. Instead it depends on `@turbasen/db-redis` and `@turbasen/db-mongo` for database connections.
1 parent 780d19f commit 205461e

10 files changed

Lines changed: 66 additions & 92 deletions

File tree

examples/server.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
'use strict';
22

33
const express = require('express');
4-
const mongo = require('../test/support/mongo');
5-
const redis = require('../test/support/redis');
4+
const mongo = require('@turbasen/db-mongo');
5+
const redis = require('@turbasen/db-redis');
66

77
const app = module.exports = express();
88
const auth = require('../');

index.js

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,33 @@
11
'use strict';
22

33
const HttpError = require('@starefossen/http-error');
4+
const redis = require('@turbasen/db-redis');
5+
const mongo = require('@turbasen/db-mongo');
6+
47
const UnauthUser = require('./lib/User').UnauthUser;
58
const AuthUser = require('./lib/User').AuthUser;
69

7-
const CACHE_VALID = process.env.NTB_USER_VALID_CACHE || 60 * 60 * 1000;
8-
const CACHE_INVALID = process.env.NTB_USER_INVALID_CACHE || 24 * 60 * 60 * 1000;
10+
const CACHE_VALID = process.env.NTB_CACHE_VALID || 60 * 60 * 1000;
11+
const CACHE_INVALID = process.env.NTB_CACHE_INVALID || 24 * 60 * 60 * 1000;
912
const API_ENV = process.env.NTB_API_ENV || 'dev';
10-
const LIMIT_UNAUTH = process.env.NTB_LIMIT_UNAUTH || 100;
11-
12-
module.exports = opts => {
13-
const redis = opts.redis;
14-
const mongo = opts.mongo;
15-
const env = opts.env || API_ENV;
13+
const RATELIMIT_UNAUTH = process.env.NTB_RATELIMIT_UNAUTH || 100;
1614

15+
module.exports = () => {
1716
return function middleware(req, res, next) {
1817
let promise;
1918

2019
// API key through Authorization header
2120
if (req.headers.authorization) {
2221
const token = req.headers.authorization.split(' ');
23-
promise = module.exports.getUserByToken(redis, mongo, env, token[1]);
22+
promise = module.exports.getUserByToken(token[1]);
2423

2524
// API key through URL query parameter
2625
} else if (req.query && req.query.api_key) {
27-
promise = module.exports.getUserByToken(redis, mongo, env, req.query.api_key);
26+
promise = module.exports.getUserByToken(req.query.api_key);
2827

2928
// No API key
3029
} else {
3130
promise = module.exports.getUserByIp(
32-
redis, mongo, env,
3331
req.headers['x-forwarded-for'] || req.connection.remoteAddres
3432
);
3533
}
@@ -78,7 +76,7 @@ module.exports = opts => {
7876
};
7977
};
8078

81-
module.exports.getUserByIp = function getUserByIp(redis, mongo, env, key) {
79+
module.exports.getUserByIp = function getUserByIp(key) {
8280
return new Promise((resolve, reject) => {
8381
redis.hgetall(AuthUser.getCacheKey(key), (redisErr, data) => {
8482
if (redisErr) { return reject(redisErr); }
@@ -89,8 +87,8 @@ module.exports.getUserByIp = function getUserByIp(redis, mongo, env, key) {
8987
const expireat = module.exports.expireat(CACHE_VALID);
9088

9189
const user = new UnauthUser(key, {
92-
limit: LIMIT_UNAUTH,
93-
remaining: LIMIT_UNAUTH,
90+
limit: RATELIMIT_UNAUTH,
91+
remaining: RATELIMIT_UNAUTH,
9492
reset: expireat,
9593
});
9694

@@ -103,7 +101,7 @@ module.exports.getUserByIp = function getUserByIp(redis, mongo, env, key) {
103101
});
104102
};
105103

106-
module.exports.getUserByToken = function getUserByToken(redis, mongo, env, key) {
104+
module.exports.getUserByToken = function getUserByToken(key) {
107105
return new Promise((resolve, reject) => {
108106
redis.hgetall(UnauthUser.getCacheKey(key), (redisErr, data) => {
109107
if (redisErr) { return reject(redisErr); }
@@ -117,7 +115,7 @@ module.exports.getUserByToken = function getUserByToken(redis, mongo, env, key)
117115
}
118116

119117
const query = {
120-
[`apps.key.${env}`]: key,
118+
[`apps.key.${API_ENV}`]: key,
121119
'apps.active': true,
122120
};
123121

@@ -128,7 +126,7 @@ module.exports.getUserByToken = function getUserByToken(redis, mongo, env, key)
128126
},
129127
};
130128

131-
return mongo.findOne(query, opts, (mongoErr, doc) => {
129+
return mongo.api.users.findOne(query, opts, (mongoErr, doc) => {
132130
if (mongoErr) { return reject(mongoErr); }
133131

134132
if (!doc) {
@@ -140,15 +138,15 @@ module.exports.getUserByToken = function getUserByToken(redis, mongo, env, key)
140138
return reject(new HttpError(`Bad credentials for user "${key}"`, 401));
141139
}
142140

143-
const app = doc.apps.find(item => item.key[env] === key);
141+
const app = doc.apps.find(item => item.key[API_ENV] === key);
144142
const expireat = module.exports.expireat(CACHE_VALID);
145143

146144
const user = new AuthUser(key, {
147145
provider: doc.provider,
148146
app: app.name,
149147

150-
limit: app.limit[env],
151-
remaining: app.limit[env],
148+
limit: app.limit[API_ENV],
149+
remaining: app.limit[API_ENV],
152150
reset: expireat,
153151
});
154152

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,22 @@
4040
"homepage": "https://github.com/Turbasen/Auth#readme",
4141
"peerDependencies": {
4242
"@starefossen/http-error": "^1.0.0",
43+
"@turbasen/db-mongo": "^1.0.0",
44+
"@turbasen/db-redis": "^1.0.0",
4345
"express": "^4.13.4"
4446
},
4547
"devDependencies": {
4648
"@starefossen/http-error": "^1.0.0",
49+
"@turbasen/db-mongo": "^1.0.0",
50+
"@turbasen/db-redis": "^1.0.0",
4751
"codacy-coverage": "^1.1.3",
4852
"eslint": "^2.13.1",
4953
"eslint-config-airbnb-base": "^3.0.1",
5054
"eslint-plugin-import": "^1.10.0",
5155
"express": "^4.13.4",
5256
"greenkeeper-postpublish": "^1.0.0",
53-
"ioredis": "^2.2.0",
5457
"istanbul": "^0.4.4",
5558
"mocha": "^2.5.3",
56-
"mongodb": "^2.1.18",
5759
"nsp": "^2.5.0",
5860
"semantic-release": "^4.3.5",
5961
"sinon": "^1.17.4",

test/index.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
'use strict';
22

3-
const mongo = require('./support/mongo');
4-
const redis = require('./support/redis');
3+
const mongo = require('@turbasen/db-mongo');
4+
const redis = require('@turbasen/db-redis');
55
const users = require('./support/users');
66

7-
before(done => mongo.on('ready', done));
7+
before(done => {
8+
if (mongo.db) { return done(); }
9+
mongo.on('ready', done);
10+
});
11+
812
beforeEach(done => redis.flushall(done));
913
beforeEach(function (done) { this.timeout(10000); mongo.db.dropDatabase(done); });
10-
beforeEach(function (done) { this.timeout(10000); mongo.users.insert(users, done); });
14+
beforeEach(function (done) { this.timeout(10000); mongo.api.users.insert(users, done); });

test/support/env.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
'use strict';
22

33
process.env.NODE_ENV = 'test';
4-
process.env.NTB_API_ENV = 'dev';
4+
process.env.NTB_API_ENV = 'test';

test/support/mongo.js

Lines changed: 0 additions & 28 deletions
This file was deleted.

test/support/redis.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

test/support/users.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ module.exports = [
1111
_id: new ObjectID('100000000000000000000001'),
1212
name: 'foo_app1',
1313
limit: {
14+
test: 499,
1415
dev: 500,
1516
prod: 5000,
1617
},
1718
key: {
19+
test: 'foo_app1_test',
1820
dev: 'foo_app1_dev',
1921
prod: 'foo_app1_prod',
2022
},
@@ -29,10 +31,12 @@ module.exports = [
2931
_id: new ObjectID('200000000000000000000001'),
3032
name: 'bar_app1',
3133
limit: {
34+
test: 499,
3235
dev: 500,
3336
prod: 5000,
3437
},
3538
key: {
39+
test: 'bar_app1_test',
3640
dev: 'bar_app1_dev',
3741
prod: 'bar_app1_prod',
3842
},
@@ -41,10 +45,12 @@ module.exports = [
4145
_id: new ObjectID('200000000000000000000002'),
4246
name: 'bar_app2',
4347
limit: {
48+
test: 499,
4449
dev: 500,
4550
prod: 5000,
4651
},
4752
key: {
53+
test: 'bar_app2_test',
4854
dev: 'bar_app2_dev',
4955
prod: 'bar_app2_prod',
5056
},

test/unit/auth.js

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ const assert = require('assert');
55
const sinon = require('sinon');
66
const auth = require('../../');
77

8-
const mongo = require('../support/mongo');
9-
const redis = require('../support/redis');
8+
const mongo = require('@turbasen/db-mongo');
9+
const redis = require('@turbasen/db-redis');
1010

1111
const AuthUser = require('../../lib/User').AuthUser;
1212
const UnauthUser = require('../../lib/User').UnauthUser;
1313

1414
describe('auth', () => {
1515
describe('getUserByToken()', () => {
1616
it('rejects invalid token', done => {
17-
auth.getUserByToken(redis, mongo.users, 'prod', 'invalid')
17+
auth.getUserByToken('invalid')
1818
.then(() => process.nextTick(() => assert.fail()))
1919
.catch(error => process.nextTick(() => {
2020
assert(error instanceof HttpError);
@@ -25,7 +25,7 @@ describe('auth', () => {
2525
});
2626

2727
it('saves invalid token to redis cache', done => {
28-
auth.getUserByToken(redis, mongo.users, 'prod', 'invalid')
28+
auth.getUserByToken('invalid')
2929
.then(() => process.nextTick(() => assert.fail()))
3030
.catch(() => process.nextTick(() => {
3131
redis.hgetall('api:token:invalid', (err, data) => {
@@ -37,7 +37,7 @@ describe('auth', () => {
3737
});
3838

3939
it('caches invalid token for 24 hours', done => {
40-
auth.getUserByToken(redis, mongo.users, 'prod', 'invalid')
40+
auth.getUserByToken('invalid')
4141
.then(() => process.nextTick(() => assert.fail()))
4242
.catch(() => process.nextTick(() => {
4343
redis.ttl('api:token:invalid', (err, ttl) => {
@@ -52,7 +52,7 @@ describe('auth', () => {
5252
redis.hset('api:token:invalid', 'access', 'false', err => {
5353
assert.ifError(err);
5454

55-
auth.getUserByToken(redis, mongo.users, 'prod', 'invalid')
55+
auth.getUserByToken('invalid')
5656
.then(() => process.nextTick(() => assert.fail()))
5757
.catch(error => process.nextTick(() => {
5858
assert.equal(error.code, 401);
@@ -64,15 +64,15 @@ describe('auth', () => {
6464
});
6565

6666
it('returns user for valid token', done => {
67-
auth.getUserByToken(redis, mongo.users, 'prod', 'foo_app1_prod')
67+
auth.getUserByToken('foo_app1_test')
6868
.then(user => process.nextTick(() => {
6969
assert(user instanceof AuthUser);
7070

71-
assert.equal(user.key, 'foo_app1_prod');
71+
assert.equal(user.key, 'foo_app1_test');
7272
assert.equal(user.provider, 'FOO');
7373
assert.equal(user.app, 'foo_app1');
74-
assert.equal(user.limit, 5000);
75-
assert.equal(user.remaining, 5000);
74+
assert.equal(user.limit, 499);
75+
assert.equal(user.remaining, 499);
7676

7777
const expire = Math.floor(new Date().getTime() / 1000);
7878
assert(user.reset > expire);
@@ -85,16 +85,16 @@ describe('auth', () => {
8585
});
8686

8787
it('saves valid token to redis chache', done => {
88-
auth.getUserByToken(redis, mongo.users, 'prod', 'foo_app1_prod')
88+
auth.getUserByToken('foo_app1_test')
8989
.then(() => process.nextTick(() => {
90-
redis.hgetall('api:token:foo_app1_prod', (err, data) => {
90+
redis.hgetall('api:token:foo_app1_test', (err, data) => {
9191
assert.ifError(err);
9292
assert.deepEqual(data, {
9393
access: 'true',
9494
app: 'foo_app1',
95-
limit: '5000',
95+
limit: '499',
9696
provider: 'FOO',
97-
remaining: '5000',
97+
remaining: '499',
9898
reset: data.reset,
9999
});
100100

@@ -108,9 +108,9 @@ describe('auth', () => {
108108
});
109109

110110
it('caches valid token for 1 hour', done => {
111-
auth.getUserByToken(redis, mongo.users, 'prod', 'foo_app1_prod')
111+
auth.getUserByToken('foo_app1_test')
112112
.then(() => process.nextTick(() => {
113-
redis.ttl('api:token:foo_app1_prod', (err, ttl) => {
113+
redis.ttl('api:token:foo_app1_test', (err, ttl) => {
114114
assert.ifError(err);
115115
assert(ttl >= 3590 && ttl <= 3610); // 24h ± 10s
116116
done();
@@ -176,7 +176,7 @@ describe('auth', () => {
176176

177177
it('looks up user by Authorization header', done => {
178178
req.headers.authorization = 'Token abc123';
179-
auth.getUserByToken = (r, m, env, token) => {
179+
auth.getUserByToken = (token) => {
180180
assert.equal(token, 'abc123');
181181
done();
182182

@@ -188,7 +188,7 @@ describe('auth', () => {
188188

189189
it('looks up user by URL query parameter', done => {
190190
req.query.api_key = 'abc123';
191-
auth.getUserByToken = (r, m, env, token) => {
191+
auth.getUserByToken = (token) => {
192192
assert.equal(token, 'abc123');
193193
done();
194194

@@ -200,7 +200,7 @@ describe('auth', () => {
200200

201201
it('looks up user by remote IP', done => {
202202
req.connection.remoteAddres = '123.456.789';
203-
auth.getUserByIp = (r, m, env, token) => {
203+
auth.getUserByIp = (token) => {
204204
assert.equal(token, '123.456.789');
205205
done();
206206

@@ -214,7 +214,7 @@ describe('auth', () => {
214214
req.connection.remoteAddres = '127.0.0.1';
215215
req.headers['x-forwarded-for'] = '123.456.789';
216216

217-
auth.getUserByIp = (r, m, env, token) => {
217+
auth.getUserByIp = (token) => {
218218
assert.equal(token, '123.456.789');
219219
done();
220220

@@ -226,7 +226,7 @@ describe('auth', () => {
226226

227227
it('sets X-RateLimit headers for valid user', done => {
228228
req.connection.remoteAddres = '127.0.0.1';
229-
auth.getUserByIp = (r, m, env, token) => Promise.resolve(
229+
auth.getUserByIp = (token) => Promise.resolve(
230230
new UnauthUser(token, {
231231
limit: 100,
232232
remaining: 49,

0 commit comments

Comments
 (0)