@turbasen/auth
Advanced tools
Comparing version 1.0.2 to 2.0.0
'use strict'; | ||
const express = require('express'); | ||
const mongo = require('../test/support/mongo'); | ||
const redis = require('../test/support/redis'); | ||
@@ -10,6 +8,3 @@ const app = module.exports = express(); | ||
app.use(auth({ | ||
mongo: mongo.users, | ||
redis, | ||
})); | ||
app.use(auth.middleware); | ||
@@ -16,0 +11,0 @@ app.get('/', (req, res) => { |
128
index.js
'use strict'; | ||
const HttpError = require('@starefossen/http-error'); | ||
const redis = require('@turbasen/db-redis'); | ||
const mongo = require('@turbasen/db-mongo'); | ||
const UnauthUser = require('./lib/User').UnauthUser; | ||
const AuthUser = require('./lib/User').AuthUser; | ||
const CACHE_VALID = process.env.NTB_USER_VALID_CACHE || 60 * 60 * 1000; | ||
const CACHE_INVALID = process.env.NTB_USER_INVALID_CACHE || 24 * 60 * 60 * 1000; | ||
const CACHE_VALID = process.env.NTB_CACHE_VALID || 60 * 60 * 1000; | ||
const CACHE_INVALID = process.env.NTB_CACHE_INVALID || 24 * 60 * 60 * 1000; | ||
const API_ENV = process.env.NTB_API_ENV || 'dev'; | ||
const LIMIT_UNAUTH = process.env.NTB_LIMIT_UNAUTH || 100; | ||
const RATELIMIT_UNAUTH = process.env.NTB_RATELIMIT_UNAUTH || 100; | ||
module.exports = opts => { | ||
const redis = opts.redis; | ||
const mongo = opts.mongo; | ||
const env = opts.env || API_ENV; | ||
module.exports = () => (req, res, next) => { | ||
let promise; | ||
return function middleware(req, res, next) { | ||
let promise; | ||
// API key through Authorization header | ||
if (req.headers.authorization) { | ||
const token = req.headers.authorization.split(' '); | ||
promise = module.exports.getUserByToken(token[1]); | ||
// API key through Authorization header | ||
if (req.headers.authorization) { | ||
const token = req.headers.authorization.split(' '); | ||
promise = module.exports.getUserByToken(redis, mongo, env, token[1]); | ||
// API key through URL query parameter | ||
} else if (req.query && req.query.api_key) { | ||
promise = module.exports.getUserByToken(req.query.api_key); | ||
// API key through URL query parameter | ||
} else if (req.query && req.query.api_key) { | ||
promise = module.exports.getUserByToken(redis, mongo, env, req.query.api_key); | ||
// No API key | ||
} else { | ||
promise = module.exports.getUserByIp( | ||
req.headers['x-forwarded-for'] || req.connection.remoteAddres | ||
); | ||
} | ||
// No API key | ||
} else { | ||
promise = module.exports.getUserByIp( | ||
redis, mongo, env, | ||
req.headers['x-forwarded-for'] || req.connection.remoteAddres | ||
); | ||
promise.then(user => { | ||
req.user = user; | ||
res.set('X-User-Auth', user.auth); | ||
if (user.auth) { | ||
res.set('X-User-Provider', user.provider); | ||
} | ||
promise.then(user => { | ||
req.user = user; | ||
res.set('X-RateLimit-Limit', user.limit); | ||
res.set('X-RateLimit-Reset', user.reset); | ||
res.set('X-User-Auth', user.auth); | ||
if (user.auth) { | ||
res.set('X-User-Provider', user.provider); | ||
} | ||
if (!user.hasRemainingQuota()) { | ||
res.set('X-RateLimit-Remaining', 0); | ||
res.set('X-RateLimit-Limit', user.limit); | ||
res.set('X-RateLimit-Reset', user.reset); | ||
return next(new HttpError( | ||
403, `API rate limit exceeded for ${user.type} "${user.key}"` | ||
)); | ||
} | ||
if (!user.hasRemainingQuota()) { | ||
res.set('X-RateLimit-Remaining', 0); | ||
res.set('X-RateLimit-Remaining', user.charge()); | ||
return next(new HttpError( | ||
403, `API rate limit exceeded for ${user.type} "${user.key}"` | ||
)); | ||
if (!user.can(req.method)) { | ||
return next(new HttpError( | ||
401, `API authentication required for "${req.method}" requests` | ||
)); | ||
} | ||
res.on('finish', function resOnFinishCb() { | ||
// Uncharge user when certain cache features are used. | ||
// 304 Not Modified, and 412 Precondition Failed | ||
if (this.statusCode === 304 || this.statusCode === 412) { | ||
this.req.user.uncharge(); | ||
} | ||
res.set('X-RateLimit-Remaining', user.charge()); | ||
if (!user.can(req.method)) { | ||
return next(new HttpError( | ||
401, `API authentication required for "${req.method}" requests` | ||
)); | ||
if (this.req.user.getCharge() > 0) { | ||
redis.hincrby(this.req.user.cacheKey, 'remaining', -1); | ||
} | ||
}); | ||
res.on('finish', function resOnFinishCb() { | ||
// Uncharge user when certain cache features are used. | ||
// 304 Not Modified, and 412 Precondition Failed | ||
if (this.statusCode === 304 || this.statusCode === 412) { | ||
this.req.user.uncharge(); | ||
} | ||
if (this.req.user.getCharge() > 0) { | ||
redis.hincrby(this.req.user.cacheKey, 'remaining', -1); | ||
} | ||
}); | ||
return next(); | ||
}).catch(next); | ||
}; | ||
return next(); | ||
}).catch(next); | ||
}; | ||
module.exports.getUserByIp = function getUserByIp(redis, mongo, env, key) { | ||
module.exports.getUserByIp = function getUserByIp(key) { | ||
return new Promise((resolve, reject) => { | ||
@@ -92,4 +88,4 @@ redis.hgetall(AuthUser.getCacheKey(key), (redisErr, data) => { | ||
const user = new UnauthUser(key, { | ||
limit: LIMIT_UNAUTH, | ||
remaining: LIMIT_UNAUTH, | ||
limit: RATELIMIT_UNAUTH, | ||
remaining: RATELIMIT_UNAUTH, | ||
reset: expireat, | ||
@@ -107,3 +103,3 @@ }); | ||
module.exports.getUserByToken = function getUserByToken(redis, mongo, env, key) { | ||
module.exports.getUserByToken = function getUserByToken(key) { | ||
return new Promise((resolve, reject) => { | ||
@@ -122,3 +118,3 @@ redis.hgetall(UnauthUser.getCacheKey(key), (redisErr, data) => { | ||
const query = { | ||
[`apps.key.${env}`]: key, | ||
[`apps.key.${API_ENV}`]: key, | ||
'apps.active': true, | ||
@@ -134,3 +130,3 @@ }; | ||
return mongo.findOne(query, opts, (mongoErr, doc) => { | ||
return mongo.api.users.findOne(query, opts, (mongoErr, doc) => { | ||
if (mongoErr) { return reject(mongoErr); } | ||
@@ -147,3 +143,3 @@ | ||
const app = doc.apps.find(item => item.key[env] === key); | ||
const app = doc.apps.find(item => item.key[API_ENV] === key); | ||
const expireat = module.exports.expireat(CACHE_VALID); | ||
@@ -155,4 +151,4 @@ | ||
limit: app.limit[env], | ||
remaining: app.limit[env], | ||
limit: app.limit[API_ENV], | ||
remaining: app.limit[API_ENV], | ||
reset: expireat, | ||
@@ -173,1 +169,3 @@ }); | ||
}; | ||
module.exports.middleware = module.exports(); |
{ | ||
"name": "@turbasen/auth", | ||
"version": "1.0.2", | ||
"version": "2.0.0", | ||
"description": "Authentication middleware used internally at Nasjonal Turbase API", | ||
@@ -43,2 +43,4 @@ "main": "index.js", | ||
"@starefossen/http-error": "^1.0.0", | ||
"@turbasen/db-mongo": "^1.0.0", | ||
"@turbasen/db-redis": "^1.0.0", | ||
"express": "^4.13.4" | ||
@@ -48,2 +50,4 @@ }, | ||
"@starefossen/http-error": "^1.0.0", | ||
"@turbasen/db-mongo": "^1.0.0", | ||
"@turbasen/db-redis": "^1.0.0", | ||
"codacy-coverage": "^1.1.3", | ||
@@ -55,3 +59,2 @@ "eslint": "^2.13.1", | ||
"greenkeeper-postpublish": "^1.0.0", | ||
"ioredis": "^2.2.0", | ||
"istanbul": "^0.4.4", | ||
@@ -58,0 +61,0 @@ "mocha": "^2.5.3", |
Sorry, the diff of this file is not supported yet
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
11906
4
16
242