mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-30 22:34:10 -05:00
feat: signature package (#3653)
* feat: signature package * feat: signature package
This commit is contained in:
parent
399cf9c47c
commit
ddb6a22396
27 changed files with 298 additions and 32 deletions
8
.changeset/kind-ladybugs-admire.md
Normal file
8
.changeset/kind-ladybugs-admire.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
'@verdaccio/auth': minor
|
||||||
|
'@verdaccio/config': minor
|
||||||
|
'@verdaccio/signature': minor
|
||||||
|
'@verdaccio/ui-components': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: signature package
|
|
@ -4,7 +4,7 @@ module.exports = Object.assign({}, config, {
|
||||||
coverageThreshold: {
|
coverageThreshold: {
|
||||||
global: {
|
global: {
|
||||||
// FIXME: increase to 90
|
// FIXME: increase to 90
|
||||||
lines: 42,
|
lines: 30,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -43,10 +43,10 @@
|
||||||
"@verdaccio/config": "workspace:6.0.0-6-next.62",
|
"@verdaccio/config": "workspace:6.0.0-6-next.62",
|
||||||
"@verdaccio/loaders": "workspace:6.0.0-6-next.31",
|
"@verdaccio/loaders": "workspace:6.0.0-6-next.31",
|
||||||
"@verdaccio/logger": "workspace:6.0.0-6-next.30",
|
"@verdaccio/logger": "workspace:6.0.0-6-next.30",
|
||||||
|
"@verdaccio/signature": "workspace:6.0.0-6-next.1",
|
||||||
"@verdaccio/utils": "workspace:6.0.0-6-next.30",
|
"@verdaccio/utils": "workspace:6.0.0-6-next.30",
|
||||||
"debug": "4.3.4",
|
"debug": "4.3.4",
|
||||||
"express": "4.18.2",
|
"express": "4.18.2",
|
||||||
"jsonwebtoken": "9.0.0",
|
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"verdaccio-htpasswd": "workspace:11.0.0-6-next.32"
|
"verdaccio-htpasswd": "workspace:11.0.0-6-next.32"
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
} from '@verdaccio/core';
|
} from '@verdaccio/core';
|
||||||
import { asyncLoadPlugin } from '@verdaccio/loaders';
|
import { asyncLoadPlugin } from '@verdaccio/loaders';
|
||||||
import { logger } from '@verdaccio/logger';
|
import { logger } from '@verdaccio/logger';
|
||||||
|
import { aesEncrypt, parseBasicPayload, signPayload } from '@verdaccio/signature';
|
||||||
import {
|
import {
|
||||||
AllowAccess,
|
AllowAccess,
|
||||||
Callback,
|
Callback,
|
||||||
|
@ -27,9 +28,6 @@ import {
|
||||||
} from '@verdaccio/types';
|
} from '@verdaccio/types';
|
||||||
import { getMatchedPackagesSpec, isFunction, isNil } from '@verdaccio/utils';
|
import { getMatchedPackagesSpec, isFunction, isNil } from '@verdaccio/utils';
|
||||||
|
|
||||||
import { signPayload } from './jwt-token';
|
|
||||||
import { aesEncrypt } from './legacy-token';
|
|
||||||
import { parseBasicPayload } from './token';
|
|
||||||
import {
|
import {
|
||||||
convertPayloadToBase64,
|
convertPayloadToBase64,
|
||||||
getDefaultPlugins,
|
getDefaultPlugins,
|
||||||
|
@ -47,6 +45,7 @@ export interface TokenEncryption {
|
||||||
aesEncrypt(buf: string): string | void;
|
aesEncrypt(buf: string): string | void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove
|
||||||
export interface AESPayload {
|
export interface AESPayload {
|
||||||
user: string;
|
user: string;
|
||||||
password: string;
|
password: string;
|
||||||
|
|
|
@ -1,5 +1,2 @@
|
||||||
export { Auth, TokenEncryption } from './auth';
|
export { Auth } from './auth';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
export * from './legacy-token';
|
|
||||||
export * from './jwt-token';
|
|
||||||
export * from './token';
|
|
||||||
|
|
|
@ -11,12 +11,10 @@ import {
|
||||||
errorUtils,
|
errorUtils,
|
||||||
pluginUtils,
|
pluginUtils,
|
||||||
} from '@verdaccio/core';
|
} from '@verdaccio/core';
|
||||||
|
import { aesDecrypt, parseBasicPayload, verifyPayload } from '@verdaccio/signature';
|
||||||
import { AuthPackageAllow, Config, Logger, RemoteUser, Security } from '@verdaccio/types';
|
import { AuthPackageAllow, Config, Logger, RemoteUser, Security } from '@verdaccio/types';
|
||||||
|
|
||||||
import { AESPayload, TokenEncryption } from './auth';
|
import { AESPayload, TokenEncryption } from './auth';
|
||||||
import { verifyPayload } from './jwt-token';
|
|
||||||
import { aesDecrypt } from './legacy-token';
|
|
||||||
import { parseBasicPayload } from './token';
|
|
||||||
|
|
||||||
const debug = buildDebug('verdaccio:auth:utils');
|
const debug = buildDebug('verdaccio:auth:utils');
|
||||||
|
|
||||||
|
|
|
@ -17,24 +17,22 @@ import {
|
||||||
errorUtils,
|
errorUtils,
|
||||||
} from '@verdaccio/core';
|
} from '@verdaccio/core';
|
||||||
import { setup } from '@verdaccio/logger';
|
import { setup } from '@verdaccio/logger';
|
||||||
|
import { aesDecrypt, signPayload, verifyPayload } from '@verdaccio/signature';
|
||||||
import { Config, RemoteUser, Security } from '@verdaccio/types';
|
import { Config, RemoteUser, Security } from '@verdaccio/types';
|
||||||
import { buildToken, buildUserBuffer, getAuthenticatedMessage } from '@verdaccio/utils';
|
import { buildToken, buildUserBuffer, getAuthenticatedMessage } from '@verdaccio/utils';
|
||||||
import type { AllowActionCallbackResponse } from '@verdaccio/utils';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ActionsAllowed,
|
ActionsAllowed,
|
||||||
|
AllowActionCallbackResponse,
|
||||||
Auth,
|
Auth,
|
||||||
aesDecrypt,
|
|
||||||
allow_action,
|
allow_action,
|
||||||
getApiToken,
|
getApiToken,
|
||||||
getDefaultPlugins,
|
getDefaultPlugins,
|
||||||
getMiddlewareCredentials,
|
getMiddlewareCredentials,
|
||||||
signPayload,
|
|
||||||
verifyJWTPayload,
|
verifyJWTPayload,
|
||||||
verifyPayload,
|
|
||||||
} from '../src';
|
} from '../src';
|
||||||
|
|
||||||
setup([]);
|
setup({});
|
||||||
|
|
||||||
const parseConfigurationFile = (conf) => {
|
const parseConfigurationFile = (conf) => {
|
||||||
const { name, ext } = path.parse(conf);
|
const { name, ext } = path.parse(conf);
|
||||||
|
@ -452,6 +450,7 @@ describe('Auth utilities', () => {
|
||||||
const config: Config = getConfig('security-legacy', secret);
|
const config: Config = getConfig('security-legacy', secret);
|
||||||
const auth: Auth = new Auth(config);
|
const auth: Auth = new Auth(config);
|
||||||
await auth.init();
|
await auth.init();
|
||||||
|
// @ts-expect-error
|
||||||
const token = auth.aesEncrypt(null);
|
const token = auth.aesEncrypt(null);
|
||||||
const security: Security = config.security;
|
const security: Security = config.security;
|
||||||
const credentials = getMiddlewareCredentials(
|
const credentials = getMiddlewareCredentials(
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
{
|
{
|
||||||
"path": "../loaders"
|
"path": "../loaders"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "../signature"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "../logger/logger"
|
"path": "../logger/logger"
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,6 +4,7 @@ export const TOKEN_VALID_LENGTH = 32;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Secret key must have 32 characters.
|
* Secret key must have 32 characters.
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
export function generateRandomSecretKey(): string {
|
export function generateRandomSecretKey(): string {
|
||||||
return randomBytes(TOKEN_VALID_LENGTH).toString('base64').substring(0, TOKEN_VALID_LENGTH);
|
return randomBytes(TOKEN_VALID_LENGTH).toString('base64').substring(0, TOKEN_VALID_LENGTH);
|
||||||
|
|
3
packages/signature/.babelrc
Normal file
3
packages/signature/.babelrc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"extends": "../../.babelrc"
|
||||||
|
}
|
3
packages/signature/jest.config.js
Normal file
3
packages/signature/jest.config.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
const config = require('../../jest/config');
|
||||||
|
|
||||||
|
module.exports = Object.assign({}, config, {});
|
53
packages/signature/package.json
Normal file
53
packages/signature/package.json
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
{
|
||||||
|
"name": "@verdaccio/signature",
|
||||||
|
"version": "6.0.0-6-next.1",
|
||||||
|
"description": "verdaccio signature utils",
|
||||||
|
"main": "./build/index.js",
|
||||||
|
"types": "build/index.d.ts",
|
||||||
|
"author": {
|
||||||
|
"name": "Juan Picado",
|
||||||
|
"email": "juanpicado19@gmail.com"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "https",
|
||||||
|
"url": "https://github.com/verdaccio/verdaccio"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"homepage": "https://verdaccio.org",
|
||||||
|
"keywords": [
|
||||||
|
"private",
|
||||||
|
"package",
|
||||||
|
"repository",
|
||||||
|
"registry",
|
||||||
|
"enterprise",
|
||||||
|
"modules",
|
||||||
|
"proxy",
|
||||||
|
"server",
|
||||||
|
"verdaccio"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf ./build",
|
||||||
|
"test": "jest",
|
||||||
|
"type-check": "tsc --noEmit -p tsconfig.build.json",
|
||||||
|
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
|
||||||
|
"build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
|
||||||
|
"watch": "pnpm build:js -- --watch",
|
||||||
|
"build": "pnpm run build:js && pnpm run build:types"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"jsonwebtoken": "9.0.0",
|
||||||
|
"debug": "4.3.4",
|
||||||
|
"lodash": "4.17.21"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@verdaccio/config": "workspace:6.0.0-6-next.62",
|
||||||
|
"@verdaccio/types": "workspace:11.0.0-6-next.21"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/verdaccio"
|
||||||
|
}
|
||||||
|
}
|
10
packages/signature/src/index.ts
Normal file
10
packages/signature/src/index.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
export {
|
||||||
|
aesDecryptDeprecated,
|
||||||
|
aesEncryptDeprecated,
|
||||||
|
generateRandomSecretKeyDeprecated,
|
||||||
|
} from './legacy-signature';
|
||||||
|
export { aesDecrypt, aesEncrypt } from './signature';
|
||||||
|
export { signPayload, verifyPayload } from './jwt-token';
|
||||||
|
export * as utils from './utils';
|
||||||
|
export * as types from './types';
|
||||||
|
export { parseBasicPayload } from './token';
|
51
packages/signature/src/legacy-signature/index.ts
Normal file
51
packages/signature/src/legacy-signature/index.ts
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import { createCipher, createDecipher } from 'crypto';
|
||||||
|
|
||||||
|
import { generateRandomHexString } from '../utils';
|
||||||
|
|
||||||
|
export const defaultAlgorithm = 'aes192';
|
||||||
|
export const defaultTarballHashAlgorithm = 'sha1';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param buf
|
||||||
|
* @param secret
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function aesEncryptDeprecated(buf: Buffer, secret: string): Buffer {
|
||||||
|
// deprecated (it will be removed in Verdaccio 6), it is a breaking change
|
||||||
|
// https://nodejs.org/api/crypto.html#crypto_crypto_createcipher_algorithm_password_options
|
||||||
|
// https://www.grainger.xyz/changing-from-cipher-to-cipheriv/
|
||||||
|
const c = createCipher(defaultAlgorithm, secret);
|
||||||
|
const b1 = c.update(buf);
|
||||||
|
const b2 = c.final();
|
||||||
|
return Buffer.concat([b1, b2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param buf
|
||||||
|
* @param secret
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function aesDecryptDeprecated(buf: Buffer, secret: string): Buffer {
|
||||||
|
try {
|
||||||
|
// https://nodejs.org/api/crypto.html#crypto_crypto_createdecipher_algorithm_password_options
|
||||||
|
// https://www.grainger.xyz/changing-from-cipher-to-cipheriv/
|
||||||
|
const c = createDecipher(defaultAlgorithm, secret);
|
||||||
|
const b1 = c.update(buf);
|
||||||
|
const b2 = c.final();
|
||||||
|
return Buffer.concat([b1, b2]);
|
||||||
|
} catch (_) {
|
||||||
|
return Buffer.alloc(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TOKEN_VALID_LENGTH_DEPRECATED = 64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Genrate a secret key of 64 characters.
|
||||||
|
* @deprecated keys should be length max of 64
|
||||||
|
*/
|
||||||
|
export function generateRandomSecretKeyDeprecated(): string {
|
||||||
|
return generateRandomHexString(6);
|
||||||
|
}
|
|
@ -14,8 +14,6 @@ const debug = buildDebug('verdaccio:auth:token:legacy');
|
||||||
export const defaultAlgorithm = process.env.VERDACCIO_LEGACY_ALGORITHM || 'aes-256-ctr';
|
export const defaultAlgorithm = process.env.VERDACCIO_LEGACY_ALGORITHM || 'aes-256-ctr';
|
||||||
const inputEncoding: CharacterEncoding = 'utf8';
|
const inputEncoding: CharacterEncoding = 'utf8';
|
||||||
const outputEncoding: BinaryToTextEncoding = 'hex';
|
const outputEncoding: BinaryToTextEncoding = 'hex';
|
||||||
// For AES, this is always 16
|
|
||||||
const IV_LENGTH = 16;
|
|
||||||
// Must be 256 bits (32 characters)
|
// Must be 256 bits (32 characters)
|
||||||
// https://stackoverflow.com/questions/50963160/invalid-key-length-in-crypto-createcipheriv#50963356
|
// https://stackoverflow.com/questions/50963160/invalid-key-length-in-crypto-createcipheriv#50963356
|
||||||
const VERDACCIO_LEGACY_ENCRYPTION_KEY = process.env.VERDACCIO_LEGACY_ENCRYPTION_KEY;
|
const VERDACCIO_LEGACY_ENCRYPTION_KEY = process.env.VERDACCIO_LEGACY_ENCRYPTION_KEY;
|
||||||
|
@ -25,7 +23,8 @@ export function aesEncrypt(value: string, key: string): string | void {
|
||||||
// https://www.grainger.xyz/changing-from-cipher-to-cipheriv/
|
// https://www.grainger.xyz/changing-from-cipher-to-cipheriv/
|
||||||
debug('encrypt %o', value);
|
debug('encrypt %o', value);
|
||||||
debug('algorithm %o', defaultAlgorithm);
|
debug('algorithm %o', defaultAlgorithm);
|
||||||
const iv = Buffer.from(randomBytes(IV_LENGTH));
|
// IV must be a buffer of length 16
|
||||||
|
const iv = Buffer.from(randomBytes(16));
|
||||||
const secretKey = VERDACCIO_LEGACY_ENCRYPTION_KEY || key;
|
const secretKey = VERDACCIO_LEGACY_ENCRYPTION_KEY || key;
|
||||||
const isKeyValid = secretKey?.length === TOKEN_VALID_LENGTH;
|
const isKeyValid = secretKey?.length === TOKEN_VALID_LENGTH;
|
||||||
debug('length secret key %o', secretKey?.length);
|
debug('length secret key %o', secretKey?.length);
|
|
@ -1,5 +1,10 @@
|
||||||
import { BasicPayload } from './utils';
|
import { BasicPayload } from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param credentials
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export function parseBasicPayload(credentials: string): BasicPayload {
|
export function parseBasicPayload(credentials: string): BasicPayload {
|
||||||
const index = credentials.indexOf(':');
|
const index = credentials.indexOf(':');
|
||||||
if (index < 0) {
|
if (index < 0) {
|
6
packages/signature/src/types.ts
Normal file
6
packages/signature/src/types.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export interface AESPayload {
|
||||||
|
user: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BasicPayload = AESPayload | void;
|
40
packages/signature/src/utils.ts
Normal file
40
packages/signature/src/utils.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { Hash, createHash, pseudoRandomBytes, randomBytes } from 'crypto';
|
||||||
|
|
||||||
|
export const defaultTarballHashAlgorithm = 'sha1';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function createTarballHash(algorithm = defaultTarballHashAlgorithm): Hash {
|
||||||
|
return createHash(algorithm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Express doesn't do ETAGS with requests <= 1024b
|
||||||
|
* we use md5 here, it works well on 1k+ bytes, but with fewer data
|
||||||
|
* could improve performance using crc32 after benchmarks.
|
||||||
|
* @param {Object} data
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
export function stringToMD5(data: Buffer | string): string {
|
||||||
|
return createHash('md5').update(data).digest('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param length
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function generateRandomHexString(length = 8): string {
|
||||||
|
return pseudoRandomBytes(length).toString('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TOKEN_VALID_LENGTH = 32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a secret of 32 characters.
|
||||||
|
*/
|
||||||
|
export function generateRandomSecretKey(): string {
|
||||||
|
return randomBytes(TOKEN_VALID_LENGTH).toString('base64').substring(0, TOKEN_VALID_LENGTH);
|
||||||
|
}
|
13
packages/signature/test/jwt.spec.ts
Normal file
13
packages/signature/test/jwt.spec.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { createRemoteUser } from '@verdaccio/config';
|
||||||
|
|
||||||
|
import { signPayload, verifyPayload } from '../src';
|
||||||
|
|
||||||
|
describe('verifyJWTPayload', () => {
|
||||||
|
test('should verify the token and return a remote user', async () => {
|
||||||
|
const remoteUser = createRemoteUser('foo', []);
|
||||||
|
const token = await signPayload(remoteUser, '12345');
|
||||||
|
const verifiedToken = verifyPayload(token, '12345');
|
||||||
|
expect(verifiedToken.groups).toEqual(remoteUser.groups);
|
||||||
|
expect(verifiedToken.name).toEqual(remoteUser.name);
|
||||||
|
});
|
||||||
|
});
|
23
packages/signature/test/legacy-token-deprecated.spec.ts
Normal file
23
packages/signature/test/legacy-token-deprecated.spec.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import {
|
||||||
|
aesDecryptDeprecated,
|
||||||
|
aesEncryptDeprecated,
|
||||||
|
generateRandomSecretKeyDeprecated,
|
||||||
|
} from '../src';
|
||||||
|
|
||||||
|
describe('test deprecated crypto utils', () => {
|
||||||
|
test('decrypt payload flow', () => {
|
||||||
|
const secret = generateRandomSecretKeyDeprecated();
|
||||||
|
const payload = 'juan:password';
|
||||||
|
const token = aesEncryptDeprecated(Buffer.from(payload), secret);
|
||||||
|
const data = aesDecryptDeprecated(token, secret);
|
||||||
|
|
||||||
|
expect(data.toString()).toEqual(payload.toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
test('crypt fails if secret is incorrect', () => {
|
||||||
|
const payload = 'juan:password';
|
||||||
|
expect(aesEncryptDeprecated(Buffer.from(payload), 'fake_token').toString()).not.toEqual(
|
||||||
|
Buffer.from(payload)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,4 +1,4 @@
|
||||||
import { aesDecrypt, aesEncrypt } from '../src/legacy-token';
|
import { aesDecrypt, aesEncrypt } from '../src';
|
||||||
|
|
||||||
describe('test crypto utils', () => {
|
describe('test crypto utils', () => {
|
||||||
test('decrypt payload flow', () => {
|
test('decrypt payload flow', () => {
|
18
packages/signature/test/utilts.spec.ts
Normal file
18
packages/signature/test/utilts.spec.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import {
|
||||||
|
TOKEN_VALID_LENGTH,
|
||||||
|
createTarballHash,
|
||||||
|
generateRandomSecretKey,
|
||||||
|
stringToMD5,
|
||||||
|
} from '../src/utils';
|
||||||
|
|
||||||
|
test('token generation length is valid', () => {
|
||||||
|
expect(generateRandomSecretKey()).toHaveLength(TOKEN_VALID_LENGTH);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('string to md5 has valid length', () => {
|
||||||
|
expect(stringToMD5(Buffer.from('foo'))).toHaveLength(32);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('create a hash of content', () => {
|
||||||
|
expect(typeof createTarballHash().update('1').digest('hex')).toEqual('string');
|
||||||
|
});
|
9
packages/signature/tsconfig.build.json
Normal file
9
packages/signature/tsconfig.build.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base",
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./build"
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts"],
|
||||||
|
"exclude": ["src/**/*.test.ts"]
|
||||||
|
}
|
17
packages/signature/tsconfig.json
Normal file
17
packages/signature/tsconfig.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.reference.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./build",
|
||||||
|
"noImplicitAny": false
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts", "types/*.d.ts"],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../config"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../utils"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -7,10 +7,6 @@
|
||||||
"homepage": "https://verdaccio.org",
|
"homepage": "https://verdaccio.org",
|
||||||
"main": "./build/index.js",
|
"main": "./build/index.js",
|
||||||
"types": "build/index.d.ts",
|
"types": "build/index.d.ts",
|
||||||
"files": [
|
|
||||||
"./build",
|
|
||||||
"./src"
|
|
||||||
],
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "cross-env TZ=UTC jest --config jest/jest.config.js",
|
"test": "cross-env TZ=UTC jest --config jest/jest.config.js",
|
||||||
"test:html": "cross-env TZ=UTC jest --config jest/jest.config.js --coverage-reporters=html",
|
"test:html": "cross-env TZ=UTC jest --config jest/jest.config.js --coverage-reporters=html",
|
||||||
|
|
|
@ -391,11 +391,11 @@ importers:
|
||||||
'@verdaccio/core': workspace:6.0.0-6-next.62
|
'@verdaccio/core': workspace:6.0.0-6-next.62
|
||||||
'@verdaccio/loaders': workspace:6.0.0-6-next.31
|
'@verdaccio/loaders': workspace:6.0.0-6-next.31
|
||||||
'@verdaccio/logger': workspace:6.0.0-6-next.30
|
'@verdaccio/logger': workspace:6.0.0-6-next.30
|
||||||
|
'@verdaccio/signature': workspace:6.0.0-6-next.1
|
||||||
'@verdaccio/types': workspace:11.0.0-6-next.21
|
'@verdaccio/types': workspace:11.0.0-6-next.21
|
||||||
'@verdaccio/utils': workspace:6.0.0-6-next.30
|
'@verdaccio/utils': workspace:6.0.0-6-next.30
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
express: 4.18.2
|
express: 4.18.2
|
||||||
jsonwebtoken: 9.0.0
|
|
||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
verdaccio-htpasswd: workspace:11.0.0-6-next.32
|
verdaccio-htpasswd: workspace:11.0.0-6-next.32
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -403,10 +403,10 @@ importers:
|
||||||
'@verdaccio/core': link:../core/core
|
'@verdaccio/core': link:../core/core
|
||||||
'@verdaccio/loaders': link:../loaders
|
'@verdaccio/loaders': link:../loaders
|
||||||
'@verdaccio/logger': link:../logger/logger
|
'@verdaccio/logger': link:../logger/logger
|
||||||
|
'@verdaccio/signature': link:../signature
|
||||||
'@verdaccio/utils': link:../utils
|
'@verdaccio/utils': link:../utils
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
express: 4.18.2
|
express: 4.18.2
|
||||||
jsonwebtoken: 9.0.0
|
|
||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
verdaccio-htpasswd: link:../plugins/htpasswd
|
verdaccio-htpasswd: link:../plugins/htpasswd
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
@ -1108,6 +1108,21 @@ importers:
|
||||||
'@verdaccio/types': link:../../core/types
|
'@verdaccio/types': link:../../core/types
|
||||||
ts-node: 10.9.1_5cc4fd05cdbba7efed0227e61dc065e1
|
ts-node: 10.9.1_5cc4fd05cdbba7efed0227e61dc065e1
|
||||||
|
|
||||||
|
packages/signature:
|
||||||
|
specifiers:
|
||||||
|
'@verdaccio/config': workspace:6.0.0-6-next.62
|
||||||
|
'@verdaccio/types': workspace:11.0.0-6-next.21
|
||||||
|
debug: 4.3.4
|
||||||
|
jsonwebtoken: 9.0.0
|
||||||
|
lodash: 4.17.21
|
||||||
|
dependencies:
|
||||||
|
debug: 4.3.4
|
||||||
|
jsonwebtoken: 9.0.0
|
||||||
|
lodash: 4.17.21
|
||||||
|
devDependencies:
|
||||||
|
'@verdaccio/config': link:../config
|
||||||
|
'@verdaccio/types': link:../core/types
|
||||||
|
|
||||||
packages/standalone:
|
packages/standalone:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@verdaccio/cli': workspace:6.0.0-6-next.62
|
'@verdaccio/cli': workspace:6.0.0-6-next.62
|
||||||
|
@ -10911,7 +10926,7 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/buffer-equal-constant-time/1.0.1:
|
/buffer-equal-constant-time/1.0.1:
|
||||||
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
resolution: {integrity: sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=}
|
||||||
|
|
||||||
/buffer-from/1.1.1:
|
/buffer-from/1.1.1:
|
||||||
resolution: {integrity: sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==}
|
resolution: {integrity: sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==}
|
||||||
|
@ -15583,7 +15598,7 @@ packages:
|
||||||
map-cache: 0.2.2
|
map-cache: 0.2.2
|
||||||
|
|
||||||
/fresh/0.5.2:
|
/fresh/0.5.2:
|
||||||
resolution: {integrity: sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=}
|
resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
/friendly-errors-webpack-plugin/1.7.0_webpack@5.75.0:
|
/friendly-errors-webpack-plugin/1.7.0_webpack@5.75.0:
|
||||||
|
@ -18164,7 +18179,7 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/jsonparse/1.3.1:
|
/jsonparse/1.3.1:
|
||||||
resolution: {integrity: sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=}
|
resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==}
|
||||||
engines: {'0': node >= 0.2.0}
|
engines: {'0': node >= 0.2.0}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
@ -19074,7 +19089,7 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/merge-descriptors/1.0.1:
|
/merge-descriptors/1.0.1:
|
||||||
resolution: {integrity: sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=}
|
resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
|
||||||
|
|
||||||
/merge-stream/2.0.0:
|
/merge-stream/2.0.0:
|
||||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||||
|
|
Loading…
Reference in a new issue