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:
parent
cba3c29a9f
commit
afd1b6e2dd
8 changed files with 146 additions and 56 deletions
80
flow-typed/npm/jsonwebtoken_vx.x.x.js
vendored
Normal file
80
flow-typed/npm/jsonwebtoken_vx.x.x.js
vendored
Normal 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'>;
|
||||
}
|
|
@ -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');
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
'use strict';
|
||||
|
||||
const Handlebars = require('handlebars');
|
||||
const request = require('request');
|
||||
const _ = require('lodash');
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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
25
test/unit/auth.spec.js
Normal 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);
|
||||
});
|
||||
|
||||
});
|
|
@ -24,7 +24,7 @@ const generateStorage = function(): IStorageHandler {
|
|||
|
||||
describe('StorageTest', () => {
|
||||
|
||||
jest.setTimeout(1000000);
|
||||
jest.setTimeout(10000);
|
||||
|
||||
beforeAll((done)=> {
|
||||
const storage: IStorageHandler = generateStorage();
|
||||
|
|
Loading…
Add table
Reference in a new issue