@verdaccio/url 12.0.0-next.5 → 13.0.0-next-8.0

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,144 @@
1
1
  # Change Log
2
2
 
3
+ ## 13.0.0-next-8.0
4
+
5
+ ### Major Changes
6
+
7
+ - chore: move v7 next to v8 next
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @verdaccio/core@8.0.0-next-8.0
13
+
14
+ ## 12.0.0
15
+
16
+ ### Major Changes
17
+
18
+ - 47f61c6: feat!: bump to v7
19
+ - e7ebccb: update major dependencies, remove old nodejs support
20
+
21
+ ### Minor Changes
22
+
23
+ - daceb6d: restore legacy support
24
+ - f047cc8: refactor: auth with legacy sign support
25
+
26
+ ### Patch Changes
27
+
28
+ - b0946b2: Improved TS types for renderHTML() and related functions (by @tobbe in #4605)
29
+ - ccc7bd1: fix(middleware): link to favicon in template
30
+ - 38b1e82: patch(core/url): Throw if VERDACCIO_FORWARDED_PROTO resolves to an array (#4613 by @Tobbe)
31
+ - Updated dependencies [47f61c6]
32
+ - Updated dependencies [6e764e3]
33
+ - Updated dependencies [daceb6d]
34
+ - Updated dependencies [e7ebccb]
35
+ - Updated dependencies [f047cc8]
36
+ - Updated dependencies [7c9f3cf]
37
+ - Updated dependencies [bd8703e]
38
+ - @verdaccio/core@7.0.0
39
+
40
+ ## 12.0.0-next-8.21
41
+
42
+ ### Patch Changes
43
+
44
+ - Updated dependencies [7c9f3cf]
45
+ - @verdaccio/core@7.0.0-next-8.21
46
+
47
+ ## 12.0.0-next-7.20
48
+
49
+ ### Patch Changes
50
+
51
+ - ccc7bd1: fix(middleware): link to favicon in template
52
+ - @verdaccio/core@7.0.0-next-7.20
53
+
54
+ ## 12.0.0-next-7.19
55
+
56
+ ### Patch Changes
57
+
58
+ - @verdaccio/core@7.0.0-next-7.19
59
+
60
+ ## 12.0.0-next-7.18
61
+
62
+ ### Patch Changes
63
+
64
+ - @verdaccio/core@7.0.0-next-7.18
65
+
66
+ ## 12.0.0-next-7.17
67
+
68
+ ### Patch Changes
69
+
70
+ - Updated dependencies [6e764e3]
71
+ - @verdaccio/core@7.0.0-next-7.17
72
+
73
+ ## 12.0.0-next-7.16
74
+
75
+ ### Patch Changes
76
+
77
+ - 38b1e82: patch(core/url): Throw if VERDACCIO_FORWARDED_PROTO resolves to an array (#4613 by @Tobbe)
78
+ - @verdaccio/core@7.0.0-next-7.16
79
+
80
+ ## 12.0.0-next-7.15
81
+
82
+ ### Patch Changes
83
+
84
+ - Updated dependencies [bd8703e]
85
+ - @verdaccio/core@7.0.0-next-7.15
86
+
87
+ ## 12.0.0-next-7.14
88
+
89
+ ### Patch Changes
90
+
91
+ - b0946b2: Improved TS types for renderHTML() and related functions (by @tobbe in #4605)
92
+ - @verdaccio/core@7.0.0-next-7.14
93
+
94
+ ## 12.0.0-next-7.13
95
+
96
+ ### Patch Changes
97
+
98
+ - @verdaccio/core@7.0.0-next-7.13
99
+
100
+ ## 12.0.0-next-7.12
101
+
102
+ ### Patch Changes
103
+
104
+ - @verdaccio/core@7.0.0-next-7.12
105
+
106
+ ## 12.0.0-next-7.11
107
+
108
+ ### Patch Changes
109
+
110
+ - @verdaccio/core@7.0.0-next-7.11
111
+
112
+ ## 12.0.0-next-7.10
113
+
114
+ ### Patch Changes
115
+
116
+ - @verdaccio/core@7.0.0-next-7.10
117
+
118
+ ## 12.0.0-next-7.9
119
+
120
+ ### Patch Changes
121
+
122
+ - @verdaccio/core@7.0.0-next-7.9
123
+
124
+ ## 12.0.0-next-7.8
125
+
126
+ ### Patch Changes
127
+
128
+ - @verdaccio/core@7.0.0-next-7.8
129
+
130
+ ## 12.0.0-next-7.7
131
+
132
+ ### Patch Changes
133
+
134
+ - @verdaccio/core@7.0.0-next-7.7
135
+
136
+ ## 12.0.0-next.6
137
+
138
+ ### Patch Changes
139
+
140
+ - @verdaccio/core@7.0.0-next.6
141
+
3
142
  ## 12.0.0-next.5
4
143
 
5
144
  ### Minor Changes
package/build/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ /// <reference types="node" />
2
+ import type { IncomingHttpHeaders } from 'node:http';
1
3
  /**
2
4
  * Check if URI is starting with "http://", "https://" or "//"
3
5
  * @param {string} uri
@@ -7,7 +9,7 @@ export declare function isHost(url?: string, options?: {}): boolean;
7
9
  /**
8
10
  * Detect running protocol (http or https)
9
11
  */
10
- export declare function getWebProtocol(headerProtocol: string | void, protocol: string): string;
12
+ export declare function getWebProtocol(headerProtocol: string | undefined, protocol: string): string;
11
13
  export declare function wrapPrefix(prefix: string | void): string;
12
14
  /**
13
15
  * Create base url for registry.
@@ -27,9 +29,7 @@ export type RequestOptions = {
27
29
  /**
28
30
  * Request headers.
29
31
  */
30
- headers: {
31
- [key: string]: string;
32
- };
32
+ headers: IncomingHttpHeaders;
33
33
  remoteAddress?: string;
34
34
  /**
35
35
  * Logged username the request, usually after token verification.
package/build/index.js CHANGED
@@ -15,7 +15,7 @@ var _debug = _interopRequireDefault(require("debug"));
15
15
  var _url = require("url");
16
16
  var _validator = _interopRequireDefault(require("validator"));
17
17
  var _core = require("@verdaccio/core");
18
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
19
19
  const debug = (0, _debug.default)('verdaccio:core:url');
20
20
  const validProtocols = ['https', 'http'];
21
21
 
@@ -106,8 +106,16 @@ function getPublicUrl(url_prefix = '', requestOptions) {
106
106
  if (!isHost(host)) {
107
107
  throw new Error('invalid host');
108
108
  }
109
+
110
+ // 'X-Forwarded-Proto' is the default header
109
111
  const protoHeader = (_process$env$VERDACCI = (_process$env$VERDACCI2 = process.env.VERDACCIO_FORWARDED_PROTO) === null || _process$env$VERDACCI2 === void 0 ? void 0 : _process$env$VERDACCI2.toLocaleLowerCase()) !== null && _process$env$VERDACCI !== void 0 ? _process$env$VERDACCI : _core.HEADERS.FORWARDED_PROTO.toLowerCase();
110
- const protocol = getWebProtocol(requestOptions.headers[protoHeader], requestOptions.protocol);
112
+ const forwardedProtocolHeaderValue = requestOptions.headers[protoHeader];
113
+ if (Array.isArray(forwardedProtocolHeaderValue)) {
114
+ // This really should never happen - only set-cookie is allowed to have
115
+ // multiple values.
116
+ throw new Error('invalid forwarded protocol header value. Reading header ' + protoHeader);
117
+ }
118
+ const protocol = getWebProtocol(forwardedProtocolHeaderValue, requestOptions.protocol);
111
119
  const combinedUrl = combineBaseUrl(protocol, host, url_prefix);
112
120
  debug('public url by request %o', combinedUrl);
113
121
  return combinedUrl;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_debug","_interopRequireDefault","require","_url","_validator","_core","obj","__esModule","default","debug","buildDebug","validProtocols","isURLhasValidProtocol","uri","test","isHost","url","options","validator","isURL","require_host","allow_trailing_dot","require_valid_protocol","require_port","require_tld","getWebProtocol","headerProtocol","protocol","returnProtocol","defaultProtocol","commaIndex","indexOf","slice","includes","wrapPrefix","prefix","startsWith","endsWith","combineBaseUrl","host","newPrefix","groupedURI","URL","result","href","validateURL","publicUrl","parsed","replace","Error","err","getPublicUrl","url_prefix","requestOptions","process","env","VERDACCIO_PUBLIC_URL","envURL","headers","_process$env$VERDACCI","_process$env$VERDACCI2","protoHeader","VERDACCIO_FORWARDED_PROTO","toLocaleLowerCase","HEADERS","FORWARDED_PROTO","toLowerCase","combinedUrl","exports"],"sources":["../src/index.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { URL } from 'url';\nimport validator from 'validator';\n\nimport { HEADERS } from '@verdaccio/core';\n\nconst debug = buildDebug('verdaccio:core:url');\n\nconst validProtocols = ['https', 'http'];\n\n/**\n * Check if URI is starting with \"http://\", \"https://\" or \"//\"\n * @param {string} uri\n */\nexport function isURLhasValidProtocol(uri: string): boolean {\n return /^(https?:)?\\/\\//.test(uri);\n}\n\nexport function isHost(url: string = '', options = {}): boolean {\n return validator.isURL(url, {\n require_host: true,\n allow_trailing_dot: false,\n require_valid_protocol: false,\n // @ts-ignore\n require_port: false,\n require_tld: false,\n ...options,\n });\n}\n\n/**\n * Detect running protocol (http or https)\n */\nexport function getWebProtocol(headerProtocol: string | void, protocol: string): string {\n let returnProtocol;\n const [, defaultProtocol] = validProtocols;\n // HAProxy variant might return http,http with X-Forwarded-Proto\n if (typeof headerProtocol === 'string' && headerProtocol !== '') {\n debug('header protocol: %o', protocol);\n const commaIndex = headerProtocol.indexOf(',');\n returnProtocol = commaIndex > 0 ? headerProtocol.slice(0, commaIndex) : headerProtocol;\n } else {\n debug('req protocol: %o', headerProtocol);\n returnProtocol = protocol;\n }\n\n return validProtocols.includes(returnProtocol) ? returnProtocol : defaultProtocol;\n}\n\nexport function wrapPrefix(prefix: string | void): string {\n if (prefix === '' || typeof prefix === 'undefined' || prefix === null) {\n return '';\n } else if (!prefix.startsWith('/') && prefix.endsWith('/')) {\n return `/${prefix}`;\n } else if (!prefix.startsWith('/') && !prefix.endsWith('/')) {\n return `/${prefix}/`;\n } else if (prefix.startsWith('/') && !prefix.endsWith('/')) {\n return `${prefix}/`;\n } else {\n return prefix;\n }\n}\n\n/**\n * Create base url for registry.\n * @return {String} base registry url\n */\nexport function combineBaseUrl(protocol: string, host: string, prefix: string = ''): string {\n debug('combined protocol %o', protocol);\n debug('combined host %o', host);\n const newPrefix = wrapPrefix(prefix);\n debug('combined prefix %o', newPrefix);\n const groupedURI = new URL(wrapPrefix(prefix), `${protocol}://${host}`);\n const result = groupedURI.href;\n debug('combined url %o', result);\n return result;\n}\n\nexport function validateURL(publicUrl: string | void) {\n try {\n const parsed = new URL(publicUrl as string);\n if (!validProtocols.includes(parsed.protocol.replace(':', ''))) {\n throw Error('invalid protocol');\n }\n return true;\n } catch (err: any) {\n // TODO: add error logger here\n return false;\n }\n}\n\nexport type RequestOptions = {\n /**\n * Request host.\n */\n host: string;\n /**\n * Request protocol.\n */\n protocol: string;\n /**\n * Request headers.\n */\n headers: { [key: string]: string };\n remoteAddress?: string;\n /**\n * Logged username the request, usually after token verification.\n */\n username?: string;\n};\n\nexport function getPublicUrl(url_prefix: string = '', requestOptions: RequestOptions): string {\n if (validateURL(process.env.VERDACCIO_PUBLIC_URL as string)) {\n const envURL = new URL(wrapPrefix(url_prefix), process.env.VERDACCIO_PUBLIC_URL as string).href;\n debug('public url by env %o', envURL);\n return envURL;\n } else if (requestOptions.headers['host']) {\n const host = requestOptions.headers['host'];\n if (!isHost(host)) {\n throw new Error('invalid host');\n }\n const protoHeader =\n process.env.VERDACCIO_FORWARDED_PROTO?.toLocaleLowerCase() ??\n HEADERS.FORWARDED_PROTO.toLowerCase();\n const protocol = getWebProtocol(requestOptions.headers[protoHeader], requestOptions.protocol);\n const combinedUrl = combineBaseUrl(protocol, host, url_prefix);\n debug('public url by request %o', combinedUrl);\n return combinedUrl;\n } else {\n return '/';\n }\n}\n\nexport const isURL = validator.isURL;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["_debug","_interopRequireDefault","require","_url","_validator","_core","e","__esModule","default","debug","buildDebug","validProtocols","isURLhasValidProtocol","uri","test","isHost","url","options","validator","isURL","require_host","allow_trailing_dot","require_valid_protocol","require_port","require_tld","getWebProtocol","headerProtocol","protocol","returnProtocol","defaultProtocol","commaIndex","indexOf","slice","includes","wrapPrefix","prefix","startsWith","endsWith","combineBaseUrl","host","newPrefix","groupedURI","URL","result","href","validateURL","publicUrl","parsed","replace","Error","err","getPublicUrl","url_prefix","requestOptions","process","env","VERDACCIO_PUBLIC_URL","envURL","headers","_process$env$VERDACCI","_process$env$VERDACCI2","protoHeader","VERDACCIO_FORWARDED_PROTO","toLocaleLowerCase","HEADERS","FORWARDED_PROTO","toLowerCase","forwardedProtocolHeaderValue","Array","isArray","combinedUrl","exports"],"sources":["../src/index.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { IncomingHttpHeaders } from 'node:http';\nimport { URL } from 'url';\nimport validator from 'validator';\n\nimport { HEADERS } from '@verdaccio/core';\n\nconst debug = buildDebug('verdaccio:core:url');\n\nconst validProtocols = ['https', 'http'];\n\n/**\n * Check if URI is starting with \"http://\", \"https://\" or \"//\"\n * @param {string} uri\n */\nexport function isURLhasValidProtocol(uri: string): boolean {\n return /^(https?:)?\\/\\//.test(uri);\n}\n\nexport function isHost(url: string = '', options = {}): boolean {\n return validator.isURL(url, {\n require_host: true,\n allow_trailing_dot: false,\n require_valid_protocol: false,\n // @ts-ignore\n require_port: false,\n require_tld: false,\n ...options,\n });\n}\n\n/**\n * Detect running protocol (http or https)\n */\nexport function getWebProtocol(headerProtocol: string | undefined, protocol: string): string {\n let returnProtocol;\n const [, defaultProtocol] = validProtocols;\n // HAProxy variant might return http,http with X-Forwarded-Proto\n if (typeof headerProtocol === 'string' && headerProtocol !== '') {\n debug('header protocol: %o', protocol);\n const commaIndex = headerProtocol.indexOf(',');\n returnProtocol = commaIndex > 0 ? headerProtocol.slice(0, commaIndex) : headerProtocol;\n } else {\n debug('req protocol: %o', headerProtocol);\n returnProtocol = protocol;\n }\n\n return validProtocols.includes(returnProtocol) ? returnProtocol : defaultProtocol;\n}\n\nexport function wrapPrefix(prefix: string | void): string {\n if (prefix === '' || typeof prefix === 'undefined' || prefix === null) {\n return '';\n } else if (!prefix.startsWith('/') && prefix.endsWith('/')) {\n return `/${prefix}`;\n } else if (!prefix.startsWith('/') && !prefix.endsWith('/')) {\n return `/${prefix}/`;\n } else if (prefix.startsWith('/') && !prefix.endsWith('/')) {\n return `${prefix}/`;\n } else {\n return prefix;\n }\n}\n\n/**\n * Create base url for registry.\n * @return {String} base registry url\n */\nexport function combineBaseUrl(protocol: string, host: string, prefix: string = ''): string {\n debug('combined protocol %o', protocol);\n debug('combined host %o', host);\n const newPrefix = wrapPrefix(prefix);\n debug('combined prefix %o', newPrefix);\n const groupedURI = new URL(wrapPrefix(prefix), `${protocol}://${host}`);\n const result = groupedURI.href;\n debug('combined url %o', result);\n return result;\n}\n\nexport function validateURL(publicUrl: string | void) {\n try {\n const parsed = new URL(publicUrl as string);\n if (!validProtocols.includes(parsed.protocol.replace(':', ''))) {\n throw Error('invalid protocol');\n }\n return true;\n } catch (err: any) {\n // TODO: add error logger here\n return false;\n }\n}\n\nexport type RequestOptions = {\n /**\n * Request host.\n */\n host: string;\n /**\n * Request protocol.\n */\n protocol: string;\n /**\n * Request headers.\n */\n headers: IncomingHttpHeaders;\n remoteAddress?: string;\n /**\n * Logged username the request, usually after token verification.\n */\n username?: string;\n};\n\nexport function getPublicUrl(url_prefix: string = '', requestOptions: RequestOptions): string {\n if (validateURL(process.env.VERDACCIO_PUBLIC_URL as string)) {\n const envURL = new URL(wrapPrefix(url_prefix), process.env.VERDACCIO_PUBLIC_URL as string).href;\n debug('public url by env %o', envURL);\n return envURL;\n } else if (requestOptions.headers['host']) {\n const host = requestOptions.headers['host'];\n if (!isHost(host)) {\n throw new Error('invalid host');\n }\n\n // 'X-Forwarded-Proto' is the default header\n const protoHeader: string =\n process.env.VERDACCIO_FORWARDED_PROTO?.toLocaleLowerCase() ??\n HEADERS.FORWARDED_PROTO.toLowerCase();\n const forwardedProtocolHeaderValue = requestOptions.headers[protoHeader];\n\n if (Array.isArray(forwardedProtocolHeaderValue)) {\n // This really should never happen - only set-cookie is allowed to have\n // multiple values.\n throw new Error('invalid forwarded protocol header value. Reading header ' + protoHeader);\n }\n\n const protocol = getWebProtocol(forwardedProtocolHeaderValue, requestOptions.protocol);\n const combinedUrl = combineBaseUrl(protocol, host, url_prefix);\n debug('public url by request %o', combinedUrl);\n return combinedUrl;\n } else {\n return '/';\n }\n}\n\nexport const isURL = validator.isURL;\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/url",
3
- "version": "12.0.0-next.5",
3
+ "version": "13.0.0-next-8.0",
4
4
  "description": "url utilities resolver",
5
5
  "keywords": [
6
6
  "private",
@@ -33,14 +33,14 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@verdaccio/core": "7.0.0-next.5",
37
- "debug": "4.3.4",
36
+ "@verdaccio/core": "8.0.0-next-8.0",
37
+ "debug": "4.3.7",
38
38
  "lodash": "4.17.21",
39
- "validator": "13.11.0"
39
+ "validator": "13.12.0"
40
40
  },
41
41
  "devDependencies": {
42
- "@verdaccio/types": "12.0.0-next.2",
43
- "node-mocks-http": "1.14.0"
42
+ "@verdaccio/types": "13.0.0-next-8.0",
43
+ "node-mocks-http": "1.14.1"
44
44
  },
45
45
  "funding": {
46
46
  "type": "opencollective",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "scripts": {
50
50
  "clean": "rimraf ./build",
51
- "test": "jest",
51
+ "test": "vitest run",
52
52
  "type-check": "tsc --noEmit -p tsconfig.build.json",
53
53
  "build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
54
54
  "build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import buildDebug from 'debug';
2
+ import type { IncomingHttpHeaders } from 'node:http';
2
3
  import { URL } from 'url';
3
4
  import validator from 'validator';
4
5
 
@@ -31,7 +32,7 @@ export function isHost(url: string = '', options = {}): boolean {
31
32
  /**
32
33
  * Detect running protocol (http or https)
33
34
  */
34
- export function getWebProtocol(headerProtocol: string | void, protocol: string): string {
35
+ export function getWebProtocol(headerProtocol: string | undefined, protocol: string): string {
35
36
  let returnProtocol;
36
37
  const [, defaultProtocol] = validProtocols;
37
38
  // HAProxy variant might return http,http with X-Forwarded-Proto
@@ -101,7 +102,7 @@ export type RequestOptions = {
101
102
  /**
102
103
  * Request headers.
103
104
  */
104
- headers: { [key: string]: string };
105
+ headers: IncomingHttpHeaders;
105
106
  remoteAddress?: string;
106
107
  /**
107
108
  * Logged username the request, usually after token verification.
@@ -119,10 +120,20 @@ export function getPublicUrl(url_prefix: string = '', requestOptions: RequestOpt
119
120
  if (!isHost(host)) {
120
121
  throw new Error('invalid host');
121
122
  }
122
- const protoHeader =
123
+
124
+ // 'X-Forwarded-Proto' is the default header
125
+ const protoHeader: string =
123
126
  process.env.VERDACCIO_FORWARDED_PROTO?.toLocaleLowerCase() ??
124
127
  HEADERS.FORWARDED_PROTO.toLowerCase();
125
- const protocol = getWebProtocol(requestOptions.headers[protoHeader], requestOptions.protocol);
128
+ const forwardedProtocolHeaderValue = requestOptions.headers[protoHeader];
129
+
130
+ if (Array.isArray(forwardedProtocolHeaderValue)) {
131
+ // This really should never happen - only set-cookie is allowed to have
132
+ // multiple values.
133
+ throw new Error('invalid forwarded protocol header value. Reading header ' + protoHeader);
134
+ }
135
+
136
+ const protocol = getWebProtocol(forwardedProtocolHeaderValue, requestOptions.protocol);
126
137
  const combinedUrl = combineBaseUrl(protocol, host, url_prefix);
127
138
  debug('public url by request %o', combinedUrl);
128
139
  return combinedUrl;
@@ -1,3 +1,5 @@
1
+ import { describe, expect, test } from 'vitest';
2
+
1
3
  import { combineBaseUrl } from '../src';
2
4
 
3
5
  describe('combineBaseUrl', () => {
@@ -1,4 +1,5 @@
1
1
  import * as httpMocks from 'node-mocks-http';
2
+ import { describe, expect, test } from 'vitest';
2
3
 
3
4
  import { HEADERS } from '@verdaccio/core';
4
5
 
@@ -102,7 +103,7 @@ describe('host', () => {
102
103
  });
103
104
 
104
105
  expect(
105
- getPublicUrl(null, {
106
+ getPublicUrl(undefined, {
106
107
  host: req.hostname,
107
108
  headers: req.headers as any,
108
109
  protocol: req.protocol,
@@ -316,6 +317,31 @@ describe('env variable', () => {
316
317
  delete process.env.VERDACCIO_FORWARDED_PROTO;
317
318
  });
318
319
 
320
+ test('with the VERDACCIO_FORWARDED_PROTO environment variable set to "set-cookie"', () => {
321
+ process.env.VERDACCIO_FORWARDED_PROTO = 'set-cookie';
322
+ const req = httpMocks.createRequest({
323
+ method: 'GET',
324
+ headers: {
325
+ host: 'some.com',
326
+ cookie: 'name=value; name2=value2;',
327
+ 'set-cookie': [
328
+ 'cookieName1=value; expires=Tue, 19 Jan 2038 03:14:07 GMT;',
329
+ 'cookieName2=value; expires=Tue, 19 Jan 2038 03:14:07 GMT;',
330
+ ],
331
+ },
332
+ url: '/',
333
+ });
334
+
335
+ expect(() =>
336
+ getPublicUrl('/test/', {
337
+ host: req.hostname,
338
+ headers: req.headers as any,
339
+ protocol: req.protocol,
340
+ })
341
+ ).toThrow('invalid forwarded protocol header value. Reading header set-cookie');
342
+ delete process.env.VERDACCIO_FORWARDED_PROTO;
343
+ });
344
+
319
345
  test('with a invalid X-Forwarded-Proto https and host injection with invalid host', () => {
320
346
  process.env.VERDACCIO_PUBLIC_URL = 'http://injection.test.com"><svg onload="alert(1)">';
321
347
  const req = httpMocks.createRequest({
@@ -1,3 +1,5 @@
1
+ import { describe, expect, test } from 'vitest';
2
+
1
3
  import { getWebProtocol } from '../src';
2
4
 
3
5
  describe('getWebProtocol', () => {
@@ -1,3 +1,5 @@
1
+ import { expect, test } from 'vitest';
2
+
1
3
  import { isURLhasValidProtocol } from '../src';
2
4
 
3
5
  test('should be HTTP/HTTPS protocol', () => {
@@ -1,3 +1,5 @@
1
+ import { expect, test } from 'vitest';
2
+
1
3
  import { isHost } from '../src';
2
4
 
3
5
  test('valid host', () => {
package/jest.config.js DELETED
@@ -1,3 +0,0 @@
1
- const config = require('../../../jest/config');
2
-
3
- module.exports = Object.assign({}, config, {});