@orangecheck/sdk 1.2.0 → 1.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/dist/index.d.mts CHANGED
@@ -33,73 +33,6 @@ interface CheckResult {
33
33
  }
34
34
  declare function check(params: CheckParams): Promise<CheckResult>;
35
35
 
36
- declare const BINDING_KIND = 30079;
37
- interface BindingInput {
38
- principal: string;
39
- btc: string;
40
- nostr: string;
41
- nonce: string;
42
- issued_at: string;
43
- extensions?: Record<string, string>;
44
- }
45
- interface BindingNostrEvent {
46
- id: string;
47
- pubkey: string;
48
- kind: number;
49
- created_at: number;
50
- tags: string[][];
51
- content: string;
52
- sig: string;
53
- }
54
- interface BindingEnvelope {
55
- binding_id?: string;
56
- v?: number;
57
- principal?: string;
58
- btc?: string;
59
- nostr?: string;
60
- message: string;
61
- message_b64url?: string;
62
- btc_signature?: string;
63
- btc_scheme?: 'bip322' | 'legacy';
64
- nostr_event?: BindingNostrEvent;
65
- }
66
- type BindingStatus = 'binding_ok' | 'malformed' | 'bad_header' | 'bad_ack' | 'bad_principal' | 'ext_unsorted' | 'id_mismatch' | 'field_mismatch' | 'expired' | 'network' | 'bad_scheme' | 'btc_sig_invalid' | 'nostr_id_invalid' | 'nostr_sig_invalid' | 'nostr_key_mismatch' | 'message_mismatch';
67
- type BindingVerifyResult = {
68
- valid: true;
69
- status: 'binding_ok';
70
- binding_id: string;
71
- principal: string;
72
- btc: string;
73
- nostr: string;
74
- } | {
75
- valid: false;
76
- status: Exclude<BindingStatus, 'binding_ok'>;
77
- };
78
- declare function buildBindingMessage(input: BindingInput): string;
79
- declare function bindingId(message: string): string;
80
- declare function verifyBinding(envelope: BindingEnvelope): BindingVerifyResult;
81
- declare function xOnlyHexToNpub(hex: string): string;
82
- interface BindingEventTemplate {
83
- kind: typeof BINDING_KIND;
84
- pubkey: string;
85
- created_at: number;
86
- tags: string[][];
87
- content: string;
88
- }
89
- declare function buildBindingEventTemplate(params: {
90
- message: string;
91
- btcSignature: string;
92
- nostrPubkeyHex: string;
93
- btc: string;
94
- createdAt?: number;
95
- }): BindingEventTemplate;
96
- declare function assembleBindingEnvelope(params: {
97
- message: string;
98
- btcSignature: string;
99
- btcScheme?: 'bip322' | 'legacy';
100
- nostrEvent: BindingNostrEvent;
101
- }): BindingEnvelope;
102
-
103
36
  declare function isNip07Available(): boolean;
104
37
  declare function getNostrPublicKey(): Promise<string | null>;
105
38
  declare function signNostrEvent(event: Omit<NostrEvent, 'id' | 'sig'>): Promise<NostrEvent | null>;
@@ -117,4 +50,4 @@ interface StatusMeta {
117
50
  }
118
51
  declare const STATUS_META: Record<StatusCode, StatusMeta>;
119
52
 
120
- export { type BindingEnvelope, type BindingEventTemplate, type BindingInput, type BindingNostrEvent, type BindingStatus, type BindingVerifyResult, type CheckParams, type CheckResult, IdentityBinding, Network, NostrEvent, STATUS_META, type Severity, StatusCode, type StatusMeta, VerifyOptions, assembleBindingEnvelope, bindingId, buildBindingEventTemplate, buildBindingMessage, check, getNip07Info, getNostrPublicKey, isNip07Available, signNostrEvent, verifyBinding, xOnlyHexToNpub };
53
+ export { type CheckParams, type CheckResult, IdentityBinding, Network, NostrEvent, STATUS_META, type Severity, StatusCode, type StatusMeta, VerifyOptions, check, getNip07Info, getNostrPublicKey, isNip07Available, signNostrEvent };
package/dist/index.d.ts CHANGED
@@ -33,73 +33,6 @@ interface CheckResult {
33
33
  }
