@patchstack/connect 0.5.5 → 0.5.7
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 +1 -1
- package/README.md +1 -0
- package/dist/chunk-2K5SHFUM.js +295 -0
- package/dist/chunk-2K5SHFUM.js.map +1 -0
- package/dist/cli.js +1026 -481
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +368 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -3
- package/dist/index.d.ts +23 -3
- package/dist/index.js +380 -39
- package/dist/index.js.map +1 -1
- package/dist/protect/templates/demo-rules.json +1 -1
- package/dist/protect.cjs +1135 -241
- package/dist/protect.cjs.map +1 -1
- package/dist/protect.d.cts +7 -2
- package/dist/protect.d.ts +7 -2
- package/dist/protect.edge.js +988 -179
- package/dist/protect.edge.js.map +3 -3
- package/dist/protect.js +842 -192
- package/dist/protect.js.map +1 -1
- package/dist/{refresh-manifest-2ALIJGZ3.js → refresh-manifest-3YWIYENU.js} +82 -39
- package/dist/refresh-manifest-3YWIYENU.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-IOODP4ZB.js +0 -104
- package/dist/chunk-IOODP4ZB.js.map +0 -1
- package/dist/refresh-manifest-2ALIJGZ3.js.map +0 -1
package/AGENT-INSTALL.md
CHANGED
|
@@ -120,7 +120,7 @@ This is a request, not a mechanism: nothing in the install depends on it. Do it
|
|
|
120
120
|
|
|
121
121
|
**Bun-managed projects:** `bun run` does not execute npm-style `pre`/`post` scripts, so wire the build script directly instead: `"build": "patchstack-connect scan && <existing build command> && patchstack-connect mark-build"`.
|
|
122
122
|
|
|
123
|
-
3. **Verify the disclosure widget** — a floating "Report a vulnerability" button. `scan` installs it automatically into a plain HTML shell, and `mark-build` carries it into built HTML. Only when `scan` reported that it found no editable shell
|
|
123
|
+
3. **Verify the disclosure widget** — a floating "Report a vulnerability" button. `scan` installs it automatically into a plain HTML shell **or a JSX root** (Next, Remix, React Router, TanStack Start, Gatsby), and `mark-build` carries it into built HTML. Only when `scan` reported that it found no editable shell at all — a root whose head mechanism is not a plain script tag, e.g. Nuxt's `useHead` or an Astro layout — add the one-liner it printed to the root layout yourself, just before `</body>` (never a JS entry point), reading `siteUuid` from `.patchstackrc.json`. On those same roots the widget also needs the production marker above the tag — `scan` adds it automatically to a JSX root, and prints it to paste when it finds no anchor. A server-rendered site without the marker serves the build-mode claim flow to its visitors:
|
|
124
124
|
|
|
125
125
|
```html
|
|
126
126
|
<script src="https://cdn.patchstack.com/patchstack-widget.js" data-site-uuid="<SITE_UUID>" defer></script>
|
package/README.md
CHANGED
|
@@ -306,6 +306,7 @@ The widget is a floating "Report a vulnerability" button — a disclosure channe
|
|
|
306
306
|
<script src="https://cdn.patchstack.com/patchstack-widget.js" data-site-uuid="<SITE_UUID>" defer data-patchstack-connect-widget="true"></script>
|
|
307
307
|
```
|
|
308
308
|
|
|
309
|
+
- **`scan`** installs the widget tag into a plain HTML shell, and — where there is none — into a JSX root (`src/routes/__root.tsx`, `app/layout.tsx`, …), just before `</body>`. The same tag serves both: JSX reads `defer` as a boolean attribute and passes `data-*` through. A server-rendered app has no HTML shell at all, so without this its published site carries no widget and Patchstack never hears from the live page.
|
|
309
310
|
- **`scan`** also adds the production marker when the root shell is JSX rather than HTML (`src/routes/__root.tsx`, `app/layout.tsx`, …), above the widget tag and guarded by the framework's production expression. A server-rendered app emits no built HTML for `mark-build` to stamp, so without it the widget reads the published site as build mode and shows the claim flow to visitors instead of the report form.
|
|
310
311
|
|
|
311
312
|
Re-runs update the tag in place (the `data-patchstack-connect-widget` attribute marks it as connector-managed); a pre-existing manual widget tag is left untouched. `--dry-run` never edits anything; a failed post still skips the widget tag (it needs the site UUID) but the production marker may already have been written, since it runs before the post. Projects whose root layout is code rather than HTML (Next.js, Nuxt, Astro, …) get the exact snippet and target file printed instead — `guide` shows framework-specific placement.
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
// src/protect/safe-origin.js
|
|
2
|
+
function isSafeOrigin(value) {
|
|
3
|
+
try {
|
|
4
|
+
const u = new URL(value);
|
|
5
|
+
if (u.protocol === "https:") return true;
|
|
6
|
+
return u.protocol === "http:" && (u.hostname === "localhost" || u.hostname === "127.0.0.1" || u.hostname === "[::1]" || u.hostname === "::1");
|
|
7
|
+
} catch {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function safeBaseUrl(candidate, fallback, label) {
|
|
12
|
+
if (typeof candidate !== "string" || candidate === "") return fallback;
|
|
13
|
+
if (isSafeOrigin(candidate)) return candidate;
|
|
14
|
+
warnOnce(label, `[patchstack] ignoring unsafe ${label} override (${candidate}): must be https (or localhost). Using the default.`);
|
|
15
|
+
return fallback;
|
|
16
|
+
}
|
|
17
|
+
var warned = /* @__PURE__ */ new Set();
|
|
18
|
+
function warnOnce(key, message) {
|
|
19
|
+
if (warned.has(key)) return;
|
|
20
|
+
warned.add(key);
|
|
21
|
+
console.warn(message);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/types.ts
|
|
25
|
+
var PatchstackError = class extends Error {
|
|
26
|
+
constructor(message, code, cause) {
|
|
27
|
+
super(message);
|
|
28
|
+
this.code = code;
|
|
29
|
+
this.cause = cause;
|
|
30
|
+
this.name = "PatchstackError";
|
|
31
|
+
}
|
|
32
|
+
code;
|
|
33
|
+
cause;
|
|
34
|
+
/**
|
|
35
|
+
* For a `VALIDATION_ERROR`, the request fields the server refused, as it named them. Read from the
|
|
36
|
+
* structured `errors` object a validation response carries, so a caller deciding what to do about a
|
|
37
|
+
* refusal keys on the field rather than on the wording of a sentence.
|
|
38
|
+
*/
|
|
39
|
+
fields = [];
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// src/endpoint-policy.ts
|
|
43
|
+
function assertConnectableEndpoint(config, target = config.endpoint) {
|
|
44
|
+
if (config.endpointTrusted === false) {
|
|
45
|
+
throw new PatchstackError(
|
|
46
|
+
"The custom endpoint in .patchstackrc.json must be confirmed with --endpoint or PATCHSTACK_ENDPOINT before it can be used.",
|
|
47
|
+
"CONFIG_INVALID"
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
if (safeRemoteUrl(config.endpoint) === null) {
|
|
51
|
+
throw new PatchstackError(
|
|
52
|
+
"Patchstack endpoints must use HTTPS, except for localhost development endpoints.",
|
|
53
|
+
"CONFIG_INVALID"
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
let endpointOrigin;
|
|
57
|
+
let targetOrigin;
|
|
58
|
+
try {
|
|
59
|
+
endpointOrigin = new URL(config.endpoint).origin;
|
|
60
|
+
targetOrigin = new URL(target).origin;
|
|
61
|
+
} catch (cause) {
|
|
62
|
+
throw new PatchstackError("The configured Patchstack endpoint is not a valid URL.", "CONFIG_INVALID", cause);
|
|
63
|
+
}
|
|
64
|
+
if (safeRemoteUrl(target) === null || targetOrigin !== endpointOrigin) {
|
|
65
|
+
throw new PatchstackError(
|
|
66
|
+
"A Patchstack request resolved outside the configured endpoint origin.",
|
|
67
|
+
"CONFIG_INVALID"
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function safeRemoteUrl(value) {
|
|
72
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 2048) return null;
|
|
73
|
+
try {
|
|
74
|
+
const parsed = new URL(value);
|
|
75
|
+
if (!isSafeOrigin(parsed.toString()) || parsed.username !== "" || parsed.password !== "") return null;
|
|
76
|
+
return parsed.toString();
|
|
77
|
+
} catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function safeDisplayString(value, maxLength = 512) {
|
|
82
|
+
if (typeof value !== "string") return null;
|
|
83
|
+
const clean = value.replace(/\u001b(?:\[[0-?]*[ -/]*[@-~]|\][^\u0007]*(?:\u0007|\u001b\\))/g, "").replace(/[\u0000-\u001f\u007f-\u009f]/g, " ").replace(/\s+/g, " ").trim();
|
|
84
|
+
if (clean.length === 0) return null;
|
|
85
|
+
return clean.slice(0, maxLength);
|
|
86
|
+
}
|
|
87
|
+
function isCanonicalUuid(value) {
|
|
88
|
+
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
89
|
+
}
|
|
90
|
+
function isCredential(value) {
|
|
91
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 4096) return false;
|
|
92
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
93
|
+
const code = value.charCodeAt(i);
|
|
94
|
+
if (code < 33 || code > 126) return false;
|
|
95
|
+
}
|
|
96
|
+
const separator = value.lastIndexOf("-");
|
|
97
|
+
return separator > 0 && separator < value.length - 1 && /^\d+$/.test(value.slice(separator + 1));
|
|
98
|
+
}
|
|
99
|
+
function isHeaderValue(value, maxLength = 8192) {
|
|
100
|
+
if (typeof value !== "string" || value.length === 0 || value.length > maxLength) return false;
|
|
101
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
102
|
+
const code = value.charCodeAt(i);
|
|
103
|
+
if (code < 33 || code > 126) return false;
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/bounded-response.ts
|
|
109
|
+
var MAX_CONTROL_RESPONSE_BYTES = 256 * 1024;
|
|
110
|
+
async function readBoundedText(response, maxBytes = MAX_CONTROL_RESPONSE_BYTES) {
|
|
111
|
+
const stated = Number(response.headers?.get?.("content-length"));
|
|
112
|
+
if (Number.isFinite(stated) && stated > maxBytes) {
|
|
113
|
+
void response.body?.cancel().catch(() => {
|
|
114
|
+
});
|
|
115
|
+
throw new Error(`response exceeds ${maxBytes} bytes`);
|
|
116
|
+
}
|
|
117
|
+
const stream = response.body;
|
|
118
|
+
if (stream === null || typeof stream.getReader !== "function") {
|
|
119
|
+
if (stated === 0) return "";
|
|
120
|
+
throw new Error("response body cannot be read with a size bound");
|
|
121
|
+
}
|
|
122
|
+
const reader = stream.getReader();
|
|
123
|
+
const chunks = [];
|
|
124
|
+
let total = 0;
|
|
125
|
+
try {
|
|
126
|
+
for (; ; ) {
|
|
127
|
+
const { done, value } = await reader.read();
|
|
128
|
+
if (done) break;
|
|
129
|
+
total += value.byteLength;
|
|
130
|
+
if (total > maxBytes) {
|
|
131
|
+
void reader.cancel().catch(() => {
|
|
132
|
+
});
|
|
133
|
+
throw new Error(`response exceeds ${maxBytes} bytes`);
|
|
134
|
+
}
|
|
135
|
+
chunks.push(value);
|
|
136
|
+
}
|
|
137
|
+
} finally {
|
|
138
|
+
reader.releaseLock();
|
|
139
|
+
}
|
|
140
|
+
const bytes = new Uint8Array(total);
|
|
141
|
+
let offset = 0;
|
|
142
|
+
for (const chunk of chunks) {
|
|
143
|
+
bytes.set(chunk, offset);
|
|
144
|
+
offset += chunk.byteLength;
|
|
145
|
+
}
|
|
146
|
+
return new TextDecoder().decode(bytes);
|
|
147
|
+
}
|
|
148
|
+
async function readBoundedJson(response, maxBytes = MAX_CONTROL_RESPONSE_BYTES) {
|
|
149
|
+
const text = await readBoundedText(response, maxBytes);
|
|
150
|
+
return JSON.parse(text);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/pulse-token.ts
|
|
154
|
+
var TOKEN_SKEW_MS = 6e4;
|
|
155
|
+
function buildTokenUrl(manifestEndpoint) {
|
|
156
|
+
const url = new URL(manifestEndpoint);
|
|
157
|
+
const path = url.pathname.replace(/\/$/, "");
|
|
158
|
+
url.pathname = path.endsWith("/manifest") ? `${path.slice(0, -"/manifest".length)}/token` : "/monitor/pulse/token";
|
|
159
|
+
url.search = "";
|
|
160
|
+
url.hash = "";
|
|
161
|
+
return url.toString();
|
|
162
|
+
}
|
|
163
|
+
function parsePulseAuth(credential) {
|
|
164
|
+
const index = credential.lastIndexOf("-");
|
|
165
|
+
if (index <= 0 || index === credential.length - 1) return null;
|
|
166
|
+
const clientId = credential.slice(index + 1);
|
|
167
|
+
if (!/^\d+$/.test(clientId)) return null;
|
|
168
|
+
return { clientId, clientSecret: credential.slice(0, index) };
|
|
169
|
+
}
|
|
170
|
+
var cached = /* @__PURE__ */ new Map();
|
|
171
|
+
var inflight = /* @__PURE__ */ new Map();
|
|
172
|
+
function cacheKey(tokenUrl, credential) {
|
|
173
|
+
return `${tokenUrl}
|
|
174
|
+
${credential}`;
|
|
175
|
+
}
|
|
176
|
+
function clearPulseToken(config) {
|
|
177
|
+
if (!config || typeof config.pulseAuth !== "string") {
|
|
178
|
+
cached.clear();
|
|
179
|
+
inflight.clear();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
const key = cacheKey(buildTokenUrl(config.endpoint), config.pulseAuth);
|
|
184
|
+
cached.delete(key);
|
|
185
|
+
inflight.delete(key);
|
|
186
|
+
} catch {
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async function getPulseToken(config, fetchImpl = fetch) {
|
|
190
|
+
if (typeof config.pulseAuth !== "string" || config.pulseAuth.length === 0) return null;
|
|
191
|
+
if (config.endpointTrusted === false) return null;
|
|
192
|
+
let tokenUrl;
|
|
193
|
+
try {
|
|
194
|
+
tokenUrl = buildTokenUrl(config.endpoint);
|
|
195
|
+
} catch {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
if (!isSafeOrigin(tokenUrl)) return null;
|
|
199
|
+
const key = cacheKey(tokenUrl, config.pulseAuth);
|
|
200
|
+
const existing = cached.get(key);
|
|
201
|
+
if (existing !== void 0 && Date.now() < existing.expiresAt - TOKEN_SKEW_MS) {
|
|
202
|
+
return existing.token;
|
|
203
|
+
}
|
|
204
|
+
const pending = inflight.get(key);
|
|
205
|
+
if (pending !== void 0) return pending;
|
|
206
|
+
const credentials = parsePulseAuth(config.pulseAuth);
|
|
207
|
+
if (credentials === null) return null;
|
|
208
|
+
let exchange;
|
|
209
|
+
exchange = (async () => {
|
|
210
|
+
try {
|
|
211
|
+
const response = await fetchImpl(tokenUrl, {
|
|
212
|
+
method: "POST",
|
|
213
|
+
headers: {
|
|
214
|
+
"Content-Type": "application/json",
|
|
215
|
+
Accept: "application/json",
|
|
216
|
+
"User-Agent": "@patchstack/connect"
|
|
217
|
+
},
|
|
218
|
+
body: JSON.stringify({
|
|
219
|
+
grant_type: "client_credentials",
|
|
220
|
+
client_id: credentials.clientId,
|
|
221
|
+
client_secret: credentials.clientSecret
|
|
222
|
+
}),
|
|
223
|
+
signal: AbortSignal.timeout(config.timeoutMs)
|
|
224
|
+
});
|
|
225
|
+
if (!response.ok) return null;
|
|
226
|
+
const body = await readBoundedJson(response);
|
|
227
|
+
if (!isHeaderValue(body.access_token)) return null;
|
|
228
|
+
const expiresIn = Number(body.expires_in);
|
|
229
|
+
const ttlMs = Number.isFinite(expiresIn) && expiresIn > 0 ? expiresIn * 1e3 : 36e5;
|
|
230
|
+
cached.set(key, { token: body.access_token, expiresAt: Date.now() + ttlMs });
|
|
231
|
+
return body.access_token;
|
|
232
|
+
} catch {
|
|
233
|
+
return null;
|
|
234
|
+
} finally {
|
|
235
|
+
if (inflight.get(key) === exchange) inflight.delete(key);
|
|
236
|
+
}
|
|
237
|
+
})();
|
|
238
|
+
inflight.set(key, exchange);
|
|
239
|
+
return exchange;
|
|
240
|
+
}
|
|
241
|
+
async function pulseAuthHeader(config, fetchImpl = fetch) {
|
|
242
|
+
const token = await getPulseToken(config, fetchImpl);
|
|
243
|
+
return token === null ? {} : { Authorization: `Bearer ${token}` };
|
|
244
|
+
}
|
|
245
|
+
async function pulseFetch(config, url, init, fetchImpl = fetch) {
|
|
246
|
+
assertConnectableEndpoint(config, url);
|
|
247
|
+
const send = async () => {
|
|
248
|
+
const auth = await pulseAuthHeader(config, fetchImpl);
|
|
249
|
+
const response = await fetchImpl(url, {
|
|
250
|
+
...init,
|
|
251
|
+
headers: { ...init.headers, ...auth }
|
|
252
|
+
});
|
|
253
|
+
return { response, authenticated: auth.Authorization !== void 0 };
|
|
254
|
+
};
|
|
255
|
+
const first = await send();
|
|
256
|
+
if (first.response.status === 401 && first.authenticated) {
|
|
257
|
+
clearPulseToken(config);
|
|
258
|
+
return (await send()).response;
|
|
259
|
+
}
|
|
260
|
+
return first.response;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// src/build-id.ts
|
|
264
|
+
var BUILD_ID = /^[0-9a-f]{64}$/i;
|
|
265
|
+
function canonicalBuildId(value) {
|
|
266
|
+
if (typeof value !== "string") return null;
|
|
267
|
+
const trimmed = value.trim();
|
|
268
|
+
return BUILD_ID.test(trimmed) ? trimmed.toLowerCase() : null;
|
|
269
|
+
}
|
|
270
|
+
var BUILD_STAMP_KEY = "_patchstack";
|
|
271
|
+
function readBuildStamp(bundle) {
|
|
272
|
+
if (bundle === null || typeof bundle !== "object") return null;
|
|
273
|
+
const namespace = bundle[BUILD_STAMP_KEY];
|
|
274
|
+
if (namespace === null || typeof namespace !== "object") return null;
|
|
275
|
+
return canonicalBuildId(namespace.build_id);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export {
|
|
279
|
+
isSafeOrigin,
|
|
280
|
+
safeBaseUrl,
|
|
281
|
+
PatchstackError,
|
|
282
|
+
assertConnectableEndpoint,
|
|
283
|
+
safeRemoteUrl,
|
|
284
|
+
safeDisplayString,
|
|
285
|
+
isCanonicalUuid,
|
|
286
|
+
isCredential,
|
|
287
|
+
isHeaderValue,
|
|
288
|
+
readBoundedText,
|
|
289
|
+
readBoundedJson,
|
|
290
|
+
pulseAuthHeader,
|
|
291
|
+
pulseFetch,
|
|
292
|
+
canonicalBuildId,
|
|
293
|
+
readBuildStamp
|
|
294
|
+
};
|
|
295
|
+
//# sourceMappingURL=chunk-2K5SHFUM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/protect/safe-origin.js","../src/types.ts","../src/endpoint-policy.ts","../src/bounded-response.ts","../src/pulse-token.ts","../src/build-id.ts"],"mappings":"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","names":[]}
|