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