Files
talk/services/tokens.js
T
2017-06-19 08:55:08 -06:00

128 lines
2.8 KiB
JavaScript

const errors = require('../errors');
const UserModel = require('../models/user');
const JWT = require('jsonwebtoken');
const uuid = require('uuid');
const {
JWT_SECRET,
JWT_ISSUER,
JWT_AUDIENCE
} = require('../config');
/**
* TokenService manages Personal Access Tokens for users. These tokens are
* persisted in the database and attached to the user.
*/
module.exports = class TokenService {
/**
* Creates a token for a user with a given name.
*
* @param {String} userID the id of the user owning the token
* @param {String} tokenName the name of the token to be created
*/
static async create(userID, tokenName) {
// Create the token.
const payload = {
jti: uuid.v4(),
iss: JWT_ISSUER,
aud: JWT_AUDIENCE,
sub: userID,
pat: true
};
// Sign the payload.
const jwt = JWT.sign(payload, JWT_SECRET, {});
// Create the PAT.
let pat = {
id: payload.jti,
name: tokenName,
active: true
};
// Wait to update the user model with the new PAT.
await UserModel.update({id: userID}, {
$push: {
tokens: pat
}
});
return {payload, jwt, pat};
}
/**
* Revokes a token and prevents the token from being used. Once a token has
* been revoked, it cannot be re-enabled.
*
* @param {String} userID the id of the user owning the token
* @param {String} tokenID the jti of the token to revoke
*/
static async revoke(userID, tokenID) {
let query = {
tokens: {
$elemMatch: {
id: tokenID
}
}
};
if (userID) {
query.id = userID;
}
// Revoke the token id.
await UserModel.update(query, {
$set: {
'tokens.$.active': false
}
});
}
/**
* Validate that a given Token is valid.
*
* @param {String} userID the user's id that owns the token
* @param {String} tokenID the id of the token
*/
static async validate(userID, tokenID) {
// Find the user.
let user = await UserModel.findOne({
id: userID
}).select('tokens');
if (!user || !user.tokens) {
throw new errors.ErrAuthentication('user does not exist');
}
// Extract the token from the user.
let token = user.tokens.find(({id}) => id === tokenID);
if (!token) {
throw new errors.ErrAuthentication('token does not exist');
}
// Check to see if it is active.
if (!token.active) {
throw new errors.ErrAuthentication('token is not active');
}
}
/**
* Lists the tokens owned by the user.
*
* @param {String} userID the id of the user owning the token
*/
static async list(userID) {
// Get the user specified by the id.
let user = await UserModel.findOne({id: userID}).select('tokens');
if (!user || !user.tokens) {
return [];
}
return user.tokens;
}
};