@turbasen/auth
Advanced tools
Comparing version 2.1.0 to 3.0.0
132
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 AbstractUser = require('./lib/AbstractUser'); | ||
const UnauthUser = require('./lib/UnauthUser'); | ||
const AuthUser = require('./lib/AuthUser'); | ||
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 RATELIMIT_UNAUTH = process.env.NTB_RATELIMIT_UNAUTH || 100; | ||
module.exports = () => (req, res, next) => { | ||
@@ -21,11 +15,11 @@ let promise; | ||
const token = req.headers.authorization.split(' '); | ||
promise = module.exports.getUserByToken(token[1]); | ||
promise = AuthUser.getByKey(token[1]); | ||
// API key through URL query parameter | ||
} else if (req.query && req.query.api_key) { | ||
promise = module.exports.getUserByToken(req.query.api_key); | ||
promise = AuthUser.getByKey(req.query.api_key); | ||
// No API key | ||
} else { | ||
promise = module.exports.getUserByIp( | ||
promise = UnauthUser.getByKey( | ||
req.headers['x-forwarded-for'] || req.connection.remoteAddres | ||
@@ -38,2 +32,3 @@ ); | ||
// X-User headers | ||
res.set('X-User-Auth', user.auth); | ||
@@ -44,5 +39,7 @@ if (user.auth) { | ||
// X-Rate-Limit headers | ||
res.set('X-RateLimit-Limit', user.limit); | ||
res.set('X-RateLimit-Reset', user.reset); | ||
// Check if user has remaining rate limit quota | ||
if (!user.hasRemainingQuota()) { | ||
@@ -56,4 +53,7 @@ res.set('X-RateLimit-Remaining', 0); | ||
// Charge user for this request | ||
res.set('X-RateLimit-Remaining', user.charge()); | ||
// Check if user can execute the HTTP method. Only authenticated users are | ||
// allowed to execute POST, PUT, and DELETE requests. | ||
if (!user.can(req.method)) { | ||
@@ -65,14 +65,5 @@ return next(new HttpError( | ||
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(); | ||
} | ||
// Attach the on finish callback which updates the user rate limit in cache. | ||
res.on('finish', module.exports.onFinish); | ||
if (this.req.user.getCharge() > 0) { | ||
redis.hincrby(this.req.user.cacheKey, 'remaining', -1); | ||
} | ||
}); | ||
return next(); | ||
@@ -82,89 +73,16 @@ }).catch(next); | ||
module.exports.getUserByIp = function getUserByIp(key) { | ||
return new Promise((resolve, reject) => { | ||
redis.hgetall(AuthUser.getCacheKey(key), (redisErr, data) => { | ||
if (redisErr) { return reject(redisErr); } | ||
module.exports.onFinish = function onFinish() { | ||
// 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 (data && data.limit) { | ||
return resolve(new UnauthUser(key, data)); | ||
} else { | ||
const expireat = module.exports.expireat(CACHE_VALID); | ||
const user = new UnauthUser(key, { | ||
limit: RATELIMIT_UNAUTH, | ||
remaining: RATELIMIT_UNAUTH, | ||
reset: expireat, | ||
}); | ||
redis.hmset(AuthUser.getCacheKey(key), user.toObject()); | ||
redis.expireat(AuthUser.getCacheKey(key), expireat); | ||
return resolve(user); | ||
} | ||
}); | ||
}); | ||
// Update user rate-limit in cache if it has changed. | ||
this.req.user.update(); | ||
}; | ||
module.exports.getUserByToken = function getUserByToken(key) { | ||
return new Promise((resolve, reject) => { | ||
redis.hgetall(UnauthUser.getCacheKey(key), (redisErr, data) => { | ||
if (redisErr) { return reject(redisErr); } | ||
if (data && data.access) { | ||
if (data.access === 'true') { | ||
return resolve(new AuthUser(key, data)); | ||
} else { | ||
return reject(new HttpError(`Bad credentials for user "${key}"`, 401)); | ||
} | ||
} | ||
const query = { | ||
[`apps.key.${API_ENV}`]: key, | ||
'apps.active': true, | ||
}; | ||
const opts = { | ||
fields: { | ||
provider: true, | ||
apps: true, | ||
}, | ||
}; | ||
return mongo.api.users.findOne(query, opts, (mongoErr, doc) => { | ||
if (mongoErr) { return reject(mongoErr); } | ||
if (!doc) { | ||
const expireat = module.exports.expireat(CACHE_INVALID); | ||
redis.hset(AuthUser.getCacheKey(key), 'access', 'false'); | ||
redis.expireat(AuthUser.getCacheKey(key), expireat); | ||
return reject(new HttpError(`Bad credentials for user "${key}"`, 401)); | ||
} | ||
const app = doc.apps.find(item => item.key[API_ENV] === key); | ||
const expireat = module.exports.expireat(CACHE_VALID); | ||
const user = new AuthUser(key, { | ||
provider: doc.provider, | ||
app: app.name, | ||
limit: app.limit[API_ENV], | ||
remaining: app.limit[API_ENV], | ||
reset: expireat, | ||
}); | ||
redis.hmset(AuthUser.getCacheKey(key), user.toObject()); | ||
redis.expireat(AuthUser.getCacheKey(key), expireat); | ||
return resolve(user); | ||
}); | ||
}); | ||
}); | ||
}; | ||
module.exports.expireat = function expireat(seconds) { | ||
return Math.floor((new Date().getTime() + seconds) / 1000); | ||
}; | ||
module.exports.middleware = module.exports(); | ||
module.exports.AbstractUser = AbstractUser; | ||
module.exports.AuthUser = AuthUser; | ||
module.exports.UnauthUser = UnauthUser; |
{ | ||
"name": "@turbasen/auth", | ||
"version": "2.1.0", | ||
"version": "3.0.0", | ||
"description": "Authentication middleware used internally at Nasjonal Turbase API", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
12763
8
263
1