@appwarden/middleware 1.0.19 → 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-5LAAKCPN.js → chunk-BHCQJZWE.js} +139 -13
- package/{chunk-D55SBZQF.js → chunk-WVVSYKJM.js} +232 -120
- package/cloudflare.d.ts +8 -11
- package/cloudflare.js +33 -18
- package/index.d.ts +15 -5
- package/index.js +14 -7
- package/package.json +1 -1
- package/use-content-security-policy-DBWKjDEH.d.ts +509 -0
- package/vercel.d.ts +6 -12
- package/vercel.js +11 -5
- package/chunk-PWSVQCB2.js +0 -207
- package/cloudflare-hVS30fDq.d.ts +0 -99
- package/nextjs-on-pages.d.ts +0 -30
- package/nextjs-on-pages.js +0 -85
- package/use-content-security-policy-BtEGGIeu.d.ts +0 -245
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
+
APPWARDEN_CACHE_KEY,
|
|
2
3
|
APPWARDEN_TEST_ROUTE,
|
|
3
4
|
LockValue,
|
|
4
5
|
MemoryCache,
|
|
6
|
+
UseCSPInputSchema,
|
|
5
7
|
debug,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
getErrors,
|
|
9
|
+
printMessage,
|
|
10
|
+
removedHeaders,
|
|
11
|
+
renderLockPage
|
|
12
|
+
} from "./chunk-WVVSYKJM.js";
|
|
8
13
|
|
|
9
14
|
// src/utils/cloudflare/cloudflare-cache.ts
|
|
10
15
|
var store = {
|
|
@@ -52,11 +57,6 @@ var updateCacheValue = async (context, cacheKey, value, cacheExpirationSeconds)
|
|
|
52
57
|
};
|
|
53
58
|
var clearCache = (context, cacheKey) => context.cache.delete(cacheKey);
|
|
54
59
|
|
|
55
|
-
// src/utils/cloudflare/create-response.ts
|
|
56
|
-
var createResponse = (body, status) => new Response(body, {
|
|
57
|
-
status
|
|
58
|
-
});
|
|
59
|
-
|
|
60
60
|
// src/utils/cloudflare/delete-edge-value.ts
|
|
61
61
|
var deleteEdgeValue = async (context) => {
|
|
62
62
|
try {
|
|
@@ -123,6 +123,45 @@ var getLockValue = async (context) => {
|
|
|
123
123
|
}
|
|
124
124
|
};
|
|
125
125
|
|
|
126
|
+
// src/utils/cloudflare/insert-errors-logs.ts
|
|
127
|
+
var insertErrorLogs = async (context, error) => new HTMLRewriter().on("body", {
|
|
128
|
+
element: (elem) => {
|
|
129
|
+
elem.append(
|
|
130
|
+
`<script>
|
|
131
|
+
${getErrors(error).map((err) => `console.error(\`${printMessage(err)}\`)`).join("\n")}
|
|
132
|
+
</script>`,
|
|
133
|
+
{ html: true }
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}).transform(await fetch(context.request));
|
|
137
|
+
|
|
138
|
+
// src/utils/cloudflare/make-csp-header.ts
|
|
139
|
+
var addNonce = (value, cspNonce) => value.replace("{{nonce}}", `'nonce-${cspNonce}'`);
|
|
140
|
+
var makeCSPHeader = (cspNonce, directives, mode) => {
|
|
141
|
+
const namesSeen = /* @__PURE__ */ new Set(), result = [];
|
|
142
|
+
Object.entries(directives ?? {}).forEach(([originalName, value]) => {
|
|
143
|
+
const name = originalName.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
144
|
+
if (namesSeen.has(name)) {
|
|
145
|
+
throw new Error(`${originalName} is specified more than once`);
|
|
146
|
+
}
|
|
147
|
+
namesSeen.add(name);
|
|
148
|
+
if (Array.isArray(value)) {
|
|
149
|
+
value = addNonce(value.join(" "), cspNonce);
|
|
150
|
+
} else if (value === true) {
|
|
151
|
+
value = "";
|
|
152
|
+
}
|
|
153
|
+
if (value) {
|
|
154
|
+
result.push(`${name} ${addNonce(value, cspNonce)}`);
|
|
155
|
+
} else if (value !== false) {
|
|
156
|
+
result.push(name);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
return [
|
|
160
|
+
mode === "enforced" ? "Content-Security-Policy" : "Content-Security-Policy-Report-Only",
|
|
161
|
+
result.join("; ")
|
|
162
|
+
];
|
|
163
|
+
};
|
|
164
|
+
|
|
126
165
|
// src/utils/cloudflare/sync-edge-value.ts
|
|
127
166
|
var APIError = class extends Error {
|
|
128
167
|
constructor(message) {
|
|
@@ -131,7 +170,7 @@ var APIError = class extends Error {
|
|
|
131
170
|
}
|
|
132
171
|
};
|
|
133
172
|
var syncEdgeValue = async (context) => {
|
|
134
|
-
debug(`syncing with api
|
|
173
|
+
debug(`syncing with api`);
|
|
135
174
|
try {
|
|
136
175
|
const response = await fetch(new URL("/v1/status/check", "https://bot-gateway.appwarden.io"), {
|
|
137
176
|
method: "POST",
|
|
@@ -178,6 +217,47 @@ var syncEdgeValue = async (context) => {
|
|
|
178
217
|
}
|
|
179
218
|
};
|
|
180
219
|
|
|
220
|
+
// src/middlewares/use-content-security-policy.ts
|
|
221
|
+
var AppendAttribute = (attribute, nonce) => ({
|
|
222
|
+
element: function(element) {
|
|
223
|
+
element.setAttribute(attribute, nonce);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
var useContentSecurityPolicy = (input) => {
|
|
227
|
+
const parsedInput = UseCSPInputSchema.safeParse(input);
|
|
228
|
+
if (!parsedInput.success) {
|
|
229
|
+
throw parsedInput.error;
|
|
230
|
+
}
|
|
231
|
+
const config = parsedInput.data;
|
|
232
|
+
return async (context, next) => {
|
|
233
|
+
await next();
|
|
234
|
+
const { response } = context;
|
|
235
|
+
if (
|
|
236
|
+
// if the csp is disabled
|
|
237
|
+
!["enforced", "report-only"].includes(config.mode)
|
|
238
|
+
) {
|
|
239
|
+
debug(printMessage("csp is disabled"));
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (response.headers.has("Content-Type") && !response.headers.get("Content-Type")?.includes("text/html")) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const cspNonce = btoa(crypto.getRandomValues(new Uint32Array(2)).toString());
|
|
246
|
+
const [cspHeaderName, cspHeaderValue] = makeCSPHeader(
|
|
247
|
+
cspNonce,
|
|
248
|
+
config.directives,
|
|
249
|
+
config.mode
|
|
250
|
+
);
|
|
251
|
+
const nextResponse = new Response(response.body, response);
|
|
252
|
+
nextResponse.headers.set(cspHeaderName, cspHeaderValue);
|
|
253
|
+
nextResponse.headers.set("content-type", "text/html; charset=utf-8");
|
|
254
|
+
removedHeaders.forEach((name) => {
|
|
255
|
+
nextResponse.headers.delete(name);
|
|
256
|
+
});
|
|
257
|
+
context.response = new HTMLRewriter().on("style", AppendAttribute("nonce", cspNonce)).on("script", AppendAttribute("nonce", cspNonce)).transform(nextResponse);
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
|
|
181
261
|
// src/handlers/maybe-quarantine.ts
|
|
182
262
|
var resolveLockValue = async (context, options) => {
|
|
183
263
|
const { lockValue, shouldDeleteEdgeValue } = await getLockValue(context);
|
|
@@ -223,10 +303,56 @@ var handleResetCache = async (keyName, provider, edgeCache, request) => {
|
|
|
223
303
|
}
|
|
224
304
|
};
|
|
225
305
|
|
|
306
|
+
// src/middlewares/use-appwarden.ts
|
|
307
|
+
var useAppwarden = (input) => async (context, next) => {
|
|
308
|
+
await next();
|
|
309
|
+
const { request, response } = context;
|
|
310
|
+
try {
|
|
311
|
+
const requestUrl = new URL(request.url);
|
|
312
|
+
const provider = "cloudflare-cache";
|
|
313
|
+
const keyName = APPWARDEN_CACHE_KEY;
|
|
314
|
+
const edgeCache = store.json(
|
|
315
|
+
{
|
|
316
|
+
serviceOrigin: requestUrl.origin,
|
|
317
|
+
cache: await caches.open("appwarden:lock")
|
|
318
|
+
},
|
|
319
|
+
keyName
|
|
320
|
+
);
|
|
321
|
+
if (isResetCacheRequest(request)) {
|
|
322
|
+
await handleResetCache(keyName, provider, edgeCache, request);
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const isHTMLRequest = response.headers.get("Content-Type")?.includes("text/html");
|
|
326
|
+
if (isHTMLRequest) {
|
|
327
|
+
const innerContext = {
|
|
328
|
+
keyName,
|
|
329
|
+
request,
|
|
330
|
+
edgeCache,
|
|
331
|
+
requestUrl,
|
|
332
|
+
provider,
|
|
333
|
+
debug: input.debug,
|
|
334
|
+
lockPageSlug: input.lockPageSlug,
|
|
335
|
+
appwardenApiToken: input.appwardenApiToken,
|
|
336
|
+
waitUntil: (fn) => context.waitUntil(fn)
|
|
337
|
+
};
|
|
338
|
+
await maybeQuarantine(innerContext, {
|
|
339
|
+
onLocked: async () => {
|
|
340
|
+
context.response = await renderLockPage(innerContext);
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
} catch (e) {
|
|
345
|
+
const message = "Appwarden encountered an unknown error. Please contact Appwarden support at https://appwarden.io/join-community.";
|
|
346
|
+
console.error(
|
|
347
|
+
printMessage(
|
|
348
|
+
e instanceof Error ? `${message} - ${e.message}` : message
|
|
349
|
+
)
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
|
|
226
354
|
export {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
isResetCacheRequest,
|
|
231
|
-
handleResetCache
|
|
355
|
+
insertErrorLogs,
|
|
356
|
+
useAppwarden,
|
|
357
|
+
useContentSecurityPolicy
|
|
232
358
|
};
|
|
@@ -1,20 +1,78 @@
|
|
|
1
1
|
// src/constants.ts
|
|
2
2
|
var LOCKDOWN_TEST_EXPIRY_MS = 5 * 60 * 1e3;
|
|
3
3
|
var removedHeaders = ["X-Powered-By", "Server"];
|
|
4
|
-
var securityHeaders = [
|
|
5
|
-
["Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload"],
|
|
6
|
-
["X-Frame-Options", "DENY"],
|
|
7
|
-
["X-XSS-Protection", "1; mode=block"],
|
|
8
|
-
["X-Content-Type-Options", "nosniff"],
|
|
9
|
-
["Referrer-Policy", "no-referrer, strict-origin-when-cross-origin"],
|
|
10
|
-
["X-DNS-Prefetch-Control", "on"]
|
|
11
|
-
];
|
|
12
4
|
var errors = { badCacheConnection: "BAD_CACHE_CONNECTION" };
|
|
13
5
|
var globalErrors = [errors.badCacheConnection];
|
|
14
6
|
var APPWARDEN_TEST_ROUTE = "_appwarden/test";
|
|
7
|
+
var APPWARDEN_CACHE_KEY = "appwarden-lock";
|
|
15
8
|
|
|
16
|
-
// src/
|
|
17
|
-
|
|
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
|
+
]);
|
|
18
76
|
|
|
19
77
|
// src/utils/debug.ts
|
|
20
78
|
var debug = (...msg) => {
|
|
@@ -23,6 +81,39 @@ var debug = (...msg) => {
|
|
|
23
81
|
}
|
|
24
82
|
};
|
|
25
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
|
+
|
|
26
117
|
// src/utils/memory-cache.ts
|
|
27
118
|
var MemoryCache = class {
|
|
28
119
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -67,19 +158,23 @@ var MemoryCache = class {
|
|
|
67
158
|
};
|
|
68
159
|
|
|
69
160
|
// src/utils/print-message.ts
|
|
70
|
-
var
|
|
161
|
+
var addSlashes = (str) => str.replace(/[\\"'`]/g, "\\$&").replace(/\u0000/g, "\\0");
|
|
162
|
+
var printMessage = (message) => `[@appwarden/middleware] ${addSlashes(message)}`;
|
|
71
163
|
|
|
72
164
|
// src/utils/vercel/delete-edge-value.ts
|
|
73
165
|
var deleteEdgeValue = async ({
|
|
74
166
|
keyName,
|
|
75
167
|
provider,
|
|
76
|
-
|
|
77
|
-
edgeConfigId,
|
|
168
|
+
cacheUrl,
|
|
78
169
|
vercelApiToken
|
|
79
170
|
}) => {
|
|
80
171
|
try {
|
|
81
172
|
switch (provider) {
|
|
82
173
|
case "edge-config": {
|
|
174
|
+
const edgeConfigId = getEdgeConfigId(cacheUrl);
|
|
175
|
+
if (!edgeConfigId) {
|
|
176
|
+
throw new Error("Failed to parse `edgeConfigId`");
|
|
177
|
+
}
|
|
83
178
|
const res = await fetch(
|
|
84
179
|
`https://api.vercel.com/v1/edge-config/${edgeConfigId}/items`,
|
|
85
180
|
{
|
|
@@ -111,9 +206,9 @@ var deleteEdgeValue = async ({
|
|
|
111
206
|
break;
|
|
112
207
|
}
|
|
113
208
|
case "upstash": {
|
|
114
|
-
const
|
|
209
|
+
const { hostname, password } = new URL(cacheUrl);
|
|
115
210
|
const { Redis } = await import("@upstash/redis");
|
|
116
|
-
const redis = new Redis({ url
|
|
211
|
+
const redis = new Redis({ url: `https://${hostname}`, token: password });
|
|
117
212
|
await redis.del(keyName);
|
|
118
213
|
break;
|
|
119
214
|
}
|
|
@@ -129,11 +224,14 @@ var deleteEdgeValue = async ({
|
|
|
129
224
|
};
|
|
130
225
|
|
|
131
226
|
// src/schemas/cloudflare.ts
|
|
132
|
-
import { z as
|
|
227
|
+
import { z as z5 } from "zod";
|
|
228
|
+
|
|
229
|
+
// src/schemas/use-appwarden.ts
|
|
230
|
+
import { z as z4 } from "zod";
|
|
133
231
|
|
|
134
232
|
// src/schemas/helpers.ts
|
|
135
|
-
import { z } from "zod";
|
|
136
|
-
var BoolOrStringSchema =
|
|
233
|
+
import { z as z3 } from "zod";
|
|
234
|
+
var BoolOrStringSchema = z3.union([z3.string(), z3.boolean()]).optional();
|
|
137
235
|
var BooleanSchema = BoolOrStringSchema.transform((val) => {
|
|
138
236
|
if (val === "true" || val === true) {
|
|
139
237
|
return true;
|
|
@@ -142,38 +240,77 @@ var BooleanSchema = BoolOrStringSchema.transform((val) => {
|
|
|
142
240
|
}
|
|
143
241
|
throw new Error("Invalid value");
|
|
144
242
|
});
|
|
145
|
-
var
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
),
|
|
151
|
-
path: ["appwardenApiToken"]
|
|
152
|
-
}),
|
|
153
|
-
lockPageSlug: z.string()
|
|
243
|
+
var LockValue = z3.object({
|
|
244
|
+
isLocked: z3.number(),
|
|
245
|
+
isLockedTest: z3.number(),
|
|
246
|
+
lastCheck: z3.number(),
|
|
247
|
+
code: z3.string()
|
|
154
248
|
});
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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"] })
|
|
160
255
|
});
|
|
161
256
|
|
|
162
257
|
// src/schemas/cloudflare.ts
|
|
163
|
-
var
|
|
164
|
-
|
|
165
|
-
})
|
|
166
|
-
var ConfigFnInputSchema = z2.function().args(z2.custom()).returns(
|
|
167
|
-
ConfigOutputSchema.extend({
|
|
168
|
-
debug: BoolOrStringSchema
|
|
258
|
+
var ConfigFnInputSchema = z5.function().args(z5.custom()).returns(
|
|
259
|
+
UseAppwardenInputSchema.extend({
|
|
260
|
+
middleware: z5.object({ before: z5.custom().array().default([]) }).default({})
|
|
169
261
|
})
|
|
170
262
|
);
|
|
171
|
-
var CloudflareConfigFnOutputSchema = z2.function().args(z2.custom()).returns(ConfigOutputSchema);
|
|
172
263
|
|
|
173
264
|
// src/schemas/nextjs.ts
|
|
174
|
-
import { z as
|
|
175
|
-
var
|
|
176
|
-
|
|
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
|
+
});
|
|
177
314
|
|
|
178
315
|
// src/utils/vercel/get-lock-value.ts
|
|
179
316
|
var getLockValue = async (context) => {
|
|
@@ -188,17 +325,22 @@ var getLockValue = async (context) => {
|
|
|
188
325
|
switch (context.provider) {
|
|
189
326
|
case "edge-config": {
|
|
190
327
|
const { createClient } = await import("@vercel/edge-config");
|
|
191
|
-
const edgeConfig = createClient(context.
|
|
328
|
+
const edgeConfig = createClient(context.cacheUrl);
|
|
192
329
|
serializedValue = await edgeConfig.get(
|
|
193
330
|
context.keyName
|
|
194
331
|
);
|
|
195
332
|
break;
|
|
196
333
|
}
|
|
197
334
|
case "upstash": {
|
|
198
|
-
const
|
|
335
|
+
const { hostname, password } = new URL(context.cacheUrl);
|
|
199
336
|
const { Redis } = await import("@upstash/redis");
|
|
200
|
-
const redis = new Redis({
|
|
201
|
-
|
|
337
|
+
const redis = new Redis({
|
|
338
|
+
url: `https://${hostname}`,
|
|
339
|
+
token: password
|
|
340
|
+
});
|
|
341
|
+
const redisValue = await redis.get(
|
|
342
|
+
context.keyName
|
|
343
|
+
);
|
|
202
344
|
serializedValue = redisValue === null ? void 0 : redisValue;
|
|
203
345
|
break;
|
|
204
346
|
}
|
|
@@ -209,7 +351,9 @@ var getLockValue = async (context) => {
|
|
|
209
351
|
return { lockValue: void 0 };
|
|
210
352
|
}
|
|
211
353
|
try {
|
|
212
|
-
lockValue = LockValue.parse(
|
|
354
|
+
lockValue = LockValue.parse(
|
|
355
|
+
typeof serializedValue === "string" ? JSON.parse(serializedValue) : serializedValue
|
|
356
|
+
);
|
|
213
357
|
} catch (error) {
|
|
214
358
|
console.error(
|
|
215
359
|
printMessage(
|
|
@@ -241,19 +385,17 @@ var APIError = class extends Error {
|
|
|
241
385
|
}
|
|
242
386
|
};
|
|
243
387
|
var syncEdgeValue = async (context) => {
|
|
244
|
-
debug(
|
|
388
|
+
debug(`syncing with api`);
|
|
245
389
|
try {
|
|
246
390
|
const response = await fetch(new URL("/v1/status/check", "https://bot-gateway.appwarden.io"), {
|
|
247
391
|
method: "POST",
|
|
248
392
|
headers: { "content-type": "application/json" },
|
|
249
393
|
body: JSON.stringify({
|
|
250
394
|
service: "vercel",
|
|
251
|
-
|
|
395
|
+
cacheUrl: context.cacheUrl,
|
|
252
396
|
fqdn: context.requestUrl.hostname,
|
|
253
|
-
edgeConfigId: context.edgeConfigId ?? "",
|
|
254
397
|
vercelApiToken: context.vercelApiToken ?? "",
|
|
255
|
-
appwardenApiToken: context.appwardenApiToken
|
|
256
|
-
connectionString: context.connectionString
|
|
398
|
+
appwardenApiToken: context.appwardenApiToken
|
|
257
399
|
})
|
|
258
400
|
});
|
|
259
401
|
if (response.status !== 200) {
|
|
@@ -325,85 +467,55 @@ var renderLockPage = (context) => fetch(new URL(context.lockPageSlug, context.re
|
|
|
325
467
|
}
|
|
326
468
|
});
|
|
327
469
|
|
|
328
|
-
// src/schemas/
|
|
329
|
-
var
|
|
330
|
-
(
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
).
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}
|
|
358
|
-
).refine(
|
|
359
|
-
(data) => {
|
|
360
|
-
return data.provider === "upstash" && data.connectionString.includes("upstash") || data.provider === "edge-config" && data.connectionString.includes("edge-config");
|
|
361
|
-
},
|
|
362
|
-
{
|
|
363
|
-
message: printMessage(
|
|
364
|
-
"Invalid connection string for the selected `provider`"
|
|
365
|
-
),
|
|
366
|
-
path: ["connectionString"]
|
|
367
|
-
}
|
|
368
|
-
).refine(
|
|
369
|
-
(data) => {
|
|
370
|
-
if (data.provider === "edge-config") {
|
|
371
|
-
return !!data.vercelApiToken;
|
|
372
|
-
}
|
|
373
|
-
return true;
|
|
374
|
-
},
|
|
375
|
-
{
|
|
376
|
-
message: printMessage("Missing vercelApiToken when provider=edge-config"),
|
|
377
|
-
path: ["vercelApiToken"]
|
|
378
|
-
}
|
|
379
|
-
).refine(
|
|
380
|
-
(data) => {
|
|
381
|
-
if (data.provider === "edge-config") {
|
|
382
|
-
return !!data.edgeConfigId;
|
|
383
|
-
}
|
|
384
|
-
return true;
|
|
385
|
-
},
|
|
386
|
-
{
|
|
387
|
-
message: printMessage(
|
|
388
|
-
"Missing `edgeConfigId` when `provider=edge-config`"
|
|
389
|
-
),
|
|
390
|
-
path: ["edgeConfigId"]
|
|
391
|
-
}
|
|
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 */ }
|
|
392
499
|
);
|
|
393
500
|
|
|
394
501
|
export {
|
|
395
502
|
LOCKDOWN_TEST_EXPIRY_MS,
|
|
396
503
|
removedHeaders,
|
|
397
|
-
securityHeaders,
|
|
398
504
|
globalErrors,
|
|
399
505
|
APPWARDEN_TEST_ROUTE,
|
|
506
|
+
APPWARDEN_CACHE_KEY,
|
|
400
507
|
debug,
|
|
508
|
+
getErrors,
|
|
401
509
|
MemoryCache,
|
|
510
|
+
getEdgeConfigId,
|
|
511
|
+
isCacheUrl,
|
|
512
|
+
isValidCacheUrl,
|
|
402
513
|
printMessage,
|
|
403
|
-
BoolOrStringSchema,
|
|
404
514
|
LockValue,
|
|
405
|
-
|
|
406
|
-
|
|
515
|
+
ConfigFnInputSchema,
|
|
516
|
+
CSPDirectivesSchema,
|
|
517
|
+
CSPModeSchema,
|
|
518
|
+
UseCSPInputSchema,
|
|
407
519
|
BaseNextJsConfigSchema,
|
|
408
520
|
AppwardenConfigSchema,
|
|
409
521
|
syncEdgeValue,
|