34
34
  declare function check(params: CheckParams): Promise<CheckResult>;
35
35
 
36
- declare const BINDING_KIND = 30079;
37
- interface BindingInput {
38
- principal: string;
39
- btc: string;
40
- nostr: string;
41
- nonce: string;
42
- issued_at: string;
43
- extensions?: Record<string, string>;
44
- }
45
- interface BindingNostrEvent {
46
- id: string;
47
- pubkey: string;
48
- kind: number;
49
- created_at: number;
50
- tags: string[][];
51
- content: string;
52
- sig: string;
53
- }
54
- interface BindingEnvelope {
55
- binding_id?: string;
56
- v?: number;
57
- principal?: string;
58
- btc?: string;
59
- nostr?: string;
60
- message: string;
61
- message_b64url?: string;
62
- btc_signature?: string;
63
- btc_scheme?: 'bip322' | 'legacy';
64
- nostr_event?: BindingNostrEvent;
65
- }
66
- type BindingStatus = 'binding_ok' | 'malformed' | 'bad_header' | 'bad_ack' | 'bad_principal' | 'ext_unsorted' | 'id_mismatch' | 'field_mismatch' | 'expired' | 'network' | 'bad_scheme' | 'btc_sig_invalid' | 'nostr_id_invalid' | 'nostr_sig_invalid' | 'nostr_key_mismatch' | 'message_mismatch';
67
- type BindingVerifyResult = {
68
- valid: true;
69
- status: 'binding_ok';
70
- binding_id: string;
71
- principal: string;
72
- btc: string;
73
- nostr: string;
74
- } | {
75
- valid: false;
76
- status: Exclude<BindingStatus, 'binding_ok'>;
77
- };
78
- declare function buildBindingMessage(input: BindingInput): string;
79
- declare function bindingId(message: string): string;
80
- declare function verifyBinding(envelope: BindingEnvelope): BindingVerifyResult;
81
- declare function xOnlyHexToNpub(hex: string): string;
82
- interface BindingEventTemplate {
83
- kind: typeof BINDING_KIND;
84
- pubkey: string;
85
- created_at: number;
86
- tags: string[][];
87
- content: string;
88
- }
89
- declare function buildBindingEventTemplate(params: {
90
- message: string;
91
- btcSignature: string;
92
- nostrPubkeyHex: string;
93
- btc: string;
94
- createdAt?: number;
95
- }): BindingEventTemplate;
96
- declare function assembleBindingEnvelope(params: {
97
- message: string;
98
- btcSignature: string;
99
- btcScheme?: 'bip322' | 'legacy';
100
- nostrEvent: BindingNostrEvent;
101
- }): BindingEnvelope;
102
-
103
36
  declare function isNip07Available(): boolean;
104
37
  declare function getNostrPublicKey(): Promise<string | null>;
105
38
  declare function signNostrEvent(event: Omit<NostrEvent, 'id' | 'sig'>): Promise<NostrEvent | null>;
@@ -117,4 +50,4 @@ interface StatusMeta {
117
50
  }
118
51
  declare const STATUS_META: Record<StatusCode, StatusMeta>;
119
52
 
120
- export { type BindingEnvelope, type BindingEventTemplate, type BindingInput, type BindingNostrEvent, type BindingStatus, type BindingVerifyResult, type CheckParams, type CheckResult, IdentityBinding, Network, NostrEvent, STATUS_META, type Severity, StatusCode, type StatusMeta, VerifyOptions, assembleBindingEnvelope, bindingId, buildBindingEventTemplate, buildBindingMessage, check, getNip07Info, getNostrPublicKey, isNip07Available, signNostrEvent, verifyBinding, xOnlyHexToNpub };
53
+ export { type CheckParams, type CheckResult, IdentityBinding, Network, NostrEvent, STATUS_META, type Severity, StatusCode, type StatusMeta, VerifyOptions, check, getNip07Info, getNostrPublicKey, isNip07Available, signNostrEvent };
package/dist/index.js CHANGED
@@ -1177,246 +1177,6 @@ async function check(params) {
1177
1177
  ...reasons.length ? { reasons } : {}
1178
1178
  };
