@orangecheck/sdk 1.9.0 → 1.11.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/challenge.js +10 -35
- package/dist/challenge.js.map +1 -1
- package/dist/challenge.mjs +10 -15
- package/dist/challenge.mjs.map +1 -1
- package/dist/identity.d.mts +5 -2
- package/dist/identity.d.ts +5 -2
- package/dist/identity.js +13 -5
- package/dist/identity.js.map +1 -1
- package/dist/identity.mjs +13 -5
- package/dist/identity.mjs.map +1 -1
- package/dist/index.js +88 -113
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +88 -93
- package/dist/index.mjs.map +1 -1
- package/dist/verify.js +65 -94
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +65 -74
- package/dist/verify.mjs.map +1 -1
- package/package.json +2 -4
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { bech32 } from '@scure/base';
|
|
2
2
|
import { Buffer } from 'buffer';
|
|
3
|
-
import {
|
|
4
|
-
import * as bitcoinMessage from 'bitcoinjs-message';
|
|
3
|
+
import { verifySignature as verifySignature$1 } from '@orangecheck/bip322';
|
|
5
4
|
import { schnorr } from '@noble/curves/secp256k1.js';
|
|
6
5
|
import { sha256 } from '@noble/hashes/sha2.js';
|
|
7
6
|
|
|
@@ -861,87 +860,79 @@ async function verifySignature({
|
|
|
861
860
|
sig,
|
|
862
861
|
scheme
|
|
863
862
|
}) {
|
|
864
|
-
|
|
865
|
-
|
|
863
|
+
const detectedScheme = scheme || detectSignatureScheme(addr, sig);
|
|
864
|
+
log4.debug(
|
|
865
|
+
{ addr, msgLength: msg.length, sigLength: sig.length, scheme: detectedScheme },
|
|
866
|
+
"Verifying signature"
|
|
867
|
+
);
|
|
868
|
+
if (detectedScheme === "bip322") {
|
|
869
|
+
const sigBase64 = toBase64Maybe(sig);
|
|
866
870
|
log4.debug(
|
|
867
|
-
{
|
|
868
|
-
"
|
|
871
|
+
{ sigBase64: sigBase64.substring(0, 50) + "..." },
|
|
872
|
+
"Signature converted to base64"
|
|
869
873
|
);
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
if (isSegWit && sigBase64.length === 88) {
|
|
890
|
-
log4.warn(
|
|
891
|
-
{ addr, wallet: "possibly Electrum", sigLength: sigBase64.length },
|
|
892
|
-
"BIP-322 verification failed - likely Electrum wallet (does not support BIP-322 for SegWit)"
|
|
893
|
-
);
|
|
894
|
-
} else {
|
|
895
|
-
log4.error(
|
|
896
|
-
{
|
|
897
|
-
addr,
|
|
898
|
-
sigLength: sigBase64.length,
|
|
899
|
-
msgLength: msg.length,
|
|
900
|
-
msgPreview: msg.substring(0, 200)
|
|
901
|
-
},
|
|
902
|
-
"BIP-322 verification failed - signature does not match message"
|
|
903
|
-
);
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
return ok ? "sig_ok_bip322" : "sig_invalid";
|
|
907
|
-
}
|
|
908
|
-
if (detectedScheme === "legacy") {
|
|
909
|
-
const sigBase64 = toBase64Maybe(sig);
|
|
910
|
-
if (!addr.startsWith("1") && !addr.startsWith("m") && !addr.startsWith("n")) {
|
|
911
|
-
log4.warn({ addr }, "Legacy signature attempted on non-P2PKH address");
|
|
912
|
-
return "sig_unsupported_script";
|
|
913
|
-
}
|
|
914
|
-
log4.debug(
|
|
915
|
-
{
|
|
916
|
-
addr,
|
|
917
|
-
sigBase64: sigBase64.substring(0, 50) + "...",
|
|
918
|
-
msgPreview: msg.substring(0, 100) + "...",
|
|
919
|
-
msgLength: msg.length
|
|
920
|
-
},
|
|
921
|
-
"Verifying legacy signature"
|
|
922
|
-
);
|
|
923
|
-
const ok = bitcoinMessage.verify(msg, addr, sigBase64);
|
|
924
|
-
log4.info({ addr, ok, sigBase64Length: sigBase64.length }, "Legacy verification result");
|
|
925
|
-
if (!ok) {
|
|
874
|
+
log4.debug(
|
|
875
|
+
{
|
|
876
|
+
msgFull: msg,
|
|
877
|
+
msgLines: msg.split("\n").length,
|
|
878
|
+
msgFirstLine: msg.split("\n")[0],
|
|
879
|
+
msgLastLine: msg.split("\n")[msg.split("\n").length - 1]
|
|
880
|
+
},
|
|
881
|
+
"Message being verified"
|
|
882
|
+
);
|
|
883
|
+
const ok = verifySignature$1(addr, msg, sigBase64);
|
|
884
|
+
log4.info({ addr, ok }, "BIP-322 verification result");
|
|
885
|
+
if (!ok) {
|
|
886
|
+
const isSegWit = addr.startsWith("bc1") || addr.startsWith("tb1");
|
|
887
|
+
if (isSegWit && sigBase64.length === 88) {
|
|
888
|
+
log4.warn(
|
|
889
|
+
{ addr, wallet: "possibly Electrum", sigLength: sigBase64.length },
|
|
890
|
+
"BIP-322 verification failed - likely Electrum wallet (does not support BIP-322 for SegWit)"
|
|
891
|
+
);
|
|
892
|
+
} else {
|
|
926
893
|
log4.error(
|
|
927
894
|
{
|
|
928
895
|
addr,
|
|
929
|
-
|
|
930
|
-
|
|
896
|
+
sigLength: sigBase64.length,
|
|
897
|
+
msgLength: msg.length,
|
|
898
|
+
msgPreview: msg.substring(0, 200)
|
|
931
899
|
},
|
|
932
|
-
"
|
|
900
|
+
"BIP-322 verification failed - signature does not match message"
|
|
933
901
|
);
|
|
934
902
|
}
|
|
935
|
-
return ok ? "sig_ok_legacy" : "sig_invalid";
|
|
936
903
|
}
|
|
937
|
-
return "
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
904
|
+
return ok ? "sig_ok_bip322" : "sig_invalid";
|
|
905
|
+
}
|
|
906
|
+
if (detectedScheme === "legacy") {
|
|
907
|
+
const sigBase64 = toBase64Maybe(sig);
|
|
908
|
+
if (!addr.startsWith("1") && !addr.startsWith("m") && !addr.startsWith("n")) {
|
|
909
|
+
log4.warn({ addr }, "Legacy signature attempted on non-P2PKH address");
|
|
910
|
+
return "sig_unsupported_script";
|
|
911
|
+
}
|
|
912
|
+
log4.debug(
|
|
913
|
+
{
|
|
914
|
+
addr,
|
|
915
|
+
sigBase64: sigBase64.substring(0, 50) + "...",
|
|
916
|
+
msgPreview: msg.substring(0, 100) + "...",
|
|
917
|
+
msgLength: msg.length
|
|
918
|
+
},
|
|
919
|
+
"Verifying legacy signature"
|
|
942
920
|
);
|
|
943
|
-
|
|
921
|
+
const ok = verifySignature$1(addr, msg, sigBase64);
|
|
922
|
+
log4.info({ addr, ok, sigBase64Length: sigBase64.length }, "Legacy verification result");
|
|
923
|
+
if (!ok) {
|
|
924
|
+
log4.error(
|
|
925
|
+
{
|
|
926
|
+
addr,
|
|
927
|
+
msgFirstLine: msg.split("\n")[0],
|
|
928
|
+
sigFormat: sigBase64.substring(0, 10)
|
|
929
|
+
},
|
|
930
|
+
"Legacy signature verification failed - check message format and signature"
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
return ok ? "sig_ok_legacy" : "sig_invalid";
|
|
944
934
|
}
|
|
935
|
+
return "invalid_scheme";
|
|
945
936
|
}
|
|
946
937
|
function parseCanonicalMessage(msg) {
|
|
947
938
|
const lines = msg.split("\n").map((l) => l.trim());
|
|
@@ -1072,7 +1063,7 @@ function computeMetrics(utxos, bondAmount) {
|
|
|
1072
1063
|
const days_unspent = Math.max(0, Math.floor((Date.now() / 1e3 - oldestTime) / (24 * 60 * 60)));
|
|
1073
1064
|
return { sats_bonded, days_unspent, confirmed_balance };
|
|
1074
1065
|
}
|
|
1075
|
-
async function
|
|
1066
|
+
async function verify(input, opts = {}) {
|
|
1076
1067
|
const codes = [];
|
|
1077
1068
|
let network = "mainnet";
|
|
1078
1069
|
try {
|
|
@@ -1227,7 +1218,7 @@ async function check(params) {
|
|
|
1227
1218
|
return { ok: false, sats: 0, days: 0, score: 0, reasons: ["not_found"] };
|
|
1228
1219
|
}
|
|
1229
1220
|
const shared = identity ? await backsOtherIdentity(env, identity, relays) : false;
|
|
1230
|
-
const outcome = await
|
|
1221
|
+
const outcome = await verify(
|
|
1231
1222
|
{
|
|
1232
1223
|
addr: env.address,
|
|
1233
1224
|
msg: env.message,
|
|
@@ -1415,21 +1406,17 @@ async function verifyChallenge(opts) {
|
|
|
1415
1406
|
return { ok: false, reason: "purpose_mismatch" };
|
|
1416
1407
|
}
|
|
1417
1408
|
const scheme = opts.scheme ?? "bip322";
|
|
1418
|
-
let sigValid
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
if (!/^[1m][a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(address)) {
|
|
1425
|
-
return { ok: false, reason: "sig_unsupported_scheme" };
|
|
1426
|
-
}
|
|
1427
|
-
sigValid = bitcoinMessage.verify(opts.message, address, opts.signature);
|
|
1428
|
-
} else {
|
|
1409
|
+
let sigValid;
|
|
1410
|
+
if (scheme === "bip322") {
|
|
1411
|
+
const sigBase64 = /^[0-9a-fA-F]+$/.test(opts.signature) && opts.signature.length % 2 === 0 ? Buffer.from(opts.signature, "hex").toString("base64") : opts.signature;
|
|
1412
|
+
sigValid = verifySignature$1(address, opts.message, sigBase64);
|
|
1413
|
+
} else if (scheme === "legacy") {
|
|
1414
|
+
if (!/^[1m][a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(address)) {
|
|
1429
1415
|
return { ok: false, reason: "sig_unsupported_scheme" };
|
|
1430
1416
|
}
|
|
1431
|
-
|
|
1432
|
-
|
|
1417
|
+
sigValid = verifySignature$1(address, opts.message, opts.signature);
|
|
1418
|
+
} else {
|
|
1419
|
+
return { ok: false, reason: "sig_unsupported_scheme" };
|
|
1433
1420
|
}
|
|
1434
1421
|
if (!sigValid) return { ok: false, reason: "sig_invalid" };
|
|
1435
1422
|
return {
|
|
@@ -1595,11 +1582,14 @@ function isValidDomain(domain) {
|
|
|
1595
1582
|
const domainPattern = /^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}$/i;
|
|
1596
1583
|
return domainPattern.test(cleanDomain);
|
|
1597
1584
|
}
|
|
1598
|
-
function isDnsIdentityVerified(attestationId,
|
|
1599
|
-
if (!cachedContent) {
|
|
1585
|
+
function isDnsIdentityVerified(attestationId, domain, cachedContent) {
|
|
1586
|
+
if (!cachedContent || !cachedContent.includes(attestationId)) {
|
|
1600
1587
|
return false;
|
|
1601
1588
|
}
|
|
1602
|
-
|
|
1589
|
+
const named = /^Domain:\s*(\S+)\s*$/im.exec(cachedContent);
|
|
1590
|
+
if (!named) return true;
|
|
1591
|
+
const cleanDomain = domain.replace(/^https?:\/\//, "").replace(/\/$/, "").toLowerCase();
|
|
1592
|
+
return named[1].toLowerCase() === cleanDomain;
|
|
1603
1593
|
}
|
|
1604
1594
|
|
|
1605
1595
|
// src/identity/github.ts
|
|
@@ -1743,8 +1733,10 @@ This gist proves that I control both:
|
|
|
1743
1733
|
Learn more about OrangeCheck: https://ochk.io
|
|
1744
1734
|
`;
|
|
1745
1735
|
}
|
|
1746
|
-
function isGitHubIdentityVerified(attestationId,
|
|
1736
|
+
function isGitHubIdentityVerified(attestationId, username, cachedGists) {
|
|
1737
|
+
const login = username.replace(/^@/, "").toLowerCase();
|
|
1747
1738
|
return cachedGists.some((gist) => {
|
|
1739
|
+
if (gist.owner?.login?.toLowerCase() !== login) return false;
|
|
1748
1740
|
if (gist.description?.includes(attestationId)) {
|
|
1749
1741
|
return true;
|
|
1750
1742
|
}
|
|
@@ -1843,6 +1835,9 @@ async function queryNostrEvents(options) {
|
|
|
1843
1835
|
return events;
|
|
1844
1836
|
}
|
|
1845
1837
|
async function verifyNostrEventSignature(event) {
|
|
1838
|
+
return nostrEventSignatureValid(event);
|
|
1839
|
+
}
|
|
1840
|
+
function nostrEventSignatureValid(event) {
|
|
1846
1841
|
try {
|
|
1847
1842
|
if (!event.id || !event.sig || !event.pubkey || typeof event.id !== "string" || typeof event.sig !== "string" || typeof event.pubkey !== "string" || event.sig.length !== 128 || !HEX_64_RE2.test(event.id) || !HEX_64_RE2.test(event.pubkey)) {
|
|
1848
1843
|
return false;
|
|
@@ -1929,7 +1924,7 @@ The verification will search Nostr relays for your note and confirm you control
|
|
|
1929
1924
|
function isNostrIdentityVerified(attestationId, npub, cachedEvents) {
|
|
1930
1925
|
const pubkeyHex = npubToHex(npub);
|
|
1931
1926
|
return cachedEvents.some(
|
|
1932
|
-
(event) => event.pubkey === pubkeyHex && event.kind === 1 && event.content.includes(attestationId)
|
|
1927
|
+
(event) => event.pubkey === pubkeyHex && event.kind === 1 && event.content.includes(attestationId) && nostrEventSignatureValid(event)
|
|
1933
1928
|
);
|
|
1934
1929
|
}
|
|
1935
1930
|
|
|
@@ -2223,6 +2218,6 @@ var STATUS_META = {
|
|
|
2223
2218
|
}
|
|
2224
2219
|
};
|
|
2225
2220
|
|
|
2226
|
-
export { DEFAULT_RELAYS, FANOUT_DEADLINE_MS, 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, nostrIdentifierForms, nostrPubkeyToHex, parseAttestationFromEvent, parseIdentities, publishAttestation, publishToRelays, queryByAddress, queryByAttestationId, queryByIdentity, queryRecent, requiresManualVerification, signNostrEvent, supportsAutomaticVerification,
|
|
2221
|
+
export { DEFAULT_RELAYS, FANOUT_DEADLINE_MS, 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, nostrIdentifierForms, nostrPubkeyToHex, parseAttestationFromEvent, parseIdentities, publishAttestation, publishToRelays, queryByAddress, queryByAttestationId, queryByIdentity, queryRecent, requiresManualVerification, signNostrEvent, supportsAutomaticVerification, verify, verifyAllIdentities, verifyAttestationById, verifyChallenge, verifyDnsIdentity, verifyGitHubIdentity, verifyIdentity, verifyNostrIdentity, verifyTwitterIdentity };
|
|
2227
2222
|
//# sourceMappingURL=index.mjs.map
|
|
2228
2223
|
//# sourceMappingURL=index.mjs.map
|