refactor: utilities and auth

This commit is contained in:
Juan Picado @jotadeveloper 2020-03-08 09:19:12 +01:00 committed by Juan Picado
parent 7739e6f4a2
commit 463888165d
17 changed files with 412 additions and 120 deletions

View File

@ -37,7 +37,7 @@
},
"devDependencies": {
"@verdaccio/dev-types": "5.0.0-alpha.0",
"@verdaccio/types": "^9.0.0"
"@verdaccio/types": "^9.3.0"
},
"gitHead": "7c246ede52ff717707fcae66dd63fc4abd536982"
}

View File

@ -7,7 +7,6 @@ import { loadPlugin } from '@verdaccio/loaders';
import { aesEncrypt, signPayload } from '@verdaccio/utils';
import {
getDefaultPlugins,
getMiddlewareCredentials,
verifyJWTPayload,
createAnonymousRemoteUser,
isAuthHeaderValid,
@ -23,6 +22,7 @@ import {
import { getMatchedPackagesSpec } from '@verdaccio/utils';
import { Config, Logger, Callback, IPluginAuth, RemoteUser, JWTSignOptions, Security, AuthPluginPackage, AllowAccess, PackageAccess } from '@verdaccio/types';
import { $RequestExtend, $ResponseExtend, IAuth, AESPayload } from '@verdaccio/dev-types';
import {getMiddlewareCredentials} from "./utils";
/* eslint-disable @typescript-eslint/no-var-requires */
const LoggerApi = require('@verdaccio/logger');

View File

@ -1 +1,2 @@
export { Auth } from './auth'
export * from './utils';

View File

@ -0,0 +1,32 @@
import {Security} from "@verdaccio/types";
import {AuthMiddlewarePayload} from "@verdaccio/dev-types";
import _ from "lodash";
import {TOKEN_BEARER} from "@verdaccio/dev-commons";
import {
isAESLegacy,
parseAESCredentials,
parseAuthTokenHeader,
parseBasicPayload,
verifyJWTPayload
} from "@verdaccio/utils";
export function getMiddlewareCredentials(security: Security, secret: string, authorizationHeader: string): AuthMiddlewarePayload {
if (isAESLegacy(security)) {
const credentials = parseAESCredentials(authorizationHeader, secret);
if (!credentials) {
return;
}
const parsedCredentials = parseBasicPayload(credentials);
if (!parsedCredentials) {
return;
}
return parsedCredentials;
}
const { scheme, token } = parseAuthTokenHeader(authorizationHeader);
if (_.isString(token) && scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {
return verifyJWTPayload(token, secret);
}
}

View File

@ -10,12 +10,16 @@ import {
buildUserBuffer,
getApiToken,
getAuthenticatedMessage,
getMiddlewareCredentials,
getSecurity,
aesDecrypt, verifyPayload,
buildToken, convertPayloadToBase64, parseConfigFile
aesDecrypt,
verifyPayload,
buildToken,
convertPayloadToBase64,
parseConfigFile
} from '@verdaccio/utils';
import { getMiddlewareCredentials } from '../src'
import { IAuth } from '@verdaccio/dev-types';
import {Config, Security, RemoteUser} from '@verdaccio/types';
import path from "path";

View File

@ -0,0 +1,54 @@
import { Package } from "@verdaccio/types";
export function generatePackageMetadata(pkgName: string, version = '1.0.0'): Package {
// @ts-ignore
return {
"_id": pkgName,
"name": pkgName,
"dist-tags": {
"latest": version
},
"versions": {
[version]: {
"name": pkgName,
"version": version,
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
],
"author": {
"name": "User NPM",
"email": "user@domain.com"
},
"license": "ISC",
"dependencies": {
"verdaccio": "^2.7.2"
},
"readme": "# test",
"readmeFilename": "README.md",
"_id": `${pkgName}@${version}`,
"_npmVersion": "5.5.1",
"_npmUser": {
'name': 'foo',
},
"dist": {
"integrity": "sha512-6gHiERpiDgtb3hjqpQH5\/i7zRmvYi9pmCjQf2ZMy3QEa9wVk9RgdZaPWUt7ZOnWUPFjcr9cmE6dUBf+XoPoH4g==",
"shasum": "2c03764f651a9f016ca0b7620421457b619151b9", // pragma: allowlist secret
"tarball": `http:\/\/localhost:5555\/${pkgName}\/-\/${pkgName}-${version}.tgz`
}
}
},
"readme": "# test",
"_attachments": {
[`${pkgName}-${version}.tgz`]: {
"content_type": "application\/octet-stream",
"data": "H4sIAAAAAAAAE+2W32vbMBDH85y\/QnjQp9qxLEeBMsbGlocNBmN7bFdQ5WuqxJaEpGQdo\/\/79KPeQsnIw5KUDX\/9IOvurLuz\/DHSjK\/YAiY6jcXSKjk6sMqypHWNdtmD6hlBI0wqQmo8nVbVqMR4OsNoVB66kF1aW8eML+Vv10m9oF\/jP6IfY4QyyTrILlD2eqkcm+gVzpdrJrPz4NuAsULJ4MZFWdBkbcByI7R79CRjx0ScCdnAvf+SkjUFWu8IubzBgXUhDPidQlfZ3BhlLpBUKDiQ1cDFrYDmKkNnZwjuhUM4808+xNVW8P2bMk1Y7vJrtLC1u1MmLPjBF40+Cc4ahV6GDmI\/DWygVRpMwVX3KtXUCg7Sxp7ff3nbt6TBFy65gK1iffsN41yoEHtdFbOiisWMH8bPvXUH0SP3k+KG3UBr+DFy7OGfEJr4x5iWVeS\/pLQe+D+FIv\/agIWI6GX66kFuIhT+1gDjrp\/4d7WAvAwEJPh0u14IufWkM0zaW2W6nLfM2lybgJ4LTJ0\/jWiAK8OcMjt8MW3OlfQppcuhhQ6k+2OgkK2Q8DssFPi\/IHpU9fz3\/+xj5NjDf8QFE39VmE4JDfzPCBn4P4X6\/f88f\/Pu47zomiPk2Lv\/dOv8h+P\/34\/D\/p9CL+Kp67mrGDRo0KBBp9ZPsETQegASAAA=",
"length": 512
}
}
}
}

View File

@ -1 +1,2 @@
export * from './constants';
export * from './helpers/pkg';

View File

@ -22,7 +22,7 @@
},
"devDependencies": {
"@verdaccio/dev-commons": "5.0.0-alpha.0",
"@verdaccio/types": "^8.5.2"
"@verdaccio/types": "^9.3.0"
},
"scripts": {
"clean": "rimraf ./build",

View File

@ -7,7 +7,7 @@ import {parseConfigFile} from '@verdaccio/utils';
/**
* Override the default.yaml configuration file with any new config provided.
*/
function configExample(externalConfig, configFile: string = 'default.yaml', location: string) {
function configExample(externalConfig, configFile: string = 'default.yaml', location: string = '') {
const locationFile = location ? path.join(location, configFile) :
path.join(__dirname, `./config/yaml/${configFile}`);
const config = parseConfigFile(locationFile);

View File

@ -1,14 +1,12 @@
import path from 'path';
import _ from 'lodash';
import selfsigned from 'selfsigned';
import os from 'os';
import fs from 'fs';
import { configExample } from '@verdaccio/mock';
import {DEFAULT_DOMAIN, DEFAULT_PORT, DEFAULT_PROTOCOL} from '@verdaccio/dev-commons';
import {DEFAULT_DOMAIN, DEFAULT_PROTOCOL} from '@verdaccio/dev-commons';
import {parseConfigFile} from '@verdaccio/utils';
import { getListListenAddresses } from '../src/cli-utils';
import { logger } from '@verdaccio/logger';
import { startVerdaccio } from '../src';
@ -181,66 +179,4 @@ describe('startServer via API', () => {
});
});
describe('getListListenAddresses test', () => {
test('should return no address if a single address is wrong', () => {
// @ts-ignore
const addrs = getListListenAddresses("wrong");
expect(_.isArray(addrs)).toBeTruthy();
expect(addrs).toHaveLength(0);
});
test('should return no address if a two address are wrong', () => {
// @ts-ignore
const addrs = getListListenAddresses(["wrong", "same-wrong"]);
expect(_.isArray(addrs)).toBeTruthy();
expect(addrs).toHaveLength(0);
});
test('should return a list of 1 address provided', () => {
// @ts-ignore
const addrs = getListListenAddresses(null, '1000');
expect(_.isArray(addrs)).toBeTruthy();
expect(addrs).toHaveLength(1);
});
test('should return a list of 2 address provided', () => {
// @ts-ignore
const addrs = getListListenAddresses(null, ['1000', '2000']);
expect(_.isArray(addrs)).toBeTruthy();
expect(addrs).toHaveLength(2);
});
test(`should return by default ${DEFAULT_PORT}`, () => {
// @ts-ignore
const [addrs] = getListListenAddresses();
// @ts-ignore
expect(addrs.proto).toBe(DEFAULT_PROTOCOL);
// @ts-ignore
expect(addrs.host).toBe(DEFAULT_DOMAIN);
// @ts-ignore
expect(addrs.port).toBe(DEFAULT_PORT);
});
test('should return default proto, host and custom port', () => {
const initPort = '1000';
// @ts-ignore
const [addrs] = getListListenAddresses(null, initPort);
// @ts-ignore
expect(addrs.proto).toEqual(DEFAULT_PROTOCOL);
// @ts-ignore
expect(addrs.host).toEqual(DEFAULT_DOMAIN);
// @ts-ignore
expect(addrs.port).toEqual(initPort);
});
});
});

