mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-16 21:56:25 -05:00
feat: add property forceMigrateToSecureLegacySignature (#4625)
* migrate to forceMigrateToSecureLegacySignature * Update token.ts * remove dep * Update token.ts
This commit is contained in:
parent
6ce34256e6
commit
2941522099
99 changed files with 1080 additions and 1338 deletions
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
|
@ -2,6 +2,12 @@ name: CI
|
|||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
concurrency:
|
||||
group: ci-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
name: Node ${{ matrix.node_version }}
|
||||
|
@ -9,7 +15,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node_version: [14, 16, 18, 19, 20, 21]
|
||||
node_version: [14, 16, 18, 19, 20, 21, 22]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
|
Binary file not shown.
BIN
.yarn/cache/@babel-cli-npm-7.24.5-c286b9ad60-13be205040.zip
vendored
Normal file
BIN
.yarn/cache/@babel-cli-npm-7.24.5-c286b9ad60-13be205040.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-eslint-parser-npm-7.24.5-adf015bef4-b9df1d0158.zip
vendored
Normal file
BIN
.yarn/cache/@babel-eslint-parser-npm-7.24.5-adf015bef4-b9df1d0158.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-helper-create-class-features-plugin-npm-7.24.5-3d8c1b302f-ea761c1155.zip
vendored
Normal file
BIN
.yarn/cache/@babel-helper-create-class-features-plugin-npm-7.24.5-3d8c1b302f-ea761c1155.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@babel-helper-member-expression-to-functions-npm-7.24.5-be355848b6-d3ad681655.zip
vendored
Normal file
BIN
.yarn/cache/@babel-helper-member-expression-to-functions-npm-7.24.5-be355848b6-d3ad681655.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@babel-helper-module-transforms-npm-7.24.5-c2288b45c7-208c2e3877.zip
vendored
Normal file
BIN
.yarn/cache/@babel-helper-module-transforms-npm-7.24.5-c2288b45c7-208c2e3877.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@babel-helper-plugin-utils-npm-7.24.5-162c4e68e8-fa1450c925.zip
vendored
Normal file
BIN
.yarn/cache/@babel-helper-plugin-utils-npm-7.24.5-162c4e68e8-fa1450c925.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@babel-helper-simple-access-npm-7.24.5-9de60df3e9-5616044603.zip
vendored
Normal file
BIN
.yarn/cache/@babel-helper-simple-access-npm-7.24.5-9de60df3e9-5616044603.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@babel-helper-split-export-declaration-npm-7.24.5-3459ebfe18-f23ab69425.zip
vendored
Normal file
BIN
.yarn/cache/@babel-helper-split-export-declaration-npm-7.24.5-3459ebfe18-f23ab69425.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@babel-helper-string-parser-npm-7.24.1-0a40ece7f8-8404e865b0.zip
vendored
Normal file
BIN
.yarn/cache/@babel-helper-string-parser-npm-7.24.1-0a40ece7f8-8404e865b0.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@babel-helper-validator-identifier-npm-7.24.5-d1938535fe-75d6f9f475.zip
vendored
Normal file
BIN
.yarn/cache/@babel-helper-validator-identifier-npm-7.24.5-d1938535fe-75d6f9f475.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-parser-npm-7.24.5-a19c3b8c3b-a251ea41bf.zip
vendored
Normal file
BIN
.yarn/cache/@babel-parser-npm-7.24.5-a19c3b8c3b-a251ea41bf.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-plugin-syntax-jsx-npm-7.24.1-b105166357-712f7e7918.zip
vendored
Normal file
BIN
.yarn/cache/@babel-plugin-syntax-jsx-npm-7.24.1-b105166357-712f7e7918.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@babel-plugin-syntax-typescript-npm-7.24.1-d4119799eb-bf4bd70788.zip
vendored
Normal file
BIN
.yarn/cache/@babel-plugin-syntax-typescript-npm-7.24.1-d4119799eb-bf4bd70788.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-plugin-transform-block-scoping-npm-7.24.5-d793da88bf-898c91efc0.zip
vendored
Normal file
BIN
.yarn/cache/@babel-plugin-transform-block-scoping-npm-7.24.5-d793da88bf-898c91efc0.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-plugin-transform-class-static-block-npm-7.24.4-6305ac1b25-3b1db3308b.zip
vendored
Normal file
BIN
.yarn/cache/@babel-plugin-transform-class-static-block-npm-7.24.4-6305ac1b25-3b1db3308b.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-plugin-transform-classes-npm-7.24.5-65eaa5a2c6-797bf2bda7.zip
vendored
Normal file
BIN
.yarn/cache/@babel-plugin-transform-classes-npm-7.24.5-65eaa5a2c6-797bf2bda7.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-plugin-transform-destructuring-npm-7.24.5-cb32661810-c5def67de0.zip
vendored
Normal file
BIN
.yarn/cache/@babel-plugin-transform-destructuring-npm-7.24.5-cb32661810-c5def67de0.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-plugin-transform-object-rest-spread-npm-7.24.5-833b98301c-427705fe13.zip
vendored
Normal file
BIN
.yarn/cache/@babel-plugin-transform-object-rest-spread-npm-7.24.5-833b98301c-427705fe13.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@babel-plugin-transform-optional-chaining-npm-7.24.5-4b144fe1df-233934463e.zip
vendored
Normal file
BIN
.yarn/cache/@babel-plugin-transform-optional-chaining-npm-7.24.5-4b144fe1df-233934463e.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-plugin-transform-parameters-npm-7.24.5-8aca61a5b2-b052e1cf43.zip
vendored
Normal file
BIN
.yarn/cache/@babel-plugin-transform-parameters-npm-7.24.5-8aca61a5b2-b052e1cf43.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-plugin-transform-private-property-in-object-npm-7.24.5-2d61eebe51-59f9007671.zip
vendored
Normal file
BIN
.yarn/cache/@babel-plugin-transform-private-property-in-object-npm-7.24.5-2d61eebe51-59f9007671.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-plugin-transform-typeof-symbol-npm-7.24.5-0372e02102-35504219e4.zip
vendored
Normal file
BIN
.yarn/cache/@babel-plugin-transform-typeof-symbol-npm-7.24.5-0372e02102-35504219e4.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-plugin-transform-typescript-npm-7.24.5-5dbc46e557-a18b16c73a.zip
vendored
Normal file
BIN
.yarn/cache/@babel-plugin-transform-typescript-npm-7.24.5-5dbc46e557-a18b16c73a.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-preset-env-npm-7.24.5-58fc1c32b3-cced4e5331.zip
vendored
Normal file
BIN
.yarn/cache/@babel-preset-env-npm-7.24.5-58fc1c32b3-cced4e5331.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-preset-typescript-npm-7.24.1-bc23045dbe-f3e0ff8c20.zip
vendored
Normal file
BIN
.yarn/cache/@babel-preset-typescript-npm-7.24.1-bc23045dbe-f3e0ff8c20.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@babel-traverse-npm-7.24.5-d9a5f00bfc-a313fbf4a0.zip
vendored
Normal file
BIN
.yarn/cache/@babel-traverse-npm-7.24.5-d9a5f00bfc-a313fbf4a0.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@babel-types-npm-7.24.5-2710b35119-8eeeacd996.zip
vendored
Normal file
BIN
.yarn/cache/@babel-types-npm-7.24.5-2710b35119-8eeeacd996.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@types-node-npm-20.12.8-f4c49e4029-84d4876d95.zip
vendored
Normal file
BIN
.yarn/cache/@types-node-npm-20.12.8-f4c49e4029-84d4876d95.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@verdaccio-auth-npm-7.0.0-next-7.15-300adf791c-99f5325a84.zip
vendored
Normal file
BIN
.yarn/cache/@verdaccio-auth-npm-7.0.0-next-7.15-300adf791c-99f5325a84.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@verdaccio-loaders-npm-7.0.0-next-7.15-552a97ba45-4ceb1d5f19.zip
vendored
Normal file
BIN
.yarn/cache/@verdaccio-loaders-npm-7.0.0-next-7.15-552a97ba45-4ceb1d5f19.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@verdaccio-logger-npm-7.0.0-next-7.15-fb2ebe73d5-f090d18e9e.zip
vendored
Normal file
BIN
.yarn/cache/@verdaccio-logger-npm-7.0.0-next-7.15-fb2ebe73d5-f090d18e9e.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@verdaccio-signature-npm-7.0.0-next-7.5-cc911368ce-1a22060bd0.zip
vendored
Normal file
BIN
.yarn/cache/@verdaccio-signature-npm-7.0.0-next-7.5-cc911368ce-1a22060bd0.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@verdaccio-types-npm-12.0.0-next-7.3-88649149df-5b089f5293.zip
vendored
Normal file
BIN
.yarn/cache/@verdaccio-types-npm-12.0.0-next-7.3-88649149df-5b089f5293.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@verdaccio-url-npm-12.0.0-next-7.15-67c4c370d7-57b8cdd649.zip
vendored
Normal file
BIN
.yarn/cache/@verdaccio-url-npm-12.0.0-next-7.15-67c4c370d7-57b8cdd649.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/fsevents-patch-2882183fbf-8.zip
vendored
Normal file
BIN
.yarn/cache/fsevents-patch-2882183fbf-8.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/node-mocks-http-npm-1.14.1-92277e4de4-cc37618fb5.zip
vendored
Normal file
BIN
.yarn/cache/node-mocks-http-npm-1.14.1-92277e4de4-cc37618fb5.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/pino-npm-8.17.2-64a1bee46e-fc769d3d7b.zip
vendored
Normal file
BIN
.yarn/cache/pino-npm-8.17.2-64a1bee46e-fc769d3d7b.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/process-warning-npm-3.0.0-e1380c08e2-1fc2eb4524.zip
vendored
Normal file
BIN
.yarn/cache/process-warning-npm-3.0.0-e1380c08e2-1fc2eb4524.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/sonic-boom-npm-3.8.1-1ea933ec95-79c90d7a2f.zip
vendored
Normal file
BIN
.yarn/cache/sonic-boom-npm-3.8.1-1ea933ec95-79c90d7a2f.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -33,7 +33,9 @@ Install with npm:
|
|||
npm install --location=global verdaccio
|
||||
```
|
||||
|
||||
> Node.js v14 or higher is required for Verdaccio 5
|
||||
**Node.js v14 or higher is required for Verdaccio 5**
|
||||
|
||||
> It's recommended using Node.js 20 (or latest LTS)
|
||||
|
||||
or pull [Docker official image](https://verdaccio.org/docs/docker)
|
||||
|
||||
|
@ -55,8 +57,6 @@ helm repo update
|
|||
helm install verdaccio/verdaccio
|
||||
```
|
||||
|
||||
Are you still using **Verdaccio 4**?. Check the [migration guide from 4.x to 5.x](https://verdaccio.org/blog/2021/04/14/verdaccio-5-migration-guide).
|
||||
|
||||
## Programmatic API
|
||||
|
||||
Verdaccio can be used as a module for launch a server programmatically, [you can find more info at the website](https://verdaccio.org/docs/verdaccio-programmatically#using-the-module-api).
|
||||
|
|
|
@ -127,6 +127,8 @@ server:
|
|||
# security:
|
||||
# api:
|
||||
# legacy: true
|
||||
# # recomended set to true for older installations
|
||||
# migrateToSecureLegacySignature: true
|
||||
# jwt:
|
||||
# sign:
|
||||
# expiresIn: 29d
|
||||
|
|
|
@ -131,6 +131,8 @@ server:
|
|||
# security:
|
||||
# api:
|
||||
# legacy: true
|
||||
# # recomended set to true for older installations
|
||||
# migrateToSecureLegacySignature: true
|
||||
# jwt:
|
||||
# sign:
|
||||
# expiresIn: 29d
|
||||
|
|
49
package.json
49
package.json
|
@ -20,23 +20,23 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@cypress/request": "3.0.1",
|
||||
"@verdaccio/config": "7.0.0-next-7.13",
|
||||
"@verdaccio/core": "7.0.0-next-7.13",
|
||||
"@verdaccio/auth": "7.0.0-next-7.15",
|
||||
"@verdaccio/config": "7.0.0-next-7.15",
|
||||
"@verdaccio/core": "7.0.0-next-7.15",
|
||||
"@verdaccio/local-storage-legacy": "11.0.2",
|
||||
"@verdaccio/logger-7": "7.0.0-next-7.13",
|
||||
"@verdaccio/middleware": "7.0.0-next-7.13",
|
||||
"@verdaccio/logger-7": "7.0.0-next-7.15",
|
||||
"@verdaccio/middleware": "7.0.0-next-7.15",
|
||||
"@verdaccio/search-indexer": "7.0.0-next-7.2",
|
||||
"@verdaccio/signature": "7.0.0-next.3",
|
||||
"@verdaccio/signature": "7.0.0-next-7.5",
|
||||
"@verdaccio/streams": "10.2.1",
|
||||
"@verdaccio/tarball": "12.0.0-next-7.13",
|
||||
"@verdaccio/ui-theme": "7.0.0-next-7.13",
|
||||
"@verdaccio/url": "12.0.0-next-7.13",
|
||||
"@verdaccio/utils": "7.0.0-next-7.13",
|
||||
"@verdaccio/tarball": "12.0.0-next-7.15",
|
||||
"@verdaccio/ui-theme": "7.0.0-next-7.15",
|
||||
"@verdaccio/url": "12.0.0-next-7.15",
|
||||
"@verdaccio/utils": "7.0.0-next-7.15",
|
||||
"JSONStream": "1.3.5",
|
||||
"async": "3.2.5",
|
||||
"clipanion": "3.2.1",
|
||||
"compression": "1.7.4",
|
||||
"cookies": "0.9.1",
|
||||
"cors": "2.8.5",
|
||||
"debug": "^4.3.4",
|
||||
"envinfo": "7.11.1",
|
||||
|
@ -55,13 +55,13 @@
|
|||
"pkginfo": "0.4.1",
|
||||
"semver": "7.6.0",
|
||||
"validator": "13.11.0",
|
||||
"verdaccio-audit": "12.0.0-next-7.13",
|
||||
"verdaccio-htpasswd": "12.0.0-next-7.13"
|
||||
"verdaccio-audit": "12.0.0-next-7.15",
|
||||
"verdaccio-htpasswd": "12.0.0-next-7.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.24.1",
|
||||
"@babel/core": "7.24.3",
|
||||
"@babel/eslint-parser": "7.23.3",
|
||||
"@babel/cli": "7.24.5",
|
||||
"@babel/core": "7.24.5",
|
||||
"@babel/eslint-parser": "7.24.5",
|
||||
"@babel/node": "7.23.9",
|
||||
"@babel/plugin-proposal-class-properties": "7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "7.24.1",
|
||||
|
@ -76,13 +76,13 @@
|
|||
"@babel/plugin-syntax-dynamic-import": "7.8.3",
|
||||
"@babel/plugin-syntax-import-meta": "7.10.4",
|
||||
"@babel/plugin-transform-async-to-generator": "7.24.1",
|
||||
"@babel/plugin-transform-classes": "7.24.1",
|
||||
"@babel/plugin-transform-classes": "7.24.5",
|
||||
"@babel/plugin-transform-runtime": "7.24.3",
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
"@babel/preset-env": "7.24.3",
|
||||
"@babel/preset-typescript": "7.23.3",
|
||||
"@babel/preset-env": "7.24.5",
|
||||
"@babel/preset-typescript": "7.24.1",
|
||||
"@babel/register": "7.23.7",
|
||||
"@babel/runtime": "7.24.1",
|
||||
"@babel/runtime": "7.24.5",
|
||||
"@octokit/rest": "19.0.13",
|
||||
"@trivago/prettier-plugin-sort-imports": "4.3.0",
|
||||
"@types/async": "3.2.24",
|
||||
|
@ -100,7 +100,7 @@
|
|||
"@typescript-eslint/eslint-plugin": "5.62.0",
|
||||
"@typescript-eslint/parser": "5.62.0",
|
||||
"@verdaccio-scope/verdaccio-auth-foo": "0.0.2",
|
||||
"@verdaccio/types": "12.0.0-next.2",
|
||||
"@verdaccio/types": "12.0.0-next-7.3",
|
||||
"babel-jest": "29.7.0",
|
||||
"babel-plugin-dynamic-import-node": "2.3.3",
|
||||
"cross-env": "7.0.3",
|
||||
|
@ -122,7 +122,7 @@
|
|||
"jest-junit": "15.0.0",
|
||||
"lockfile-lint": "4.12.1",
|
||||
"nock": "13.5.0",
|
||||
"node-mocks-http": "^1.13.0",
|
||||
"node-mocks-http": "^1.14.1",
|
||||
"pinst": "2.1.6",
|
||||
"prettier": "3.2.2",
|
||||
"rimraf": "3.0.2",
|
||||
|
@ -186,5 +186,10 @@
|
|||
"url": "https://opencollective.com/verdaccio",
|
||||
"logo": "https://opencollective.com/verdaccio/logo.txt"
|
||||
},
|
||||
"packageManager": "yarn@3.8.1"
|
||||
"packageManager": "yarn@3.8.1",
|
||||
"dependenciesMeta": {
|
||||
"@verdaccio/signature@7.0.0-next-7.5": {
|
||||
"unplugged": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import Cookies from 'cookies';
|
||||
import express, { Response, Router } from 'express';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { getApiToken } from '@verdaccio/auth';
|
||||
import { createRemoteUser } from '@verdaccio/config';
|
||||
import { validationUtils } from '@verdaccio/core';
|
||||
import { rateLimit } from '@verdaccio/middleware';
|
||||
import { Config, RemoteUser } from '@verdaccio/types';
|
||||
import { createSessionToken, getAuthenticatedMessage } from '@verdaccio/utils';
|
||||
import { getAuthenticatedMessage } from '@verdaccio/utils';
|
||||
|
||||
import Auth from '../../../lib/auth';
|
||||
import { getApiToken, validatePassword } from '../../../lib/auth-utils';
|
||||
import { API_ERROR, API_MESSAGE, HEADERS, HTTP_STATUS } from '../../../lib/constants';
|
||||
import { logger } from '../../../lib/logger';
|
||||
import { ErrorCode } from '../../../lib/utils';
|
||||
|
@ -63,7 +63,7 @@ export default function (route: Router, auth: Auth, config: Config): void {
|
|||
}
|
||||
);
|
||||
} else {
|
||||
if (validatePassword(password) === false) {
|
||||
if (validationUtils.validatePassword(password) === false) {
|
||||
// eslint-disable-next-line new-cap
|
||||
return next(ErrorCode.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.PASSWORD_SHORT));
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Response, Router } from 'express';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { validationUtils } from '@verdaccio/core';
|
||||
import { rateLimit } from '@verdaccio/middleware';
|
||||
import { ConfigYaml } from '@verdaccio/types';
|
||||
|
||||
import Auth from '../../../../lib/auth';
|
||||
import { validatePassword } from '../../../../lib/auth-utils';
|
||||
import { API_ERROR, APP_ERROR, HTTP_STATUS, SUPPORT_ERRORS } from '../../../../lib/constants';
|
||||
import { ErrorCode } from '../../../../lib/utils';
|
||||
import { $NextFunctionVer, $RequestExtend } from '../../../../types';
|
||||
|
@ -65,7 +65,7 @@ export default function (router: Router, auth: Auth, config: ConfigYaml) {
|
|||
const { name } = req.remote_user;
|
||||
|
||||
if (_.isNil(password) === false) {
|
||||
if (validatePassword(password.new) === false) {
|
||||
if (validationUtils.validatePassword(password.new) === false) {
|
||||
/* eslint new-cap:off */
|
||||
return next(ErrorCode.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.PASSWORD_SHORT));
|
||||
/* eslint new-cap:off */
|
||||
|
|
|
@ -2,12 +2,12 @@ import buildDebug from 'debug';
|
|||
import { Response, Router } from 'express';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { getApiToken } from '@verdaccio/auth';
|
||||
import { rateLimit } from '@verdaccio/middleware';
|
||||
import { Config, RemoteUser, Token } from '@verdaccio/types';
|
||||
import { stringToMD5 } from '@verdaccio/utils';
|
||||
|
||||
import Auth from '../../../../lib/auth';
|
||||
import { getApiToken } from '../../../../lib/auth-utils';
|
||||
import { HEADERS, HTTP_STATUS, SUPPORT_ERRORS } from '../../../../lib/constants';
|
||||
import { logger } from '../../../../lib/logger';
|
||||
import Storage from '../../../../lib/storage';
|
||||
|
@ -81,10 +81,10 @@ export default function (router: Router, auth: Auth, storage: Storage, config: C
|
|||
}
|
||||
|
||||
try {
|
||||
const token = await getApiToken(auth, config, user, password);
|
||||
const key = stringToMD5(token);
|
||||
const token = (await getApiToken(auth, config, user, password)) as string;
|
||||
const key = stringToMD5(token as string);
|
||||
// TODO: use a utility here
|
||||
const maskedToken = mask(token, 5);
|
||||
const maskedToken = mask(token as string, 5);
|
||||
const created = new Date().getTime();
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { Request, Response, Router } from 'express';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { validationUtils } from '@verdaccio/core';
|
||||
import { rateLimit } from '@verdaccio/middleware';
|
||||
import { Config, JWTSignOptions, RemoteUser } from '@verdaccio/types';
|
||||
|
||||
import Auth from '../../../lib/auth';
|
||||
import { getSecurity, validatePassword } from '../../../lib/auth-utils';
|
||||
import { getSecurity } from '../../../lib/auth-utils';
|
||||
import { API_ERROR, APP_ERROR, HEADERS, HTTP_STATUS } from '../../../lib/constants';
|
||||
import { ErrorCode } from '../../../lib/utils';
|
||||
import { $NextFunctionVer } from '../../../types';
|
||||
|
@ -48,7 +49,7 @@ function addUserAuthApi(route: Router, auth: Auth, config: Config): Router {
|
|||
const { password } = req.body;
|
||||
const { name } = req.remote_user;
|
||||
|
||||
if (validatePassword(password.new) === false) {
|
||||
if (validationUtils.validatePassword(password.new) === false) {
|
||||
auth.changePassword(name as string, password.old, password.new, (err, isUpdated): void => {
|
||||
if (_.isNil(err) && isUpdated) {
|
||||
next({
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import buildDebug from 'debug';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { createAnonymousRemoteUser } from '@verdaccio/config';
|
||||
import { pluginUtils } from '@verdaccio/core';
|
||||
import { aesDecryptDeprecated as aesDecrypt, verifyPayload } from '@verdaccio/signature';
|
||||
import {
|
||||
APITokenOptions,
|
||||
Callback,
|
||||
|
@ -13,19 +11,10 @@ import {
|
|||
RemoteUser,
|
||||
Security,
|
||||
} from '@verdaccio/types';
|
||||
import { buildUserBuffer } from '@verdaccio/utils';
|
||||
|
||||
import { AuthMiddlewarePayload, AuthTokenHeader, BasicPayload, IAuthWebUI } from '../types';
|
||||
import {
|
||||
API_ERROR,
|
||||
DEFAULT_MIN_LIMIT_PASSWORD,
|
||||
HTTP_STATUS,
|
||||
TIME_EXPIRATION_1H,
|
||||
TOKEN_BASIC,
|
||||
TOKEN_BEARER,
|
||||
} from './constants';
|
||||
import { API_ERROR, DEFAULT_MIN_LIMIT_PASSWORD, TIME_EXPIRATION_1H } from './constants';
|
||||
import { logger } from './logger';
|
||||
import { ErrorCode, convertPayloadToBase64 } from './utils';
|
||||
import { ErrorCode } from './utils';
|
||||
|
||||
const debug = buildDebug('verdaccio');
|
||||
|
||||
|
@ -110,6 +99,7 @@ const defaultWebTokenOptions: JWTOptions = {
|
|||
|
||||
const defaultApiTokenConf: APITokenOptions = {
|
||||
legacy: true,
|
||||
migrateToSecureLegacySignature: false,
|
||||
};
|
||||
|
||||
export const defaultSecurity: Security = {
|
||||
|
@ -124,120 +114,3 @@ export function getSecurity(config: Config): Security {
|
|||
|
||||
return defaultSecurity;
|
||||
}
|
||||
|
||||
export function isAESLegacy(security: Security): boolean {
|
||||
const { legacy, jwt } = security.api;
|
||||
|
||||
return _.isNil(legacy) === false && _.isNil(jwt) && legacy === true;
|
||||
}
|
||||
|
||||
export async function getApiToken(
|
||||
auth: IAuthWebUI,
|
||||
config: Config,
|
||||
remoteUser: RemoteUser,
|
||||
aesPassword: string
|
||||
): Promise<string> {
|
||||
const security: Security = getSecurity(config);
|
||||
if (isAESLegacy(security)) {
|
||||
// fallback all goes to AES encryption
|
||||
return await new Promise((resolve): void => {
|
||||
resolve(
|
||||
auth.aesEncrypt(buildUserBuffer(remoteUser.name as string, aesPassword)).toString('base64')
|
||||
);
|
||||
});
|
||||
}
|
||||
// i am wiling to use here _.isNil but flow does not like it yet.
|
||||
const { jwt } = security.api;
|
||||
|
||||
if (jwt && jwt.sign) {
|
||||
return await auth.jwtEncrypt(remoteUser, jwt.sign);
|
||||
}
|
||||
return await new Promise((resolve): void => {
|
||||
resolve(
|
||||
auth.aesEncrypt(buildUserBuffer(remoteUser.name as string, aesPassword)).toString('base64')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function parseAuthTokenHeader(authorizationHeader: string): AuthTokenHeader {
|
||||
const parts = authorizationHeader.split(' ');
|
||||
const [scheme, token] = parts;
|
||||
|
||||
return { scheme, token };
|
||||
}
|
||||
|
||||
export function parseBasicPayload(credentials: string): BasicPayload {
|
||||
const index = credentials.indexOf(':');
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const user: string = credentials.slice(0, index);
|
||||
const password: string = credentials.slice(index + 1);
|
||||
|
||||
return { user, password };
|
||||
}
|
||||
|
||||
export function parseAESCredentials(authorizationHeader: string, secret: string) {
|
||||
const { scheme, token } = parseAuthTokenHeader(authorizationHeader);
|
||||
|
||||
// basic is deprecated and should not be enforced
|
||||
if (scheme.toUpperCase() === TOKEN_BASIC.toUpperCase()) {
|
||||
const credentials = convertPayloadToBase64(token).toString();
|
||||
|
||||
return credentials;
|
||||
} else if (scheme.toUpperCase() === TOKEN_BEARER.toUpperCase()) {
|
||||
const tokenAsBuffer = convertPayloadToBase64(token);
|
||||
const credentials = aesDecrypt(tokenAsBuffer, secret).toString('utf8');
|
||||
|
||||
return credentials;
|
||||
}
|
||||
}
|
||||
|
||||
export const expireReasons: string[] = ['JsonWebTokenError', 'TokenExpiredError'];
|
||||
|
||||
export function verifyJWTPayload(token: string, secret: string): RemoteUser {
|
||||
try {
|
||||
const payload: RemoteUser = verifyPayload(token, secret);
|
||||
|
||||
return payload;
|
||||
} catch (error: any) {
|
||||
// #168 this check should be removed as soon AES encrypt is removed.
|
||||
if (expireReasons.includes(error.name)) {
|
||||
// it might be possible the jwt configuration is enabled and
|
||||
// old tokens fails still remains in usage, thus
|
||||
// we return an anonymous user to force log in.
|
||||
return createAnonymousRemoteUser();
|
||||
}
|
||||
throw ErrorCode.getCode(HTTP_STATUS.UNAUTHORIZED, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,22 @@ import buildDebug from 'debug';
|
|||
import { NextFunction } from 'express';
|
||||
import _ from 'lodash';
|
||||
|
||||
import {
|
||||
getMiddlewareCredentials,
|
||||
isAESLegacy,
|
||||
isAuthHeaderValid,
|
||||
parseAuthTokenHeader,
|
||||
verifyJWTPayload,
|
||||
} from '@verdaccio/auth';
|
||||
import { createAnonymousRemoteUser, createRemoteUser } from '@verdaccio/config';
|
||||
import { VerdaccioError, pluginUtils } from '@verdaccio/core';
|
||||
import { aesEncryptDeprecated as aesEncrypt, signPayload } from '@verdaccio/signature';
|
||||
import {
|
||||
aesEncrypt,
|
||||
aesEncryptDeprecated,
|
||||
parseBasicPayload,
|
||||
signPayload,
|
||||
utils as signatureUtils,
|
||||
} from '@verdaccio/signature';
|
||||
import {
|
||||
AllowAccess,
|
||||
Callback,
|
||||
|
@ -19,16 +32,7 @@ import { getMatchedPackagesSpec } from '@verdaccio/utils';
|
|||
|
||||
import loadPlugin from '../lib/plugin-loader';
|
||||
import { $RequestExtend, $ResponseExtend, AESPayload } from '../types';
|
||||
import {
|
||||
getDefaultPlugins,
|
||||
getMiddlewareCredentials,
|
||||
getSecurity,
|
||||
isAESLegacy,
|
||||
isAuthHeaderValid,
|
||||
parseAuthTokenHeader,
|
||||
parseBasicPayload,
|
||||
verifyJWTPayload,
|
||||
} from './auth-utils';
|
||||
import { getDefaultPlugins, getSecurity } from './auth-utils';
|
||||
import { API_ERROR, SUPPORT_ERRORS, TOKEN_BASIC, TOKEN_BEARER } from './constants';
|
||||
import { logger } from './logger';
|
||||
import { ErrorCode, convertPayloadToBase64 } from './utils';
|
||||
|
@ -526,8 +530,17 @@ class Auth {
|
|||
/**
|
||||
* Encrypt a string.
|
||||
*/
|
||||
public aesEncrypt(buf: Buffer): Buffer {
|
||||
return aesEncrypt(buf, this.secret);
|
||||
public aesEncrypt(value: string): string | void {
|
||||
if (this.secret.length === signatureUtils.TOKEN_VALID_LENGTH) {
|
||||
debug('signing with enhanced aes legacy');
|
||||
const token = aesEncrypt(value, this.secret);
|
||||
return token;
|
||||
} else {
|
||||
debug('signing with enhanced aes deprecated legacy');
|
||||
// deprecated aes (legacy) signature, only must be used for legacy version
|
||||
const token = aesEncryptDeprecated(Buffer.from(value), this.secret).toString('base64');
|
||||
return token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// import assert from 'assert';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { Config as ConfigCore } from '@verdaccio/config';
|
||||
|
@ -6,7 +5,7 @@ import { Config as ConfigCore } from '@verdaccio/config';
|
|||
class Config extends ConfigCore {
|
||||
public constructor(config: any) {
|
||||
config.configPath = config.self_path;
|
||||
super(config, { forceEnhancedLegacySignature: false });
|
||||
super(config, { forceMigrateToSecureLegacySignature: false });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import assert from 'assert';
|
||||
import async, { AsyncResultArrayCallback } from 'async';
|
||||
import buildDebug from 'debug';
|
||||
import _ from 'lodash';
|
||||
import Stream from 'stream';
|
||||
|
||||
|
@ -38,6 +39,8 @@ import ProxyStorage from './up-storage';
|
|||
import { setupUpLinks, updateVersionsHiddenUpLink } from './uplink-util';
|
||||
import { ErrorCode, isObject, normalizeDistTags } from './utils';
|
||||
|
||||
const debug = buildDebug('verdaccio:storage');
|
||||
|
||||
class Storage {
|
||||
public localStorage: LocalStorage;
|
||||
public config: Config;
|
||||
|
@ -54,11 +57,15 @@ class Storage {
|
|||
this.localStorage = null;
|
||||
}
|
||||
|
||||
public init(config: Config, filters: IPluginFilters = []): Promise<string> {
|
||||
this.filters = filters;
|
||||
this.localStorage = new LocalStorage(this.config, logger);
|
||||
|
||||
return this.localStorage.getSecret(config);
|
||||
public async init(config: Config, filters: IPluginFilters = []): Promise<void> {
|
||||
if (this.localStorage === null) {
|
||||
this.filters = filters;
|
||||
this.localStorage = new LocalStorage(this.config, logger);
|
||||
await this.localStorage.getSecret(config);
|
||||
debug('initialization completed');
|
||||
} else {
|
||||
debug('storage has been already initialized');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -472,4 +472,9 @@ export function hasLogin(config: Config) {
|
|||
return _.isNil(config?.web?.login) || config?.web?.login === true;
|
||||
}
|
||||
|
||||
export function isNodeVersionHigherThanV22() {
|
||||
const [major, minor] = process.versions.node.split('.').map(Number);
|
||||
return major > 22 || (major === 22 && minor > 0);
|
||||
}
|
||||
|
||||
export { buildTokenUtil as buildToken, parseConfigFile };
|
||||
|
|
|
@ -44,14 +44,6 @@ export interface AESPayload {
|
|||
password: string;
|
||||
}
|
||||
|
||||
export interface AuthTokenHeader {
|
||||
scheme: string;
|
||||
token: string;
|
||||
}
|
||||
|
||||
export type BasicPayload = AESPayload | void;
|
||||
export type AuthMiddlewarePayload = RemoteUser | BasicPayload;
|
||||
|
||||
export interface Utils {
|
||||
ErrorCode: any;
|
||||
getLatestVersion: Callback;
|
||||
|
@ -78,11 +70,6 @@ export type $ResponseExtend = Response & { cookies?: any };
|
|||
export type $NextFunctionVer = NextFunction & any;
|
||||
export type $SidebarPackage = Package & { latest: any };
|
||||
|
||||
export interface IAuthWebUI {
|
||||
jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string>;
|
||||
aesEncrypt(buf: Buffer): Buffer;
|
||||
}
|
||||
|
||||
interface IAuthMiddleware {
|
||||
apiJWTmiddleware(): $NextFunctionVer;
|
||||
webUIJWTmiddleware(): $NextFunctionVer;
|
||||
|
|
|
@ -17,20 +17,23 @@ describe('token', () => {
|
|||
|
||||
describe('basics', () => {
|
||||
const FAKE_TOKEN: string = buildToken(TOKEN_BEARER, 'fake');
|
||||
test.each([['user.yaml'], ['user.jwt.yaml']])('should test add a new user', async (conf) => {
|
||||
nock('https://registry.verdaccio.org/').get(`/vue`).once().reply(200, { name: 'vue' });
|
||||
const app = await initializeServer(conf);
|
||||
const credentials = { name: 'JotaJWT', password: 'secretPass' };
|
||||
const response = await createUser(app, credentials.name, credentials.password);
|
||||
expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
|
||||
test.each([['user.yaml'], ['user.jwt.yaml']])(
|
||||
'should test add a new user for %s',
|
||||
async (conf) => {
|
||||
nock('https://registry.verdaccio.org/').get(`/vue`).once().reply(200, { name: 'vue' });
|
||||
const app = await initializeServer(conf);
|
||||
const credentials = { name: 'JotaJWT', password: 'secretPass' };
|
||||
const response = await createUser(app, credentials.name, credentials.password);
|
||||
expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
|
||||
|
||||
const vueResponse = await getPackage(app, response.body.token, 'vue');
|
||||
expect(vueResponse.body).toBeDefined();
|
||||
expect(vueResponse.body.name).toMatch('vue');
|
||||
const vueResponse = await getPackage(app, response.body.token, 'vue');
|
||||
expect(vueResponse.body).toBeDefined();
|
||||
expect(vueResponse.body.name).toMatch('vue');
|
||||
|
||||
const vueFailResp = await getPackage(app, FAKE_TOKEN, 'vue', HTTP_STATUS.UNAUTHORIZED);
|
||||
expect(vueFailResp.body.error).toMatch(FORBIDDEN_VUE);
|
||||
});
|
||||
const vueFailResp = await getPackage(app, FAKE_TOKEN, 'vue', HTTP_STATUS.UNAUTHORIZED);
|
||||
expect(vueFailResp.body.error).toMatch(FORBIDDEN_VUE);
|
||||
}
|
||||
);
|
||||
|
||||
test.each([['user.yaml'], ['user.jwt.yaml']])('should login an user', async (conf) => {
|
||||
const app = await initializeServer(conf);
|
||||
|
|
|
@ -1,363 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
import { aesDecryptDeprecated as aesDecrypt, verifyPayload } from '@verdaccio/signature';
|
||||
import { Config, RemoteUser, Security } from '@verdaccio/types';
|
||||
import { buildUserBuffer } from '@verdaccio/utils';
|
||||
|
||||
import Auth from '../../../../src/lib/auth';
|
||||
import { getApiToken, getMiddlewareCredentials, getSecurity } from '../../../../src/lib/auth-utils';
|
||||
import AppConfig from '../../../../src/lib/config';
|
||||
import { CHARACTER_ENCODING, TOKEN_BEARER } from '../../../../src/lib/constants';
|
||||
import { setup } from '../../../../src/lib/logger';
|
||||
import { buildToken, convertPayloadToBase64, parseConfigFile } from '../../../../src/lib/utils';
|
||||
import { IAuth } from '../../../types';
|
||||
import { parseConfigurationFile } from '../../__helper';
|
||||
import configExample from '../../partials/config';
|
||||
|
||||
setup([]);
|
||||
|
||||
describe('Auth utilities', () => {
|
||||
jest.setTimeout(20000);
|
||||
|
||||
const parseConfigurationSecurityFile = (name) => {
|
||||
return parseConfigurationFile(`security/${name}`);
|
||||
};
|
||||
|
||||
function getConfig(configFileName: string, secret: string) {
|
||||
const conf = parseConfigFile(parseConfigurationSecurityFile(configFileName));
|
||||
const secConf = _.merge(configExample(), conf);
|
||||
secConf.secret = secret;
|
||||
const config: Config = new AppConfig(secConf);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
async function signCredentials(
|
||||
configFileName: string,
|
||||
username: string,
|
||||
password: string,
|
||||
secret = '12345',
|
||||
methodToSpy: string,
|
||||
methodNotBeenCalled: string
|
||||
): Promise<string> {
|
||||
const config: Config = getConfig(configFileName, secret);
|
||||
const auth: IAuth = new Auth(config);
|
||||
// @ts-ignore
|
||||
const spy = jest.spyOn(auth, methodToSpy);
|
||||
// @ts-ignore
|
||||
const spyNotCalled = jest.spyOn(auth, methodNotBeenCalled);
|
||||
const user: RemoteUser = {
|
||||
name: username,
|
||||
real_groups: ['test', '$all', '$authenticated', '@all', '@authenticated', 'all'],
|
||||
groups: ['company-role1', 'company-role2'],
|
||||
};
|
||||
const token = await getApiToken(auth, config, user, password);
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
expect(spyNotCalled).not.toHaveBeenCalled();
|
||||
expect(token).toBeDefined();
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
const verifyJWT = (token: string, user: string, password: string, secret: string) => {
|
||||
const payload = verifyPayload(token, secret);
|
||||
expect(payload.name).toBe(user);
|
||||
expect(payload.groups).toBeDefined();
|
||||
expect(payload.groups).toEqual([
|
||||
'company-role1',
|
||||
'company-role2',
|
||||
'test',
|
||||
'$all',
|
||||
'$authenticated',
|
||||
'@all',
|
||||
'@authenticated',
|
||||
'all',
|
||||
]);
|
||||
expect(payload.real_groups).toBeDefined();
|
||||
expect(payload.real_groups).toEqual([
|
||||
'test',
|
||||
'$all',
|
||||
'$authenticated',
|
||||
'@all',
|
||||
'@authenticated',
|
||||
'all',
|
||||
]);
|
||||
};
|
||||
|
||||
const verifyAES = (token: string, user: string, password: string, secret: string) => {
|
||||
const payload = aesDecrypt(convertPayloadToBase64(token), secret).toString(
|
||||
CHARACTER_ENCODING.UTF8
|
||||
);
|
||||
const content = payload.split(':');
|
||||
|
||||
expect(content[0]).toBe(user);
|
||||
expect(content[0]).toBe(password);
|
||||
};
|
||||
|
||||
describe('getApiToken test', () => {
|
||||
test('should sign token with aes and security missing', async () => {
|
||||
const token = await signCredentials(
|
||||
'security-missing',
|
||||
'test',
|
||||
'test',
|
||||
'1234567',
|
||||
'aesEncrypt',
|
||||
'jwtEncrypt'
|
||||
);
|
||||
|
||||
verifyAES(token, 'test', 'test', '1234567');
|
||||
expect(_.isString(token)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should sign token with aes and security empty', async () => {
|
||||
const token = await signCredentials(
|
||||
'security-empty',
|
||||
'test',
|
||||
'test',
|
||||
'123456',
|
||||
'aesEncrypt',
|
||||
'jwtEncrypt'
|
||||
);
|
||||
|
||||
verifyAES(token, 'test', 'test', '123456');
|
||||
expect(_.isString(token)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should sign token with aes', async () => {
|
||||
const token = await signCredentials(
|
||||
'security-basic',
|
||||
'test',
|
||||
'test',
|
||||
'123456',
|
||||
'aesEncrypt',
|
||||
'jwtEncrypt'
|
||||
);
|
||||
|
||||
verifyAES(token, 'test', 'test', '123456');
|
||||
expect(_.isString(token)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should sign token with legacy and jwt disabled', async () => {
|
||||
const token = await signCredentials(
|
||||
'security-no-legacy',
|
||||
'test',
|
||||
'test',
|
||||
'x8T#ZCx=2t',
|
||||
'aesEncrypt',
|
||||
'jwtEncrypt'
|
||||
);
|
||||
|
||||
expect(_.isString(token)).toBeTruthy();
|
||||
verifyAES(token, 'test', 'test', 'x8T#ZCx=2t');
|
||||
});
|
||||
|
||||
test('should sign token with legacy enabled and jwt enabled', async () => {
|
||||
const token = await signCredentials(
|
||||
'security-jwt-legacy-enabled',
|
||||
'test',
|
||||
'test',
|
||||
'secret',
|
||||
'jwtEncrypt',
|
||||
'aesEncrypt'
|
||||
);
|
||||
|
||||
verifyJWT(token, 'test', 'test', 'secret');
|
||||
expect(_.isString(token)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should sign token with jwt enabled', async () => {
|
||||
const token = await signCredentials(
|
||||
'security-jwt',
|
||||
'test',
|
||||
'test',
|
||||
'secret',
|
||||
'jwtEncrypt',
|
||||
'aesEncrypt'
|
||||
);
|
||||
|
||||
expect(_.isString(token)).toBeTruthy();
|
||||
verifyJWT(token, 'test', 'test', 'secret');
|
||||
});
|
||||
|
||||
test('should sign with jwt whether legacy is disabled', async () => {
|
||||
const token = await signCredentials(
|
||||
'security-legacy-disabled',
|
||||
'test',
|
||||
'test',
|
||||
'secret',
|
||||
'jwtEncrypt',
|
||||
'aesEncrypt'
|
||||
);
|
||||
|
||||
expect(_.isString(token)).toBeTruthy();
|
||||
verifyJWT(token, 'test', 'test', 'secret');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMiddlewareCredentials test', () => {
|
||||
describe('should get AES credentials', () => {
|
||||
test.concurrent('should unpack aes token and credentials', async () => {
|
||||
const secret = 'secret';
|
||||
const user = 'test';
|
||||
const pass = 'test';
|
||||
const token = await signCredentials(
|
||||
'security-legacy',
|
||||
user,
|
||||
pass,
|
||||
secret,
|
||||
'aesEncrypt',
|
||||
'jwtEncrypt'
|
||||
);
|
||||
const config: Config = getConfig('security-legacy', secret);
|
||||
const security: Security = getSecurity(config);
|
||||
const credentials = getMiddlewareCredentials(security, secret, `Bearer ${token}`);
|
||||
expect(credentials).toBeDefined();
|
||||
// @ts-ignore
|
||||
expect(credentials.user).toEqual(user);
|
||||
// @ts-ignore
|
||||
expect(credentials.password).toEqual(pass);
|
||||
});
|
||||
|
||||
test.concurrent('should unpack aes token and credentials', async () => {
|
||||
const secret = 'secret';
|
||||
const user = 'test';
|
||||
const pass = 'test';
|
||||
const token = buildUserBuffer(user, pass).toString('base64');
|
||||
const config: Config = getConfig('security-legacy', secret);
|
||||
const security: Security = getSecurity(config);
|
||||
const credentials = getMiddlewareCredentials(security, secret, `Basic ${token}`);
|
||||
expect(credentials).toBeDefined();
|
||||
// @ts-ignore
|
||||
expect(credentials.user).toEqual(user);
|
||||
// @ts-ignore
|
||||
expect(credentials.password).toEqual(pass);
|
||||
});
|
||||
|
||||
test.concurrent('should return empty credential wrong secret key', async () => {
|
||||
const secret = 'secret';
|
||||
const token = await signCredentials(
|
||||
'security-legacy',
|
||||
'test',
|
||||
'test',
|
||||
secret,
|
||||
'aesEncrypt',
|
||||
'jwtEncrypt'
|
||||
);
|
||||
const config: Config = getConfig('security-legacy', secret);
|
||||
const security: Security = getSecurity(config);
|
||||
const credentials = getMiddlewareCredentials(
|
||||
security,
|
||||
'BAD_SECRET',
|
||||
buildToken(TOKEN_BEARER, token)
|
||||
);
|
||||
expect(credentials).not.toBeDefined();
|
||||
});
|
||||
|
||||
test.concurrent('should return empty credential wrong scheme', async () => {
|
||||
const secret = 'secret';
|
||||
const token = await signCredentials(
|
||||
'security-legacy',
|
||||
'test',
|
||||
'test',
|
||||
secret,
|
||||
'aesEncrypt',
|
||||
'jwtEncrypt'
|
||||
);
|
||||
const config: Config = getConfig('security-legacy', secret);
|
||||
const security: Security = getSecurity(config);
|
||||
const credentials = getMiddlewareCredentials(
|
||||
security,
|
||||
secret,
|
||||
buildToken('BAD_SCHEME', token)
|
||||
);
|
||||
expect(credentials).not.toBeDefined();
|
||||
});
|
||||
|
||||
test.concurrent('should return empty credential corrupted payload', async () => {
|
||||
const secret = 'secret';
|
||||
const config: Config = getConfig('security-legacy', secret);
|
||||
const auth: IAuth = new Auth(config);
|
||||
const token = auth.aesEncrypt(Buffer.from(`corruptedBuffer`)).toString('base64');
|
||||
const security: Security = getSecurity(config);
|
||||
const credentials = getMiddlewareCredentials(
|
||||
security,
|
||||
secret,
|
||||
buildToken(TOKEN_BEARER, token)
|
||||
);
|
||||
expect(credentials).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('should get JWT credentials', () => {
|
||||
test('should return anonymous whether token is corrupted', () => {
|
||||
const config: Config = getConfig('security-jwt', '12345');
|
||||
const security: Security = getSecurity(config);
|
||||
const credentials = getMiddlewareCredentials(
|
||||
security,
|
||||
'12345',
|
||||
buildToken(TOKEN_BEARER, 'fakeToken')
|
||||
) as RemoteUser;
|
||||
|
||||
expect(credentials).toBeDefined();
|
||||
expect(credentials.name).not.toBeDefined();
|
||||
expect(credentials.real_groups).toBeDefined();
|
||||
expect(credentials.real_groups).toEqual([]);
|
||||
expect(credentials.groups).toEqual(['$all', '$anonymous', '@all', '@anonymous']);
|
||||
});
|
||||
|
||||
test('should return anonymous whether token and scheme are corrupted', () => {
|
||||
const config: Config = getConfig('security-jwt', '12345');
|
||||
const security: Security = getSecurity(config);
|
||||
const credentials = getMiddlewareCredentials(
|
||||
security,
|
||||
'12345',
|
||||
buildToken('FakeScheme', 'fakeToken')
|
||||
);
|
||||
|
||||
expect(credentials).not.toBeDefined();
|
||||
});
|
||||
|
||||
test('should verify succesfully a JWT token', async () => {
|
||||
const secret = 'secret';
|
||||
const user = 'test';
|
||||
const config: Config = getConfig('security-jwt', secret);
|
||||
const token = await signCredentials(
|
||||
'security-jwt',
|
||||
user,
|
||||
'secretTest',
|
||||
secret,
|
||||
'jwtEncrypt',
|
||||
'aesEncrypt'
|
||||
);
|
||||
const security: Security = getSecurity(config);
|
||||
const credentials = getMiddlewareCredentials(
|
||||
security,
|
||||
secret,
|
||||
buildToken(TOKEN_BEARER, token)
|
||||
) as RemoteUser;
|
||||
expect(credentials).toBeDefined();
|
||||
expect(credentials.name).toEqual(user);
|
||||
expect(credentials.real_groups).toBeDefined();
|
||||
expect(credentials.real_groups).toEqual([
|
||||
'test',
|
||||
'$all',
|
||||
'$authenticated',
|
||||
'@all',
|
||||
'@authenticated',
|
||||
'all',
|
||||
]);
|
||||
expect(credentials.groups).toEqual([
|
||||
'company-role1',
|
||||
'company-role2',
|
||||
'test',
|
||||
'$all',
|
||||
'$authenticated',
|
||||
'@all',
|
||||
'@authenticated',
|
||||
'all',
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -61,7 +61,7 @@ const checkDefaultConfPackages = (config) => {
|
|||
expect(config.url_prefix).toBeUndefined();
|
||||
expect(config.url_prefix).toBeUndefined();
|
||||
expect(config.security).toEqual({
|
||||
api: { legacy: true },
|
||||
api: { legacy: true, migrateToSecureLegacySignature: false },
|
||||
web: { sign: { expiresIn: '1h' }, verify: {} },
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"list":[],"secret":"12c39716d7c75d50b9988255fff332e1b066bad04e10fff9cba42434bc5fe19e"}
|
||||
{"list":[],"secret":"12c39716d7c75d50b9988255fff332e1"}
|
BIN
yarn.lock
BIN
yarn.lock
Binary file not shown.
Loading…
Reference in a new issue