@verdaccio/config 7.0.0-next-7.13 → 7.0.0-next-7.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @verdaccio/config
2
2
 
3
+ ## 7.0.0-next-7.15
4
+
5
+ ### Minor Changes
6
+
7
+ - bd8703e: feat: add migrateToSecureLegacySignature and remove enhancedLegacySignature property
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [bd8703e]
12
+ - @verdaccio/core@7.0.0-next-7.15
13
+ - @verdaccio/utils@7.0.0-next-7.15
14
+
15
+ ## 7.0.0-next-7.14
16
+
17
+ ### Patch Changes
18
+
19
+ - @verdaccio/core@7.0.0-next-7.14
20
+ - @verdaccio/utils@7.0.0-next-7.14
21
+
3
22
  ## 7.0.0-next-7.13
4
23
 
5
24
  ### Patch Changes
package/build/config.d.ts CHANGED
@@ -4,6 +4,7 @@ export declare const defaultUserRateLimiting: {
4
4
  windowMs: number;
5
5
  max: number;
6
6
  };
7
+ export declare function isNodeVersionGreaterThan21(): boolean;
7
8
  /**
8
9
  * Coordinates the application configuration
9
10
  */
@@ -23,23 +24,30 @@ declare class Config implements AppConfig {
23
24
  plugins: string | void | null;
24
25
  security: Security;
25
26
  serverSettings: ServerSettingsConf;
27
+ private configOverrideOptions;
26
28
  secret: string;
27
29
  flags: FlagsConfig;
28
30
  userRateLimit: RateLimit;
29
- private configOptions;
30
31
  constructor(config: ConfigYaml & {
31
32
  config_path: string;
32
- }, configOptions?: {
33
- forceEnhancedLegacySignature: boolean;
33
+ }, configOverrideOptions?: {
34
+ forceMigrateToSecureLegacySignature: boolean;
34
35
  });
35
- getEnhancedLegacySignature(): boolean;
36
+ getMigrateToSecureLegacySignature(): boolean;
36
37
  getConfigPath(): string;
37
38
  /**
38
39
  * Check for package spec
39
40
  */
40
41
  getMatchedPackagesSpec(pkgName: string): PackageAccess | void;
41
42
  /**
42
- * Store or create whether receive a secret key
43
+ * Verify if the secret complies with the required structure
44
+ * - If the secret is not provided, it will generate a new one
45
+ * - For any Node.js version the new secret will be 32 characters long (to allow compatibility with modern Node.js versions)
46
+ * - If the secret is provided:
47
+ * - If Node.js 22 or higher, the secret must be 32 characters long thus the application will fail on startup
48
+ * - If Node.js 21 or lower, the secret will be used as is but will display a deprecation warning
49
+ * - If the property `security.api.migrateToSecureLegacySignature` is provided and set to true, the secret will be
50
+ * generated with the new signature model
43
51
  * @secret external secret key
44
52
  */
45
53
  checkSecretKey(secret?: string): string;
package/build/config.js CHANGED
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.defaultUserRateLimiting = exports.WEB_TITLE = exports.Config = void 0;
7
+ exports.isNodeVersionGreaterThan21 = isNodeVersionGreaterThan21;
7
8
  var _assert = _interopRequireDefault(require("assert"));
8
9
  var _debug = _interopRequireDefault(require("debug"));
9
10
  var _lodash = _interopRequireDefault(require("lodash"));
@@ -28,6 +29,11 @@ const defaultUserRateLimiting = exports.defaultUserRateLimiting = {
28
29
  // 15 minutes
29
30
  max: 1000
30
31
  };
32
+ function isNodeVersionGreaterThan21() {
33
+ const [major, minor] = process.versions.node.split('.').map(Number);
34
+ return major > 21 || major === 21 && minor >= 0;
35
+ }
36
+ const TOKEN_VALID_LENGTH = 32;
31
37
 
32
38
  /**
33
39
  * Coordinates the application configuration
@@ -44,12 +50,11 @@ class Config {
44
50
  // allows switch a new legacy aes signature token signature
45
51
  // for older versions do not want to have this new signature model
46
52
  // this property must be false
47
- configOptions = {
48
- forceEnhancedLegacySignature: true
53
+ configOverrideOptions = {
54
+ forceMigrateToSecureLegacySignature: true
49
55
  }) {
50
56
  var _config$flags$searchR, _config$flags, _config$flags$changeP, _config$flags2;
51
57
  const self = this;
52
- this.configOptions = configOptions;
53
58
  this.storage = process.env.VERDACCIO_STORAGE_PATH || config.storage;
54
59
  if (!config.configPath) {
55
60
  var _config$config_path;
@@ -60,11 +65,18 @@ class Config {
60
65
  throw new Error('configPath property is required');
61
66
  }
62
67
  }
68
+ this.configOverrideOptions = configOverrideOptions;
63
69
  this.configPath = config.configPath;
64
70
  this.self_path = this.configPath;
65
71
  debug('config path: %s', this.configPath);
66
72
  this.plugins = config.plugins;
67
- this.security = _lodash.default.merge(_security.defaultSecurity, config.security);
73
+ this.security = _lodash.default.merge(
74
+ // override the default security configuration via constructor
75
+ _lodash.default.merge(_security.defaultSecurity, {
76
+ api: {
77
+ migrateToSecureLegacySignature: this.configOverrideOptions.forceMigrateToSecureLegacySignature
78
+ }
79
+ }), config.security);
68
80
  this.serverSettings = _serverSettings.default;
69
81
  this.flags = {
70
82
  searchRemote: (_config$flags$searchR = (_config$flags = config.flags) === null || _config$flags === void 0 ? void 0 : _config$flags.searchRemote) !== null && _config$flags$searchR !== void 0 ? _config$flags$searchR : true,
@@ -112,14 +124,8 @@ class Config {
112
124
  this.server_id = (0, _utils.generateRandomHexString)(6);
113
125
  }
114
126
  }
115
- getEnhancedLegacySignature() {
116
- if (typeof (this === null || this === void 0 ? void 0 : this.security.enhancedLegacySignature) !== 'undefined') {
117
- if (this.security.enhancedLegacySignature === true) {
118
- return true;
119
- }
120
- return false;
121
- }
122
- return this.configOptions.forceEnhancedLegacySignature;
127
+ getMigrateToSecureLegacySignature() {
128
+ return this.security.api.migrateToSecureLegacySignature;
123
129
  }
124
130
  getConfigPath() {
125
131
  return this.configPath;
@@ -134,35 +140,65 @@ class Config {
134
140
  }
135
141
 
136
142
  /**
137
- * Store or create whether receive a secret key
143
+ * Verify if the secret complies with the required structure
144
+ * - If the secret is not provided, it will generate a new one
145
+ * - For any Node.js version the new secret will be 32 characters long (to allow compatibility with modern Node.js versions)
146
+ * - If the secret is provided:
147
+ * - If Node.js 22 or higher, the secret must be 32 characters long thus the application will fail on startup
148
+ * - If Node.js 21 or lower, the secret will be used as is but will display a deprecation warning
149
+ * - If the property `security.api.migrateToSecureLegacySignature` is provided and set to true, the secret will be
150
+ * generated with the new signature model
138
151
  * @secret external secret key
139
152
  */
140
153
  checkSecretKey(secret) {
141
- var _this$security, _this$secret;
142
- debug('check secret key');
154
+ debug('checking secret key init');
143
155
  if (typeof secret === 'string' && _lodash.default.isEmpty(secret) === false) {
156
+ debug('checking secret key length %s', secret.length);
157
+ if (secret.length > TOKEN_VALID_LENGTH) {
158
+ if (isNodeVersionGreaterThan21()) {
159
+ debug('is node version greater than 21');
160
+ if (this.getMigrateToSecureLegacySignature() === true) {
161
+ this.secret = (0, _token.generateRandomSecretKey)();
162
+ debug('rewriting secret key with length %s', this.secret.length);
163
+ return this.secret;
164
+ }
165
+ // oops, user needs to generate a new secret key
166
+ debug('secret does not comply with the required length, current length %d, application will fail on startup', secret.length);
167
+ throw new Error(`Invalid storage secret key length, must be 32 characters long but is ${secret.length}.
168
+ The secret length in Node.js 22 or higher must be 32 characters long. Please consider generate a new one.
169
+ Learn more at https://verdaccio.org/docs/configuration/#.verdaccio-db`);
170
+ } else {
171
+ debug('is node version lower than 22');
172
+ if (this.getMigrateToSecureLegacySignature() === true) {
173
+ this.secret = (0, _token.generateRandomSecretKey)();
174
+ debug('rewriting secret key with length %s', this.secret.length);
175
+ return this.secret;
176
+ }
177
+ debug('triggering deprecation warning for secret key length %s', secret.length);
178
+ // still using Node.js versions previous to 22, but we need to emit a deprecation warning
179
+ // deprecation warning, secret key is too long and must be 32
180
+ // this will be removed in the next major release and will produce an error
181
+ _core.warningUtils.emit(_warningUtils.Codes.VERWAR007);
182
+ this.secret = secret;
183
+ return this.secret;
184
+ }
185
+ } else if (secret.length === TOKEN_VALID_LENGTH) {
186
+ debug('detected valid secret key length %s', secret.length);
187
+ this.secret = secret;
188
+ return this.secret;
189
+ }
190
+ debug('reusing previous key with length %s', secret.length);
144
191
  this.secret = secret;
145
- debug('reusing previous key');
146
- return secret;
147
- }
148
- // generate a new a secret key
149
- // FUTURE: this might be an external secret key, perhaps within config file?
150
- debug('generating a new secret key');
151
- if (this.getEnhancedLegacySignature()) {
152
- debug('key generated with "enhanced" legacy signature user config');
153
- this.secret = (0, _token.generateRandomSecretKey)();
192
+ return this.secret;
154
193
  } else {
155
- debug('key generated with legacy signature user config');
156
- this.secret = (0, _utils.generateRandomHexString)(32);
157
- }
158
- // set this to false allow use old token signature and is not recommended
159
- // only use for migration reasons, major release will remove this property and
160
- // set it by default
161
- if (((_this$security = this.security) === null || _this$security === void 0 ? void 0 : _this$security.enhancedLegacySignature) === false) {
162
- _core.warningUtils.emit(_warningUtils.Codes.VERWAR005);
194
+ var _this$secret;
195
+ // generate a new a secret key
196
+ // FUTURE: this might be an external secret key, perhaps within config file?
197
+ debug('generating a new secret key');
198
+ this.secret = (0, _token.generateRandomSecretKey)();
199
+ debug('generated a new secret key length %s', (_this$secret = this.secret) === null || _this$secret === void 0 ? void 0 : _this$secret.length);
200
+ return this.secret;
163
201
  }
164
- debug('generated a new secret key length %s', (_this$secret = this.secret) === null || _this$secret === void 0 ? void 0 : _this$secret.length);
165
- return this.secret;
166
202
  }
167
203
  }
