mirror of
https://github.com/wassname/talk.git
synced 2026-08-07 11:29:44 +08:00
added tests, fixed some services
This commit is contained in:
@@ -12,6 +12,7 @@ program
|
||||
.command('assets', 'interact with assets')
|
||||
.command('setup', 'setup the application')
|
||||
.command('jobs', 'work with the job queues')
|
||||
.command('token', 'work with the access tokens')
|
||||
.command('users', 'work with the application auth')
|
||||
.command('migration', 'provides utilities for migrating the database')
|
||||
.command('plugins', 'provides utilities for interacting with the plugin system')
|
||||
|
||||
Regular → Executable
+2
@@ -49,6 +49,8 @@ async function revokeToken(tokenID) {
|
||||
|
||||
await TokensService.revoke(null, tokenID);
|
||||
|
||||
console.log(`Revoked Token[${tokenID}]`);
|
||||
|
||||
util.shutdown();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
+16
-22
@@ -1,6 +1,7 @@
|
||||
const passport = require('passport');
|
||||
const UsersService = require('./users');
|
||||
const SettingsService = require('./settings');
|
||||
const TokensService = require('./tokens');
|
||||
const fetch = require('node-fetch');
|
||||
const FormData = require('form-data');
|
||||
const JWT = require('jsonwebtoken');
|
||||
@@ -34,23 +35,6 @@ const GenerateToken = (user) => JWT.sign({}, JWT_SECRET, {
|
||||
audience: JWT_AUDIENCE
|
||||
});
|
||||
|
||||
// GeneratePersonalAccessToken will sign a token to include all the
|
||||
// authorization information needed for the front end for headless access.
|
||||
const GeneratePersonalAccessToken = (userID) => {
|
||||
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, {});
|
||||
|
||||
return {payload, jwt};
|
||||
};
|
||||
|
||||
// SetTokenForSafari sends the token in a cookie for Safari clients.
|
||||
const SetTokenForSafari = (req, res, token) => {
|
||||
const browser = bowser._detect(req.headers['user-agent']);
|
||||
@@ -174,10 +158,7 @@ const HandleLogout = (req, res, next) => {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the given token is already blacklisted, throw an error if it is.
|
||||
*/
|
||||
const CheckBlacklisted = (jwt) => new Promise((resolve, reject) => {
|
||||
const checkGeneralTokenBlacklist = (jwt) => new Promise((resolve, reject) => {
|
||||
client.get(`jtir[${jwt.jti}]`, (err, expiry) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
@@ -191,6 +172,20 @@ const CheckBlacklisted = (jwt) => new Promise((resolve, reject) => {
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if the given token is already blacklisted, throw an error if it is.
|
||||
*/
|
||||
const CheckBlacklisted = async (jwt) => {
|
||||
|
||||
// Check to see if this is a PAT.
|
||||
if (jwt.pat) {
|
||||
return TokensService.validate(jwt.sub, jwt.jti);
|
||||
}
|
||||
|
||||
// It wasn't a PAT! Check to see if it is valid anyways.
|
||||
return checkGeneralTokenBlacklist(jwt);
|
||||
};
|
||||
|
||||
const jwt = require('jsonwebtoken');
|
||||
const JwtStrategy = require('passport-jwt').Strategy;
|
||||
const ExtractJwt = require('passport-jwt').ExtractJwt;
|
||||
@@ -491,6 +486,5 @@ module.exports = {
|
||||
HandleAuthPopupCallback,
|
||||
HandleGenerateCredentials,
|
||||
HandleLogout,
|
||||
GeneratePersonalAccessToken,
|
||||
CheckBlacklisted
|
||||
};
|
||||
|
||||
+47
-2
@@ -1,5 +1,13 @@
|
||||
const errors = require('../errors');
|
||||
const UserModel = require('../models/user');
|
||||
const {GeneratePersonalAccessToken} = require('./passport');
|
||||
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
|
||||
@@ -16,7 +24,16 @@ module.exports = class TokenService {
|
||||
static async create(userID, tokenName) {
|
||||
|
||||
// Create the token.
|
||||
let {payload, jwt} = GeneratePersonalAccessToken(userID);
|
||||
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 = {
|
||||
@@ -63,6 +80,34 @@ module.exports = class TokenService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
const TokensService = require('../../../services/tokens');
|
||||
const UsersService = require('../../../services/users');
|
||||
const SettingsService = require('../../../services/settings');
|
||||
|
||||
const chai = require('chai');
|
||||
const chaiAsPromised = require('chai-as-promised');
|
||||
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
const expect = chai.expect;
|
||||
|
||||
describe('services.TokensService', () => {
|
||||
|
||||
let user;
|
||||
beforeEach(async () => {
|
||||
await SettingsService.init();
|
||||
user = await UsersService.createLocalUser('sockmonster@gmail.com', '2Coral!!', 'Sockmonster');
|
||||
});
|
||||
|
||||
describe('#create', () => {
|
||||
|
||||
it('can create the token without error', async () => {
|
||||
let token = await TokensService.create(user.id, 'Github Token');
|
||||
expect(token).to.be.an.object;
|
||||
expect(token.jwt).to.be.a.string;
|
||||
expect(token.pat).to.be.an.object;
|
||||
|
||||
let pat = token.pat;
|
||||
|
||||
let tokens = await TokensService.list(user.id);
|
||||
expect(tokens).to.have.length(1);
|
||||
expect(tokens[0]).to.have.property('id', pat.id);
|
||||
expect(tokens[0]).to.have.property('name', pat.name);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#revoke', () => {
|
||||
|
||||
it('can revoke a token', async () => {
|
||||
let {pat: {id}} = await TokensService.create(user.id, 'Github Token');
|
||||
|
||||
let tokens = await TokensService.list(user.id);
|
||||
expect(tokens).to.have.length(1);
|
||||
expect(tokens[0]).to.have.property('id', id);
|
||||
expect(tokens[0]).to.have.property('active', true);
|
||||
|
||||
await TokensService.revoke(user.id, id);
|
||||
|
||||
tokens = await TokensService.list(user.id);
|
||||
expect(tokens).to.have.length(1);
|
||||
expect(tokens[0]).to.have.property('id', id);
|
||||
expect(tokens[0]).to.have.property('active', false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#validate', () => {
|
||||
|
||||
it('will allow a valid token', async () => {
|
||||
|
||||
// Create a token.
|
||||
let {pat: {id}} = await TokensService.create(user.id, 'Github Token');
|
||||
|
||||
// Validate it.
|
||||
await TokensService.validate(user.id, id);
|
||||
});
|
||||
|
||||
it('will not allow an invalid token', async () => {
|
||||
|
||||
// Create a token.
|
||||
let {pat: {id}} = await TokensService.create(user.id, 'Github Token');
|
||||
|
||||
// Revoke it.
|
||||
await TokensService.revoke(user.id, id);
|
||||
|
||||
// Validate it.
|
||||
return TokensService.validate(user.id, id).should.eventually.be.rejected;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#list', () => {
|
||||
|
||||
it('lists the tokens for a user', async () => {
|
||||
|
||||
let tokens = await TokensService.list(user.id);
|
||||
expect(tokens).to.have.length(0);
|
||||
|
||||
// Create a token.
|
||||
let {pat: {id}} = await TokensService.create(user.id, 'Github Token');
|
||||
|
||||
tokens = await TokensService.list(user.id);
|
||||
expect(tokens).to.have.length(1);
|
||||
expect(tokens[0]).to.have.property('id', id);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user