@appwarden/middleware 3.11.5 → 3.12.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-5HCAAVK5.js → chunk-6YCNCR22.js} +3 -5
- package/{chunk-R7TXTHSG.js → chunk-EXGUJ5XK.js} +75 -143
- package/chunk-G6BMPIYD.js +11 -0
- package/chunk-HTSD4WPC.js +378 -0
- package/chunk-HUWGPM4M.js +9 -0
- package/{chunk-WBWF3PPX.js → chunk-ILIYP3TG.js} +4 -6
- package/{chunk-XFG6SUSV.js → chunk-M2YVPCTG.js} +15 -0
- package/chunk-NV7K5PRA.js +36 -0
- package/{chunk-ZTVJBORU.js → chunk-Z7P4QVEY.js} +74 -8
- package/cloudflare/astro.d.ts +3 -3
- package/cloudflare/astro.js +109 -62
- package/cloudflare/nextjs.d.ts +2 -2
- package/cloudflare/nextjs.js +65 -21
- package/cloudflare/react-router.d.ts +3 -3
- package/cloudflare/react-router.js +92 -57
- package/cloudflare/tanstack-start.d.ts +2 -2
- package/cloudflare/tanstack-start.js +92 -80
- package/cloudflare.d.ts +1 -1
- package/cloudflare.js +80 -11
- package/index.d.ts +1 -1
- package/index.js +2 -3
- 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-X7WZVYQS.js +0 -6
- package/cloudflare-MAHYENA6.js +0 -29
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useContentSecurityPolicy
|
|
3
|
+
} from "./chunk-ILIYP3TG.js";
|
|
4
|
+
|
|
5
|
+
// src/utils/apply-content-security-policy-to-response.ts
|
|
6
|
+
var applyContentSecurityPolicyToResponse = async ({
|
|
7
|
+
contentSecurityPolicy,
|
|
8
|
+
...context
|
|
9
|
+
}) => {
|
|
10
|
+
await useContentSecurityPolicy(contentSecurityPolicy)(context, async () => {
|
|
11
|
+
});
|
|
12
|
+
return context.response;
|
|
13
|
+
};
|
|
14
|
+
|
|
1
15
|
// src/utils/is-response-like.ts
|
|
2
16
|
var isResponseLike = (value) => {
|
|
3
17
|
if (!value || typeof value !== "object") return false;
|
|
@@ -7,5 +21,6 @@ var isResponseLike = (value) => {
|
|
|
7
21
|
};
|
|
8
22
|
|
|
9
23
|
export {
|
|
24
|
+
applyContentSecurityPolicyToResponse,
|
|
10
25
|
isResponseLike
|
|
11
26
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/utils/errors.ts
|
|
2
|
+
var errorsMap = {
|
|
3
|
+
mode: '`CSP_MODE` must be one of "disabled", "report-only", or "enforced"',
|
|
4
|
+
directives: {
|
|
5
|
+
["DirectivesRequired" /* DirectivesRequired */]: '`CSP_DIRECTIVES` must be provided when `CSP_MODE` is "report-only" or "enforced"',
|
|
6
|
+
["DirectivesBadParse" /* DirectivesBadParse */]: "Failed to parse `CSP_DIRECTIVES`. Is it a valid JSON string?"
|
|
7
|
+
},
|
|
8
|
+
appwardenApiToken: "Please provide a valid `appwardenApiToken`. Learn more at https://appwarden.com/docs/guides/api-token-management."
|
|
9
|
+
};
|
|
10
|
+
var getErrors = (error) => {
|
|
11
|
+
const matches = [];
|
|
12
|
+
const errors = [...Object.entries(error.flatten().fieldErrors)];
|
|
13
|
+
for (const issue of error.issues) {
|
|
14
|
+
errors.push(
|
|
15
|
+
...Object.entries(
|
|
16
|
+
"returnTypeError" in issue ? issue.returnTypeError.flatten().fieldErrors : {}
|
|
17
|
+
)
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
for (const [field, maybeSchemaErrorKey] of errors) {
|
|
21
|
+
let match = errorsMap[field];
|
|
22
|
+
if (match) {
|
|
23
|
+
if (match instanceof Object) {
|
|
24
|
+
if (maybeSchemaErrorKey) {
|
|
25
|
+
match = match[maybeSchemaErrorKey[0]];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
matches.push(match);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return matches;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export {
|
|
35
|
+
getErrors
|
|
36
|
+
};
|
|
@@ -3,10 +3,41 @@ var LOCKDOWN_TEST_EXPIRY_MS = 5 * 60 * 1e3;
|
|
|
3
3
|
var errors = { badCacheConnection: "BAD_CACHE_CONNECTION" };
|
|
4
4
|
var globalErrors = [errors.badCacheConnection];
|
|
5
5
|
var APPWARDEN_TEST_ROUTE = "/_appwarden/test";
|
|
6
|
+
var APPWARDEN_HEARTBEAT_ROUTE = "/_appwarden/heartbeat";
|
|
7
|
+
var HEARTBEAT_CONTRACT_VERSION = 1;
|
|
8
|
+
var HEARTBEAT_CONFIG_ERROR_MAX_COUNT = 10;
|
|
9
|
+
var HEARTBEAT_CONFIG_ERROR_MAX_PATH_DEPTH = 10;
|
|
10
|
+
var HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH = 100;
|
|
11
|
+
var HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH = 500;
|
|
12
|
+
var HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH = 100;
|
|
6
13
|
var APPWARDEN_CACHE_KEY = "appwarden-lock";
|
|
14
|
+
var HEARTBEAT_SERVICE_VALUES = [
|
|
15
|
+
"cloudflare",
|
|
16
|
+
"cloudflare-astro",
|
|
17
|
+
"cloudflare-react-router",
|
|
18
|
+
"cloudflare-tanstack-start",
|
|
19
|
+
"cloudflare-nextjs",
|
|
20
|
+
"vercel"
|
|
21
|
+
];
|
|
22
|
+
var [
|
|
23
|
+
CLOUDFLARE,
|
|
24
|
+
CLOUDFLARE_ASTRO,
|
|
25
|
+
CLOUDFLARE_REACT_ROUTER,
|
|
26
|
+
CLOUDFLARE_TANSTACK_START,
|
|
27
|
+
CLOUDFLARE_NEXTJS,
|
|
28
|
+
VERCEL
|
|
29
|
+
] = HEARTBEAT_SERVICE_VALUES;
|
|
30
|
+
var HEARTBEAT_SERVICES = {
|
|
31
|
+
CLOUDFLARE,
|
|
32
|
+
CLOUDFLARE_ASTRO,
|
|
33
|
+
CLOUDFLARE_REACT_ROUTER,
|
|
34
|
+
CLOUDFLARE_TANSTACK_START,
|
|
35
|
+
CLOUDFLARE_NEXTJS,
|
|
36
|
+
VERCEL
|
|
37
|
+
};
|
|
7
38
|
|
|
8
39
|
// src/schemas/use-content-security-policy.ts
|
|
9
|
-
import { z as
|
|
40
|
+
import { z as z3 } from "zod";
|
|
10
41
|
|
|
11
42
|
// src/types/csp.ts
|
|
12
43
|
import { z } from "zod";
|
|
@@ -40,17 +71,40 @@ var ContentSecurityPolicySchema = z.object({
|
|
|
40
71
|
"require-trusted-types-for": stringySchema.optional()
|
|
41
72
|
});
|
|
42
73
|
|
|
74
|
+
// src/schemas/helpers.ts
|
|
75
|
+
import { z as z2 } from "zod";
|
|
76
|
+
var BoolOrStringSchema = z2.union([z2.string(), z2.boolean()]).optional();
|
|
77
|
+
var BooleanSchema = BoolOrStringSchema.transform((val) => {
|
|
78
|
+
if (val === "true" || val === true) {
|
|
79
|
+
return true;
|
|
80
|
+
} else if (val === "false" || val === false) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
throw new Error("Invalid value");
|
|
84
|
+
});
|
|
85
|
+
var AppwardenApiTokenSchema = z2.string().refine((val) => !!val, { message: "appwardenApiToken is required" });
|
|
86
|
+
var AppwardenApiHostnameSchema = z2.string().url({
|
|
87
|
+
message: "Invalid `appwardenApiHostname`. Please provide an absolute URL (e.g. https://api.appwarden.io)."
|
|
88
|
+
}).refine((value) => value.startsWith("https://"), {
|
|
89
|
+
message: "`appwardenApiHostname` must use the https:// scheme (e.g. https://api.appwarden.io)."
|
|
90
|
+
});
|
|
91
|
+
var LockValue = z2.object({
|
|
92
|
+
isLocked: z2.number(),
|
|
93
|
+
isLockedTest: z2.number(),
|
|
94
|
+
lastCheck: z2.number()
|
|
95
|
+
});
|
|
96
|
+
|
|
43
97
|
// src/schemas/use-content-security-policy.ts
|
|
44
|
-
var CSPDirectivesSchema =
|
|
45
|
-
|
|
98
|
+
var CSPDirectivesSchema = z3.union([
|
|
99
|
+
z3.string(),
|
|
46
100
|
ContentSecurityPolicySchema
|
|
47
101
|
]);
|
|
48
|
-
var CSPModeSchema =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
102
|
+
var CSPModeSchema = z3.union([
|
|
103
|
+
z3.literal("disabled"),
|
|
104
|
+
z3.literal("report-only"),
|
|
105
|
+
z3.literal("enforced")
|
|
52
106
|
]);
|
|
53
|
-
var UseCSPInputSchema =
|
|
107
|
+
var UseCSPInputSchema = z3.object({
|
|
54
108
|
mode: CSPModeSchema,
|
|
55
109
|
directives: CSPDirectivesSchema.refine(
|
|
56
110
|
(val) => {
|
|
@@ -74,7 +128,19 @@ export {
|
|
|
74
128
|
errors,
|
|
75
129
|
globalErrors,
|
|
76
130
|
APPWARDEN_TEST_ROUTE,
|
|
131
|
+
APPWARDEN_HEARTBEAT_ROUTE,
|
|
132
|
+
HEARTBEAT_CONTRACT_VERSION,
|
|
133
|
+
HEARTBEAT_CONFIG_ERROR_MAX_COUNT,
|
|
134
|
+
HEARTBEAT_CONFIG_ERROR_MAX_PATH_DEPTH,
|
|
135
|
+
HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH,
|
|
136
|
+
HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH,
|
|
137
|
+
HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH,
|
|
77
138
|
APPWARDEN_CACHE_KEY,
|
|
139
|
+
HEARTBEAT_SERVICES,
|
|
140
|
+
BooleanSchema,
|
|
141
|
+
AppwardenApiTokenSchema,
|
|
142
|
+
AppwardenApiHostnameSchema,
|
|
143
|
+
LockValue,
|
|
78
144
|
CSPDirectivesSchema,
|
|
79
145
|
CSPModeSchema,
|
|
80
146
|
UseCSPInputSchema
|
package/cloudflare/astro.d.ts
CHANGED
|
@@ -270,8 +270,8 @@ declare const AstroCloudflareConfigSchema: z.ZodObject<{
|
|
|
270
270
|
};
|
|
271
271
|
}>>>;
|
|
272
272
|
}, "strip", z.ZodTypeAny, {
|
|
273
|
-
debug: boolean;
|
|
274
273
|
lockPageSlug: string;
|
|
274
|
+
debug: boolean;
|
|
275
275
|
appwardenApiToken: string;
|
|
276
276
|
contentSecurityPolicy?: {
|
|
277
277
|
mode: "disabled" | "report-only" | "enforced";
|
|
@@ -308,7 +308,6 @@ declare const AstroCloudflareConfigSchema: z.ZodObject<{
|
|
|
308
308
|
}, {
|
|
309
309
|
lockPageSlug: string;
|
|
310
310
|
appwardenApiToken: string;
|
|
311
|
-
debug?: string | boolean | undefined;
|
|
312
311
|
contentSecurityPolicy?: {
|
|
313
312
|
mode: "disabled" | "report-only" | "enforced";
|
|
314
313
|
directives: string | {
|
|
@@ -340,6 +339,7 @@ declare const AstroCloudflareConfigSchema: z.ZodObject<{
|
|
|
340
339
|
"require-trusted-types-for"?: string | boolean | string[] | undefined;
|
|
341
340
|
};
|
|
342
341
|
} | undefined;
|
|
342
|
+
debug?: string | boolean | undefined;
|
|
343
343
|
appwardenApiHostname?: string | undefined;
|
|
344
344
|
}>;
|
|
345
345
|
type AstroCloudflareConfig = z.infer<typeof AstroCloudflareConfigSchema>;
|
|
@@ -383,7 +383,7 @@ type AstroConfigFn = (runtime: AstroCloudflareRuntime) => AstroCloudflareConfigI
|
|
|
383
383
|
* ```typescript
|
|
384
384
|
* // src/middleware.ts
|
|
385
385
|
* import { sequence } from "astro:middleware"
|
|
386
|
-
* import { createAppwardenMiddleware } from "@appwarden/middleware/astro"
|
|
386
|
+
* import { createAppwardenMiddleware } from "@appwarden/middleware/cloudflare/astro"
|
|
387
387
|
*
|
|
388
388
|
* const appwarden = createAppwardenMiddleware(({ env }) => ({
|
|
389
389
|
* lockPageSlug: env.APPWARDEN_LOCK_PAGE_SLUG,
|
package/cloudflare/astro.js
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
import {
|
|
2
|
+
applyContentSecurityPolicyToResponse,
|
|
2
3
|
isResponseLike
|
|
3
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-M2YVPCTG.js";
|
|
5
|
+
import "../chunk-ILIYP3TG.js";
|
|
4
6
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
getNowMs
|
|
9
|
-
} from "../chunk-X7WZVYQS.js";
|
|
7
|
+
getNowMs,
|
|
8
|
+
logElapsed
|
|
9
|
+
} from "../chunk-G6BMPIYD.js";
|
|
10
10
|
import {
|
|
11
11
|
checkLockStatus
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-EXGUJ5XK.js";
|
|
13
13
|
import {
|
|
14
14
|
TEMPORARY_REDIRECT_STATUS,
|
|
15
15
|
buildLockPageUrl,
|
|
16
|
+
createHeartbeatConfigError,
|
|
16
17
|
createRedirect,
|
|
17
18
|
debug,
|
|
19
|
+
handleHeartbeatRequest,
|
|
18
20
|
isHTMLRequest,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} from "../chunk-
|
|
24
|
-
import {
|
|
25
|
-
printMessage
|
|
26
|
-
} from "../chunk-R7TXTHSG.js";
|
|
21
|
+
isHeartbeatRequest,
|
|
22
|
+
isOnLockPage,
|
|
23
|
+
printMessage,
|
|
24
|
+
sanitizeConfigErrors
|
|
25
|
+
} from "../chunk-HTSD4WPC.js";
|
|
27
26
|
import {
|
|
28
27
|
AppwardenApiHostnameSchema,
|
|
29
28
|
AppwardenApiTokenSchema,
|
|
30
|
-
BooleanSchema
|
|
31
|
-
|
|
29
|
+
BooleanSchema,
|
|
30
|
+
HEARTBEAT_SERVICES,
|
|
31
|
+
UseCSPInputSchema
|
|
32
|
+
} from "../chunk-Z7P4QVEY.js";
|
|
32
33
|
|
|
33
34
|
// src/adapters/astro-cloudflare.ts
|
|
34
35
|
import { waitUntil } from "cloudflare:workers";
|
|
@@ -49,11 +50,76 @@ var AstroCloudflareConfigSchema = z.object({
|
|
|
49
50
|
});
|
|
50
51
|
|
|
51
52
|
// src/adapters/astro-cloudflare.ts
|
|
53
|
+
var createAstroHeartbeatResponse = (request, runtime, configFn) => {
|
|
54
|
+
if (!runtime) {
|
|
55
|
+
return handleHeartbeatRequest(
|
|
56
|
+
request,
|
|
57
|
+
HEARTBEAT_SERVICES.CLOUDFLARE_ASTRO,
|
|
58
|
+
[
|
|
59
|
+
createHeartbeatConfigError(
|
|
60
|
+
["runtime"],
|
|
61
|
+
"custom",
|
|
62
|
+
"Cloudflare runtime unavailable"
|
|
63
|
+
)
|
|
64
|
+
]
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const validationResult = AstroCloudflareConfigSchema.safeParse(
|
|
69
|
+
configFn(runtime)
|
|
70
|
+
);
|
|
71
|
+
return handleHeartbeatRequest(
|
|
72
|
+
request,
|
|
73
|
+
HEARTBEAT_SERVICES.CLOUDFLARE_ASTRO,
|
|
74
|
+
validationResult.success ? [] : sanitizeConfigErrors(validationResult.error)
|
|
75
|
+
);
|
|
76
|
+
} catch {
|
|
77
|
+
return handleHeartbeatRequest(
|
|
78
|
+
request,
|
|
79
|
+
HEARTBEAT_SERVICES.CLOUDFLARE_ASTRO,
|
|
80
|
+
[
|
|
81
|
+
createHeartbeatConfigError(
|
|
82
|
+
["config"],
|
|
83
|
+
"custom",
|
|
84
|
+
"Appwarden config evaluation failed"
|
|
85
|
+
)
|
|
86
|
+
]
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
52
90
|
function createAppwardenMiddleware(configFn) {
|
|
53
91
|
return async (context, next) => {
|
|
54
92
|
const startTime = getNowMs();
|
|
55
93
|
const { request } = context;
|
|
94
|
+
let config;
|
|
95
|
+
let debugFn;
|
|
96
|
+
const requestUrl = new URL(request.url);
|
|
97
|
+
const applyCspToResponse = async (response2) => {
|
|
98
|
+
if (!config.contentSecurityPolicy || !isResponseLike(response2)) {
|
|
99
|
+
return response2;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
return await applyContentSecurityPolicyToResponse({
|
|
103
|
+
request,
|
|
104
|
+
response: response2,
|
|
105
|
+
hostname: requestUrl.hostname,
|
|
106
|
+
waitUntil,
|
|
107
|
+
debug: debugFn,
|
|
108
|
+
contentSecurityPolicy: config.contentSecurityPolicy
|
|
109
|
+
});
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.error(
|
|
112
|
+
printMessage(
|
|
113
|
+
`Failed to apply content security policy: ${error instanceof Error ? error.message : String(error)}`
|
|
114
|
+
)
|
|
115
|
+
);
|
|
116
|
+
return response2;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
56
119
|
const locals = context.locals;
|
|
120
|
+
if (isHeartbeatRequest(request, requestUrl)) {
|
|
121
|
+
return createAstroHeartbeatResponse(request, locals.runtime, configFn);
|
|
122
|
+
}
|
|
57
123
|
try {
|
|
58
124
|
const runtime = locals.runtime;
|
|
59
125
|
if (!runtime) {
|
|
@@ -74,9 +140,8 @@ function createAppwardenMiddleware(configFn) {
|
|
|
74
140
|
);
|
|
75
141
|
return next();
|
|
76
142
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const requestUrl = new URL(request.url);
|
|
143
|
+
config = validationResult.data;
|
|
144
|
+
debugFn = debug(config.debug);
|
|
80
145
|
const isHTML = isHTMLRequest(request);
|
|
81
146
|
debugFn(
|
|
82
147
|
`Appwarden middleware invoked for ${requestUrl.pathname}`,
|
|
@@ -86,51 +151,29 @@ function createAppwardenMiddleware(configFn) {
|
|
|
86
151
|
return next();
|
|
87
152
|
}
|
|
88
153
|
if (isOnLockPage(config.lockPageSlug, request.url)) {
|
|
89
|
-
debugFn("Already on lock page - skipping");
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const result = await checkLockStatus({
|
|
93
|
-
request,
|
|
94
|
-
appwardenApiToken: config.appwardenApiToken,
|
|
95
|
-
appwardenApiHostname: config.appwardenApiHostname,
|
|
96
|
-
debug: config.debug,
|
|
97
|
-
lockPageSlug: config.lockPageSlug,
|
|
98
|
-
waitUntil
|
|
99
|
-
});
|
|
100
|
-
if (result.isLocked) {
|
|
101
|
-
const lockPageUrl = buildLockPageUrl(config.lockPageSlug, request.url);
|
|
102
|
-
debugFn(`Website is locked - redirecting to ${lockPageUrl.pathname}`);
|
|
103
|
-
if (context.redirect) {
|
|
104
|
-
return context.redirect(
|
|
105
|
-
lockPageUrl.toString(),
|
|
106
|
-
TEMPORARY_REDIRECT_STATUS
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
return createRedirect(lockPageUrl);
|
|
110
|
-
}
|
|
111
|
-
debugFn("Website is unlocked");
|
|
112
|
-
const response = await next();
|
|
113
|
-
if (config.contentSecurityPolicy && isResponseLike(response)) {
|
|
114
|
-
const cspContext = {
|
|
154
|
+
debugFn("Already on lock page - skipping lock status check");
|
|
155
|
+
} else {
|
|
156
|
+
const result = await checkLockStatus({
|
|
115
157
|
request,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
158
|
+
appwardenApiToken: config.appwardenApiToken,
|
|
159
|
+
appwardenApiHostname: config.appwardenApiHostname,
|
|
160
|
+
debug: config.debug,
|
|
161
|
+
lockPageSlug: config.lockPageSlug,
|
|
162
|
+
waitUntil
|
|
163
|
+
});
|
|
164
|
+
if (result.isLocked) {
|
|
165
|
+
const lockPageUrl = buildLockPageUrl(config.lockPageSlug, request.url);
|
|
166
|
+
debugFn(`Website is locked - redirecting to ${lockPageUrl.pathname}`);
|
|
167
|
+
if (context.redirect) {
|
|
168
|
+
return context.redirect(
|
|
169
|
+
lockPageUrl.toString(),
|
|
170
|
+
TEMPORARY_REDIRECT_STATUS
|
|
171
|
+
);
|
|
124
172
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
debugFn(`Middleware executed in ${elapsed2}ms`);
|
|
129
|
-
return cspContext.response;
|
|
173
|
+
return createRedirect(lockPageUrl);
|
|
174
|
+
}
|
|
175
|
+
debugFn("Website is unlocked");
|
|
130
176
|
}
|
|
131
|
-
const elapsed = Math.round(getNowMs() - startTime);
|
|
132
|
-
debugFn(`Middleware executed in ${elapsed}ms`);
|
|
133
|
-
return response;
|
|
134
177
|
} catch (error) {
|
|
135
178
|
if (isResponseLike(error)) {
|
|
136
179
|
throw error;
|
|
@@ -142,6 +185,10 @@ function createAppwardenMiddleware(configFn) {
|
|
|
142
185
|
);
|
|
143
186
|
return next();
|
|
144
187
|
}
|
|
188
|
+
const response = await next();
|
|
189
|
+
const finalResponse = await applyCspToResponse(response);
|
|
190
|
+
logElapsed(debugFn, startTime);
|
|
191
|
+
return finalResponse;
|
|
145
192
|
};
|
|
146
193
|
}
|
|
147
194
|
export {
|
package/cloudflare/nextjs.d.ts
CHANGED
|
@@ -329,8 +329,8 @@ declare const NextJsCloudflareConfigSchema: z.ZodObject<{
|
|
|
329
329
|
};
|
|
330
330
|
}>>>;
|
|
331
331
|
}, "strip", z.ZodTypeAny, {
|
|
332
|
-
debug: boolean;
|
|
333
332
|
lockPageSlug: string;
|
|
333
|
+
debug: boolean;
|
|
334
334
|
appwardenApiToken: string;
|
|
335
335
|
contentSecurityPolicy?: {
|
|
336
336
|
mode: "disabled" | "report-only" | "enforced";
|
|
@@ -367,7 +367,6 @@ declare const NextJsCloudflareConfigSchema: z.ZodObject<{
|
|
|
367
367
|
}, {
|
|
368
368
|
lockPageSlug: string;
|
|
369
369
|
appwardenApiToken: string;
|
|
370
|
-
debug?: string | boolean | undefined;
|
|
371
370
|
contentSecurityPolicy?: {
|
|
372
371
|
mode: "disabled" | "report-only" | "enforced";
|
|
373
372
|
directives: string | {
|
|
@@ -399,6 +398,7 @@ declare const NextJsCloudflareConfigSchema: z.ZodObject<{
|
|
|
399
398
|
"require-trusted-types-for"?: string | boolean | string[] | undefined;
|
|
400
399
|
};
|
|
401
400
|
} | undefined;
|
|
401
|
+
debug?: string | boolean | undefined;
|
|
402
402
|
appwardenApiHostname?: string | undefined;
|
|
403
403
|
}>;
|
|
404
404
|
type NextJsCloudflareConfig = z.infer<typeof NextJsCloudflareConfigSchema>;
|
package/cloudflare/nextjs.js
CHANGED
|
@@ -1,29 +1,36 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "../chunk-
|
|
2
|
+
toNextResponse
|
|
3
|
+
} from "../chunk-HUWGPM4M.js";
|
|
4
|
+
import {
|
|
5
|
+
getNowMs,
|
|
6
|
+
logElapsed
|
|
7
|
+
} from "../chunk-G6BMPIYD.js";
|
|
4
8
|
import {
|
|
5
9
|
checkLockStatus
|
|
6
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-EXGUJ5XK.js";
|
|
7
11
|
import {
|
|
8
12
|
TEMPORARY_REDIRECT_STATUS,
|
|
9
13
|
buildLockPageUrl,
|
|
14
|
+
createHeartbeatConfigError,
|
|
10
15
|
debug,
|
|
16
|
+
handleHeartbeatRequest,
|
|
11
17
|
isHTMLRequest,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
printMessage
|
|
19
|
-
} from "../chunk-R7TXTHSG.js";
|
|
18
|
+
isHeartbeatRequest,
|
|
19
|
+
isOnLockPage,
|
|
20
|
+
makeCSPHeader,
|
|
21
|
+
printMessage,
|
|
22
|
+
sanitizeConfigErrors
|
|
23
|
+
} from "../chunk-HTSD4WPC.js";
|
|
20
24
|
import {
|
|
21
25
|
AppwardenApiHostnameSchema,
|
|
22
26
|
AppwardenApiTokenSchema,
|
|
23
|
-
BooleanSchema
|
|
24
|
-
|
|
27
|
+
BooleanSchema,
|
|
28
|
+
HEARTBEAT_SERVICES,
|
|
29
|
+
UseCSPInputSchema
|
|
30
|
+
} from "../chunk-Z7P4QVEY.js";
|
|
25
31
|
|
|
26
32
|
// src/adapters/nextjs-cloudflare.ts
|
|
33
|
+
import { getCloudflareContext } from "@opennextjs/cloudflare";
|
|
27
34
|
import {
|
|
28
35
|
NextResponse
|
|
29
36
|
} from "next/server";
|
|
@@ -55,12 +62,53 @@ var NextJsCloudflareConfigSchema = z.object({
|
|
|
55
62
|
});
|
|
56
63
|
|
|
57
64
|
// src/adapters/nextjs-cloudflare.ts
|
|
65
|
+
var createNextJsHeartbeatResponse = (request, configFn) => {
|
|
66
|
+
let runtime;
|
|
67
|
+
try {
|
|
68
|
+
runtime = getCloudflareContext();
|
|
69
|
+
} catch {
|
|
70
|
+
return toNextResponse(
|
|
71
|
+
handleHeartbeatRequest(request, HEARTBEAT_SERVICES.CLOUDFLARE_NEXTJS, [
|
|
72
|
+
createHeartbeatConfigError(
|
|
73
|
+
["context"],
|
|
74
|
+
"custom",
|
|
75
|
+
"Cloudflare context unavailable"
|
|
76
|
+
)
|
|
77
|
+
])
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const validationResult = NextJsCloudflareConfigSchema.safeParse(
|
|
82
|
+
configFn(runtime)
|
|
83
|
+
);
|
|
84
|
+
return toNextResponse(
|
|
85
|
+
handleHeartbeatRequest(
|
|
86
|
+
request,
|
|
87
|
+
HEARTBEAT_SERVICES.CLOUDFLARE_NEXTJS,
|
|
88
|
+
validationResult.success ? [] : sanitizeConfigErrors(validationResult.error)
|
|
89
|
+
)
|
|
90
|
+
);
|
|
91
|
+
} catch {
|
|
92
|
+
return toNextResponse(
|
|
93
|
+
handleHeartbeatRequest(request, HEARTBEAT_SERVICES.CLOUDFLARE_NEXTJS, [
|
|
94
|
+
createHeartbeatConfigError(
|
|
95
|
+
["config"],
|
|
96
|
+
"custom",
|
|
97
|
+
"Appwarden config evaluation failed"
|
|
98
|
+
)
|
|
99
|
+
])
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
58
103
|
function createAppwardenMiddleware(configFn) {
|
|
59
104
|
return async (request, _event) => {
|
|
60
105
|
const startTime = getNowMs();
|
|
106
|
+
const requestUrl = new URL(request.url);
|
|
107
|
+
if (isHeartbeatRequest(request, requestUrl)) {
|
|
108
|
+
return createNextJsHeartbeatResponse(request, configFn);
|
|
109
|
+
}
|
|
61
110
|
try {
|
|
62
|
-
const {
|
|
63
|
-
const { env, ctx } = await getCloudflareContext();
|
|
111
|
+
const { env, ctx } = getCloudflareContext();
|
|
64
112
|
const rawConfig = configFn({ env, ctx });
|
|
65
113
|
const validationResult = NextJsCloudflareConfigSchema.safeParse(rawConfig);
|
|
66
114
|
if (!validationResult.success) {
|
|
@@ -73,7 +121,6 @@ function createAppwardenMiddleware(configFn) {
|
|
|
73
121
|
}
|
|
74
122
|
const config = validationResult.data;
|
|
75
123
|
const debugFn = debug(config.debug);
|
|
76
|
-
const requestUrl = new URL(request.url);
|
|
77
124
|
const isHTML = isHTMLRequest(request);
|
|
78
125
|
debugFn(
|
|
79
126
|
`Appwarden middleware invoked for ${requestUrl.pathname}`,
|
|
@@ -104,7 +151,6 @@ function createAppwardenMiddleware(configFn) {
|
|
|
104
151
|
debugFn(
|
|
105
152
|
`Applying CSP headers in ${config.contentSecurityPolicy.mode} mode`
|
|
106
153
|
);
|
|
107
|
-
const { makeCSPHeader } = await import("../cloudflare-MAHYENA6.js");
|
|
108
154
|
const [headerName, headerValue] = makeCSPHeader(
|
|
109
155
|
"",
|
|
110
156
|
config.contentSecurityPolicy.directives,
|
|
@@ -112,12 +158,10 @@ function createAppwardenMiddleware(configFn) {
|
|
|
112
158
|
);
|
|
113
159
|
const response = NextResponse.next();
|
|
114
160
|
response.headers.set(headerName, headerValue);
|
|
115
|
-
|
|
116
|
-
debugFn(`Middleware executed in ${elapsed2}ms`);
|
|
161
|
+
logElapsed(debugFn, startTime);
|
|
117
162
|
return response;
|
|
118
163
|
}
|
|
119
|
-
|
|
120
|
-
debugFn(`Middleware executed in ${elapsed}ms`);
|
|
164
|
+
logElapsed(debugFn, startTime);
|
|
121
165
|
return NextResponse.next();
|
|
122
166
|
} catch (error) {
|
|
123
167
|
console.error(
|
|
@@ -268,8 +268,8 @@ declare const ReactRouterCloudflareConfigSchema: z.ZodObject<{
|
|
|
268
268
|
};
|
|
269
269
|
}>>>;
|
|
270
270
|
}, "strip", z.ZodTypeAny, {
|
|
271
|
-
debug: boolean;
|
|
272
271
|
lockPageSlug: string;
|
|
272
|
+
debug: boolean;
|
|
273
273
|
appwardenApiToken: string;
|
|
274
274
|
contentSecurityPolicy?: {
|
|
275
275
|
mode: "disabled" | "report-only" | "enforced";
|
|
@@ -306,7 +306,6 @@ declare const ReactRouterCloudflareConfigSchema: z.ZodObject<{
|
|
|
306
306
|
}, {
|
|
307
307
|
lockPageSlug: string;
|
|
308
308
|
appwardenApiToken: string;
|
|
309
|
-
debug?: string | boolean | undefined;
|
|
310
309
|
contentSecurityPolicy?: {
|
|
311
310
|
mode: "disabled" | "report-only" | "enforced";
|
|
312
311
|
directives: string | {
|
|
@@ -338,6 +337,7 @@ declare const ReactRouterCloudflareConfigSchema: z.ZodObject<{
|
|
|
338
337
|
"require-trusted-types-for"?: string | boolean | string[] | undefined;
|
|
339
338
|
};
|
|
340
339
|
} | undefined;
|
|
340
|
+
debug?: string | boolean | undefined;
|
|
341
341
|
appwardenApiHostname?: string | undefined;
|
|
342
342
|
}>;
|
|
343
343
|
type ReactRouterCloudflareConfig = z.infer<typeof ReactRouterCloudflareConfigSchema>;
|
|
@@ -377,7 +377,7 @@ type ReactRouterMiddlewareFunction = (args: ReactRouterMiddlewareArgs, next: ()
|
|
|
377
377
|
* ```typescript
|
|
378
378
|
* // app/root.tsx
|
|
379
379
|
* import { env } from "cloudflare:workers"
|
|
380
|
-
* import { createAppwardenMiddleware } from "@appwarden/middleware/react-router"
|
|
380
|
+
* import { createAppwardenMiddleware } from "@appwarden/middleware/cloudflare/react-router"
|
|
381
381
|
*
|
|
382
382
|
* export const unstable_middleware = [
|
|
383
383
|
* createAppwardenMiddleware(() => ({
|