168
204
  exports.Config = Config;
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","names":["_assert","_interopRequireDefault","require","_debug","_lodash","_core","_warningUtils","_utils","_agent","_packageAccess","_security","_serverSettings","_token","_uplinks","obj","__esModule","default","strategicConfigProps","allowedEnvConfig","debug","buildDebug","WEB_TITLE","exports","defaultUserRateLimiting","windowMs","max","Config","constructor","config","configOptions","forceEnhancedLegacySignature","_config$flags$searchR","_config$flags","_config$flags$changeP","_config$flags2","self","storage","process","env","VERDACCIO_STORAGE_PATH","configPath","_config$config_path","config_path","self_path","Error","plugins","security","_","merge","defaultSecurity","serverSettings","flags","searchRemote","changePassword","user_agent","configProp","getUserAgent","userRateLimit","assert","isObject","APP_ERROR","CONFIG_NOT_VALID","forEach","x","uplinks","sanityCheckUplinksProps","uplinkSanityCheck","packages","normalisePackageAccess","envConf","toUpperCase","server_id","generateRandomHexString","getEnhancedLegacySignature","enhancedLegacySignature","getConfigPath","getMatchedPackagesSpec","pkgName","checkSecretKey","secret","_this$security","_this$secret","isEmpty","generateRandomSecretKey","warningUtils","emit","Codes","VERWAR005","length"],"sources":["../src/config.ts"],"sourcesContent":["import assert from 'assert';\nimport buildDebug from 'debug';\nimport _ from 'lodash';\n\nimport { APP_ERROR, warningUtils } from '@verdaccio/core';\nimport { Codes } from '@verdaccio/core/build/warning-utils';\nimport {\n Config as AppConfig,\n AuthConf,\n ConfigYaml,\n FlagsConfig,\n PackageAccess,\n PackageList,\n RateLimit,\n Security,\n ServerSettingsConf,\n} from '@verdaccio/types';\nimport { generateRandomHexString, getMatchedPackagesSpec, isObject } from '@verdaccio/utils';\n\nimport { getUserAgent } from './agent';\nimport { normalisePackageAccess } from './package-access';\nimport { defaultSecurity } from './security';\nimport serverSettings from './serverSettings';\nimport { generateRandomSecretKey } from './token';\nimport { sanityCheckUplinksProps, uplinkSanityCheck } from './uplinks';\n\nconst strategicConfigProps = ['uplinks', 'packages'];\nconst allowedEnvConfig = ['http_proxy', 'https_proxy', 'no_proxy'];\nconst debug = buildDebug('verdaccio:config');\n\nexport const WEB_TITLE = 'Verdaccio';\n\n// we limit max 1000 request per 15 minutes on user endpoints\nexport const defaultUserRateLimiting = {\n windowMs: 15 * 60 * 1000, // 15 minutes\n max: 1000,\n};\n\n/**\n * Coordinates the application configuration\n */\nclass Config implements AppConfig {\n public user_agent: string | undefined;\n public uplinks: any;\n public packages: PackageList;\n public users: any;\n public auth: AuthConf;\n public server_id: string;\n public configPath: string;\n /**\n * @deprecated use configPath or config.getConfigPath();\n */\n public self_path: string;\n public storage: string | void;\n\n public plugins: string | void | null;\n public security: Security;\n public serverSettings: ServerSettingsConf;\n // @ts-ignore\n public secret: string;\n public flags: FlagsConfig;\n public userRateLimit: RateLimit;\n private configOptions: { forceEnhancedLegacySignature: boolean };\n public constructor(\n config: ConfigYaml & { config_path: string },\n // forceEnhancedLegacySignature is a property that\n // allows switch a new legacy aes signature token signature\n // for older versions do not want to have this new signature model\n // this property must be false\n configOptions = { forceEnhancedLegacySignature: true }\n ) {\n const self = this;\n this.configOptions = configOptions;\n this.storage = process.env.VERDACCIO_STORAGE_PATH || config.storage;\n if (!config.configPath) {\n // backport self_path for previous to version 6\n // @ts-expect-error\n config.configPath = config.config_path ?? config.self_path;\n if (!config.configPath) {\n throw new Error('configPath property is required');\n }\n }\n this.configPath = config.configPath;\n this.self_path = this.configPath;\n debug('config path: %s', this.configPath);\n this.plugins = config.plugins;\n this.security = _.merge(defaultSecurity, config.security);\n this.serverSettings = serverSettings;\n this.flags = {\n searchRemote: config.flags?.searchRemote ?? true,\n changePassword: config.flags?.changePassword ?? false,\n };\n this.user_agent = config.user_agent;\n\n for (const configProp in config) {\n if (self[configProp] == null) {\n self[configProp] = config[configProp];\n }\n }\n\n if (typeof this.user_agent === 'undefined') {\n // by default user agent is hidden\n debug('set default user agent');\n this.user_agent = getUserAgent(false);\n }\n\n this.userRateLimit = { ...defaultUserRateLimiting, ...config?.userRateLimit };\n\n // some weird shell scripts are valid yaml files parsed as string\n assert(_.isObject(config), APP_ERROR.CONFIG_NOT_VALID);\n\n // sanity check for strategic config properties\n strategicConfigProps.forEach(function (x): void {\n if (self[x] == null) {\n self[x] = {};\n }\n\n assert(isObject(self[x]), `CONFIG: bad \"${x}\" value (object expected)`);\n });\n\n this.uplinks = sanityCheckUplinksProps(uplinkSanityCheck(this.uplinks));\n this.packages = normalisePackageAccess(self.packages);\n\n // loading these from ENV if aren't in config\n allowedEnvConfig.forEach((envConf): void => {\n if (!(envConf in self)) {\n self[envConf] = process.env[envConf] || process.env[envConf.toUpperCase()];\n }\n });\n\n // unique identifier of self server (or a cluster), used to avoid loops\n // @ts-ignore\n if (!this.server_id) {\n this.server_id = generateRandomHexString(6);\n }\n }\n\n public getEnhancedLegacySignature() {\n if (typeof this?.security.enhancedLegacySignature !== 'undefined') {\n if (this.security.enhancedLegacySignature === true) {\n return true;\n }\n return false;\n }\n return this.configOptions.forceEnhancedLegacySignature;\n }\n\n public getConfigPath() {\n return this.configPath;\n }\n\n /**\n * Check for package spec\n */\n public getMatchedPackagesSpec(pkgName: string): PackageAccess | void {\n // TODO: remove this method and replace by library utils\n return getMatchedPackagesSpec(pkgName, this.packages);\n }\n\n /**\n * Store or create whether receive a secret key\n * @secret external secret key\n */\n public checkSecretKey(secret?: string): string {\n debug('check secret key');\n if (typeof secret === 'string' && _.isEmpty(secret) === false) {\n this.secret = secret;\n debug('reusing previous key');\n return secret;\n }\n // generate a new a secret key\n // FUTURE: this might be an external secret key, perhaps within config file?\n debug('generating a new secret key');\n\n if (this.getEnhancedLegacySignature()) {\n debug('key generated with \"enhanced\" legacy signature user config');\n this.secret = generateRandomSecretKey();\n } else {\n debug('key generated with legacy signature user config');\n this.secret = generateRandomHexString(32);\n }\n // set this to false allow use old token signature and is not recommended\n // only use for migration reasons, major release will remove this property and\n // set it by default\n if (this.security?.enhancedLegacySignature === false) {\n warningUtils.emit(Codes.VERWAR005);\n }\n\n debug('generated a new secret key length %s', this.secret?.length);\n return this.secret;\n }\n}\n\nexport { Config };\n"],"mappings":";;;;;;AAAA,IAAAA,OAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,MAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,OAAA,GAAAH,sBAAA,CAAAC,OAAA;AAEA,IAAAG,KAAA,GAAAH,OAAA;AACA,IAAAI,aAAA,GAAAJ,OAAA;AAYA,IAAAK,MAAA,GAAAL,OAAA;AAEA,IAAAM,MAAA,GAAAN,OAAA;AACA,IAAAO,cAAA,GAAAP,OAAA;AACA,IAAAQ,SAAA,GAAAR,OAAA;AACA,IAAAS,eAAA,GAAAV,sBAAA,CAAAC,OAAA;AACA,IAAAU,MAAA,GAAAV,OAAA;AACA,IAAAW,QAAA,GAAAX,OAAA;AAAuE,SAAAD,uBAAAa,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAEvE,MAAMG,oBAAoB,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC;AACpD,MAAMC,gBAAgB,GAAG,CAAC,YAAY,EAAE,aAAa,EAAE,UAAU,CAAC;AAClE,MAAMC,KAAK,GAAG,IAAAC,cAAU,EAAC,kBAAkB,CAAC;AAErC,MAAMC,SAAS,GAAAC,OAAA,CAAAD,SAAA,GAAG,WAAW;;AAEpC;AACO,MAAME,uBAAuB,GAAAD,OAAA,CAAAC,uBAAA,GAAG;EACrCC,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;EAAE;EAC1BC,GAAG,EAAE;AACP,CAAC;;AAED;AACA;AACA;AACA,MAAMC,MAAM,CAAsB;EAQhC;AACF;AACA;;EAOE;;EAKOC,WAAWA,CAChBC,MAA4C;EAC5C;EACA;EACA;EACA;EACAC,aAAa,GAAG;IAAEC,4BAA4B,EAAE;EAAK,CAAC,EACtD;IAAA,IAAAC,qBAAA,EAAAC,aAAA,EAAAC,qBAAA,EAAAC,cAAA;IACA,MAAMC,IAAI,GAAG,IAAI;IACjB,IAAI,CAACN,aAAa,GAAGA,aAAa;IAClC,IAAI,CAACO,OAAO,GAAGC,OAAO,CAACC,GAAG,CAACC,sBAAsB,IAAIX,MAAM,CAACQ,OAAO;IACnE,IAAI,CAACR,MAAM,CAACY,UAAU,EAAE;MAAA,IAAAC,mBAAA;MACtB;MACA;MACAb,MAAM,CAACY,UAAU,IAAAC,mBAAA,GAAGb,MAAM,CAACc,WAAW,cAAAD,mBAAA,cAAAA,mBAAA,GAAIb,MAAM,CAACe,SAAS;MAC1D,IAAI,CAACf,MAAM,CAACY,UAAU,EAAE;QACtB,MAAM,IAAII,KAAK,CAAC,iCAAiC,CAAC;MACpD;IACF;IACA,IAAI,CAACJ,UAAU,GAAGZ,MAAM,CAACY,UAAU;IACnC,IAAI,CAACG,SAAS,GAAG,IAAI,CAACH,UAAU;IAChCrB,KAAK,CAAC,iBAAiB,EAAE,IAAI,CAACqB,UAAU,CAAC;IACzC,IAAI,CAACK,OAAO,GAAGjB,MAAM,CAACiB,OAAO;IAC7B,IAAI,CAACC,QAAQ,GAAGC,eAAC,CAACC,KAAK,CAACC,yBAAe,EAAErB,MAAM,CAACkB,QAAQ,CAAC;IACzD,IAAI,CAACI,cAAc,GAAGA,uBAAc;IACpC,IAAI,CAACC,KAAK,GAAG;MACXC,YAAY,GAAArB,qBAAA,IAAAC,aAAA,GAAEJ,MAAM,CAACuB,KAAK,cAAAnB,aAAA,uBAAZA,aAAA,CAAcoB,YAAY,cAAArB,qBAAA,cAAAA,qBAAA,GAAI,IAAI;MAChDsB,cAAc,GAAApB,qBAAA,IAAAC,cAAA,GAAEN,MAAM,CAACuB,KAAK,cAAAjB,cAAA,uBAAZA,cAAA,CAAcmB,cAAc,cAAApB,qBAAA,cAAAA,qBAAA,GAAI;IAClD,CAAC;IACD,IAAI,CAACqB,UAAU,GAAG1B,MAAM,CAAC0B,UAAU;IAEnC,KAAK,MAAMC,UAAU,IAAI3B,MAAM,EAAE;MAC/B,IAAIO,IAAI,CAACoB,UAAU,CAAC,IAAI,IAAI,EAAE;QAC5BpB,IAAI,CAACoB,UAAU,CAAC,GAAG3B,MAAM,CAAC2B,UAAU,CAAC;MACvC;IACF;IAEA,IAAI,OAAO,IAAI,CAACD,UAAU,KAAK,WAAW,EAAE;MAC1C;MACAnC,KAAK,CAAC,wBAAwB,CAAC;MAC/B,IAAI,CAACmC,UAAU,GAAG,IAAAE,mBAAY,EAAC,KAAK,CAAC;IACvC;IAEA,IAAI,CAACC,aAAa,GAAG;MAAE,GAAGlC,uBAAuB;MAAE,IAAGK,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAE6B,aAAa;IAAC,CAAC;;IAE7E;IACA,IAAAC,eAAM,EAACX,eAAC,CAACY,QAAQ,CAAC/B,MAAM,CAAC,EAAEgC,eAAS,CAACC,gBAAgB,CAAC;;IAEtD;IACA5C,oBAAoB,CAAC6C,OAAO,CAAC,UAAUC,CAAC,EAAQ;MAC9C,IAAI5B,IAAI,CAAC4B,CAAC,CAAC,IAAI,IAAI,EAAE;QACnB5B,IAAI,CAAC4B,CAAC,CAAC,GAAG,CAAC,CAAC;MACd;MAEA,IAAAL,eAAM,EAAC,IAAAC,eAAQ,EAACxB,IAAI,CAAC4B,CAAC,CAAC,CAAC,EAAG,gBAAeA,CAAE,2BAA0B,CAAC;IACzE,CAAC,CAAC;IAEF,IAAI,CAACC,OAAO,GAAG,IAAAC,gCAAuB,EAAC,IAAAC,0BAAiB,EAAC,IAAI,CAACF,OAAO,CAAC,CAAC;IACvE,IAAI,CAACG,QAAQ,GAAG,IAAAC,qCAAsB,EAACjC,IAAI,CAACgC,QAAQ,CAAC;;IAErD;IACAjD,gBAAgB,CAAC4C,OAAO,CAAEO,OAAO,IAAW;MAC1C,IAAI,EAAEA,OAAO,IAAIlC,IAAI,CAAC,EAAE;QACtBA,IAAI,CAACkC,OAAO,CAAC,GAAGhC,OAAO,CAACC,GAAG,CAAC+B,OAAO,CAAC,IAAIhC,OAAO,CAACC,GAAG,CAAC+B,OAAO,CAACC,WAAW,CAAC,CAAC,CAAC;MAC5E;IACF,CAAC,CAAC;;IAEF;IACA;IACA,IAAI,CAAC,IAAI,CAACC,SAAS,EAAE;MACnB,IAAI,CAACA,SAAS,GAAG,IAAAC,8BAAuB,EAAC,CAAC,CAAC;IAC7C;EACF;EAEOC,0BAA0BA,CAAA,EAAG;IAClC,IAAI,QAAO,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE3B,QAAQ,CAAC4B,uBAAuB,MAAK,WAAW,EAAE;MACjE,IAAI,IAAI,CAAC5B,QAAQ,CAAC4B,uBAAuB,KAAK,IAAI,EAAE;QAClD,OAAO,IAAI;MACb;MACA,OAAO,KAAK;IACd;IACA,OAAO,IAAI,CAAC7C,aAAa,CAACC,4BAA4B;EACxD;EAEO6C,aAAaA,CAAA,EAAG;IACrB,OAAO,IAAI,CAACnC,UAAU;EACxB;;EAEA;AACF;AACA;EACSoC,sBAAsBA,CAACC,OAAe,EAAwB;IACnE;IACA,OAAO,IAAAD,6BAAsB,EAACC,OAAO,EAAE,IAAI,CAACV,QAAQ,CAAC;EACvD;;EAEA;AACF;AACA;AACA;EACSW,cAAcA,CAACC,MAAe,EAAU;IAAA,IAAAC,cAAA,EAAAC,YAAA;IAC7C9D,KAAK,CAAC,kBAAkB,CAAC;IACzB,IAAI,OAAO4D,MAAM,KAAK,QAAQ,IAAIhC,eAAC,CAACmC,OAAO,CAACH,MAAM,CAAC,KAAK,KAAK,EAAE;MAC7D,IAAI,CAACA,MAAM,GAAGA,MAAM;MACpB5D,KAAK,CAAC,sBAAsB,CAAC;MAC7B,OAAO4D,MAAM;IACf;IACA;IACA;IACA5D,KAAK,CAAC,6BAA6B,CAAC;IAEpC,IAAI,IAAI,CAACsD,0BAA0B,CAAC,CAAC,EAAE;MACrCtD,KAAK,CAAC,4DAA4D,CAAC;MACnE,IAAI,CAAC4D,MAAM,GAAG,IAAAI,8BAAuB,EAAC,CAAC;IACzC,CAAC,MAAM;MACLhE,KAAK,CAAC,iDAAiD,CAAC;MACxD,IAAI,CAAC4D,MAAM,GAAG,IAAAP,8BAAuB,EAAC,EAAE,CAAC;IAC3C;IACA;IACA;IACA;IACA,IAAI,EAAAQ,cAAA,OAAI,CAAClC,QAAQ,cAAAkC,cAAA,uBAAbA,cAAA,CAAeN,uBAAuB,MAAK,KAAK,EAAE;MACpDU,kBAAY,CAACC,IAAI,CAACC,mBAAK,CAACC,SAAS,CAAC;IACpC;IAEApE,KAAK,CAAC,sCAAsC,GAAA8D,YAAA,GAAE,IAAI,CAACF,MAAM,cAAAE,YAAA,uBAAXA,YAAA,CAAaO,MAAM,CAAC;IAClE,OAAO,IAAI,CAACT,MAAM;EACpB;AACF;AAACzD,OAAA,CAAAI,MAAA,GAAAA,MAAA"}
1
+ {"version":3,"file":"config.js","names":["_assert","_interopRequireDefault","require","_debug","_lodash","_core","_warningUtils","_utils","_agent","_packageAccess","_security","_serverSettings","_token","_uplinks","obj","__esModule","default","strategicConfigProps","allowedEnvConfig","debug","buildDebug","WEB_TITLE","exports","defaultUserRateLimiting","windowMs","max","isNodeVersionGreaterThan21","major","minor","process","versions","node","split","map","Number","TOKEN_VALID_LENGTH","Config","constructor","config","configOverrideOptions","forceMigrateToSecureLegacySignature","_config$flags$searchR","_config$flags","_config$flags$changeP","_config$flags2","self","storage","env","VERDACCIO_STORAGE_PATH","configPath","_config$config_path","config_path","self_path","Error","plugins","security","_","merge","defaultSecurity","api","migrateToSecureLegacySignature","serverSettings","flags","searchRemote","changePassword","user_agent","configProp","getUserAgent","userRateLimit","assert","isObject","APP_ERROR","CONFIG_NOT_VALID","forEach","x","uplinks","sanityCheckUplinksProps","uplinkSanityCheck","packages","normalisePackageAccess","envConf","toUpperCase","server_id","generateRandomHexString","getMigrateToSecureLegacySignature","getConfigPath","getMatchedPackagesSpec","pkgName","checkSecretKey","secret","isEmpty","length","generateRandomSecretKey","warningUtils","emit","Codes","VERWAR007","_this$secret"],"sources":["../src/config.ts"],"sourcesContent":["import assert from 'assert';\nimport buildDebug from 'debug';\nimport _ from 'lodash';\n\nimport { APP_ERROR, warningUtils } from '@verdaccio/core';\nimport { Codes } from '@verdaccio/core/build/warning-utils';\nimport {\n Config as AppConfig,\n AuthConf,\n ConfigYaml,\n FlagsConfig,\n PackageAccess,\n PackageList,\n RateLimit,\n Security,\n ServerSettingsConf,\n} from '@verdaccio/types';\nimport { generateRandomHexString, getMatchedPackagesSpec, isObject } from '@verdaccio/utils';\n\nimport { getUserAgent } from './agent';\nimport { normalisePackageAccess } from './package-access';\nimport { defaultSecurity } from './security';\nimport serverSettings from './serverSettings';\nimport { generateRandomSecretKey } from './token';\nimport { sanityCheckUplinksProps, uplinkSanityCheck } from './uplinks';\n\nconst strategicConfigProps = ['uplinks', 'packages'];\nconst allowedEnvConfig = ['http_proxy', 'https_proxy', 'no_proxy'];\nconst debug = buildDebug('verdaccio:config');\n\nexport const WEB_TITLE = 'Verdaccio';\n\n// we limit max 1000 request per 15 minutes on user endpoints\nexport const defaultUserRateLimiting = {\n windowMs: 15 * 60 * 1000, // 15 minutes\n max: 1000,\n};\n\nexport function isNodeVersionGreaterThan21() {\n const [major, minor] = process.versions.node.split('.').map(Number);\n return major > 21 || (major === 21 && minor >= 0);\n}\n\nconst TOKEN_VALID_LENGTH = 32;\n\n/**\n * Coordinates the application configuration\n */\nclass Config implements AppConfig {\n public user_agent: string | undefined;\n public uplinks: any;\n public packages: PackageList;\n public users: any;\n public auth: AuthConf;\n public server_id: string;\n public configPath: string;\n /**\n * @deprecated use configPath or config.getConfigPath();\n */\n public self_path: string;\n public storage: string | void;\n\n public plugins: string | void | null;\n public security: Security;\n public serverSettings: ServerSettingsConf;\n private configOverrideOptions: { forceMigrateToSecureLegacySignature: boolean };\n // @ts-ignore\n public secret: string;\n public flags: FlagsConfig;\n public userRateLimit: RateLimit;\n public constructor(\n config: ConfigYaml & { config_path: string },\n // forceEnhancedLegacySignature is a property that\n // allows switch a new legacy aes signature token signature\n // for older versions do not want to have this new signature model\n // this property must be false\n configOverrideOptions = { forceMigrateToSecureLegacySignature: true }\n ) {\n const self = this;\n this.storage = process.env.VERDACCIO_STORAGE_PATH || config.storage;\n if (!config.configPath) {\n // backport self_path for previous to version 6\n // @ts-expect-error\n config.configPath = config.config_path ?? config.self_path;\n if (!config.configPath) {\n throw new Error('configPath property is required');\n }\n }\n this.configOverrideOptions = configOverrideOptions;\n this.configPath = config.configPath;\n this.self_path = this.configPath;\n debug('config path: %s', this.configPath);\n this.plugins = config.plugins;\n this.security = _.merge(\n // override the default security configuration via constructor\n _.merge(defaultSecurity, {\n api: {\n migrateToSecureLegacySignature:\n this.configOverrideOptions.forceMigrateToSecureLegacySignature,\n },\n }),\n config.security\n );\n this.serverSettings = serverSettings;\n this.flags = {\n searchRemote: config.flags?.searchRemote ?? true,\n changePassword: config.flags?.changePassword ?? false,\n };\n this.user_agent = config.user_agent;\n\n for (const configProp in config) {\n if (self[configProp] == null) {\n self[configProp] = config[configProp];\n }\n }\n\n if (typeof this.user_agent === 'undefined') {\n // by default user agent is hidden\n debug('set default user agent');\n this.user_agent = getUserAgent(false);\n }\n\n this.userRateLimit = { ...defaultUserRateLimiting, ...config?.userRateLimit };\n\n // some weird shell scripts are valid yaml files parsed as string\n assert(_.isObject(config), APP_ERROR.CONFIG_NOT_VALID);\n\n // sanity check for strategic config properties\n strategicConfigProps.forEach(function (x): void {\n if (self[x] == null) {\n self[x] = {};\n }\n\n assert(isObject(self[x]), `CONFIG: bad \"${x}\" value (object expected)`);\n });\n\n this.uplinks = sanityCheckUplinksProps(uplinkSanityCheck(this.uplinks));\n this.packages = normalisePackageAccess(self.packages);\n\n // loading these from ENV if aren't in config\n allowedEnvConfig.forEach((envConf): void => {\n if (!(envConf in self)) {\n self[envConf] = process.env[envConf] || process.env[envConf.toUpperCase()];\n }\n });\n\n // unique identifier of self server (or a cluster), used to avoid loops\n // @ts-ignore\n if (!this.server_id) {\n this.server_id = generateRandomHexString(6);\n }\n }\n\n public getMigrateToSecureLegacySignature() {\n return this.security.api.migrateToSecureLegacySignature;\n }\n\n public getConfigPath() {\n return this.configPath;\n }\n\n /**\n * Check for package spec\n */\n public getMatchedPackagesSpec(pkgName: string): PackageAccess | void {\n // TODO: remove this method and replace by library utils\n return getMatchedPackagesSpec(pkgName, this.packages);\n }\n\n /**\n * Verify if the secret complies with the required structure\n * - If the secret is not provided, it will generate a new one\n * - For any Node.js version the new secret will be 32 characters long (to allow compatibility with modern Node.js versions)\n * - If the secret is provided:\n * - If Node.js 22 or higher, the secret must be 32 characters long thus the application will fail on startup\n * - If Node.js 21 or lower, the secret will be used as is but will display a deprecation warning\n * - If the property `security.api.migrateToSecureLegacySignature` is provided and set to true, the secret will be\n * generated with the new signature model\n * @secret external secret key\n */\n public checkSecretKey(secret?: string): string {\n debug('checking secret key init');\n if (typeof secret === 'string' && _.isEmpty(secret) === false) {\n debug('checking secret key length %s', secret.length);\n if (secret.length > TOKEN_VALID_LENGTH) {\n if (isNodeVersionGreaterThan21()) {\n debug('is node version greater than 21');\n if (this.getMigrateToSecureLegacySignature() === true) {\n this.secret = generateRandomSecretKey();\n debug('rewriting secret key with length %s', this.secret.length);\n return this.secret;\n }\n // oops, user needs to generate a new secret key\n debug(\n 'secret does not comply with the required length, current length %d, application will fail on startup',\n secret.length\n );\n throw new Error(\n `Invalid storage secret key length, must be 32 characters long but is ${secret.length}. \n The secret length in Node.js 22 or higher must be 32 characters long. Please consider generate a new one. \n Learn more at https://verdaccio.org/docs/configuration/#.verdaccio-db`\n );\n } else {\n debug('is node version lower than 22');\n if (this.getMigrateToSecureLegacySignature() === true) {\n this.secret = generateRandomSecretKey();\n debug('rewriting secret key with length %s', this.secret.length);\n return this.secret;\n }\n debug('triggering deprecation warning for secret key length %s', secret.length);\n // still using Node.js versions previous to 22, but we need to emit a deprecation warning\n // deprecation warning, secret key is too long and must be 32\n // this will be removed in the next major release and will produce an error\n warningUtils.emit(Codes.VERWAR007);\n this.secret = secret;\n return this.secret;\n }\n } else if (secret.length === TOKEN_VALID_LENGTH) {\n debug('detected valid secret key length %s', secret.length);\n this.secret = secret;\n return this.secret;\n }\n debug('reusing previous key with length %s', secret.length);\n this.secret = secret;\n return this.secret;\n } else {\n // generate a new a secret key\n // FUTURE: this might be an external secret key, perhaps within config file?\n debug('generating a new secret key');\n this.secret = generateRandomSecretKey();\n debug('generated a new secret key length %s', this.secret?.length);\n\n return this.secret;\n }\n }\n}\n\nexport { Config };\n"],"mappings":"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"}
package/build/security.js CHANGED
@@ -14,7 +14,8 @@ const defaultWebTokenOptions = {
14
14
  verify: {}
15
15
  };
