@appwarden/middleware 1.0.18 → 1.1.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/chunk-BHCQJZWE.js +358 -0
- package/chunk-WVVSYKJM.js +525 -0
- package/cloudflare.d.ts +8 -11
- package/cloudflare.js +54 -6
- package/index.d.ts +15 -5
- package/index.js +14 -4
- package/package.json +1 -1
- package/use-content-security-policy-DBWKjDEH.d.ts +509 -0
- package/vercel.d.ts +6 -12
- package/vercel.js +82 -5
- package/chunk-C7APN7T6.js +0 -821
- package/chunk-JXIVUR6E.js +0 -186
- package/cloudflare-hVS30fDq.d.ts +0 -99
- package/nextjs-on-pages.d.ts +0 -30
- package/nextjs-on-pages.js +0 -10
- package/use-content-security-policy-BtEGGIeu.d.ts +0 -245
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
// src/constants.ts
|
|
2
|
+
var LOCKDOWN_TEST_EXPIRY_MS = 5 * 60 * 1e3;
|
|
3
|
+
var removedHeaders = ["X-Powered-By", "Server"];
|
|
4
|
+
var errors = { badCacheConnection: "BAD_CACHE_CONNECTION" };
|
|
5
|
+
var globalErrors = [errors.badCacheConnection];
|
|
6
|
+
var APPWARDEN_TEST_ROUTE = "_appwarden/test";
|
|
7
|
+
var APPWARDEN_CACHE_KEY = "appwarden-lock";
|
|
8
|
+
|
|
9
|
+
// src/utils/is-cache-url.ts
|
|
10
|
+
var getEdgeConfigId = (value = "") => isValidCacheUrl.edgeConfig(value) ? new URL(value).pathname.replace("/", "") : void 0;
|
|
11
|
+
var isCacheUrl = {
|
|
12
|
+
edgeConfig: (value = "") => value.includes("edge-config.vercel.com"),
|
|
13
|
+
upstash: (value = "") => value.includes(".upstash.io")
|
|
14
|
+
};
|
|
15
|
+
var isValidCacheUrl = {
|
|
16
|
+
edgeConfig: (value = "") => {
|
|
17
|
+
try {
|
|
18
|
+
const url = new URL(value);
|
|
19
|
+
return url.hostname === "edge-config.vercel.com" && url.pathname.startsWith("/ecfg_") && url.searchParams.has("token");
|
|
20
|
+
} catch (error) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
upstash: (value = "") => {
|
|
25
|
+
try {
|
|
26
|
+
const url = new URL(value);
|
|
27
|
+
return ["redis:", "rediss:"].includes(url.protocol) && url.hostname.endsWith("upstash.io") && url.password;
|
|
28
|
+
} catch (error) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// src/schemas/use-content-security-policy.ts
|
|
35
|
+
import { z as z8 } from "zod";
|
|
36
|
+
|
|
37
|
+
// src/types/csp.ts
|
|
38
|
+
import { z } from "zod";
|
|
39
|
+
var stringySchema = z.union([z.array(z.string()), z.string(), z.boolean()]);
|
|
40
|
+
var ContentSecurityPolicySchema = z.object({
|
|
41
|
+
"default-src": stringySchema.optional(),
|
|
42
|
+
"script-src": stringySchema.optional(),
|
|
43
|
+
"style-src": stringySchema.optional(),
|
|
44
|
+
"img-src": stringySchema.optional(),
|
|
45
|
+
"connect-src": stringySchema.optional(),
|
|
46
|
+
"font-src": stringySchema.optional(),
|
|
47
|
+
"object-src": stringySchema.optional(),
|
|
48
|
+
"media-src": stringySchema.optional(),
|
|
49
|
+
"frame-src": stringySchema.optional(),
|
|
50
|
+
sandbox: stringySchema.optional(),
|
|
51
|
+
"report-uri": stringySchema.optional(),
|
|
52
|
+
"child-src": stringySchema.optional(),
|
|
53
|
+
"form-action": stringySchema.optional(),
|
|
54
|
+
"frame-ancestors": stringySchema.optional(),
|
|
55
|
+
"plugin-types": stringySchema.optional(),
|
|
56
|
+
"base-uri": stringySchema.optional(),
|
|
57
|
+
"report-to": stringySchema.optional(),
|
|
58
|
+
"worker-src": stringySchema.optional(),
|
|
59
|
+
"manifest-src": stringySchema.optional(),
|
|
60
|
+
"prefetch-src": stringySchema.optional(),
|
|
61
|
+
"navigate-to": stringySchema.optional(),
|
|
62
|
+
"require-sri-for": stringySchema.optional(),
|
|
63
|
+
"block-all-mixed-content": stringySchema.optional(),
|
|
64
|
+
"upgrade-insecure-requests": stringySchema.optional(),
|
|
65
|
+
"trusted-types": stringySchema.optional(),
|
|
66
|
+
"require-trusted-types-for": stringySchema.optional()
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// src/types/middleware.ts
|
|
70
|
+
import { z as z2 } from "zod";
|
|
71
|
+
var MiddlewareNextSchema = z2.union([
|
|
72
|
+
z2.void(),
|
|
73
|
+
z2.null(),
|
|
74
|
+
z2.promise(z2.union([z2.void(), z2.null()]))
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
// src/utils/debug.ts
|
|
78
|
+
var debug = (...msg) => {
|
|
79
|
+
if (true) {
|
|
80
|
+
console.log(...msg);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// src/utils/errors.ts
|
|
85
|
+
var errorsMap = {
|
|
86
|
+
mode: '`CSP_MODE` must be one of "disabled", "report-only", or "enforced"',
|
|
87
|
+
directives: {
|
|
88
|
+
["DirectivesRequired" /* DirectivesRequired */]: '`CSP_DIRECTIVES` must be provided when `CSP_MODE` is "report-only" or "enforced"',
|
|
89
|
+
["DirectivesBadParse" /* DirectivesBadParse */]: "Failed to parse `CSP_DIRECTIVES`. Is it a valid JSON string?"
|
|
90
|
+
},
|
|
91
|
+
appwardenApiToken: "Please provide a valid `appwardenApiToken`. Learn more at https://appwarden.com/docs/api-tokens."
|
|
92
|
+
};
|
|
93
|
+
var getErrors = (error) => {
|
|
94
|
+
const matches = [];
|
|
95
|
+
const errors2 = [...Object.entries(error.flatten().fieldErrors)];
|
|
96
|
+
for (const issue of error.issues) {
|
|
97
|
+
errors2.push(
|
|
98
|
+
...Object.entries(
|
|
99
|
+
"returnTypeError" in issue ? issue.returnTypeError.flatten().fieldErrors : {}
|
|
100
|
+
)
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
for (const [field, maybeSchemaErrorKey] of errors2) {
|
|
104
|
+
let match = errorsMap[field];
|
|
105
|
+
if (match) {
|
|
106
|
+
if (match instanceof Object) {
|
|
107
|
+
if (maybeSchemaErrorKey) {
|
|
108
|
+
match = match[maybeSchemaErrorKey[0]];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
matches.push(match);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return matches;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// src/utils/memory-cache.ts
|
|
118
|
+
var MemoryCache = class {
|
|
119
|
+
cache = /* @__PURE__ */ new Map();
|
|
120
|
+
maxSize;
|
|
121
|
+
constructor(options) {
|
|
122
|
+
this.maxSize = options.maxSize;
|
|
123
|
+
}
|
|
124
|
+
get(key) {
|
|
125
|
+
let item;
|
|
126
|
+
if (this.cache.has(key)) {
|
|
127
|
+
item = this.cache.get(key);
|
|
128
|
+
this.cache.delete(key);
|
|
129
|
+
this.cache.set(key, item);
|
|
130
|
+
}
|
|
131
|
+
return item;
|
|
132
|
+
}
|
|
133
|
+
put(key, value) {
|
|
134
|
+
if (this.cache.has(key)) {
|
|
135
|
+
this.cache.delete(key);
|
|
136
|
+
} else if (this.cache.size >= this.maxSize) {
|
|
137
|
+
const firstKey = this.cache.keys().next().value;
|
|
138
|
+
this.cache.delete(firstKey);
|
|
139
|
+
}
|
|
140
|
+
this.cache.set(key, value);
|
|
141
|
+
}
|
|
142
|
+
getValues() {
|
|
143
|
+
return this.cache;
|
|
144
|
+
}
|
|
145
|
+
// the default value will be expired here
|
|
146
|
+
static isExpired = (lockValue) => {
|
|
147
|
+
if (!lockValue) {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
return Date.now() > lockValue.lastCheck + 3e4;
|
|
151
|
+
};
|
|
152
|
+
static isTestExpired = (lockValue) => {
|
|
153
|
+
if (!lockValue) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
return Date.now() > lockValue.isLockedTest + LOCKDOWN_TEST_EXPIRY_MS;
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// src/utils/print-message.ts
|
|
161
|
+
var addSlashes = (str) => str.replace(/[\\"'`]/g, "\\$&").replace(/\u0000/g, "\\0");
|
|
162
|
+
var printMessage = (message) => `[@appwarden/middleware] ${addSlashes(message)}`;
|
|
163
|
+
|
|
164
|
+
// src/utils/vercel/delete-edge-value.ts
|
|
165
|
+
var deleteEdgeValue = async ({
|
|
166
|
+
keyName,
|
|
167
|
+
provider,
|
|
168
|
+
cacheUrl,
|
|
169
|
+
vercelApiToken
|
|
170
|
+
}) => {
|
|
171
|
+
try {
|
|
172
|
+
switch (provider) {
|
|
173
|
+
case "edge-config": {
|
|
174
|
+
const edgeConfigId = getEdgeConfigId(cacheUrl);
|
|
175
|
+
if (!edgeConfigId) {
|
|
176
|
+
throw new Error("Failed to parse `edgeConfigId`");
|
|
177
|
+
}
|
|
178
|
+
const res = await fetch(
|
|
179
|
+
`https://api.vercel.com/v1/edge-config/${edgeConfigId}/items`,
|
|
180
|
+
{
|
|
181
|
+
method: "PATCH",
|
|
182
|
+
headers: {
|
|
183
|
+
Authorization: `Bearer ${vercelApiToken}`,
|
|
184
|
+
"Content-Type": "application/json"
|
|
185
|
+
},
|
|
186
|
+
body: JSON.stringify({
|
|
187
|
+
items: [
|
|
188
|
+
{
|
|
189
|
+
key: keyName,
|
|
190
|
+
operation: "delete"
|
|
191
|
+
}
|
|
192
|
+
]
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
if (res.status !== 200) {
|
|
197
|
+
let response = void 0;
|
|
198
|
+
try {
|
|
199
|
+
response = await res.json();
|
|
200
|
+
} catch (error) {
|
|
201
|
+
}
|
|
202
|
+
throw new Error(
|
|
203
|
+
`api.vercel.com/v1/edge-config responded with ${res.status} - ${res.statusText}${response?.error?.message ? ` - ${response?.error?.message}` : ""}`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
case "upstash": {
|
|
209
|
+
const { hostname, password } = new URL(cacheUrl);
|
|
210
|
+
const { Redis } = await import("@upstash/redis");
|
|
211
|
+
const redis = new Redis({ url: `https://${hostname}`, token: password });
|
|
212
|
+
await redis.del(keyName);
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
default:
|
|
216
|
+
throw new Error(`Unsupported provider: ${provider}`);
|
|
217
|
+
}
|
|
218
|
+
} catch (e) {
|
|
219
|
+
const message = "Failed to delete edge value";
|
|
220
|
+
console.error(
|
|
221
|
+
printMessage(e instanceof Error ? `${message} - ${e.message}` : message)
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// src/schemas/cloudflare.ts
|
|
227
|
+
import { z as z5 } from "zod";
|
|
228
|
+
|
|
229
|
+
// src/schemas/use-appwarden.ts
|
|
230
|
+
import { z as z4 } from "zod";
|
|
231
|
+
|
|
232
|
+
// src/schemas/helpers.ts
|
|
233
|
+
import { z as z3 } from "zod";
|
|
234
|
+
var BoolOrStringSchema = z3.union([z3.string(), z3.boolean()]).optional();
|
|
235
|
+
var BooleanSchema = BoolOrStringSchema.transform((val) => {
|
|
236
|
+
if (val === "true" || val === true) {
|
|
237
|
+
return true;
|
|
238
|
+
} else if (val === "false" || val === false) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
throw new Error("Invalid value");
|
|
242
|
+
});
|
|
243
|
+
var LockValue = z3.object({
|
|
244
|
+
isLocked: z3.number(),
|
|
245
|
+
isLockedTest: z3.number(),
|
|
246
|
+
lastCheck: z3.number(),
|
|
247
|
+
code: z3.string()
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// src/schemas/use-appwarden.ts
|
|
251
|
+
var UseAppwardenInputSchema = z4.object({
|
|
252
|
+
debug: BooleanSchema.default(false),
|
|
253
|
+
lockPageSlug: z4.string(),
|
|
254
|
+
appwardenApiToken: z4.string().refine((val) => !!val, { path: ["appwardenApiToken"] })
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// src/schemas/cloudflare.ts
|
|
258
|
+
var ConfigFnInputSchema = z5.function().args(z5.custom()).returns(
|
|
259
|
+
UseAppwardenInputSchema.extend({
|
|
260
|
+
middleware: z5.object({ before: z5.custom().array().default([]) }).default({})
|
|
261
|
+
})
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
// src/schemas/nextjs.ts
|
|
265
|
+
import { z as z6 } from "zod";
|
|
266
|
+
var NextJsConfigFnOutputSchema = z6.function().args(z6.custom()).returns(UseAppwardenInputSchema);
|
|
267
|
+
|
|
268
|
+
// src/schemas/vercel.ts
|
|
269
|
+
import { z as z7 } from "zod";
|
|
270
|
+
var BaseNextJsConfigSchema = z7.object({
|
|
271
|
+
cacheUrl: z7.string(),
|
|
272
|
+
appwardenApiToken: z7.string(),
|
|
273
|
+
vercelApiToken: z7.string().optional(),
|
|
274
|
+
lockPageSlug: z7.string().default("").transform((val) => val.replace(/^\/?/, "/"))
|
|
275
|
+
});
|
|
276
|
+
var AppwardenConfigSchema = BaseNextJsConfigSchema.refine(
|
|
277
|
+
(data) => isCacheUrl.edgeConfig(data.cacheUrl) || isCacheUrl.upstash(data.cacheUrl),
|
|
278
|
+
{
|
|
279
|
+
message: printMessage(
|
|
280
|
+
"Provided `cacheUrl` is not recognized. Please provide a Vercel Edge Config or Upstash KV url."
|
|
281
|
+
),
|
|
282
|
+
path: ["cacheUrl"]
|
|
283
|
+
}
|
|
284
|
+
).refine(
|
|
285
|
+
(data) => isCacheUrl.edgeConfig(data.cacheUrl) ? isValidCacheUrl.edgeConfig(data.cacheUrl) : true,
|
|
286
|
+
{
|
|
287
|
+
message: printMessage(
|
|
288
|
+
"Provided Vercel Edge Config `cacheUrl` is not valid. Please provide a valid Vercel Edge Config url."
|
|
289
|
+
),
|
|
290
|
+
path: ["cacheUrl"]
|
|
291
|
+
}
|
|
292
|
+
).refine(
|
|
293
|
+
(data) => isCacheUrl.upstash(data.cacheUrl) ? isValidCacheUrl.upstash(data.cacheUrl) : true,
|
|
294
|
+
{
|
|
295
|
+
message: printMessage(
|
|
296
|
+
"Provided Upstash KV `cacheUrl` is not valid. Please provide a valid Upstash KV url."
|
|
297
|
+
),
|
|
298
|
+
path: ["cacheUrl"]
|
|
299
|
+
}
|
|
300
|
+
).refine(
|
|
301
|
+
(data) => isCacheUrl.edgeConfig(data.cacheUrl) ? !!data.vercelApiToken : true,
|
|
302
|
+
{
|
|
303
|
+
message: printMessage(
|
|
304
|
+
"The `vercelApiToken` option is required when using Vercel Edge Config"
|
|
305
|
+
),
|
|
306
|
+
path: ["vercelApiToken"]
|
|
307
|
+
}
|
|
308
|
+
).refine((data) => !!data.appwardenApiToken, {
|
|
309
|
+
message: printMessage(
|
|
310
|
+
"Please provide a valid `appwardenApiToken`. Learn more at https://appwarden.com/docs/api-tokens."
|
|
311
|
+
),
|
|
312
|
+
path: ["appwardenApiToken"]
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// src/utils/vercel/get-lock-value.ts
|
|
316
|
+
var getLockValue = async (context) => {
|
|
317
|
+
try {
|
|
318
|
+
let shouldDeleteEdgeValue = false;
|
|
319
|
+
let serializedValue, lockValue = {
|
|
320
|
+
isLocked: 0,
|
|
321
|
+
isLockedTest: 0,
|
|
322
|
+
lastCheck: 0,
|
|
323
|
+
code: ""
|
|
324
|
+
};
|
|
325
|
+
switch (context.provider) {
|
|
326
|
+
case "edge-config": {
|
|
327
|
+
const { createClient } = await import("@vercel/edge-config");
|
|
328
|
+
const edgeConfig = createClient(context.cacheUrl);
|
|
329
|
+
serializedValue = await edgeConfig.get(
|
|
330
|
+
context.keyName
|
|
331
|
+
);
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
case "upstash": {
|
|
335
|
+
const { hostname, password } = new URL(context.cacheUrl);
|
|
336
|
+
const { Redis } = await import("@upstash/redis");
|
|
337
|
+
const redis = new Redis({
|
|
338
|
+
url: `https://${hostname}`,
|
|
339
|
+
token: password
|
|
340
|
+
});
|
|
341
|
+
const redisValue = await redis.get(
|
|
342
|
+
context.keyName
|
|
343
|
+
);
|
|
344
|
+
serializedValue = redisValue === null ? void 0 : redisValue;
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
default:
|
|
348
|
+
throw new Error(`Unsupported provider: ${context.provider}`);
|
|
349
|
+
}
|
|
350
|
+
if (!serializedValue) {
|
|
351
|
+
return { lockValue: void 0 };
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
lockValue = LockValue.parse(
|
|
355
|
+
typeof serializedValue === "string" ? JSON.parse(serializedValue) : serializedValue
|
|
356
|
+
);
|
|
357
|
+
} catch (error) {
|
|
358
|
+
console.error(
|
|
359
|
+
printMessage(
|
|
360
|
+
`Failed to parse ${context.keyName} from edge cache - ${error}`
|
|
361
|
+
)
|
|
362
|
+
);
|
|
363
|
+
shouldDeleteEdgeValue = true;
|
|
364
|
+
}
|
|
365
|
+
return { lockValue, shouldDeleteEdgeValue };
|
|
366
|
+
} catch (e) {
|
|
367
|
+
const message = "Failed to retrieve edge value";
|
|
368
|
+
console.error(
|
|
369
|
+
printMessage(e instanceof Error ? `${message} - ${e.message}` : message)
|
|
370
|
+
);
|
|
371
|
+
if (e instanceof Error) {
|
|
372
|
+
if (e.message.includes("Invalid connection string provided")) {
|
|
373
|
+
throw new Error(errors.badCacheConnection);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return { lockValue: void 0 };
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
// src/utils/vercel/sync-edge-value.ts
|
|
381
|
+
var APIError = class extends Error {
|
|
382
|
+
constructor(message) {
|
|
383
|
+
super(message);
|
|
384
|
+
this.name = "APIError";
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
var syncEdgeValue = async (context) => {
|
|
388
|
+
debug(`syncing with api`);
|
|
389
|
+
try {
|
|
390
|
+
const response = await fetch(new URL("/v1/status/check", "https://bot-gateway.appwarden.io"), {
|
|
391
|
+
method: "POST",
|
|
392
|
+
headers: { "content-type": "application/json" },
|
|
393
|
+
body: JSON.stringify({
|
|
394
|
+
service: "vercel",
|
|
395
|
+
cacheUrl: context.cacheUrl,
|
|
396
|
+
fqdn: context.requestUrl.hostname,
|
|
397
|
+
vercelApiToken: context.vercelApiToken ?? "",
|
|
398
|
+
appwardenApiToken: context.appwardenApiToken
|
|
399
|
+
})
|
|
400
|
+
});
|
|
401
|
+
if (response.status !== 200) {
|
|
402
|
+
throw new Error(`${response.status} ${response.statusText}`);
|
|
403
|
+
}
|
|
404
|
+
if (response.headers.get("content-type")?.includes("application/json")) {
|
|
405
|
+
const result = await response.json();
|
|
406
|
+
if (result.error) {
|
|
407
|
+
throw new APIError(result.error.message);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
} catch (e) {
|
|
411
|
+
const message = "Failed to fetch from check endpoint";
|
|
412
|
+
console.error(
|
|
413
|
+
printMessage(
|
|
414
|
+
e instanceof APIError ? e.message : e instanceof Error ? `${message} - ${e.message}` : message
|
|
415
|
+
)
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
// src/utils/handle-vercel-request.ts
|
|
421
|
+
var handleVercelRequest = async (context, options) => {
|
|
422
|
+
let cachedLockValue = context.memoryCache.get(context.keyName);
|
|
423
|
+
const shouldRecheck = MemoryCache.isExpired(cachedLockValue);
|
|
424
|
+
if (shouldRecheck) {
|
|
425
|
+
const { lockValue, shouldDeleteEdgeValue } = await getLockValue(context);
|
|
426
|
+
if (lockValue) {
|
|
427
|
+
context.memoryCache.put(context.keyName, lockValue);
|
|
428
|
+
}
|
|
429
|
+
if (shouldDeleteEdgeValue) {
|
|
430
|
+
await deleteEdgeValue(context);
|
|
431
|
+
}
|
|
432
|
+
cachedLockValue = lockValue;
|
|
433
|
+
}
|
|
434
|
+
if (cachedLockValue?.isLocked || context.requestUrl.pathname === APPWARDEN_TEST_ROUTE && !MemoryCache.isTestExpired(cachedLockValue)) {
|
|
435
|
+
options.onLocked();
|
|
436
|
+
}
|
|
437
|
+
return cachedLockValue;
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
// src/utils/middleware.ts
|
|
441
|
+
var usePipeline = (...initMiddlewares) => {
|
|
442
|
+
const stack = [...initMiddlewares];
|
|
443
|
+
const execute = async (context) => {
|
|
444
|
+
const runner = async (prevIndex, index) => {
|
|
445
|
+
if (index === prevIndex) {
|
|
446
|
+
throw new Error("next() called multiple times");
|
|
447
|
+
}
|
|
448
|
+
if (index >= stack.length) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
const middleware = stack[index];
|
|
452
|
+
const next = async () => runner(index, index + 1);
|
|
453
|
+
await middleware(context, next);
|
|
454
|
+
};
|
|
455
|
+
await runner(-1, 0);
|
|
456
|
+
};
|
|
457
|
+
return {
|
|
458
|
+
execute
|
|
459
|
+
};
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
// src/utils/render-lock-page.ts
|
|
463
|
+
var renderLockPage = (context) => fetch(new URL(context.lockPageSlug, context.requestUrl.origin), {
|
|
464
|
+
headers: {
|
|
465
|
+
// no browser caching, otherwise we need to hard refresh to disable lock screen
|
|
466
|
+
"Cache-Control": "no-store"
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
// src/schemas/use-content-security-policy.ts
|
|
471
|
+
var CSPDirectivesSchema = z8.union([
|
|
472
|
+
z8.string(),
|
|
473
|
+
ContentSecurityPolicySchema
|
|
474
|
+
]);
|
|
475
|
+
var CSPModeSchema = z8.literal("disabled").or(z8.literal("report-only")).or(z8.literal("enforced")).optional().default("disabled");
|
|
476
|
+
var UseCSPInputSchema = z8.object({
|
|
477
|
+
mode: CSPModeSchema,
|
|
478
|
+
directives: CSPDirectivesSchema.optional().refine(
|
|
479
|
+
(val) => {
|
|
480
|
+
try {
|
|
481
|
+
if (typeof val === "string") {
|
|
482
|
+
JSON.parse(val);
|
|
483
|
+
}
|
|
484
|
+
return true;
|
|
485
|
+
} catch (error) {
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
{ message: "DirectivesBadParse" /* DirectivesBadParse */ }
|
|
490
|
+
).transform(
|
|
491
|
+
(val) => typeof val === "string" ? JSON.parse(val) : val
|
|
492
|
+
)
|
|
493
|
+
}).refine(
|
|
494
|
+
(values) => (
|
|
495
|
+
// validate that directives are provided when the mode is "report-only" or "enforced"
|
|
496
|
+
["report-only", "enforced"].includes(values.mode) && values.directives
|
|
497
|
+
),
|
|
498
|
+
{ path: ["directives"], message: "DirectivesRequired" /* DirectivesRequired */ }
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
export {
|
|
502
|
+
LOCKDOWN_TEST_EXPIRY_MS,
|
|
503
|
+
removedHeaders,
|
|
504
|
+
globalErrors,
|
|
505
|
+
APPWARDEN_TEST_ROUTE,
|
|
506
|
+
APPWARDEN_CACHE_KEY,
|
|
507
|
+
debug,
|
|
508
|
+
getErrors,
|
|
509
|
+
MemoryCache,
|
|
510
|
+
getEdgeConfigId,
|
|
511
|
+
isCacheUrl,
|
|
512
|
+
isValidCacheUrl,
|
|
513
|
+
printMessage,
|
|
514
|
+
LockValue,
|
|
515
|
+
ConfigFnInputSchema,
|
|
516
|
+
CSPDirectivesSchema,
|
|
517
|
+
CSPModeSchema,
|
|
518
|
+
UseCSPInputSchema,
|
|
519
|
+
BaseNextJsConfigSchema,
|
|
520
|
+
AppwardenConfigSchema,
|
|
521
|
+
syncEdgeValue,
|
|
522
|
+
handleVercelRequest,
|
|
523
|
+
usePipeline,
|
|
524
|
+
renderLockPage
|
|
525
|
+
};
|
package/cloudflare.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { B as Bindings } from './
|
|
1
|
+
import { M as Middleware, B as Bindings } from './use-content-security-policy-DBWKjDEH.js';
|
|
2
|
+
export { u as useContentSecurityPolicy } from './use-content-security-policy-DBWKjDEH.js';
|
|
2
3
|
import { z } from 'zod';
|
|
3
|
-
import { M as Middleware } from './use-content-security-policy-BtEGGIeu.js';
|
|
4
|
-
export { u as useContentSecurityPolicy } from './use-content-security-policy-BtEGGIeu.js';
|
|
5
4
|
|
|
6
5
|
declare const ConfigFnInputSchema: z.ZodFunction<z.ZodTuple<[z.ZodType<{
|
|
7
6
|
env: CloudflareEnv;
|
|
@@ -11,10 +10,10 @@ declare const ConfigFnInputSchema: z.ZodFunction<z.ZodTuple<[z.ZodType<{
|
|
|
11
10
|
env: CloudflareEnv;
|
|
12
11
|
cf: Record<string, unknown>;
|
|
13
12
|
ctx: unknown;
|
|
14
|
-
}>], z.ZodUnknown>, z.ZodObject<z.objectUtil.extendShape<
|
|
13
|
+
}>], z.ZodUnknown>, z.ZodObject<z.objectUtil.extendShape<{
|
|
15
14
|
debug: z.ZodDefault<z.ZodEffects<z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean]>>, boolean, string | boolean | undefined>>;
|
|
16
|
-
appwardenApiToken: z.ZodEffects<z.ZodString, string, string>;
|
|
17
15
|
lockPageSlug: z.ZodString;
|
|
16
|
+
appwardenApiToken: z.ZodEffects<z.ZodString, string, string>;
|
|
18
17
|
}, {
|
|
19
18
|
middleware: z.ZodDefault<z.ZodObject<{
|
|
20
19
|
before: z.ZodDefault<z.ZodArray<z.ZodType<Middleware, z.ZodTypeDef, Middleware>, "many">>;
|
|
@@ -23,15 +22,13 @@ declare const ConfigFnInputSchema: z.ZodFunction<z.ZodTuple<[z.ZodType<{
|
|
|
23
22
|
}, {
|
|
24
23
|
before?: Middleware[] | undefined;
|
|
25
24
|
}>>;
|
|
26
|
-
}>, {
|
|
27
|
-
debug: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean]>>;
|
|
28
25
|
}>, "strip", z.ZodTypeAny, {
|
|
26
|
+
debug: boolean;
|
|
29
27
|
lockPageSlug: string;
|
|
30
28
|
appwardenApiToken: string;
|
|
31
29
|
middleware: {
|
|
32
30
|
before: Middleware[];
|
|
33
31
|
};
|
|
34
|
-
debug?: string | boolean | undefined;
|
|
35
32
|
}, {
|
|
36
33
|
lockPageSlug: string;
|
|
37
34
|
appwardenApiToken: string;
|
|
@@ -40,8 +37,8 @@ declare const ConfigFnInputSchema: z.ZodFunction<z.ZodTuple<[z.ZodType<{
|
|
|
40
37
|
before?: Middleware[] | undefined;
|
|
41
38
|
} | undefined;
|
|
42
39
|
}>>;
|
|
43
|
-
type
|
|
40
|
+
type CloudflareConfigType = ReturnType<z.infer<typeof ConfigFnInputSchema>>;
|
|
44
41
|
|
|
45
|
-
declare const
|
|
42
|
+
declare const withAppwarden: (inputFn: CloudflareConfigType) => ExportedHandlerFetchHandler<Bindings>;
|
|
46
43
|
|
|
47
|
-
export {
|
|
44
|
+
export { withAppwarden };
|
package/cloudflare.js
CHANGED
|
@@ -1,13 +1,61 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
2
|
+
insertErrorLogs,
|
|
3
|
+
useAppwarden,
|
|
5
4
|
useContentSecurityPolicy
|
|
6
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-BHCQJZWE.js";
|
|
6
|
+
import {
|
|
7
|
+
ConfigFnInputSchema,
|
|
8
|
+
usePipeline
|
|
9
|
+
} from "./chunk-WVVSYKJM.js";
|
|
10
|
+
|
|
11
|
+
// src/runners/appwarden-on-cloudflare.ts
|
|
12
|
+
import { ZodError } from "zod";
|
|
13
|
+
|
|
14
|
+
// src/middlewares/use-fetch-origin.ts
|
|
15
|
+
var useFetchOrigin = () => async (context, next) => {
|
|
16
|
+
context.response = await fetch(
|
|
17
|
+
new Request(context.request, {
|
|
18
|
+
...context.request,
|
|
19
|
+
redirect: "follow"
|
|
20
|
+
})
|
|
21
|
+
);
|
|
22
|
+
await next();
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// src/runners/appwarden-on-cloudflare.ts
|
|
26
|
+
var appwardenOnCloudflare = (inputFn) => async (request, env, ctx) => {
|
|
27
|
+
ctx.passThroughOnException();
|
|
28
|
+
const context = {
|
|
29
|
+
request,
|
|
30
|
+
hostname: new URL(request.url).host,
|
|
31
|
+
response: new Response("Unhandled response"),
|
|
32
|
+
// https://developers.cloudflare.com/workers/observability/errors/#illegal-invocation-errors
|
|
33
|
+
waitUntil: (fn) => ctx.waitUntil(fn)
|
|
34
|
+
};
|
|
35
|
+
const parsedInput = ConfigFnInputSchema.safeParse(inputFn);
|
|
36
|
+
if (!parsedInput.success) {
|
|
37
|
+
return insertErrorLogs(context, parsedInput.error);
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const input = parsedInput.data({ env, ctx, cf: {} });
|
|
41
|
+
const pipeline = [
|
|
42
|
+
...input.middleware.before,
|
|
43
|
+
useAppwarden(input),
|
|
44
|
+
useFetchOrigin()
|
|
45
|
+
];
|
|
46
|
+
await usePipeline(...pipeline).execute(context);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (error instanceof ZodError) {
|
|
49
|
+
return insertErrorLogs(context, error);
|
|
50
|
+
}
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
return context.response;
|
|
54
|
+
};
|
|
7
55
|
|
|
8
56
|
// src/bundles/cloudflare.ts
|
|
9
|
-
var
|
|
57
|
+
var withAppwarden = appwardenOnCloudflare;
|
|
10
58
|
export {
|
|
11
59
|
useContentSecurityPolicy,
|
|
12
|
-
|
|
60
|
+
withAppwarden
|
|
13
61
|
};
|
package/index.d.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
export { B as Bindings } from './
|
|
2
|
-
export { C as CSPDirectivesSchema, a as CSPEnforcedSchema, M as Middleware, u as useContentSecurityPolicy } from './use-content-security-policy-BtEGGIeu.js';
|
|
1
|
+
export { B as Bindings, C as CSPDirectivesSchema, a as CSPModeSchema, M as Middleware, u as useContentSecurityPolicy } from './use-content-security-policy-DBWKjDEH.js';
|
|
3
2
|
import { z } from 'zod';
|
|
4
3
|
|
|
5
4
|
declare const LOCKDOWN_TEST_EXPIRY_MS: number;
|
|
5
|
+
declare const APPWARDEN_CACHE_KEY: "appwarden-lock";
|
|
6
|
+
|
|
7
|
+
declare const getEdgeConfigId: (value?: string) => string | undefined;
|
|
8
|
+
declare const isCacheUrl: {
|
|
9
|
+
edgeConfig: (value?: string) => boolean;
|
|
10
|
+
upstash: (value?: string) => boolean;
|
|
11
|
+
};
|
|
12
|
+
declare const isValidCacheUrl: {
|
|
13
|
+
edgeConfig: (value?: string) => boolean;
|
|
14
|
+
upstash: (value?: string) => string | false;
|
|
15
|
+
};
|
|
6
16
|
|
|
7
17
|
declare const LockValue: z.ZodObject<{
|
|
8
18
|
isLocked: z.ZodNumber;
|
|
@@ -10,16 +20,16 @@ declare const LockValue: z.ZodObject<{
|
|
|
10
20
|
lastCheck: z.ZodNumber;
|
|
11
21
|
code: z.ZodString;
|
|
12
22
|
}, "strip", z.ZodTypeAny, {
|
|
23
|
+
code: string;
|
|
13
24
|
isLocked: number;
|
|
14
25
|
isLockedTest: number;
|
|
15
26
|
lastCheck: number;
|
|
16
|
-
code: string;
|
|
17
27
|
}, {
|
|
28
|
+
code: string;
|
|
18
29
|
isLocked: number;
|
|
19
30
|
isLockedTest: number;
|
|
20
31
|
lastCheck: number;
|
|
21
|
-
code: string;
|
|
22
32
|
}>;
|
|
23
33
|
type LockValueType = z.infer<typeof LockValue>;
|
|
24
34
|
|
|
25
|
-
export { LOCKDOWN_TEST_EXPIRY_MS, type LockValueType };
|
|
35
|
+
export { APPWARDEN_CACHE_KEY, LOCKDOWN_TEST_EXPIRY_MS, type LockValueType, getEdgeConfigId, isCacheUrl, isValidCacheUrl };
|