0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2025-03-11 02:15:57 -05:00

test: refactor and add small test for auth class

This commit is contained in:
Juan Picado @jotadeveloper 2018-02-24 07:59:36 +01:00
parent cba3c29a9f
commit afd1b6e2dd
No known key found for this signature in database
GPG key ID: 18AC54485952D158
8 changed files with 146 additions and 56 deletions

80
flow-typed/npm/jsonwebtoken_vx.x.x.js vendored Normal file
View file

@ -0,0 +1,80 @@
// flow-typed signature: 4ec026fce9b8a945dbac93217027085d
// flow-typed version: <<STUB>>/jsonwebtoken_v8.1.1/flow_v0.64.0
/**
* This is an autogenerated libdef stub for:
*
* 'jsonwebtoken'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/
declare module 'jsonwebtoken' {
declare module.exports: any;
}
/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module 'jsonwebtoken/decode' {
declare module.exports: any;
}
declare module 'jsonwebtoken/lib/JsonWebTokenError' {
declare module.exports: any;
}
declare module 'jsonwebtoken/lib/NotBeforeError' {
declare module.exports: any;
}
declare module 'jsonwebtoken/lib/timespan' {
declare module.exports: any;
}
declare module 'jsonwebtoken/lib/TokenExpiredError' {
declare module.exports: any;
}
declare module 'jsonwebtoken/sign' {
declare module.exports: any;
}
declare module 'jsonwebtoken/verify' {
declare module.exports: any;
}
// Filename aliases
declare module 'jsonwebtoken/decode.js' {
declare module.exports: $Exports<'jsonwebtoken/decode'>;
}
declare module 'jsonwebtoken/index' {
declare module.exports: $Exports<'jsonwebtoken'>;
}
declare module 'jsonwebtoken/index.js' {
declare module.exports: $Exports<'jsonwebtoken'>;
}
declare module 'jsonwebtoken/lib/JsonWebTokenError.js' {
declare module.exports: $Exports<'jsonwebtoken/lib/JsonWebTokenError'>;
}
declare module 'jsonwebtoken/lib/NotBeforeError.js' {
declare module.exports: $Exports<'jsonwebtoken/lib/NotBeforeError'>;
}
declare module 'jsonwebtoken/lib/timespan.js' {
declare module.exports: $Exports<'jsonwebtoken/lib/timespan'>;
}
declare module 'jsonwebtoken/lib/TokenExpiredError.js' {
declare module.exports: $Exports<'jsonwebtoken/lib/TokenExpiredError'>;
}
declare module 'jsonwebtoken/sign.js' {
declare module.exports: $Exports<'jsonwebtoken/sign'>;
}
declare module 'jsonwebtoken/verify.js' {
declare module.exports: $Exports<'jsonwebtoken/verify'>;
}

View file

@ -6,8 +6,8 @@ import cors from 'cors';
import Storage from '../lib/storage';
import {loadPlugin} from '../lib/plugin-loader';
import hookDebug from './debug';
import Auth from '../lib/auth';
const Auth = require('../lib/auth');
const Logger = require('../lib/logger');
const Config = require('../lib/config');
const Middleware = require('./web/middleware');

View file

@ -1,41 +1,41 @@
/* eslint prefer-spread: "off" */
/* eslint prefer-rest-params: "off" */
import {loadPlugin} from '../lib/plugin-loader';
const Crypto = require('crypto');
import Crypto from 'crypto';
import jwt from 'jsonwebtoken';
import {ErrorCode} from './utils';
const Error = require('http-errors');
const Logger = require('./logger');
const jwt = require('jsonwebtoken');
import type {Config, Logger, Callback} from '@verdaccio/types';
const LoggerApi = require('./logger');
/**
* Handles the authentification, load auth plugins.
*/
class Auth {
config: Config;
logger: Logger;
secret: string;
plugins: Array<any>;
/**
* @param {*} config config reference
*/
constructor(config) {
constructor(config: Config) {
this.config = config;
this.logger = Logger.logger.child({sub: 'auth'});
this.logger = LoggerApi.logger.child({sub: 'auth'});
this.secret = config.secret;
this.plugins = this._loadPlugin(config);
this._applyDefaultPlugins();
}
_loadPlugin(config: Config) {
const plugin_params = {
config: config,
config,
logger: this.logger,
};
if (config.users_file) {
if (!config.auth || !config.auth.htpasswd) {
// b/w compat
config.auth = config.auth || {};
config.auth.htpasswd = {file: config.users_file};
}
}
this.plugins = loadPlugin(config, config.auth, plugin_params, function(p) {
return loadPlugin(config, config.auth, plugin_params, function(p) {
return p.authenticate || p.allow_access || p.allow_publish;
});
}
_applyDefaultPlugins() {
const allow_action = function(action) {
return function(user, pkg, cb) {
let ok = pkg[action].reduce(function(prev, curr) {
@ -46,20 +46,20 @@ class Auth {
if (ok) return cb(null, true);
if (user.name) {
cb( Error[403]('user ' + user.name + ' is not allowed to ' + action + ' package ' + pkg.name) );
cb(ErrorCode.get403('user ' + user.name + ' is not allowed to ' + action + ' package ' + pkg.name));
} else {
cb( Error[403]('unregistered users are not allowed to ' + action + ' package ' + pkg.name) );
cb(ErrorCode.get403('unregistered users are not allowed to ' + action + ' package ' + pkg.name));
}
};
};
this.plugins.push({
authenticate: function(user, password, cb) {
return cb( Error[403]('bad username/password, access denied') );
cb(ErrorCode.get403('bad username/password, access denied'));
},
add_user: function(user, password, cb) {
return cb( Error[409]('registration is disabled') );
return cb(ErrorCode.get409('bad username/password, access denied'));
},
allow_access: allow_action('access'),
@ -67,13 +67,7 @@ class Auth {
});
}
/**
* Authenticate an user.
* @param {*} user
* @param {*} password
* @param {*} cb
*/
authenticate(user, password, cb) {
authenticate(user: string, password: string, cb: Callback) {
const plugins = this.plugins.slice(0)
;(function next() {
let p = plugins.shift();
@ -94,13 +88,7 @@ class Auth {
})();
}
/**
* Add a new user.
* @param {*} user
* @param {*} password
* @param {*} cb
*/
add_user(user, password, cb) {
add_user(user: string, password: string, cb: Callback) {
let self = this;
let plugins = this.plugins.slice(0)
@ -222,7 +210,7 @@ class Auth {
let parts = authorization.split(' ');
if (parts.length !== 2) {
return next( Error[400]('bad authorization header') );
return next( ErrorCode.get400('bad authorization header') );
}
const scheme = parts[0];
@ -267,6 +255,8 @@ class Auth {
req.pause();
const next = function(_err) {
req.resume();
/* eslint prefer-spread: "off" */
/* eslint prefer-rest-params: "off" */
return _next.apply(null, arguments);
};
@ -283,7 +273,7 @@ class Auth {
let parts = authorization.split(' ');
if (parts.length !== 2) {
return next( Error[400]('bad authorization header') );
return next( ErrorCode.get400('bad authorization header') );
}
let scheme = parts[0];
@ -343,7 +333,7 @@ class Auth {
* @param {string} expire_time
* @return {string}
*/
issue_token(user, expire_time) {
issue_token(user: any, expire_time: string) {
return jwt.sign(
{
user: user.name,
@ -362,7 +352,7 @@ class Auth {
* @param {*} token
* @return {Object}
*/
decode_token(token) {
decode_token(token: string) {
let decoded;
try {
decoded = jwt.verify(token, this.secret);
@ -430,4 +420,4 @@ function authenticatedUser(name, groups) {
};
}
module.exports = Auth;
export default Auth;

View file

@ -1,5 +1,3 @@
'use strict';
const Handlebars = require('handlebars');
const request = require('request');
const _ = require('lodash');

View file

@ -1,7 +1,3 @@
/* eslint prefer-rest-params: "off" */
'use strict';
// see https://secure.flickr.com/photos/girliemac/sets/72157628409467125
const images = {
@ -69,6 +65,7 @@ module.exports.middleware = function(req, res, next) {
if (status in images) {
res.setHeader('X-Status-Cat', module.exports.get_image(status));
}
/* eslint prefer-rest-params: "off" */
_writeHead.apply(res, arguments);
};

View file

@ -327,8 +327,8 @@ const getLatestVersion = function(pkgInfo) {
};
const ErrorCode = {
get409: () => {
return createError(409, 'this package is already present');
get409: (message = 'this package is already present') => {
return createError(409, message);
},
get422: (customMessage) => {
return createError(422, customMessage || 'bad data');
@ -339,8 +339,8 @@ const ErrorCode = {
get500: (customMessage) => {
return customMessage ? createError(500, customMessage) : createError(500);
},
get403: () => {
return createError(403, 'can\'t use this filename');
get403: (message = 'can\'t use this filename') => {
return createError(403, message);
},
get503: () => {
return createError(500, 'resource temporarily unavailable');

25
test/unit/auth.spec.js Normal file
View file

@ -0,0 +1,25 @@
// @flow
import Auth from '../../src/lib/auth';
jest.mock('../../src/lib/auth');
// $FlowFixMe
import configExample from './partials/config';
import AppConfig from '../../src/lib/config';
import {setup} from '../../src/lib/logger';
import type {IAuth, Config} from '@verdaccio/types';
setup(configExample.logs);
describe('AuthTest', () => {
test('should be defined', () => {
const config: Config = new AppConfig(configExample);
const auth: IAuth = new Auth(config);
expect(auth).toBeDefined();
expect(Auth).toHaveBeenCalledTimes(1);
});
});

View file

@ -24,7 +24,7 @@ const generateStorage = function(): IStorageHandler {
describe('StorageTest', () => {
jest.setTimeout(1000000);
jest.setTimeout(10000);
beforeAll((done)=> {
const storage: IStorageHandler = generateStorage();