@orangecheck/sdk 1.16.0 → 1.16.2
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/attestation.d.mts +1 -1
- package/dist/attestation.d.ts +1 -1
- package/dist/attestation.js +86 -170
- package/dist/attestation.js.map +1 -1
- package/dist/attestation.mjs +86 -170
- package/dist/attestation.mjs.map +1 -1
- package/dist/canonical.d.mts +1 -1
- package/dist/canonical.d.ts +1 -1
- package/dist/challenge.d.mts +1 -1
- package/dist/challenge.d.ts +1 -1
- package/dist/identity.d.mts +1 -1
- package/dist/identity.d.ts +1 -1
- package/dist/identity.js.map +1 -1
- package/dist/identity.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +106 -173
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +106 -173
- package/dist/index.mjs.map +1 -1
- package/dist/nostr.d.mts +1 -1
- package/dist/nostr.d.ts +1 -1
- package/dist/nostr.js +86 -170
- package/dist/nostr.js.map +1 -1
- package/dist/nostr.mjs +86 -170
- package/dist/nostr.mjs.map +1 -1
- package/dist/{types-BBRMCgMo.d.mts → types-DsrYs3EB.d.mts} +1 -1
- package/dist/{types-BBRMCgMo.d.ts → types-DsrYs3EB.d.ts} +1 -1
- package/dist/verify.d.mts +2 -1
- package/dist/verify.d.ts +2 -1
- package/dist/verify.js +19 -0
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +19 -0
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -213,6 +213,7 @@ function logVerificationError(protocol, identifier, error, context) {
|
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
// src/utils/time.ts
|
|
216
|
+
var ISSUED_AHEAD_MS = 12e4;
|
|
216
217
|
var RFC3339 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
217
218
|
function rfc3339Ms(value) {
|
|
218
219
|
if (!value || !RFC3339.test(value)) return null;
|
|
@@ -305,11 +306,15 @@ function parseCanonicalMessage(msg) {
|
|
|
305
306
|
"ack"
|
|
306
307
|
]);
|
|
307
308
|
const extensions = {};
|
|
309
|
+
const keys = /* @__PURE__ */ new Set();
|
|
310
|
+
const repeated = [];
|
|
308
311
|
for (const line of lines) {
|
|
309
312
|
const idx = line.indexOf(":");
|
|
310
313
|
if (idx === -1) continue;
|
|
311
314
|
const key = line.slice(0, idx).trim().toLowerCase();
|
|
312
315
|
const val = line.slice(idx + 1).trim();
|
|
316
|
+
if (keys.has(key)) repeated.push(key);
|
|
317
|
+
keys.add(key);
|
|
313
318
|
if (!coreKeys.has(key) && val) extensions[key] = val;
|
|
314
319
|
}
|
|
315
320
|
const network = extensions["network"] || "mainnet";
|
|
@@ -318,6 +323,7 @@ function parseCanonicalMessage(msg) {
|
|
|
318
323
|
return {
|
|
319
324
|
core: { address, identities, issued_at },
|
|
320
325
|
expires,
|
|
326
|
+
repeated,
|
|
321
327
|
network,
|
|
322
328
|
extensions,
|
|
323
329
|
bond: bond !== void 0 && !isNaN(bond) && bond > 0 ? bond : void 0
|
|
@@ -436,6 +442,10 @@ async function verify(input, opts = {}) {
|
|
|
436
442
|
const parsed = parseCanonicalMessage(input.msg);
|
|
437
443
|
network = parsed.network || "mainnet";
|
|
438
444
|
const attestation_id = await generateAttestationId(input.msg);
|
|
445
|
+
if (parsed.repeated.length > 0) {
|
|
446
|
+
codes.push("decode_error");
|
|
447
|
+
return { ok: false, codes, network, attestation_id };
|
|
448
|
+
}
|
|
439
449
|
if (parsed.core.address !== input.addr) {
|
|
440
450
|
codes.push("bad_request");
|
|
441
451
|
return { ok: false, codes, network, attestation_id };
|
|
@@ -451,6 +461,15 @@ async function verify(input, opts = {}) {
|
|
|
451
461
|
return { ok: false, codes, network, attestation_id };
|
|
452
462
|
}
|
|
453
463
|
}
|
|
464
|
+
const issued = rfc3339Ms(parsed.core.issued_at);
|
|
465
|
+
if (issued === null) {
|
|
466
|
+
codes.push("decode_error");
|
|
467
|
+
return { ok: false, codes, network, attestation_id };
|
|
468
|
+
}
|
|
469
|
+
if (issued > Date.now() + ISSUED_AHEAD_MS) {
|
|
470
|
+
codes.push("not_yet_valid");
|
|
471
|
+
return { ok: false, codes, network, attestation_id };
|
|
472
|
+
}
|
|
454
473
|
if (parsed.expires !== void 0) {
|
|
455
474
|
const exp = rfc3339Ms(parsed.expires);
|
|
456
475
|
if (exp === null || exp < Date.now()) {
|
|
@@ -684,188 +703,98 @@ async function publishToRelays(event, relays = DEFAULT_RELAYS) {
|
|
|
684
703
|
log2.info({ successCount: success.length, failedCount: failed.length }, "Publishing complete");
|
|
685
704
|
return { success, failed };
|
|
686
705
|
}
|
|
687
|
-
|
|
706
|
+
var PAGE_LIMIT = 500;
|
|
707
|
+
var MAX_PAGES = 4;
|
|
708
|
+
async function querySubject(filter, relays, label) {
|
|
688
709
|
const events = [];
|
|
689
|
-
log2.info({ attestationId, relayCount: relays.length }, "Querying relays for attestation");
|
|
690
710
|
const deadlineAt = Date.now() + FANOUT_DEADLINE_MS;
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
711
|
+
await Promise.allSettled(
|
|
712
|
+
relays.map(async (relayUrl) => {
|
|
713
|
+
let ws = null;
|
|
714
|
+
try {
|
|
715
|
+
ws = new WebSocket(relayUrl);
|
|
716
|
+
const wsRef = ws;
|
|
717
|
+
await new Promise((resolve, reject) => {
|
|
718
|
+
const timeout = setTimeout(() => {
|
|
719
|
+
wsRef.close();
|
|
720
|
+
reject(new Error("Query timeout"));
|
|
721
|
+
}, budgetFor(deadlineAt));
|
|
722
|
+
const seen = /* @__PURE__ */ new Set();
|
|
723
|
+
let page = 0;
|
|
724
|
+
let inPage = 0;
|
|
725
|
+
let newInPage = 0;
|
|
726
|
+
let oldest = Infinity;
|
|
727
|
+
const ask = () => {
|
|
728
|
+
page++;
|
|
729
|
+
inPage = 0;
|
|
730
|
+
newInPage = 0;
|
|
731
|
+
const until = Number.isFinite(oldest) ? { until: oldest } : {};
|
|
732
|
+
wsRef.send(
|
|
733
|
+
JSON.stringify([
|
|
734
|
+
"REQ",
|
|
735
|
+
`ochk_${label}_${Date.now()}_${page}`,
|
|
736
|
+
{ ...filter, ...until, limit: PAGE_LIMIT }
|
|
737
|
+
])
|
|
738
|
+
);
|
|
739
|
+
};
|
|
740
|
+
wsRef.onopen = ask;
|
|
741
|
+
wsRef.onmessage = (msg) => {
|
|
742
|
+
try {
|
|
743
|
+
const data = JSON.parse(msg.data);
|
|
744
|
+
if (data[0] === "EVENT") {
|
|
745
|
+
const event = data[2];
|
|
746
|
+
const key = event.id ?? JSON.stringify(event);
|
|
747
|
+
inPage++;
|
|
748
|
+
if (!seen.has(key)) {
|
|
749
|
+
seen.add(key);
|
|
750
|
+
newInPage++;
|
|
751
|
+
events.push(event);
|
|
752
|
+
}
|
|
753
|
+
if (typeof event.created_at === "number") {
|
|
754
|
+
oldest = Math.min(oldest, event.created_at);
|
|
755
|
+
}
|
|
756
|
+
} else if (data[0] === "EOSE") {
|
|
757
|
+
wsRef.send(JSON.stringify(["CLOSE", data[1]]));
|
|
758
|
+
if (inPage >= PAGE_LIMIT && newInPage > 0 && page < MAX_PAGES) {
|
|
759
|
+
ask();
|
|
760
|
+
} else {
|
|
761
|
+
clearTimeout(timeout);
|
|
762
|
+
wsRef.close();
|
|
763
|
+
resolve();
|
|
764
|
+
}
|
|
715
765
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
};
|
|
719
|
-
wsRef.onmessage = (msg) => {
|
|
720
|
-
try {
|
|
721
|
-
const data = JSON.parse(msg.data);
|
|
722
|
-
if (data[0] === "EVENT") {
|
|
723
|
-
events.push(data[2]);
|
|
724
|
-
} else if (data[0] === "EOSE") {
|
|
725
|
-
cleanup();
|
|
726
|
-
resolve();
|
|
766
|
+
} catch (err) {
|
|
767
|
+
log2.error({ relay: relayUrl, error: err }, "Failed to parse event");
|
|
727
768
|
}
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
};
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
};
|
|
740
|
-
});
|
|
741
|
-
} catch (err) {
|
|
742
|
-
log2.error({ relay: relayUrl, error: err }, "Failed to query relay");
|
|
743
|
-
} finally {
|
|
744
|
-
if (ws && ws.readyState !== WebSocket.CLOSED) {
|
|
745
|
-
ws.close();
|
|
769
|
+
};
|
|
770
|
+
wsRef.onerror = (err) => {
|
|
771
|
+
clearTimeout(timeout);
|
|
772
|
+
log2.error({ relay: relayUrl, error: err }, "WebSocket error during query");
|
|
773
|
+
reject(err);
|
|
774
|
+
};
|
|
775
|
+
});
|
|
776
|
+
} catch (err) {
|
|
777
|
+
log2.error({ relay: relayUrl, error: err }, "Failed to query relay");
|
|
778
|
+
} finally {
|
|
779
|
+
if (ws && ws.readyState !== WebSocket.CLOSED) ws.close();
|
|
746
780
|
}
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
log2.info({ eventCount: events.length }, "Query complete");
|
|
781
|
+
})
|
|
782
|
+
);
|
|
783
|
+
log2.info({ label, eventCount: events.length }, "Query complete");
|
|
751
784
|
return events;
|
|
752
785
|
}
|
|
786
|
+
async function queryByAttestationId(attestationId, relays = DEFAULT_RELAYS) {
|
|
787
|
+
log2.info({ attestationId, relayCount: relays.length }, "Querying relays for attestation");
|
|
788
|
+
return querySubject({ kinds: [30078], "#d": [attestationId] }, relays, "id");
|
|
789
|
+
}
|
|
753
790
|
async function queryByAddress(address, relays = DEFAULT_RELAYS) {
|
|
754
|
-
const events = [];
|
|
755
791
|
log2.info({ address, relayCount: relays.length }, "Querying relays for address");
|
|
756
|
-
|
|
757
|
-
const queryPromises = relays.map(async (relayUrl) => {
|
|
758
|
-
try {
|
|
759
|
-
const ws = new WebSocket(relayUrl);
|
|
760
|
-
await new Promise((resolve, reject) => {
|
|
761
|
-
const timeout = setTimeout(() => {
|
|
762
|
-
ws.close();
|
|
763
|
-
reject(new Error("Query timeout"));
|
|
764
|
-
}, budgetFor(deadlineAt));
|
|
765
|
-
ws.onopen = () => {
|
|
766
|
-
const subscriptionId = `ochk_addr_${Date.now()}`;
|
|
767
|
-
ws.send(
|
|
768
|
-
JSON.stringify([
|
|
769
|
-
"REQ",
|
|
770
|
-
subscriptionId,
|
|
771
|
-
{
|
|
772
|
-
kinds: [30078],
|
|
773
|
-
// `#t`, NOT `#address`: NIP-12 relays index
|
|
774
|
-
// single-letter tags only, so `#address`
|
|
775
|
-
// matched nothing on any relay and this
|
|
776
|
-
// function returned empty for every real
|
|
777
|
-
// attestation. attest.ochk.io's verifier has
|
|
778
|
-
// queried `#t` since the same fix landed
|
|
779
|
-
// there; this is the back-port.
|
|
780
|
-
"#t": [address],
|
|
781
|
-
limit: 50
|
|
782
|
-
}
|
|
783
|
-
])
|
|
784
|
-
);
|
|
785
|
-
};
|
|
786
|
-
ws.onmessage = (msg) => {
|
|
787
|
-
try {
|
|
788
|
-
const data = JSON.parse(msg.data);
|
|
789
|
-
if (data[0] === "EVENT") {
|
|
790
|
-
events.push(data[2]);
|
|
791
|
-
} else if (data[0] === "EOSE") {
|
|
792
|
-
clearTimeout(timeout);
|
|
793
|
-
ws.close();
|
|
794
|
-
resolve();
|
|
795
|
-
}
|
|
796
|
-
} catch (err) {
|
|
797
|
-
log2.error({ relay: relayUrl, error: err }, "Failed to parse event");
|
|
798
|
-
}
|
|
799
|
-
};
|
|
800
|
-
ws.onerror = (err) => {
|
|
801
|
-
clearTimeout(timeout);
|
|
802
|
-
log2.error({ relay: relayUrl, error: err }, "WebSocket error during query");
|
|
803
|
-
reject(err);
|
|
804
|
-
};
|
|
805
|
-
});
|
|
806
|
-
} catch (err) {
|
|
807
|
-
log2.error({ relay: relayUrl, error: err }, "Failed to query relay");
|
|
808
|
-
}
|
|
809
|
-
});
|
|
810
|
-
await Promise.allSettled(queryPromises);
|
|
811
|
-
log2.info({ eventCount: events.length }, "Query complete");
|
|
812
|
-
return events;
|
|
792
|
+
return querySubject({ kinds: [30078], "#t": [address] }, relays, "addr");
|
|
813
793
|
}
|
|
814
794
|
async function queryByIdentity(protocol, identifier, relays = DEFAULT_RELAYS) {
|
|
815
|
-
const
|
|
816
|
-
const identityTag = `${protocol}:${identifier}`;
|
|
817
|
-
const identityTags = protocol === "nostr" ? nostrIdentifierForms(identifier).map((f) => `nostr:${f}`) : [identityTag];
|
|
795
|
+
const identityTags = protocol === "nostr" ? nostrIdentifierForms(identifier).map((f) => `nostr:${f}`) : [`${protocol}:${identifier}`];
|
|
818
796
|
log2.info({ protocol, identifier, relayCount: relays.length }, "Querying relays for identity");
|
|
819
|
-
|
|
820
|
-
const queryPromises = relays.map(async (relayUrl) => {
|
|
821
|
-
try {
|
|
822
|
-
const ws = new WebSocket(relayUrl);
|
|
823
|
-
await new Promise((resolve, reject) => {
|
|
824
|
-
const timeout = setTimeout(() => {
|
|
825
|
-
ws.close();
|
|
826
|
-
reject(new Error("Query timeout"));
|
|
827
|
-
}, budgetFor(deadlineAt));
|
|
828
|
-
ws.onopen = () => {
|
|
829
|
-
const subscriptionId = `ochk_identity_${Date.now()}`;
|
|
830
|
-
ws.send(
|
|
831
|
-
JSON.stringify([
|
|
832
|
-
"REQ",
|
|
833
|
-
subscriptionId,
|
|
834
|
-
{
|
|
835
|
-
kinds: [30078],
|
|
836
|
-
"#i": identityTags,
|
|
837
|
-
limit: 10
|
|
838
|
-
}
|
|
839
|
-
])
|
|
840
|
-
);
|
|
841
|
-
};
|
|
842
|
-
ws.onmessage = (msg) => {
|
|
843
|
-
try {
|
|
844
|
-
const data = JSON.parse(msg.data);
|
|
845
|
-
if (data[0] === "EVENT") {
|
|
846
|
-
events.push(data[2]);
|
|
847
|
-
} else if (data[0] === "EOSE") {
|
|
848
|
-
clearTimeout(timeout);
|
|
849
|
-
ws.close();
|
|
850
|
-
resolve();
|
|
851
|
-
}
|
|
852
|
-
} catch (err) {
|
|
853
|
-
log2.error({ relay: relayUrl, error: err }, "Failed to parse event");
|
|
854
|
-
}
|
|
855
|
-
};
|
|
856
|
-
ws.onerror = (err) => {
|
|
857
|
-
clearTimeout(timeout);
|
|
858
|
-
log2.error({ relay: relayUrl, error: err }, "WebSocket error during query");
|
|
859
|
-
reject(err);
|
|
860
|
-
};
|
|
861
|
-
});
|
|
862
|
-
} catch (err) {
|
|
863
|
-
log2.error({ relay: relayUrl, error: err }, "Failed to query relay");
|
|
864
|
-
}
|
|
865
|
-
});
|
|
866
|
-
await Promise.allSettled(queryPromises);
|
|
867
|
-
log2.info({ eventCount: events.length }, "Query complete");
|
|
868
|
-
return events;
|
|
797
|
+
return querySubject({ kinds: [30078], "#i": identityTags }, relays, "identity");
|
|
869
798
|
}
|
|
870
799
|
async function queryRecent(relays = DEFAULT_RELAYS, limit = 200) {
|
|
871
800
|
const events = [];
|
|
@@ -948,6 +877,7 @@ function signedEnvelope(envelope) {
|
|
|
948
877
|
return null;
|
|
949
878
|
}
|
|
950
879
|
if (!parsed.core.address || rfc3339Ms(parsed.core.issued_at) === null) return null;
|
|
880
|
+
if (parsed.repeated.length > 0) return null;
|
|
951
881
|
const { expires_at: _copy, ...rest } = envelope;
|
|
952
882
|
return {
|
|
953
883
|
...rest,
|
|
@@ -1179,8 +1109,6 @@ function extractAttestationIdFromUrl(url) {
|
|
|
1179
1109
|
}
|
|
1180
1110
|
|
|
1181
1111
|
// src/check.ts
|
|
1182
|
-
var ISSUED_AHEAD_MS = 12e4;
|
|
1183
|
-
var MAX_CANDIDATES = 20;
|
|
1184
1112
|
async function check(params) {
|
|
1185
1113
|
const {
|
|
1186
1114
|
addr,
|
|
@@ -1208,7 +1136,7 @@ async function check(params) {
|
|
|
1208
1136
|
return { ok: false, sats: 0, days: 0, score: 0, reasons: ["not_found"] };
|
|
1209
1137
|
}
|
|
1210
1138
|
let env = envelopes[0];
|
|
1211
|
-
for (const candidate of envelopes
|
|
1139
|
+
for (const candidate of envelopes) {
|
|
1212
1140
|
if (await signedBy(candidate)) {
|
|
1213
1141
|
env = candidate;
|
|
1214
1142
|
break;
|
|
@@ -2359,6 +2287,11 @@ var STATUS_META = {
|
|
|
2359
2287
|
detail: "This signature has passed its expiration date. Generate a new signature with a fresh message.",
|
|
2360
2288
|
severity: "error"
|
|
2361
2289
|
},
|
|
2290
|
+
not_yet_valid: {
|
|
2291
|
+
label: "Not valid yet",
|
|
2292
|
+
detail: "The message is dated ahead of this clock. It counts once that time arrives, or once a clock that is wrong is set right.",
|
|
2293
|
+
severity: "error"
|
|
2294
|
+
},
|
|
2362
2295
|
network_testmode: {
|
|
2363
2296
|
label: "Test network detected",
|
|
2364
2297
|
detail: "This signature uses testnet or signet. Test networks are for development only and cannot be verified in production mode.",
|