@orangecheck/sdk 1.1.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,50 +33,6 @@ interface CheckResult {
33
33
  }
34
34
  declare function check(params: CheckParams): Promise<CheckResult>;
35
35
 
36
- interface BindingInput {
37
- principal: string;
38
- btc: string;
39
- nostr: string;
40
- nonce: string;
41
- issued_at: string;
42
- extensions?: Record<string, string>;
43
- }
44
- interface BindingNostrEvent {
45
- id: string;
46
- pubkey: string;
47
- kind: number;
48
- created_at: number;
49
- tags: string[][];
50
- content: string;
51
- sig: string;
52
- }
53
- interface BindingEnvelope {
54
- binding_id?: string;
55
- v?: number;
56
- principal?: string;
57
- btc?: string;
58
- nostr?: string;
59
- message: string;
60
- btc_signature?: string;
61
- btc_scheme?: 'bip322' | 'legacy';
62
- nostr_event?: BindingNostrEvent;
63
- }
64
- 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';
65
- type BindingVerifyResult = {
66
- valid: true;
67
- status: 'binding_ok';
68
- binding_id: string;
69
- principal: string;
70
- btc: string;
71
- nostr: string;
72
- } | {
73
- valid: false;
74
- status: Exclude<BindingStatus, 'binding_ok'>;
75
- };
76
- declare function buildBindingMessage(input: BindingInput): string;
77
- declare function bindingId(message: string): string;
78
- declare function verifyBinding(envelope: BindingEnvelope): BindingVerifyResult;
79
-
80
36
  declare function isNip07Available(): boolean;
81
37
  declare function getNostrPublicKey(): Promise<string | null>;
82
38
  declare function signNostrEvent(event: Omit<NostrEvent, 'id' | 'sig'>): Promise<NostrEvent | null>;
@@ -94,4 +50,4 @@ interface StatusMeta {
94
50
  }
95
51
  declare const STATUS_META: Record<StatusCode, StatusMeta>;
96
52
 
97
- export { type BindingEnvelope, type BindingInput, type BindingNostrEvent, type BindingStatus, type BindingVerifyResult, type CheckParams, type CheckResult, IdentityBinding, Network, NostrEvent, STATUS_META, type Severity, StatusCode, type StatusMeta, VerifyOptions, bindingId, buildBindingMessage, check, getNip07Info, getNostrPublicKey, isNip07Available, signNostrEvent, verifyBinding };
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,50 +33,6 @@ interface CheckResult {
33
33
  }
34
34
  declare function check(params: CheckParams): Promise<CheckResult>;
35
35
 
36
- interface BindingInput {
37
- principal: string;
38
- btc: string;
39
- nostr: string;
40
- nonce: string;
41
- issued_at: string;
42
- extensions?: Record<string, string>;
43
- }
44
- interface BindingNostrEvent {
45
- id: string;
46
- pubkey: string;
47
- kind: number;
48
- created_at: number;
49
- tags: string[][];
50
- content: string;
51
- sig: string;
52
- }
53
- interface BindingEnvelope {
54
- binding_id?: string;
55
- v?: number;
56
- principal?: string;
57
- btc?: string;
58
- nostr?: string;
59
- message: string;
60
- btc_signature?: string;
61
- btc_scheme?: 'bip322' | 'legacy';
62
- nostr_event?: BindingNostrEvent;
63
- }
64
- 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';
65
- type BindingVerifyResult = {
66
- valid: true;
67
- status: 'binding_ok';
68
- binding_id: string;
69
- principal: string;
70
- btc: string;
71
- nostr: string;
72
- } | {
73
- valid: false;
74
- status: Exclude<BindingStatus, 'binding_ok'>;
75
- };
76
- declare function buildBindingMessage(input: BindingInput): string;
77
- declare function bindingId(message: string): string;
78
- declare function verifyBinding(envelope: BindingEnvelope): BindingVerifyResult;
79
-
80
36
  declare function isNip07Available(): boolean;
81
37
  declare function getNostrPublicKey(): Promise<string | null>;
82
38
  declare function signNostrEvent(event: Omit<NostrEvent, 'id' | 'sig'>): Promise<NostrEvent | null>;
