nginx-proxy-manager/backend/models/token.js
Jamie Curnow 2a07445005
Refactor configuration
- No longer use config npm package
- Prefer config from env vars, though still has support for config file
- No longer writes a config file for database config
- Writes keys to a new file in /data folder
- Removes a lot of cruft and improves config understanding
2023-03-21 16:53:39 +10:00

140 lines
3.0 KiB
JavaScript

/**
NOTE: This is not a database table, this is a model of a Token object that can be created/loaded
and then has abilities after that.
*/
const _ = require('lodash');
const jwt = require('jsonwebtoken');
const crypto = require('crypto');
const config = require('../lib/config');
const error = require('../lib/error');
const logger = require('../logger').global;
const ALGO = 'RS256';
module.exports = function () {
let token_data = {};
const self = {
/**
* @param {Object} payload
* @returns {Promise}
*/
create: (payload) => {
if (!config.getPrivateKey()) {
logger.error('Private key is empty!')
}
// sign with RSA SHA256
const options = {
algorithm: ALGO,
expiresIn: payload.expiresIn || '1d'
};
payload.jti = crypto.randomBytes(12)
.toString('base64')
.substring(-8);
return new Promise((resolve, reject) => {
jwt.sign(payload, config.getPrivateKey(), options, (err, token) => {
if (err) {
reject(err);
} else {
token_data = payload;
resolve({
token: token,
payload: payload
});
}
});
});
},
/**
* @param {String} token
* @returns {Promise}
*/
load: function (token) {
if (!config.getPublicKey()) {
logger.error('Public key is empty!')
}
return new Promise((resolve, reject) => {
try {
if (!token || token === null || token === 'null') {
reject(new error.AuthError('Empty token'));
} else {
jwt.verify(token, config.getPublicKey(), {ignoreExpiration: false, algorithms: [ALGO]}, (err, result) => {
if (err) {
if (err.name === 'TokenExpiredError') {
reject(new error.AuthError('Token has expired', err));
} else {
reject(err);
}
} else {
token_data = result;
// Hack: some tokens out in the wild have a scope of 'all' instead of 'user'.
// For 30 days at least, we need to replace 'all' with user.
if ((typeof token_data.scope !== 'undefined' && _.indexOf(token_data.scope, 'all') !== -1)) {
token_data.scope = ['user'];
}
resolve(token_data);
}
});
}
} catch (err) {
reject(err);
}
});
},
/**
* Does the token have the specified scope?
*
* @param {String} scope
* @returns {Boolean}
*/
hasScope: function (scope) {
return typeof token_data.scope !== 'undefined' && _.indexOf(token_data.scope, scope) !== -1;
},
/**
* @param {String} key
* @return {*}
*/
get: function (key) {
if (typeof token_data[key] !== 'undefined') {
return token_data[key];
}
return null;
},
/**
* @param {String} key
* @param {*} value
*/
set: function (key, value) {
token_data[key] = value;
},
/**
* @param [default_value]
* @returns {Integer}
*/
getUserId: (default_value) => {
const attrs = self.get('attrs');
if (attrs && typeof attrs.id !== 'undefined' && attrs.id) {
return attrs.id;
}
return default_value || 0;
}
};
return self;
};