@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.mjs CHANGED
@@ -1155,189 +1155,6 @@ async function check(params) {
1155
1155
  ...reasons.length ? { reasons } : {}
1156
1156
  };
1157
1157
  }
1158
- var HEADER = "orangecheck-binding";
1159
- var ACK = "I attest the keys named in this message are one principal.";
1160
- var BINDING_KIND = 30079;
1161
- function toHex(bytes) {
1162
- let out = "";
1163
- for (const b of bytes) out += b.toString(16).padStart(2, "0");
1164
- return out;
1165
- }
1166
- function fromHex(hex) {
1167
- const clean = hex.toLowerCase();
1168
- if (clean.length % 2 !== 0 || /[^0-9a-f]/.test(clean)) {
1169
- throw new Error("invalid hex");
1170
- }
1171
- const out = new Uint8Array(clean.length / 2);
1172
- for (let i = 0; i < out.length; i++) out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
1173
- return out;
1174
- }
1175
- function assertPrintableAscii(field, value) {
1176
- for (let i = 0; i < value.length; i++) {
1177
- const c = value.charCodeAt(i);
1178
- if (c < 32 || c > 126) {
1179
- throw new Error(
1180
- `binding ${field} contains an unsafe character (0x${c.toString(16)}) \u2014 line-smuggling defense (SPEC-BINDING \xA73.5)`
1181
- );
1182
- }
1183
- }
1184
- }
1185
- function buildBindingMessage(input) {
1186
- assertPrintableAscii("principal", input.principal);
1187
- assertPrintableAscii("btc", input.btc);
1188
- assertPrintableAscii("nostr", input.nostr);
1189
- assertPrintableAscii("nonce", input.nonce);
1190
- assertPrintableAscii("issued_at", input.issued_at);
1191
- const core = [
1192
- HEADER,
1193
- "v: 1",
1194
- `principal: ${input.principal}`,
1195
- `btc: ${input.btc}`,
1196
- `nostr: ${input.nostr}`,
1197
- `nonce: ${input.nonce}`,
1198
- `issued_at: ${input.issued_at}`,
1199
- `ack: ${ACK}`
1200
- ];
1201
- const ext = [];
1202
- if (input.extensions) {
1203
- for (const key of Object.keys(input.extensions).sort()) {
1204
- const value = input.extensions[key];
1205
- if (value == null) continue;
1206
- if (!/^[a-z]+$/.test(key)) {
1207
- throw new Error(`binding extension key "${key}" must be lowercase ASCII`);
1208
- }
1209
- assertPrintableAscii(`extension ${key}`, value);
1210
- ext.push(`${key}: ${value}`);
1211
- }
1212
- }
1213
- return [...core, ...ext].join("\n") + "\n";
1214
- }
1215
- function bindingId(message) {
1216
- return toHex(sha256(new TextEncoder().encode(message)));
1217
- }
1218
- function linePrefix(line, prefix) {
1219
- if (typeof line !== "string" || !line.startsWith(prefix)) return null;
1220
- return line.slice(prefix.length);
1221
- }
1222
- function nostrEventId(ev) {
1223
- const serialized = JSON.stringify([
1224
- 0,
1225
- ev.pubkey,
1226
- ev.created_at,
1227
- ev.kind,
1228
- ev.tags,
1229
- ev.content
1230
- ]);
1231
- return toHex(sha256(new TextEncoder().encode(serialized)));
1232
- }
1233
- function npubToXOnlyHex(npub) {
1234
- const decoded = bech32.decode(npub, 90);
1235
- if (decoded.prefix !== "npub") throw new Error("not an npub");
1236
- const bytes = Uint8Array.from(bech32.fromWords(decoded.words));
1237
- if (bytes.length !== 32) throw new Error("npub payload is not 32 bytes");
1238
- return toHex(bytes);
1239
- }
1240
- function verifyBinding(envelope) {
1241
- const fail = (status) => ({
1242
- valid: false,
1243
- status
1244
- });
1245
- try {
1246
- const msg = envelope.message;
1247
- if (typeof msg !== "string" || msg.length === 0) return fail("malformed");
1248
- const lines = msg.split("\n");
1249
- if ((lines[0] ?? "") !== HEADER) return fail("bad_header");
1250
- if (lines.length < 9 || lines[lines.length - 1] !== "") return fail("malformed");
1251
- const body = lines.slice(0, -1);
1252
- if (body.length < 8) return fail("malformed");
1253
- if (body[1] !== "v: 1") return fail("malformed");
1254
- if (body[7] !== `ack: ${ACK}`) return fail("bad_ack");
1255
- const principal = linePrefix(body[2], "principal: ");
1256
- const btc = linePrefix(body[3], "btc: ");
1257
- const nostr = linePrefix(body[4], "nostr: ");
1258
- const nonce = linePrefix(body[5], "nonce: ");
1259
- const issuedAt = linePrefix(body[6], "issued_at: ");
1260
- if (principal == null || btc == null || nostr == null || nonce == null || issuedAt == null) {
1261
- return fail("malformed");
1262
- }
1263
- for (const value of [principal, btc, nostr, nonce, issuedAt]) {
1264
- for (let i = 0; i < value.length; i++) {
1265
- const c = value.charCodeAt(i);
1266
- if (c < 32 || c > 126) return fail("malformed");
1267
- }
1268
- }
1269
- if (!/^did:oc:[0-9a-f]{32}$/.test(principal)) return fail("bad_principal");
1270
- if (!/^[0-9a-f]{32}$/.test(nonce)) return fail("malformed");
1271
- const ext = {};
1272
- let prevKey = "";
1273
- for (const line of body.slice(8)) {
1274
- const idx = line.indexOf(": ");
1275
- if (idx <= 0) return fail("malformed");
1276
- const key = line.slice(0, idx);
1277
- const value = line.slice(idx + 2);
1278
- if (!/^[a-z]+$/.test(key)) return fail("malformed");
1279
- if (key <= prevKey) return fail("ext_unsorted");
1280
- prevKey = key;
1281
- ext[key] = value;
1282
- }
1283
- const bid = bindingId(msg);
1284
- if (envelope.binding_id && envelope.binding_id.toLowerCase() !== bid) {
1285
- return fail("id_mismatch");
1286
- }
1287
- if (envelope.btc && envelope.btc !== btc) return fail("field_mismatch");
1288
- if (envelope.nostr && envelope.nostr !== nostr) return fail("field_mismatch");
1289
- if (envelope.principal && envelope.principal !== principal) return fail("field_mismatch");
1290
- if (ext.expires) {
1291
- const t = Date.parse(ext.expires);
1292
- if (!Number.isNaN(t) && Date.now() > t) return fail("expired");
1293
- }
1294
- if (typeof envelope.btc_signature !== "string" || !envelope.btc_signature) {
1295
- return fail("btc_sig_invalid");
1296
- }
1297
- const scheme = envelope.btc_scheme ?? "bip322";
1298
- let btcOk = false;
1299
- try {
1300
- if (scheme === "bip322") {
1301
- btcOk = Verifier.verifySignature(btc, msg, envelope.btc_signature);
1302
- } else if (scheme === "legacy") {
1303
- btcOk = bitcoinMessage.verify(msg, btc, envelope.btc_signature);
1304
- } else {
1305
- return fail("bad_scheme");
1306
- }
1307
- } catch {
1308
- btcOk = false;
1309
- }
1310
- if (!btcOk) return fail("btc_sig_invalid");
1311
- const ev = envelope.nostr_event;
1312
- if (!ev || ev.kind !== BINDING_KIND || typeof ev.id !== "string") return fail("malformed");
1313
- if (nostrEventId(ev) !== ev.id.toLowerCase()) return fail("nostr_id_invalid");
1314
- let nostrSigOk = false;
1315
- try {
1316
- nostrSigOk = schnorr.verify(fromHex(ev.sig), fromHex(ev.id), fromHex(ev.pubkey));
1317
- } catch {
1318
- nostrSigOk = false;
1319
- }
1320
- if (!nostrSigOk) return fail("nostr_sig_invalid");
1321
- let nostrXOnly;
1322
- try {
1323
- nostrXOnly = npubToXOnlyHex(nostr);
1324
- } catch {
1325
- return fail("nostr_key_mismatch");
1326
- }
1327
- if (nostrXOnly !== ev.pubkey.toLowerCase()) return fail("nostr_key_mismatch");
1328
- let content;
1329
- try {
1330
- content = JSON.parse(ev.content);
1331
- } catch {
1332
- return fail("message_mismatch");
1333
- }
1334
- if (content.message !== msg) return fail("message_mismatch");
1335
- if (content.btc_signature !== envelope.btc_signature) return fail("message_mismatch");
1336
- return { valid: true, status: "binding_ok", binding_id: bid, principal, btc, nostr };
1337
- } catch {
1338
- return fail("malformed");
1339
- }
1340
- }
1341
1158
  var AUTH_HEADER = "orangecheck-auth";
