@orangecheck/agent-signer 0.1.0 → 0.3.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 +4 -0
- package/dist/index.d.mts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +24 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +25 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +60 -57
- package/src/index.ts +66 -2
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# @orangecheck/agent-signer
|
|
2
2
|
|
|
3
|
+
> **Full reference:** [docs.ochk.io/sdk/agent-signer](https://docs.ochk.io/sdk/agent-signer) — auto-generated from the TypeScript source on every release.
|
|
4
|
+
> Hand-written prose below is the high-level overview; the docs site is the source of truth for every export, type, and signature.
|
|
5
|
+
|
|
6
|
+
|
|
3
7
|
High-level API for producing [OC Agent](https://github.com/orangecheck/oc-agent-protocol) envelopes from a BIP-322-capable signer.
|
|
4
8
|
|
|
5
9
|
Three functions:
|
package/dist/index.d.mts
CHANGED
|
@@ -17,6 +17,16 @@ interface CreateDelegationInput {
|
|
|
17
17
|
revocationHolders?: RevocationHolder[];
|
|
18
18
|
revocationRef?: string | null;
|
|
19
19
|
scopeMode?: ValidationOptions['mode'];
|
|
20
|
+
privateScopes?: {
|
|
21
|
+
recipients: PrivateScopeRecipient[];
|
|
22
|
+
hint?: string;
|
|
23
|
+
envelopeExpiresAt?: Date | null;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
interface PrivateScopeRecipient {
|
|
27
|
+
address: string;
|
|
28
|
+
device_id: string;
|
|
29
|
+
device_pk: string;
|
|
20
30
|
}
|
|
21
31
|
declare function createDelegation(input: CreateDelegationInput): Promise<DelegationEnvelope>;
|
|
22
32
|
interface SignAsAgentInput {
|
|
@@ -42,4 +52,4 @@ interface RevokeInput {
|
|
|
42
52
|
}
|
|
43
53
|
declare function revoke(input: RevokeInput): Promise<RevocationEnvelope>;
|
|
44
54
|
|
|
45
|
-
export { type CreateDelegationInput, type RevokeInput, type SignAsAgentInput, type SignerRef, createDelegation, revoke, signAsAgent };
|
|
55
|
+
export { type CreateDelegationInput, type PrivateScopeRecipient, type RevokeInput, type SignAsAgentInput, type SignerRef, createDelegation, revoke, signAsAgent };
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,16 @@ interface CreateDelegationInput {
|
|
|
17
17
|
revocationHolders?: RevocationHolder[];
|
|
18
18
|
revocationRef?: string | null;
|
|
19
19
|
scopeMode?: ValidationOptions['mode'];
|
|
20
|
+
privateScopes?: {
|
|
21
|
+
recipients: PrivateScopeRecipient[];
|
|
22
|
+
hint?: string;
|
|
23
|
+
envelopeExpiresAt?: Date | null;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
interface PrivateScopeRecipient {
|
|
27
|
+
address: string;
|
|
28
|
+
device_id: string;
|
|
29
|
+
device_pk: string;
|
|
20
30
|
}
|
|
21
31
|
declare function createDelegation(input: CreateDelegationInput): Promise<DelegationEnvelope>;
|
|
22
32
|
interface SignAsAgentInput {
|
|
@@ -42,4 +52,4 @@ interface RevokeInput {
|
|
|
42
52
|
}
|
|
43
53
|
declare function revoke(input: RevokeInput): Promise<RevocationEnvelope>;
|
|
44
54
|
|
|
45
|
-
export { type CreateDelegationInput, type RevokeInput, type SignAsAgentInput, type SignerRef, createDelegation, revoke, signAsAgent };
|
|
55
|
+
export { type CreateDelegationInput, type PrivateScopeRecipient, type RevokeInput, type SignAsAgentInput, type SignerRef, createDelegation, revoke, signAsAgent };
|
package/dist/index.js
CHANGED
|
@@ -49,6 +49,28 @@ async function createDelegation(input) {
|
|
|
49
49
|
nonce
|
|
50
50
|
};
|
|
51
51
|
const id = agentCore.computeDelegationId(canonInput);
|
|
52
|
+
let scopesEncrypted;
|
|
53
|
+
if (input.privateScopes) {
|
|
54
|
+
if (!input.privateScopes.recipients || input.privateScopes.recipients.length === 0) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
"createDelegation: privateScopes.recipients must contain at least the agent device"
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
scopesEncrypted = await agentCore.sealScopes({
|
|
60
|
+
scopes,
|
|
61
|
+
sender: {
|
|
62
|
+
address: input.principal.address,
|
|
63
|
+
signMessage: input.principal.signMessage
|
|
64
|
+
},
|
|
65
|
+
recipients: input.privateScopes.recipients,
|
|
66
|
+
...input.privateScopes.hint !== void 0 && {
|
|
67
|
+
hint: input.privateScopes.hint
|
|
68
|
+
},
|
|
69
|
+
...input.privateScopes.envelopeExpiresAt !== void 0 && {
|
|
70
|
+
expiresAt: input.privateScopes.envelopeExpiresAt
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
52
74
|
const sigValue = await input.principal.signMessage(id);
|
|
53
75
|
const envelope = {
|
|
54
76
|
v: agentCore.ENVELOPE_VERSION,
|
|
@@ -56,7 +78,8 @@ async function createDelegation(input) {
|
|
|
56
78
|
id,
|
|
57
79
|
principal: { address: input.principal.address, alg: "bip322" },
|
|
58
80
|
agent: { address: input.agentAddress, alg: "bip322" },
|
|
59
|
-
|
|
81
|
+
// Public OR private mode — never both. PRIVATE-SCOPE.md §1.1.
|
|
82
|
+
...scopesEncrypted ? { scopes_encrypted: scopesEncrypted } : { scopes },
|
|
60
83
|
bond,
|
|
61
84
|
issued_at: issuedAt,
|
|
62
85
|
expires_at: expiresAt,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["validateScope","parseScope","canonicalizeScopes","computeDelegationId","ENVELOPE_VERSION","hexEncode","sha256","computeActionId","computeRevocationId"],"mappings":"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","file":"index.js","sourcesContent":["// @orangecheck/agent-signer — high-level API for producing OC Agent envelopes.\n//\n// createDelegation — principal signs a scoped grant to an agent address.\n// signAsAgent — agent produces an agent-action envelope over content.\n// revoke — principal (or agent, if authorized) burns a delegation.\n//\n// Each function wraps @orangecheck/agent-core's canonical-message + id\n// computation with a caller-supplied `signMessage` wallet adapter. Nothing here\n// touches the network — OTS anchoring and Nostr publication are separate steps\n// the caller wires up.\n\nimport { sha256 } from '@noble/hashes/sha256';\nimport {\n canonicalizeScopes,\n computeActionId,\n computeDelegationId,\n computeRevocationId,\n ENVELOPE_VERSION,\n hexEncode,\n parseScope,\n validateScope,\n} from '@orangecheck/agent-core';\nimport type { ValidationOptions } from '@orangecheck/agent-core';\nimport type {\n ActionEnvelope,\n ActionOts,\n DelegationBond,\n DelegationEnvelope,\n RevocationEnvelope,\n RevocationHolder,\n} from '@orangecheck/agent-core';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Shared wallet-adapter shape (matches `@orangecheck/stamp-core` StampInput).\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SignerRef {\n address: string;\n /** Returns a base64 BIP-322 signature over the given message as UTF-8 bytes. */\n signMessage: (msg: string) => Promise<string>;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// createDelegation\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface CreateDelegationInput {\n principal: SignerRef;\n agentAddress: string;\n scopes: string[];\n bond?: DelegationBond | null;\n issuedAt?: Date;\n /** Duration from issuedAt in ms. Default 7 days. MAX 365 days per SPEC §4.4. */\n ttlMs?: number;\n /** Explicit expires_at overrides ttlMs. */\n expiresAt?: Date;\n /** 32-hex. Defaults to crypto.getRandomValues(16-byte) rendered as hex. */\n nonce?: string;\n /** Default ['principal']. */\n revocationHolders?: RevocationHolder[];\n /** Optional Nostr pointer to a revocation event. Non-cryptographic. */\n revocationRef?: string | null;\n /** Default 'strict'. 'permissive' allows unregistered scopes / constraint keys. */\n scopeMode?: ValidationOptions['mode'];\n}\n\nexport async function createDelegation(input: CreateDelegationInput): Promise<DelegationEnvelope> {\n if (!input.scopes || input.scopes.length === 0) {\n throw new Error('createDelegation: at least one scope is required');\n }\n const mode = input.scopeMode ?? 'strict';\n for (const s of input.scopes) validateScope(parseScope(s), { mode });\n const scopes = canonicalizeScopes(input.scopes);\n\n const issuedAt = isoUtcSeconds(input.issuedAt ?? new Date());\n let expiresAtDate: Date;\n if (input.expiresAt) {\n expiresAtDate = input.expiresAt;\n } else {\n const ttl = input.ttlMs ?? 7 * 24 * 60 * 60 * 1000;\n expiresAtDate = new Date(new Date(issuedAt).getTime() + ttl);\n }\n const expiresAt = isoUtcSeconds(expiresAtDate);\n\n const durationMs = new Date(expiresAt).getTime() - new Date(issuedAt).getTime();\n if (durationMs <= 0) throw new Error('createDelegation: expires_at must be after issued_at');\n if (durationMs > 365 * 24 * 60 * 60 * 1000) {\n throw new Error('createDelegation: delegation duration must not exceed 365 days');\n }\n\n const nonce = input.nonce ?? randomHex(16);\n if (!/^[0-9a-f]{32}$/.test(nonce)) {\n throw new Error('createDelegation: nonce must be 32 lowercase hex chars');\n }\n\n const bond = input.bond ?? null;\n if (bond) {\n if (!Number.isInteger(bond.sats) || bond.sats < 0) {\n throw new Error('createDelegation: bond.sats must be a non-negative integer');\n }\n if (!/^[0-9a-f]{64}$/.test(bond.attestation_id)) {\n throw new Error('createDelegation: bond.attestation_id must be 64 lowercase hex chars');\n }\n }\n\n const canonInput = {\n principal: input.principal.address,\n agent: input.agentAddress,\n scopes,\n bond_sats: bond?.sats ?? 0,\n bond_attestation: bond?.attestation_id ?? 'none',\n issued_at: issuedAt,\n expires_at: expiresAt,\n nonce,\n };\n const id = computeDelegationId(canonInput);\n\n const sigValue = await input.principal.signMessage(id);\n\n const envelope: DelegationEnvelope = {\n v: ENVELOPE_VERSION,\n kind: 'agent-delegation',\n id,\n principal: { address: input.principal.address, alg: 'bip322' },\n agent: { address: input.agentAddress, alg: 'bip322' },\n scopes,\n bond,\n issued_at: issuedAt,\n expires_at: expiresAt,\n nonce,\n revocation: {\n holders: input.revocationHolders ?? ['principal'],\n ref: input.revocationRef ?? null,\n },\n sig: {\n alg: 'bip322',\n pubkey: input.principal.address,\n value: sigValue,\n },\n };\n return envelope;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// signAsAgent\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SignAsAgentInput {\n agent: SignerRef;\n delegation: DelegationEnvelope;\n /** Raw bytes to stamp, or a pre-computed { hash, length } pair. */\n content: Uint8Array | { hash: string; length: number };\n mime: string;\n /** Which scope from delegation.scopes is being exercised (or a narrower sub-scope). */\n scopeExercised: string;\n ref?: string | null;\n signedAt?: Date;\n /** OTS proof / anchor data if the caller has already submitted; otherwise null. */\n ots?: ActionOts | null;\n}\n\nexport async function signAsAgent(input: SignAsAgentInput): Promise<ActionEnvelope> {\n if (input.agent.address !== input.delegation.agent.address) {\n throw new Error('signAsAgent: signer address does not match delegation.agent.address');\n }\n\n let contentHash: string;\n let contentLength: number;\n if (input.content instanceof Uint8Array) {\n contentHash = 'sha256:' + hexEncode(sha256(input.content));\n contentLength = input.content.byteLength;\n } else {\n if (!input.content.hash.startsWith('sha256:') || input.content.hash.length !== 'sha256:'.length + 64) {\n throw new Error('signAsAgent: content.hash must be \"sha256:\" + 64 lowercase hex chars');\n }\n contentHash = input.content.hash;\n contentLength = input.content.length;\n if (!Number.isInteger(contentLength) || contentLength < 0) {\n throw new Error('signAsAgent: content.length must be a non-negative integer');\n }\n }\n\n const signedAt = isoUtcSeconds(input.signedAt ?? new Date());\n\n const canonInput = {\n address: input.agent.address,\n content_hash: contentHash,\n content_length: contentLength,\n content_mime: input.mime,\n signed_at: signedAt,\n delegation_id: input.delegation.id,\n scope_exercised: input.scopeExercised,\n };\n const id = computeActionId(canonInput);\n\n const sigValue = await input.agent.signMessage(id);\n\n const envelope: ActionEnvelope = {\n v: ENVELOPE_VERSION,\n kind: 'agent-action',\n id,\n content: {\n hash: contentHash,\n length: contentLength,\n mime: input.mime,\n ref: input.ref ?? null,\n },\n signer: { address: input.agent.address, alg: 'bip322' },\n signed_at: signedAt,\n delegation_id: input.delegation.id,\n scope_exercised: input.scopeExercised,\n ots: input.ots ?? null,\n sig: { alg: 'bip322', pubkey: input.agent.address, value: sigValue },\n };\n return envelope;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// revoke\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface RevokeInput {\n signer: SignerRef;\n delegation: DelegationEnvelope;\n /** Short ASCII rationale. Defaults to empty string. */\n reason?: string;\n signedAt?: Date;\n /** OTS proof / anchor data if the caller has already submitted; otherwise null. */\n ots?: ActionOts | null;\n}\n\nexport async function revoke(input: RevokeInput): Promise<RevocationEnvelope> {\n const holders = input.delegation.revocation?.holders ?? ['principal'];\n const allowed = new Set<string>();\n if (holders.includes('principal')) allowed.add(input.delegation.principal.address);\n if (holders.includes('agent')) allowed.add(input.delegation.agent.address);\n if (!allowed.has(input.signer.address)) {\n throw new Error(\n `revoke: signer ${input.signer.address} not authorized to revoke this delegation`\n );\n }\n\n const reason = input.reason ?? '';\n if (reason.length > 128) throw new Error('revoke: reason must be <=128 bytes');\n\n const signedAt = isoUtcSeconds(input.signedAt ?? new Date());\n const canonInput = {\n address: input.signer.address,\n delegation_id: input.delegation.id,\n reason,\n signed_at: signedAt,\n };\n const id = computeRevocationId(canonInput);\n\n const sigValue = await input.signer.signMessage(id);\n\n const envelope: RevocationEnvelope = {\n v: ENVELOPE_VERSION,\n kind: 'agent-revocation',\n id,\n delegation_id: input.delegation.id,\n signer: { address: input.signer.address, alg: 'bip322' },\n reason,\n signed_at: signedAt,\n ots: input.ots ?? null,\n sig: { alg: 'bip322', pubkey: input.signer.address, value: sigValue },\n };\n return envelope;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Re-exports for convenience\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport {\n canonicalizeScopes,\n computeActionId,\n computeDelegationId,\n computeRevocationId,\n verifyAction,\n verifyDelegation,\n verifyRevocation,\n parseScope,\n isSubScope,\n canonicalizeScope,\n REGISTERED_SCOPES,\n} from '@orangecheck/agent-core';\nexport type {\n ActionEnvelope,\n ActionOts,\n DelegationBond,\n DelegationEnvelope,\n RevocationEnvelope,\n Scope,\n ScopeConstraint,\n AgentErrorCode,\n} from '@orangecheck/agent-core';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction isoUtcSeconds(d: Date): string {\n return d.toISOString().replace(/\\.\\d+Z$/, 'Z');\n}\n\nfunction randomHex(bytes: number): string {\n const buf = new Uint8Array(bytes);\n const c: Crypto | undefined = (globalThis as unknown as { crypto?: Crypto }).crypto;\n if (c && typeof c.getRandomValues === 'function') {\n c.getRandomValues(buf);\n } else {\n // Non-browser fallback. Node ≥18 exposes globalThis.crypto, so this is unlikely to fire.\n for (let i = 0; i < bytes; i++) buf[i] = Math.floor(Math.random() * 256);\n }\n let out = '';\n for (let i = 0; i < bytes; i++) {\n const b = buf[i]!;\n out += b.toString(16).padStart(2, '0');\n }\n return out;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["validateScope","parseScope","canonicalizeScopes","computeDelegationId","sealScopes","ENVELOPE_VERSION","hexEncode","sha256","computeActionId","computeRevocationId"],"mappings":"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","file":"index.js","sourcesContent":["// @orangecheck/agent-signer — high-level API for producing OC Agent envelopes.\n//\n// createDelegation — principal signs a scoped grant to an agent address.\n// signAsAgent — agent produces an agent-action envelope over content.\n// revoke — principal (or agent, if authorized) burns a delegation.\n//\n// Each function wraps @orangecheck/agent-core's canonical-message + id\n// computation with a caller-supplied `signMessage` wallet adapter. Nothing here\n// touches the network — OTS anchoring and Nostr publication are separate steps\n// the caller wires up.\n\nimport { sha256 } from '@noble/hashes/sha256';\nimport {\n canonicalizeScopes,\n computeActionId,\n computeDelegationId,\n computeRevocationId,\n ENVELOPE_VERSION,\n hexEncode,\n parseScope,\n sealScopes,\n validateScope,\n} from '@orangecheck/agent-core';\nimport type {\n ScopesEncryptedEnvelope,\n ValidationOptions,\n} from '@orangecheck/agent-core';\nimport type {\n ActionEnvelope,\n ActionOts,\n DelegationBond,\n DelegationEnvelope,\n RevocationEnvelope,\n RevocationHolder,\n} from '@orangecheck/agent-core';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Shared wallet-adapter shape (matches `@orangecheck/stamp-core` StampInput).\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SignerRef {\n address: string;\n /** Returns a base64 BIP-322 signature over the given message as UTF-8 bytes. */\n signMessage: (msg: string) => Promise<string>;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// createDelegation\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface CreateDelegationInput {\n principal: SignerRef;\n agentAddress: string;\n scopes: string[];\n bond?: DelegationBond | null;\n issuedAt?: Date;\n /** Duration from issuedAt in ms. Default 7 days. MAX 365 days per SPEC §4.4. */\n ttlMs?: number;\n /** Explicit expires_at overrides ttlMs. */\n expiresAt?: Date;\n /** 32-hex. Defaults to crypto.getRandomValues(16-byte) rendered as hex. */\n nonce?: string;\n /** Default ['principal']. */\n revocationHolders?: RevocationHolder[];\n /** Optional Nostr pointer to a revocation event. Non-cryptographic. */\n revocationRef?: string | null;\n /** Default 'strict'. 'permissive' allows unregistered scopes / constraint keys. */\n scopeMode?: ValidationOptions['mode'];\n /**\n * v1.2 private-scope (PRIVATE-SCOPE.md). When supplied, the resulting\n * delegation envelope omits the public `scopes` field and instead carries\n * `scopes_encrypted` — an OC Lock envelope wrapping the canonical scope\n * list, sealed to one or more recipient device keys. The principal signs\n * BOTH the inner OC Lock envelope (via the `signMessage` callback already\n * provided on `principal`) AND the outer OC Agent canonical message.\n *\n * Recipients MUST include at least the agent's device. Additional\n * recipients (compliance auditors, third-party verifiers) are optional.\n */\n privateScopes?: {\n /**\n * Devices authorized to read the scope set. Each is `{ address,\n * device_id, device_pk }` matching OC Lock's `DeviceRecord` shape.\n * The same `signMessage` callback on `principal` is used to sign the\n * inner OC Lock envelope.\n */\n recipients: PrivateScopeRecipient[];\n /** Optional human hint stored in the OC Lock envelope. */\n hint?: string;\n /** Optional expiry on the OC Lock envelope. Independent of the\n * delegation's expires_at; usually left unset. */\n envelopeExpiresAt?: Date | null;\n };\n}\n\n/** Mirror of @orangecheck/lock-core's DeviceRecord. */\nexport interface PrivateScopeRecipient {\n address: string;\n device_id: string;\n /** 32-byte hex X25519 public key. */\n device_pk: string;\n}\n\nexport async function createDelegation(input: CreateDelegationInput): Promise<DelegationEnvelope> {\n if (!input.scopes || input.scopes.length === 0) {\n throw new Error('createDelegation: at least one scope is required');\n }\n const mode = input.scopeMode ?? 'strict';\n for (const s of input.scopes) validateScope(parseScope(s), { mode });\n const scopes = canonicalizeScopes(input.scopes);\n\n const issuedAt = isoUtcSeconds(input.issuedAt ?? new Date());\n let expiresAtDate: Date;\n if (input.expiresAt) {\n expiresAtDate = input.expiresAt;\n } else {\n const ttl = input.ttlMs ?? 7 * 24 * 60 * 60 * 1000;\n expiresAtDate = new Date(new Date(issuedAt).getTime() + ttl);\n }\n const expiresAt = isoUtcSeconds(expiresAtDate);\n\n const durationMs = new Date(expiresAt).getTime() - new Date(issuedAt).getTime();\n if (durationMs <= 0) throw new Error('createDelegation: expires_at must be after issued_at');\n if (durationMs > 365 * 24 * 60 * 60 * 1000) {\n throw new Error('createDelegation: delegation duration must not exceed 365 days');\n }\n\n const nonce = input.nonce ?? randomHex(16);\n if (!/^[0-9a-f]{32}$/.test(nonce)) {\n throw new Error('createDelegation: nonce must be 32 lowercase hex chars');\n }\n\n const bond = input.bond ?? null;\n if (bond) {\n if (!Number.isInteger(bond.sats) || bond.sats < 0) {\n throw new Error('createDelegation: bond.sats must be a non-negative integer');\n }\n if (!/^[0-9a-f]{64}$/.test(bond.attestation_id)) {\n throw new Error('createDelegation: bond.attestation_id must be 64 lowercase hex chars');\n }\n }\n\n const canonInput = {\n principal: input.principal.address,\n agent: input.agentAddress,\n scopes,\n bond_sats: bond?.sats ?? 0,\n bond_attestation: bond?.attestation_id ?? 'none',\n issued_at: issuedAt,\n expires_at: expiresAt,\n nonce,\n };\n const id = computeDelegationId(canonInput);\n\n // v1.2 private-scope: seal BEFORE the principal's outer signature so the\n // user's wallet sees both prompts in a deterministic order (inner Lock\n // sig first, outer OC Agent sig second).\n let scopesEncrypted: ScopesEncryptedEnvelope | undefined;\n if (input.privateScopes) {\n if (!input.privateScopes.recipients || input.privateScopes.recipients.length === 0) {\n throw new Error(\n 'createDelegation: privateScopes.recipients must contain at least the agent device'\n );\n }\n scopesEncrypted = await sealScopes({\n scopes,\n sender: {\n address: input.principal.address,\n signMessage: input.principal.signMessage,\n },\n recipients: input.privateScopes.recipients,\n ...(input.privateScopes.hint !== undefined && {\n hint: input.privateScopes.hint,\n }),\n ...(input.privateScopes.envelopeExpiresAt !== undefined && {\n expiresAt: input.privateScopes.envelopeExpiresAt,\n }),\n });\n }\n\n const sigValue = await input.principal.signMessage(id);\n\n const envelope: DelegationEnvelope = {\n v: ENVELOPE_VERSION,\n kind: 'agent-delegation',\n id,\n principal: { address: input.principal.address, alg: 'bip322' },\n agent: { address: input.agentAddress, alg: 'bip322' },\n // Public OR private mode — never both. PRIVATE-SCOPE.md §1.1.\n ...(scopesEncrypted ? { scopes_encrypted: scopesEncrypted } : { scopes }),\n bond,\n issued_at: issuedAt,\n expires_at: expiresAt,\n nonce,\n revocation: {\n holders: input.revocationHolders ?? ['principal'],\n ref: input.revocationRef ?? null,\n },\n sig: {\n alg: 'bip322',\n pubkey: input.principal.address,\n value: sigValue,\n },\n };\n return envelope;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// signAsAgent\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SignAsAgentInput {\n agent: SignerRef;\n delegation: DelegationEnvelope;\n /** Raw bytes to stamp, or a pre-computed { hash, length } pair. */\n content: Uint8Array | { hash: string; length: number };\n mime: string;\n /** Which scope from delegation.scopes is being exercised (or a narrower sub-scope). */\n scopeExercised: string;\n ref?: string | null;\n signedAt?: Date;\n /** OTS proof / anchor data if the caller has already submitted; otherwise null. */\n ots?: ActionOts | null;\n}\n\nexport async function signAsAgent(input: SignAsAgentInput): Promise<ActionEnvelope> {\n if (input.agent.address !== input.delegation.agent.address) {\n throw new Error('signAsAgent: signer address does not match delegation.agent.address');\n }\n\n let contentHash: string;\n let contentLength: number;\n if (input.content instanceof Uint8Array) {\n contentHash = 'sha256:' + hexEncode(sha256(input.content));\n contentLength = input.content.byteLength;\n } else {\n if (!input.content.hash.startsWith('sha256:') || input.content.hash.length !== 'sha256:'.length + 64) {\n throw new Error('signAsAgent: content.hash must be \"sha256:\" + 64 lowercase hex chars');\n }\n contentHash = input.content.hash;\n contentLength = input.content.length;\n if (!Number.isInteger(contentLength) || contentLength < 0) {\n throw new Error('signAsAgent: content.length must be a non-negative integer');\n }\n }\n\n const signedAt = isoUtcSeconds(input.signedAt ?? new Date());\n\n const canonInput = {\n address: input.agent.address,\n content_hash: contentHash,\n content_length: contentLength,\n content_mime: input.mime,\n signed_at: signedAt,\n delegation_id: input.delegation.id,\n scope_exercised: input.scopeExercised,\n };\n const id = computeActionId(canonInput);\n\n const sigValue = await input.agent.signMessage(id);\n\n const envelope: ActionEnvelope = {\n v: ENVELOPE_VERSION,\n kind: 'agent-action',\n id,\n content: {\n hash: contentHash,\n length: contentLength,\n mime: input.mime,\n ref: input.ref ?? null,\n },\n signer: { address: input.agent.address, alg: 'bip322' },\n signed_at: signedAt,\n delegation_id: input.delegation.id,\n scope_exercised: input.scopeExercised,\n ots: input.ots ?? null,\n sig: { alg: 'bip322', pubkey: input.agent.address, value: sigValue },\n };\n return envelope;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// revoke\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface RevokeInput {\n signer: SignerRef;\n delegation: DelegationEnvelope;\n /** Short ASCII rationale. Defaults to empty string. */\n reason?: string;\n signedAt?: Date;\n /** OTS proof / anchor data if the caller has already submitted; otherwise null. */\n ots?: ActionOts | null;\n}\n\nexport async function revoke(input: RevokeInput): Promise<RevocationEnvelope> {\n const holders = input.delegation.revocation?.holders ?? ['principal'];\n const allowed = new Set<string>();\n if (holders.includes('principal')) allowed.add(input.delegation.principal.address);\n if (holders.includes('agent')) allowed.add(input.delegation.agent.address);\n if (!allowed.has(input.signer.address)) {\n throw new Error(\n `revoke: signer ${input.signer.address} not authorized to revoke this delegation`\n );\n }\n\n const reason = input.reason ?? '';\n if (reason.length > 128) throw new Error('revoke: reason must be <=128 bytes');\n\n const signedAt = isoUtcSeconds(input.signedAt ?? new Date());\n const canonInput = {\n address: input.signer.address,\n delegation_id: input.delegation.id,\n reason,\n signed_at: signedAt,\n };\n const id = computeRevocationId(canonInput);\n\n const sigValue = await input.signer.signMessage(id);\n\n const envelope: RevocationEnvelope = {\n v: ENVELOPE_VERSION,\n kind: 'agent-revocation',\n id,\n delegation_id: input.delegation.id,\n signer: { address: input.signer.address, alg: 'bip322' },\n reason,\n signed_at: signedAt,\n ots: input.ots ?? null,\n sig: { alg: 'bip322', pubkey: input.signer.address, value: sigValue },\n };\n return envelope;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Re-exports for convenience\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport {\n canonicalizeScopes,\n computeActionId,\n computeDelegationId,\n computeRevocationId,\n verifyAction,\n verifyDelegation,\n verifyRevocation,\n parseScope,\n isSubScope,\n canonicalizeScope,\n REGISTERED_SCOPES,\n} from '@orangecheck/agent-core';\nexport type {\n ActionEnvelope,\n ActionOts,\n DelegationBond,\n DelegationEnvelope,\n RevocationEnvelope,\n Scope,\n ScopeConstraint,\n AgentErrorCode,\n} from '@orangecheck/agent-core';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction isoUtcSeconds(d: Date): string {\n return d.toISOString().replace(/\\.\\d+Z$/, 'Z');\n}\n\nfunction randomHex(bytes: number): string {\n const buf = new Uint8Array(bytes);\n const c: Crypto | undefined = (globalThis as unknown as { crypto?: Crypto }).crypto;\n if (c && typeof c.getRandomValues === 'function') {\n c.getRandomValues(buf);\n } else {\n // Non-browser fallback. Node ≥18 exposes globalThis.crypto, so this is unlikely to fire.\n for (let i = 0; i < bytes; i++) buf[i] = Math.floor(Math.random() * 256);\n }\n let out = '';\n for (let i = 0; i < bytes; i++) {\n const b = buf[i]!;\n out += b.toString(16).padStart(2, '0');\n }\n return out;\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { sha256 } from '@noble/hashes/sha256';
|
|
2
|
-
import { validateScope, parseScope, canonicalizeScopes, computeDelegationId, ENVELOPE_VERSION, hexEncode, computeActionId, computeRevocationId } from '@orangecheck/agent-core';
|
|
2
|
+
import { validateScope, parseScope, canonicalizeScopes, computeDelegationId, sealScopes, ENVELOPE_VERSION, hexEncode, computeActionId, computeRevocationId } from '@orangecheck/agent-core';
|
|
3
3
|
export { REGISTERED_SCOPES, canonicalizeScope, canonicalizeScopes, computeActionId, computeDelegationId, computeRevocationId, isSubScope, parseScope, verifyAction, verifyDelegation, verifyRevocation } from '@orangecheck/agent-core';
|
|
4
4
|
|
|
5
5
|
// src/index.ts
|
|
@@ -48,6 +48,28 @@ async function createDelegation(input) {
|
|
|
48
48
|
nonce
|
|
49
49
|
};
|
|
50
50
|
const id = computeDelegationId(canonInput);
|
|
51
|
+
let scopesEncrypted;
|
|
52
|
+
if (input.privateScopes) {
|
|
53
|
+
if (!input.privateScopes.recipients || input.privateScopes.recipients.length === 0) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
"createDelegation: privateScopes.recipients must contain at least the agent device"
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
scopesEncrypted = await sealScopes({
|
|
59
|
+
scopes,
|
|
60
|
+
sender: {
|
|
61
|
+
address: input.principal.address,
|
|
62
|
+
signMessage: input.principal.signMessage
|
|
63
|
+
},
|
|
64
|
+
recipients: input.privateScopes.recipients,
|
|
65
|
+
...input.privateScopes.hint !== void 0 && {
|
|
66
|
+
hint: input.privateScopes.hint
|
|
67
|
+
},
|
|
68
|
+
...input.privateScopes.envelopeExpiresAt !== void 0 && {
|
|
69
|
+
expiresAt: input.privateScopes.envelopeExpiresAt
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
51
73
|
const sigValue = await input.principal.signMessage(id);
|
|
52
74
|
const envelope = {
|
|
53
75
|
v: ENVELOPE_VERSION,
|
|
@@ -55,7 +77,8 @@ async function createDelegation(input) {
|
|
|
55
77
|
id,
|
|
56
78
|
principal: { address: input.principal.address, alg: "bip322" },
|
|
57
79
|
agent: { address: input.agentAddress, alg: "bip322" },
|
|
58
|
-
|
|
80
|
+
// Public OR private mode — never both. PRIVATE-SCOPE.md §1.1.
|
|
81
|
+
...scopesEncrypted ? { scopes_encrypted: scopesEncrypted } : { scopes },
|
|
59
82
|
bond,
|
|
60
83
|
issued_at: issuedAt,
|
|
61
84
|
expires_at: expiresAt,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["// @orangecheck/agent-signer — high-level API for producing OC Agent envelopes.\n//\n// createDelegation — principal signs a scoped grant to an agent address.\n// signAsAgent — agent produces an agent-action envelope over content.\n// revoke — principal (or agent, if authorized) burns a delegation.\n//\n// Each function wraps @orangecheck/agent-core's canonical-message + id\n// computation with a caller-supplied `signMessage` wallet adapter. Nothing here\n// touches the network — OTS anchoring and Nostr publication are separate steps\n// the caller wires up.\n\nimport { sha256 } from '@noble/hashes/sha256';\nimport {\n canonicalizeScopes,\n computeActionId,\n computeDelegationId,\n computeRevocationId,\n ENVELOPE_VERSION,\n hexEncode,\n parseScope,\n validateScope,\n} from '@orangecheck/agent-core';\nimport type { ValidationOptions } from '@orangecheck/agent-core';\nimport type {\n ActionEnvelope,\n ActionOts,\n DelegationBond,\n DelegationEnvelope,\n RevocationEnvelope,\n RevocationHolder,\n} from '@orangecheck/agent-core';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Shared wallet-adapter shape (matches `@orangecheck/stamp-core` StampInput).\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SignerRef {\n address: string;\n /** Returns a base64 BIP-322 signature over the given message as UTF-8 bytes. */\n signMessage: (msg: string) => Promise<string>;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// createDelegation\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface CreateDelegationInput {\n principal: SignerRef;\n agentAddress: string;\n scopes: string[];\n bond?: DelegationBond | null;\n issuedAt?: Date;\n /** Duration from issuedAt in ms. Default 7 days. MAX 365 days per SPEC §4.4. */\n ttlMs?: number;\n /** Explicit expires_at overrides ttlMs. */\n expiresAt?: Date;\n /** 32-hex. Defaults to crypto.getRandomValues(16-byte) rendered as hex. */\n nonce?: string;\n /** Default ['principal']. */\n revocationHolders?: RevocationHolder[];\n /** Optional Nostr pointer to a revocation event. Non-cryptographic. */\n revocationRef?: string | null;\n /** Default 'strict'. 'permissive' allows unregistered scopes / constraint keys. */\n scopeMode?: ValidationOptions['mode'];\n}\n\nexport async function createDelegation(input: CreateDelegationInput): Promise<DelegationEnvelope> {\n if (!input.scopes || input.scopes.length === 0) {\n throw new Error('createDelegation: at least one scope is required');\n }\n const mode = input.scopeMode ?? 'strict';\n for (const s of input.scopes) validateScope(parseScope(s), { mode });\n const scopes = canonicalizeScopes(input.scopes);\n\n const issuedAt = isoUtcSeconds(input.issuedAt ?? new Date());\n let expiresAtDate: Date;\n if (input.expiresAt) {\n expiresAtDate = input.expiresAt;\n } else {\n const ttl = input.ttlMs ?? 7 * 24 * 60 * 60 * 1000;\n expiresAtDate = new Date(new Date(issuedAt).getTime() + ttl);\n }\n const expiresAt = isoUtcSeconds(expiresAtDate);\n\n const durationMs = new Date(expiresAt).getTime() - new Date(issuedAt).getTime();\n if (durationMs <= 0) throw new Error('createDelegation: expires_at must be after issued_at');\n if (durationMs > 365 * 24 * 60 * 60 * 1000) {\n throw new Error('createDelegation: delegation duration must not exceed 365 days');\n }\n\n const nonce = input.nonce ?? randomHex(16);\n if (!/^[0-9a-f]{32}$/.test(nonce)) {\n throw new Error('createDelegation: nonce must be 32 lowercase hex chars');\n }\n\n const bond = input.bond ?? null;\n if (bond) {\n if (!Number.isInteger(bond.sats) || bond.sats < 0) {\n throw new Error('createDelegation: bond.sats must be a non-negative integer');\n }\n if (!/^[0-9a-f]{64}$/.test(bond.attestation_id)) {\n throw new Error('createDelegation: bond.attestation_id must be 64 lowercase hex chars');\n }\n }\n\n const canonInput = {\n principal: input.principal.address,\n agent: input.agentAddress,\n scopes,\n bond_sats: bond?.sats ?? 0,\n bond_attestation: bond?.attestation_id ?? 'none',\n issued_at: issuedAt,\n expires_at: expiresAt,\n nonce,\n };\n const id = computeDelegationId(canonInput);\n\n const sigValue = await input.principal.signMessage(id);\n\n const envelope: DelegationEnvelope = {\n v: ENVELOPE_VERSION,\n kind: 'agent-delegation',\n id,\n principal: { address: input.principal.address, alg: 'bip322' },\n agent: { address: input.agentAddress, alg: 'bip322' },\n scopes,\n bond,\n issued_at: issuedAt,\n expires_at: expiresAt,\n nonce,\n revocation: {\n holders: input.revocationHolders ?? ['principal'],\n ref: input.revocationRef ?? null,\n },\n sig: {\n alg: 'bip322',\n pubkey: input.principal.address,\n value: sigValue,\n },\n };\n return envelope;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// signAsAgent\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SignAsAgentInput {\n agent: SignerRef;\n delegation: DelegationEnvelope;\n /** Raw bytes to stamp, or a pre-computed { hash, length } pair. */\n content: Uint8Array | { hash: string; length: number };\n mime: string;\n /** Which scope from delegation.scopes is being exercised (or a narrower sub-scope). */\n scopeExercised: string;\n ref?: string | null;\n signedAt?: Date;\n /** OTS proof / anchor data if the caller has already submitted; otherwise null. */\n ots?: ActionOts | null;\n}\n\nexport async function signAsAgent(input: SignAsAgentInput): Promise<ActionEnvelope> {\n if (input.agent.address !== input.delegation.agent.address) {\n throw new Error('signAsAgent: signer address does not match delegation.agent.address');\n }\n\n let contentHash: string;\n let contentLength: number;\n if (input.content instanceof Uint8Array) {\n contentHash = 'sha256:' + hexEncode(sha256(input.content));\n contentLength = input.content.byteLength;\n } else {\n if (!input.content.hash.startsWith('sha256:') || input.content.hash.length !== 'sha256:'.length + 64) {\n throw new Error('signAsAgent: content.hash must be \"sha256:\" + 64 lowercase hex chars');\n }\n contentHash = input.content.hash;\n contentLength = input.content.length;\n if (!Number.isInteger(contentLength) || contentLength < 0) {\n throw new Error('signAsAgent: content.length must be a non-negative integer');\n }\n }\n\n const signedAt = isoUtcSeconds(input.signedAt ?? new Date());\n\n const canonInput = {\n address: input.agent.address,\n content_hash: contentHash,\n content_length: contentLength,\n content_mime: input.mime,\n signed_at: signedAt,\n delegation_id: input.delegation.id,\n scope_exercised: input.scopeExercised,\n };\n const id = computeActionId(canonInput);\n\n const sigValue = await input.agent.signMessage(id);\n\n const envelope: ActionEnvelope = {\n v: ENVELOPE_VERSION,\n kind: 'agent-action',\n id,\n content: {\n hash: contentHash,\n length: contentLength,\n mime: input.mime,\n ref: input.ref ?? null,\n },\n signer: { address: input.agent.address, alg: 'bip322' },\n signed_at: signedAt,\n delegation_id: input.delegation.id,\n scope_exercised: input.scopeExercised,\n ots: input.ots ?? null,\n sig: { alg: 'bip322', pubkey: input.agent.address, value: sigValue },\n };\n return envelope;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// revoke\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface RevokeInput {\n signer: SignerRef;\n delegation: DelegationEnvelope;\n /** Short ASCII rationale. Defaults to empty string. */\n reason?: string;\n signedAt?: Date;\n /** OTS proof / anchor data if the caller has already submitted; otherwise null. */\n ots?: ActionOts | null;\n}\n\nexport async function revoke(input: RevokeInput): Promise<RevocationEnvelope> {\n const holders = input.delegation.revocation?.holders ?? ['principal'];\n const allowed = new Set<string>();\n if (holders.includes('principal')) allowed.add(input.delegation.principal.address);\n if (holders.includes('agent')) allowed.add(input.delegation.agent.address);\n if (!allowed.has(input.signer.address)) {\n throw new Error(\n `revoke: signer ${input.signer.address} not authorized to revoke this delegation`\n );\n }\n\n const reason = input.reason ?? '';\n if (reason.length > 128) throw new Error('revoke: reason must be <=128 bytes');\n\n const signedAt = isoUtcSeconds(input.signedAt ?? new Date());\n const canonInput = {\n address: input.signer.address,\n delegation_id: input.delegation.id,\n reason,\n signed_at: signedAt,\n };\n const id = computeRevocationId(canonInput);\n\n const sigValue = await input.signer.signMessage(id);\n\n const envelope: RevocationEnvelope = {\n v: ENVELOPE_VERSION,\n kind: 'agent-revocation',\n id,\n delegation_id: input.delegation.id,\n signer: { address: input.signer.address, alg: 'bip322' },\n reason,\n signed_at: signedAt,\n ots: input.ots ?? null,\n sig: { alg: 'bip322', pubkey: input.signer.address, value: sigValue },\n };\n return envelope;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Re-exports for convenience\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport {\n canonicalizeScopes,\n computeActionId,\n computeDelegationId,\n computeRevocationId,\n verifyAction,\n verifyDelegation,\n verifyRevocation,\n parseScope,\n isSubScope,\n canonicalizeScope,\n REGISTERED_SCOPES,\n} from '@orangecheck/agent-core';\nexport type {\n ActionEnvelope,\n ActionOts,\n DelegationBond,\n DelegationEnvelope,\n RevocationEnvelope,\n Scope,\n ScopeConstraint,\n AgentErrorCode,\n} from '@orangecheck/agent-core';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction isoUtcSeconds(d: Date): string {\n return d.toISOString().replace(/\\.\\d+Z$/, 'Z');\n}\n\nfunction randomHex(bytes: number): string {\n const buf = new Uint8Array(bytes);\n const c: Crypto | undefined = (globalThis as unknown as { crypto?: Crypto }).crypto;\n if (c && typeof c.getRandomValues === 'function') {\n c.getRandomValues(buf);\n } else {\n // Non-browser fallback. Node ≥18 exposes globalThis.crypto, so this is unlikely to fire.\n for (let i = 0; i < bytes; i++) buf[i] = Math.floor(Math.random() * 256);\n }\n let out = '';\n for (let i = 0; i < bytes; i++) {\n const b = buf[i]!;\n out += b.toString(16).padStart(2, '0');\n }\n return out;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["// @orangecheck/agent-signer — high-level API for producing OC Agent envelopes.\n//\n// createDelegation — principal signs a scoped grant to an agent address.\n// signAsAgent — agent produces an agent-action envelope over content.\n// revoke — principal (or agent, if authorized) burns a delegation.\n//\n// Each function wraps @orangecheck/agent-core's canonical-message + id\n// computation with a caller-supplied `signMessage` wallet adapter. Nothing here\n// touches the network — OTS anchoring and Nostr publication are separate steps\n// the caller wires up.\n\nimport { sha256 } from '@noble/hashes/sha256';\nimport {\n canonicalizeScopes,\n computeActionId,\n computeDelegationId,\n computeRevocationId,\n ENVELOPE_VERSION,\n hexEncode,\n parseScope,\n sealScopes,\n validateScope,\n} from '@orangecheck/agent-core';\nimport type {\n ScopesEncryptedEnvelope,\n ValidationOptions,\n} from '@orangecheck/agent-core';\nimport type {\n ActionEnvelope,\n ActionOts,\n DelegationBond,\n DelegationEnvelope,\n RevocationEnvelope,\n RevocationHolder,\n} from '@orangecheck/agent-core';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Shared wallet-adapter shape (matches `@orangecheck/stamp-core` StampInput).\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SignerRef {\n address: string;\n /** Returns a base64 BIP-322 signature over the given message as UTF-8 bytes. */\n signMessage: (msg: string) => Promise<string>;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// createDelegation\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface CreateDelegationInput {\n principal: SignerRef;\n agentAddress: string;\n scopes: string[];\n bond?: DelegationBond | null;\n issuedAt?: Date;\n /** Duration from issuedAt in ms. Default 7 days. MAX 365 days per SPEC §4.4. */\n ttlMs?: number;\n /** Explicit expires_at overrides ttlMs. */\n expiresAt?: Date;\n /** 32-hex. Defaults to crypto.getRandomValues(16-byte) rendered as hex. */\n nonce?: string;\n /** Default ['principal']. */\n revocationHolders?: RevocationHolder[];\n /** Optional Nostr pointer to a revocation event. Non-cryptographic. */\n revocationRef?: string | null;\n /** Default 'strict'. 'permissive' allows unregistered scopes / constraint keys. */\n scopeMode?: ValidationOptions['mode'];\n /**\n * v1.2 private-scope (PRIVATE-SCOPE.md). When supplied, the resulting\n * delegation envelope omits the public `scopes` field and instead carries\n * `scopes_encrypted` — an OC Lock envelope wrapping the canonical scope\n * list, sealed to one or more recipient device keys. The principal signs\n * BOTH the inner OC Lock envelope (via the `signMessage` callback already\n * provided on `principal`) AND the outer OC Agent canonical message.\n *\n * Recipients MUST include at least the agent's device. Additional\n * recipients (compliance auditors, third-party verifiers) are optional.\n */\n privateScopes?: {\n /**\n * Devices authorized to read the scope set. Each is `{ address,\n * device_id, device_pk }` matching OC Lock's `DeviceRecord` shape.\n * The same `signMessage` callback on `principal` is used to sign the\n * inner OC Lock envelope.\n */\n recipients: PrivateScopeRecipient[];\n /** Optional human hint stored in the OC Lock envelope. */\n hint?: string;\n /** Optional expiry on the OC Lock envelope. Independent of the\n * delegation's expires_at; usually left unset. */\n envelopeExpiresAt?: Date | null;\n };\n}\n\n/** Mirror of @orangecheck/lock-core's DeviceRecord. */\nexport interface PrivateScopeRecipient {\n address: string;\n device_id: string;\n /** 32-byte hex X25519 public key. */\n device_pk: string;\n}\n\nexport async function createDelegation(input: CreateDelegationInput): Promise<DelegationEnvelope> {\n if (!input.scopes || input.scopes.length === 0) {\n throw new Error('createDelegation: at least one scope is required');\n }\n const mode = input.scopeMode ?? 'strict';\n for (const s of input.scopes) validateScope(parseScope(s), { mode });\n const scopes = canonicalizeScopes(input.scopes);\n\n const issuedAt = isoUtcSeconds(input.issuedAt ?? new Date());\n let expiresAtDate: Date;\n if (input.expiresAt) {\n expiresAtDate = input.expiresAt;\n } else {\n const ttl = input.ttlMs ?? 7 * 24 * 60 * 60 * 1000;\n expiresAtDate = new Date(new Date(issuedAt).getTime() + ttl);\n }\n const expiresAt = isoUtcSeconds(expiresAtDate);\n\n const durationMs = new Date(expiresAt).getTime() - new Date(issuedAt).getTime();\n if (durationMs <= 0) throw new Error('createDelegation: expires_at must be after issued_at');\n if (durationMs > 365 * 24 * 60 * 60 * 1000) {\n throw new Error('createDelegation: delegation duration must not exceed 365 days');\n }\n\n const nonce = input.nonce ?? randomHex(16);\n if (!/^[0-9a-f]{32}$/.test(nonce)) {\n throw new Error('createDelegation: nonce must be 32 lowercase hex chars');\n }\n\n const bond = input.bond ?? null;\n if (bond) {\n if (!Number.isInteger(bond.sats) || bond.sats < 0) {\n throw new Error('createDelegation: bond.sats must be a non-negative integer');\n }\n if (!/^[0-9a-f]{64}$/.test(bond.attestation_id)) {\n throw new Error('createDelegation: bond.attestation_id must be 64 lowercase hex chars');\n }\n }\n\n const canonInput = {\n principal: input.principal.address,\n agent: input.agentAddress,\n scopes,\n bond_sats: bond?.sats ?? 0,\n bond_attestation: bond?.attestation_id ?? 'none',\n issued_at: issuedAt,\n expires_at: expiresAt,\n nonce,\n };\n const id = computeDelegationId(canonInput);\n\n // v1.2 private-scope: seal BEFORE the principal's outer signature so the\n // user's wallet sees both prompts in a deterministic order (inner Lock\n // sig first, outer OC Agent sig second).\n let scopesEncrypted: ScopesEncryptedEnvelope | undefined;\n if (input.privateScopes) {\n if (!input.privateScopes.recipients || input.privateScopes.recipients.length === 0) {\n throw new Error(\n 'createDelegation: privateScopes.recipients must contain at least the agent device'\n );\n }\n scopesEncrypted = await sealScopes({\n scopes,\n sender: {\n address: input.principal.address,\n signMessage: input.principal.signMessage,\n },\n recipients: input.privateScopes.recipients,\n ...(input.privateScopes.hint !== undefined && {\n hint: input.privateScopes.hint,\n }),\n ...(input.privateScopes.envelopeExpiresAt !== undefined && {\n expiresAt: input.privateScopes.envelopeExpiresAt,\n }),\n });\n }\n\n const sigValue = await input.principal.signMessage(id);\n\n const envelope: DelegationEnvelope = {\n v: ENVELOPE_VERSION,\n kind: 'agent-delegation',\n id,\n principal: { address: input.principal.address, alg: 'bip322' },\n agent: { address: input.agentAddress, alg: 'bip322' },\n // Public OR private mode — never both. PRIVATE-SCOPE.md §1.1.\n ...(scopesEncrypted ? { scopes_encrypted: scopesEncrypted } : { scopes }),\n bond,\n issued_at: issuedAt,\n expires_at: expiresAt,\n nonce,\n revocation: {\n holders: input.revocationHolders ?? ['principal'],\n ref: input.revocationRef ?? null,\n },\n sig: {\n alg: 'bip322',\n pubkey: input.principal.address,\n value: sigValue,\n },\n };\n return envelope;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// signAsAgent\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SignAsAgentInput {\n agent: SignerRef;\n delegation: DelegationEnvelope;\n /** Raw bytes to stamp, or a pre-computed { hash, length } pair. */\n content: Uint8Array | { hash: string; length: number };\n mime: string;\n /** Which scope from delegation.scopes is being exercised (or a narrower sub-scope). */\n scopeExercised: string;\n ref?: string | null;\n signedAt?: Date;\n /** OTS proof / anchor data if the caller has already submitted; otherwise null. */\n ots?: ActionOts | null;\n}\n\nexport async function signAsAgent(input: SignAsAgentInput): Promise<ActionEnvelope> {\n if (input.agent.address !== input.delegation.agent.address) {\n throw new Error('signAsAgent: signer address does not match delegation.agent.address');\n }\n\n let contentHash: string;\n let contentLength: number;\n if (input.content instanceof Uint8Array) {\n contentHash = 'sha256:' + hexEncode(sha256(input.content));\n contentLength = input.content.byteLength;\n } else {\n if (!input.content.hash.startsWith('sha256:') || input.content.hash.length !== 'sha256:'.length + 64) {\n throw new Error('signAsAgent: content.hash must be \"sha256:\" + 64 lowercase hex chars');\n }\n contentHash = input.content.hash;\n contentLength = input.content.length;\n if (!Number.isInteger(contentLength) || contentLength < 0) {\n throw new Error('signAsAgent: content.length must be a non-negative integer');\n }\n }\n\n const signedAt = isoUtcSeconds(input.signedAt ?? new Date());\n\n const canonInput = {\n address: input.agent.address,\n content_hash: contentHash,\n content_length: contentLength,\n content_mime: input.mime,\n signed_at: signedAt,\n delegation_id: input.delegation.id,\n scope_exercised: input.scopeExercised,\n };\n const id = computeActionId(canonInput);\n\n const sigValue = await input.agent.signMessage(id);\n\n const envelope: ActionEnvelope = {\n v: ENVELOPE_VERSION,\n kind: 'agent-action',\n id,\n content: {\n hash: contentHash,\n length: contentLength,\n mime: input.mime,\n ref: input.ref ?? null,\n },\n signer: { address: input.agent.address, alg: 'bip322' },\n signed_at: signedAt,\n delegation_id: input.delegation.id,\n scope_exercised: input.scopeExercised,\n ots: input.ots ?? null,\n sig: { alg: 'bip322', pubkey: input.agent.address, value: sigValue },\n };\n return envelope;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// revoke\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface RevokeInput {\n signer: SignerRef;\n delegation: DelegationEnvelope;\n /** Short ASCII rationale. Defaults to empty string. */\n reason?: string;\n signedAt?: Date;\n /** OTS proof / anchor data if the caller has already submitted; otherwise null. */\n ots?: ActionOts | null;\n}\n\nexport async function revoke(input: RevokeInput): Promise<RevocationEnvelope> {\n const holders = input.delegation.revocation?.holders ?? ['principal'];\n const allowed = new Set<string>();\n if (holders.includes('principal')) allowed.add(input.delegation.principal.address);\n if (holders.includes('agent')) allowed.add(input.delegation.agent.address);\n if (!allowed.has(input.signer.address)) {\n throw new Error(\n `revoke: signer ${input.signer.address} not authorized to revoke this delegation`\n );\n }\n\n const reason = input.reason ?? '';\n if (reason.length > 128) throw new Error('revoke: reason must be <=128 bytes');\n\n const signedAt = isoUtcSeconds(input.signedAt ?? new Date());\n const canonInput = {\n address: input.signer.address,\n delegation_id: input.delegation.id,\n reason,\n signed_at: signedAt,\n };\n const id = computeRevocationId(canonInput);\n\n const sigValue = await input.signer.signMessage(id);\n\n const envelope: RevocationEnvelope = {\n v: ENVELOPE_VERSION,\n kind: 'agent-revocation',\n id,\n delegation_id: input.delegation.id,\n signer: { address: input.signer.address, alg: 'bip322' },\n reason,\n signed_at: signedAt,\n ots: input.ots ?? null,\n sig: { alg: 'bip322', pubkey: input.signer.address, value: sigValue },\n };\n return envelope;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Re-exports for convenience\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport {\n canonicalizeScopes,\n computeActionId,\n computeDelegationId,\n computeRevocationId,\n verifyAction,\n verifyDelegation,\n verifyRevocation,\n parseScope,\n isSubScope,\n canonicalizeScope,\n REGISTERED_SCOPES,\n} from '@orangecheck/agent-core';\nexport type {\n ActionEnvelope,\n ActionOts,\n DelegationBond,\n DelegationEnvelope,\n RevocationEnvelope,\n Scope,\n ScopeConstraint,\n AgentErrorCode,\n} from '@orangecheck/agent-core';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction isoUtcSeconds(d: Date): string {\n return d.toISOString().replace(/\\.\\d+Z$/, 'Z');\n}\n\nfunction randomHex(bytes: number): string {\n const buf = new Uint8Array(bytes);\n const c: Crypto | undefined = (globalThis as unknown as { crypto?: Crypto }).crypto;\n if (c && typeof c.getRandomValues === 'function') {\n c.getRandomValues(buf);\n } else {\n // Non-browser fallback. Node ≥18 exposes globalThis.crypto, so this is unlikely to fire.\n for (let i = 0; i < bytes; i++) buf[i] = Math.floor(Math.random() * 256);\n }\n let out = '';\n for (let i = 0; i < bytes; i++) {\n const b = buf[i]!;\n out += b.toString(16).padStart(2, '0');\n }\n return out;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,60 +1,63 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
"files": [
|
|
36
|
-
"dist",
|
|
37
|
-
"src",
|
|
38
|
-
"README.md",
|
|
39
|
-
"LICENSE"
|
|
40
|
-
],
|
|
41
|
-
"scripts": {
|
|
42
|
-
"build": "tsup",
|
|
43
|
-
"dev": "tsup --watch",
|
|
44
|
-
"type-check": "tsc --noEmit",
|
|
45
|
-
"test": "vitest run",
|
|
46
|
-
"test:watch": "vitest",
|
|
47
|
-
"clean": "rm -rf dist",
|
|
48
|
-
"prepublishOnly": "npm run clean && npm run build"
|
|
49
|
-
},
|
|
50
|
-
"dependencies": {
|
|
51
|
-
"@noble/hashes": "^1.5.0",
|
|
52
|
-
"@orangecheck/agent-core": "^0.1.0"
|
|
53
|
-
},
|
|
54
|
-
"devDependencies": {
|
|
55
|
-
"@types/node": "^22.10.2",
|
|
56
|
-
"tsup": "^8.3.5",
|
|
57
|
-
"typescript": "^5.7.2",
|
|
58
|
-
"vitest": "^3.2.4"
|
|
2
|
+
"name": "@orangecheck/agent-signer",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "OC Agent signer: createDelegation(), signAsAgent(), revoke(). Composes @orangecheck/agent-core with a wallet-adapter signing function and optional OTS anchoring.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"bitcoin",
|
|
7
|
+
"agent",
|
|
8
|
+
"authority",
|
|
9
|
+
"delegation",
|
|
10
|
+
"bip322",
|
|
11
|
+
"oc-agent",
|
|
12
|
+
"orangecheck"
|
|
13
|
+
],
|
|
14
|
+
"author": "OrangeCheck",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/orangecheck/oc-packages.git",
|
|
19
|
+
"directory": "agent-signer"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/orangecheck/oc-agent-protocol",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/orangecheck/oc-agent-protocol/issues"
|
|
24
|
+
},
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"module": "./dist/index.mjs",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.mjs",
|
|
32
|
+
"require": "./dist/index.js"
|
|
59
33
|
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"src",
|
|
38
|
+
"README.md",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
],
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsup",
|
|
43
|
+
"dev": "tsup --watch",
|
|
44
|
+
"type-check": "tsc --noEmit",
|
|
45
|
+
"test": "vitest run",
|
|
46
|
+
"test:watch": "vitest",
|
|
47
|
+
"clean": "rm -rf dist",
|
|
48
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@noble/hashes": "^1.5.0",
|
|
52
|
+
"@orangecheck/agent-core": "^1.2.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/node": "^22.10.2",
|
|
56
|
+
"tsup": "^8.3.5",
|
|
57
|
+
"typescript": "^5.7.2",
|
|
58
|
+
"vitest": "^3.2.4"
|
|
59
|
+
},
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"access": "public"
|
|
62
|
+
}
|
|
60
63
|
}
|
package/src/index.ts
CHANGED
|
@@ -18,9 +18,13 @@ import {
|
|
|
18
18
|
ENVELOPE_VERSION,
|
|
19
19
|
hexEncode,
|
|
20
20
|
parseScope,
|
|
21
|
+
sealScopes,
|
|
21
22
|
validateScope,
|
|
22
23
|
} from '@orangecheck/agent-core';
|
|
23
|
-
import type {
|
|
24
|
+
import type {
|
|
25
|
+
ScopesEncryptedEnvelope,
|
|
26
|
+
ValidationOptions,
|
|
27
|
+
} from '@orangecheck/agent-core';
|
|
24
28
|
import type {
|
|
25
29
|
ActionEnvelope,
|
|
26
30
|
ActionOts,
|
|
@@ -62,6 +66,39 @@ export interface CreateDelegationInput {
|
|
|
62
66
|
revocationRef?: string | null;
|
|
63
67
|
/** Default 'strict'. 'permissive' allows unregistered scopes / constraint keys. */
|
|
64
68
|
scopeMode?: ValidationOptions['mode'];
|
|
69
|
+
/**
|
|
70
|
+
* v1.2 private-scope (PRIVATE-SCOPE.md). When supplied, the resulting
|
|
71
|
+
* delegation envelope omits the public `scopes` field and instead carries
|
|
72
|
+
* `scopes_encrypted` — an OC Lock envelope wrapping the canonical scope
|
|
73
|
+
* list, sealed to one or more recipient device keys. The principal signs
|
|
74
|
+
* BOTH the inner OC Lock envelope (via the `signMessage` callback already
|
|
75
|
+
* provided on `principal`) AND the outer OC Agent canonical message.
|
|
76
|
+
*
|
|
77
|
+
* Recipients MUST include at least the agent's device. Additional
|
|
78
|
+
* recipients (compliance auditors, third-party verifiers) are optional.
|
|
79
|
+
*/
|
|
80
|
+
privateScopes?: {
|
|
81
|
+
/**
|
|
82
|
+
* Devices authorized to read the scope set. Each is `{ address,
|
|
83
|
+
* device_id, device_pk }` matching OC Lock's `DeviceRecord` shape.
|
|
84
|
+
* The same `signMessage` callback on `principal` is used to sign the
|
|
85
|
+
* inner OC Lock envelope.
|
|
86
|
+
*/
|
|
87
|
+
recipients: PrivateScopeRecipient[];
|
|
88
|
+
/** Optional human hint stored in the OC Lock envelope. */
|
|
89
|
+
hint?: string;
|
|
90
|
+
/** Optional expiry on the OC Lock envelope. Independent of the
|
|
91
|
+
* delegation's expires_at; usually left unset. */
|
|
92
|
+
envelopeExpiresAt?: Date | null;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Mirror of @orangecheck/lock-core's DeviceRecord. */
|
|
97
|
+
export interface PrivateScopeRecipient {
|
|
98
|
+
address: string;
|
|
99
|
+
device_id: string;
|
|
100
|
+
/** 32-byte hex X25519 public key. */
|
|
101
|
+
device_pk: string;
|
|
65
102
|
}
|
|
66
103
|
|
|
67
104
|
export async function createDelegation(input: CreateDelegationInput): Promise<DelegationEnvelope> {
|
|
@@ -115,6 +152,32 @@ export async function createDelegation(input: CreateDelegationInput): Promise<De
|
|
|
115
152
|
};
|
|
116
153
|
const id = computeDelegationId(canonInput);
|
|
117
154
|
|
|
155
|
+
// v1.2 private-scope: seal BEFORE the principal's outer signature so the
|
|
156
|
+
// user's wallet sees both prompts in a deterministic order (inner Lock
|
|
157
|
+
// sig first, outer OC Agent sig second).
|
|
158
|
+
let scopesEncrypted: ScopesEncryptedEnvelope | undefined;
|
|
159
|
+
if (input.privateScopes) {
|
|
160
|
+
if (!input.privateScopes.recipients || input.privateScopes.recipients.length === 0) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
'createDelegation: privateScopes.recipients must contain at least the agent device'
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
scopesEncrypted = await sealScopes({
|
|
166
|
+
scopes,
|
|
167
|
+
sender: {
|
|
168
|
+
address: input.principal.address,
|
|
169
|
+
signMessage: input.principal.signMessage,
|
|
170
|
+
},
|
|
171
|
+
recipients: input.privateScopes.recipients,
|
|
172
|
+
...(input.privateScopes.hint !== undefined && {
|
|
173
|
+
hint: input.privateScopes.hint,
|
|
174
|
+
}),
|
|
175
|
+
...(input.privateScopes.envelopeExpiresAt !== undefined && {
|
|
176
|
+
expiresAt: input.privateScopes.envelopeExpiresAt,
|
|
177
|
+
}),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
118
181
|
const sigValue = await input.principal.signMessage(id);
|
|
119
182
|
|
|
120
183
|
const envelope: DelegationEnvelope = {
|
|
@@ -123,7 +186,8 @@ export async function createDelegation(input: CreateDelegationInput): Promise<De
|
|
|
123
186
|
id,
|
|
124
187
|
principal: { address: input.principal.address, alg: 'bip322' },
|
|
125
188
|
agent: { address: input.agentAddress, alg: 'bip322' },
|
|
126
|
-
|
|
189
|
+
// Public OR private mode — never both. PRIVATE-SCOPE.md §1.1.
|
|
190
|
+
...(scopesEncrypted ? { scopes_encrypted: scopesEncrypted } : { scopes }),
|
|
127
191
|
bond,
|
|
128
192
|
issued_at: issuedAt,
|
|
129
193
|
expires_at: expiresAt,
|