@insumermodel/mppx-condition-gate 2.0.2 → 3.0.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 +34 -6
- package/dist/index.d.ts +62 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +113 -74
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/index.ts +151 -66
package/README.md
CHANGED
|
@@ -6,16 +6,23 @@ Condition-based access for [mppx](https://github.com/wevm/mppx) routes. One sign
|
|
|
6
6
|
|
|
7
7
|
## How it works
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Free access requires a payer your payment method has **proven** controls the request. You supply that payer through `provenPayer`; the gate never infers one.
|
|
10
10
|
|
|
11
11
|
1. Request arrives with a payment credential
|
|
12
|
-
2.
|
|
13
|
-
3.
|
|
14
|
-
4.
|
|
15
|
-
5. **
|
|
12
|
+
2. The gate calls the method's non-mutating `validate` hook
|
|
13
|
+
3. Your `provenPayer` resolver receives mppx's method-specific validation `details` and returns the proven payer, or `null`
|
|
14
|
+
4. [InsumerAPI](https://insumermodel.com/developers/api-reference/) evaluates the conditions for that payer and returns an ECDSA P-256 signed attestation
|
|
15
|
+
5. **Pass** → free receipt returned (`reference: "condition-gate:free:{attestationId}"`)
|
|
16
|
+
6. **Fail, or no proven payer** → the normal paid path runs
|
|
16
17
|
|
|
17
18
|
The signed attestation is verifiable offline via [JWKS](https://insumermodel.com/.well-known/jwks.json). The adapter does not re-sign or wrap the result; the signature on the attestation is the one InsumerAPI produced.
|
|
18
19
|
|
|
20
|
+
### Why you must supply the payer
|
|
21
|
+
|
|
22
|
+
mppx credentials carry an optional `source` DID, but mppx documents it as *"an asserted identity, not independent proof of control"* — it is a claim by the caller, not a proof. Versions before 3.0.0 granted free access on it, which let anyone name a qualifying wallet and skip payment ([GHSA-jg6q-3qfh-r9f8](https://github.com/douglasborthwick-crypto/mppx-condition-gate/security/advisories/GHSA-jg6q-3qfh-r9f8)). The gate now refuses to guess.
|
|
23
|
+
|
|
24
|
+
`provenPayer` receives **only** the validation `details` — never the credential and never `source` — so the unproven identity is not reachable from it. Return a payer only if the payment method has actually established control of it. **Every path that cannot justify free access falls through to payment:** no resolver, no `validate` hook on the method, a resolver returning `null` or throwing, a credential that fails validation, conditions not met, or an attestation error.
|
|
25
|
+
|
|
19
26
|
## Install
|
|
20
27
|
|
|
21
28
|
```bash
|
|
@@ -35,6 +42,9 @@ const tempoCharge = tempo({
|
|
|
35
42
|
|
|
36
43
|
const gatedCharge = conditionGate(tempoCharge, {
|
|
37
44
|
apiKey: process.env.INSUMER_API_KEY,
|
|
45
|
+
// Return only a payer this method has PROVEN for this request, else null.
|
|
46
|
+
// The argument is mppx's method-specific validation `details`.
|
|
47
|
+
provenPayer: (details) => (details as { payer?: string }).payer ?? null,
|
|
38
48
|
conditions: [{
|
|
39
49
|
type: 'nft_ownership',
|
|
40
50
|
contractAddress: '0xYourNFT',
|
|
@@ -176,7 +186,7 @@ Either way, set `INSUMER_API_KEY` as an environment variable in your runtime.
|
|
|
176
186
|
|
|
177
187
|
## Supported chains
|
|
178
188
|
|
|
179
|
-
|
|
189
|
+
32 EVM chains (Ethereum, Base, Polygon, Arbitrum, Optimism, BNB, Avalanche, Robinhood Chain, and 24 more) + Solana + XRPL + Bitcoin — the 35 chains this adapter's wallet handling reaches. The engine itself covers 38 (adding Tron, Stellar, and Sui via InsumerAPI directly). EAS conditions evaluate on EVM chains only. Farcaster always on Optimism.
|
|
180
190
|
|
|
181
191
|
[Full chain list](https://insumermodel.com/developers/api-reference/)
|
|
182
192
|
|
|
@@ -222,6 +232,24 @@ The condition shapes for `token_balance` and `nft_ownership` are unchanged. `eas
|
|
|
222
232
|
|
|
223
233
|
The `parsXrplDid` typo from v1 is fixed: use `parseXrplDid`. The cache helper renamed: `clearTokenGateCache` is now `clearConditionGateCache`.
|
|
224
234
|
|
|
235
|
+
## Migrating from 2.x (security release)
|
|
236
|
+
|
|
237
|
+
3.0.0 fixes an authentication bypass ([GHSA-jg6q-3qfh-r9f8](https://github.com/douglasborthwick-crypto/mppx-condition-gate/security/advisories/GHSA-jg6q-3qfh-r9f8)). All 2.x versions, and all versions of the predecessor `@insumermodel/mppx-token-gate`, are affected.
|
|
238
|
+
|
|
239
|
+
Add a `provenPayer` resolver:
|
|
240
|
+
|
|
241
|
+
```diff
|
|
242
|
+
const gated = conditionGate(server, {
|
|
243
|
+
apiKey: process.env.INSUMER_API_KEY,
|
|
244
|
+
+ provenPayer: (details) => (details as { payer?: string }).payer ?? null,
|
|
245
|
+
conditions: [ ... ],
|
|
246
|
+
})
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Without it the gate compiles and runs, but never grants free access — every request takes the paid path. That is deliberate: the insecure default is gone, and the safe default is to charge.
|
|
250
|
+
|
|
251
|
+
Your method must expose mppx's `validate` hook. Legacy `verify`-only methods have no non-mutating pre-check, so they are never gated.
|
|
252
|
+
|
|
225
253
|
## License
|
|
226
254
|
|
|
227
255
|
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -77,9 +77,42 @@ export type RatioToSupplyCondition = {
|
|
|
77
77
|
};
|
|
78
78
|
/** Any condition accepted by /v1/attest */
|
|
79
79
|
export type Condition = TokenBalanceCondition | NftOwnershipCondition | EasAttestationCondition | FarcasterIdCondition | RatioToAmountCondition | RatioToSupplyCondition;
|
|
80
|
+
/** Wallet family for a proven payer. */
|
|
81
|
+
export type WalletType = 'evm' | 'solana' | 'xrpl' | 'bitcoin';
|
|
82
|
+
/**
|
|
83
|
+
* A payer the caller has cryptographically proven for this request.
|
|
84
|
+
*
|
|
85
|
+
* Accepts a `did:pkh:...` string, a bare `0x` EVM address, or an explicit
|
|
86
|
+
* `{ address, type }` pair. Bare non-EVM addresses are rejected because their
|
|
87
|
+
* wallet family cannot be inferred unambiguously — pass the object form.
|
|
88
|
+
*/
|
|
89
|
+
export type ProvenPayer = string | {
|
|
90
|
+
address: string;
|
|
91
|
+
type: WalletType;
|
|
92
|
+
} | null | undefined;
|
|
80
93
|
export type ConditionGateOptions = {
|
|
81
94
|
/** InsumerAPI key. Falls back to INSUMER_API_KEY env var. */
|
|
82
95
|
apiKey?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Resolves the payer that the payment method has PROVEN controls this
|
|
98
|
+
* request. Required for free access — without it every request takes the
|
|
99
|
+
* paid path.
|
|
100
|
+
*
|
|
101
|
+
* It receives only mppx's method-specific validation `details` (for example
|
|
102
|
+
* a recovered payer address). It is deliberately NOT given the credential or
|
|
103
|
+
* the declared `source`: mppx documents `source` as "an asserted identity,
|
|
104
|
+
* not independent proof of control", and granting on it is the vulnerability
|
|
105
|
+
* fixed in 3.0.0 (GHSA-jg6q-3qfh-r9f8).
|
|
106
|
+
*
|
|
107
|
+
* Return `null` when no payer has been proven. Returning an address you have
|
|
108
|
+
* not proven reintroduces that vulnerability.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* provenPayer: (details) => (details as { payer?: string }).payer ?? null
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
provenPayer?: (details: unknown) => ProvenPayer | Promise<ProvenPayer>;
|
|
83
116
|
/** One or more conditions to evaluate. Mix any of the six types. */
|
|
84
117
|
conditions: Condition[];
|
|
85
118
|
/** Whether the wallet must satisfy "any" (default) or "all" conditions. */
|
|
@@ -142,18 +175,37 @@ export declare function parseSolanaDid(source: string): string | null;
|
|
|
142
175
|
export declare function parseXrplDid(source: string): string | null;
|
|
143
176
|
/** Extracts a Bitcoin address from a `did:pkh:bip122:{chainId}:{address}` string. */
|
|
144
177
|
export declare function parseBitcoinDid(source: string): string | null;
|
|
178
|
+
/**
|
|
179
|
+
* Normalizes a caller-supplied proven payer into an address + wallet family.
|
|
180
|
+
*
|
|
181
|
+
* Fail-closed: anything it cannot resolve unambiguously returns null, which
|
|
182
|
+
* sends the request to the paid path.
|
|
183
|
+
*/
|
|
184
|
+
export declare function normalizeProvenPayer(payer: ProvenPayer): {
|
|
185
|
+
address: string;
|
|
186
|
+
type: WalletType;
|
|
187
|
+
} | null;
|
|
145
188
|
/**
|
|
146
189
|
* Wraps an mppx Method.Server with condition-based access using signed attestations.
|
|
147
190
|
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
191
|
+
* Free access requires a PROVEN payer. The gate calls the method's non-mutating
|
|
192
|
+
* `validate` hook, hands the resulting method-specific `details` to your
|
|
193
|
+
* `provenPayer` resolver, and only then evaluates conditions. It never reads
|
|
194
|
+
* `credential.source` — mppx documents that field as an asserted identity
|
|
195
|
+
* rather than proof of control.
|
|
196
|
+
*
|
|
197
|
+
* The gate falls through to the paid path whenever free access cannot be
|
|
198
|
+
* justified: no `provenPayer` resolver, no `validate` hook on the method
|
|
199
|
+
* (legacy `verify`-only methods included), a resolver returning null, a
|
|
200
|
+
* credential that fails validation, conditions not met, or an attestation
|
|
201
|
+
* error. There is no path from an unproven wallet to a free receipt.
|
|
152
202
|
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
203
|
+
* Conditions are evaluated across the 35 chains this adapter reaches (32 EVM +
|
|
204
|
+
* Solana + XRPL + Bitcoin; the engine itself covers 38). Six condition types
|
|
205
|
+
* are typed here: token_balance, nft_ownership, eas_attestation, farcaster_id,
|
|
206
|
+
* ratio_to_amount, and ratio_to_supply. InsumerAPI also offers evm_view_call,
|
|
207
|
+
* erc8004_agent, and erc7710_delegation; those are not typed or normalized
|
|
208
|
+
* here, so call /v1/attest directly if you need them.
|
|
157
209
|
*
|
|
158
210
|
* The attestation is ECDSA P-256 signed and verifiable offline via the public
|
|
159
211
|
* JWKS at https://insumermodel.com/.well-known/jwks.json.
|
|
@@ -163,6 +215,8 @@ export declare function parseBitcoinDid(source: string): string | null;
|
|
|
163
215
|
* import { conditionGate } from '@insumermodel/mppx-condition-gate'
|
|
164
216
|
*
|
|
165
217
|
* const gated = conditionGate(tempoCharge, {
|
|
218
|
+
* // Return only a payer this method has proven for THIS request.
|
|
219
|
+
* provenPayer: (details) => (details as { payer?: string }).payer ?? null,
|
|
166
220
|
* conditions: [
|
|
167
221
|
* { type: 'eas_attestation', template: 'coinbase_verified_account', chainId: 8453 },
|
|
168
222
|
* { type: 'farcaster_id' },
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -177,18 +177,61 @@ async function callAttest(wallet, walletType, conditions, options) {
|
|
|
177
177
|
// ---------------------------------------------------------------------------
|
|
178
178
|
// conditionGate adapter
|
|
179
179
|
// ---------------------------------------------------------------------------
|
|
180
|
+
/**
|
|
181
|
+
* Normalizes a caller-supplied proven payer into an address + wallet family.
|
|
182
|
+
*
|
|
183
|
+
* Fail-closed: anything it cannot resolve unambiguously returns null, which
|
|
184
|
+
* sends the request to the paid path.
|
|
185
|
+
*/
|
|
186
|
+
export function normalizeProvenPayer(payer) {
|
|
187
|
+
if (!payer)
|
|
188
|
+
return null;
|
|
189
|
+
if (typeof payer === 'object') {
|
|
190
|
+
const { address, type } = payer;
|
|
191
|
+
if (!address || !type)
|
|
192
|
+
return null;
|
|
193
|
+
return { address, type };
|
|
194
|
+
}
|
|
195
|
+
if (typeof payer !== 'string')
|
|
196
|
+
return null;
|
|
197
|
+
const evm = parseDid(payer);
|
|
198
|
+
if (evm)
|
|
199
|
+
return { address: evm, type: 'evm' };
|
|
200
|
+
const sol = parseSolanaDid(payer);
|
|
201
|
+
if (sol)
|
|
202
|
+
return { address: sol, type: 'solana' };
|
|
203
|
+
const xrpl = parseXrplDid(payer);
|
|
204
|
+
if (xrpl)
|
|
205
|
+
return { address: xrpl, type: 'xrpl' };
|
|
206
|
+
const btc = parseBitcoinDid(payer);
|
|
207
|
+
if (btc)
|
|
208
|
+
return { address: btc, type: 'bitcoin' };
|
|
209
|
+
// Bare EVM address is unambiguous; anything else needs the object form.
|
|
210
|
+
if (payer.startsWith('0x'))
|
|
211
|
+
return { address: payer, type: 'evm' };
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
180
214
|
/**
|
|
181
215
|
* Wraps an mppx Method.Server with condition-based access using signed attestations.
|
|
182
216
|
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
217
|
+
* Free access requires a PROVEN payer. The gate calls the method's non-mutating
|
|
218
|
+
* `validate` hook, hands the resulting method-specific `details` to your
|
|
219
|
+
* `provenPayer` resolver, and only then evaluates conditions. It never reads
|
|
220
|
+
* `credential.source` — mppx documents that field as an asserted identity
|
|
221
|
+
* rather than proof of control.
|
|
222
|
+
*
|
|
223
|
+
* The gate falls through to the paid path whenever free access cannot be
|
|
224
|
+
* justified: no `provenPayer` resolver, no `validate` hook on the method
|
|
225
|
+
* (legacy `verify`-only methods included), a resolver returning null, a
|
|
226
|
+
* credential that fails validation, conditions not met, or an attestation
|
|
227
|
+
* error. There is no path from an unproven wallet to a free receipt.
|
|
187
228
|
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
229
|
+
* Conditions are evaluated across the 35 chains this adapter reaches (32 EVM +
|
|
230
|
+
* Solana + XRPL + Bitcoin; the engine itself covers 38). Six condition types
|
|
231
|
+
* are typed here: token_balance, nft_ownership, eas_attestation, farcaster_id,
|
|
232
|
+
* ratio_to_amount, and ratio_to_supply. InsumerAPI also offers evm_view_call,
|
|
233
|
+
* erc8004_agent, and erc7710_delegation; those are not typed or normalized
|
|
234
|
+
* here, so call /v1/attest directly if you need them.
|
|
192
235
|
*
|
|
193
236
|
* The attestation is ECDSA P-256 signed and verifiable offline via the public
|
|
194
237
|
* JWKS at https://insumermodel.com/.well-known/jwks.json.
|
|
@@ -198,6 +241,8 @@ async function callAttest(wallet, walletType, conditions, options) {
|
|
|
198
241
|
* import { conditionGate } from '@insumermodel/mppx-condition-gate'
|
|
199
242
|
*
|
|
200
243
|
* const gated = conditionGate(tempoCharge, {
|
|
244
|
+
* // Return only a payer this method has proven for THIS request.
|
|
245
|
+
* provenPayer: (details) => (details as { payer?: string }).payer ?? null,
|
|
201
246
|
* conditions: [
|
|
202
247
|
* { type: 'eas_attestation', template: 'coinbase_verified_account', chainId: 8453 },
|
|
203
248
|
* { type: 'farcaster_id' },
|
|
@@ -209,87 +254,81 @@ async function callAttest(wallet, walletType, conditions, options) {
|
|
|
209
254
|
* ```
|
|
210
255
|
*/
|
|
211
256
|
export function conditionGate(server, options) {
|
|
212
|
-
const { conditions, matchMode = 'any', cacheTtlSeconds = 300 } = options;
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if (!
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
257
|
+
const { conditions, matchMode = 'any', cacheTtlSeconds = 300, provenPayer } = options;
|
|
258
|
+
const anyServer = server;
|
|
259
|
+
const originalVerify = anyServer.verify;
|
|
260
|
+
const originalBroadcast = anyServer.broadcast;
|
|
261
|
+
const originalValidate = anyServer.validate;
|
|
262
|
+
// Free access is only reachable when BOTH exist: a resolver to supply the
|
|
263
|
+
// proven payer, and a non-mutating validate hook to derive it from. A method
|
|
264
|
+
// without `validate` (legacy verify-only, or broadcast-without-validate) has
|
|
265
|
+
// no safe pre-check, so it is never gated.
|
|
266
|
+
const canGate = typeof provenPayer === 'function' && typeof originalValidate === 'function';
|
|
267
|
+
/** Returns a free receipt, or null to take the paid path. */
|
|
268
|
+
async function tryFree(params) {
|
|
269
|
+
if (!canGate)
|
|
270
|
+
return null;
|
|
271
|
+
let details;
|
|
272
|
+
try {
|
|
273
|
+
const validation = await originalValidate(params);
|
|
274
|
+
details = validation?.details;
|
|
228
275
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
walletType = 'xrpl';
|
|
276
|
+
catch {
|
|
277
|
+
// Credential is not currently acceptable → let the payment method decide.
|
|
278
|
+
return null;
|
|
233
279
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
280
|
+
let resolved;
|
|
281
|
+
try {
|
|
282
|
+
resolved = await provenPayer(details);
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
return null;
|
|
238
286
|
}
|
|
239
|
-
|
|
240
|
-
if (!
|
|
241
|
-
return
|
|
242
|
-
|
|
243
|
-
const key = cacheKey(wallet, conditions);
|
|
287
|
+
const payer = normalizeProvenPayer(resolved);
|
|
288
|
+
if (!payer)
|
|
289
|
+
return null;
|
|
290
|
+
const key = cacheKey(payer.address, conditions);
|
|
244
291
|
const cached = cache.get(key);
|
|
245
292
|
if (cached && cached.expiresAt > Date.now()) {
|
|
246
|
-
if (cached.pass)
|
|
247
|
-
return
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
}
|
|
254
|
-
// Cached non-holder → fall through
|
|
255
|
-
return originalVerify(params);
|
|
293
|
+
if (!cached.pass)
|
|
294
|
+
return null;
|
|
295
|
+
return {
|
|
296
|
+
method: server.name,
|
|
297
|
+
reference: `condition-gate:free:${cached.attestationId}`,
|
|
298
|
+
status: 'success',
|
|
299
|
+
timestamp: new Date().toISOString(),
|
|
300
|
+
};
|
|
256
301
|
}
|
|
257
|
-
// Call InsumerAPI
|
|
258
302
|
try {
|
|
259
|
-
const result = await callAttest(
|
|
303
|
+
const result = await callAttest(payer.address, payer.type, conditions, options);
|
|
260
304
|
const attestation = result.data.attestation;
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
pass = attestation.pass; // all conditions must be met
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
267
|
-
// "any" — at least one condition met
|
|
268
|
-
pass = attestation.results.some((r) => r.met);
|
|
269
|
-
}
|
|
270
|
-
// Cache the result
|
|
305
|
+
const pass = matchMode === 'all'
|
|
306
|
+
? attestation.pass
|
|
307
|
+
: attestation.results.some((r) => r.met);
|
|
271
308
|
cache.set(key, {
|
|
272
309
|
pass,
|
|
273
310
|
attestationId: attestation.id,
|
|
274
311
|
expiresAt: Date.now() + cacheTtlSeconds * 1000,
|
|
275
312
|
});
|
|
276
|
-
if (pass)
|
|
277
|
-
return
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}
|
|
313
|
+
if (!pass)
|
|
314
|
+
return null;
|
|
315
|
+
return {
|
|
316
|
+
method: server.name,
|
|
317
|
+
reference: `condition-gate:free:${attestation.id}`,
|
|
318
|
+
status: 'success',
|
|
319
|
+
timestamp: new Date().toISOString(),
|
|
320
|
+
};
|
|
284
321
|
}
|
|
285
322
|
catch {
|
|
286
|
-
// Attestation
|
|
323
|
+
// Attestation error → paid path.
|
|
324
|
+
return null;
|
|
287
325
|
}
|
|
288
|
-
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
326
|
+
}
|
|
327
|
+
const wrapped = { ...server };
|
|
328
|
+
if (typeof originalBroadcast === 'function') {
|
|
329
|
+
wrapped.broadcast = async (params) => (await tryFree(params)) ?? originalBroadcast(params);
|
|
330
|
+
}
|
|
331
|
+
wrapped.verify = async (params) => (await tryFree(params)) ?? originalVerify(params);
|
|
332
|
+
return wrapped;
|
|
294
333
|
}
|
|
295
334
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@insumermodel/mppx-condition-gate",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Condition-based access for mppx routes. Wallet auth via signed attestations. Six condition types: token balance, NFT ownership, EAS attestation, Farcaster ID, ratio_to_amount, ratio_to_supply.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
19
|
"build": "tsc",
|
|
20
|
-
"prepublishOnly": "npm run build"
|
|
20
|
+
"prepublishOnly": "npm run build",
|
|
21
|
+
"test": "tsc && node --test test/*.test.mjs"
|
|
21
22
|
},
|
|
22
23
|
"keywords": [
|
|
23
24
|
"condition-based-access",
|
package/src/index.ts
CHANGED
|
@@ -101,9 +101,45 @@ export type Condition =
|
|
|
101
101
|
| RatioToAmountCondition
|
|
102
102
|
| RatioToSupplyCondition
|
|
103
103
|
|
|
104
|
+
/** Wallet family for a proven payer. */
|
|
105
|
+
export type WalletType = 'evm' | 'solana' | 'xrpl' | 'bitcoin'
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* A payer the caller has cryptographically proven for this request.
|
|
109
|
+
*
|
|
110
|
+
* Accepts a `did:pkh:...` string, a bare `0x` EVM address, or an explicit
|
|
111
|
+
* `{ address, type }` pair. Bare non-EVM addresses are rejected because their
|
|
112
|
+
* wallet family cannot be inferred unambiguously — pass the object form.
|
|
113
|
+
*/
|
|
114
|
+
export type ProvenPayer =
|
|
115
|
+
| string
|
|
116
|
+
| { address: string; type: WalletType }
|
|
117
|
+
| null
|
|
118
|
+
| undefined
|
|
119
|
+
|
|
104
120
|
export type ConditionGateOptions = {
|
|
105
121
|
/** InsumerAPI key. Falls back to INSUMER_API_KEY env var. */
|
|
106
122
|
apiKey?: string
|
|
123
|
+
/**
|
|
124
|
+
* Resolves the payer that the payment method has PROVEN controls this
|
|
125
|
+
* request. Required for free access — without it every request takes the
|
|
126
|
+
* paid path.
|
|
127
|
+
*
|
|
128
|
+
* It receives only mppx's method-specific validation `details` (for example
|
|
129
|
+
* a recovered payer address). It is deliberately NOT given the credential or
|
|
130
|
+
* the declared `source`: mppx documents `source` as "an asserted identity,
|
|
131
|
+
* not independent proof of control", and granting on it is the vulnerability
|
|
132
|
+
* fixed in 3.0.0 (GHSA-jg6q-3qfh-r9f8).
|
|
133
|
+
*
|
|
134
|
+
* Return `null` when no payer has been proven. Returning an address you have
|
|
135
|
+
* not proven reintroduces that vulnerability.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```ts
|
|
139
|
+
* provenPayer: (details) => (details as { payer?: string }).payer ?? null
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
provenPayer?: (details: unknown) => ProvenPayer | Promise<ProvenPayer>
|
|
107
143
|
/** One or more conditions to evaluate. Mix any of the six types. */
|
|
108
144
|
conditions: Condition[]
|
|
109
145
|
/** Whether the wallet must satisfy "any" (default) or "all" conditions. */
|
|
@@ -343,18 +379,60 @@ async function callAttest(
|
|
|
343
379
|
// conditionGate adapter
|
|
344
380
|
// ---------------------------------------------------------------------------
|
|
345
381
|
|
|
382
|
+
/**
|
|
383
|
+
* Normalizes a caller-supplied proven payer into an address + wallet family.
|
|
384
|
+
*
|
|
385
|
+
* Fail-closed: anything it cannot resolve unambiguously returns null, which
|
|
386
|
+
* sends the request to the paid path.
|
|
387
|
+
*/
|
|
388
|
+
export function normalizeProvenPayer(
|
|
389
|
+
payer: ProvenPayer,
|
|
390
|
+
): { address: string; type: WalletType } | null {
|
|
391
|
+
if (!payer) return null
|
|
392
|
+
|
|
393
|
+
if (typeof payer === 'object') {
|
|
394
|
+
const { address, type } = payer
|
|
395
|
+
if (!address || !type) return null
|
|
396
|
+
return { address, type }
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (typeof payer !== 'string') return null
|
|
400
|
+
|
|
401
|
+
const evm = parseDid(payer)
|
|
402
|
+
if (evm) return { address: evm, type: 'evm' }
|
|
403
|
+
const sol = parseSolanaDid(payer)
|
|
404
|
+
if (sol) return { address: sol, type: 'solana' }
|
|
405
|
+
const xrpl = parseXrplDid(payer)
|
|
406
|
+
if (xrpl) return { address: xrpl, type: 'xrpl' }
|
|
407
|
+
const btc = parseBitcoinDid(payer)
|
|
408
|
+
if (btc) return { address: btc, type: 'bitcoin' }
|
|
409
|
+
|
|
410
|
+
// Bare EVM address is unambiguous; anything else needs the object form.
|
|
411
|
+
if (payer.startsWith('0x')) return { address: payer, type: 'evm' }
|
|
412
|
+
return null
|
|
413
|
+
}
|
|
414
|
+
|
|
346
415
|
/**
|
|
347
416
|
* Wraps an mppx Method.Server with condition-based access using signed attestations.
|
|
348
417
|
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
*
|
|
418
|
+
* Free access requires a PROVEN payer. The gate calls the method's non-mutating
|
|
419
|
+
* `validate` hook, hands the resulting method-specific `details` to your
|
|
420
|
+
* `provenPayer` resolver, and only then evaluates conditions. It never reads
|
|
421
|
+
* `credential.source` — mppx documents that field as an asserted identity
|
|
422
|
+
* rather than proof of control.
|
|
423
|
+
*
|
|
424
|
+
* The gate falls through to the paid path whenever free access cannot be
|
|
425
|
+
* justified: no `provenPayer` resolver, no `validate` hook on the method
|
|
426
|
+
* (legacy `verify`-only methods included), a resolver returning null, a
|
|
427
|
+
* credential that fails validation, conditions not met, or an attestation
|
|
428
|
+
* error. There is no path from an unproven wallet to a free receipt.
|
|
353
429
|
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
430
|
+
* Conditions are evaluated across the 35 chains this adapter reaches (32 EVM +
|
|
431
|
+
* Solana + XRPL + Bitcoin; the engine itself covers 38). Six condition types
|
|
432
|
+
* are typed here: token_balance, nft_ownership, eas_attestation, farcaster_id,
|
|
433
|
+
* ratio_to_amount, and ratio_to_supply. InsumerAPI also offers evm_view_call,
|
|
434
|
+
* erc8004_agent, and erc7710_delegation; those are not typed or normalized
|
|
435
|
+
* here, so call /v1/attest directly if you need them.
|
|
358
436
|
*
|
|
359
437
|
* The attestation is ECDSA P-256 signed and verifiable offline via the public
|
|
360
438
|
* JWKS at https://insumermodel.com/.well-known/jwks.json.
|
|
@@ -364,6 +442,8 @@ async function callAttest(
|
|
|
364
442
|
* import { conditionGate } from '@insumermodel/mppx-condition-gate'
|
|
365
443
|
*
|
|
366
444
|
* const gated = conditionGate(tempoCharge, {
|
|
445
|
+
* // Return only a payer this method has proven for THIS request.
|
|
446
|
+
* provenPayer: (details) => (details as { payer?: string }).payer ?? null,
|
|
367
447
|
* conditions: [
|
|
368
448
|
* { type: 'eas_attestation', template: 'coinbase_verified_account', chainId: 8453 },
|
|
369
449
|
* { type: 'farcaster_id' },
|
|
@@ -378,92 +458,97 @@ export function conditionGate(
|
|
|
378
458
|
server: Method.AnyServer,
|
|
379
459
|
options: ConditionGateOptions,
|
|
380
460
|
): Method.AnyServer {
|
|
381
|
-
const { conditions, matchMode = 'any', cacheTtlSeconds = 300 } = options
|
|
461
|
+
const { conditions, matchMode = 'any', cacheTtlSeconds = 300, provenPayer } = options
|
|
382
462
|
|
|
383
|
-
const
|
|
463
|
+
const anyServer = server as unknown as {
|
|
464
|
+
verify: (params: any) => Promise<any>
|
|
465
|
+
broadcast?: (params: any) => Promise<any>
|
|
466
|
+
validate?: (params: any) => Promise<any>
|
|
467
|
+
}
|
|
384
468
|
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
469
|
+
const originalVerify = anyServer.verify
|
|
470
|
+
const originalBroadcast = anyServer.broadcast
|
|
471
|
+
const originalValidate = anyServer.validate
|
|
388
472
|
|
|
389
|
-
|
|
390
|
-
|
|
473
|
+
// Free access is only reachable when BOTH exist: a resolver to supply the
|
|
474
|
+
// proven payer, and a non-mutating validate hook to derive it from. A method
|
|
475
|
+
// without `validate` (legacy verify-only, or broadcast-without-validate) has
|
|
476
|
+
// no safe pre-check, so it is never gated.
|
|
477
|
+
const canGate =
|
|
478
|
+
typeof provenPayer === 'function' && typeof originalValidate === 'function'
|
|
391
479
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
480
|
+
/** Returns a free receipt, or null to take the paid path. */
|
|
481
|
+
async function tryFree(params: any): Promise<any | null> {
|
|
482
|
+
if (!canGate) return null
|
|
395
483
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
if (wallet) walletType = 'xrpl'
|
|
484
|
+
let details: unknown
|
|
485
|
+
try {
|
|
486
|
+
const validation = await originalValidate!(params)
|
|
487
|
+
details = (validation as { details?: unknown } | undefined)?.details
|
|
488
|
+
} catch {
|
|
489
|
+
// Credential is not currently acceptable → let the payment method decide.
|
|
490
|
+
return null
|
|
404
491
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
492
|
+
|
|
493
|
+
let resolved: ProvenPayer
|
|
494
|
+
try {
|
|
495
|
+
resolved = await provenPayer!(details)
|
|
496
|
+
} catch {
|
|
497
|
+
return null
|
|
408
498
|
}
|
|
409
499
|
|
|
410
|
-
|
|
411
|
-
if (!
|
|
500
|
+
const payer = normalizeProvenPayer(resolved)
|
|
501
|
+
if (!payer) return null
|
|
412
502
|
|
|
413
|
-
|
|
414
|
-
const key = cacheKey(wallet, conditions)
|
|
503
|
+
const key = cacheKey(payer.address, conditions)
|
|
415
504
|
const cached = cache.get(key)
|
|
416
505
|
if (cached && cached.expiresAt > Date.now()) {
|
|
417
|
-
if (cached.pass)
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
}
|
|
506
|
+
if (!cached.pass) return null
|
|
507
|
+
return {
|
|
508
|
+
method: server.name,
|
|
509
|
+
reference: `condition-gate:free:${cached.attestationId}`,
|
|
510
|
+
status: 'success' as const,
|
|
511
|
+
timestamp: new Date().toISOString(),
|
|
424
512
|
}
|
|
425
|
-
// Cached non-holder → fall through
|
|
426
|
-
return originalVerify(params)
|
|
427
513
|
}
|
|
428
514
|
|
|
429
|
-
// Call InsumerAPI
|
|
430
515
|
try {
|
|
431
|
-
const result = await callAttest(
|
|
516
|
+
const result = await callAttest(payer.address, payer.type, conditions, options)
|
|
432
517
|
const attestation = result.data.attestation
|
|
433
518
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
} else {
|
|
439
|
-
// "any" — at least one condition met
|
|
440
|
-
pass = attestation.results.some((r) => r.met)
|
|
441
|
-
}
|
|
519
|
+
const pass =
|
|
520
|
+
matchMode === 'all'
|
|
521
|
+
? attestation.pass
|
|
522
|
+
: attestation.results.some((r) => r.met)
|
|
442
523
|
|
|
443
|
-
// Cache the result
|
|
444
524
|
cache.set(key, {
|
|
445
525
|
pass,
|
|
446
526
|
attestationId: attestation.id,
|
|
447
527
|
expiresAt: Date.now() + cacheTtlSeconds * 1000,
|
|
448
528
|
})
|
|
449
529
|
|
|
450
|
-
if (pass)
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
}
|
|
530
|
+
if (!pass) return null
|
|
531
|
+
return {
|
|
532
|
+
method: server.name,
|
|
533
|
+
reference: `condition-gate:free:${attestation.id}`,
|
|
534
|
+
status: 'success' as const,
|
|
535
|
+
timestamp: new Date().toISOString(),
|
|
457
536
|
}
|
|
458
537
|
} catch {
|
|
459
|
-
// Attestation
|
|
538
|
+
// Attestation error → paid path.
|
|
539
|
+
return null
|
|
460
540
|
}
|
|
461
|
-
|
|
462
|
-
return originalVerify(params)
|
|
463
541
|
}
|
|
464
542
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
543
|
+
const wrapped = { ...server } as unknown as Record<string, unknown>
|
|
544
|
+
|
|
545
|
+
if (typeof originalBroadcast === 'function') {
|
|
546
|
+
wrapped.broadcast = async (params: any) =>
|
|
547
|
+
(await tryFree(params)) ?? originalBroadcast(params)
|
|
468
548
|
}
|
|
549
|
+
|
|
550
|
+
wrapped.verify = async (params: any) =>
|
|
551
|
+
(await tryFree(params)) ?? originalVerify(params)
|
|
552
|
+
|
|
553
|
+
return wrapped as unknown as Method.AnyServer
|
|
469
554
|
}
|