lifecycleion 0.0.9 → 0.0.11
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/README.md +47 -36
- package/dist/lib/domain-utils/domain-utils.cjs +1154 -0
- package/dist/lib/domain-utils/domain-utils.cjs.map +1 -0
- package/dist/lib/domain-utils/domain-utils.d.cts +210 -0
- package/dist/lib/domain-utils/domain-utils.d.ts +210 -0
- package/dist/lib/domain-utils/domain-utils.js +1112 -0
- package/dist/lib/domain-utils/domain-utils.js.map +1 -0
- package/dist/lib/event-emitter.cjs.map +1 -1
- package/dist/lib/event-emitter.js.map +1 -1
- package/dist/lib/http-client/index.cjs +5254 -0
- package/dist/lib/http-client/index.cjs.map +1 -0
- package/dist/lib/http-client/index.d.cts +372 -0
- package/dist/lib/http-client/index.d.ts +372 -0
- package/dist/lib/http-client/index.js +5207 -0
- package/dist/lib/http-client/index.js.map +1 -0
- package/dist/lib/http-client-mock/index.cjs +525 -0
- package/dist/lib/http-client-mock/index.cjs.map +1 -0
- package/dist/lib/http-client-mock/index.d.cts +129 -0
- package/dist/lib/http-client-mock/index.d.ts +129 -0
- package/dist/lib/http-client-mock/index.js +488 -0
- package/dist/lib/http-client-mock/index.js.map +1 -0
- package/dist/lib/http-client-node/index.cjs +1112 -0
- package/dist/lib/http-client-node/index.cjs.map +1 -0
- package/dist/lib/http-client-node/index.d.cts +43 -0
- package/dist/lib/http-client-node/index.d.ts +43 -0
- package/dist/lib/http-client-node/index.js +1075 -0
- package/dist/lib/http-client-node/index.js.map +1 -0
- package/dist/lib/http-client-xhr/index.cjs +323 -0
- package/dist/lib/http-client-xhr/index.cjs.map +1 -0
- package/dist/lib/http-client-xhr/index.d.cts +23 -0
- package/dist/lib/http-client-xhr/index.d.ts +23 -0
- package/dist/lib/http-client-xhr/index.js +286 -0
- package/dist/lib/http-client-xhr/index.js.map +1 -0
- package/dist/lib/lifecycle-manager/index.cjs.map +1 -1
- package/dist/lib/lifecycle-manager/index.js.map +1 -1
- package/dist/lib/logger/index.cjs +6 -5
- package/dist/lib/logger/index.cjs.map +1 -1
- package/dist/lib/logger/index.d.cts +3 -3
- package/dist/lib/logger/index.d.ts +3 -3
- package/dist/lib/logger/index.js +6 -5
- package/dist/lib/logger/index.js.map +1 -1
- package/dist/lib/lru-cache/index.cjs +1141 -0
- package/dist/lib/lru-cache/index.cjs.map +1 -0
- package/dist/lib/lru-cache/index.d.cts +100 -0
- package/dist/lib/lru-cache/index.d.ts +100 -0
- package/dist/lib/lru-cache/index.js +1104 -0
- package/dist/lib/lru-cache/index.js.map +1 -0
- package/dist/lib/process-signal-manager.cjs.map +1 -1
- package/dist/lib/process-signal-manager.js.map +1 -1
- package/dist/lib/promise-protected-resolver.cjs.map +1 -1
- package/dist/lib/promise-protected-resolver.js.map +1 -1
- package/dist/lib/retry-utils/index.cjs.map +1 -1
- package/dist/lib/retry-utils/index.d.cts +3 -23
- package/dist/lib/retry-utils/index.d.ts +3 -23
- package/dist/lib/retry-utils/index.js.map +1 -1
- package/dist/lib/safe-handle-callback.cjs.map +1 -1
- package/dist/lib/safe-handle-callback.d.cts +2 -2
- package/dist/lib/safe-handle-callback.d.ts +2 -2
- package/dist/lib/safe-handle-callback.js.map +1 -1
- package/dist/lib/single-event-observer.cjs.map +1 -1
- package/dist/lib/single-event-observer.js.map +1 -1
- package/dist/types-CUPvmYQ8.d.cts +868 -0
- package/dist/types-D_MywcG0.d.cts +23 -0
- package/dist/types-D_MywcG0.d.ts +23 -0
- package/dist/types-Hw2PUTIT.d.ts +868 -0
- package/package.json +45 -3
|
@@ -0,0 +1,1154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/lib/domain-utils/domain-utils.ts
|
|
21
|
+
var domain_utils_exports = {};
|
|
22
|
+
__export(domain_utils_exports, {
|
|
23
|
+
canonicalizeBracketedIPv6Content: () => canonicalizeBracketedIPv6Content,
|
|
24
|
+
checkDNSLength: () => checkDNSLength,
|
|
25
|
+
getDomain: () => import_tldts2.getDomain,
|
|
26
|
+
getSubdomain: () => import_tldts2.getSubdomain,
|
|
27
|
+
isApexDomain: () => isApexDomain,
|
|
28
|
+
isIPAddress: () => isIPAddress,
|
|
29
|
+
isIPv4: () => isIPv4,
|
|
30
|
+
isIPv6: () => isIPv6,
|
|
31
|
+
matchesCORSCredentialsList: () => matchesCORSCredentialsList,
|
|
32
|
+
matchesDomainList: () => matchesDomainList,
|
|
33
|
+
matchesOriginList: () => matchesOriginList,
|
|
34
|
+
matchesWildcardDomain: () => matchesWildcardDomain,
|
|
35
|
+
matchesWildcardOrigin: () => matchesWildcardOrigin,
|
|
36
|
+
normalizeDomain: () => normalizeDomain,
|
|
37
|
+
normalizeOrigin: () => normalizeOrigin,
|
|
38
|
+
parseHostHeader: () => parseHostHeader,
|
|
39
|
+
safeParseURL: () => safeParseURL,
|
|
40
|
+
validateConfigEntry: () => validateConfigEntry
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(domain_utils_exports);
|
|
43
|
+
var import_tldts = require("tldts");
|
|
44
|
+
|
|
45
|
+
// src/lib/domain-utils/helpers.ts
|
|
46
|
+
var import_tr46 = require("tr46");
|
|
47
|
+
var MAX_LABELS = 32;
|
|
48
|
+
var STEP_LIMIT = 1e4;
|
|
49
|
+
var INVALID_DOMAIN_CHARS = /[/?#:[\]@\\]/;
|
|
50
|
+
var INTERNAL_PSEUDO_TLDS = Object.freeze(
|
|
51
|
+
/* @__PURE__ */ new Set(["localhost", "local", "test", "internal"])
|
|
52
|
+
);
|
|
53
|
+
function isAllWildcards(s) {
|
|
54
|
+
return s.split(".").every((l) => l === "*" || l === "**");
|
|
55
|
+
}
|
|
56
|
+
function hasPartialLabelWildcard(s) {
|
|
57
|
+
return s.split(".").some((l) => l.includes("*") && l !== "*" && l !== "**");
|
|
58
|
+
}
|
|
59
|
+
function checkDNSLength(host) {
|
|
60
|
+
const labels = host.split(".");
|
|
61
|
+
if (labels.length === 0 || labels.length > 127) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
let total = 0;
|
|
65
|
+
let i = 0;
|
|
66
|
+
for (const lbl of labels) {
|
|
67
|
+
const isLast = i++ === labels.length - 1;
|
|
68
|
+
if (lbl.length === 0) {
|
|
69
|
+
if (!isLast) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (lbl.length > 63) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
total += lbl.length + 1;
|
|
78
|
+
}
|
|
79
|
+
return total > 0 ? total - 1 <= 255 : false;
|
|
80
|
+
}
|
|
81
|
+
var IPV6_BASE_REGEX = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
|
|
82
|
+
function isIPv4(str) {
|
|
83
|
+
const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
84
|
+
return ipv4Regex.test(str);
|
|
85
|
+
}
|
|
86
|
+
function isIPv6(str) {
|
|
87
|
+
const cleaned = str.replace(/^\[|\]$/g, "");
|
|
88
|
+
if (cleaned.includes("%")) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
return IPV6_BASE_REGEX.test(cleaned);
|
|
92
|
+
}
|
|
93
|
+
function isIPAddress(str) {
|
|
94
|
+
return isIPv4(str) || isIPv6(str);
|
|
95
|
+
}
|
|
96
|
+
function canonicalizeIPAddressLiteral(host) {
|
|
97
|
+
const isIPAddressLike = host.includes(".") || host.includes(":") || host.startsWith("[") && host.endsWith("]");
|
|
98
|
+
if (!isIPAddressLike) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
if (isIPv6(host)) {
|
|
102
|
+
return canonicalizeBracketedIPv6Content(host.replace(/^\[|\]$/g, ""));
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
const url = new URL(`http://${host}/`);
|
|
106
|
+
const canonicalHostname = url.hostname.toLowerCase();
|
|
107
|
+
if (isIPv4(canonicalHostname)) {
|
|
108
|
+
return canonicalHostname;
|
|
109
|
+
}
|
|
110
|
+
if (isIPv6(canonicalHostname)) {
|
|
111
|
+
return canonicalHostname.replace(/^\[|\]$/g, "");
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
function canonicalizeBracketedIPv6Content(content) {
|
|
118
|
+
try {
|
|
119
|
+
const url = new URL(`http://[${content}]/`);
|
|
120
|
+
return url.hostname.replace(/^\[|\]$/g, "");
|
|
121
|
+
} catch {
|
|
122
|
+
return content.toLowerCase();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function extractFixedTailAfterLastWildcard(patternLabels) {
|
|
126
|
+
let lastWildcardIdx = -1;
|
|
127
|
+
for (let i = patternLabels.length - 1; i >= 0; i--) {
|
|
128
|
+
const lbl = patternLabels[i];
|
|
129
|
+
if (lbl === "*" || lbl === "**") {
|
|
130
|
+
lastWildcardIdx = i;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const fixedTailStart = lastWildcardIdx + 1;
|
|
135
|
+
const fixedTail = patternLabels.slice(fixedTailStart);
|
|
136
|
+
return { fixedTailStart, fixedTail };
|
|
137
|
+
}
|
|
138
|
+
function matchesWildcardLabelsInternal(domainLabels, patternLabels, domainIndex, patternIndex, counter) {
|
|
139
|
+
if (++counter.count > STEP_LIMIT) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
while (patternIndex < patternLabels.length) {
|
|
143
|
+
const patternLabel = patternLabels[patternIndex];
|
|
144
|
+
if (patternLabel === "**") {
|
|
145
|
+
const isLeftmost = patternIndex === 0;
|
|
146
|
+
if (isLeftmost) {
|
|
147
|
+
for (let i = domainIndex + 1; i <= domainLabels.length; i++) {
|
|
148
|
+
if (matchesWildcardLabelsInternal(
|
|
149
|
+
domainLabels,
|
|
150
|
+
patternLabels,
|
|
151
|
+
i,
|
|
152
|
+
patternIndex + 1,
|
|
153
|
+
counter
|
|
154
|
+
)) {
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
if (matchesWildcardLabelsInternal(
|
|
161
|
+
domainLabels,
|
|
162
|
+
patternLabels,
|
|
163
|
+
domainIndex,
|
|
164
|
+
patternIndex + 1,
|
|
165
|
+
counter
|
|
166
|
+
)) {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
for (let i = domainIndex + 1; i <= domainLabels.length; i++) {
|
|
170
|
+
if (matchesWildcardLabelsInternal(
|
|
171
|
+
domainLabels,
|
|
172
|
+
patternLabels,
|
|
173
|
+
i,
|
|
174
|
+
patternIndex + 1,
|
|
175
|
+
counter
|
|
176
|
+
)) {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return false;
|
|
181
|
+
} else if (patternLabel === "*") {
|
|
182
|
+
if (domainIndex >= domainLabels.length) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
domainIndex++;
|
|
186
|
+
patternIndex++;
|
|
187
|
+
} else {
|
|
188
|
+
if (domainIndex >= domainLabels.length || domainLabels[domainIndex] !== patternLabel) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
domainIndex++;
|
|
192
|
+
patternIndex++;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return domainIndex === domainLabels.length;
|
|
196
|
+
}
|
|
197
|
+
function matchesWildcardLabels(domainLabels, patternLabels) {
|
|
198
|
+
const counter = { count: 0 };
|
|
199
|
+
return matchesWildcardLabelsInternal(
|
|
200
|
+
domainLabels,
|
|
201
|
+
patternLabels,
|
|
202
|
+
0,
|
|
203
|
+
0,
|
|
204
|
+
counter
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
function matchesMultiLabelPattern(domain, pattern) {
|
|
208
|
+
const domainLabels = domain.split(".");
|
|
209
|
+
const patternLabels = pattern.split(".");
|
|
210
|
+
if (domainLabels.length > MAX_LABELS || patternLabels.length > MAX_LABELS) {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
if (patternLabels.length === 0 || patternLabels.every((label) => label === "*" || label === "**")) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
const { fixedTailStart, fixedTail } = extractFixedTailAfterLastWildcard(patternLabels);
|
|
217
|
+
if (domainLabels.length < fixedTail.length) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
for (let i = 0; i < fixedTail.length; i++) {
|
|
221
|
+
const domainLabel = domainLabels[domainLabels.length - fixedTail.length + i];
|
|
222
|
+
const patternLabel = fixedTail[i];
|
|
223
|
+
if (patternLabel !== domainLabel) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const remainingDomainLabels = domainLabels.slice(
|
|
228
|
+
0,
|
|
229
|
+
domainLabels.length - fixedTail.length
|
|
230
|
+
);
|
|
231
|
+
const leftPatternLabels = patternLabels.slice(0, fixedTailStart);
|
|
232
|
+
if (leftPatternLabels.length === 0) {
|
|
233
|
+
return remainingDomainLabels.length === 0;
|
|
234
|
+
}
|
|
235
|
+
return matchesWildcardLabels(remainingDomainLabels, leftPatternLabels);
|
|
236
|
+
}
|
|
237
|
+
function toAsciiDots(s) {
|
|
238
|
+
return s.replace(/[.。。]/g, ".");
|
|
239
|
+
}
|
|
240
|
+
function normalizeDomain(domain) {
|
|
241
|
+
let trimmed = domain.trim();
|
|
242
|
+
trimmed = toAsciiDots(trimmed);
|
|
243
|
+
if (/\.\.+$/.test(trimmed)) {
|
|
244
|
+
return "";
|
|
245
|
+
}
|
|
246
|
+
if (trimmed.endsWith(".")) {
|
|
247
|
+
trimmed = trimmed.slice(0, -1);
|
|
248
|
+
}
|
|
249
|
+
const canonicalIPAddress = canonicalizeIPAddressLiteral(trimmed);
|
|
250
|
+
if (canonicalIPAddress !== null) {
|
|
251
|
+
return canonicalIPAddress;
|
|
252
|
+
}
|
|
253
|
+
const normalized = trimmed.normalize("NFC").toLowerCase();
|
|
254
|
+
try {
|
|
255
|
+
const ascii = (0, import_tr46.toASCII)(normalized, {
|
|
256
|
+
useSTD3ASCIIRules: true,
|
|
257
|
+
checkHyphens: true,
|
|
258
|
+
checkBidi: true,
|
|
259
|
+
checkJoiners: true,
|
|
260
|
+
transitionalProcessing: false,
|
|
261
|
+
// matches modern browser behavior (non-transitional)
|
|
262
|
+
verifyDNSLength: false
|
|
263
|
+
// we already do our own length checks
|
|
264
|
+
});
|
|
265
|
+
if (!ascii) {
|
|
266
|
+
throw new Error("TR46 processing failed");
|
|
267
|
+
}
|
|
268
|
+
return checkDNSLength(ascii) ? ascii : "";
|
|
269
|
+
} catch {
|
|
270
|
+
return "";
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function normalizeWildcardPattern(pattern) {
|
|
274
|
+
let trimmed = pattern.trim().normalize("NFC").replace(/[.。。]/g, ".");
|
|
275
|
+
if (INVALID_DOMAIN_CHARS.test(trimmed)) {
|
|
276
|
+
return "";
|
|
277
|
+
}
|
|
278
|
+
if (trimmed.endsWith(".")) {
|
|
279
|
+
trimmed = trimmed.slice(0, -1);
|
|
280
|
+
}
|
|
281
|
+
const labels = trimmed.split(".");
|
|
282
|
+
for (const lbl of labels) {
|
|
283
|
+
if (lbl.length === 0) {
|
|
284
|
+
return "";
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
const normalizedLabels = [];
|
|
288
|
+
for (const lbl of labels) {
|
|
289
|
+
if (lbl === "*" || lbl === "**") {
|
|
290
|
+
normalizedLabels.push(lbl);
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (lbl.length > 63) {
|
|
294
|
+
return "";
|
|
295
|
+
}
|
|
296
|
+
const nd = normalizeDomain(lbl);
|
|
297
|
+
if (nd === "") {
|
|
298
|
+
return "";
|
|
299
|
+
}
|
|
300
|
+
normalizedLabels.push(nd);
|
|
301
|
+
}
|
|
302
|
+
const concreteLabels = normalizedLabels.filter(
|
|
303
|
+
(lbl) => lbl !== "*" && lbl !== "**"
|
|
304
|
+
);
|
|
305
|
+
if (concreteLabels.length > 0) {
|
|
306
|
+
const concretePattern = concreteLabels.join(".");
|
|
307
|
+
if (!checkDNSLength(concretePattern)) {
|
|
308
|
+
return "";
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return normalizedLabels.join(".");
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/lib/domain-utils/domain-utils.ts
|
|
315
|
+
var import_tldts2 = require("tldts");
|
|
316
|
+
function safeParseURL(input) {
|
|
317
|
+
try {
|
|
318
|
+
return new URL(input);
|
|
319
|
+
} catch {
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function hasValidWildcardOriginHost(url) {
|
|
324
|
+
return normalizeDomain(url.hostname) !== "";
|
|
325
|
+
}
|
|
326
|
+
function extractAuthority(input, schemeIdx) {
|
|
327
|
+
const afterScheme = input.slice(schemeIdx + 3);
|
|
328
|
+
const cut = Math.min(
|
|
329
|
+
...[
|
|
330
|
+
afterScheme.indexOf("/"),
|
|
331
|
+
afterScheme.indexOf("?"),
|
|
332
|
+
afterScheme.indexOf("#")
|
|
333
|
+
].filter((i) => i !== -1)
|
|
334
|
+
);
|
|
335
|
+
return cut === Infinity ? afterScheme : afterScheme.slice(0, cut);
|
|
336
|
+
}
|
|
337
|
+
function hasDanglingPortInAuthority(input) {
|
|
338
|
+
const schemeIdx = input.indexOf("://");
|
|
339
|
+
if (schemeIdx === -1) {
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
const authority = extractAuthority(input, schemeIdx);
|
|
343
|
+
const at = authority.lastIndexOf("@");
|
|
344
|
+
const hostPort = at === -1 ? authority : authority.slice(at + 1);
|
|
345
|
+
return hostPort.endsWith(":");
|
|
346
|
+
}
|
|
347
|
+
function normalizeOrigin(origin) {
|
|
348
|
+
if (origin === "null") {
|
|
349
|
+
return "null";
|
|
350
|
+
}
|
|
351
|
+
const normalizedOrigin = toAsciiDots(origin);
|
|
352
|
+
if (hasDanglingPortInAuthority(normalizedOrigin)) {
|
|
353
|
+
return "";
|
|
354
|
+
}
|
|
355
|
+
const url = safeParseURL(normalizedOrigin);
|
|
356
|
+
if (url) {
|
|
357
|
+
if (url.username || url.password || url.pathname && url.pathname !== "/" || url.search || url.hash) {
|
|
358
|
+
return "";
|
|
359
|
+
}
|
|
360
|
+
const normalizedHostname = normalizeDomain(url.hostname);
|
|
361
|
+
if (normalizedHostname === "") {
|
|
362
|
+
return "";
|
|
363
|
+
}
|
|
364
|
+
let host;
|
|
365
|
+
const schemeSep = normalizedOrigin.indexOf("://");
|
|
366
|
+
const authority = extractAuthority(normalizedOrigin, schemeSep);
|
|
367
|
+
const bracketMatch = authority.match(/\[([^\]]+)\]/);
|
|
368
|
+
const rawBracketContent = bracketMatch ? bracketMatch[1] : null;
|
|
369
|
+
const hostnameForIpv6Check = (rawBracketContent ? rawBracketContent : normalizedHostname).replace(/%25/g, "%").toLowerCase();
|
|
370
|
+
if (isIPv6(hostnameForIpv6Check)) {
|
|
371
|
+
const raw = rawBracketContent ? rawBracketContent : normalizedHostname.replace(/^\[|\]$/g, "");
|
|
372
|
+
const canon = canonicalizeBracketedIPv6Content(raw);
|
|
373
|
+
host = `[${canon}]`;
|
|
374
|
+
} else {
|
|
375
|
+
host = normalizedHostname;
|
|
376
|
+
}
|
|
377
|
+
let port = "";
|
|
378
|
+
const protocolLower = url.protocol.toLowerCase();
|
|
379
|
+
const defaultPort = protocolLower === "https:" ? "443" : protocolLower === "http:" ? "80" : "";
|
|
380
|
+
if (url.port) {
|
|
381
|
+
port = url.port === defaultPort ? "" : `:${url.port}`;
|
|
382
|
+
} else {
|
|
383
|
+
let portMatch = authority.match(/^(?:[^@]*@)?\[[^\]]+\]:(\d+)$/);
|
|
384
|
+
if (portMatch) {
|
|
385
|
+
const explicit = portMatch[1];
|
|
386
|
+
port = explicit === defaultPort ? "" : `:${explicit}`;
|
|
387
|
+
} else {
|
|
388
|
+
portMatch = authority.match(/^(?:[^@]*@)?([^:]+):(\d+)$/);
|
|
389
|
+
if (portMatch) {
|
|
390
|
+
const explicit = portMatch[2];
|
|
391
|
+
port = explicit === defaultPort ? "" : `:${explicit}`;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return `${protocolLower}//${host}${port}`;
|
|
396
|
+
}
|
|
397
|
+
return "";
|
|
398
|
+
}
|
|
399
|
+
function matchesWildcardDomain(domain, pattern) {
|
|
400
|
+
const normalizedDomain = normalizeDomain(domain);
|
|
401
|
+
if (normalizedDomain === "") {
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
const normalizedPattern = normalizeWildcardPattern(pattern);
|
|
405
|
+
if (!normalizedPattern) {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
if (!normalizedPattern.includes("*")) {
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
if (normalizedPattern === "*") {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
if (isIPAddress(normalizedDomain)) {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
if (isAllWildcards(normalizedPattern)) {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
const labels = normalizedPattern.split(".");
|
|
421
|
+
const { fixedTail: fixedTailLabels } = extractFixedTailAfterLastWildcard(labels);
|
|
422
|
+
if (fixedTailLabels.length === 0) {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
const tail = fixedTailLabels.join(".");
|
|
426
|
+
if (isIPAddress(tail)) {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
const ps = (0, import_tldts.getPublicSuffix)(tail);
|
|
430
|
+
if (INTERNAL_PSEUDO_TLDS.has(tail) || ps && ps === tail) {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
if (normalizedPattern.startsWith("**.")) {
|
|
434
|
+
if (normalizedDomain === normalizeDomain(normalizedPattern.slice(3))) {
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
return matchesMultiLabelPattern(normalizedDomain, normalizedPattern);
|
|
439
|
+
}
|
|
440
|
+
function matchesWildcardOrigin(origin, pattern) {
|
|
441
|
+
const normalizedOrigin = toAsciiDots(origin);
|
|
442
|
+
const normalizedPattern = toAsciiDots(pattern);
|
|
443
|
+
if (hasDanglingPortInAuthority(normalizedOrigin)) {
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
const originURL = safeParseURL(normalizedOrigin);
|
|
447
|
+
if (originURL) {
|
|
448
|
+
const scheme = originURL.protocol.toLowerCase();
|
|
449
|
+
if (scheme !== "http:" && scheme !== "https:") {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
if (originURL.username || originURL.password || originURL.pathname && originURL.pathname !== "/" || originURL.search || originURL.hash) {
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (normalizedPattern === "*") {
|
|
457
|
+
return originURL !== null && hasValidWildcardOriginHost(originURL);
|
|
458
|
+
}
|
|
459
|
+
const patternLower = normalizedPattern.toLowerCase();
|
|
460
|
+
if (patternLower === "https://*" || patternLower === "http://*") {
|
|
461
|
+
if (!originURL) {
|
|
462
|
+
return false;
|
|
463
|
+
}
|
|
464
|
+
const want = patternLower === "https://*" ? "https:" : "http:";
|
|
465
|
+
return originURL.protocol.toLowerCase() === want && hasValidWildcardOriginHost(originURL);
|
|
466
|
+
}
|
|
467
|
+
if (!originURL) {
|
|
468
|
+
return false;
|
|
469
|
+
}
|
|
470
|
+
const normalizedHostname = normalizeDomain(originURL.hostname);
|
|
471
|
+
if (normalizedHostname === "") {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
const originProtocol = originURL.protocol.slice(0, -1).toLowerCase();
|
|
475
|
+
if (normalizedPattern.includes("://")) {
|
|
476
|
+
const [patternProtocol, ...rest] = normalizedPattern.split("://");
|
|
477
|
+
const domainPattern = rest.join("://");
|
|
478
|
+
if (INVALID_DOMAIN_CHARS.test(domainPattern)) {
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
if (originProtocol !== patternProtocol.toLowerCase()) {
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
if (!domainPattern.includes("*") || isAllWildcards(domainPattern)) {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
return matchesWildcardDomain(normalizedHostname, domainPattern);
|
|
488
|
+
}
|
|
489
|
+
if (normalizedPattern.includes("*")) {
|
|
490
|
+
if (normalizedPattern !== "*" && isAllWildcards(normalizedPattern)) {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
return matchesWildcardDomain(normalizedHostname, normalizedPattern);
|
|
494
|
+
}
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
function matchesDomainList(domain, allowedDomains) {
|
|
498
|
+
const normalizedDomain = normalizeDomain(domain);
|
|
499
|
+
if (normalizedDomain === "") {
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
const cleaned = allowedDomains.map((s) => s.trim()).filter((s) => s.length > 0);
|
|
503
|
+
const ORIGIN_LIKE = /^[a-z][a-z0-9+\-.]*:\/\//i;
|
|
504
|
+
const originLike = cleaned.filter((s) => ORIGIN_LIKE.test(s));
|
|
505
|
+
if (originLike.length > 0) {
|
|
506
|
+
throw new Error(
|
|
507
|
+
`matchesDomainList: origin-style patterns are not allowed in domain lists: ${originLike.join(", ")}`
|
|
508
|
+
);
|
|
509
|
+
}
|
|
510
|
+
for (const allowed of cleaned) {
|
|
511
|
+
if (allowed.includes("*")) {
|
|
512
|
+
if (matchesWildcardDomain(domain, allowed)) {
|
|
513
|
+
return true;
|
|
514
|
+
}
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
const normalizedAllowed = normalizeDomain(allowed);
|
|
518
|
+
if (isAllowedExactHostname(normalizedAllowed) && normalizedDomain === normalizedAllowed) {
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
function isAllowedExactHostname(normalizedHostname) {
|
|
525
|
+
if (!normalizedHostname) {
|
|
526
|
+
return false;
|
|
527
|
+
}
|
|
528
|
+
if (normalizedHostname === "null") {
|
|
529
|
+
return false;
|
|
530
|
+
}
|
|
531
|
+
if (isIPAddress(normalizedHostname) || INTERNAL_PSEUDO_TLDS.has(normalizedHostname)) {
|
|
532
|
+
return true;
|
|
533
|
+
}
|
|
534
|
+
const publicSuffix = (0, import_tldts.getPublicSuffix)(normalizedHostname);
|
|
535
|
+
return !(publicSuffix && publicSuffix === normalizedHostname);
|
|
536
|
+
}
|
|
537
|
+
function isValidPortString(port) {
|
|
538
|
+
if (!/^\d+$/.test(port)) {
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
const portNumber = Number(port);
|
|
542
|
+
return Number.isInteger(portNumber) && portNumber >= 0 && portNumber <= 65535;
|
|
543
|
+
}
|
|
544
|
+
function validateConfigEntry(entry, context, options) {
|
|
545
|
+
const raw = (entry ?? "").trim();
|
|
546
|
+
const SCHEME_RE = /^[a-z][a-z0-9+\-.]*$/i;
|
|
547
|
+
if (!raw) {
|
|
548
|
+
return { valid: false, info: "empty entry", wildcardKind: "none" };
|
|
549
|
+
}
|
|
550
|
+
const opts = {
|
|
551
|
+
allowGlobalWildcard: false,
|
|
552
|
+
allowProtocolWildcard: true,
|
|
553
|
+
...options ?? {}
|
|
554
|
+
};
|
|
555
|
+
function validateConcreteLabels(pattern) {
|
|
556
|
+
const labels = pattern.split(".");
|
|
557
|
+
const concrete = [];
|
|
558
|
+
for (const lbl of labels) {
|
|
559
|
+
if (lbl === "*" || lbl === "**") {
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
if (lbl.length > 63) {
|
|
563
|
+
return false;
|
|
564
|
+
}
|
|
565
|
+
const nd2 = normalizeDomain(lbl);
|
|
566
|
+
if (nd2 === "") {
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
569
|
+
concrete.push(nd2);
|
|
570
|
+
}
|
|
571
|
+
if (concrete.length > 0) {
|
|
572
|
+
if (!checkDNSLength(concrete.join("."))) {
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
function wildcardTailIsInvalid(pattern) {
|
|
579
|
+
const normalized = normalizeWildcardPattern(pattern);
|
|
580
|
+
const labels = normalized.split(".");
|
|
581
|
+
const { fixedTail: fixedTailLabels } = extractFixedTailAfterLastWildcard(labels);
|
|
582
|
+
if (fixedTailLabels.length === 0) {
|
|
583
|
+
return true;
|
|
584
|
+
}
|
|
585
|
+
const tail = fixedTailLabels.join(".");
|
|
586
|
+
if (isIPAddress(tail)) {
|
|
587
|
+
return true;
|
|
588
|
+
}
|
|
589
|
+
const ps2 = (0, import_tldts.getPublicSuffix)(tail);
|
|
590
|
+
if (INTERNAL_PSEUDO_TLDS.has(tail) || ps2 && ps2 === tail) {
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
function validateDomainWildcard(pattern) {
|
|
596
|
+
const trimmed = pattern.trim().normalize("NFC").replace(/[.。。]/g, ".");
|
|
597
|
+
if (INVALID_DOMAIN_CHARS.test(trimmed)) {
|
|
598
|
+
return {
|
|
599
|
+
valid: false,
|
|
600
|
+
info: "invalid characters in domain pattern",
|
|
601
|
+
wildcardKind: "none"
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
if (hasPartialLabelWildcard(trimmed)) {
|
|
605
|
+
return {
|
|
606
|
+
valid: false,
|
|
607
|
+
info: "partial-label wildcards are not allowed",
|
|
608
|
+
wildcardKind: "none"
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
const normalized = normalizeWildcardPattern(trimmed);
|
|
612
|
+
if (!normalized) {
|
|
613
|
+
return {
|
|
614
|
+
valid: false,
|
|
615
|
+
info: "invalid domain labels",
|
|
616
|
+
wildcardKind: "none"
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
if (normalized.split(".").length > MAX_LABELS) {
|
|
620
|
+
return {
|
|
621
|
+
valid: false,
|
|
622
|
+
info: "wildcard pattern exceeds label limit",
|
|
623
|
+
wildcardKind: "none"
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
if (isAllWildcards(normalized)) {
|
|
627
|
+
return {
|
|
628
|
+
valid: false,
|
|
629
|
+
info: "all-wildcards pattern is not allowed",
|
|
630
|
+
wildcardKind: "none"
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
if (!validateConcreteLabels(normalized)) {
|
|
634
|
+
return {
|
|
635
|
+
valid: false,
|
|
636
|
+
info: "invalid domain labels",
|
|
637
|
+
wildcardKind: "none"
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
if (wildcardTailIsInvalid(normalized)) {
|
|
641
|
+
return {
|
|
642
|
+
valid: false,
|
|
643
|
+
info: "wildcard tail targets public suffix or IP (disallowed)",
|
|
644
|
+
wildcardKind: "none"
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
return { valid: true, wildcardKind: "subdomain" };
|
|
648
|
+
}
|
|
649
|
+
function validateExactDomain(s) {
|
|
650
|
+
if (s.toLowerCase() === "null") {
|
|
651
|
+
return {
|
|
652
|
+
valid: false,
|
|
653
|
+
info: '"null" is not a valid domain entry',
|
|
654
|
+
wildcardKind: "none"
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
const sDots = toAsciiDots(s);
|
|
658
|
+
if (isIPAddress(sDots)) {
|
|
659
|
+
return { valid: true, wildcardKind: "none" };
|
|
660
|
+
}
|
|
661
|
+
if (INVALID_DOMAIN_CHARS.test(s)) {
|
|
662
|
+
return {
|
|
663
|
+
valid: false,
|
|
664
|
+
info: "invalid characters in domain",
|
|
665
|
+
wildcardKind: "none"
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
const nd2 = normalizeDomain(s);
|
|
669
|
+
if (nd2 === "") {
|
|
670
|
+
return { valid: false, info: "invalid domain", wildcardKind: "none" };
|
|
671
|
+
}
|
|
672
|
+
const ps2 = (0, import_tldts.getPublicSuffix)(nd2);
|
|
673
|
+
if (ps2 && ps2 === nd2 && !INTERNAL_PSEUDO_TLDS.has(nd2)) {
|
|
674
|
+
return {
|
|
675
|
+
valid: false,
|
|
676
|
+
info: "entry equals a public suffix (not registrable)",
|
|
677
|
+
wildcardKind: "none"
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
return { valid: true, wildcardKind: "none" };
|
|
681
|
+
}
|
|
682
|
+
if (context === "domain") {
|
|
683
|
+
if (/^[a-z][a-z0-9+\-.]*:\/\//i.test(raw)) {
|
|
684
|
+
return {
|
|
685
|
+
valid: false,
|
|
686
|
+
info: "protocols are not allowed in domain context",
|
|
687
|
+
wildcardKind: "none"
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
if (raw === "*") {
|
|
691
|
+
return opts.allowGlobalWildcard ? { valid: true, wildcardKind: "global" } : {
|
|
692
|
+
valid: false,
|
|
693
|
+
info: "global wildcard '*' not allowed in this context",
|
|
694
|
+
wildcardKind: "none"
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
if (raw.includes("*")) {
|
|
698
|
+
return validateDomainWildcard(raw);
|
|
699
|
+
}
|
|
700
|
+
return validateExactDomain(raw);
|
|
701
|
+
}
|
|
702
|
+
if (raw === "null") {
|
|
703
|
+
return { valid: true, wildcardKind: "none" };
|
|
704
|
+
}
|
|
705
|
+
if (raw === "*") {
|
|
706
|
+
return opts.allowGlobalWildcard ? { valid: true, wildcardKind: "global" } : {
|
|
707
|
+
valid: false,
|
|
708
|
+
info: "global wildcard '*' not allowed in this context",
|
|
709
|
+
wildcardKind: "none"
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
const schemeIdx = raw.indexOf("://");
|
|
713
|
+
if (schemeIdx === -1) {
|
|
714
|
+
if (raw.includes("*")) {
|
|
715
|
+
return validateDomainWildcard(raw);
|
|
716
|
+
}
|
|
717
|
+
return validateExactDomain(raw);
|
|
718
|
+
}
|
|
719
|
+
const scheme = raw.slice(0, schemeIdx).toLowerCase();
|
|
720
|
+
const rest = raw.slice(schemeIdx + 3);
|
|
721
|
+
if (!SCHEME_RE.test(scheme)) {
|
|
722
|
+
return {
|
|
723
|
+
valid: false,
|
|
724
|
+
info: "invalid scheme in origin",
|
|
725
|
+
wildcardKind: "none"
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
let normalizedRest = rest;
|
|
729
|
+
if (normalizedRest.includes("#") || normalizedRest.includes("?")) {
|
|
730
|
+
return {
|
|
731
|
+
valid: false,
|
|
732
|
+
info: "origin must not contain path, query, or fragment",
|
|
733
|
+
wildcardKind: "none"
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
const slashIdx = normalizedRest.indexOf("/");
|
|
737
|
+
if (slashIdx !== -1) {
|
|
738
|
+
const authority = normalizedRest.slice(0, slashIdx);
|
|
739
|
+
const suffix = normalizedRest.slice(slashIdx);
|
|
740
|
+
if (suffix !== "/" || authority.includes("*")) {
|
|
741
|
+
return {
|
|
742
|
+
valid: false,
|
|
743
|
+
info: "origin must not contain path, query, or fragment",
|
|
744
|
+
wildcardKind: "none"
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
normalizedRest = authority;
|
|
748
|
+
}
|
|
749
|
+
if (!normalizedRest) {
|
|
750
|
+
return {
|
|
751
|
+
valid: false,
|
|
752
|
+
info: "missing host in origin",
|
|
753
|
+
wildcardKind: "none"
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
if (normalizedRest.includes("@")) {
|
|
757
|
+
return {
|
|
758
|
+
valid: false,
|
|
759
|
+
info: "origin must not include userinfo",
|
|
760
|
+
wildcardKind: "none"
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
if (normalizedRest === "*") {
|
|
764
|
+
if (scheme !== "http" && scheme !== "https") {
|
|
765
|
+
return {
|
|
766
|
+
valid: false,
|
|
767
|
+
info: "wildcard origins require http or https scheme",
|
|
768
|
+
wildcardKind: "none"
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
if (!opts.allowProtocolWildcard) {
|
|
772
|
+
return {
|
|
773
|
+
valid: false,
|
|
774
|
+
info: "protocol wildcard not allowed",
|
|
775
|
+
wildcardKind: "none"
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
const info2 = scheme === "http" || scheme === "https" ? void 0 : "non-http(s) scheme; CORS may not match";
|
|
779
|
+
return { valid: true, info: info2, wildcardKind: "protocol" };
|
|
780
|
+
}
|
|
781
|
+
let host = normalizedRest;
|
|
782
|
+
let hasPort = false;
|
|
783
|
+
if (normalizedRest.startsWith("[")) {
|
|
784
|
+
const end = normalizedRest.indexOf("]");
|
|
785
|
+
if (end === -1) {
|
|
786
|
+
return {
|
|
787
|
+
valid: false,
|
|
788
|
+
info: "unclosed IPv6 bracket",
|
|
789
|
+
wildcardKind: "none"
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
host = normalizedRest.slice(0, end + 1);
|
|
793
|
+
const after = normalizedRest.slice(end + 1);
|
|
794
|
+
if (after.startsWith(":")) {
|
|
795
|
+
const port = after.slice(1);
|
|
796
|
+
if (!isValidPortString(port)) {
|
|
797
|
+
return {
|
|
798
|
+
valid: false,
|
|
799
|
+
info: "invalid port in origin",
|
|
800
|
+
wildcardKind: "none"
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
hasPort = true;
|
|
804
|
+
} else if (after.length > 0) {
|
|
805
|
+
return {
|
|
806
|
+
valid: false,
|
|
807
|
+
info: "unexpected characters after IPv6 host",
|
|
808
|
+
wildcardKind: "none"
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
} else {
|
|
812
|
+
const colon = normalizedRest.indexOf(":");
|
|
813
|
+
if (colon !== -1) {
|
|
814
|
+
host = normalizedRest.slice(0, colon);
|
|
815
|
+
const port = normalizedRest.slice(colon + 1);
|
|
816
|
+
if (!isValidPortString(port)) {
|
|
817
|
+
return {
|
|
818
|
+
valid: false,
|
|
819
|
+
info: "invalid port in origin",
|
|
820
|
+
wildcardKind: "none"
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
hasPort = true;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
if (host.includes("*")) {
|
|
827
|
+
if (scheme !== "http" && scheme !== "https") {
|
|
828
|
+
return {
|
|
829
|
+
valid: false,
|
|
830
|
+
info: "wildcard origins require http or https scheme",
|
|
831
|
+
wildcardKind: "none"
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
if (host.includes("[") || host.includes("]")) {
|
|
835
|
+
return {
|
|
836
|
+
valid: false,
|
|
837
|
+
info: "wildcard host cannot be an IP literal",
|
|
838
|
+
wildcardKind: "none"
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
if (hasPort) {
|
|
842
|
+
return {
|
|
843
|
+
valid: false,
|
|
844
|
+
info: "ports are not allowed in wildcard origins",
|
|
845
|
+
wildcardKind: "none"
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
const verdict = validateDomainWildcard(host);
|
|
849
|
+
if (!verdict.valid) {
|
|
850
|
+
return verdict;
|
|
851
|
+
}
|
|
852
|
+
const info2 = scheme === "http" || scheme === "https" ? void 0 : "non-http(s) scheme; CORS may not match";
|
|
853
|
+
return { valid: true, info: info2, wildcardKind: "subdomain" };
|
|
854
|
+
}
|
|
855
|
+
if (host.startsWith("[")) {
|
|
856
|
+
const bracketContent = host.slice(1, -1);
|
|
857
|
+
if (!isIPv6(bracketContent)) {
|
|
858
|
+
return {
|
|
859
|
+
valid: false,
|
|
860
|
+
info: "invalid IPv6 literal in origin",
|
|
861
|
+
wildcardKind: "none"
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
const info2 = scheme === "http" || scheme === "https" ? void 0 : "non-http(s) scheme; CORS may not match";
|
|
865
|
+
return { valid: true, info: info2, wildcardKind: "none" };
|
|
866
|
+
}
|
|
867
|
+
const hostDots = toAsciiDots(host);
|
|
868
|
+
if (isIPAddress(hostDots)) {
|
|
869
|
+
const info2 = scheme === "http" || scheme === "https" ? void 0 : "non-http(s) scheme; CORS may not match";
|
|
870
|
+
return { valid: true, info: info2, wildcardKind: "none" };
|
|
871
|
+
}
|
|
872
|
+
const nd = normalizeDomain(host);
|
|
873
|
+
if (nd === "") {
|
|
874
|
+
return {
|
|
875
|
+
valid: false,
|
|
876
|
+
info: "invalid domain in origin",
|
|
877
|
+
wildcardKind: "none"
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
const ps = (0, import_tldts.getPublicSuffix)(nd);
|
|
881
|
+
if (ps && ps === nd && !INTERNAL_PSEUDO_TLDS.has(nd)) {
|
|
882
|
+
return {
|
|
883
|
+
valid: false,
|
|
884
|
+
info: "origin host equals a public suffix (not registrable)",
|
|
885
|
+
wildcardKind: "none"
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
const info = scheme === "http" || scheme === "https" ? void 0 : "non-http(s) scheme; CORS may not match";
|
|
889
|
+
return { valid: true, info, wildcardKind: "none" };
|
|
890
|
+
}
|
|
891
|
+
function parseExactOriginForMatching(entry) {
|
|
892
|
+
if (entry === "null") {
|
|
893
|
+
return { normalizedOrigin: "null", normalizedHostname: "" };
|
|
894
|
+
}
|
|
895
|
+
const normalized = toAsciiDots(entry);
|
|
896
|
+
const schemeIdx = normalized.indexOf("://");
|
|
897
|
+
if (schemeIdx !== -1) {
|
|
898
|
+
const authority = extractAuthority(normalized, schemeIdx);
|
|
899
|
+
const at = authority.lastIndexOf("@");
|
|
900
|
+
const hostPort = at === -1 ? authority : authority.slice(at + 1);
|
|
901
|
+
if (hostPort.endsWith(":")) {
|
|
902
|
+
return null;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
const url = safeParseURL(normalized);
|
|
906
|
+
if (!url) {
|
|
907
|
+
return null;
|
|
908
|
+
}
|
|
909
|
+
if (url.username || url.password) {
|
|
910
|
+
return null;
|
|
911
|
+
}
|
|
912
|
+
if (url.pathname && url.pathname !== "/") {
|
|
913
|
+
return null;
|
|
914
|
+
}
|
|
915
|
+
if (url.search || url.hash) {
|
|
916
|
+
return null;
|
|
917
|
+
}
|
|
918
|
+
const normalizedOrigin = normalizeOrigin(entry);
|
|
919
|
+
if (normalizedOrigin === "") {
|
|
920
|
+
return null;
|
|
921
|
+
}
|
|
922
|
+
return {
|
|
923
|
+
normalizedOrigin,
|
|
924
|
+
normalizedHostname: normalizeDomain(url.hostname)
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
function isCredentialsSafeWildcardOriginPattern(pattern) {
|
|
928
|
+
const trimmed = pattern.trim().normalize("NFC").replace(/[.。。]/g, ".");
|
|
929
|
+
function isValidCredentialWildcardHost(hostPattern) {
|
|
930
|
+
if (isAllWildcards(hostPattern)) {
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
if (INVALID_DOMAIN_CHARS.test(hostPattern)) {
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
if (hasPartialLabelWildcard(hostPattern)) {
|
|
937
|
+
return false;
|
|
938
|
+
}
|
|
939
|
+
const labels = hostPattern.split(".");
|
|
940
|
+
const concrete = [];
|
|
941
|
+
for (const lbl of labels) {
|
|
942
|
+
if (lbl === "*" || lbl === "**") {
|
|
943
|
+
continue;
|
|
944
|
+
}
|
|
945
|
+
if (lbl.length > 63) {
|
|
946
|
+
return false;
|
|
947
|
+
}
|
|
948
|
+
const nd = normalizeDomain(lbl);
|
|
949
|
+
if (nd === "") {
|
|
950
|
+
return false;
|
|
951
|
+
}
|
|
952
|
+
concrete.push(nd);
|
|
953
|
+
}
|
|
954
|
+
if (concrete.length > 0 && !checkDNSLength(concrete.join("."))) {
|
|
955
|
+
return false;
|
|
956
|
+
}
|
|
957
|
+
const normalized = normalizeWildcardPattern(hostPattern);
|
|
958
|
+
const { fixedTail } = extractFixedTailAfterLastWildcard(
|
|
959
|
+
(normalized || hostPattern).split(".")
|
|
960
|
+
);
|
|
961
|
+
if (!normalized || fixedTail.length === 0) {
|
|
962
|
+
return false;
|
|
963
|
+
}
|
|
964
|
+
const tail = fixedTail.join(".");
|
|
965
|
+
if (isIPAddress(tail)) {
|
|
966
|
+
return false;
|
|
967
|
+
}
|
|
968
|
+
const ps = (0, import_tldts.getPublicSuffix)(tail);
|
|
969
|
+
return !INTERNAL_PSEUDO_TLDS.has(tail) && !(ps && ps === tail);
|
|
970
|
+
}
|
|
971
|
+
if (!trimmed.includes("*")) {
|
|
972
|
+
return false;
|
|
973
|
+
}
|
|
974
|
+
const schemeIdx = trimmed.indexOf("://");
|
|
975
|
+
if (schemeIdx === -1) {
|
|
976
|
+
return isValidCredentialWildcardHost(trimmed);
|
|
977
|
+
}
|
|
978
|
+
const scheme = trimmed.slice(0, schemeIdx).toLowerCase();
|
|
979
|
+
const host = trimmed.slice(schemeIdx + 3);
|
|
980
|
+
if (scheme !== "http" && scheme !== "https" || host === "*") {
|
|
981
|
+
return false;
|
|
982
|
+
}
|
|
983
|
+
return isValidCredentialWildcardHost(host);
|
|
984
|
+
}
|
|
985
|
+
function matchesOriginList(origin, allowedOrigins, opts = {}) {
|
|
986
|
+
const cleaned = allowedOrigins.map((s) => s.trim()).filter(Boolean);
|
|
987
|
+
if (!origin) {
|
|
988
|
+
return !!opts.treatNoOriginAsAllowed && cleaned.includes("*");
|
|
989
|
+
}
|
|
990
|
+
const parsedOrigin = parseExactOriginForMatching(origin);
|
|
991
|
+
if (!parsedOrigin) {
|
|
992
|
+
return false;
|
|
993
|
+
}
|
|
994
|
+
return cleaned.some((allowed) => {
|
|
995
|
+
if (allowed === "*") {
|
|
996
|
+
return matchesWildcardOrigin(origin, "*");
|
|
997
|
+
}
|
|
998
|
+
if (allowed.includes("*")) {
|
|
999
|
+
return matchesWildcardOrigin(origin, allowed);
|
|
1000
|
+
}
|
|
1001
|
+
if (allowed === "null") {
|
|
1002
|
+
return parsedOrigin.normalizedOrigin === "null";
|
|
1003
|
+
}
|
|
1004
|
+
if (!allowed.includes("://")) {
|
|
1005
|
+
const normalizedAllowedDomain = normalizeDomain(allowed);
|
|
1006
|
+
return isAllowedExactHostname(normalizedAllowedDomain) && parsedOrigin.normalizedHostname !== "" && parsedOrigin.normalizedHostname === normalizedAllowedDomain;
|
|
1007
|
+
}
|
|
1008
|
+
const parsedAllowed = parseExactOriginForMatching(allowed);
|
|
1009
|
+
if (!parsedAllowed) {
|
|
1010
|
+
return false;
|
|
1011
|
+
}
|
|
1012
|
+
if (!isAllowedExactHostname(parsedAllowed.normalizedHostname)) {
|
|
1013
|
+
return false;
|
|
1014
|
+
}
|
|
1015
|
+
return parsedOrigin.normalizedOrigin === parsedAllowed.normalizedOrigin;
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
function matchesCORSCredentialsList(origin, allowedOrigins, options = {}) {
|
|
1019
|
+
if (!origin) {
|
|
1020
|
+
return false;
|
|
1021
|
+
}
|
|
1022
|
+
const parsedOrigin = parseExactOriginForMatching(origin);
|
|
1023
|
+
if (!parsedOrigin) {
|
|
1024
|
+
return false;
|
|
1025
|
+
}
|
|
1026
|
+
const cleaned = allowedOrigins.map((s) => s.trim()).filter(Boolean);
|
|
1027
|
+
const allowWildcard = !!options.allowWildcardSubdomains;
|
|
1028
|
+
for (const allowed of cleaned) {
|
|
1029
|
+
if (allowWildcard && allowed.includes("*")) {
|
|
1030
|
+
if (isCredentialsSafeWildcardOriginPattern(allowed) && matchesWildcardOrigin(origin, allowed)) {
|
|
1031
|
+
return true;
|
|
1032
|
+
}
|
|
1033
|
+
continue;
|
|
1034
|
+
}
|
|
1035
|
+
if (allowed === "null") {
|
|
1036
|
+
if (parsedOrigin.normalizedOrigin === "null") {
|
|
1037
|
+
return true;
|
|
1038
|
+
}
|
|
1039
|
+
continue;
|
|
1040
|
+
}
|
|
1041
|
+
if (!allowed.includes("://")) {
|
|
1042
|
+
const normalizedAllowedDomain = normalizeDomain(allowed);
|
|
1043
|
+
if (isAllowedExactHostname(normalizedAllowedDomain) && parsedOrigin.normalizedHostname !== "" && parsedOrigin.normalizedHostname === normalizedAllowedDomain) {
|
|
1044
|
+
return true;
|
|
1045
|
+
}
|
|
1046
|
+
continue;
|
|
1047
|
+
}
|
|
1048
|
+
const parsedAllowed = parseExactOriginForMatching(allowed);
|
|
1049
|
+
if (!parsedAllowed) {
|
|
1050
|
+
continue;
|
|
1051
|
+
}
|
|
1052
|
+
if (!isAllowedExactHostname(parsedAllowed.normalizedHostname)) {
|
|
1053
|
+
continue;
|
|
1054
|
+
}
|
|
1055
|
+
if (parsedOrigin.normalizedOrigin === parsedAllowed.normalizedOrigin) {
|
|
1056
|
+
return true;
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
return false;
|
|
1060
|
+
}
|
|
1061
|
+
function parseHostHeader(host) {
|
|
1062
|
+
const trimmedHost = host.trim();
|
|
1063
|
+
if (!trimmedHost) {
|
|
1064
|
+
return { domain: "", port: "" };
|
|
1065
|
+
}
|
|
1066
|
+
function parsePortOrFail(port) {
|
|
1067
|
+
if (!isValidPortString(port)) {
|
|
1068
|
+
return { domain: "", port: "" };
|
|
1069
|
+
}
|
|
1070
|
+
return null;
|
|
1071
|
+
}
|
|
1072
|
+
if (trimmedHost.startsWith("[")) {
|
|
1073
|
+
const end = trimmedHost.indexOf("]");
|
|
1074
|
+
if (end !== -1) {
|
|
1075
|
+
const domain = trimmedHost.slice(1, end);
|
|
1076
|
+
const rest = trimmedHost.slice(end + 1);
|
|
1077
|
+
if (!isIPv6(domain)) {
|
|
1078
|
+
return { domain: "", port: "" };
|
|
1079
|
+
}
|
|
1080
|
+
if (rest === "") {
|
|
1081
|
+
return { domain, port: "" };
|
|
1082
|
+
}
|
|
1083
|
+
if (rest.startsWith(":")) {
|
|
1084
|
+
const invalid2 = parsePortOrFail(rest.slice(1));
|
|
1085
|
+
if (invalid2) {
|
|
1086
|
+
return invalid2;
|
|
1087
|
+
}
|
|
1088
|
+
return { domain, port: rest.slice(1) };
|
|
1089
|
+
}
|
|
1090
|
+
return { domain: "", port: "" };
|
|
1091
|
+
}
|
|
1092
|
+
return { domain: "", port: "" };
|
|
1093
|
+
}
|
|
1094
|
+
const idx = trimmedHost.indexOf(":");
|
|
1095
|
+
if (idx === -1) {
|
|
1096
|
+
return { domain: trimmedHost, port: "" };
|
|
1097
|
+
}
|
|
1098
|
+
if (idx === 0) {
|
|
1099
|
+
return { domain: "", port: "" };
|
|
1100
|
+
}
|
|
1101
|
+
const invalid = parsePortOrFail(trimmedHost.slice(idx + 1));
|
|
1102
|
+
if (invalid) {
|
|
1103
|
+
return invalid;
|
|
1104
|
+
}
|
|
1105
|
+
return {
|
|
1106
|
+
domain: trimmedHost.slice(0, idx),
|
|
1107
|
+
port: trimmedHost.slice(idx + 1)
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
function isApexDomain(domain) {
|
|
1111
|
+
const normalizedDomain = normalizeDomain(domain);
|
|
1112
|
+
if (!normalizedDomain || isIPAddress(normalizedDomain)) {
|
|
1113
|
+
return false;
|
|
1114
|
+
}
|
|
1115
|
+
const labels = normalizedDomain.split(".");
|
|
1116
|
+
const lastLabel = labels[labels.length - 1];
|
|
1117
|
+
if (INTERNAL_PSEUDO_TLDS.has(lastLabel)) {
|
|
1118
|
+
if (normalizedDomain === lastLabel) {
|
|
1119
|
+
return true;
|
|
1120
|
+
}
|
|
1121
|
+
if (lastLabel === "localhost") {
|
|
1122
|
+
return false;
|
|
1123
|
+
}
|
|
1124
|
+
return labels.length === 2;
|
|
1125
|
+
}
|
|
1126
|
+
const parsedDomain = (0, import_tldts.getDomain)(normalizedDomain);
|
|
1127
|
+
const subdomain = (0, import_tldts.getSubdomain)(normalizedDomain);
|
|
1128
|
+
if (!parsedDomain) {
|
|
1129
|
+
return false;
|
|
1130
|
+
}
|
|
1131
|
+
return parsedDomain === normalizedDomain && !subdomain;
|
|
1132
|
+
}
|
|
1133
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1134
|
+
0 && (module.exports = {
|
|
1135
|
+
canonicalizeBracketedIPv6Content,
|
|
1136
|
+
checkDNSLength,
|
|
1137
|
+
getDomain,
|
|
1138
|
+
getSubdomain,
|
|
1139
|
+
isApexDomain,
|
|
1140
|
+
isIPAddress,
|
|
1141
|
+
isIPv4,
|
|
1142
|
+
isIPv6,
|
|
1143
|
+
matchesCORSCredentialsList,
|
|
1144
|
+
matchesDomainList,
|
|
1145
|
+
matchesOriginList,
|
|
1146
|
+
matchesWildcardDomain,
|
|
1147
|
+
matchesWildcardOrigin,
|
|
1148
|
+
normalizeDomain,
|
|
1149
|
+
normalizeOrigin,
|
|
1150
|
+
parseHostHeader,
|
|
1151
|
+
safeParseURL,
|
|
1152
|
+
validateConfigEntry
|
|
1153
|
+
});
|
|
1154
|
+
//# sourceMappingURL=domain-utils.cjs.map
|