@billionsnetwork/x402-human-proof 0.1.3
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/node/cjs/declare.cjs +42 -0
- package/dist/node/cjs/declare.cjs.map +1 -0
- package/dist/node/cjs/hooks.cjs +198 -0
- package/dist/node/cjs/hooks.cjs.map +1 -0
- package/dist/node/cjs/index.cjs +493 -0
- package/dist/node/cjs/index.cjs.map +1 -0
- package/dist/node/cjs/server.cjs +469 -0
- package/dist/node/cjs/server.cjs.map +1 -0
- package/dist/node/cjs/types.cjs +19 -0
- package/dist/node/cjs/types.cjs.map +1 -0
- package/dist/node/cjs/utils.cjs +184 -0
- package/dist/node/cjs/utils.cjs.map +1 -0
- package/dist/node/cjs/verifier.cjs +102 -0
- package/dist/node/cjs/verifier.cjs.map +1 -0
- package/dist/node/esm/declare.js +15 -0
- package/dist/node/esm/declare.js.map +1 -0
- package/dist/node/esm/hooks.js +160 -0
- package/dist/node/esm/hooks.js.map +1 -0
- package/dist/node/esm/index.js +445 -0
- package/dist/node/esm/index.js.map +1 -0
- package/dist/node/esm/server.js +427 -0
- package/dist/node/esm/server.js.map +1 -0
- package/dist/node/esm/types.js +1 -0
- package/dist/node/esm/types.js.map +1 -0
- package/dist/node/esm/utils.js +145 -0
- package/dist/node/esm/utils.js.map +1 -0
- package/dist/node/esm/verifier.js +74 -0
- package/dist/node/esm/verifier.js.map +1 -0
- package/dist/types/declare.d.ts +17 -0
- package/dist/types/declare.d.ts.map +1 -0
- package/dist/types/hooks.d.ts +36 -0
- package/dist/types/hooks.d.ts.map +1 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/server.d.ts +87 -0
- package/dist/types/server.d.ts.map +1 -0
- package/dist/types/types.d.ts +99 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/utils.d.ts +40 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/dist/types/verifier.d.ts +13 -0
- package/dist/types/verifier.d.ts.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils.ts"],"sourcesContent":["import { recoverPublicKey, hashMessage, recoverMessageAddress } from 'viem'\nimport bs58 from 'bs58'\nimport nacl from 'tweetnacl'\nimport type { PaywallProvider } from '@x402/core/server'\nimport type { PaymentRequired } from '@x402/core/types'\n\nexport type SignatureType = 'eip191' | 'ed25519'\n\nexport type SupportedChain = {\n chainId: string\n type: SignatureType\n}\n\nexport type HumanProofExtensionInfo = {\n domain: string\n uri?: string\n version: string\n nonce: string\n issuedAt: string\n expirationTime?: string\n statement?: string\n resources?: string[]\n requiredAttestations: string[]\n}\n\nexport type HumanProofExtensionPayload = HumanProofExtensionInfo & {\n chainId: string\n type: SignatureType\n address: string\n signature: string\n}\n\ntype ValidationResult = {\n valid: boolean\n error?: string\n}\n\ntype SignatureVerificationResult = {\n valid: boolean\n address?: string\n pubKey?: string\n error?: string\n}\n\nfunction formatResources(resources?: string[]): string {\n if (!resources?.length) return ''\n const lines = resources.map(resource => `- ${resource}`).join('\\n')\n return `\\nResources:\\n${lines}`\n}\n\nfunction formatSIWEMessage(payload: HumanProofExtensionPayload): string {\n const statementBlock = payload.statement ? `\\n${payload.statement}\\n` : '\\n'\n const expirationLine = payload.expirationTime ? `\\nExpiration Time: ${payload.expirationTime}` : ''\n\n return (\n `${payload.domain} wants you to sign in with your Ethereum account:\\n` +\n `${payload.address}${statementBlock}\\n` +\n `URI: ${payload.uri ?? ''}\\n` +\n `Version: ${payload.version}\\n` +\n `Chain ID: ${payload.chainId}\\n` +\n `Nonce: ${payload.nonce}\\n` +\n `Issued At: ${payload.issuedAt}` +\n `${expirationLine}` +\n `${formatResources(payload.resources)}`\n )\n}\n\nfunction formatSIWSMessage(payload: HumanProofExtensionPayload): string {\n const statementBlock = payload.statement ? `\\n${payload.statement}\\n` : '\\n'\n const expirationLine = payload.expirationTime ? `\\nExpiration Time: ${payload.expirationTime}` : ''\n\n return (\n `${payload.domain} wants you to sign in with your Solana account:\\n` +\n `${payload.address}${statementBlock}\\n` +\n `URI: ${payload.uri ?? ''}\\n` +\n `Version: ${payload.version}\\n` +\n `Chain ID: ${payload.chainId}\\n` +\n `Nonce: ${payload.nonce}\\n` +\n `Issued At: ${payload.issuedAt}` +\n `${expirationLine}` +\n `${formatResources(payload.resources)}`\n )\n}\n\nfunction decodeBase58(input: string): Uint8Array {\n return bs58.decode(input)\n}\n\nexport function buildHumanProofSchema(): Record<string, unknown> {\n return {\n type: 'object',\n required: ['domain', 'version', 'nonce', 'issuedAt', 'chainId', 'type', 'address', 'signature', 'requiredAttestations'],\n properties: {\n domain: { type: 'string' },\n uri: { type: 'string' },\n version: { type: 'string' },\n nonce: { type: 'string' },\n issuedAt: { type: 'string' },\n expirationTime: { type: 'string' },\n statement: { type: 'string' },\n resources: { type: 'array', items: { type: 'string' } },\n chainId: { type: 'string' },\n type: { enum: ['eip191', 'ed25519'] },\n address: { type: 'string' },\n signature: { type: 'string' },\n requiredAttestations: { type: 'array', items: { type: 'string' }},\n },\n additionalProperties: true,\n }\n}\n\nexport function parseHumanProofHeader(headerValue: string): HumanProofExtensionPayload {\n const parsed = JSON.parse(headerValue) as unknown\n if (!parsed || typeof parsed !== 'object') {\n throw new Error('Invalid header payload')\n }\n\n const payload = parsed as Partial<HumanProofExtensionPayload>\n if (!payload.address || !payload.signature || !payload.chainId || !payload.type) {\n throw new Error('Missing required fields in header payload')\n }\n\n return payload as HumanProofExtensionPayload\n}\n\nexport async function validateHumanProofMessage(\n payload: HumanProofExtensionPayload,\n resource: string,\n): Promise<ValidationResult> {\n if (!payload.domain || !payload.version || !payload.nonce || !payload.issuedAt) {\n return { valid: false, error: 'invalid_message' }\n }\n\n if (!payload.uri || payload.uri !== resource) {\n return { valid: false, error: 'resource_mismatch' }\n }\n\n const issuedAtMillis = Date.parse(payload.issuedAt)\n if (Number.isNaN(issuedAtMillis)) {\n return { valid: false, error: 'invalid_issued_at' }\n }\n\n if (payload.expirationTime) {\n const expirationMillis = Date.parse(payload.expirationTime)\n if (Number.isNaN(expirationMillis)) {\n return { valid: false, error: 'invalid_expiration_time' }\n }\n if (expirationMillis < Date.now()) {\n return { valid: false, error: 'message_expired' }\n }\n }\n\n return { valid: true }\n}\n\nexport async function verifyHumanProofSignature(\n payload: HumanProofExtensionPayload,\n): Promise<SignatureVerificationResult> {\n if (payload.type === 'eip191') {\n if (!payload.signature.startsWith('0x')) {\n return { valid: false, error: 'invalid_signature' }\n }\n try {\n const message = formatSIWEMessage(payload)\n const signature = payload.signature as `0x${string}`\n\n const recovered = await recoverMessageAddress({ message, signature })\n if (recovered.toLowerCase() !== payload.address.toLowerCase()) {\n return { valid: false, error: 'invalid_signature' }\n }\n\n const publicKey = await recoverPublicKey({ hash: hashMessage(message), signature })\n return { valid: true, address: payload.address, pubKey: publicKey }\n } catch {\n return { valid: false, error: 'invalid_signature' }\n }\n }\n\n if (payload.type === 'ed25519') {\n try {\n const message = new TextEncoder().encode(formatSIWSMessage(payload))\n const publicKey = decodeBase58(payload.address)\n const signature = decodeBase58(payload.signature)\n\n const valid = nacl.sign.detached.verify(message, signature, publicKey)\n if (!valid) return { valid: false, error: 'invalid_signature' }\n return { valid: true, address: payload.address, pubKey: bs58.encode(publicKey) }\n } catch {\n return { valid: false, error: 'invalid_signature' }\n }\n }\n\n return { valid: false, error: 'invalid_signature_type' }\n}\n\nconst DEFAULT_PAYWALL_HTML =\n \"<html><body>\" +\n \"<h1>Payment Required</h1>\" +\n \"<p>Please complete the payment to access this resource.</p>\" +\n \"<p>The payment depends on verified-agent-identity plugin. \" +\n \"That can be downloaded from: \" +\n '<a href=\"https://clawhub.ai/obrezhniev/verified-agent-identity\">clawhub.ai</a> ' +\n '<a href=\"https://skills.sh/billionsnetwork/verified-agent-identity/verified-agent-identity\">skills.sh</a>' +\n \"</p></body></html>\"\n\nexport function paywallInstructions(html?: string): PaywallProvider {\n return new (class implements PaywallProvider {\n public generateHtml(_: PaymentRequired): string {\n return html ?? DEFAULT_PAYWALL_HTML\n }\n })()\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// src/verifier.ts
|
|
2
|
+
var DEFAULT_ATTESTATIONS_API_BASE_URL = "https://attestations-api.billions.network/api/v1/attestations";
|
|
3
|
+
var DEFAULT_NULLIFIER_API_BASE_URL = "https://attestations-api.billions.network/api/v1/nullifier";
|
|
4
|
+
var DEFAULT_AGENT_OWNERSHIP_SCHEMA = "0xca354bee6dc5eded165461d15ccb13aceb6f77ebbb1fd3fe45aca686097f2911";
|
|
5
|
+
async function fetchExplorerPage(baseUrl, schema, recipientDid) {
|
|
6
|
+
const url = new URL(baseUrl);
|
|
7
|
+
url.searchParams.set("schemaId", schema);
|
|
8
|
+
url.searchParams.set("recipientDid", recipientDid);
|
|
9
|
+
const response = await fetch(url.toString());
|
|
10
|
+
if (!response.ok) {
|
|
11
|
+
throw new Error(`Attestations explorer lookup failed (${response.status})`);
|
|
12
|
+
}
|
|
13
|
+
const json = await response.json();
|
|
14
|
+
return json;
|
|
15
|
+
}
|
|
16
|
+
async function fetchNullifier(nullifierBaseUrl, userId) {
|
|
17
|
+
const url = new URL(nullifierBaseUrl);
|
|
18
|
+
url.searchParams.set("userId", userId);
|
|
19
|
+
const response = await fetch(url.toString());
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
throw new Error(`Nullifier lookup failed (${response.status})`);
|
|
22
|
+
}
|
|
23
|
+
const json = await response.json();
|
|
24
|
+
return json.nullifier ?? null;
|
|
25
|
+
}
|
|
26
|
+
async function lookupHumanFromExplorer(did, options) {
|
|
27
|
+
const payload = await fetchExplorerPage(
|
|
28
|
+
options.baseUrl,
|
|
29
|
+
options.schema,
|
|
30
|
+
did
|
|
31
|
+
);
|
|
32
|
+
const sorted = (payload.data ?? []).sort((a, b) => (b.creationTime ?? 0) - (a.creationTime ?? 0));
|
|
33
|
+
const match = sorted[0];
|
|
34
|
+
if (match?.fromId) {
|
|
35
|
+
const nullifier = await fetchNullifier(options.nullifierBaseUrl, match.fromId);
|
|
36
|
+
if (nullifier) {
|
|
37
|
+
return {
|
|
38
|
+
humanId: nullifier,
|
|
39
|
+
verifiedAt: new Date(match.creationTime * 1e3).toISOString(),
|
|
40
|
+
attestationId: match.id,
|
|
41
|
+
humanDid: match.fromDid,
|
|
42
|
+
humanAddress: match.fromEthereumAddress,
|
|
43
|
+
agentDid: match.toDid,
|
|
44
|
+
agentAddress: match.toEthereumAddress
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
function createPoUVerifier(options = {}) {
|
|
51
|
+
const baseUrl = options.attestationsApiBaseUrl ?? DEFAULT_ATTESTATIONS_API_BASE_URL;
|
|
52
|
+
const nullifierBaseUrl = options.nullifierApiBaseUrl ?? DEFAULT_NULLIFIER_API_BASE_URL;
|
|
53
|
+
const ownershipSchema = options.agentOwnershipSchema ?? DEFAULT_AGENT_OWNERSHIP_SCHEMA;
|
|
54
|
+
return {
|
|
55
|
+
ownershipSchema,
|
|
56
|
+
async lookupHuman(did, _chainId) {
|
|
57
|
+
return lookupHumanFromExplorer(did, { baseUrl, schema: ownershipSchema, nullifierBaseUrl });
|
|
58
|
+
},
|
|
59
|
+
async hasAttestation(did, _chainId, schema) {
|
|
60
|
+
if (options.hasAttestation) {
|
|
61
|
+
return options.hasAttestation(did, _chainId, schema);
|
|
62
|
+
}
|
|
63
|
+
const payload = await fetchExplorerPage(baseUrl, schema, did);
|
|
64
|
+
return (payload.data ?? []).length > 0;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export {
|
|
69
|
+
DEFAULT_AGENT_OWNERSHIP_SCHEMA,
|
|
70
|
+
DEFAULT_ATTESTATIONS_API_BASE_URL,
|
|
71
|
+
DEFAULT_NULLIFIER_API_BASE_URL,
|
|
72
|
+
createPoUVerifier
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/verifier.ts"],"sourcesContent":["import type {\n HumanResolution,\n PoUVerifier,\n PoUVerifierOptions,\n} from './types.js'\n\nexport const DEFAULT_ATTESTATIONS_API_BASE_URL =\n 'https://attestations-api.billions.network/api/v1/attestations'\n\nexport const DEFAULT_NULLIFIER_API_BASE_URL =\n 'https://attestations-api.billions.network/api/v1/nullifier'\n\nexport const DEFAULT_AGENT_OWNERSHIP_SCHEMA =\n '0xca354bee6dc5eded165461d15ccb13aceb6f77ebbb1fd3fe45aca686097f2911'\n\ntype ExplorerAttestationItem = {\n creationTime: number\n time?: number\n id: string\n schemaId: string\n fromId?: string\n recipientEthereumAddress?: string\n attesterEthereumAddress?: string\n toDid: string\n toEthereumAddress: string\n fromDid: string\n fromEthereumAddress: string\n}\n\ntype ExplorerAttestationsResponse = {\n data?: ExplorerAttestationItem[]\n nextPage?: number | null\n}\n\nasync function fetchExplorerPage(\n baseUrl: string,\n schema: string,\n recipientDid: string,\n): Promise<ExplorerAttestationsResponse> {\n const url = new URL(baseUrl)\n\n url.searchParams.set('schemaId', schema)\n url.searchParams.set('recipientDid', recipientDid)\n\n const response = await fetch(url.toString())\n if (!response.ok) {\n throw new Error(`Attestations explorer lookup failed (${response.status})`)\n }\n\n const json = (await response.json()) as ExplorerAttestationsResponse\n return json\n}\n\nasync function fetchNullifier(nullifierBaseUrl: string, userId: string): Promise<string | null> {\n const url = new URL(nullifierBaseUrl)\n url.searchParams.set('userId', userId)\n\n const response = await fetch(url.toString())\n if (!response.ok) {\n throw new Error(`Nullifier lookup failed (${response.status})`)\n }\n\n const json = (await response.json()) as { userId: string; nullifier: string }\n return json.nullifier ?? null\n}\n\nasync function lookupHumanFromExplorer(\n did: string,\n options: {\n baseUrl: string\n schema: string\n nullifierBaseUrl: string\n },\n): Promise<HumanResolution | null> {\n const payload = await fetchExplorerPage(\n options.baseUrl,\n options.schema,\n did,\n )\n\n const sorted = (payload.data ?? []).sort((a, b) => (b.creationTime ?? 0) - (a.creationTime ?? 0))\n const match = sorted[0]\n\n if (match?.fromId) {\n const nullifier = await fetchNullifier(options.nullifierBaseUrl, match.fromId)\n if (nullifier) {\n return {\n humanId: nullifier,\n verifiedAt: new Date(match.creationTime * 1000).toISOString(),\n attestationId: match.id,\n humanDid: match.fromDid,\n humanAddress: match.fromEthereumAddress,\n agentDid: match.toDid,\n agentAddress: match.toEthereumAddress,\n }\n }\n }\n\n return null\n}\n\n/**\n * Creates a PoU (Proof of Uniqueness) verifier that resolves a DID\n * to a HumanResolution.\n * @example\n * const verifier = createPoUVerifier()\n * const resolution = await verifier.lookupHuman('did:iden3:...', 'eip155:137')\n */\nexport function createPoUVerifier(options: PoUVerifierOptions = {}): PoUVerifier {\n const baseUrl = options.attestationsApiBaseUrl ?? DEFAULT_ATTESTATIONS_API_BASE_URL\n const nullifierBaseUrl = options.nullifierApiBaseUrl ?? DEFAULT_NULLIFIER_API_BASE_URL\n const ownershipSchema = options.agentOwnershipSchema ?? DEFAULT_AGENT_OWNERSHIP_SCHEMA\n\n return {\n ownershipSchema,\n\n async lookupHuman(did: string, _chainId: string): Promise<HumanResolution | null> {\n return lookupHumanFromExplorer(did, { baseUrl, schema: ownershipSchema, nullifierBaseUrl })\n },\n\n async hasAttestation(did: string, _chainId: string, schema: string): Promise<boolean> {\n if (options.hasAttestation) {\n return options.hasAttestation(did, _chainId, schema)\n }\n const payload = await fetchExplorerPage(baseUrl, schema, did)\n return (payload.data ?? []).length > 0\n },\n }\n}\n"],"mappings":";AAMO,IAAM,oCACX;AAEK,IAAM,iCACX;AAEK,IAAM,iCACX;AAqBF,eAAe,kBACb,SACA,QACA,cACuC;AACvC,QAAM,MAAM,IAAI,IAAI,OAAO;AAE3B,MAAI,aAAa,IAAI,YAAY,MAAM;AACvC,MAAI,aAAa,IAAI,gBAAgB,YAAY;AAEjD,QAAM,WAAW,MAAM,MAAM,IAAI,SAAS,CAAC;AAC3C,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,wCAAwC,SAAS,MAAM,GAAG;AAAA,EAC5E;AAEA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAO;AACT;AAEA,eAAe,eAAe,kBAA0B,QAAwC;AAC9F,QAAM,MAAM,IAAI,IAAI,gBAAgB;AACpC,MAAI,aAAa,IAAI,UAAU,MAAM;AAErC,QAAM,WAAW,MAAM,MAAM,IAAI,SAAS,CAAC;AAC3C,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,4BAA4B,SAAS,MAAM,GAAG;AAAA,EAChE;AAEA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAO,KAAK,aAAa;AAC3B;AAEA,eAAe,wBACb,KACA,SAKiC;AACjC,QAAM,UAAU,MAAM;AAAA,IACpB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR;AAAA,EACF;AAEA,QAAM,UAAU,QAAQ,QAAQ,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO,EAAE,gBAAgB,MAAM,EAAE,gBAAgB,EAAE;AAChG,QAAM,QAAQ,OAAO,CAAC;AAEtB,MAAI,OAAO,QAAQ;AACjB,UAAM,YAAY,MAAM,eAAe,QAAQ,kBAAkB,MAAM,MAAM;AAC7E,QAAI,WAAW;AACb,aAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY,IAAI,KAAK,MAAM,eAAe,GAAI,EAAE,YAAY;AAAA,QAC5D,eAAe,MAAM;AAAA,QACrB,UAAU,MAAM;AAAA,QAChB,cAAc,MAAM;AAAA,QACpB,UAAU,MAAM;AAAA,QAChB,cAAc,MAAM;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AASO,SAAS,kBAAkB,UAA8B,CAAC,GAAgB;AAC/E,QAAM,UAAU,QAAQ,0BAA0B;AAClD,QAAM,mBAAmB,QAAQ,uBAAuB;AACxD,QAAM,kBAAkB,QAAQ,wBAAwB;AAExD,SAAO;AAAA,IACL;AAAA,IAEA,MAAM,YAAY,KAAa,UAAmD;AAChF,aAAO,wBAAwB,KAAK,EAAE,SAAS,QAAQ,iBAAiB,iBAAiB,CAAC;AAAA,IAC5F;AAAA,IAEA,MAAM,eAAe,KAAa,UAAkB,QAAkC;AACpF,UAAI,QAAQ,gBAAgB;AAC1B,eAAO,QAAQ,eAAe,KAAK,UAAU,MAAM;AAAA,MACrD;AACA,YAAM,UAAU,MAAM,kBAAkB,SAAS,QAAQ,GAAG;AAC5D,cAAQ,QAAQ,QAAQ,CAAC,GAAG,SAAS;AAAA,IACvC;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SignatureType } from './utils.js';
|
|
2
|
+
import type { DeclareHumanProofOptions, HumanProofDeclaration } from './types.js';
|
|
3
|
+
export declare const HUMAN_PROOF = "human-proof";
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* extensions: declareHumanProofExtension({
|
|
8
|
+
* statement: 'Verify your agent is backed by a verified human',
|
|
9
|
+
* })
|
|
10
|
+
*/
|
|
11
|
+
export declare function declareHumanProofExtension(options: DeclareHumanProofOptions): HumanProofDeclaration;
|
|
12
|
+
/**
|
|
13
|
+
* Returns the supported signature types for a given CAIP-2 network.
|
|
14
|
+
* Solana uses ed25519 (SIWS); all EVM networks use eip191 (SIWE).
|
|
15
|
+
*/
|
|
16
|
+
export declare function getSignatureTypes(network: string): SignatureType[];
|
|
17
|
+
//# sourceMappingURL=declare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declare.d.ts","sourceRoot":"","sources":["../../src/declare.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,KAAK,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEjF,eAAO,MAAM,WAAW,gBAAgB,CAAA;AAExC;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,wBAAwB,GAAG,qBAAqB,CAEnG;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAGlE"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { HumanResolution, HumanProofEvent, PoUVerifier } from './types.js';
|
|
2
|
+
export declare const HUMAN_PROOF_HEADER = "HUMAN-PROOF";
|
|
3
|
+
export type HumanProofRequestContext = {
|
|
4
|
+
/** The resource URI being accessed (used to validate the CAIP-122 message). */
|
|
5
|
+
resource: string;
|
|
6
|
+
/** Value of the HUMAN-PROOF request header, or null if absent. */
|
|
7
|
+
humanProofHeader: string | null;
|
|
8
|
+
/** Optional callback fired on human_verified and human_not_registered events. */
|
|
9
|
+
onEvent?: (event: HumanProofEvent) => void | Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
export type HumanProofRequestResult = {
|
|
12
|
+
allowed: true;
|
|
13
|
+
resolution: HumanResolution;
|
|
14
|
+
did: string;
|
|
15
|
+
chainId: string;
|
|
16
|
+
} | {
|
|
17
|
+
allowed: false;
|
|
18
|
+
reason: 'missing_header' | 'invalid_header' | 'invalid_message' | 'invalid_signature' | 'not_registered' | string;
|
|
19
|
+
did?: string;
|
|
20
|
+
humanId?: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Verify a HUMAN-PROOF request header against the PoU registry.
|
|
24
|
+
*
|
|
25
|
+
* Call this inside a request hook (BeforeVerifyHook or framework middleware)
|
|
26
|
+
* to gate access based on human verification.
|
|
27
|
+
*
|
|
28
|
+
* Flow:
|
|
29
|
+
* 1. Parse the CAIP-122 signed payload from the HUMAN-PROOF header
|
|
30
|
+
* 2. Validate message fields (resource URI, nonce expiry)
|
|
31
|
+
* 3. Verify the cryptographic signature (EVM eip191 or Solana ed25519)
|
|
32
|
+
* 4. Resolve the wallet address to a HumanResolution via the on-chain registry
|
|
33
|
+
* 5. Fire hook events
|
|
34
|
+
*/
|
|
35
|
+
export declare function verifyHumanProofRequest(verifier: PoUVerifier, context: HumanProofRequestContext): Promise<HumanProofRequestResult>;
|
|
36
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/hooks.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAI/E,eAAO,MAAM,kBAAkB,gBAAgB,CAAA;AAE/C,MAAM,MAAM,wBAAwB,GAAG;IACrC,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAA;IAChB,kEAAkE;IAClE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,iFAAiF;IACjF,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3D,CAAA;AAED,MAAM,MAAM,uBAAuB,GAC/B;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,eAAe,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC5E;IACE,OAAO,EAAE,KAAK,CAAA;IACd,MAAM,EACF,gBAAgB,GAChB,gBAAgB,GAChB,iBAAiB,GACjB,mBAAmB,GACnB,gBAAgB,GAChB,MAAM,CAAA;IACV,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAEL;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,uBAAuB,CAAC,CAqDlC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { createHumanProofExtension, createVerifyHumanProofHook, configureHumanProofServer, } from './server.js';
|
|
2
|
+
export type { CreateHumanProofExtensionOptions, CreateVerifyHumanProofHookOptions, ConfigureHumanProofServerOptions, } from './server.js';
|
|
3
|
+
export { HUMAN_PROOF, declareHumanProofExtension, getSignatureTypes } from './declare.js';
|
|
4
|
+
export { createPoUVerifier, DEFAULT_AGENT_OWNERSHIP_SCHEMA, DEFAULT_ATTESTATIONS_API_BASE_URL, } from './verifier.js';
|
|
5
|
+
export { verifyHumanProofRequest, HUMAN_PROOF_HEADER } from './hooks.js';
|
|
6
|
+
export type { HumanProofRequestContext, HumanProofRequestResult } from './hooks.js';
|
|
7
|
+
export type { HumanResolution, DeclareHumanProofOptions, HumanProofDeclaration, HumanVerifiedEvent, HumanNotRegisteredEvent, MaxUseExceededEvent, HumanProofEvent, PoUVerifierOptions, PoUVerifier, HumanUsageStorage, } from './types.js';
|
|
8
|
+
export { paywallInstructions } from './utils.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,aAAa,CAAA;AACpB,YAAY,EACV,gCAAgC,EAChC,iCAAiC,EACjC,gCAAgC,GACjC,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEzF,OAAO,EACL,iBAAiB,EACjB,8BAA8B,EAC9B,iCAAiC,GAClC,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AACxE,YAAY,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAEnF,YAAY,EACV,eAAe,EACf,wBAAwB,EACxB,qBAAqB,EACrB,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,iBAAiB,GAClB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { HumanProofEvent, HumanUsageStorage, PoUVerifier, PoUVerifierOptions } from './types.js';
|
|
2
|
+
import type { ResourceServerExtension } from '@x402/core/types';
|
|
3
|
+
import type { x402ResourceServer } from '@x402/core/server';
|
|
4
|
+
export type CreateHumanProofExtensionOptions = {
|
|
5
|
+
/** Must match the agentOwnershipSchema configured in your PoUVerifier, if customised. */
|
|
6
|
+
agentOwnershipSchema?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function createHumanProofExtension(options?: CreateHumanProofExtensionOptions): ResourceServerExtension;
|
|
9
|
+
export type CreateVerifyHumanProofHookOptions = {
|
|
10
|
+
verifier?: PoUVerifier;
|
|
11
|
+
verifierOptions?: PoUVerifierOptions;
|
|
12
|
+
onEvent?: (event: HumanProofEvent) => void | Promise<void>;
|
|
13
|
+
storage?: HumanUsageStorage;
|
|
14
|
+
};
|
|
15
|
+
export declare function createVerifyHumanProofHook(options?: CreateVerifyHumanProofHookOptions): (context: {
|
|
16
|
+
paymentPayload: {
|
|
17
|
+
extensions?: Record<string, unknown>;
|
|
18
|
+
resource?: {
|
|
19
|
+
url: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
requirements?: {
|
|
23
|
+
extra?: Record<string, unknown>;
|
|
24
|
+
};
|
|
25
|
+
}) => Promise<void | {
|
|
26
|
+
abort: true;
|
|
27
|
+
reason: string;
|
|
28
|
+
}>;
|
|
29
|
+
export type CreateAfterVerifyFailureRollbackHookOptions = {
|
|
30
|
+
storage: HumanUsageStorage;
|
|
31
|
+
verifier: PoUVerifier;
|
|
32
|
+
};
|
|
33
|
+
export declare function createAfterVerifyFailureRollbackHook(options: CreateAfterVerifyFailureRollbackHookOptions): (context: {
|
|
34
|
+
paymentPayload: {
|
|
35
|
+
extensions?: Record<string, unknown>;
|
|
36
|
+
resource?: {
|
|
37
|
+
url: string;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
requirements?: {
|
|
41
|
+
extra?: Record<string, unknown>;
|
|
42
|
+
};
|
|
43
|
+
result: {
|
|
44
|
+
isValid?: boolean;
|
|
45
|
+
};
|
|
46
|
+
}) => Promise<void>;
|
|
47
|
+
export type CreateVerifyFailureRollbackHookOptions = {
|
|
48
|
+
storage: HumanUsageStorage;
|
|
49
|
+
verifier: PoUVerifier;
|
|
50
|
+
};
|
|
51
|
+
export declare function createVerifyFailureRollbackHook(options: CreateVerifyFailureRollbackHookOptions): (context: {
|
|
52
|
+
paymentPayload: {
|
|
53
|
+
extensions?: Record<string, unknown>;
|
|
54
|
+
resource?: {
|
|
55
|
+
url: string;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
requirements?: {
|
|
59
|
+
extra?: Record<string, unknown>;
|
|
60
|
+
};
|
|
61
|
+
error?: Error;
|
|
62
|
+
}) => Promise<void>;
|
|
63
|
+
export type CreateSettleFailureRollbackHookOptions = {
|
|
64
|
+
storage: HumanUsageStorage;
|
|
65
|
+
verifier: PoUVerifier;
|
|
66
|
+
};
|
|
67
|
+
export declare function createSettleFailureRollbackHook(options: CreateSettleFailureRollbackHookOptions): (context: {
|
|
68
|
+
paymentPayload: {
|
|
69
|
+
extensions?: Record<string, unknown>;
|
|
70
|
+
resource?: {
|
|
71
|
+
url: string;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
requirements?: {
|
|
75
|
+
extra?: Record<string, unknown>;
|
|
76
|
+
};
|
|
77
|
+
error?: Error;
|
|
78
|
+
}) => Promise<void>;
|
|
79
|
+
export type ConfigureHumanProofServerOptions = {
|
|
80
|
+
extensionOptions?: CreateHumanProofExtensionOptions;
|
|
81
|
+
verifier?: PoUVerifier;
|
|
82
|
+
verifierOptions?: PoUVerifierOptions;
|
|
83
|
+
onEvent?: (event: HumanProofEvent) => void | Promise<void>;
|
|
84
|
+
storage?: HumanUsageStorage;
|
|
85
|
+
};
|
|
86
|
+
export declare function configureHumanProofServer(server: x402ResourceServer, options?: ConfigureHumanProofServerOptions): void;
|
|
87
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export type HumanResolution = {
|
|
2
|
+
humanId: string;
|
|
3
|
+
verifiedAt: string;
|
|
4
|
+
attestationId: string;
|
|
5
|
+
humanDid: string;
|
|
6
|
+
humanAddress: string;
|
|
7
|
+
agentDid: string;
|
|
8
|
+
agentAddress: string;
|
|
9
|
+
};
|
|
10
|
+
export type DeclareHumanProofOptions = {
|
|
11
|
+
statement?: string;
|
|
12
|
+
resourceUri?: string;
|
|
13
|
+
domain?: string;
|
|
14
|
+
version?: string;
|
|
15
|
+
expirationSeconds?: number;
|
|
16
|
+
network?: string | string[];
|
|
17
|
+
};
|
|
18
|
+
export type HumanProofDeclaration = {
|
|
19
|
+
_options: DeclareHumanProofOptions;
|
|
20
|
+
_type: 'human-proof';
|
|
21
|
+
};
|
|
22
|
+
export type HumanVerifiedEvent = {
|
|
23
|
+
type: 'human_verified';
|
|
24
|
+
resource: string;
|
|
25
|
+
humanId: string;
|
|
26
|
+
verifiedAt: string;
|
|
27
|
+
attestationId: string;
|
|
28
|
+
humanDid: string;
|
|
29
|
+
humanAddress: string;
|
|
30
|
+
agentDid: string;
|
|
31
|
+
agentAddress: string;
|
|
32
|
+
};
|
|
33
|
+
export type HumanNotRegisteredEvent = {
|
|
34
|
+
type: 'human_not_registered';
|
|
35
|
+
resource: string;
|
|
36
|
+
did: string;
|
|
37
|
+
};
|
|
38
|
+
export type MaxUseExceededEvent = {
|
|
39
|
+
type: 'max_use_exceeded';
|
|
40
|
+
resource: string;
|
|
41
|
+
humanId: string;
|
|
42
|
+
maxUse: number;
|
|
43
|
+
};
|
|
44
|
+
export type HumanProofEvent = HumanVerifiedEvent | HumanNotRegisteredEvent | MaxUseExceededEvent;
|
|
45
|
+
export type PoUVerifierOptions = {
|
|
46
|
+
/**
|
|
47
|
+
* Optional override for the attestation check implementation.
|
|
48
|
+
* If not provided, queries the Billions Network explorer API.
|
|
49
|
+
* For full customisation (including human lookup), implement the PoUVerifier
|
|
50
|
+
* interface directly and pass it via CreateVerifyHumanProofHookOptions.verifier.
|
|
51
|
+
*/
|
|
52
|
+
hasAttestation?: (did: string, chainId: string, schema: string) => Promise<boolean>;
|
|
53
|
+
/** Override the attestations API base URL. Defaults to the Billions Network explorer. */
|
|
54
|
+
attestationsApiBaseUrl?: string;
|
|
55
|
+
/** Override the agent-ownership schema ID used for human registry lookups. */
|
|
56
|
+
agentOwnershipSchema?: string;
|
|
57
|
+
/** Override the nullifier API base URL. Defaults to the Billions Network nullifier endpoint. */
|
|
58
|
+
nullifierApiBaseUrl?: string;
|
|
59
|
+
};
|
|
60
|
+
export interface HumanUsageStorage {
|
|
61
|
+
/**
|
|
62
|
+
* Atomically increments the usage count for (humanId, scope) only if the
|
|
63
|
+
* current count is strictly below maxUse, and returns the new count.
|
|
64
|
+
* Returns null if the limit was already reached (no increment is performed).
|
|
65
|
+
*
|
|
66
|
+
* `scope` isolates counters per resource so that a limit on one route does
|
|
67
|
+
* not consume quota for another. Typically the resource URL, but callers may
|
|
68
|
+
* supply any stable key (e.g. a route ID or accept-option identifier).
|
|
69
|
+
*
|
|
70
|
+
* Implementations must be a single atomic operation so concurrent requests
|
|
71
|
+
* cannot both pass the limit check:
|
|
72
|
+
* - Redis: Lua script (GET + conditional INCR), key = `${humanId}:${scope}`
|
|
73
|
+
* - SQL: UPDATE human_usage SET count = count + 1 WHERE human_id = ? AND scope = ? AND count < ? RETURNING count
|
|
74
|
+
*/
|
|
75
|
+
incrementIfBelow(humanId: string, maxUse: number, scope: string): Promise<number | null>;
|
|
76
|
+
/**
|
|
77
|
+
* Decrements usage for (humanId, scope) if current value is above zero.
|
|
78
|
+
* Returns the new count, or null if no decrement was performed.
|
|
79
|
+
*/
|
|
80
|
+
decrementIfAboveZero(humanId: string, scope: string): Promise<number | null>;
|
|
81
|
+
}
|
|
82
|
+
export interface PoUVerifier {
|
|
83
|
+
/**
|
|
84
|
+
* The schema ID used to determine human registration (checked by lookupHuman).
|
|
85
|
+
* Used by hooks to skip redundant hasAttestation calls for this schema.
|
|
86
|
+
*/
|
|
87
|
+
ownershipSchema: string;
|
|
88
|
+
/**
|
|
89
|
+
* Resolve an agent DID to its verified human record.
|
|
90
|
+
* Returns null if the DID is not registered in the PoU registry.
|
|
91
|
+
*/
|
|
92
|
+
lookupHuman(did: string, chainId: string): Promise<HumanResolution | null>;
|
|
93
|
+
/**
|
|
94
|
+
* Check whether a DID holds a specific attestation schema.
|
|
95
|
+
* Returns true if the attestation exists, false otherwise.
|
|
96
|
+
*/
|
|
97
|
+
hasAttestation?(did: string, chainId: string, schema: string): Promise<boolean>;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC5B,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,wBAAwB,CAAA;IAClC,KAAK,EAAE,aAAa,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,gBAAgB,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,sBAAsB,CAAA;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,kBAAkB,CAAA;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,kBAAkB,GAAG,uBAAuB,GAAG,mBAAmB,CAAA;AAGhG,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACnF,yFAAyF;IACzF,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,8EAA8E;IAC9E,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,gGAAgG;IAChG,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAA;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;;;;;;OAaG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAExF;;;OAGG;IACH,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;CAC7E;AAED,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,eAAe,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAA;IAC1E;;;OAGG;IACH,cAAc,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAChF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { PaywallProvider } from '@x402/core/server';
|
|
2
|
+
export type SignatureType = 'eip191' | 'ed25519';
|
|
3
|
+
export type SupportedChain = {
|
|
4
|
+
chainId: string;
|
|
5
|
+
type: SignatureType;
|
|
6
|
+
};
|
|
7
|
+
export type HumanProofExtensionInfo = {
|
|
8
|
+
domain: string;
|
|
9
|
+
uri?: string;
|
|
10
|
+
version: string;
|
|
11
|
+
nonce: string;
|
|
12
|
+
issuedAt: string;
|
|
13
|
+
expirationTime?: string;
|
|
14
|
+
statement?: string;
|
|
15
|
+
resources?: string[];
|
|
16
|
+
requiredAttestations: string[];
|
|
17
|
+
};
|
|
18
|
+
export type HumanProofExtensionPayload = HumanProofExtensionInfo & {
|
|
19
|
+
chainId: string;
|
|
20
|
+
type: SignatureType;
|
|
21
|
+
address: string;
|
|
22
|
+
signature: string;
|
|
23
|
+
};
|
|
24
|
+
type ValidationResult = {
|
|
25
|
+
valid: boolean;
|
|
26
|
+
error?: string;
|
|
27
|
+
};
|
|
28
|
+
type SignatureVerificationResult = {
|
|
29
|
+
valid: boolean;
|
|
30
|
+
address?: string;
|
|
31
|
+
pubKey?: string;
|
|
32
|
+
error?: string;
|
|
33
|
+
};
|
|
34
|
+
export declare function buildHumanProofSchema(): Record<string, unknown>;
|
|
35
|
+
export declare function parseHumanProofHeader(headerValue: string): HumanProofExtensionPayload;
|
|
36
|
+
export declare function validateHumanProofMessage(payload: HumanProofExtensionPayload, resource: string): Promise<ValidationResult>;
|
|
37
|
+
export declare function verifyHumanProofSignature(payload: HumanProofExtensionPayload): Promise<SignatureVerificationResult>;
|
|
38
|
+
export declare function paywallInstructions(html?: string): PaywallProvider;
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAGxD,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAA;AAEhD,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,aAAa,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,oBAAoB,EAAE,MAAM,EAAE,CAAA;CAC/B,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG,uBAAuB,GAAG;IACjE,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,aAAa,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,KAAK,gBAAgB,GAAG;IACtB,KAAK,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,KAAK,2BAA2B,GAAG;IACjC,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AA8CD,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAqB/D;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,0BAA0B,CAYrF;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,0BAA0B,EACnC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,gBAAgB,CAAC,CAyB3B;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,2BAA2B,CAAC,CAoCtC;AAYD,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,eAAe,CAMlE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PoUVerifier, PoUVerifierOptions } from './types.js';
|
|
2
|
+
export declare const DEFAULT_ATTESTATIONS_API_BASE_URL = "https://attestations-api.billions.network/api/v1/attestations";
|
|
3
|
+
export declare const DEFAULT_NULLIFIER_API_BASE_URL = "https://attestations-api.billions.network/api/v1/nullifier";
|
|
4
|
+
export declare const DEFAULT_AGENT_OWNERSHIP_SCHEMA = "0xca354bee6dc5eded165461d15ccb13aceb6f77ebbb1fd3fe45aca686097f2911";
|
|
5
|
+
/**
|
|
6
|
+
* Creates a PoU (Proof of Uniqueness) verifier that resolves a DID
|
|
7
|
+
* to a HumanResolution.
|
|
8
|
+
* @example
|
|
9
|
+
* const verifier = createPoUVerifier()
|
|
10
|
+
* const resolution = await verifier.lookupHuman('did:iden3:...', 'eip155:137')
|
|
11
|
+
*/
|
|
12
|
+
export declare function createPoUVerifier(options?: PoUVerifierOptions): PoUVerifier;
|
|
13
|
+
//# sourceMappingURL=verifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../../src/verifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,WAAW,EACX,kBAAkB,EACnB,MAAM,YAAY,CAAA;AAEnB,eAAO,MAAM,iCAAiC,kEACmB,CAAA;AAEjE,eAAO,MAAM,8BAA8B,+DACmB,CAAA;AAE9D,eAAO,MAAM,8BAA8B,uEAC2B,CAAA;AAwFtE;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAoB/E"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@billionsnetwork/x402-human-proof",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"license": "UNLICENSED",
|
|
5
|
+
"description": "Server SDK for the x402 human-proof extension — human verification for API providers using signature verification and PoU registry lookups",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/node/cjs/index.cjs",
|
|
8
|
+
"types": "./dist/types/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/types/index.d.ts",
|
|
12
|
+
"node": {
|
|
13
|
+
"import": "./dist/node/esm/index.js",
|
|
14
|
+
"require": "./dist/node/cjs/index.cjs"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=20.11.0"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup --config tsup.config.ts && tsc --emitDeclarationOnly --declaration --declarationMap --outDir dist/types",
|
|
26
|
+
"dev": "tsup --watch"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@0xpolygonid/js-sdk": "^1.43.0",
|
|
30
|
+
"@iden3/js-iden3-core": "^1.8.0",
|
|
31
|
+
"@x402/core": "^2.8.0",
|
|
32
|
+
"bs58": "^6.0.0",
|
|
33
|
+
"tweetnacl": "^1.0.3",
|
|
34
|
+
"viem": "^2.37.5"
|
|
35
|
+
}
|
|
36
|
+
}
|