16
16
  const defaultApiTokenConf = {
17
- legacy: true
17
+ legacy: true,
18
+ migrateToSecureLegacySignature: true
18
19
  };
19
20
  const defaultSecurity = exports.defaultSecurity = {
20
21
  web: defaultWebTokenOptions,
@@ -1 +1 @@
1
- {"version":3,"file":"security.js","names":["TIME_EXPIRATION_1H","exports","defaultWebTokenOptions","sign","expiresIn","verify","defaultApiTokenConf","legacy","defaultSecurity","web","api"],"sources":["../src/security.ts"],"sourcesContent":["import { APITokenOptions, JWTOptions, Security } from '@verdaccio/types';\n\n// TODO: get this from core package\nexport const TIME_EXPIRATION_1H = '1h';\n\nconst defaultWebTokenOptions: JWTOptions = {\n sign: {\n // The expiration token for the website is 7 days\n expiresIn: TIME_EXPIRATION_1H,\n },\n verify: {},\n};\n\nconst defaultApiTokenConf: APITokenOptions = {\n legacy: true,\n};\n\nexport const defaultSecurity: Security = {\n web: defaultWebTokenOptions,\n api: defaultApiTokenConf,\n};\n"],"mappings":";;;;;;AAEA;AACO,MAAMA,kBAAkB,GAAAC,OAAA,CAAAD,kBAAA,GAAG,IAAI;AAEtC,MAAME,sBAAkC,GAAG;EACzCC,IAAI,EAAE;IACJ;IACAC,SAAS,EAAEJ;EACb,CAAC;EACDK,MAAM,EAAE,CAAC;AACX,CAAC;AAED,MAAMC,mBAAoC,GAAG;EAC3CC,MAAM,EAAE;AACV,CAAC;AAEM,MAAMC,eAAyB,GAAAP,OAAA,CAAAO,eAAA,GAAG;EACvCC,GAAG,EAAEP,sBAAsB;EAC3BQ,GAAG,EAAEJ;AACP,CAAC"}
1
+ {"version":3,"file":"security.js","names":["TIME_EXPIRATION_1H","exports","defaultWebTokenOptions","sign","expiresIn","verify","defaultApiTokenConf","legacy","migrateToSecureLegacySignature","defaultSecurity","web","api"],"sources":["../src/security.ts"],"sourcesContent":["import { APITokenOptions, JWTOptions, Security } from '@verdaccio/types';\n\n// TODO: get this from core package\nexport const TIME_EXPIRATION_1H = '1h';\n\nconst defaultWebTokenOptions: JWTOptions = {\n sign: {\n // The expiration token for the website is 7 days\n expiresIn: TIME_EXPIRATION_1H,\n },\n verify: {},\n};\n\nconst defaultApiTokenConf: APITokenOptions = {\n legacy: true,\n migrateToSecureLegacySignature: true,\n};\n\nexport const defaultSecurity: Security = {\n web: defaultWebTokenOptions,\n api: defaultApiTokenConf,\n};\n"],"mappings":";;;;;;AAEA;AACO,MAAMA,kBAAkB,GAAAC,OAAA,CAAAD,kBAAA,GAAG,IAAI;AAEtC,MAAME,sBAAkC,GAAG;EACzCC,IAAI,EAAE;IACJ;IACAC,SAAS,EAAEJ;EACb,CAAC;EACDK,MAAM,EAAE,CAAC;AACX,CAAC;AAED,MAAMC,mBAAoC,GAAG;EAC3CC,MAAM,EAAE,IAAI;EACZC,8BAA8B,EAAE;AAClC,CAAC;AAEM,MAAMC,eAAyB,GAAAR,OAAA,CAAAQ,eAAA,GAAG;EACvCC,GAAG,EAAER,sBAAsB;EAC3BS,GAAG,EAAEL;AACP,CAAC"}
package/build/token.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export declare const TOKEN_VALID_LENGTH = 32;
2
2
  /**
3
3
  * Secret key must have 32 characters.
4
+ * // TODO: code duplicated at @verdaccio/signature
4
5
  */
5
6
  export declare function generateRandomSecretKey(): string;
package/build/token.js CHANGED
@@ -6,10 +6,12 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.TOKEN_VALID_LENGTH = void 0;
7
7
  exports.generateRandomSecretKey = generateRandomSecretKey;
8
8
  var _crypto = require("crypto");
9
+ // TODO: code duplicated at @verdaccio/signature
9
10
  const TOKEN_VALID_LENGTH = exports.TOKEN_VALID_LENGTH = 32;
10
11
 
11
12
  /**
12
13
  * Secret key must have 32 characters.
14
+ * // TODO: code duplicated at @verdaccio/signature
13
15
  */
14
16
  function generateRandomSecretKey() {
15
17
  return (0, _crypto.randomBytes)(TOKEN_VALID_LENGTH).toString('base64').substring(0, TOKEN_VALID_LENGTH);
@@ -1 +1 @@
1
- {"version":3,"file":"token.js","names":["_crypto","require","TOKEN_VALID_LENGTH","exports","generateRandomSecretKey","randomBytes","toString","substring"],"sources":["../src/token.ts"],"sourcesContent":["import { randomBytes } from 'crypto';\n\nexport const TOKEN_VALID_LENGTH = 32;\n\n/**\n * Secret key must have 32 characters.\n */\nexport function generateRandomSecretKey(): string {\n return randomBytes(TOKEN_VALID_LENGTH).toString('base64').substring(0, TOKEN_VALID_LENGTH);\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AAEO,MAAMC,kBAAkB,GAAAC,OAAA,CAAAD,kBAAA,GAAG,EAAE;;AAEpC;AACA;AACA;AACO,SAASE,uBAAuBA,CAAA,EAAW;EAChD,OAAO,IAAAC,mBAAW,EAACH,kBAAkB,CAAC,CAACI,QAAQ,CAAC,QAAQ,CAAC,CAACC,SAAS,CAAC,CAAC,EAAEL,kBAAkB,CAAC;AAC5F"}
1
+ {"version":3,"file":"token.js","names":["_crypto","require","TOKEN_VALID_LENGTH","exports","generateRandomSecretKey","randomBytes","toString","substring"],"sources":["../src/token.ts"],"sourcesContent":["import { randomBytes } from 'crypto';\n\n// TODO: code duplicated at @verdaccio/signature\nexport const TOKEN_VALID_LENGTH = 32;\n\n/**\n * Secret key must have 32 characters.\n * // TODO: code duplicated at @verdaccio/signature\n */\nexport function generateRandomSecretKey(): string {\n return randomBytes(TOKEN_VALID_LENGTH).toString('base64').substring(0, TOKEN_VALID_LENGTH);\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AAEA;AACO,MAAMC,kBAAkB,GAAAC,OAAA,CAAAD,kBAAA,GAAG,EAAE;;AAEpC;AACA;AACA;AACA;AACO,SAASE,uBAAuBA,CAAA,EAAW;EAChD,OAAO,IAAAC,mBAAW,EAACH,kBAAkB,CAAC,CAACI,QAAQ,CAAC,QAAQ,CAAC,CAACC,SAAS,CAAC,CAAC,EAAEL,kBAAkB,CAAC;AAC5F"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/config",
3
- "version": "7.0.0-next-7.13",
3
+ "version": "7.0.0-next-7.15",
4
4
  "description": "logger",
5
5
  "main": "./build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -29,8 +29,8 @@
29
29
  "node": ">=12"
30
30
  },
31
31
  "dependencies": {
32
- "@verdaccio/core": "7.0.0-next-7.13",
33
- "@verdaccio/utils": "7.0.0-next-7.13",
32
+ "@verdaccio/core": "7.0.0-next-7.15",
33
+ "@verdaccio/utils": "7.0.0-next-7.15",
34
34
  "debug": "4.3.4",
35
35
  "js-yaml": "4.1.0",
36
36
  "lodash": "4.17.21",
package/src/config.ts CHANGED
@@ -36,6 +36,13 @@ export const defaultUserRateLimiting = {
36
36
  max: 1000,
37
37
  };
38
38
 
39
+ export function isNodeVersionGreaterThan21() {
40
+ const [major, minor] = process.versions.node.split('.').map(Number);
41
+ return major > 21 || (major === 21 && minor >= 0);
42
+ }
43
+
44
+ const TOKEN_VALID_LENGTH = 32;
45
+
39
46
  /**
40
47
  * Coordinates the application configuration
41
48
  */
@@ -56,21 +63,20 @@ class Config implements AppConfig {
56
63
  public plugins: string | void | null;
57
64
  public security: Security;
58
65
  public serverSettings: ServerSettingsConf;
66
+ private configOverrideOptions: { forceMigrateToSecureLegacySignature: boolean };
59
67
  // @ts-ignore
60
68
  public secret: string;
61
69
  public flags: FlagsConfig;
62
70
  public userRateLimit: RateLimit;
63
- private configOptions: { forceEnhancedLegacySignature: boolean };
64
71
  public constructor(
65
72
  config: ConfigYaml & { config_path: string },
66
73
  // forceEnhancedLegacySignature is a property that
67
74
  // allows switch a new legacy aes signature token signature
68
75
  // for older versions do not want to have this new signature model
69
76
  // this property must be false
70
- configOptions = { forceEnhancedLegacySignature: true }
77
+ configOverrideOptions = { forceMigrateToSecureLegacySignature: true }
71
78
  ) {
72
79
  const self = this;
73
- this.configOptions = configOptions;
74
80
  this.storage = process.env.VERDACCIO_STORAGE_PATH || config.storage;
75
81
  if (!config.configPath) {
76
82
  // backport self_path for previous to version 6
@@ -80,11 +86,21 @@ class Config implements AppConfig {
80
86
  throw new Error('configPath property is required');
81
87
  }
82
88
  }
89
+ this.configOverrideOptions = configOverrideOptions;
83
90
  this.configPath = config.configPath;
84
91
  this.self_path = this.configPath;
85
92
  debug('config path: %s', this.configPath);
86
93
  this.plugins = config.plugins;
87
- this.security = _.merge(defaultSecurity, config.security);
94
+ this.security = _.merge(
95
+ // override the default security configuration via constructor
96
+ _.merge(defaultSecurity, {
97
+ api: {
98
+ migrateToSecureLegacySignature:
99
+ this.configOverrideOptions.forceMigrateToSecureLegacySignature,
100
+ },
101
+ }),
102
+ config.security
103
+ );
88
104
  this.serverSettings = serverSettings;
89
105
  this.flags = {
90
106
  searchRemote: config.flags?.searchRemote ?? true,
@@ -135,14 +151,8 @@ class Config implements AppConfig {
135
151
  }
136
152
  }
137
153
 
138
- public getEnhancedLegacySignature() {
139
- if (typeof this?.security.enhancedLegacySignature !== 'undefined') {
140
- if (this.security.enhancedLegacySignature === true) {
141
- return true;
142
- }
143
- return false;
144
- }
145
- return this.configOptions.forceEnhancedLegacySignature;
154
+ public getMigrateToSecureLegacySignature() {
155
+ return this.security.api.migrateToSecureLegacySignature;
146
156
  }
147
157
 
148
158
  public getConfigPath() {
@@ -158,36 +168,70 @@ class Config implements AppConfig {
158
168
  }
159
169
 
160
170
  /**
161
- * Store or create whether receive a secret key
171
+ * Verify if the secret complies with the required structure
172
+ * - If the secret is not provided, it will generate a new one
173
+ * - For any Node.js version the new secret will be 32 characters long (to allow compatibility with modern Node.js versions)
174
+ * - If the secret is provided:
175
+ * - If Node.js 22 or higher, the secret must be 32 characters long thus the application will fail on startup
176
+ * - If Node.js 21 or lower, the secret will be used as is but will display a deprecation warning
177
+ * - If the property `security.api.migrateToSecureLegacySignature` is provided and set to true, the secret will be
178
+ * generated with the new signature model
162
179
  * @secret external secret key
163
180
  */
164
181
  public checkSecretKey(secret?: string): string {
165
- debug('check secret key');
182
+ debug('checking secret key init');
166
183
  if (typeof secret === 'string' && _.isEmpty(secret) === false) {
184
+ debug('checking secret key length %s', secret.length);
185
+ if (secret.length > TOKEN_VALID_LENGTH) {
186
+ if (isNodeVersionGreaterThan21()) {
187
+ debug('is node version greater than 21');
188
+ if (this.getMigrateToSecureLegacySignature() === true) {
189
+ this.secret = generateRandomSecretKey();
190
+ debug('rewriting secret key with length %s', this.secret.length);
191
+ return this.secret;
192
+ }
193
+ // oops, user needs to generate a new secret key
194
+ debug(
195
+ 'secret does not comply with the required length, current length %d, application will fail on startup',
196
+ secret.length
197
+ );
198
+ throw new Error(
199
+ `Invalid storage secret key length, must be 32 characters long but is ${secret.length}.
200
+ The secret length in Node.js 22 or higher must be 32 characters long. Please consider generate a new one.
201
+ Learn more at https://verdaccio.org/docs/configuration/#.verdaccio-db`
202
+ );
203
+ } else {
204
+ debug('is node version lower than 22');
205
+ if (this.getMigrateToSecureLegacySignature() === true) {
206
+ this.secret = generateRandomSecretKey();
207
+ debug('rewriting secret key with length %s', this.secret.length);
208
+ return this.secret;
209
+ }
210
+ debug('triggering deprecation warning for secret key length %s', secret.length);
211
+ // still using Node.js versions previous to 22, but we need to emit a deprecation warning
212
+ // deprecation warning, secret key is too long and must be 32
213
+ // this will be removed in the next major release and will produce an error
214
+ warningUtils.emit(Codes.VERWAR007);
215
+ this.secret = secret;
216
+ return this.secret;
217
+ }
218
+ } else if (secret.length === TOKEN_VALID_LENGTH) {
219
+ debug('detected valid secret key length %s', secret.length);
220
+ this.secret = secret;
221
+ return this.secret;
222
+ }
223
+ debug('reusing previous key with length %s', secret.length);
167
224
  this.secret = secret;
168
- debug('reusing previous key');
169
- return secret;
170
- }
171
- // generate a new a secret key
172
- // FUTURE: this might be an external secret key, perhaps within config file?
173
- debug('generating a new secret key');
174
-
175
- if (this.getEnhancedLegacySignature()) {
176
- debug('key generated with "enhanced" legacy signature user config');
177
- this.secret = generateRandomSecretKey();
225
+ return this.secret;
178
226
  } else {
179
- debug('key generated with legacy signature user config');
180
- this.secret = generateRandomHexString(32);
181
- }
182
- // set this to false allow use old token signature and is not recommended
183
- // only use for migration reasons, major release will remove this property and
184
- // set it by default
185
- if (this.security?.enhancedLegacySignature === false) {
186
- warningUtils.emit(Codes.VERWAR005);
187
- }
227
+ // generate a new a secret key
228
+ // FUTURE: this might be an external secret key, perhaps within config file?
229
+ debug('generating a new secret key');
230
+ this.secret = generateRandomSecretKey();
231
+ debug('generated a new secret key length %s', this.secret?.length);
188
232
 
189
- debug('generated a new secret key length %s', this.secret?.length);
190
- return this.secret;
233
+ return this.secret;
234
+ }
191
235
  }
192
236
  }
193
237
 
package/src/security.ts CHANGED
@@ -13,6 +13,7 @@ const defaultWebTokenOptions: JWTOptions = {
13
13
 
14
14
  const defaultApiTokenConf: APITokenOptions = {
15
15
  legacy: true,
16
+ migrateToSecureLegacySignature: true,
16
17
  };
17
18
 
18
19
  export const defaultSecurity: Security = {
package/src/token.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import { randomBytes } from 'crypto';
2
2
 
3
+ // TODO: code duplicated at @verdaccio/signature
3
4
  export const TOKEN_VALID_LENGTH = 32;
4
5
 
5
6
  /**
6
7
  * Secret key must have 32 characters.
8
+ * // TODO: code duplicated at @verdaccio/signature
7
9
  */
8
10
  export function generateRandomSecretKey(): string {
9
11
  return randomBytes(TOKEN_VALID_LENGTH).toString('base64').substring(0, TOKEN_VALID_LENGTH);
@@ -6,9 +6,12 @@ import {
6
6
  DEFAULT_REGISTRY,
7
7
  DEFAULT_UPLINK,
8
8
  ROLES,
9
+ TOKEN_VALID_LENGTH,
9
10
  WEB_TITLE,
10
11
  defaultSecurity,
12
+ generateRandomSecretKey,
11
13
  getDefaultConfig,
14
+ isNodeVersionGreaterThan21,
12
15
  parseConfigFile,
13
16
  } from '../src';
14
17
  import { parseConfigurationFile } from './utils';
@@ -19,6 +22,8 @@ const resolveConf = (conf) => {
19
22
  return path.join(__dirname, `../src/conf/${name}${ext.startsWith('.') ? ext : '.yaml'}`);
20
23
  };
21
24
 
25
+ const itif = (condition) => (condition ? it : it.skip);
26
+
22
27
  const checkDefaultUplink = (config) => {
23
28
  expect(_.isObject(config.uplinks[DEFAULT_UPLINK])).toBeTruthy();
24
29
  expect(config.uplinks[DEFAULT_UPLINK].url).toMatch(DEFAULT_REGISTRY);
@@ -94,32 +99,85 @@ describe('check basic content parsed file', () => {
94
99
  describe('checkSecretKey', () => {
95
100
  test('with default.yaml and pre selected secret', () => {
96
101
  const config = new Config(parseConfigFile(resolveConf('default')));
97
- expect(config.checkSecretKey('12345')).toEqual('12345');
102
+ expect(config.checkSecretKey(generateRandomSecretKey())).toHaveLength(TOKEN_VALID_LENGTH);
98
103
  });
99
104
 
100
105
  test('with default.yaml and void secret', () => {
101
106
  const config = new Config(parseConfigFile(resolveConf('default')));
102
- expect(typeof config.checkSecretKey() === 'string').toBeTruthy();
107
+ const secret = config.checkSecretKey();
108
+ expect(typeof secret === 'string').toBeTruthy();
109
+ expect(secret).toHaveLength(TOKEN_VALID_LENGTH);
103
110
  });
104
111
 
105
- test('with default.yaml and emtpy string secret', () => {
112
+ test('with default.yaml and empty string secret', () => {
106
113
  const config = new Config(parseConfigFile(resolveConf('default')));
107
- expect(typeof config.checkSecretKey('') === 'string').toBeTruthy();
114
+ const secret = config.checkSecretKey('');
115
+ expect(typeof secret === 'string').toBeTruthy();
116
+ expect(secret).toHaveLength(TOKEN_VALID_LENGTH);
108
117
  });
109
118
 
110
- test('with enhanced legacy signature', () => {
119
+ test('with default.yaml and valid string secret length', () => {
111
120
  const config = new Config(parseConfigFile(resolveConf('default')));
112
- config.security.enhancedLegacySignature = true;
113
- expect(typeof config.checkSecretKey() === 'string').toBeTruthy();
114
- expect(config.secret.length).toBe(32);
121
+ expect(typeof config.checkSecretKey(generateRandomSecretKey()) === 'string').toBeTruthy();
122
+ });
123
+
124
+ test('with default.yaml migrate a valid string secret length', () => {
125
+ const config = new Config(parseConfigFile(resolveConf('default')), {
126
+ forceMigrateToSecureLegacySignature: true,
127
+ });
128
+ expect(
129
+ // 64 characters secret long
130
+ config.checkSecretKey('b4982dbb0108531fafb552374d7e83724b6458a2b3ffa97ad0edb899bdaefc4a')
131
+ ).toHaveLength(TOKEN_VALID_LENGTH);
115
132
  });
116
133
 
117
- test('without enhanced legacy signature', () => {
134
+ // only runs on Node.js 22 or higher
135
+ itif(isNodeVersionGreaterThan21())('with enhanced legacy signature Node 22 or higher', () => {
136
+ const config = new Config(parseConfigFile(resolveConf('default')), {
137
+ forceMigrateToSecureLegacySignature: false,
138
+ });
139
+ // eslint-disable-next-line jest/no-standalone-expect
140
+ expect(() =>
141
+ // 64 characters secret long
142
+ config.checkSecretKey('b4982dbb0108531fafb552374d7e83724b6458a2b3ffa97ad0edb899bdaefc4a')
143
+ ).toThrow();
144
+ });
145
+
146
+ itif(isNodeVersionGreaterThan21())('with enhanced legacy signature Node 22 or higher', () => {
147
+ const config = new Config(parseConfigFile(resolveConf('default')), {
148
+ forceMigrateToSecureLegacySignature: false,
149
+ });
150
+ config.security.api.migrateToSecureLegacySignature = true;
151
+ // eslint-disable-next-line jest/no-standalone-expect
152
+ expect(
153
+ config.checkSecretKey('b4982dbb0108531fafb552374d7e83724b6458a2b3ffa97ad0edb899bdaefc4a')
154
+ ).toHaveLength(TOKEN_VALID_LENGTH);
155
+ });
156
+
157
+ itif(isNodeVersionGreaterThan21() === false)(
158
+ 'with old unsecure legacy signature Node 21 or lower',
159
+ () => {
160
+ const config = new Config(parseConfigFile(resolveConf('default')));
161
+ config.security.api.migrateToSecureLegacySignature = false;
162
+ // 64 characters secret long
163
+ // eslint-disable-next-line jest/no-standalone-expect
164
+ expect(
165
+ config.checkSecretKey('b4982dbb0108531fafb552374d7e83724b6458a2b3ffa97ad0edb899bdaefc4a')
166
+ ).toHaveLength(64);
167
+ }
168
+ );
169
+
170
+ test('with migration to new legacy signature Node 21 or lower', () => {
118
171
  const config = new Config(parseConfigFile(resolveConf('default')));
119
- config.security.enhancedLegacySignature = false;
120
- expect(typeof config.checkSecretKey() === 'string').toBeTruthy();
121
- expect(config.secret.length).toBe(64);
172
+ config.security.api.migrateToSecureLegacySignature = true;
173
+ // 64 characters secret long
174
+ // eslint-disable-next-line jest/no-standalone-expect
175
+ expect(
176
+ config.checkSecretKey('b4982dbb0108531fafb552374d7e83724b6458a2b3ffa97ad0edb899bdaefc4a')
177
+ ).toHaveLength(TOKEN_VALID_LENGTH);
122
178
  });
179
+
180
+ test.todo('test emit warning with secret key');
123
181
  });
124
182
 
125
183
  describe('getMatchedPackagesSpec', () => {