1179
1179
  }
1180
- var HEADER = "orangecheck-binding";
1181
- var ACK = "I attest the keys named in this message are one principal.";
1182
- var BINDING_KIND = 30079;
1183
- function toHex(bytes) {
1184
- let out = "";
1185
- for (const b of bytes) out += b.toString(16).padStart(2, "0");
1186
- return out;
1187
- }
1188
- function fromHex(hex) {
1189
- const clean = hex.toLowerCase();
1190
- if (clean.length % 2 !== 0 || /[^0-9a-f]/.test(clean)) {
1191
- throw new Error("invalid hex");
1192
- }
1193
- const out = new Uint8Array(clean.length / 2);
1194
- for (let i = 0; i < out.length; i++) out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
1195
- return out;
1196
- }
1197
- function assertPrintableAscii(field, value) {
1198
- for (let i = 0; i < value.length; i++) {
1199
- const c = value.charCodeAt(i);
1200
- if (c < 32 || c > 126) {
1201
- throw new Error(
1202
- `binding ${field} contains an unsafe character (0x${c.toString(16)}) \u2014 line-smuggling defense (SPEC-BINDING \xA73.5)`
1203
- );
1204
- }
1205
- }
1206
- }
1207
- function buildBindingMessage(input) {
1208
- assertPrintableAscii("principal", input.principal);
1209
- assertPrintableAscii("btc", input.btc);
1210
- assertPrintableAscii("nostr", input.nostr);
1211
- assertPrintableAscii("nonce", input.nonce);
1212
- assertPrintableAscii("issued_at", input.issued_at);
1213
- const core = [
1214
- HEADER,
1215
- "v: 1",
1216
- `principal: ${input.principal}`,
1217
- `btc: ${input.btc}`,
1218
- `nostr: ${input.nostr}`,
1219
- `nonce: ${input.nonce}`,
1220
- `issued_at: ${input.issued_at}`,
1221
- `ack: ${ACK}`
1222
- ];
1223
- const ext = [];
1224
- if (input.extensions) {
1225
- for (const key of Object.keys(input.extensions).sort()) {
1226
- const value = input.extensions[key];
1227
- if (value == null) continue;
1228
- if (!/^[a-z]+$/.test(key)) {
1229
- throw new Error(`binding extension key "${key}" must be lowercase ASCII`);
1230
- }
1231
- assertPrintableAscii(`extension ${key}`, value);
1232
- ext.push(`${key}: ${value}`);
1233
- }
1234
- }
1235
- return [...core, ...ext].join("\n") + "\n";
1236
- }
1237
- function bindingId(message) {
1238
- return toHex(sha2_js.sha256(new TextEncoder().encode(message)));
1239
- }
1240
- function linePrefix(line, prefix) {
1241
- if (typeof line !== "string" || !line.startsWith(prefix)) return null;
1242
- return line.slice(prefix.length);
1243
- }
1244
- function nostrEventId(ev) {
1245
- const serialized = JSON.stringify([
1246
- 0,
1247
- ev.pubkey,
1248
- ev.created_at,
1249
- ev.kind,
1250
- ev.tags,
1251
- ev.content
1252
- ]);
1253
- return toHex(sha2_js.sha256(new TextEncoder().encode(serialized)));
1254
- }
1255
- function npubToXOnlyHex(npub) {
1256
- const decoded = base.bech32.decode(npub, 90);
1257
- if (decoded.prefix !== "npub") throw new Error("not an npub");
1258
- const bytes = Uint8Array.from(base.bech32.fromWords(decoded.words));
1259
- if (bytes.length !== 32) throw new Error("npub payload is not 32 bytes");
1260
- return toHex(bytes);
1261
- }
1262
- function verifyBinding(envelope) {
1263
- const fail = (status) => ({
1264
- valid: false,
1265
- status
1266
- });
1267
- try {
1268
- const msg = envelope.message;
1269
- if (typeof msg !== "string" || msg.length === 0) return fail("malformed");
1270
- const lines = msg.split("\n");
1271
- if ((lines[0] ?? "") !== HEADER) return fail("bad_header");
1272
- if (lines.length < 9 || lines[lines.length - 1] !== "") return fail("malformed");
1273
- const body = lines.slice(0, -1);
1274
- if (body.length < 8) return fail("malformed");
1275
- if (body[1] !== "v: 1") return fail("malformed");
1276
- if (body[7] !== `ack: ${ACK}`) return fail("bad_ack");
1277
- const principal = linePrefix(body[2], "principal: ");
1278
- const btc = linePrefix(body[3], "btc: ");
1279
- const nostr = linePrefix(body[4], "nostr: ");
1280
- const nonce = linePrefix(body[5], "nonce: ");
1281
- const issuedAt = linePrefix(body[6], "issued_at: ");
1282
- if (principal == null || btc == null || nostr == null || nonce == null || issuedAt == null) {
1283
- return fail("malformed");
1284
- }
1285
- for (const value of [principal, btc, nostr, nonce, issuedAt]) {
1286
- for (let i = 0; i < value.length; i++) {
1287
- const c = value.charCodeAt(i);
1288
- if (c < 32 || c > 126) return fail("malformed");
1289
- }
1290
- }
1291
- if (!/^did:oc:[0-9a-f]{32}$/.test(principal)) return fail("bad_principal");
1292
- if (!/^[0-9a-f]{32}$/.test(nonce)) return fail("malformed");
1293
- const ext = {};
1294
- let prevKey = "";
1295
- for (const line of body.slice(8)) {
1296
- const idx = line.indexOf(": ");
1297
- if (idx <= 0) return fail("malformed");
1298
- const key = line.slice(0, idx);
1299
- const value = line.slice(idx + 2);
1300
- if (!/^[a-z]+$/.test(key)) return fail("malformed");
1301
- if (key <= prevKey) return fail("ext_unsorted");
1302
- prevKey = key;
1303
- ext[key] = value;
1304
- }
1305
- const bid = bindingId(msg);
1306
- if (envelope.binding_id && envelope.binding_id.toLowerCase() !== bid) {
1307
- return fail("id_mismatch");
1308
- }
1309
- if (envelope.btc && envelope.btc !== btc) return fail("field_mismatch");
1310
- if (envelope.nostr && envelope.nostr !== nostr) return fail("field_mismatch");
1311
- if (envelope.principal && envelope.principal !== principal) return fail("field_mismatch");
1312
- if (ext.expires) {
1313
- const t = Date.parse(ext.expires);
1314
- if (!Number.isNaN(t) && Date.now() > t) return fail("expired");
1315
- }
1316
- if (typeof envelope.btc_signature !== "string" || !envelope.btc_signature) {
1317
- return fail("btc_sig_invalid");
1318
- }
1319
- const scheme = envelope.btc_scheme ?? "bip322";
1320
- let btcOk = false;
1321
- try {
1322
- if (scheme === "bip322") {
1323
- btcOk = bip322Js.Verifier.verifySignature(btc, msg, envelope.btc_signature);
1324
- } else if (scheme === "legacy") {
1325
- btcOk = bitcoinMessage__namespace.verify(msg, btc, envelope.btc_signature);
1326
- } else {
1327
- return fail("bad_scheme");
1328
- }
1329
- } catch {
1330
- btcOk = false;
1331
- }
1332
- if (!btcOk) return fail("btc_sig_invalid");
1333
- const ev = envelope.nostr_event;
1334
- if (!ev || ev.kind !== BINDING_KIND || typeof ev.id !== "string") return fail("malformed");
1335
- if (nostrEventId(ev) !== ev.id.toLowerCase()) return fail("nostr_id_invalid");
1336
- let nostrSigOk = false;
1337
- try {
1338
- nostrSigOk = secp256k1_js.schnorr.verify(fromHex(ev.sig), fromHex(ev.id), fromHex(ev.pubkey));
1339
- } catch {
1340
- nostrSigOk = false;
1341
- }
1342
- if (!nostrSigOk) return fail("nostr_sig_invalid");
1343
- let nostrXOnly;
1344
- try {
1345
- nostrXOnly = npubToXOnlyHex(nostr);
1346
- } catch {
1347
- return fail("nostr_key_mismatch");
1348
- }
1349
- if (nostrXOnly !== ev.pubkey.toLowerCase()) return fail("nostr_key_mismatch");
1350
- let content;
1351
- try {
1352
- content = JSON.parse(ev.content);
1353
- } catch {
1354
- return fail("message_mismatch");
1355
- }
1356
- if (content.message !== msg) return fail("message_mismatch");
1357
- if (content.btc_signature !== envelope.btc_signature) return fail("message_mismatch");
1358
- return { valid: true, status: "binding_ok", binding_id: bid, principal, btc, nostr };
1359
- } catch {
1360
- return fail("malformed");
1361
- }
1362
- }
1363
- function xOnlyHexToNpub(hex) {
1364
- const bytes = fromHex(hex);
1365
- if (bytes.length !== 32) throw new Error("x-only Nostr key must be 32 bytes");
1366
- return base.bech32.encode("npub", base.bech32.toWords(bytes), 90);
1367
- }
1368
- function buildBindingEventTemplate(params) {
1369
- const id = bindingId(params.message);
1370
- return {
1371
- kind: BINDING_KIND,
1372
- pubkey: params.nostrPubkeyHex.toLowerCase(),
1373
- created_at: params.createdAt ?? Math.floor(Date.now() / 1e3),
1374
- tags: [
1375
- ["d", `oc-attest-binding:${id}`],
1376
- ["btc", params.btc],
1377
- ["oc", "binding-attestation"],
1378
- ["v", "1"]
1379
- ],
1380
- content: JSON.stringify({ message: params.message, btc_signature: params.btcSignature })
1381
- };
1382
- }
1383
- function parseBindingFields(message) {
1384
- const body = message.split("\n");
1385
- const at = (i, prefix) => {
1386
- const line = body[i];
1387
- if (typeof line !== "string" || !line.startsWith(prefix)) {
1388
- throw new Error(`binding message line ${i + 1} is malformed`);
1389
- }
1390
- return line.slice(prefix.length);
1391
- };
1392
- return {
1393
- principal: at(2, "principal: "),
1394
- btc: at(3, "btc: "),
1395
- nostr: at(4, "nostr: ")
1396
- };
1397
- }
1398
- function toBase64Url(s) {
1399
- const bytes = new TextEncoder().encode(s);
1400
- let bin = "";
1401
- for (const b of bytes) bin += String.fromCharCode(b);
1402
- const b64 = typeof btoa !== "undefined" ? btoa(bin) : Buffer.from(bytes).toString("base64");
1403
- return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1404
- }
1405
- function assembleBindingEnvelope(params) {
1406
- const { principal, btc, nostr } = parseBindingFields(params.message);
1407
- return {
1408
- binding_id: bindingId(params.message),
1409
- v: 1,
1410
- principal,
1411
- btc,
1412
- nostr,
1413
- message: params.message,
1414
- message_b64url: toBase64Url(params.message),
1415
- btc_signature: params.btcSignature,
1416
- btc_scheme: params.btcScheme ?? "bip322",
1417
- nostr_event: params.nostrEvent
1418
- };
1419
- }
1420
1180
  var AUTH_HEADER = "orangecheck-auth";
