@patchstack/connect 0.3.13 → 0.3.14
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/dist/cli.js +28 -35
- package/dist/cli.js.map +1 -1
- package/dist/protect/templates/guard.ts +3 -9
- package/dist/protect.cjs +2 -82
- package/dist/protect.cjs.map +1 -1
- package/dist/protect.d.ts +0 -4
- package/dist/protect.js +2 -81
- package/dist/protect.js.map +1 -1
- package/package.json +1 -1
|
@@ -20,9 +20,6 @@ import {
|
|
|
20
20
|
} from "@patchstack/connect/protect";
|
|
21
21
|
import fallbackRules from "./rules.json";
|
|
22
22
|
|
|
23
|
-
// Baked by `patchstack-connect protect` from .patchstackrc.json (empty if the app isn't scanned yet).
|
|
24
|
-
const PS_SITE_UUID = "__PATCHSTACK_SITE_UUID__";
|
|
25
|
-
|
|
26
23
|
export { GUARD_PATH };
|
|
27
24
|
|
|
28
25
|
// One shared protection policy for both guards (rules load once).
|
|
@@ -32,7 +29,6 @@ async function getProtection() {
|
|
|
32
29
|
// Always-on: block by default. An explicit PATCHSTACK_MODE=dry-run downgrades to log-only.
|
|
33
30
|
const mode = process.env.PATCHSTACK_MODE === "dry-run" ? "dry-run" : "block";
|
|
34
31
|
const token = process.env.PATCHSTACK_WAF_TOKEN;
|
|
35
|
-
const siteUuid = PS_SITE_UUID.startsWith("__") ? process.env.PATCHSTACK_SITE_UUID : PS_SITE_UUID;
|
|
36
32
|
// Egress SSRF screening: block the app's outbound calls to internal / metadata addresses,
|
|
37
33
|
// but never its own Supabase project.
|
|
38
34
|
let allowHosts: string[] = [];
|
|
@@ -43,11 +39,9 @@ async function getProtection() {
|
|
|
43
39
|
}
|
|
44
40
|
const common = { mode, egress: true, allowHosts };
|
|
45
41
|
_protection = await createProtection(
|
|
46
|
-
|
|
47
|
-
? { ...common,
|
|
48
|
-
: token
|
|
49
|
-
? { ...common, token, cacheDir: ".patchstack" } // live per-site WAF rules from the Patchstack API (cached)
|
|
50
|
-
: { ...common, rules: fallbackRules as never }, // demo fallback until a site UUID / token is set
|
|
42
|
+
token
|
|
43
|
+
? { ...common, token, cacheDir: ".patchstack" } // live per-site rules from the Patchstack API (cached)
|
|
44
|
+
: { ...common, rules: fallbackRules as never }, // demo fallback until a token is set
|
|
51
45
|
);
|
|
52
46
|
}
|
|
53
47
|
return _protection;
|
package/dist/protect.cjs
CHANGED
|
@@ -21,7 +21,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var runtime_exports = {};
|
|
22
22
|
__export(runtime_exports, {
|
|
23
23
|
GUARD_PATH: () => GUARD_PATH,
|
|
24
|
-
PulseRuleClient: () => PulseRuleClient,
|
|
25
24
|
createProtection: () => createProtection,
|
|
26
25
|
createServerFnGuard: () => createServerFnGuard,
|
|
27
26
|
createSupabaseGuard: () => createSupabaseGuard
|
|
@@ -929,64 +928,6 @@ var RuleEngine = class {
|
|
|
929
928
|
}
|
|
930
929
|
};
|
|
931
930
|
|
|
932
|
-
// src/protect/engine/pulse-client.js
|
|
933
|
-
var DEFAULT_BASE_URL2 = "https://api.patchstack.com/monitor/pulse";
|
|
934
|
-
var DEFAULT_CACHE_TTL2 = 3e5;
|
|
935
|
-
var PulseRuleClient = class {
|
|
936
|
-
#siteUuid;
|
|
937
|
-
#baseUrl;
|
|
938
|
-
#cacheTtl;
|
|
939
|
-
#cache = null;
|
|
940
|
-
#cacheTime = null;
|
|
941
|
-
constructor({ siteUuid, baseUrl, cacheTtl } = {}) {
|
|
942
|
-
this.#siteUuid = siteUuid ?? process.env.PATCHSTACK_SITE_UUID;
|
|
943
|
-
this.#baseUrl = baseUrl ?? process.env.PATCHSTACK_PULSE_RULES_URL ?? DEFAULT_BASE_URL2;
|
|
944
|
-
this.#cacheTtl = cacheTtl ?? DEFAULT_CACHE_TTL2;
|
|
945
|
-
if (!this.#siteUuid) {
|
|
946
|
-
throw new Error("Patchstack site UUID is required. Pass { siteUuid } or set PATCHSTACK_SITE_UUID.");
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
async getRules() {
|
|
950
|
-
const now = Date.now();
|
|
951
|
-
if (this.#cache && this.#cacheTime && now - this.#cacheTime < this.#cacheTtl) {
|
|
952
|
-
return this.#cache;
|
|
953
|
-
}
|
|
954
|
-
const url = `${this.#baseUrl}/rules/${encodeURIComponent(this.#siteUuid)}`;
|
|
955
|
-
try {
|
|
956
|
-
const response = await fetch(url, {
|
|
957
|
-
method: "GET",
|
|
958
|
-
headers: { Accept: "application/json" },
|
|
959
|
-
signal: AbortSignal.timeout(3e4)
|
|
960
|
-
});
|
|
961
|
-
if (!response.ok) {
|
|
962
|
-
return { success: false, error: `API returned ${response.status}`, firewall: [], whitelists: [], whitelist_keys: {} };
|
|
963
|
-
}
|
|
964
|
-
const data = await response.json();
|
|
965
|
-
const result = {
|
|
966
|
-
success: true,
|
|
967
|
-
firewall: Array.isArray(data.firewall) ? data.firewall : [],
|
|
968
|
-
whitelists: Array.isArray(data.whitelists) ? data.whitelists : [],
|
|
969
|
-
whitelist_keys: data.whitelist_keys ?? {}
|
|
970
|
-
};
|
|
971
|
-
this.#cache = result;
|
|
972
|
-
this.#cacheTime = now;
|
|
973
|
-
return result;
|
|
974
|
-
} catch (err) {
|
|
975
|
-
return {
|
|
976
|
-
success: false,
|
|
977
|
-
error: err.name === "TimeoutError" ? "Request timed out" : err.message,
|
|
978
|
-
firewall: [],
|
|
979
|
-
whitelists: [],
|
|
980
|
-
whitelist_keys: {}
|
|
981
|
-
};
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
clearCache() {
|
|
985
|
-
this.#cache = null;
|
|
986
|
-
this.#cacheTime = null;
|
|
987
|
-
}
|
|
988
|
-
};
|
|
989
|
-
|
|
990
931
|
// src/protect/engine/fetch.js
|
|
991
932
|
async function fromFetchRequest(request) {
|
|
992
933
|
const url = new URL(request.url);
|
|
@@ -1609,25 +1550,8 @@ function leakResponse() {
|
|
|
1609
1550
|
});
|
|
1610
1551
|
}
|
|
1611
1552
|
async function resolveRules(options) {
|
|
1612
|
-
if (options.
|
|
1613
|
-
|
|
1614
|
-
const res = await client.getRules();
|
|
1615
|
-
if (res.success) {
|
|
1616
|
-
const bundle = normalizeBundle(res);
|
|
1617
|
-
cacheWrite(options.cacheDir, bundle);
|
|
1618
|
-
return bundle;
|
|
1619
|
-
}
|
|
1620
|
-
const cached = cacheRead(options.cacheDir);
|
|
1621
|
-
if (cached) {
|
|
1622
|
-
options.onError?.(new Error(`pulse rule fetch failed (${res.error}); using cached bundle`));
|
|
1623
|
-
return normalizeBundle(cached);
|
|
1624
|
-
}
|
|
1625
|
-
if (options.rules) {
|
|
1626
|
-
options.onError?.(new Error(`pulse rule fetch failed (${res.error}); using bundled fallback`));
|
|
1627
|
-
return normalizeBundle(options.rules);
|
|
1628
|
-
}
|
|
1629
|
-
options.onError?.(new Error(`pulse rule fetch failed (${res.error}); no cache \u2014 running with no rules`));
|
|
1630
|
-
return emptyBundle();
|
|
1553
|
+
if (options.rules) {
|
|
1554
|
+
return normalizeBundle(options.rules);
|
|
1631
1555
|
}
|
|
1632
1556
|
if (options.token) {
|
|
1633
1557
|
const client = new PatchstackRuleClient({ token: options.token, baseUrl: options.baseUrl });
|
|
@@ -1645,9 +1569,6 @@ async function resolveRules(options) {
|
|
|
1645
1569
|
options.onError?.(new Error(`rule fetch failed (${res.error}); no cache \u2014 running with no rules`));
|
|
1646
1570
|
return emptyBundle();
|
|
1647
1571
|
}
|
|
1648
|
-
if (options.rules) {
|
|
1649
|
-
return normalizeBundle(options.rules);
|
|
1650
|
-
}
|
|
1651
1572
|
return emptyBundle();
|
|
1652
1573
|
}
|
|
1653
1574
|
function normalizeBundle(b) {
|
|
@@ -1699,7 +1620,6 @@ function defaultOnDetect({ phase, mode, category, rule, message }) {
|
|
|
1699
1620
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1700
1621
|
0 && (module.exports = {
|
|
1701
1622
|
GUARD_PATH,
|
|
1702
|
-
PulseRuleClient,
|
|
1703
1623
|
createProtection,
|
|
1704
1624
|
createServerFnGuard,
|
|
1705
1625
|
createSupabaseGuard
|