View File

@ -0,0 +1,76 @@
import {getListListenAddresses} from "../src/cli-utils";
import _ from "lodash";
import {DEFAULT_DOMAIN, DEFAULT_PORT, DEFAULT_PROTOCOL} from "@verdaccio/dev-commons";
jest.mock('@verdaccio/logger', () => ({
setup: jest.fn(),
logger: {
child: jest.fn(),
debug: jest.fn(),
trace: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
fatal: jest.fn()
}
}));
describe('getListListenAddresses test', () => {
test('should return no address if a single address is wrong', () => {
// @ts-ignore
const addrs = getListListenAddresses("wrong");
expect(_.isArray(addrs)).toBeTruthy();
expect(addrs).toHaveLength(0);
});
test('should return no address if a two address are wrong', () => {
// @ts-ignore
const addrs = getListListenAddresses(["wrong", "same-wrong"]);
expect(_.isArray(addrs)).toBeTruthy();
expect(addrs).toHaveLength(0);
});
test('should return a list of 1 address provided', () => {
// @ts-ignore
const addrs = getListListenAddresses(null, '1000');
expect(_.isArray(addrs)).toBeTruthy();
expect(addrs).toHaveLength(1);
});
test('should return a list of 2 address provided', () => {
// @ts-ignore
const addrs = getListListenAddresses(null, ['1000', '2000']);
expect(_.isArray(addrs)).toBeTruthy();
expect(addrs).toHaveLength(2);
});
test(`should return by default ${DEFAULT_PORT}`, () => {
// @ts-ignore
const [addrs] = getListListenAddresses();
// @ts-ignore
expect(addrs.proto).toBe(DEFAULT_PROTOCOL);
// @ts-ignore
expect(addrs.host).toBe(DEFAULT_DOMAIN);
// @ts-ignore
expect(addrs.port).toBe(DEFAULT_PORT);
});
test('should return default proto, host and custom port', () => {
const initPort = '1000';
// @ts-ignore
const [addrs] = getListListenAddresses(null, initPort);
// @ts-ignore
expect(addrs.proto).toEqual(DEFAULT_PROTOCOL);
// @ts-ignore
expect(addrs.host).toEqual(DEFAULT_DOMAIN);
// @ts-ignore
expect(addrs.port).toEqual(initPort);
});
});

