@patchstack/connect 0.5.27 → 0.5.32
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/AGENT-INSTALL.md +75 -25
- package/README.md +28 -14
- package/dist/{chunk-YG5C7HYB.js → chunk-52IV7LN7.js} +1 -1
- package/dist/{chunk-YG5C7HYB.js.map → chunk-52IV7LN7.js.map} +1 -1
- package/dist/cli.js +2749 -372
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +10 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +10 -6
- package/dist/index.js.map +1 -1
- package/dist/protect/templates/astro-middleware.ts +5 -4
- package/dist/protect/templates/express-guard.cjs +5 -8
- package/dist/protect/templates/express-guard.js +5 -8
- package/dist/protect/templates/express-guard.ts +5 -8
- package/dist/protect/templates/fastify-plugin.cjs +52 -6
- package/dist/protect/templates/fastify-plugin.js +52 -6
- package/dist/protect/templates/fastify-plugin.ts +53 -7
- package/dist/protect/templates/fetch-guard.ts +52 -0
- package/dist/protect/templates/generic-guard.cjs +6 -5
- package/dist/protect/templates/generic-guard.js +6 -5
- package/dist/protect/templates/generic-guard.ts +5 -8
- package/dist/protect/templates/guard.ts +4 -7
- package/dist/protect/templates/next-guard.ts +5 -4
- package/dist/protect/templates/next-middleware.ts +5 -4
- package/dist/protect/templates/nuxt-middleware.ts +5 -4
- package/dist/protect/templates/sveltekit-hooks.ts +5 -4
- package/dist/protect.cjs +10 -6
- package/dist/protect.cjs.map +1 -1
- package/dist/protect.d.cts +1 -1
- package/dist/protect.d.ts +1 -1
- package/dist/protect.edge.js +2 -2
- package/dist/protect.edge.js.map +1 -1
- package/dist/protect.js +4 -4
- package/dist/protect.js.map +1 -1
- package/dist/{refresh-manifest-THITZHBD.js → refresh-manifest-EBORKM75.js} +10 -6
- package/dist/refresh-manifest-EBORKM75.js.map +1 -0
- package/package.json +5 -2
- package/dist/refresh-manifest-THITZHBD.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Patchstack runtime guard for Fastify — plugin. Managed by `patchstack-connect protect`.
|
|
2
2
|
// Register it once (`app.register(patchstackFastify)`); it adds a preHandler hook that runs the
|
|
3
|
-
// request-phase WAF (+ egress SSRF)
|
|
3
|
+
// request-phase WAF (+ egress SSRF) and filters buffered onSend output. Fastify's request/reply aren't Web-Fetch
|
|
4
4
|
// shaped, so we reconstruct a Request from the parsed fastify request and run the fetch guard.
|
|
5
5
|
import { createProtection, sentinelAnswer, VERIFY_HEADER } from "@patchstack/connect/protect";
|
|
6
6
|
import fallbackRules from "./rules.json";
|
|
@@ -29,10 +29,11 @@ async function getProtection() {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
async function buildProtection() {
|
|
32
|
-
const mode = process.env.PATCHSTACK_MODE === "dry-run" ? "dry-run" : "block";
|
|
33
|
-
const token = process.env.PATCHSTACK_WAF_TOKEN;
|
|
34
|
-
const siteUuid = PS_SITE_UUID.startsWith("__") ? process.env.PATCHSTACK_SITE_UUID : PS_SITE_UUID;
|
|
35
|
-
const
|
|
32
|
+
const mode = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_MODE) === "dry-run" ? "dry-run" : "block";
|
|
33
|
+
const token = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_WAF_TOKEN);
|
|
34
|
+
const siteUuid = PS_SITE_UUID.startsWith("__") ? (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_SITE_UUID) : PS_SITE_UUID;
|
|
35
|
+
const refreshMs = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_ENVIRONMENT) === "sandbox" ? 15000 : 300000;
|
|
36
|
+
const common = { mode, egress: true, refreshMs } as const;
|
|
36
37
|
return createProtection(
|
|
37
38
|
siteUuid
|
|
38
39
|
? { ...common, siteUuid, rules: fallbackRules as never, cacheDir: ".patchstack" }
|
|
@@ -92,8 +93,23 @@ export async function patchstackFastify(fastify: any) {
|
|
|
92
93
|
const host = request.headers?.host ?? "localhost";
|
|
93
94
|
const url = `http://${host}${request.url ?? "/"}`;
|
|
94
95
|
const hasBody = method !== "GET" && method !== "HEAD" && request.body != null;
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
let blocked;
|
|
97
|
+
try {
|
|
98
|
+
const headers = new Headers();
|
|
99
|
+
for (const [name, value] of Object.entries(request.headers)) {
|
|
100
|
+
if (value !== undefined) headers.set(name, Array.isArray(value) ? value.join(", ") : String(value));
|
|
101
|
+
}
|
|
102
|
+
const parsed = hasBody && typeof request.body === "object" && !Buffer.isBuffer(request.body);
|
|
103
|
+
const body = hasBody ? (parsed ? JSON.stringify(request.body) : request.body) : undefined;
|
|
104
|
+
// Fastify already parsed form fields. Screen that object as JSON, not JSON mislabeled as a form.
|
|
105
|
+
// Only the screening copy changes; the route keeps its original body, headers and raw stream.
|
|
106
|
+
if (parsed) headers.set("content-type", "application/json");
|
|
107
|
+
headers.delete("content-length");
|
|
108
|
+
blocked = await guard(new Request(url, { method, headers, body }));
|
|
109
|
+
} catch (err) {
|
|
110
|
+
psStepAside(err);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
97
113
|
if (blocked) {
|
|
98
114
|
const contentType = blocked.headers.get("content-type");
|
|
99
115
|
reply.code(blocked.status);
|
|
@@ -102,6 +118,36 @@ export async function patchstackFastify(fastify: any) {
|
|
|
102
118
|
return reply; // stop the request here
|
|
103
119
|
}
|
|
104
120
|
});
|
|
121
|
+
|
|
122
|
+
fastify.addHook("onSend", async (request: any, reply: any, payload: any) => {
|
|
123
|
+
// Do not consume streams, hijacked responses, or bodyless status codes.
|
|
124
|
+
if ((typeof payload !== "string" && !Buffer.isBuffer(payload))
|
|
125
|
+
|| request.method === "HEAD" || reply.statusCode < 200 || [204, 205, 304].includes(reply.statusCode)) return payload;
|
|
126
|
+
const protection = await getProtection().catch(psStepAside);
|
|
127
|
+
if (!protection) return payload;
|
|
128
|
+
try {
|
|
129
|
+
const headers = new Headers();
|
|
130
|
+
for (const [name, value] of Object.entries(reply.getHeaders())) {
|
|
131
|
+
for (const item of Array.isArray(value) ? value : [value]) {
|
|
132
|
+
if (item !== undefined) headers.append(name, String(item));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const original = new Response(typeof payload === "string" ? payload : new Uint8Array(payload).buffer, { status: reply.statusCode, headers });
|
|
136
|
+
const context = new Request(`http://${request.headers?.host ?? "localhost"}${request.url ?? "/"}`, { method: request.method, headers: request.headers });
|
|
137
|
+
const screened = await protection.screenResponse(original, context);
|
|
138
|
+
if (screened === original) return payload;
|
|
139
|
+
const body = Buffer.from(await screened.arrayBuffer());
|
|
140
|
+
reply.code(screened.status);
|
|
141
|
+
for (const name of Object.keys(reply.getHeaders())) reply.removeHeader(name);
|
|
142
|
+
screened.headers.forEach((value, name) => { if (name !== "set-cookie") reply.header(name, value); });
|
|
143
|
+
const cookies = screened.headers.getSetCookie();
|
|
144
|
+
if (cookies.length) reply.header("set-cookie", cookies);
|
|
145
|
+
return body;
|
|
146
|
+
} catch (err) {
|
|
147
|
+
psStepAside(err);
|
|
148
|
+
return payload;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
105
151
|
}
|
|
106
152
|
// #endregion patchstack-fastify
|
|
107
153
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Server-only Fetch guard for bundled applications. Never import this module into client code.
|
|
2
|
+
import { createProtection, sentinelAnswer, VERIFY_HEADER } from "@patchstack/connect/protect";
|
|
3
|
+
import fallbackRules from "./rules.json";
|
|
4
|
+
|
|
5
|
+
const PS_SITE_UUID = "__PATCHSTACK_SITE_UUID__";
|
|
6
|
+
type Protection = Awaited<ReturnType<typeof createProtection>>;
|
|
7
|
+
const policies = new WeakMap<object, Promise<Protection>>();
|
|
8
|
+
const emptyEnvironment = {};
|
|
9
|
+
let warned = false;
|
|
10
|
+
|
|
11
|
+
function environment(value: unknown): Record<string, unknown> {
|
|
12
|
+
if (value && typeof value === "object" && ["PATCHSTACK_API_KEY", "PATCHSTACK_SITE_UUID", "PATCHSTACK_PULSE_AUTH"].some(key => key in value)) {
|
|
13
|
+
return value as Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
return typeof process === "undefined" ? emptyEnvironment : process.env;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function getProtection(bindings: unknown) {
|
|
19
|
+
const env = environment(bindings);
|
|
20
|
+
let pending = policies.get(env);
|
|
21
|
+
if (!pending) {
|
|
22
|
+
const value = (key: string) => typeof env[key] === "string" ? env[key] as string : undefined;
|
|
23
|
+
pending = createProtection({
|
|
24
|
+
siteUuid: PS_SITE_UUID.startsWith("__") ? value("PATCHSTACK_SITE_UUID") : PS_SITE_UUID,
|
|
25
|
+
apiKey: value("PATCHSTACK_API_KEY"),
|
|
26
|
+
pulseAuth: value("PATCHSTACK_PULSE_AUTH") ?? value("PATCHSTACK_API_KEY"),
|
|
27
|
+
mode: value("PATCHSTACK_MODE") === "dry-run" ? "dry-run" : "block",
|
|
28
|
+
rules: fallbackRules as never,
|
|
29
|
+
cacheDir: ".patchstack",
|
|
30
|
+
refreshMs: value("PATCHSTACK_ENVIRONMENT") === "sandbox" ? 15000 : 300000,
|
|
31
|
+
egress: true,
|
|
32
|
+
}).catch(error => { policies.delete(env); throw error; });
|
|
33
|
+
policies.set(env, pending);
|
|
34
|
+
}
|
|
35
|
+
return pending.catch(error => {
|
|
36
|
+
if (!warned) {
|
|
37
|
+
warned = true;
|
|
38
|
+
console.warn("[patchstack] protection is unavailable; traffic may pass through unscreened until a later attempt succeeds.", error instanceof Error ? error.message : String(error));
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function protectFetch<Args extends unknown[]>(handler: (request: Request, ...args: Args) => Response | Promise<Response>) {
|
|
45
|
+
return async function(this: unknown, request: Request, ...args: Args): Promise<Response> {
|
|
46
|
+
const answered = await sentinelAnswer(request.headers.get(VERIFY_HEADER));
|
|
47
|
+
if (answered) return new Response(answered, { headers: { "content-type": "text/plain" } });
|
|
48
|
+
const protection = await getProtection(args[0]);
|
|
49
|
+
// Only initialization fails open here. Application failures propagate without repeating the handler.
|
|
50
|
+
return protection ? protection.fetch(handler).call(this, request, ...args) : handler.call(this, request, ...args);
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -31,10 +31,11 @@ async function getProtection() {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
async function buildProtection() {
|
|
34
|
-
const mode = process.env.PATCHSTACK_MODE === "dry-run" ? "dry-run" : "block";
|
|
35
|
-
const token = process.env.PATCHSTACK_WAF_TOKEN;
|
|
36
|
-
const siteUuid = PS_SITE_UUID.startsWith("__") ? process.env.PATCHSTACK_SITE_UUID : PS_SITE_UUID;
|
|
37
|
-
const
|
|
34
|
+
const mode = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_MODE) === "dry-run" ? "dry-run" : "block";
|
|
35
|
+
const token = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_WAF_TOKEN);
|
|
36
|
+
const siteUuid = PS_SITE_UUID.startsWith("__") ? (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_SITE_UUID) : PS_SITE_UUID;
|
|
37
|
+
const refreshMs = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_ENVIRONMENT) === "sandbox" ? 15000 : 300000;
|
|
38
|
+
const common = { mode, egress: true, refreshMs };
|
|
38
39
|
return createProtection(
|
|
39
40
|
siteUuid
|
|
40
41
|
? { ...common, siteUuid, rules: fallbackRules, cacheDir: ".patchstack" }
|
|
@@ -105,7 +106,7 @@ function patchstackMiddleware(req, res, next) {
|
|
|
105
106
|
// there is nothing to answer and the request is screened as normal.
|
|
106
107
|
const screen = () => {
|
|
107
108
|
getProtection().then(
|
|
108
|
-
(active) => active.node()(req, res, carryOn),
|
|
109
|
+
(active) => active.node({ screenResponses: true })(req, res, carryOn),
|
|
109
110
|
(err) => {
|
|
110
111
|
psStepAside(err);
|
|
111
112
|
carryOn();
|
|
@@ -32,10 +32,11 @@ export async function getProtection() {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
async function buildProtection() {
|
|
35
|
-
const mode = process.env.PATCHSTACK_MODE === "dry-run" ? "dry-run" : "block";
|
|
36
|
-
const token = process.env.PATCHSTACK_WAF_TOKEN;
|
|
37
|
-
const siteUuid = PS_SITE_UUID.startsWith("__") ? process.env.PATCHSTACK_SITE_UUID : PS_SITE_UUID;
|
|
38
|
-
const
|
|
35
|
+
const mode = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_MODE) === "dry-run" ? "dry-run" : "block";
|
|
36
|
+
const token = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_WAF_TOKEN);
|
|
37
|
+
const siteUuid = PS_SITE_UUID.startsWith("__") ? (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_SITE_UUID) : PS_SITE_UUID;
|
|
38
|
+
const refreshMs = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_ENVIRONMENT) === "sandbox" ? 15000 : 300000;
|
|
39
|
+
const common = { mode, egress: true, refreshMs };
|
|
39
40
|
return createProtection(
|
|
40
41
|
siteUuid
|
|
41
42
|
? { ...common, siteUuid, rules: fallbackRules, cacheDir: ".patchstack" }
|
|
@@ -107,7 +108,7 @@ export function patchstackMiddleware(req, res, next) {
|
|
|
107
108
|
// there is nothing to answer and the request is screened as normal.
|
|
108
109
|
const screen = () => {
|
|
109
110
|
getProtection().then(
|
|
110
|
-
(active) => active.node()(req, res, carryOn),
|
|
111
|
+
(active) => active.node({ screenResponses: true })(req, res, carryOn),
|
|
111
112
|
(err) => {
|
|
112
113
|
psStepAside(err);
|
|
113
114
|
carryOn();
|
|
@@ -35,13 +35,10 @@ export async function getProtection() {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
async function buildProtection() {
|
|
38
|
-
const mode = process.env.PATCHSTACK_MODE === "dry-run" ? "dry-run" : "block";
|
|
39
|
-
const token = process.env.PATCHSTACK_WAF_TOKEN;
|
|
40
|
-
const siteUuid = PS_SITE_UUID.startsWith("__") ? process.env.PATCHSTACK_SITE_UUID : PS_SITE_UUID;
|
|
41
|
-
|
|
42
|
-
// rules periodically — a dependency flagged after boot is then enforced without a restart.
|
|
43
|
-
// Production relies on a redeploy (which re-fetches at boot), so refresh stays off there.
|
|
44
|
-
const refreshMs = process.env.PATCHSTACK_ENVIRONMENT === "sandbox" ? 15000 : 0;
|
|
38
|
+
const mode = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_MODE) === "dry-run" ? "dry-run" : "block";
|
|
39
|
+
const token = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_WAF_TOKEN);
|
|
40
|
+
const siteUuid = PS_SITE_UUID.startsWith("__") ? (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_SITE_UUID) : PS_SITE_UUID;
|
|
41
|
+
const refreshMs = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_ENVIRONMENT) === "sandbox" ? 15000 : 300000;
|
|
45
42
|
const common = { mode, egress: true, refreshMs } as const;
|
|
46
43
|
return createProtection(
|
|
47
44
|
siteUuid
|
|
@@ -116,7 +113,7 @@ export function patchstackMiddleware(req: unknown, res: unknown, next: (err?: un
|
|
|
116
113
|
// there is nothing to answer and the request is screened as normal.
|
|
117
114
|
const screen = () => {
|
|
118
115
|
getProtection().then(
|
|
119
|
-
(protection) => (protection.node() as (a: unknown, b: unknown, c: (e?: unknown) => void) => void)(req, res, carryOn),
|
|
116
|
+
(protection) => (protection.node({ screenResponses: true }) as (a: unknown, b: unknown, c: (e?: unknown) => void) => void)(req, res, carryOn),
|
|
120
117
|
(err) => {
|
|
121
118
|
psStepAside(err);
|
|
122
119
|
carryOn();
|
|
@@ -49,9 +49,9 @@ async function getProtection() {
|
|
|
49
49
|
|
|
50
50
|
async function buildProtection() {
|
|
51
51
|
// Always-on: block by default. An explicit PATCHSTACK_MODE=dry-run downgrades to log-only.
|
|
52
|
-
const mode: "block" | "dry-run" = process.env.PATCHSTACK_MODE === "dry-run" ? "dry-run" : "block";
|
|
53
|
-
const token = process.env.PATCHSTACK_WAF_TOKEN;
|
|
54
|
-
const siteUuid = PS_SITE_UUID.startsWith("__") ? process.env.PATCHSTACK_SITE_UUID : PS_SITE_UUID;
|
|
52
|
+
const mode: "block" | "dry-run" = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_MODE) === "dry-run" ? "dry-run" : "block";
|
|
53
|
+
const token = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_WAF_TOKEN);
|
|
54
|
+
const siteUuid = PS_SITE_UUID.startsWith("__") ? (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_SITE_UUID) : PS_SITE_UUID;
|
|
55
55
|
// Egress SSRF screening: block the app's outbound calls to internal / metadata addresses,
|
|
56
56
|
// but never its own Supabase project.
|
|
57
57
|
let allowHosts: string[] = [];
|
|
@@ -60,10 +60,7 @@ async function buildProtection() {
|
|
|
60
60
|
} catch {
|
|
61
61
|
/* ignore a malformed SUPABASE_URL — just don't add an allow entry */
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
// rules periodically — a dependency flagged after boot is then enforced without a restart.
|
|
65
|
-
// Production relies on a redeploy (which re-fetches at boot), so refresh stays off there.
|
|
66
|
-
const refreshMs = process.env.PATCHSTACK_ENVIRONMENT === "sandbox" ? 15000 : 0;
|
|
63
|
+
const refreshMs = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_ENVIRONMENT) === "sandbox" ? 15000 : 300000;
|
|
67
64
|
const common = { mode, egress: true, allowHosts, refreshMs };
|
|
68
65
|
return createProtection(
|
|
69
66
|
siteUuid
|
|
@@ -18,10 +18,11 @@ async function getProtection() {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
async function buildProtection() {
|
|
21
|
-
const mode = process.env.PATCHSTACK_MODE === "dry-run" ? "dry-run" : "block";
|
|
22
|
-
const siteUuid = PS_SITE_UUID.startsWith("__") ? process.env.PATCHSTACK_SITE_UUID : PS_SITE_UUID;
|
|
23
|
-
const token = process.env.PATCHSTACK_WAF_TOKEN;
|
|
24
|
-
const
|
|
21
|
+
const mode = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_MODE) === "dry-run" ? "dry-run" : "block";
|
|
22
|
+
const siteUuid = PS_SITE_UUID.startsWith("__") ? (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_SITE_UUID) : PS_SITE_UUID;
|
|
23
|
+
const token = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_WAF_TOKEN);
|
|
24
|
+
const refreshMs = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_ENVIRONMENT) === "sandbox" ? 15000 : 300000;
|
|
25
|
+
const common = { mode, egress: true, refreshMs } as const;
|
|
25
26
|
return createProtection(
|
|
26
27
|
siteUuid
|
|
27
28
|
? { ...common, siteUuid, rules: fallbackRules as never, cacheDir: ".patchstack" }
|
|
@@ -29,10 +29,11 @@ async function getProtection() {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
async function buildProtection() {
|
|
32
|
-
const mode = process.env.PATCHSTACK_MODE === "dry-run" ? "dry-run" : "block";
|
|
33
|
-
const token = process.env.PATCHSTACK_WAF_TOKEN;
|
|
34
|
-
const siteUuid = PS_SITE_UUID.startsWith("__") ? process.env.PATCHSTACK_SITE_UUID : PS_SITE_UUID;
|
|
35
|
-
const
|
|
32
|
+
const mode = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_MODE) === "dry-run" ? "dry-run" : "block";
|
|
33
|
+
const token = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_WAF_TOKEN);
|
|
34
|
+
const siteUuid = PS_SITE_UUID.startsWith("__") ? (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_SITE_UUID) : PS_SITE_UUID;
|
|
35
|
+
const refreshMs = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_ENVIRONMENT) === "sandbox" ? 15000 : 300000;
|
|
36
|
+
const common = { mode, egress: true, refreshMs } as const;
|
|
36
37
|
return createProtection(
|
|
37
38
|
siteUuid
|
|
38
39
|
? { ...common, siteUuid, rules: fallbackRules as never, cacheDir: ".patchstack" }
|
|
@@ -29,10 +29,11 @@ async function getProtection() {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
async function buildProtection() {
|
|
32
|
-
const mode = process.env.PATCHSTACK_MODE === "dry-run" ? "dry-run" : "block";
|
|
33
|
-
const token = process.env.PATCHSTACK_WAF_TOKEN;
|
|
34
|
-
const siteUuid = PS_SITE_UUID.startsWith("__") ? process.env.PATCHSTACK_SITE_UUID : PS_SITE_UUID;
|
|
35
|
-
const
|
|
32
|
+
const mode = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_MODE) === "dry-run" ? "dry-run" : "block";
|
|
33
|
+
const token = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_WAF_TOKEN);
|
|
34
|
+
const siteUuid = PS_SITE_UUID.startsWith("__") ? (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_SITE_UUID) : PS_SITE_UUID;
|
|
35
|
+
const refreshMs = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_ENVIRONMENT) === "sandbox" ? 15000 : 300000;
|
|
36
|
+
const common = { mode, egress: true, refreshMs } as const;
|
|
36
37
|
return createProtection(
|
|
37
38
|
siteUuid
|
|
38
39
|
? { ...common, siteUuid, rules: fallbackRules as never, cacheDir: ".patchstack" }
|
|
@@ -29,10 +29,11 @@ async function getProtection() {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
async function buildProtection() {
|
|
32
|
-
const mode = process.env.PATCHSTACK_MODE === "dry-run" ? "dry-run" : "block";
|
|
33
|
-
const token = process.env.PATCHSTACK_WAF_TOKEN;
|
|
34
|
-
const siteUuid = PS_SITE_UUID.startsWith("__") ? process.env.PATCHSTACK_SITE_UUID : PS_SITE_UUID;
|
|
35
|
-
const
|
|
32
|
+
const mode = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_MODE) === "dry-run" ? "dry-run" : "block";
|
|
33
|
+
const token = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_WAF_TOKEN);
|
|
34
|
+
const siteUuid = PS_SITE_UUID.startsWith("__") ? (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_SITE_UUID) : PS_SITE_UUID;
|
|
35
|
+
const refreshMs = (typeof process === "undefined" ? undefined : process.env.PATCHSTACK_ENVIRONMENT) === "sandbox" ? 15000 : 300000;
|
|
36
|
+
const common = { mode, egress: true, refreshMs } as const;
|
|
36
37
|
return createProtection(
|
|
37
38
|
siteUuid
|
|
38
39
|
? { ...common, siteUuid, rules: fallbackRules as never, cacheDir: ".patchstack" }
|
package/dist/protect.cjs
CHANGED
|
@@ -976,10 +976,13 @@ async function resolveConfig(options) {
|
|
|
976
976
|
"CONFIG_INVALID"
|
|
977
977
|
);
|
|
978
978
|
}
|
|
979
|
-
const inferred =
|
|
980
|
-
const
|
|
981
|
-
const
|
|
982
|
-
const
|
|
979
|
+
const inferred = fromEnv.environment === void 0 ? inferEnvironment(process.env, detectHostedBuilder(options.cwd)) : null;
|
|
980
|
+
const fileLabelOverruled = fromEnv.environment === void 0 && environmentRaw !== void 0 && environmentRaw !== "production" && inferred.environment === "production";
|
|
981
|
+
const labelled = fileLabelOverruled ? void 0 : environmentRaw;
|
|
982
|
+
const environment = labelled ?? inferred.environment;
|
|
983
|
+
const environmentEvidence = labelled === void 0 ? inferred.evidence : [];
|
|
984
|
+
const environmentSource = labelled !== void 0 ? "override" : inferred.source;
|
|
985
|
+
const ignoredFileEnvironment = fileLabelOverruled ? environmentRaw : null;
|
|
983
986
|
if (siteUuid !== null && siteUuid.length > 0 && !isCanonicalUuid(siteUuid)) {
|
|
984
987
|
throw new PatchstackError(
|
|
985
988
|
`Site UUID "${siteUuid}" does not look like a valid UUID.`,
|
|
@@ -1008,6 +1011,7 @@ async function resolveConfig(options) {
|
|
|
1008
1011
|
environment,
|
|
1009
1012
|
environmentEvidence,
|
|
1010
1013
|
environmentSource,
|
|
1014
|
+
ignoredFileEnvironment,
|
|
1011
1015
|
widget: fromFile.widget !== false,
|
|
1012
1016
|
claimToken
|
|
1013
1017
|
};
|
|
@@ -9360,10 +9364,10 @@ async function createProtection(options = {}) {
|
|
|
9360
9364
|
},
|
|
9361
9365
|
// Wrap a fetch handler: screens the request, then the response (redact/block).
|
|
9362
9366
|
fetch(handler) {
|
|
9363
|
-
return async (request, ...rest)
|
|
9367
|
+
return async function(request, ...rest) {
|
|
9364
9368
|
const { blocked, client } = await screenFetchRequest(request, rest);
|
|
9365
9369
|
if (blocked) return blocked;
|
|
9366
|
-
const response = await handler(request, ...rest);
|
|
9370
|
+
const response = await handler.call(this, request, ...rest);
|
|
9367
9371
|
return screenResp(response, reqContextFromFetch(request, client));
|
|
9368
9372
|
};
|
|
9369
9373
|
},
|