@appwarden/middleware 3.11.6 → 3.13.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/README.md +1 -1
- package/chunk-2ZSJUEHK.js +445 -0
- package/{chunk-5HCAAVK5.js → chunk-GNDWHKJ5.js} +3 -5
- package/{chunk-R7TXTHSG.js → chunk-HP5GMFH7.js} +75 -143
- package/chunk-HUWGPM4M.js +9 -0
- package/{chunk-WBWF3PPX.js → chunk-J2TA6BEU.js} +4 -6
- package/chunk-NV7K5PRA.js +36 -0
- package/chunk-SREQAAZC.js +220 -0
- package/{chunk-UFWJYCX6.js → chunk-TBSMAMWC.js} +1 -1
- package/cloudflare/astro.d.ts +2 -2
- package/cloudflare/astro.js +55 -15
- package/cloudflare/nextjs.d.ts +2 -2
- package/cloudflare/nextjs.js +60 -15
- package/cloudflare/react-router.d.ts +2 -2
- package/cloudflare/react-router.js +43 -15
- package/cloudflare/tanstack-start.d.ts +2 -2
- package/cloudflare/tanstack-start.js +40 -15
- package/cloudflare.d.ts +1 -1
- package/cloudflare.js +80 -11
- package/index.d.ts +109 -2
- package/index.js +10 -5
- package/package.json +1 -1
- package/{use-content-security-policy-CvdzUPYF.d.ts → use-content-security-policy-Dwdcwp33.d.ts} +0 -1
- package/vercel.js +38 -16
- package/chunk-AY4ZKZTF.js +0 -162
- package/chunk-QC2ZUZWY.js +0 -84
- package/chunk-WEM7GS4M.js +0 -29
- package/chunk-ZTVJBORU.js +0 -81
- package/cloudflare-MAHYENA6.js +0 -29
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://github.com/appwarden/middleware)
|
|
5
5
|
[](https://www.npmjs.com/package/@appwarden/middleware)
|
|
6
6
|
[](https://docs.npmjs.com/generating-provenance-statements)
|
|
7
|
-

|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
9
|
|
|
10
10
|
## Core Features
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
import {
|
|
2
|
+
APPWARDEN_HEARTBEAT_ROUTE,
|
|
3
|
+
HEARTBEAT_CONFIG_ERRORS_MAX_SERIALIZED_BYTES,
|
|
4
|
+
HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH,
|
|
5
|
+
HEARTBEAT_CONFIG_ERROR_MAX_COUNT,
|
|
6
|
+
HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH,
|
|
7
|
+
HEARTBEAT_CONFIG_ERROR_MAX_PATH_DEPTH,
|
|
8
|
+
HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH,
|
|
9
|
+
HEARTBEAT_CONTRACT_VERSION,
|
|
10
|
+
HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES,
|
|
11
|
+
LOCKDOWN_TEST_EXPIRY_MS,
|
|
12
|
+
validateHeartbeatResponseBody
|
|
13
|
+
} from "./chunk-SREQAAZC.js";
|
|
14
|
+
|
|
15
|
+
// src/utils/build-lock-page-url.ts
|
|
16
|
+
function normalizeLockPageSlug(lockPageSlug) {
|
|
17
|
+
return lockPageSlug.startsWith("/") ? lockPageSlug : `/${lockPageSlug}`;
|
|
18
|
+
}
|
|
19
|
+
function buildLockPageUrl(lockPageSlug, requestUrl) {
|
|
20
|
+
const normalizedSlug = normalizeLockPageSlug(lockPageSlug);
|
|
21
|
+
return new URL(normalizedSlug, requestUrl);
|
|
22
|
+
}
|
|
23
|
+
function normalizeTrailingSlash(path) {
|
|
24
|
+
if (path === "/") return path;
|
|
25
|
+
return path.endsWith("/") ? path.slice(0, -1) : path;
|
|
26
|
+
}
|
|
27
|
+
function isOnLockPage(lockPageSlug, requestUrl) {
|
|
28
|
+
const normalizedSlug = normalizeTrailingSlash(
|
|
29
|
+
normalizeLockPageSlug(lockPageSlug)
|
|
30
|
+
);
|
|
31
|
+
const url = typeof requestUrl === "string" ? new URL(requestUrl) : requestUrl;
|
|
32
|
+
const normalizedPathname = normalizeTrailingSlash(url.pathname);
|
|
33
|
+
return normalizedPathname === normalizedSlug;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/utils/create-redirect.ts
|
|
37
|
+
var TEMPORARY_REDIRECT_STATUS = 302;
|
|
38
|
+
var createRedirect = (url) => {
|
|
39
|
+
return new Response(null, {
|
|
40
|
+
status: TEMPORARY_REDIRECT_STATUS,
|
|
41
|
+
headers: {
|
|
42
|
+
Location: url.toString()
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// src/utils/print-message.ts
|
|
48
|
+
var addSlashes = (str) => str.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$").replace(/"/g, '\\"').replace(/'/g, "\\'").replace(/\u0000/g, "\\0").replace(/<\/script>/gi, "<\\/script>");
|
|
49
|
+
var printMessage = (message) => `[@appwarden/middleware] ${addSlashes(message)}`;
|
|
50
|
+
|
|
51
|
+
// src/utils/debug.ts
|
|
52
|
+
var debug = (isDebug) => (...msg) => {
|
|
53
|
+
if (!isDebug) return;
|
|
54
|
+
const parts = msg.map((m) => {
|
|
55
|
+
let content;
|
|
56
|
+
if (m instanceof Error) {
|
|
57
|
+
content = m.stack ?? m.message;
|
|
58
|
+
} else if (typeof m === "object" && m !== null) {
|
|
59
|
+
try {
|
|
60
|
+
content = JSON.stringify(m);
|
|
61
|
+
} catch {
|
|
62
|
+
try {
|
|
63
|
+
content = String(m);
|
|
64
|
+
} catch {
|
|
65
|
+
content = "[Unserializable value]";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
content = String(m);
|
|
70
|
+
}
|
|
71
|
+
return content;
|
|
72
|
+
});
|
|
73
|
+
const message = parts.join(" ");
|
|
74
|
+
console.log(printMessage(message));
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// src/utils/memory-cache.ts
|
|
78
|
+
var MemoryCache = class {
|
|
79
|
+
cache = /* @__PURE__ */ new Map();
|
|
80
|
+
maxSize;
|
|
81
|
+
constructor(options) {
|
|
82
|
+
this.maxSize = options.maxSize;
|
|
83
|
+
}
|
|
84
|
+
get(key) {
|
|
85
|
+
let item;
|
|
86
|
+
if (this.cache.has(key)) {
|
|
87
|
+
item = this.cache.get(key);
|
|
88
|
+
this.cache.delete(key);
|
|
89
|
+
if (item !== void 0) {
|
|
90
|
+
this.cache.set(key, item);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return item;
|
|
94
|
+
}
|
|
95
|
+
put(key, value) {
|
|
96
|
+
if (this.cache.has(key)) {
|
|
97
|
+
this.cache.delete(key);
|
|
98
|
+
} else if (this.cache.size >= this.maxSize) {
|
|
99
|
+
const firstKey = this.cache.keys().next().value;
|
|
100
|
+
if (firstKey !== void 0) {
|
|
101
|
+
this.cache.delete(firstKey);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
this.cache.set(key, value);
|
|
105
|
+
}
|
|
106
|
+
getValues() {
|
|
107
|
+
return this.cache;
|
|
108
|
+
}
|
|
109
|
+
// the default value will be expired here
|
|
110
|
+
static isExpired = (lockValue) => {
|
|
111
|
+
if (!lockValue) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
return Date.now() > lockValue.lastCheck + 3e4;
|
|
115
|
+
};
|
|
116
|
+
static isTestExpired = (lockValue) => {
|
|
117
|
+
if (!lockValue) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
return Date.now() > lockValue.isLockedTest + LOCKDOWN_TEST_EXPIRY_MS;
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// src/version.ts
|
|
125
|
+
var MIDDLEWARE_VERSION = "3.12.0";
|
|
126
|
+
|
|
127
|
+
// src/utils/heartbeat.ts
|
|
128
|
+
var DEFAULT_HEARTBEAT_CONFIG_ERROR_CODE = "custom";
|
|
129
|
+
var DEFAULT_HEARTBEAT_CONFIG_ERROR_MESSAGE = "Appwarden configuration validation failed";
|
|
130
|
+
var HEARTBEAT_CONSTRUCTION_FAILURE_BODY = JSON.stringify({
|
|
131
|
+
error: "appwarden_heartbeat_construction_failed"
|
|
132
|
+
});
|
|
133
|
+
function createSanitizedMessage(code, path) {
|
|
134
|
+
const fieldName = path.length > 0 ? path[path.length - 1] : "field";
|
|
135
|
+
switch (code) {
|
|
136
|
+
case "invalid_type":
|
|
137
|
+
return `Invalid type for ${fieldName}`;
|
|
138
|
+
case "invalid_literal":
|
|
139
|
+
return `Invalid value for ${fieldName}`;
|
|
140
|
+
case "unrecognized_keys":
|
|
141
|
+
return `Unrecognized keys in ${fieldName}`;
|
|
142
|
+
case "invalid_union":
|
|
143
|
+
return `Invalid union value for ${fieldName}`;
|
|
144
|
+
case "invalid_enum_value":
|
|
145
|
+
return `Invalid enum value for ${fieldName}`;
|
|
146
|
+
case "invalid_arguments":
|
|
147
|
+
return `Invalid arguments for ${fieldName}`;
|
|
148
|
+
case "invalid_return_type":
|
|
149
|
+
return `Invalid return type for ${fieldName}`;
|
|
150
|
+
case "invalid_date":
|
|
151
|
+
return `Invalid date for ${fieldName}`;
|
|
152
|
+
case "invalid_string":
|
|
153
|
+
return `Invalid string format for ${fieldName}`;
|
|
154
|
+
case "too_small":
|
|
155
|
+
return `Value too small for ${fieldName}`;
|
|
156
|
+
case "too_big":
|
|
157
|
+
return `Value too large for ${fieldName}`;
|
|
158
|
+
case "invalid_intersection_types":
|
|
159
|
+
return `Invalid intersection types for ${fieldName}`;
|
|
160
|
+
case "not_multiple_of":
|
|
161
|
+
return `Value not a multiple of required value for ${fieldName}`;
|
|
162
|
+
case "not_finite":
|
|
163
|
+
return `Value must be finite for ${fieldName}`;
|
|
164
|
+
case "custom":
|
|
165
|
+
return `Validation failed for ${fieldName}`;
|
|
166
|
+
default:
|
|
167
|
+
return `Validation error for ${fieldName}`;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function truncateWithEllipsis(value, maxLength) {
|
|
171
|
+
if (value.length <= maxLength) {
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
if (maxLength <= 3) {
|
|
175
|
+
return value.substring(0, maxLength);
|
|
176
|
+
}
|
|
177
|
+
return value.substring(0, maxLength - 3) + "...";
|
|
178
|
+
}
|
|
179
|
+
function sanitizePathSegment(segment) {
|
|
180
|
+
if (typeof segment === "number" && Number.isFinite(segment)) {
|
|
181
|
+
return Number.isSafeInteger(segment) ? Math.max(0, segment) : Math.max(0, Math.trunc(segment));
|
|
182
|
+
}
|
|
183
|
+
return truncateWithEllipsis(
|
|
184
|
+
typeof segment === "string" ? segment : String(segment),
|
|
185
|
+
HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
function sanitizePath(path) {
|
|
189
|
+
const truncatedPath = path.slice(0, HEARTBEAT_CONFIG_ERROR_MAX_PATH_DEPTH);
|
|
190
|
+
return truncatedPath.map(sanitizePathSegment);
|
|
191
|
+
}
|
|
192
|
+
function truncateMessage(message) {
|
|
193
|
+
return truncateWithEllipsis(
|
|
194
|
+
message,
|
|
195
|
+
HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
function truncateCode(code) {
|
|
199
|
+
return truncateWithEllipsis(code, HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH);
|
|
200
|
+
}
|
|
201
|
+
function normalizeNonEmptyString(value, fallback, truncate) {
|
|
202
|
+
const normalizedValue = truncate(value.trim());
|
|
203
|
+
if (normalizedValue.length > 0) {
|
|
204
|
+
return normalizedValue;
|
|
205
|
+
}
|
|
206
|
+
return truncate(fallback);
|
|
207
|
+
}
|
|
208
|
+
function getSerializedJsonByteLength(value) {
|
|
209
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
210
|
+
}
|
|
211
|
+
function isConfigErrorsWithinByteBudget(configErrors) {
|
|
212
|
+
return getSerializedJsonByteLength(configErrors) <= HEARTBEAT_CONFIG_ERRORS_MAX_SERIALIZED_BYTES;
|
|
213
|
+
}
|
|
214
|
+
function isResponseBodyWithinByteBudget(body) {
|
|
215
|
+
return getSerializedJsonByteLength(body) <= HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES;
|
|
216
|
+
}
|
|
217
|
+
function createHeartbeatConfigError(path, code, message) {
|
|
218
|
+
return {
|
|
219
|
+
path: sanitizePath(path),
|
|
220
|
+
code: normalizeNonEmptyString(
|
|
221
|
+
code,
|
|
222
|
+
DEFAULT_HEARTBEAT_CONFIG_ERROR_CODE,
|
|
223
|
+
truncateCode
|
|
224
|
+
),
|
|
225
|
+
message: normalizeNonEmptyString(
|
|
226
|
+
message,
|
|
227
|
+
DEFAULT_HEARTBEAT_CONFIG_ERROR_MESSAGE,
|
|
228
|
+
truncateMessage
|
|
229
|
+
)
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function normalizeHeartbeatConfigErrors(configErrors) {
|
|
233
|
+
const normalizedConfigErrors = configErrors.slice(0, HEARTBEAT_CONFIG_ERROR_MAX_COUNT).map(
|
|
234
|
+
(configError) => createHeartbeatConfigError(
|
|
235
|
+
configError.path,
|
|
236
|
+
configError.code,
|
|
237
|
+
configError.message
|
|
238
|
+
)
|
|
239
|
+
);
|
|
240
|
+
while (normalizedConfigErrors.length > 0 && !isConfigErrorsWithinByteBudget(normalizedConfigErrors)) {
|
|
241
|
+
normalizedConfigErrors.pop();
|
|
242
|
+
}
|
|
243
|
+
return normalizedConfigErrors;
|
|
244
|
+
}
|
|
245
|
+
function sanitizeConfigErrors(error) {
|
|
246
|
+
if (!error) {
|
|
247
|
+
return [];
|
|
248
|
+
}
|
|
249
|
+
const errors = [];
|
|
250
|
+
const issues = error.issues.slice(0, HEARTBEAT_CONFIG_ERROR_MAX_COUNT);
|
|
251
|
+
for (const issue of issues) {
|
|
252
|
+
const sanitizedPath = sanitizePath(issue.path);
|
|
253
|
+
const message = truncateMessage(
|
|
254
|
+
createSanitizedMessage(issue.code, sanitizedPath)
|
|
255
|
+
);
|
|
256
|
+
errors.push({
|
|
257
|
+
path: sanitizedPath,
|
|
258
|
+
code: issue.code,
|
|
259
|
+
message
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
return errors;
|
|
263
|
+
}
|
|
264
|
+
function createHeartbeatResponseBody(service, configErrors = []) {
|
|
265
|
+
const normalizedConfigErrors = normalizeHeartbeatConfigErrors(configErrors);
|
|
266
|
+
const body = {
|
|
267
|
+
app: "appwarden",
|
|
268
|
+
kind: "heartbeat",
|
|
269
|
+
status: "ok",
|
|
270
|
+
contractVersion: HEARTBEAT_CONTRACT_VERSION,
|
|
271
|
+
service,
|
|
272
|
+
version: MIDDLEWARE_VERSION,
|
|
273
|
+
configErrors: normalizedConfigErrors
|
|
274
|
+
};
|
|
275
|
+
while (body.configErrors.length > 0 && !isResponseBodyWithinByteBudget(body)) {
|
|
276
|
+
body.configErrors.pop();
|
|
277
|
+
}
|
|
278
|
+
return validateHeartbeatResponseBody(body);
|
|
279
|
+
}
|
|
280
|
+
function createHeartbeatConstructionFailureResponse() {
|
|
281
|
+
return new Response(HEARTBEAT_CONSTRUCTION_FAILURE_BODY, {
|
|
282
|
+
status: 500,
|
|
283
|
+
headers: {
|
|
284
|
+
"content-type": "application/json",
|
|
285
|
+
"cache-control": "no-store"
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
function createHeartbeatResponse(service, configErrors = []) {
|
|
290
|
+
try {
|
|
291
|
+
const body = createHeartbeatResponseBody(service, configErrors);
|
|
292
|
+
return new Response(JSON.stringify(body), {
|
|
293
|
+
status: 200,
|
|
294
|
+
headers: {
|
|
295
|
+
"content-type": "application/json",
|
|
296
|
+
"cache-control": "no-store",
|
|
297
|
+
"x-appwarden-heartbeat": "1",
|
|
298
|
+
"x-appwarden-contract-version": String(HEARTBEAT_CONTRACT_VERSION),
|
|
299
|
+
"x-appwarden-service": service,
|
|
300
|
+
"x-appwarden-version": MIDDLEWARE_VERSION
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
} catch {
|
|
304
|
+
return createHeartbeatConstructionFailureResponse();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
function isHeartbeatRoute(url) {
|
|
308
|
+
return url.pathname === APPWARDEN_HEARTBEAT_ROUTE;
|
|
309
|
+
}
|
|
310
|
+
function isHeartbeatRequest(request, url) {
|
|
311
|
+
return request.method === "GET" && isHeartbeatRoute(url);
|
|
312
|
+
}
|
|
313
|
+
function handleHeartbeatRequest(request, service, configErrors = []) {
|
|
314
|
+
return createHeartbeatResponse(service, configErrors);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// src/utils/request-checks.ts
|
|
318
|
+
function isHTMLResponse(response) {
|
|
319
|
+
return response.headers.get("Content-Type")?.includes("text/html") ?? false;
|
|
320
|
+
}
|
|
321
|
+
function isHTMLRequest(request) {
|
|
322
|
+
const accept = request.headers.get("accept");
|
|
323
|
+
if (!accept) {
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
const normalizedAccept = accept.toLowerCase();
|
|
327
|
+
const isWildcardOnlyAccept = (value) => {
|
|
328
|
+
const mediaRanges2 = value.split(",");
|
|
329
|
+
let hasNonEmptyRange = false;
|
|
330
|
+
for (const range of mediaRanges2) {
|
|
331
|
+
const [typeSubtype] = range.split(";");
|
|
332
|
+
const trimmed = typeSubtype.trim();
|
|
333
|
+
if (!trimmed) {
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
hasNonEmptyRange = true;
|
|
337
|
+
if (trimmed !== "*/*" && trimmed !== "*") {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return hasNonEmptyRange;
|
|
342
|
+
};
|
|
343
|
+
if (isWildcardOnlyAccept(normalizedAccept)) {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
const mediaRanges = normalizedAccept.split(",");
|
|
347
|
+
for (const range of mediaRanges) {
|
|
348
|
+
const [typeSubtype] = range.split(";");
|
|
349
|
+
const token = typeSubtype.trim();
|
|
350
|
+
if (token === "text/html") {
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// src/utils/cloudflare/csp-keywords.ts
|
|
358
|
+
var CSP_KEYWORDS = [
|
|
359
|
+
"self",
|
|
360
|
+
"none",
|
|
361
|
+
"unsafe-inline",
|
|
362
|
+
"unsafe-eval",
|
|
363
|
+
"unsafe-hashes",
|
|
364
|
+
"strict-dynamic",
|
|
365
|
+
"report-sample",
|
|
366
|
+
"unsafe-allow-redirects",
|
|
367
|
+
"wasm-unsafe-eval",
|
|
368
|
+
"trusted-types-eval",
|
|
369
|
+
"report-sha256",
|
|
370
|
+
"report-sha384",
|
|
371
|
+
"report-sha512",
|
|
372
|
+
"unsafe-webtransport-hashes"
|
|
373
|
+
];
|
|
374
|
+
var CSP_KEYWORDS_SET = new Set(CSP_KEYWORDS);
|
|
375
|
+
var isCSPKeyword = (value) => {
|
|
376
|
+
return CSP_KEYWORDS_SET.has(value.toLowerCase());
|
|
377
|
+
};
|
|
378
|
+
var isQuoted = (value) => {
|
|
379
|
+
return value.startsWith("'") && value.endsWith("'");
|
|
380
|
+
};
|
|
381
|
+
var autoQuoteCSPKeyword = (value) => {
|
|
382
|
+
const trimmed = value.trim();
|
|
383
|
+
if (isQuoted(trimmed)) {
|
|
384
|
+
return trimmed;
|
|
385
|
+
}
|
|
386
|
+
if (isCSPKeyword(trimmed)) {
|
|
387
|
+
return `'${trimmed}'`;
|
|
388
|
+
}
|
|
389
|
+
return trimmed;
|
|
390
|
+
};
|
|
391
|
+
var autoQuoteCSPDirectiveValue = (value) => {
|
|
392
|
+
return value.trim().split(/\s+/).filter(Boolean).map(autoQuoteCSPKeyword).join(" ");
|
|
393
|
+
};
|
|
394
|
+
var autoQuoteCSPDirectiveArray = (values) => {
|
|
395
|
+
return values.map(autoQuoteCSPKeyword);
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// src/utils/cloudflare/make-csp-header.ts
|
|
399
|
+
var addNonce = (value, cspNonce) => value.replace("{{nonce}}", `'nonce-${cspNonce}'`);
|
|
400
|
+
var makeCSPHeader = (cspNonce, directives, mode) => {
|
|
401
|
+
const namesSeen = /* @__PURE__ */ new Set(), result = [];
|
|
402
|
+
Object.entries(directives ?? {}).forEach(([originalName, value]) => {
|
|
403
|
+
const name = originalName.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
404
|
+
if (namesSeen.has(name)) {
|
|
405
|
+
throw new Error(`${originalName} is specified more than once`);
|
|
406
|
+
}
|
|
407
|
+
namesSeen.add(name);
|
|
408
|
+
let directiveValue;
|
|
409
|
+
if (Array.isArray(value)) {
|
|
410
|
+
directiveValue = autoQuoteCSPDirectiveArray(value).join(" ");
|
|
411
|
+
} else if (value === true) {
|
|
412
|
+
directiveValue = "";
|
|
413
|
+
} else if (typeof value === "string") {
|
|
414
|
+
directiveValue = autoQuoteCSPDirectiveValue(value);
|
|
415
|
+
} else {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
if (directiveValue) {
|
|
419
|
+
result.push(`${name} ${addNonce(directiveValue, cspNonce)}`);
|
|
420
|
+
} else {
|
|
421
|
+
result.push(name);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
return [
|
|
425
|
+
mode === "enforced" ? "Content-Security-Policy" : "Content-Security-Policy-Report-Only",
|
|
426
|
+
result.join("; ")
|
|
427
|
+
];
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
export {
|
|
431
|
+
buildLockPageUrl,
|
|
432
|
+
isOnLockPage,
|
|
433
|
+
TEMPORARY_REDIRECT_STATUS,
|
|
434
|
+
createRedirect,
|
|
435
|
+
printMessage,
|
|
436
|
+
debug,
|
|
437
|
+
MemoryCache,
|
|
438
|
+
createHeartbeatConfigError,
|
|
439
|
+
sanitizeConfigErrors,
|
|
440
|
+
isHeartbeatRequest,
|
|
441
|
+
handleHeartbeatRequest,
|
|
442
|
+
isHTMLResponse,
|
|
443
|
+
isHTMLRequest,
|
|
444
|
+
makeCSPHeader
|
|
445
|
+
};
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
UseCSPInputSchema
|
|
3
|
-
} from "./chunk-ZTVJBORU.js";
|
|
4
1
|
import {
|
|
5
2
|
AppwardenApiHostnameSchema,
|
|
6
3
|
AppwardenApiTokenSchema,
|
|
7
|
-
BooleanSchema
|
|
8
|
-
|
|
4
|
+
BooleanSchema,
|
|
5
|
+
UseCSPInputSchema
|
|
6
|
+
} from "./chunk-SREQAAZC.js";
|
|
9
7
|
|
|
10
8
|
// src/schemas/use-appwarden.ts
|
|
11
9
|
import { z } from "zod";
|