View File

@ -33,7 +33,7 @@
},
"devDependencies": {
"@verdaccio/dev-types": "5.0.0-alpha.0",
"@verdaccio/types": "^8.5.2"
"@verdaccio/types": "^9.3.0"
},
"gitHead": "7c246ede52ff717707fcae66dd63fc4abd536982"
}

View File

@ -1,8 +1,9 @@
import _ from 'lodash';
import { API_ERROR, HTTP_STATUS, ROLES, TIME_EXPIRATION_7D, TOKEN_BASIC, TOKEN_BEARER, DEFAULT_MIN_LIMIT_PASSWORD } from '@verdaccio/dev-commons';
import { CookieSessionToken, IAuthWebUI, AuthMiddlewarePayload, AuthTokenHeader, BasicPayload } from '@verdaccio/dev-types';
import { RemoteUser, Package, Callback, Config, Security, APITokenOptions, JWTOptions, IPluginAuth } from '@verdaccio/types';
import { CookieSessionToken, IAuthWebUI, AuthTokenHeader, BasicPayload } from '@verdaccio/dev-types';
import { RemoteUser, AllowAccess, PackageAccess, Callback, Config, Security, APITokenOptions, JWTOptions, IPluginAuth } from '@verdaccio/types';
import { VerdaccioError } from '@verdaccio/commons-api';
import { convertPayloadToBase64, ErrorCode } from './utils';
import { aesDecrypt, verifyPayload } from './crypto-utils';
@ -13,13 +14,28 @@ export function validatePassword(password: string, minLength: number = DEFAULT_M
return typeof password === 'string' && password.length >= minLength;
}
/**
* All logged users will have by default the group $all and $authenticate
*/
export const defaultLoggedUserRoles = [ROLES.$ALL, ROLES.$AUTH, ROLES.DEPRECATED_ALL, ROLES.DEPRECATED_AUTH, ROLES.ALL];
/**
*
*/
export const defaultNonLoggedUserRoles = [
ROLES.$ALL,
ROLES.$ANONYMOUS,
// groups without '$' are going to be deprecated eventually
ROLES.DEPRECATED_ALL,
ROLES.DEPRECATED_ANONYMOUS
];
/**
* Create a RemoteUser object
* @return {Object} { name: xx, pluginGroups: [], real_groups: [] }
*/
export function createRemoteUser(name: string, pluginGroups: string[]): RemoteUser {
const isGroupValid: boolean = Array.isArray(pluginGroups);
const groups = (isGroupValid ? pluginGroups : []).concat([ROLES.$ALL, ROLES.$AUTH, ROLES.DEPRECATED_ALL, ROLES.DEPRECATED_AUTH, ROLES.ALL]);
const groups = (isGroupValid ? pluginGroups : []).concat([...defaultLoggedUserRoles]);
return {
name,
@ -35,17 +51,26 @@ export function createRemoteUser(name: string, pluginGroups: string[]): RemoteUs
export function createAnonymousRemoteUser(): RemoteUser {
return {
name: undefined,
// groups without '$' are going to be deprecated eventually
groups: [ROLES.$ALL, ROLES.$ANONYMOUS, ROLES.DEPRECATED_ALL, ROLES.DEPRECATED_ANONYMOUS],
groups: [...defaultNonLoggedUserRoles],
real_groups: [],
};
}
export function allow_action(action: string): Function {
return function(user: RemoteUser, pkg: Package, callback: Callback): void {
export type AllowActionCallbackResponse = boolean | undefined;
export type AllowActionCallback = (error: VerdaccioError | null, allowed?: AllowActionCallbackResponse) => void;
export type AllowAction = (user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback) => void;
export interface AuthPackageAllow extends PackageAccess, AllowAccess {
// TODO: this should be on @verdaccio/types
unpublish: boolean | string[];
}
export type ActionsAllowed = 'publish' | 'unpublish' | 'access';
export function allow_action(action: ActionsAllowed): AllowAction {
return function allowActionCallback(user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback): void {
logger.trace({remote: user.name}, `[auth/allow_action]: user: @{user.name}`);
const { name, groups } = user;
const groupAccess = pkg[action];
const groupAccess = pkg[action] as string[];
const hasPermission = groupAccess.some(group => name === group || groups.includes(group));
logger.trace({pkgName: pkg.name, hasPermission, remote: user.name, groupAccess}, `[auth/allow_action]: hasPermission? @{hasPermission} for user: @{user}`);
@ -66,11 +91,11 @@ export function allow_action(action: string): Function {
*
*/
export function handleSpecialUnpublish(): any {
return function(user: RemoteUser, pkg: Package, callback: Callback): void {
return function(user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback): void {
const action = 'unpublish';
// verify whether the unpublish prop has been defined
const isUnpublishMissing: boolean = _.isNil(pkg[action]);
const hasGroups: boolean = isUnpublishMissing ? false : pkg[action].length > 0;
const hasGroups: boolean = isUnpublishMissing ? false : ((pkg[action]) as string[]).length > 0;
logger.trace({user: user.name, name: pkg.name, hasGroups}, `fallback unpublish for @{name} has groups: @{hasGroups} for @{user}`);
if (isUnpublishMissing || hasGroups === false) {
@ -88,7 +113,7 @@ export function getDefaultPlugins(): IPluginAuth<Config> {
cb(ErrorCode.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
},
add_user(user: string, password: string, cb: Callback): void {
adduser(user: string, password: string, cb: Callback): void {
return cb(ErrorCode.getConflict(API_ERROR.BAD_USERNAME_PASSWORD));
},
@ -227,24 +252,3 @@ export function verifyJWTPayload(token: string, secret: string): RemoteUser {
export function isAuthHeaderValid(authorization: string): boolean {
return authorization.split(' ').length === 2;
}
export function getMiddlewareCredentials(security: Security, secret: string, authorizationHeader: string): AuthMiddlewarePayload {
if (isAESLegacy(security)) {
const credentials = parseAESCredentials(authorizationHeader, secret);
if (!credentials) {
return;
}
const parsedCredentials = parseBasicPayload(credentials);
if (!parsedCredentials) {
return;
}
return parsedCredentials;
}
const { scheme, token } = parseAuthTokenHeader(authorizationHeader);
if (_.isString(token) && scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {
return verifyJWTPayload(token, secret);
}
}

View File

@ -42,25 +42,31 @@ export function createTarballHash(): Hash {
* @return {String}
*/
export function stringToMD5(data: Buffer | string): string {
return createHash('md5').update(data).digest('hex');
return createHash('md5')
.update(data)
.digest('hex');
}
export function generateRandomHexString(length = 8): string {
return pseudoRandomBytes(length).toString('hex');
}
export async function signPayload(
payload: RemoteUser,
secretOrPrivateKey: string,
options: JWTSignOptions
): Promise<string> {
/**
* Sign the payload and return JWT
* https://github.com/auth0/node-jsonwebtoken#jwtsignpayload-secretorprivatekey-options-callback
* @param payload
* @param secretOrPrivateKey
* @param options
*/
export async function signPayload(payload: RemoteUser, secretOrPrivateKey: string, options: JWTSignOptions = {}): Promise<string> {
return new Promise(function(resolve, reject): Promise<string> {
return jwt.sign(
payload,
secretOrPrivateKey,
{
// 1 === 1ms (one millisecond)
notBefore: '1', // Make sure the time will not rollback :)
...options
...options,
},
(error, token) => (error ? reject(error) : resolve(token))
);

View File

@ -0,0 +1,183 @@
import {
allow_action,
createAnonymousRemoteUser,
createRemoteUser,
validatePassword,
ActionsAllowed,
AllowActionCallbackResponse,
getDefaultPlugins,
createSessionToken,
getAuthenticatedMessage,
verifyJWTPayload, defaultNonLoggedUserRoles, signPayload
} from "../src";
import { API_ERROR, ROLES } from "@verdaccio/dev-commons";
import { VerdaccioError, getForbidden } from "@verdaccio/commons-api";
import { Config, IPluginAuth } from '@verdaccio/types';
jest.mock('@verdaccio/logger', () => ({
logger: { trace: jest.fn() }
}));
describe('Auth Utilities', () => {
describe('validatePassword', () => {
test('should validate password according the length', () => {
expect(validatePassword('12345', 1)).toBeTruthy();
});
test('should fails on validate password according the length', () => {
expect(validatePassword('12345', 10)).toBeFalsy();
});
test('should fails on validate password according the length and default config', () => {
expect(validatePassword('12')).toBeFalsy();
});
test('should validate password according the length and default config', () => {
expect(validatePassword('1235678910')).toBeTruthy();
});
});
describe('createRemoteUser and createAnonymousRemoteUser', () => {
test('should create a remote user with default groups', () => {
expect(createRemoteUser('12345', ['foo', 'bar'])).toEqual(
{
"groups": ["foo", "bar", ROLES.$ALL, ROLES.$AUTH, ROLES.DEPRECATED_ALL, ROLES.DEPRECATED_AUTH, ROLES.ALL],
"name": "12345",
"real_groups": ["foo", "bar"]
}
);
});
test('should create a anonymous remote user with default groups', () => {
expect(createAnonymousRemoteUser()).toEqual(
{
"groups": [ROLES.$ALL, ROLES.$ANONYMOUS, ROLES.DEPRECATED_ALL, ROLES.DEPRECATED_ANONYMOUS],
"name": undefined,
"real_groups": []
}
);
});
});
describe('allow_action', () => {
describe('access/publish/unpublish and anonymous', () => {
const packageAccess = {
name: 'foo',
version: undefined,
access: ['foo'],
unpublish: false
};
// const type = 'access';
test.each(['access', 'publish', 'unpublish'])('should restrict %s to anonymous users', (type) => {
allow_action(type as ActionsAllowed)(
createAnonymousRemoteUser(), {
...packageAccess,
[type]: ['foo']
},
(error: VerdaccioError | null, allowed: AllowActionCallbackResponse) => {
expect(error).not.toBeNull();
expect(allowed).toBeUndefined();
}
);
});
test.each(['access', 'publish', 'unpublish'])('should allow %s to anonymous users', (type) => {
allow_action(type as ActionsAllowed)(
createAnonymousRemoteUser(), {
...packageAccess,
[type]: [ROLES.$ANONYMOUS]
},
(error: VerdaccioError | null, allowed: AllowActionCallbackResponse) => {
expect(error).toBeNull();
expect(allowed).toBe(true);
}
);
});
test.each(['access', 'publish', 'unpublish'])('should allow %s only if user is anonymous if the logged user has groups', (type) => {
allow_action(type as ActionsAllowed)(
createRemoteUser('juan', ['maintainer', 'admin']), {
...packageAccess,
[type]: [ROLES.$ANONYMOUS]
},
(error: VerdaccioError | null, allowed: AllowActionCallbackResponse) => {
expect(error).not.toBeNull();
expect(allowed).toBeUndefined();
}
);
});
test.each(['access', 'publish', 'unpublish'])('should allow %s only if user is anonymous match any other groups', (type) => {
allow_action(type as ActionsAllowed)(
createRemoteUser('juan', ['maintainer', 'admin']), {
...packageAccess,
[type]: ['admin', 'some-other-group', ROLES.$ANONYMOUS]
},
(error: VerdaccioError | null, allowed: AllowActionCallbackResponse) => {
expect(error).toBeNull();
expect(allowed).toBe(true);
}
);
});
test.each(['access', 'publish', 'unpublish'])('should not allow %s anonymous if other groups are defined and does not match', (type) => {
allow_action(type as ActionsAllowed)(
createRemoteUser('juan', ['maintainer', 'admin']), {
...packageAccess,
[type]: ['bla-bla-group', 'some-other-group', ROLES.$ANONYMOUS]
},
(error: VerdaccioError | null, allowed: AllowActionCallbackResponse) => {
expect(error).not.toBeNull();
expect(allowed).toBeUndefined();
}
);
});
});
});
describe('createSessionToken', () => {
test('should generate session token', () => {
expect(createSessionToken()).toHaveProperty('expires');
expect(createSessionToken().expires).toBeInstanceOf(Date);
});
});
describe('getDefaultPlugins', () => {
test('authentication should fail by default (default)', () => {
const plugin = getDefaultPlugins();
plugin.authenticate('foo', 'bar', (error: any) => {
expect(error).toEqual(getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
});
});
test('add user should fail by default (default)', () => {
const plugin: IPluginAuth<Config> = getDefaultPlugins();
// @ts-ignore
plugin.adduser('foo', 'bar', (error: any) => {
expect(error).toEqual(getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
});
});
});
describe('getAuthenticatedMessage', () => {
test('should generate user message token', () => {
expect(getAuthenticatedMessage('foo')).toEqual('you are authenticated as \'foo\'');
});
});
describe('verifyJWTPayload', () => {
test('should fail on verify the token and return anonymous users', () => {
expect(verifyJWTPayload('fakeToken', 'secret')).toEqual(createAnonymousRemoteUser());
});
test('should fail on verify the token and return anonymous users', async () => {
const remoteUser = createRemoteUser('foo', []);
const token = await signPayload(remoteUser, '12345');
const verifiedToken = verifyJWTPayload(token, '12345');
expect(verifiedToken.groups).toEqual(remoteUser.groups);
expect(verifiedToken.name).toEqual(remoteUser.name);
});
});
// verifyJWTPayload
});

View File

@ -1,4 +1,4 @@
import {aesDecrypt, aesEncrypt, convertPayloadToBase64} from "@verdaccio/utils";
import {aesDecrypt, aesEncrypt, convertPayloadToBase64} from '../src';
describe('test crypto utils', () => {
describe('default encryption', () => {

View File

@ -2745,16 +2745,11 @@
resolved "https://registry.verdaccio.org/@verdaccio%2fstreams/-/streams-9.3.1.tgz#4e1524382e18d3121d60c32b7d5ee39e21381430"
integrity sha512-AO0i8lsu3H1ss694Dtg9KbWpOlSRFNVeT5J2oscAAjQydXjOB63paxiOdUBTaavhT03T+i/AnSgWahsdSG1diA==
"@verdaccio/types@9.3.0", "@verdaccio/types@^9.0.0", "@verdaccio/types@^9.3.0":
"@verdaccio/types@9.3.0", "@verdaccio/types@^9.3.0":
version "9.3.0"
resolved "https://registry.verdaccio.org/@verdaccio%2ftypes/-/types-9.3.0.tgz#4062183e84bef3a56b4275d111181873f8a082d6"
integrity sha512-TzBuWPKxhQILk3Tl8EGvAj6zinwBJw+bEhg5w7HYoE+FpEV6rJ1XW+GF/h/7mRBPhtKiPMMzclRRPysNsT/0ww==
"@verdaccio/types@^8.5.2":
version "8.5.2"
resolved "https://registry.verdaccio.org/@verdaccio%2ftypes/-/types-8.5.2.tgz#4e371aae10e8550b4a19b57f6ba1f1f185147669"
integrity sha512-x/sacqVndl1dXVKPd7pomea6gs9BKC+i83LDn6MEAO+tuhqWRsKC3UwztLA1YSKjNF33//7JCYMDQk6uaJ9ipw==
"@verdaccio/ui-theme@^0.3.12", "@verdaccio/ui-theme@^0.3.13":
version "0.3.13"
resolved "https://registry.verdaccio.org/@verdaccio%2fui-theme/-/ui-theme-0.3.13.tgz#e6f06907b0940c47883f35861723012437b7b958"