1421
1181
  var AUTH_ACK = "I authorize this session under the OrangeCheck auth challenge.";
1422
1182
  function randomNonce() {
@@ -1872,12 +1632,12 @@ function getGistCreationUrl() {
1872
1632
  }
1873
1633
  var log7 = createLogger("identity-verification/nostr");
1874
1634
  var HEX_64_RE = /^[0-9a-f]{64}$/;
1875
- function toHex2(bytes) {
1635
+ function toHex(bytes) {
1876
1636
  let out = "";
1877
1637
  for (const b of bytes) out += b.toString(16).padStart(2, "0");
1878
1638
  return out;
1879
1639
  }
1880
- function fromHex2(hex) {
1640
+ function fromHex(hex) {
1881
1641
  if (hex.length % 2 !== 0) throw new Error("odd-length hex");
1882
1642
  const out = new Uint8Array(hex.length / 2);
1883
1643
  for (let i = 0; i < out.length; i++) {
@@ -1901,7 +1661,7 @@ function npubToHex(npub) {
1901
1661
  if (bytes.length !== 32) {
1902
1662
  throw new Error(`invalid npub payload length: ${bytes.length}`);
1903
1663
  }
1904
- return toHex2(Uint8Array.from(bytes));
1664
+ return toHex(Uint8Array.from(bytes));
1905
1665
  }
1906
1666
  async function queryNostrEvents(options) {
1907
1667
  const { authors, kinds, search, relays = DEFAULT_RELAYS, limit = 100 } = options;
@@ -1984,7 +1744,7 @@ async function verifyNostrEventSignature(event) {
1984
1744
  event.tags ?? [],
1985
1745
  event.content ?? ""
1986
1746
  ]);
1987
- const computedId = toHex2(sha2_js.sha256(new TextEncoder().encode(preimage)));
1747
+ const computedId = toHex(sha2_js.sha256(new TextEncoder().encode(preimage)));
1988
1748
  if (computedId !== event.id.toLowerCase()) {
1989
1749
  log7.warn(
1990
1750
  { eventId: event.id, computedId },
@@ -1992,7 +1752,7 @@ async function verifyNostrEventSignature(event) {
1992
1752
  );
1993
1753
  return false;
1994
1754
  }
1995
- return secp256k1_js.schnorr.verify(fromHex2(event.sig), fromHex2(event.id), fromHex2(event.pubkey));
1755
+ return secp256k1_js.schnorr.verify(fromHex(event.sig), fromHex(event.id), fromHex(event.pubkey));
1996
1756
  } catch (err) {
1997
1757
  log7.warn({ err }, "schnorr verify threw");
1998
1758
  return false;
@@ -2354,10 +2114,6 @@ var STATUS_META = {
2354
2114
 
2355
2115
  exports.DEFAULT_RELAYS = DEFAULT_RELAYS;
2356
2116
  exports.STATUS_META = STATUS_META;
2357
- exports.assembleBindingEnvelope = assembleBindingEnvelope;
2358
- exports.bindingId = bindingId;
2359
- exports.buildBindingEventTemplate = buildBindingEventTemplate;
2360
- exports.buildBindingMessage = buildBindingMessage;
2361
2117
  exports.buildCanonicalMessage = buildCanonicalMessage;
2362
2118
  exports.check = check;
2363
2119
  exports.computeAllScores = computeAllScores;
@@ -2409,13 +2165,11 @@ exports.supportsAutomaticVerification = supportsAutomaticVerification;
2409
2165
  exports.verify = verify2;
2410
2166
  exports.verifyAllIdentities = verifyAllIdentities;
2411
2167
  exports.verifyAttestationById = verifyAttestationById;
2412
- exports.verifyBinding = verifyBinding;
2413
2168
  exports.verifyChallenge = verifyChallenge;
2414
2169
  exports.verifyDnsIdentity = verifyDnsIdentity;
2415
2170
  exports.verifyGitHubIdentity = verifyGitHubIdentity;
2416
2171
  exports.verifyIdentity = verifyIdentity;
2417
2172
  exports.verifyNostrIdentity = verifyNostrIdentity;
2418
2173
  exports.verifyTwitterIdentity = verifyTwitterIdentity;
2419
- exports.xOnlyHexToNpub = xOnlyHexToNpub;
2420
2174
  //# sourceMappingURL=index.js.map
2421
2175
  //# sourceMappingURL=index.js.map