x402-surface-check 0.2.3 → 0.2.4
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 -0
- package/bin/x402-surface-check.mjs +23 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ npx --yes x402-surface-check --endpoint --method POST https://x402.rpc.ankr.com/
|
|
|
24
24
|
- HTTPS resource URLs and stable resource metadata
|
|
25
25
|
- Browser CORS allowance for `X-PAYMENT`
|
|
26
26
|
- Over-broad public method surfaces
|
|
27
|
+
- Auth, validation, and free/trial responses that appear before a payment challenge, without piling on missing-field findings when no challenge was actually returned
|
|
27
28
|
|
|
28
29
|
## Options
|
|
29
30
|
|
|
@@ -373,6 +373,11 @@ function challengeAccepts(result) {
|
|
|
373
373
|
return Array.isArray(result.body.json?.accepts) ? result.body.json.accepts : []
|
|
374
374
|
}
|
|
375
375
|
|
|
376
|
+
function hasPaymentChallenge(result) {
|
|
377
|
+
const challenge = result.body.json
|
|
378
|
+
return challengeAccepts(result).length > 0 || Boolean(challenge?.resource || challenge?.payment || result.headers?.['www-authenticate'])
|
|
379
|
+
}
|
|
380
|
+
|
|
376
381
|
function challengeSummary(result) {
|
|
377
382
|
const challenge = result.body.json
|
|
378
383
|
const firstAccept = challenge?.accepts?.[0] ?? {}
|
|
@@ -427,10 +432,27 @@ function findingList(documentResult, challengeResults, preflightResults, entries
|
|
|
427
432
|
for (const result of challengeResults) {
|
|
428
433
|
const summary = challengeSummary(result)
|
|
429
434
|
if (summary.network) challengeNetworks.add(summary.network)
|
|
435
|
+
const hasChallenge = hasPaymentChallenge(result)
|
|
430
436
|
|
|
431
437
|
if (result.status !== 402) {
|
|
432
|
-
|
|
438
|
+
if (result.status >= 200 && result.status < 300) {
|
|
439
|
+
findings.push(`P3 - ${result.name} returned ${result.status} without a payment challenge for a no-payment ${result.method ?? 'POST'} probe; document this as free/trial access or move the 402 challenge before content.`)
|
|
440
|
+
}
|
|
441
|
+
else if (result.status === 400 || result.status === 422) {
|
|
442
|
+
findings.push(`P1 - ${result.name} returned validation HTTP ${result.status} before a payment challenge for a no-payment ${result.method ?? 'POST'} probe.`)
|
|
443
|
+
}
|
|
444
|
+
else if (result.status === 401 || result.status === 403) {
|
|
445
|
+
findings.push(`P2 - ${result.name} returned auth HTTP ${result.status} before a payment challenge for a no-payment ${result.method ?? 'POST'} probe; document the auth/free-tier order if this is intentional.`)
|
|
446
|
+
}
|
|
447
|
+
else {
|
|
448
|
+
findings.push(`P1 - ${result.name} returned ${result.status}, not 402, for a no-payment ${result.method ?? 'POST'} probe.`)
|
|
449
|
+
}
|
|
433
450
|
}
|
|
451
|
+
|
|
452
|
+
if (!hasChallenge) {
|
|
453
|
+
continue
|
|
454
|
+
}
|
|
455
|
+
|
|
434
456
|
if (summary.resourceUrl.startsWith('http://') || summary.extraResource.startsWith('http://')) {
|
|
435
457
|
findings.push(`P1 - ${result.name} challenge uses a non-HTTPS resource URL: ${summary.resourceUrl || summary.extraResource}.`)
|
|
436
458
|
}
|