@@ -94,4 +50,4 @@ interface StatusMeta {
94
50
  }
95
51
  declare const STATUS_META: Record<StatusCode, StatusMeta>;
96
52
 
97
- export { type BindingEnvelope, type BindingInput, type BindingNostrEvent, type BindingStatus, type BindingVerifyResult, type CheckParams, type CheckResult, IdentityBinding, Network, NostrEvent, STATUS_META, type Severity, StatusCode, type StatusMeta, VerifyOptions, bindingId, buildBindingMessage, check, getNip07Info, getNostrPublicKey, isNip07Available, signNostrEvent, verifyBinding };
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,189 +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
1180
  var AUTH_HEADER = "orangecheck-auth";
1364
1181
  var AUTH_ACK = "I authorize this session under the OrangeCheck auth challenge.";
1365
1182
  function randomNonce() {
@@ -1815,12 +1632,12 @@ function getGistCreationUrl() {
1815
1632
  }
1816
1633
  var log7 = createLogger("identity-verification/nostr");
1817
1634
  var HEX_64_RE = /^[0-9a-f]{64}$/;
1818
- function toHex2(bytes) {
1635
+ function toHex(bytes) {
1819
1636
  let out = "";
1820
1637
  for (const b of bytes) out += b.toString(16).padStart(2, "0");
1821
1638
  return out;
1822
1639
  }
1823
- function fromHex2(hex) {
1640
+ function fromHex(hex) {
1824
1641
  if (hex.length % 2 !== 0) throw new Error("odd-length hex");
1825
1642
  const out = new Uint8Array(hex.length / 2);
1826
1643
  for (let i = 0; i < out.length; i++) {
@@ -1844,7 +1661,7 @@ function npubToHex(npub) {
1844
1661
  if (bytes.length !== 32) {
1845
1662
  throw new Error(`invalid npub payload length: ${bytes.length}`);
1846
1663
  }
1847
- return toHex2(Uint8Array.from(bytes));
1664
+ return toHex(Uint8Array.from(bytes));
1848
1665
  }
1849
1666
  async function queryNostrEvents(options) {
1850
1667
  const { authors, kinds, search, relays = DEFAULT_RELAYS, limit = 100 } = options;
@@ -1927,7 +1744,7 @@ async function verifyNostrEventSignature(event) {
1927
1744
  event.tags ?? [],
1928
1745
  event.content ?? ""
1929
1746
  ]);
1930
- const computedId = toHex2(sha2_js.sha256(new TextEncoder().encode(preimage)));
1747
+ const computedId = toHex(sha2_js.sha256(new TextEncoder().encode(preimage)));
1931
1748
  if (computedId !== event.id.toLowerCase()) {
1932
1749
  log7.warn(
1933
1750
  { eventId: event.id, computedId },
@@ -1935,7 +1752,7 @@ async function verifyNostrEventSignature(event) {
1935
1752
  );
1936
1753
  return false;
1937
1754
  }
1938
- 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));
1939
1756
  } catch (err) {
1940
1757
  log7.warn({ err }, "schnorr verify threw");
1941
1758
  return false;
@@ -2297,8 +2114,6 @@ var STATUS_META = {
2297
2114
 
2298
2115
  exports.DEFAULT_RELAYS = DEFAULT_RELAYS;
2299
2116
  exports.STATUS_META = STATUS_META;
2300
- exports.bindingId = bindingId;
2301
- exports.buildBindingMessage = buildBindingMessage;
2302
2117
  exports.buildCanonicalMessage = buildCanonicalMessage;
2303
2118
  exports.check = check;
2304
2119
  exports.computeAllScores = computeAllScores;
@@ -2350,7 +2165,6 @@ exports.supportsAutomaticVerification = supportsAutomaticVerification;
2350
2165
  exports.verify = verify2;
2351
2166
  exports.verifyAllIdentities = verifyAllIdentities;
2352
2167
  exports.verifyAttestationById = verifyAttestationById;
2353
- exports.verifyBinding = verifyBinding;
2354
2168
  exports.verifyChallenge = verifyChallenge;
2355
2169
  exports.verifyDnsIdentity = verifyDnsIdentity;
2356
2170
  exports.verifyGitHubIdentity = verifyGitHubIdentity;