1342
1159
  var AUTH_ACK = "I authorize this session under the OrangeCheck auth challenge.";
1343
1160
  function randomNonce() {
@@ -1793,12 +1610,12 @@ function getGistCreationUrl() {
1793
1610
  }
1794
1611
  var log7 = createLogger("identity-verification/nostr");
1795
1612
  var HEX_64_RE = /^[0-9a-f]{64}$/;
1796
- function toHex2(bytes) {
1613
+ function toHex(bytes) {
1797
1614
  let out = "";
1798
1615
  for (const b of bytes) out += b.toString(16).padStart(2, "0");
1799
1616
  return out;
1800
1617
  }
1801
- function fromHex2(hex) {
1618
+ function fromHex(hex) {
1802
1619
  if (hex.length % 2 !== 0) throw new Error("odd-length hex");
1803
1620
  const out = new Uint8Array(hex.length / 2);
1804
1621
  for (let i = 0; i < out.length; i++) {
@@ -1822,7 +1639,7 @@ function npubToHex(npub) {
1822
1639
  if (bytes.length !== 32) {
1823
1640
  throw new Error(`invalid npub payload length: ${bytes.length}`);
1824
1641
  }
1825
- return toHex2(Uint8Array.from(bytes));
1642
+ return toHex(Uint8Array.from(bytes));
1826
1643
  }
1827
1644
  async function queryNostrEvents(options) {
1828
1645
  const { authors, kinds, search, relays = DEFAULT_RELAYS, limit = 100 } = options;
@@ -1905,7 +1722,7 @@ async function verifyNostrEventSignature(event) {
1905
1722
  event.tags ?? [],
1906
1723
  event.content ?? ""
1907
1724
  ]);
1908
- const computedId = toHex2(sha256(new TextEncoder().encode(preimage)));
1725
+ const computedId = toHex(sha256(new TextEncoder().encode(preimage)));
1909
1726
  if (computedId !== event.id.toLowerCase()) {
1910
1727
  log7.warn(
1911
1728
  { eventId: event.id, computedId },
@@ -1913,7 +1730,7 @@ async function verifyNostrEventSignature(event) {
1913
1730
  );
1914
1731
  return false;
1915
1732
  }
1916
- return schnorr.verify(fromHex2(event.sig), fromHex2(event.id), fromHex2(event.pubkey));
1733
+ return schnorr.verify(fromHex(event.sig), fromHex(event.id), fromHex(event.pubkey));
1917
1734
  } catch (err) {
1918
1735
  log7.warn({ err }, "schnorr verify threw");
1919
1736
  return false;
@@ -2273,6 +2090,6 @@ var STATUS_META = {
2273
2090
  }
2274
2091
  };
2275
2092
 
2276
- export { DEFAULT_RELAYS, STATUS_META, bindingId, buildBindingMessage, buildCanonicalMessage, check, computeAllScores, computeScore, createAttestation, createAttestationEnvelope, createAttestationEvent, discoverAttestations, extractAttestationIdFromUrl, formatIdentities, formatIdentitiesForDisplay, generateAttestationId, generateGistTemplate, generateTweetText, generateWellKnownContent, getAttestationsForAddress, getAttestationsForIdentity, getDnsVerificationInstructions, getGistCreationUrl, getGitHubVerificationInstructions, getManualVerificationInstructions, getNip07Info, getNostrPublicKey, getNostrVerificationInstructions, getTweetUrl, getTwitterComposeUrl, getTwitterVerificationInstructions, getVerificationInstructions, getVerificationSummary, getVerificationUrl, getWellKnownUrl, isDnsIdentityVerified, isGitHubIdentityVerified, isNip07Available, isNostrIdentityVerified, isValidDomain, isValidTweetUrl, issueChallenge, parseAttestationFromEvent, parseIdentities, publishAttestation, publishToRelays, queryByAddress, queryByAttestationId, queryByIdentity, requiresManualVerification, signNostrEvent, supportsAutomaticVerification, verify2 as verify, verifyAllIdentities, verifyAttestationById, verifyBinding, verifyChallenge, verifyDnsIdentity, verifyGitHubIdentity, verifyIdentity, verifyNostrIdentity, verifyTwitterIdentity };
2093
+ export { DEFAULT_RELAYS, STATUS_META, buildCanonicalMessage, check, computeAllScores, computeScore, createAttestation, createAttestationEnvelope, createAttestationEvent, discoverAttestations, extractAttestationIdFromUrl, formatIdentities, formatIdentitiesForDisplay, generateAttestationId, generateGistTemplate, generateTweetText, generateWellKnownContent, getAttestationsForAddress, getAttestationsForIdentity, getDnsVerificationInstructions, getGistCreationUrl, getGitHubVerificationInstructions, getManualVerificationInstructions, getNip07Info, getNostrPublicKey, getNostrVerificationInstructions, getTweetUrl, getTwitterComposeUrl, getTwitterVerificationInstructions, getVerificationInstructions, getVerificationSummary, getVerificationUrl, getWellKnownUrl, isDnsIdentityVerified, isGitHubIdentityVerified, isNip07Available, isNostrIdentityVerified, isValidDomain, isValidTweetUrl, issueChallenge, parseAttestationFromEvent, parseIdentities, publishAttestation, publishToRelays, queryByAddress, queryByAttestationId, queryByIdentity, requiresManualVerification, signNostrEvent, supportsAutomaticVerification, verify2 as verify, verifyAllIdentities, verifyAttestationById, verifyChallenge, verifyDnsIdentity, verifyGitHubIdentity, verifyIdentity, verifyNostrIdentity, verifyTwitterIdentity };
2277
2094
  //# sourceMappingURL=index.mjs.map
2278
2095
  //# sourceMappingURL=index.mjs.map