@orangecheck/sdk 1.16.1 → 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.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/identity.js.map +1 -1
- package/dist/identity.mjs.map +1 -1
- package/dist/index.js +91 -172
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +91 -172
- package/dist/index.mjs.map +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/verify.d.mts +1 -0
- package/dist/verify.d.ts +1 -0
- package/dist/verify.js +9 -0
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +9 -0
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -306,11 +306,15 @@ function parseCanonicalMessage(msg) {
|
|
|
306
306
|
"ack"
|
|
307
307
|
]);
|
|
308
308
|
const extensions = {};
|
|
309
|
+
const keys = /* @__PURE__ */ new Set();
|
|
310
|
+
const repeated = [];
|
|
309
311
|
for (const line of lines) {
|
|
310
312
|
const idx = line.indexOf(":");
|
|
311
313
|
if (idx === -1) continue;
|
|
312
314
|
const key = line.slice(0, idx).trim().toLowerCase();
|
|
313
315
|
const val = line.slice(idx + 1).trim();
|
|
316
|
+
if (keys.has(key)) repeated.push(key);
|
|
317
|
+
keys.add(key);
|
|
314
318
|
if (!coreKeys.has(key) && val) extensions[key] = val;
|
|
315
319
|
}
|
|
316
320
|
const network = extensions["network"] || "mainnet";
|
|
@@ -319,6 +323,7 @@ function parseCanonicalMessage(msg) {
|
|
|
319
323
|
return {
|
|
320
324
|
core: { address, identities, issued_at },
|
|
321
325
|
expires,
|
|
326
|
+
repeated,
|
|
322
327
|
network,
|
|
323
328
|
extensions,
|
|
324
329
|
bond: bond !== void 0 && !isNaN(bond) && bond > 0 ? bond : void 0
|
|
@@ -437,6 +442,10 @@ async function verify(input, opts = {}) {
|
|
|
437
442
|
const parsed = parseCanonicalMessage(input.msg);
|
|
438
443
|
network = parsed.network || "mainnet";
|
|
439
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
|
+
}
|
|
440
449
|
if (parsed.core.address !== input.addr) {
|
|
441
450
|
codes.push("bad_request");
|
|
442
451
|
return { ok: false, codes, network, attestation_id };
|
|
@@ -694,188 +703,98 @@ async function publishToRelays(event, relays = DEFAULT_RELAYS) {
|
|
|
694
703
|
log2.info({ successCount: success.length, failedCount: failed.length }, "Publishing complete");
|
|
695
704
|
return { success, failed };
|
|
696
705
|
}
|
|
697
|
-
|
|
706
|
+
var PAGE_LIMIT = 500;
|
|
707
|
+
var MAX_PAGES = 4;
|
|
708
|
+
async function querySubject(filter, relays, label) {
|
|
698
709
|
const events = [];
|
|
699
|
-
log2.info({ attestationId, relayCount: relays.length }, "Querying relays for attestation");
|
|
700
710
|
const deadlineAt = Date.now() + FANOUT_DEADLINE_MS;
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
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
|
+
}
|
|
725
765
|
}
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
};
|
|
729
|
-
wsRef.onmessage = (msg) => {
|
|
730
|
-
try {
|
|
731
|
-
const data = JSON.parse(msg.data);
|
|
732
|
-
if (data[0] === "EVENT") {
|
|
733
|
-
events.push(data[2]);
|
|
734
|
-
} else if (data[0] === "EOSE") {
|
|
735
|
-
cleanup();
|
|
736
|
-
resolve();
|
|
766
|
+
} catch (err) {
|
|
767
|
+
log2.error({ relay: relayUrl, error: err }, "Failed to parse event");
|
|
737
768
|
}
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
};
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
};
|
|
750
|
-
});
|
|
751
|
-
} catch (err) {
|
|
752
|
-
log2.error({ relay: relayUrl, error: err }, "Failed to query relay");
|
|
753
|
-
} finally {
|
|
754
|
-
if (ws && ws.readyState !== WebSocket.CLOSED) {
|
|
755
|
-
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();
|
|
756
780
|
}
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
log2.info({ eventCount: events.length }, "Query complete");
|
|
781
|
+
})
|
|
782
|
+
);
|
|
783
|
+
log2.info({ label, eventCount: events.length }, "Query complete");
|
|
761
784
|
return events;
|
|
762
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
|
+
}
|
|
763
790
|
async function queryByAddress(address, relays = DEFAULT_RELAYS) {
|
|
764
|
-
const events = [];
|
|
765
791
|
log2.info({ address, relayCount: relays.length }, "Querying relays for address");
|
|
766
|
-
|
|
767
|
-
const queryPromises = relays.map(async (relayUrl) => {
|
|
768
|
-
try {
|
|
769
|
-
const ws = new WebSocket(relayUrl);
|
|
770
|
-
await new Promise((resolve, reject) => {
|
|
771
|
-
const timeout = setTimeout(() => {
|
|
772
|
-
ws.close();
|
|
773
|
-
reject(new Error("Query timeout"));
|
|
774
|
-
}, budgetFor(deadlineAt));
|
|
775
|
-
ws.onopen = () => {
|
|
776
|
-
const subscriptionId = `ochk_addr_${Date.now()}`;
|
|
777
|
-
ws.send(
|
|
778
|
-
JSON.stringify([
|
|
779
|
-
"REQ",
|
|
780
|
-
subscriptionId,
|
|
781
|
-
{
|
|
782
|
-
kinds: [30078],
|
|
783
|
-
// `#t`, NOT `#address`: NIP-12 relays index
|
|
784
|
-
// single-letter tags only, so `#address`
|
|
785
|
-
// matched nothing on any relay and this
|
|
786
|
-
// function returned empty for every real
|
|
787
|
-
// attestation. attest.ochk.io's verifier has
|
|
788
|
-
// queried `#t` since the same fix landed
|
|
789
|
-
// there; this is the back-port.
|
|
790
|
-
"#t": [address],
|
|
791
|
-
limit: 50
|
|
792
|
-
}
|
|
793
|
-
])
|
|
794
|
-
);
|
|
795
|
-
};
|
|
796
|
-
ws.onmessage = (msg) => {
|
|
797
|
-
try {
|
|
798
|
-
const data = JSON.parse(msg.data);
|
|
799
|
-
if (data[0] === "EVENT") {
|
|
800
|
-
events.push(data[2]);
|
|
801
|
-
} else if (data[0] === "EOSE") {
|
|
802
|
-
clearTimeout(timeout);
|
|
803
|
-
ws.close();
|
|
804
|
-
resolve();
|
|
805
|
-
}
|
|
806
|
-
} catch (err) {
|
|
807
|
-
log2.error({ relay: relayUrl, error: err }, "Failed to parse event");
|
|
808
|
-
}
|
|
809
|
-
};
|
|
810
|
-
ws.onerror = (err) => {
|
|
811
|
-
clearTimeout(timeout);
|
|
812
|
-
log2.error({ relay: relayUrl, error: err }, "WebSocket error during query");
|
|
813
|
-
reject(err);
|
|
814
|
-
};
|
|
815
|
-
});
|
|
816
|
-
} catch (err) {
|
|
817
|
-
log2.error({ relay: relayUrl, error: err }, "Failed to query relay");
|
|
818
|
-
}
|
|
819
|
-
});
|
|
820
|
-
await Promise.allSettled(queryPromises);
|
|
821
|
-
log2.info({ eventCount: events.length }, "Query complete");
|
|
822
|
-
return events;
|
|
792
|
+
return querySubject({ kinds: [30078], "#t": [address] }, relays, "addr");
|
|
823
793
|
}
|
|
824
794
|
async function queryByIdentity(protocol, identifier, relays = DEFAULT_RELAYS) {
|
|
825
|
-
const
|
|
826
|
-
const identityTag = `${protocol}:${identifier}`;
|
|
827
|
-
const identityTags = protocol === "nostr" ? nostrIdentifierForms(identifier).map((f) => `nostr:${f}`) : [identityTag];
|
|
795
|
+
const identityTags = protocol === "nostr" ? nostrIdentifierForms(identifier).map((f) => `nostr:${f}`) : [`${protocol}:${identifier}`];
|
|
828
796
|
log2.info({ protocol, identifier, relayCount: relays.length }, "Querying relays for identity");
|
|
829
|
-
|
|
830
|
-
const queryPromises = relays.map(async (relayUrl) => {
|
|
831
|
-
try {
|
|
832
|
-
const ws = new WebSocket(relayUrl);
|
|
833
|
-
await new Promise((resolve, reject) => {
|
|
834
|
-
const timeout = setTimeout(() => {
|
|
835
|
-
ws.close();
|
|
836
|
-
reject(new Error("Query timeout"));
|
|
837
|
-
}, budgetFor(deadlineAt));
|
|
838
|
-
ws.onopen = () => {
|
|
839
|
-
const subscriptionId = `ochk_identity_${Date.now()}`;
|
|
840
|
-
ws.send(
|
|
841
|
-
JSON.stringify([
|
|
842
|
-
"REQ",
|
|
843
|
-
subscriptionId,
|
|
844
|
-
{
|
|
845
|
-
kinds: [30078],
|
|
846
|
-
"#i": identityTags,
|
|
847
|
-
limit: 10
|
|
848
|
-
}
|
|
849
|
-
])
|
|
850
|
-
);
|
|
851
|
-
};
|
|
852
|
-
ws.onmessage = (msg) => {
|
|
853
|
-
try {
|
|
854
|
-
const data = JSON.parse(msg.data);
|
|
855
|
-
if (data[0] === "EVENT") {
|
|
856
|
-
events.push(data[2]);
|
|
857
|
-
} else if (data[0] === "EOSE") {
|
|
858
|
-
clearTimeout(timeout);
|
|
859
|
-
ws.close();
|
|
860
|
-
resolve();
|
|
861
|
-
}
|
|
862
|
-
} catch (err) {
|
|
863
|
-
log2.error({ relay: relayUrl, error: err }, "Failed to parse event");
|
|
864
|
-
}
|
|
865
|
-
};
|
|
866
|
-
ws.onerror = (err) => {
|
|
867
|
-
clearTimeout(timeout);
|
|
868
|
-
log2.error({ relay: relayUrl, error: err }, "WebSocket error during query");
|
|
869
|
-
reject(err);
|
|
870
|
-
};
|
|
871
|
-
});
|
|
872
|
-
} catch (err) {
|
|
873
|
-
log2.error({ relay: relayUrl, error: err }, "Failed to query relay");
|
|
874
|
-
}
|
|
875
|
-
});
|
|
876
|
-
await Promise.allSettled(queryPromises);
|
|
877
|
-
log2.info({ eventCount: events.length }, "Query complete");
|
|
878
|
-
return events;
|
|
797
|
+
return querySubject({ kinds: [30078], "#i": identityTags }, relays, "identity");
|
|
879
798
|
}
|
|
880
799
|
async function queryRecent(relays = DEFAULT_RELAYS, limit = 200) {
|
|
881
800
|
const events = [];
|
|
@@ -958,6 +877,7 @@ function signedEnvelope(envelope) {
|
|
|
958
877
|
return null;
|
|
959
878
|
}
|
|
960
879
|
if (!parsed.core.address || rfc3339Ms(parsed.core.issued_at) === null) return null;
|
|
880
|
+
if (parsed.repeated.length > 0) return null;
|
|
961
881
|
const { expires_at: _copy, ...rest } = envelope;
|
|
962
882
|
return {
|
|
963
883
|
...rest,
|
|
@@ -1189,7 +1109,6 @@ function extractAttestationIdFromUrl(url) {
|
|
|
1189
1109
|
}
|
|
1190
1110
|
|
|
1191
1111
|
// src/check.ts
|
|
1192
|
-
var MAX_CANDIDATES = 20;
|
|
1193
1112
|
async function check(params) {
|
|
1194
1113
|
const {
|
|
1195
1114
|
addr,
|
|
@@ -1217,7 +1136,7 @@ async function check(params) {
|
|
|
1217
1136
|
return { ok: false, sats: 0, days: 0, score: 0, reasons: ["not_found"] };
|
|
1218
1137
|
}
|
|
1219
1138
|
let env = envelopes[0];
|
|
1220
|
-
for (const candidate of envelopes
|
|
1139
|
+
for (const candidate of envelopes) {
|
|
1221
1140
|
if (await signedBy(candidate)) {
|
|
1222
1141
|
env = candidate;
|
|
1223
1142
|
break;
|