@thurinlabs/identity-kit 1.3.7 → 2.0.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/README.md +44 -359
- package/dist/{chunk-ROQWHCHP.js → chunk-AAJWERE2.js} +2275 -1005
- package/dist/chunk-DJGCYNJN.cjs +3377 -0
- package/dist/core.cjs +58 -3
- package/dist/core.d.cts +1615 -892
- package/dist/core.d.ts +1615 -892
- package/dist/core.js +79 -24
- package/dist/index.cjs +39 -459
- package/dist/index.d.cts +1 -83
- package/dist/index.d.ts +1 -83
- package/dist/index.js +79 -499
- package/package.json +5 -22
- package/dist/chunk-OIE72R6J.cjs +0 -2107
- package/dist/chunk-OIE72R6J.cjs.map +0 -1
- package/dist/chunk-ROQWHCHP.js.map +0 -1
- package/dist/core.cjs.map +0 -1
- package/dist/core.js.map +0 -1
- package/dist/embed.global.js +0 -32151
- package/dist/embed.global.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.css +0 -185
- package/dist/index.css.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -1,3 +1,874 @@
|
|
|
1
|
+
// src/core/fingerprint.ts
|
|
2
|
+
import { keccak256 } from "viem";
|
|
3
|
+
var FINGERPRINT_HEX = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
|
|
4
|
+
function normalizeFingerprint(input) {
|
|
5
|
+
const hex = input.replace(/^0x/i, "").replace(/\s+/g, "").toLowerCase();
|
|
6
|
+
return FINGERPRINT_HEX.test(hex) ? hex : null;
|
|
7
|
+
}
|
|
8
|
+
function sameFingerprint(a, b) {
|
|
9
|
+
const x = a ? normalizeFingerprint(a) : null;
|
|
10
|
+
return x !== null && x === (b ? normalizeFingerprint(b) : null);
|
|
11
|
+
}
|
|
12
|
+
function fingerprintToBytes(fingerprint) {
|
|
13
|
+
const hex = normalizeFingerprint(fingerprint);
|
|
14
|
+
if (!hex) throw new Error(`Invalid PGP fingerprint: ${fingerprint}`);
|
|
15
|
+
return `0x${hex}`;
|
|
16
|
+
}
|
|
17
|
+
function bytesToFingerprint(bytes) {
|
|
18
|
+
return bytes.replace(/^0x/i, "").toLowerCase();
|
|
19
|
+
}
|
|
20
|
+
function fingerprintHash(fingerprint) {
|
|
21
|
+
return keccak256(fingerprintToBytes(fingerprint));
|
|
22
|
+
}
|
|
23
|
+
function keyIdOf(fingerprint) {
|
|
24
|
+
const hex = normalizeFingerprint(fingerprint);
|
|
25
|
+
if (!hex) throw new Error(`Invalid PGP fingerprint: ${fingerprint}`);
|
|
26
|
+
return `0x${keyIdHex(hex)}`;
|
|
27
|
+
}
|
|
28
|
+
function keyIdHex(normalizedFingerprint) {
|
|
29
|
+
return normalizedFingerprint.length === 64 ? normalizedFingerprint.slice(0, 16) : normalizedFingerprint.slice(-16);
|
|
30
|
+
}
|
|
31
|
+
function keyIdToBytes(keyId) {
|
|
32
|
+
const hex = keyId.replace(/^0x/i, "").replace(/\s+/g, "").toLowerCase();
|
|
33
|
+
return /^[0-9a-f]{16}$/.test(hex) ? `0x${hex}` : null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/core/proofs.ts
|
|
37
|
+
var get = (url, init = {}) => fetch(url, { referrerPolicy: "no-referrer", ...init });
|
|
38
|
+
var PROVIDERS = [
|
|
39
|
+
{
|
|
40
|
+
provider: "github",
|
|
41
|
+
label: "GitHub",
|
|
42
|
+
pattern: /^https:\/\/gist\.github\.com\/([^/]+)\/([a-f0-9]+)$/i,
|
|
43
|
+
parse: (m) => ({ user: m[1], gistId: m[2] })
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
// A repository's description: the form an organisation can use, since gists belong to user
|
|
47
|
+
// accounts only. Same shape as the Codeberg proof.
|
|
48
|
+
provider: "github",
|
|
49
|
+
label: "GitHub",
|
|
50
|
+
pattern: /^https:\/\/github\.com\/([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+)$/i,
|
|
51
|
+
parse: (m) => ({ user: m[1], repo: m[2] })
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
provider: "dns",
|
|
55
|
+
label: "DNS",
|
|
56
|
+
// A hostname only; underscores allowed for names like _thurin.example.com.
|
|
57
|
+
pattern: /^dns:([a-z0-9._-]+)\?type=TXT$/i,
|
|
58
|
+
parse: (m) => ({ domain: m[1] })
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
provider: "farcaster",
|
|
62
|
+
label: "Farcaster",
|
|
63
|
+
pattern: /^https:\/\/farcaster\.xyz\/([^/]+)\/(0x[a-f0-9]+)$/i,
|
|
64
|
+
parse: (m) => ({ user: m[1], castHash: m[2] })
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
provider: "codeberg",
|
|
68
|
+
label: "Codeberg",
|
|
69
|
+
pattern: /^https:\/\/codeberg\.org\/([^/]+)\/([^/]+)$/i,
|
|
70
|
+
parse: (m) => ({ user: m[1], repo: m[2] })
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
provider: "mastodon",
|
|
74
|
+
label: "Mastodon",
|
|
75
|
+
// A bare hostname (optional port), so "mastodon.social@evil.com" can't send the lookup elsewhere.
|
|
76
|
+
pattern: /^https:\/\/([a-z0-9.-]+(?::\d+)?)\/@([^/@?#\s]+)$/i,
|
|
77
|
+
parse: (m) => ({ instance: m[1], user: m[2] })
|
|
78
|
+
}
|
|
79
|
+
];
|
|
80
|
+
function identifyProof(notation) {
|
|
81
|
+
if (notation.name !== "proof@thurin.id") return null;
|
|
82
|
+
for (const { provider, label, pattern, parse } of PROVIDERS) {
|
|
83
|
+
const m = notation.value.match(pattern);
|
|
84
|
+
if (m) {
|
|
85
|
+
return { provider, label, url: notation.value, ...parse(m) };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { provider: "unknown", label: "Unknown", url: notation.value };
|
|
89
|
+
}
|
|
90
|
+
function displayUrl(proof) {
|
|
91
|
+
if (proof.provider === "dns") return proof.domain;
|
|
92
|
+
if (proof.provider === "github") return proof.user;
|
|
93
|
+
if (proof.provider === "farcaster") return `@${proof.user}`;
|
|
94
|
+
if (proof.provider === "codeberg") return proof.user;
|
|
95
|
+
if (proof.provider === "mastodon") return `@${proof.user}@${proof.instance}`;
|
|
96
|
+
return proof.url;
|
|
97
|
+
}
|
|
98
|
+
function proofHref(proof) {
|
|
99
|
+
if (proof.provider === "dns") return `https://${proof.domain}`;
|
|
100
|
+
if (proof.provider === "github") return `https://github.com/${proof.user}`;
|
|
101
|
+
if (proof.provider === "farcaster") return `https://farcaster.xyz/${proof.user}`;
|
|
102
|
+
if (proof.provider === "codeberg") return `https://codeberg.org/${proof.user}`;
|
|
103
|
+
if (proof.provider === "mastodon") return `https://${proof.instance}/@${proof.user}`;
|
|
104
|
+
if (proof.url.startsWith("http")) return proof.url;
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
function proofSecondaryHref(proof) {
|
|
108
|
+
if (proof.provider === "github") return proof.url;
|
|
109
|
+
if (proof.provider === "farcaster") return proof.url;
|
|
110
|
+
if (proof.provider === "codeberg") return proof.url;
|
|
111
|
+
if (proof.provider === "mastodon") return proof.url;
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
var FPR_TOKEN = "OPENPGP4FPR:";
|
|
115
|
+
function containsFingerprint(text, fingerprint) {
|
|
116
|
+
return text.toUpperCase().includes(FPR_TOKEN + fingerprint.toUpperCase());
|
|
117
|
+
}
|
|
118
|
+
function containsFingerprintUrl(text, fingerprint) {
|
|
119
|
+
return text.toUpperCase().includes(fingerprint.toUpperCase());
|
|
120
|
+
}
|
|
121
|
+
async function verifyGitHub(proof, fingerprint) {
|
|
122
|
+
if (proof.repo) return verifyGitHubRepo(proof, fingerprint);
|
|
123
|
+
try {
|
|
124
|
+
const resp = await get(`https://api.github.com/gists/${proof.gistId}`);
|
|
125
|
+
if (!resp.ok) return { verified: false, reason: `GitHub API returned ${resp.status}` };
|
|
126
|
+
const data = await resp.json();
|
|
127
|
+
if (data.owner?.login?.toLowerCase() !== proof.user.toLowerCase()) {
|
|
128
|
+
return { verified: false, reason: "Gist owner does not match claimed user" };
|
|
129
|
+
}
|
|
130
|
+
for (const file of Object.values(data.files || {})) {
|
|
131
|
+
if (file.content && containsFingerprint(file.content, fingerprint)) {
|
|
132
|
+
return { verified: true };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return { verified: false, reason: "Fingerprint token not found in gist" };
|
|
136
|
+
} catch (err) {
|
|
137
|
+
return { verified: false, reason: `GitHub fetch failed: ${err.message}` };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async function verifyGitHubRepo(proof, fingerprint) {
|
|
141
|
+
try {
|
|
142
|
+
const resp = await get(
|
|
143
|
+
`https://api.github.com/repos/${encodeURIComponent(proof.user)}/${encodeURIComponent(proof.repo)}`
|
|
144
|
+
);
|
|
145
|
+
if (!resp.ok) return { verified: false, reason: `GitHub API returned ${resp.status}` };
|
|
146
|
+
const data = await resp.json();
|
|
147
|
+
if (data.owner?.login?.toLowerCase() !== proof.user.toLowerCase()) {
|
|
148
|
+
return { verified: false, reason: "Repository owner does not match claimed account" };
|
|
149
|
+
}
|
|
150
|
+
if (data.description && containsFingerprint(data.description, fingerprint)) {
|
|
151
|
+
return { verified: true };
|
|
152
|
+
}
|
|
153
|
+
return { verified: false, reason: "Fingerprint token not found in repository description" };
|
|
154
|
+
} catch (err) {
|
|
155
|
+
return { verified: false, reason: `GitHub fetch failed: ${err.message}` };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function verifyDNS(proof, fingerprint) {
|
|
159
|
+
try {
|
|
160
|
+
const resp = await get(
|
|
161
|
+
`https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(proof.domain)}&type=TXT`,
|
|
162
|
+
{ headers: { Accept: "application/dns-json" } }
|
|
163
|
+
);
|
|
164
|
+
if (!resp.ok) return { verified: false, reason: `DNS query returned ${resp.status}` };
|
|
165
|
+
const data = await resp.json();
|
|
166
|
+
for (const answer of data.Answer || []) {
|
|
167
|
+
if (answer.type !== 16) continue;
|
|
168
|
+
if (answer.data && containsFingerprint(answer.data, fingerprint)) {
|
|
169
|
+
return { verified: true };
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return { verified: false, reason: "Fingerprint token not found in TXT records" };
|
|
173
|
+
} catch (err) {
|
|
174
|
+
return { verified: false, reason: `DNS fetch failed: ${err.message}` };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
var FARCASTER_HUB = "https://haatz.quilibrium.com";
|
|
178
|
+
var NEYNAR_HUB = "https://hub-api.neynar.com";
|
|
179
|
+
function farcasterSource(opts) {
|
|
180
|
+
if (opts.farcasterHub) return { base: opts.farcasterHub.replace(/\/+$/, ""), headers: {} };
|
|
181
|
+
if (opts.neynarApiKey) return { base: NEYNAR_HUB, headers: { "x-api-key": opts.neynarApiKey } };
|
|
182
|
+
return { base: FARCASTER_HUB, headers: {} };
|
|
183
|
+
}
|
|
184
|
+
async function verifyFarcaster(proof, fingerprint, opts = {}) {
|
|
185
|
+
const { base, headers } = farcasterSource(opts);
|
|
186
|
+
const host = base.replace(/^https?:\/\//, "");
|
|
187
|
+
try {
|
|
188
|
+
const nameResp = await get(`${base}/v1/userNameProofByName?name=${encodeURIComponent(proof.user)}`, { headers });
|
|
189
|
+
if (nameResp.status === 404) return { verified: false, reason: `Could not resolve Farcaster user "${proof.user}"` };
|
|
190
|
+
if (!nameResp.ok) return { verified: false, reason: `Couldn't check: the Farcaster node (${host}) returned ${nameResp.status}` };
|
|
191
|
+
const fid = (await nameResp.json()).fid;
|
|
192
|
+
if (!fid) return { verified: false, reason: `Could not resolve Farcaster user "${proof.user}"` };
|
|
193
|
+
let pageToken = "";
|
|
194
|
+
for (let page = 0; page < 5; page++) {
|
|
195
|
+
const url = `${base}/v1/castsByFid?fid=${fid}&pageSize=100&reverse=true${pageToken ? `&pageToken=${pageToken}` : ""}`;
|
|
196
|
+
const resp = await get(url, { headers });
|
|
197
|
+
if (!resp.ok) return { verified: false, reason: `Couldn't check: the Farcaster node (${host}) returned ${resp.status}` };
|
|
198
|
+
const data = await resp.json();
|
|
199
|
+
for (const msg of data.messages || []) {
|
|
200
|
+
if (msg.hash && msg.hash.startsWith(proof.castHash)) {
|
|
201
|
+
const text = msg.data?.castAddBody?.text || "";
|
|
202
|
+
if (containsFingerprint(text, fingerprint)) {
|
|
203
|
+
return { verified: true };
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (!data.nextPageToken) break;
|
|
208
|
+
pageToken = data.nextPageToken;
|
|
209
|
+
}
|
|
210
|
+
return { verified: false, reason: "Cast not found" };
|
|
211
|
+
} catch (err) {
|
|
212
|
+
return { verified: false, reason: `Couldn't check: the Farcaster node (${host}) didn't answer (${err.message})` };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
async function verifyCodeberg(proof, fingerprint) {
|
|
216
|
+
try {
|
|
217
|
+
const resp = await get(
|
|
218
|
+
`https://codeberg.org/api/v1/repos/${encodeURIComponent(proof.user)}/${encodeURIComponent(proof.repo)}`
|
|
219
|
+
);
|
|
220
|
+
if (!resp.ok) return { verified: false, reason: `Codeberg API returned ${resp.status}` };
|
|
221
|
+
const data = await resp.json();
|
|
222
|
+
if (data.owner?.login?.toLowerCase() !== proof.user.toLowerCase()) {
|
|
223
|
+
return { verified: false, reason: "Repository owner does not match claimed account" };
|
|
224
|
+
}
|
|
225
|
+
if (data.description && containsFingerprint(data.description, fingerprint)) {
|
|
226
|
+
return { verified: true };
|
|
227
|
+
}
|
|
228
|
+
return { verified: false, reason: "Fingerprint token not found in repo description" };
|
|
229
|
+
} catch (err) {
|
|
230
|
+
return { verified: false, reason: `Codeberg fetch failed: ${err.message}` };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
async function verifyMastodon(proof, fingerprint) {
|
|
234
|
+
try {
|
|
235
|
+
if (!proof.instance || !/^[a-z0-9.-]+(?::\d+)?$/i.test(proof.instance)) {
|
|
236
|
+
return { verified: false, reason: "Invalid Mastodon instance host" };
|
|
237
|
+
}
|
|
238
|
+
const resp = await get(
|
|
239
|
+
`https://${proof.instance}/api/v1/accounts/lookup?acct=${encodeURIComponent(proof.user)}`
|
|
240
|
+
);
|
|
241
|
+
if (!resp.ok) return { verified: false, reason: `Mastodon API returned ${resp.status}` };
|
|
242
|
+
const data = await resp.json();
|
|
243
|
+
const keyId = keyIdHex(fingerprint.replace(/^0x/i, "").replace(/\s+/g, "").toLowerCase());
|
|
244
|
+
for (const field of data.fields || []) {
|
|
245
|
+
const text = field.value.replace(/<[^>]*>/g, "");
|
|
246
|
+
if (containsFingerprintUrl(text, fingerprint) || containsFingerprintUrl(text, keyId)) {
|
|
247
|
+
return { verified: true };
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (data.note) {
|
|
251
|
+
const text = data.note.replace(/<[^>]*>/g, "");
|
|
252
|
+
if (containsFingerprintUrl(text, fingerprint) || containsFingerprintUrl(text, keyId)) {
|
|
253
|
+
return { verified: true };
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return { verified: false, reason: "Fingerprint not found in profile fields or bio" };
|
|
257
|
+
} catch (err) {
|
|
258
|
+
return { verified: false, reason: `Mastodon fetch failed: ${err.message}` };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
var verifiers = {
|
|
262
|
+
github: verifyGitHub,
|
|
263
|
+
dns: verifyDNS,
|
|
264
|
+
farcaster: verifyFarcaster,
|
|
265
|
+
codeberg: verifyCodeberg,
|
|
266
|
+
mastodon: verifyMastodon
|
|
267
|
+
};
|
|
268
|
+
async function verifyProof(proof, fingerprint, opts) {
|
|
269
|
+
const fn = verifiers[proof.provider];
|
|
270
|
+
if (!fn) return { verified: false, reason: "Unknown provider" };
|
|
271
|
+
return fn(proof, fingerprint, typeof opts === "string" ? { neynarApiKey: opts } : opts ?? {});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/core/pgp.ts
|
|
275
|
+
function pgpConfig(openpgp) {
|
|
276
|
+
const rejectCurves = new Set([...openpgp.config.rejectCurves ?? []].filter((c) => c !== "secp256k1"));
|
|
277
|
+
return { ...openpgp.config, rejectCurves };
|
|
278
|
+
}
|
|
279
|
+
function newestSignature(sigs = []) {
|
|
280
|
+
return [...sigs].sort((x, y) => (y.created?.getTime?.() ?? 0) - (x.created?.getTime?.() ?? 0))[0];
|
|
281
|
+
}
|
|
282
|
+
function algorithmName(keyOrSubkey) {
|
|
283
|
+
try {
|
|
284
|
+
const info = keyOrSubkey.getAlgorithmInfo();
|
|
285
|
+
const curve = (info.curve || "").toLowerCase();
|
|
286
|
+
if (curve.startsWith("ed25519") || info.algorithm === "ed25519" || info.algorithm === "eddsaLegacy") return "Ed25519";
|
|
287
|
+
if (curve.startsWith("curve25519") || info.algorithm === "x25519") return "Cv25519";
|
|
288
|
+
if (curve.startsWith("ed448")) return "Ed448";
|
|
289
|
+
if (curve.startsWith("curve448") || info.algorithm === "x448") return "X448";
|
|
290
|
+
if (curve.startsWith("nistp") || curve.startsWith("p")) return `NIST P-${curve.replace(/\D/g, "")}`;
|
|
291
|
+
if (curve.startsWith("secp")) return curve;
|
|
292
|
+
if (curve.startsWith("brainpool")) return curve;
|
|
293
|
+
if (info.algorithm.startsWith("rsa")) return info.bits ? `RSA ${info.bits}` : "RSA";
|
|
294
|
+
if (info.algorithm.startsWith("dsa")) return info.bits ? `DSA ${info.bits}` : "DSA";
|
|
295
|
+
if (info.algorithm.startsWith("elgamal")) return info.bits ? `ElGamal ${info.bits}` : "ElGamal";
|
|
296
|
+
return info.curve || info.algorithm;
|
|
297
|
+
} catch {
|
|
298
|
+
return String(keyOrSubkey.keyPacket?.algorithm ?? "unknown");
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
var TEXT_START = 45;
|
|
302
|
+
function hexToBytes(hex) {
|
|
303
|
+
const h = hex.slice(2);
|
|
304
|
+
const out = new Uint8Array(h.length / 2);
|
|
305
|
+
for (let i = 0; i < out.length; i++) out[i] = parseInt(h.substr(i * 2, 2), 16);
|
|
306
|
+
return out;
|
|
307
|
+
}
|
|
308
|
+
function normalizeInput(input) {
|
|
309
|
+
if (typeof input === "string") {
|
|
310
|
+
const t = input.trim();
|
|
311
|
+
if (/^0x([0-9a-fA-F]{2})*$/.test(t)) return normalizeInput(hexToBytes(t));
|
|
312
|
+
return input;
|
|
313
|
+
}
|
|
314
|
+
if (input.length > 0 && input[0] === TEXT_START) return new TextDecoder().decode(input);
|
|
315
|
+
return input;
|
|
316
|
+
}
|
|
317
|
+
async function readKeyAny(openpgp, input) {
|
|
318
|
+
const v = normalizeInput(input);
|
|
319
|
+
return typeof v === "string" ? openpgp.readKey({ armoredKey: v }) : openpgp.readKey({ binaryKey: v });
|
|
320
|
+
}
|
|
321
|
+
async function readSignatureAny(openpgp, input) {
|
|
322
|
+
const v = normalizeInput(input);
|
|
323
|
+
if (typeof v === "string" && v.includes("-----BEGIN PGP SIGNED MESSAGE-----")) {
|
|
324
|
+
const message = await openpgp.readCleartextMessage({ cleartextMessage: v });
|
|
325
|
+
return { packets: message.signature.packets, text: message.getText(), signature: message.signature };
|
|
326
|
+
}
|
|
327
|
+
const signature = typeof v === "string" ? await openpgp.readSignature({ armoredSignature: v }) : await openpgp.readSignature({ binarySignature: v });
|
|
328
|
+
return { packets: signature.packets, text: null, signature };
|
|
329
|
+
}
|
|
330
|
+
function statementText(address) {
|
|
331
|
+
return `I control the Ethereum address: ${address.toLowerCase()}`;
|
|
332
|
+
}
|
|
333
|
+
async function parsePgpKey(armoredKey) {
|
|
334
|
+
try {
|
|
335
|
+
const openpgp = await import("openpgp");
|
|
336
|
+
const config = pgpConfig(openpgp);
|
|
337
|
+
const key = await readKeyAny(openpgp, armoredKey);
|
|
338
|
+
const fingerprint = key.getFingerprint().toUpperCase();
|
|
339
|
+
const algorithm = algorithmName(key);
|
|
340
|
+
const created = key.keyPacket.created?.toISOString() ?? null;
|
|
341
|
+
const expiration = await key.getExpirationTime();
|
|
342
|
+
const expires = expiration && expiration !== Infinity ? new Date(expiration).toISOString() : null;
|
|
343
|
+
const userIDs = [];
|
|
344
|
+
const notations = [];
|
|
345
|
+
const seen = /* @__PURE__ */ new Set();
|
|
346
|
+
for (const user of key.users) {
|
|
347
|
+
const certs = user.selfCertifications;
|
|
348
|
+
if (!certs || certs.length === 0) continue;
|
|
349
|
+
let userVerified = false;
|
|
350
|
+
for (const cert of certs) {
|
|
351
|
+
try {
|
|
352
|
+
await cert.verify(
|
|
353
|
+
key.keyPacket,
|
|
354
|
+
cert.signatureType,
|
|
355
|
+
{ userID: user.userID, key: key.keyPacket },
|
|
356
|
+
void 0,
|
|
357
|
+
// date: now
|
|
358
|
+
void 0,
|
|
359
|
+
// detached
|
|
360
|
+
config
|
|
361
|
+
);
|
|
362
|
+
} catch {
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
userVerified = true;
|
|
366
|
+
if (cert.rawNotations) {
|
|
367
|
+
for (const n of cert.rawNotations) {
|
|
368
|
+
const name = typeof n.name === "string" ? n.name : new TextDecoder().decode(n.name);
|
|
369
|
+
const value = n.value instanceof Uint8Array ? new TextDecoder().decode(n.value) : typeof n.value === "string" ? n.value : null;
|
|
370
|
+
if (value) {
|
|
371
|
+
if (!seen.has(value)) {
|
|
372
|
+
seen.add(value);
|
|
373
|
+
notations.push({ name, value });
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
if (userVerified) {
|
|
380
|
+
const uid = user.userID?.userID;
|
|
381
|
+
if (uid) userIDs.push(uid);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
const now = /* @__PURE__ */ new Date();
|
|
385
|
+
const subkeys = await Promise.all(key.subkeys.map(async (sk) => {
|
|
386
|
+
const flags = newestSignature(sk.bindingSignatures)?.keyFlags?.[0] ?? 0;
|
|
387
|
+
const usage = [];
|
|
388
|
+
if (flags & 2) usage.push("sign");
|
|
389
|
+
if (flags & 12) usage.push("encrypt");
|
|
390
|
+
if (flags & 32) usage.push("auth");
|
|
391
|
+
const exp = await sk.getExpirationTime(now, config).catch(() => null);
|
|
392
|
+
const valid = await sk.verify(now, config).then(() => true, () => false);
|
|
393
|
+
return {
|
|
394
|
+
algorithm: algorithmName(sk),
|
|
395
|
+
created: sk.keyPacket.created?.toISOString() ?? null,
|
|
396
|
+
fingerprint: sk.getFingerprint().toUpperCase(),
|
|
397
|
+
usage,
|
|
398
|
+
expires: exp && exp !== Infinity ? new Date(exp).toISOString() : null,
|
|
399
|
+
valid
|
|
400
|
+
};
|
|
401
|
+
}));
|
|
402
|
+
const canEncrypt = await key.getEncryptionKey(void 0, now, void 0, config).then(() => true, () => false);
|
|
403
|
+
return { fingerprint, userIDs, algorithm, created, expires, notations, subkeys, canEncrypt };
|
|
404
|
+
} catch {
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
async function verifySignedText(openpgp, publicKey, packets, text) {
|
|
409
|
+
const { LiteralDataPacket } = openpgp;
|
|
410
|
+
const config = pgpConfig(openpgp);
|
|
411
|
+
const now = /* @__PURE__ */ new Date();
|
|
412
|
+
for (const sig of packets) {
|
|
413
|
+
if (!publicKey.getKeys(sig.issuerKeyID).length) continue;
|
|
414
|
+
const signingKey = await publicKey.getSigningKey(sig.issuerKeyID, now, void 0, config);
|
|
415
|
+
const literal = new LiteralDataPacket();
|
|
416
|
+
literal.setText(text.replace(/\r?\n/g, "\r\n"));
|
|
417
|
+
await sig.verify(signingKey.keyPacket, sig.signatureType, literal, now, true, config);
|
|
418
|
+
return true;
|
|
419
|
+
}
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
async function verifyClearsigned({ armoredKey, clearsigned }) {
|
|
423
|
+
try {
|
|
424
|
+
const openpgp = await import("openpgp");
|
|
425
|
+
const publicKey = await readKeyAny(openpgp, armoredKey);
|
|
426
|
+
const message = await openpgp.readCleartextMessage({ cleartextMessage: clearsigned });
|
|
427
|
+
const text = message.text ?? message.getText();
|
|
428
|
+
if (await verifySignedText(openpgp, publicKey, message.signature.packets, text)) return { verified: true, text: message.getText() };
|
|
429
|
+
return { verified: false, reason: "Message is not signed by this key", text: message.getText() };
|
|
430
|
+
} catch (err) {
|
|
431
|
+
return { verified: false, reason: err instanceof Error ? err.message : "Verification failed", text: "" };
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
async function verifyStatementSignature({ key, signature, address }) {
|
|
435
|
+
const text = statementText(address);
|
|
436
|
+
try {
|
|
437
|
+
const openpgp = await import("openpgp");
|
|
438
|
+
const publicKey = await readKeyAny(openpgp, key);
|
|
439
|
+
const { packets } = await readSignatureAny(openpgp, signature);
|
|
440
|
+
if (await verifySignedText(openpgp, publicKey, packets, text)) return { verified: true, text };
|
|
441
|
+
return { verified: false, reason: "Message is not signed by this key", text };
|
|
442
|
+
} catch (err) {
|
|
443
|
+
return { verified: false, reason: err instanceof Error ? err.message : "Verification failed", text };
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
var REVOCATION_REASON = {
|
|
447
|
+
1: "replaced by a newer key",
|
|
448
|
+
2: "compromised",
|
|
449
|
+
3: "no longer used",
|
|
450
|
+
32: "a user ID is no longer valid"
|
|
451
|
+
};
|
|
452
|
+
var iso = (d) => d instanceof Date ? d.toISOString() : typeof d === "number" && Number.isFinite(d) ? new Date(d).toISOString() : null;
|
|
453
|
+
function revocationOf(sigs) {
|
|
454
|
+
const sig = [...sigs ?? []].sort((a, b) => (b.created?.getTime?.() ?? 0) - (a.created?.getTime?.() ?? 0))[0];
|
|
455
|
+
const flag = sig?.reasonForRevocationFlag ?? null;
|
|
456
|
+
return {
|
|
457
|
+
at: iso(sig?.created),
|
|
458
|
+
compromised: flag === 2,
|
|
459
|
+
revocationReason: sig?.reasonForRevocationString || (flag !== null ? REVOCATION_REASON[flag] ?? null : null)
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
async function keyLife(key, issuer, config) {
|
|
463
|
+
const now = /* @__PURE__ */ new Date();
|
|
464
|
+
const signer = issuer && !key.getKeyID().equals(issuer) ? key.subkeys.find((s) => s.getKeyID().equals(issuer)) ?? null : key;
|
|
465
|
+
const signingKey = signer ? signer.getFingerprint().toUpperCase() : null;
|
|
466
|
+
const safe = async (f, fallback) => {
|
|
467
|
+
try {
|
|
468
|
+
return await f();
|
|
469
|
+
} catch {
|
|
470
|
+
return fallback;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
const keyRevoked = await safe(() => key.isRevoked(void 0, void 0, now, config), false);
|
|
474
|
+
const keyExp = await safe(() => key.getExpirationTime(void 0, config), null);
|
|
475
|
+
const isSub = signer && signer !== key;
|
|
476
|
+
const subRevoked = isSub ? await safe(() => signer.isRevoked(null, key.keyPacket, now, config), false) : false;
|
|
477
|
+
const subExp = isSub ? await safe(() => signer.getExpirationTime(null, config), null) : null;
|
|
478
|
+
const finite = (d) => d instanceof Date && Number.isFinite(d.getTime()) ? d : null;
|
|
479
|
+
const kExp = finite(keyExp), sExp = finite(subExp);
|
|
480
|
+
let problem = null;
|
|
481
|
+
if (keyRevoked) {
|
|
482
|
+
const r = revocationOf(key.revocationSignatures);
|
|
483
|
+
problem = { kind: r.compromised ? "compromised" : "revoked", at: r.at, revocationReason: r.revocationReason };
|
|
484
|
+
} else if (kExp && kExp <= now) {
|
|
485
|
+
problem = { kind: "expired", at: kExp.toISOString() };
|
|
486
|
+
} else if (subRevoked) {
|
|
487
|
+
const r = revocationOf(signer.revocationSignatures);
|
|
488
|
+
problem = { kind: r.compromised ? "compromised" : "signing-key-revoked", at: r.at, revocationReason: r.revocationReason };
|
|
489
|
+
} else if (sExp && sExp <= now) {
|
|
490
|
+
problem = { kind: "signing-key-expired", at: sExp.toISOString() };
|
|
491
|
+
}
|
|
492
|
+
const earliest = [kExp, sExp].filter(Boolean).sort((a, b) => a - b)[0];
|
|
493
|
+
return { problem, signingKey, expiresAt: earliest ? earliest.toISOString() : null, algorithm: algorithmName(signer ?? key) };
|
|
494
|
+
}
|
|
495
|
+
async function verifyAttestation({
|
|
496
|
+
pgpPublicKey,
|
|
497
|
+
pgpSignature,
|
|
498
|
+
fingerprint,
|
|
499
|
+
ethAddress
|
|
500
|
+
}) {
|
|
501
|
+
try {
|
|
502
|
+
if (!pgpPublicKey || !pgpSignature) {
|
|
503
|
+
return { verified: false, reason: "Missing PGP data", kind: "bad-signature" };
|
|
504
|
+
}
|
|
505
|
+
const openpgp = await import("openpgp");
|
|
506
|
+
const publicKey = await readKeyAny(openpgp, pgpPublicKey);
|
|
507
|
+
const keyFingerprint = publicKey.getFingerprint().toUpperCase();
|
|
508
|
+
if (keyFingerprint !== fingerprint.toUpperCase()) {
|
|
509
|
+
return { verified: false, reason: "Key fingerprint mismatch", kind: "bad-signature" };
|
|
510
|
+
}
|
|
511
|
+
let sig;
|
|
512
|
+
try {
|
|
513
|
+
sig = await readSignatureAny(openpgp, pgpSignature);
|
|
514
|
+
} catch {
|
|
515
|
+
return { verified: false, reason: "Unreadable signature", kind: "bad-signature" };
|
|
516
|
+
}
|
|
517
|
+
const life = await keyLife(publicKey, sig.packets[0]?.issuerKeyID ?? null, pgpConfig(openpgp));
|
|
518
|
+
const v = sig.text !== null ? await verifyClearsigned({ armoredKey: publicKey.armor(), clearsigned: normalizeInput(pgpSignature) }) : await verifyStatementSignature({ key: publicKey.armor(), signature: pgpSignature, address: ethAddress });
|
|
519
|
+
if (!v.verified) {
|
|
520
|
+
if (life.problem) return { verified: false, reason: v.reason, signingKey: life.signingKey, ...life.problem };
|
|
521
|
+
if (/too weak|reject|unsupported|not supported|unknown (curve|algorithm)/i.test(v.reason || "")) {
|
|
522
|
+
return { verified: false, reason: v.reason, kind: "unsupported", algorithm: life.algorithm, signingKey: life.signingKey };
|
|
523
|
+
}
|
|
524
|
+
return { verified: false, reason: v.reason, kind: "bad-signature", signingKey: life.signingKey };
|
|
525
|
+
}
|
|
526
|
+
if (v.text.trim().toLowerCase() !== statementText(ethAddress).toLowerCase()) {
|
|
527
|
+
return { verified: false, reason: "Signed text is not the statement for this address", kind: "bad-signature", signingKey: life.signingKey };
|
|
528
|
+
}
|
|
529
|
+
return { verified: true, kind: "verified", signingKey: life.signingKey, expiresAt: life.expiresAt };
|
|
530
|
+
} catch {
|
|
531
|
+
return { verified: false, reason: "Signature verification failed", kind: "bad-signature" };
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
var EMAIL_UID = /@/;
|
|
535
|
+
var EMAIL_IN_TEXT = /(?:^|[^\w/.+-])([\w.+-]+@[\w-]+(?:\.[\w-]+)+)/;
|
|
536
|
+
function notationEmails(sig) {
|
|
537
|
+
const out = [];
|
|
538
|
+
for (const n of sig?.rawNotations ?? []) {
|
|
539
|
+
const text = typeof n.value === "string" ? n.value : new TextDecoder().decode(n.value);
|
|
540
|
+
const m = text.match(EMAIL_IN_TEXT);
|
|
541
|
+
if (m) out.push(m[1]);
|
|
542
|
+
}
|
|
543
|
+
return out;
|
|
544
|
+
}
|
|
545
|
+
async function stripEmailUserIDs(armoredKey) {
|
|
546
|
+
try {
|
|
547
|
+
const openpgp = await import("openpgp");
|
|
548
|
+
const key = await readKeyAny(openpgp, armoredKey);
|
|
549
|
+
const kept = [];
|
|
550
|
+
const removed = [];
|
|
551
|
+
const users = key.users.filter((u) => {
|
|
552
|
+
const uid = u.userID?.userID;
|
|
553
|
+
if (!uid) return false;
|
|
554
|
+
if (EMAIL_UID.test(uid)) {
|
|
555
|
+
removed.push(uid);
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
kept.push(uid);
|
|
559
|
+
return true;
|
|
560
|
+
});
|
|
561
|
+
if (users.length === 0) return null;
|
|
562
|
+
key.users = users;
|
|
563
|
+
return { armored: key.armor(), binary: key.write(), kept, removed };
|
|
564
|
+
} catch {
|
|
565
|
+
return null;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
async function hasEmailUserID(armoredKey) {
|
|
569
|
+
try {
|
|
570
|
+
const openpgp = await import("openpgp");
|
|
571
|
+
const key = await readKeyAny(openpgp, armoredKey);
|
|
572
|
+
return key.users.some((u) => EMAIL_UID.test(u.userID?.userID ?? ""));
|
|
573
|
+
} catch {
|
|
574
|
+
return false;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
async function leanKey(input, { includeEmail = false } = {}) {
|
|
578
|
+
try {
|
|
579
|
+
const openpgp = await import("openpgp");
|
|
580
|
+
const key = await readKeyAny(openpgp, input);
|
|
581
|
+
const kept = [];
|
|
582
|
+
const removed = [];
|
|
583
|
+
const newest = (sigs = []) => sigs.length ? [[...sigs].sort((x, y) => (y.created?.getTime?.() ?? 0) - (x.created?.getTime?.() ?? 0))[0]] : [];
|
|
584
|
+
for (const u of key.users) {
|
|
585
|
+
u.selfCertifications = u.revocationSignatures?.length ? [] : newest(u.selfCertifications);
|
|
586
|
+
u.otherCertifications = [];
|
|
587
|
+
}
|
|
588
|
+
const users = key.users.filter((u) => {
|
|
589
|
+
const uid = u.userID?.userID;
|
|
590
|
+
if (!uid) return false;
|
|
591
|
+
if (!includeEmail && (EMAIL_UID.test(uid) || u.selfCertifications.some((c) => notationEmails(c).length))) {
|
|
592
|
+
removed.push(uid);
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
kept.push(uid);
|
|
596
|
+
return true;
|
|
597
|
+
});
|
|
598
|
+
if (users.length === 0) return null;
|
|
599
|
+
key.users = users;
|
|
600
|
+
key.directSignatures = newest(key.directSignatures);
|
|
601
|
+
const keyNotationEmails = includeEmail ? [] : key.directSignatures.flatMap(notationEmails);
|
|
602
|
+
for (const sk of key.subkeys) sk.bindingSignatures = newest(sk.bindingSignatures);
|
|
603
|
+
return { binary: key.write(), kept, removed, keyNotationEmails };
|
|
604
|
+
} catch {
|
|
605
|
+
return null;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
async function claimSignature({ signature, key, address }) {
|
|
609
|
+
try {
|
|
610
|
+
const openpgp = await import("openpgp");
|
|
611
|
+
const sig = await readSignatureAny(openpgp, signature);
|
|
612
|
+
if (sig.text === null) {
|
|
613
|
+
const v = normalizeInput(signature);
|
|
614
|
+
const raw = typeof v === "string" ? (await openpgp.unarmor(v)).data : v;
|
|
615
|
+
return { signature: raw, messageVersion: 1 };
|
|
616
|
+
}
|
|
617
|
+
const packet = sig.signature.write();
|
|
618
|
+
if ((await verifyStatementSignature({ key, signature: packet, address })).verified) return { signature: packet, messageVersion: 1 };
|
|
619
|
+
return { signature: normalizeInput(signature), messageVersion: 0 };
|
|
620
|
+
} catch {
|
|
621
|
+
return null;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
async function signatureEmail(signature) {
|
|
625
|
+
try {
|
|
626
|
+
const openpgp = await import("openpgp");
|
|
627
|
+
const { packets } = await readSignatureAny(openpgp, signature);
|
|
628
|
+
for (const p of packets) {
|
|
629
|
+
const uid = p.signersUserID ?? null;
|
|
630
|
+
if (uid && uid.includes("@")) return uid;
|
|
631
|
+
}
|
|
632
|
+
return null;
|
|
633
|
+
} catch {
|
|
634
|
+
return null;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
async function payloadText(input, kind) {
|
|
638
|
+
try {
|
|
639
|
+
const v = normalizeInput(input);
|
|
640
|
+
if (typeof v === "string") return v;
|
|
641
|
+
const openpgp = await import("openpgp");
|
|
642
|
+
if (kind === "key") return (await openpgp.readKey({ binaryKey: v })).armor();
|
|
643
|
+
return (await openpgp.readSignature({ binarySignature: v })).armor();
|
|
644
|
+
} catch {
|
|
645
|
+
return null;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
var AUTH_FLAG = 32;
|
|
649
|
+
function sshString(bytes) {
|
|
650
|
+
const out = new Uint8Array(4 + bytes.length);
|
|
651
|
+
new DataView(out.buffer).setUint32(0, bytes.length);
|
|
652
|
+
out.set(bytes, 4);
|
|
653
|
+
return out;
|
|
654
|
+
}
|
|
655
|
+
function sshMpint(bytes) {
|
|
656
|
+
let i = 0;
|
|
657
|
+
while (i < bytes.length - 1 && bytes[i] === 0) i++;
|
|
658
|
+
const b = bytes.subarray(i);
|
|
659
|
+
return sshString(b[0] & 128 ? new Uint8Array([0, ...b]) : b);
|
|
660
|
+
}
|
|
661
|
+
function sshBlob(p) {
|
|
662
|
+
const text = (s) => new TextEncoder().encode(s);
|
|
663
|
+
const join = (...parts) => {
|
|
664
|
+
const out = new Uint8Array(parts.reduce((n, x) => n + x.length, 0));
|
|
665
|
+
let o = 0;
|
|
666
|
+
for (const x of parts) {
|
|
667
|
+
out.set(x, o);
|
|
668
|
+
o += x.length;
|
|
669
|
+
}
|
|
670
|
+
return out;
|
|
671
|
+
};
|
|
672
|
+
const { publicParams: pp } = p;
|
|
673
|
+
switch (p.algorithm) {
|
|
674
|
+
case 1:
|
|
675
|
+
case 3:
|
|
676
|
+
return { type: "ssh-rsa", blob: join(sshString(text("ssh-rsa")), sshMpint(pp.e), sshMpint(pp.n)) };
|
|
677
|
+
case 22:
|
|
678
|
+
if (pp.oid?.getName?.() !== "ed25519Legacy" || pp.Q?.length !== 33) return null;
|
|
679
|
+
return { type: "ssh-ed25519", blob: join(sshString(text("ssh-ed25519")), sshString(pp.Q.subarray(1))) };
|
|
680
|
+
case 27:
|
|
681
|
+
return { type: "ssh-ed25519", blob: join(sshString(text("ssh-ed25519")), sshString(pp.A)) };
|
|
682
|
+
case 19: {
|
|
683
|
+
const curve = { nistP256: "nistp256", nistP384: "nistp384", nistP521: "nistp521" }[pp.oid?.getName?.()];
|
|
684
|
+
if (!curve) return null;
|
|
685
|
+
const type = `ecdsa-sha2-${curve}`;
|
|
686
|
+
return { type, blob: join(sshString(text(type)), sshString(text(curve)), sshString(pp.Q)) };
|
|
687
|
+
}
|
|
688
|
+
default:
|
|
689
|
+
return null;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
function base64(bytes) {
|
|
693
|
+
let s = "";
|
|
694
|
+
for (const b of bytes) s += String.fromCharCode(b);
|
|
695
|
+
return btoa(s);
|
|
696
|
+
}
|
|
697
|
+
async function sshKeys(input) {
|
|
698
|
+
try {
|
|
699
|
+
const openpgp = await import("openpgp");
|
|
700
|
+
const config = pgpConfig(openpgp);
|
|
701
|
+
const key = await readKeyAny(openpgp, input);
|
|
702
|
+
const now = /* @__PURE__ */ new Date();
|
|
703
|
+
try {
|
|
704
|
+
await key.verifyPrimaryKey(now, void 0, config);
|
|
705
|
+
} catch {
|
|
706
|
+
return [];
|
|
707
|
+
}
|
|
708
|
+
const candidates = [];
|
|
709
|
+
const direct = newestSignature(key.directSignatures);
|
|
710
|
+
const primarySig = direct?.keyFlags ? direct : (await key.getPrimaryUser(now, void 0, config)).selfCertification;
|
|
711
|
+
candidates.push({ packet: key.keyPacket, flags: primarySig?.keyFlags?.[0] ?? 0 });
|
|
712
|
+
for (const sk of key.subkeys) {
|
|
713
|
+
try {
|
|
714
|
+
await sk.verify(now, config);
|
|
715
|
+
} catch {
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
718
|
+
candidates.push({ packet: sk.keyPacket, flags: newestSignature(sk.bindingSignatures)?.keyFlags?.[0] ?? 0 });
|
|
719
|
+
}
|
|
720
|
+
const out = [];
|
|
721
|
+
for (const { packet, flags } of candidates) {
|
|
722
|
+
if (!(flags & AUTH_FLAG)) continue;
|
|
723
|
+
const ssh = sshBlob(packet);
|
|
724
|
+
if (!ssh) continue;
|
|
725
|
+
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", ssh.blob));
|
|
726
|
+
out.push({
|
|
727
|
+
line: `${ssh.type} ${base64(ssh.blob)}`,
|
|
728
|
+
sha256: `SHA256:${base64(digest).replace(/=+$/, "")}`,
|
|
729
|
+
fingerprint: packet.getFingerprint().toUpperCase()
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
return out;
|
|
733
|
+
} catch {
|
|
734
|
+
return [];
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// src/core/authorization.ts
|
|
739
|
+
import { hashTypedData, keccak256 as keccak2562, stringToHex } from "viem";
|
|
740
|
+
var EIP712_NAME = "Thurin PGPRegistry";
|
|
741
|
+
var EIP712_VERSION = "3";
|
|
742
|
+
function registryDomain(chainId, verifyingContract) {
|
|
743
|
+
return { name: EIP712_NAME, version: EIP712_VERSION, chainId, verifyingContract };
|
|
744
|
+
}
|
|
745
|
+
var AUTHORIZATION_TYPES = {
|
|
746
|
+
Attest: [
|
|
747
|
+
{ name: "owner", type: "address" },
|
|
748
|
+
{ name: "fingerprint", type: "bytes" },
|
|
749
|
+
{ name: "signature", type: "bytes" },
|
|
750
|
+
{ name: "key", type: "bytes" },
|
|
751
|
+
{ name: "nonce", type: "uint256" },
|
|
752
|
+
{ name: "deadline", type: "uint256" }
|
|
753
|
+
],
|
|
754
|
+
Reattest: [
|
|
755
|
+
{ name: "owner", type: "address" },
|
|
756
|
+
{ name: "revokeIndex", type: "uint256" },
|
|
757
|
+
{ name: "fingerprint", type: "bytes" },
|
|
758
|
+
{ name: "signature", type: "bytes" },
|
|
759
|
+
{ name: "key", type: "bytes" },
|
|
760
|
+
{ name: "keepRecords", type: "bool" },
|
|
761
|
+
{ name: "nonce", type: "uint256" },
|
|
762
|
+
{ name: "deadline", type: "uint256" }
|
|
763
|
+
],
|
|
764
|
+
UpdateKey: [
|
|
765
|
+
{ name: "owner", type: "address" },
|
|
766
|
+
{ name: "index", type: "uint256" },
|
|
767
|
+
{ name: "key", type: "bytes" },
|
|
768
|
+
{ name: "nonce", type: "uint256" },
|
|
769
|
+
{ name: "deadline", type: "uint256" }
|
|
770
|
+
],
|
|
771
|
+
Revoke: [
|
|
772
|
+
{ name: "owner", type: "address" },
|
|
773
|
+
{ name: "index", type: "uint256" },
|
|
774
|
+
{ name: "reason", type: "string" },
|
|
775
|
+
{ name: "nonce", type: "uint256" },
|
|
776
|
+
{ name: "deadline", type: "uint256" }
|
|
777
|
+
],
|
|
778
|
+
SetRecord: [
|
|
779
|
+
{ name: "owner", type: "address" },
|
|
780
|
+
{ name: "index", type: "uint256" },
|
|
781
|
+
{ name: "kind", type: "string" },
|
|
782
|
+
{ name: "value", type: "string" },
|
|
783
|
+
{ name: "nonce", type: "uint256" },
|
|
784
|
+
{ name: "deadline", type: "uint256" }
|
|
785
|
+
],
|
|
786
|
+
MarkCompromised: [
|
|
787
|
+
{ name: "owner", type: "address" },
|
|
788
|
+
{ name: "index", type: "uint256" },
|
|
789
|
+
{ name: "nonce", type: "uint256" },
|
|
790
|
+
{ name: "deadline", type: "uint256" }
|
|
791
|
+
]
|
|
792
|
+
};
|
|
793
|
+
var REVOKE_REASONS = ["", "compromised", "retired", "superseded", "other"];
|
|
794
|
+
var OWNER_REVOKE_REASONS = ["", "compromised", "retired", "other"];
|
|
795
|
+
function payloadBytes(v) {
|
|
796
|
+
return /^0x([0-9a-fA-F]{2})*$/.test(v) ? v : stringToHex(v);
|
|
797
|
+
}
|
|
798
|
+
function attestTypedData(chainId, registry, a) {
|
|
799
|
+
return {
|
|
800
|
+
domain: registryDomain(chainId, registry),
|
|
801
|
+
types: { Attest: AUTHORIZATION_TYPES.Attest },
|
|
802
|
+
primaryType: "Attest",
|
|
803
|
+
message: {
|
|
804
|
+
owner: a.owner,
|
|
805
|
+
fingerprint: fingerprintToBytes(a.fingerprint),
|
|
806
|
+
signature: payloadBytes(a.signature),
|
|
807
|
+
key: payloadBytes(a.key),
|
|
808
|
+
nonce: a.nonce,
|
|
809
|
+
deadline: a.deadline
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
function reattestTypedData(chainId, registry, a) {
|
|
814
|
+
return {
|
|
815
|
+
domain: registryDomain(chainId, registry),
|
|
816
|
+
types: { Reattest: AUTHORIZATION_TYPES.Reattest },
|
|
817
|
+
primaryType: "Reattest",
|
|
818
|
+
message: {
|
|
819
|
+
owner: a.owner,
|
|
820
|
+
revokeIndex: a.revokeIndex,
|
|
821
|
+
fingerprint: fingerprintToBytes(a.fingerprint),
|
|
822
|
+
signature: payloadBytes(a.signature),
|
|
823
|
+
key: payloadBytes(a.key),
|
|
824
|
+
keepRecords: a.keepRecords,
|
|
825
|
+
nonce: a.nonce,
|
|
826
|
+
deadline: a.deadline
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
function updateKeyTypedData(chainId, registry, a) {
|
|
831
|
+
return {
|
|
832
|
+
domain: registryDomain(chainId, registry),
|
|
833
|
+
types: { UpdateKey: AUTHORIZATION_TYPES.UpdateKey },
|
|
834
|
+
primaryType: "UpdateKey",
|
|
835
|
+
message: { owner: a.owner, index: a.index, key: payloadBytes(a.key), nonce: a.nonce, deadline: a.deadline }
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
function revokeTypedData(chainId, registry, a) {
|
|
839
|
+
return {
|
|
840
|
+
domain: registryDomain(chainId, registry),
|
|
841
|
+
types: { Revoke: AUTHORIZATION_TYPES.Revoke },
|
|
842
|
+
primaryType: "Revoke",
|
|
843
|
+
message: { owner: a.owner, index: a.index, reason: a.reason ?? "", nonce: a.nonce, deadline: a.deadline }
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
function setRecordTypedData(chainId, registry, a) {
|
|
847
|
+
return {
|
|
848
|
+
domain: registryDomain(chainId, registry),
|
|
849
|
+
types: { SetRecord: AUTHORIZATION_TYPES.SetRecord },
|
|
850
|
+
primaryType: "SetRecord",
|
|
851
|
+
message: { owner: a.owner, index: a.index, kind: a.kind, value: a.value, nonce: a.nonce, deadline: a.deadline }
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
function markCompromisedTypedData(chainId, registry, a) {
|
|
855
|
+
return {
|
|
856
|
+
domain: registryDomain(chainId, registry),
|
|
857
|
+
types: { MarkCompromised: AUTHORIZATION_TYPES.MarkCompromised },
|
|
858
|
+
primaryType: "MarkCompromised",
|
|
859
|
+
message: { owner: a.owner, index: a.index, nonce: a.nonce, deadline: a.deadline }
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
function authorizationDigest(typedData) {
|
|
863
|
+
return hashTypedData(typedData);
|
|
864
|
+
}
|
|
865
|
+
function recordKind(name) {
|
|
866
|
+
return keccak2562(stringToHex(name));
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
// src/core/contract.ts
|
|
870
|
+
import { mainnet, sepolia, foundry } from "viem/chains";
|
|
871
|
+
|
|
1
872
|
// src/core/abi.ts
|
|
2
873
|
var REGISTRY_ABI = [
|
|
3
874
|
{
|
|
@@ -52,6 +923,45 @@ var REGISTRY_ABI = [
|
|
|
52
923
|
],
|
|
53
924
|
"stateMutability": "view"
|
|
54
925
|
},
|
|
926
|
+
{
|
|
927
|
+
"type": "function",
|
|
928
|
+
"name": "EPOCH",
|
|
929
|
+
"inputs": [],
|
|
930
|
+
"outputs": [
|
|
931
|
+
{
|
|
932
|
+
"name": "",
|
|
933
|
+
"type": "uint256",
|
|
934
|
+
"internalType": "uint256"
|
|
935
|
+
}
|
|
936
|
+
],
|
|
937
|
+
"stateMutability": "view"
|
|
938
|
+
},
|
|
939
|
+
{
|
|
940
|
+
"type": "function",
|
|
941
|
+
"name": "MARK_COMPROMISED_TYPEHASH",
|
|
942
|
+
"inputs": [],
|
|
943
|
+
"outputs": [
|
|
944
|
+
{
|
|
945
|
+
"name": "",
|
|
946
|
+
"type": "bytes32",
|
|
947
|
+
"internalType": "bytes32"
|
|
948
|
+
}
|
|
949
|
+
],
|
|
950
|
+
"stateMutability": "view"
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
"type": "function",
|
|
954
|
+
"name": "MAX_CLAIMS_PER_OWNER",
|
|
955
|
+
"inputs": [],
|
|
956
|
+
"outputs": [
|
|
957
|
+
{
|
|
958
|
+
"name": "",
|
|
959
|
+
"type": "uint256",
|
|
960
|
+
"internalType": "uint256"
|
|
961
|
+
}
|
|
962
|
+
],
|
|
963
|
+
"stateMutability": "view"
|
|
964
|
+
},
|
|
55
965
|
{
|
|
56
966
|
"type": "function",
|
|
57
967
|
"name": "MAX_KEY_BYTES",
|
|
@@ -65,6 +975,32 @@ var REGISTRY_ABI = [
|
|
|
65
975
|
],
|
|
66
976
|
"stateMutability": "view"
|
|
67
977
|
},
|
|
978
|
+
{
|
|
979
|
+
"type": "function",
|
|
980
|
+
"name": "MAX_KIND_BYTES",
|
|
981
|
+
"inputs": [],
|
|
982
|
+
"outputs": [
|
|
983
|
+
{
|
|
984
|
+
"name": "",
|
|
985
|
+
"type": "uint256",
|
|
986
|
+
"internalType": "uint256"
|
|
987
|
+
}
|
|
988
|
+
],
|
|
989
|
+
"stateMutability": "view"
|
|
990
|
+
},
|
|
991
|
+
{
|
|
992
|
+
"type": "function",
|
|
993
|
+
"name": "MAX_PAYLOAD_BYTES",
|
|
994
|
+
"inputs": [],
|
|
995
|
+
"outputs": [
|
|
996
|
+
{
|
|
997
|
+
"name": "",
|
|
998
|
+
"type": "uint256",
|
|
999
|
+
"internalType": "uint256"
|
|
1000
|
+
}
|
|
1001
|
+
],
|
|
1002
|
+
"stateMutability": "view"
|
|
1003
|
+
},
|
|
68
1004
|
{
|
|
69
1005
|
"type": "function",
|
|
70
1006
|
"name": "MAX_RECORD_BYTES",
|
|
@@ -80,7 +1016,7 @@ var REGISTRY_ABI = [
|
|
|
80
1016
|
},
|
|
81
1017
|
{
|
|
82
1018
|
"type": "function",
|
|
83
|
-
"name": "
|
|
1019
|
+
"name": "MAX_SIGNATURE_BYTES",
|
|
84
1020
|
"inputs": [],
|
|
85
1021
|
"outputs": [
|
|
86
1022
|
{
|
|
@@ -93,7 +1029,20 @@ var REGISTRY_ABI = [
|
|
|
93
1029
|
},
|
|
94
1030
|
{
|
|
95
1031
|
"type": "function",
|
|
96
|
-
"name": "
|
|
1032
|
+
"name": "MESSAGE_CLEARSIGNED",
|
|
1033
|
+
"inputs": [],
|
|
1034
|
+
"outputs": [
|
|
1035
|
+
{
|
|
1036
|
+
"name": "",
|
|
1037
|
+
"type": "uint8",
|
|
1038
|
+
"internalType": "uint8"
|
|
1039
|
+
}
|
|
1040
|
+
],
|
|
1041
|
+
"stateMutability": "view"
|
|
1042
|
+
},
|
|
1043
|
+
{
|
|
1044
|
+
"type": "function",
|
|
1045
|
+
"name": "MESSAGE_DETACHED",
|
|
97
1046
|
"inputs": [],
|
|
98
1047
|
"outputs": [
|
|
99
1048
|
{
|
|
@@ -171,87 +1120,107 @@ var REGISTRY_ABI = [
|
|
|
171
1120
|
},
|
|
172
1121
|
{
|
|
173
1122
|
"type": "function",
|
|
174
|
-
"name": "
|
|
1123
|
+
"name": "armorToBytes",
|
|
175
1124
|
"inputs": [
|
|
176
1125
|
{
|
|
177
|
-
"name": "
|
|
178
|
-
"type": "
|
|
179
|
-
"internalType": "
|
|
1126
|
+
"name": "armored",
|
|
1127
|
+
"type": "string",
|
|
1128
|
+
"internalType": "string"
|
|
180
1129
|
}
|
|
181
1130
|
],
|
|
182
1131
|
"outputs": [
|
|
183
1132
|
{
|
|
184
1133
|
"name": "",
|
|
185
|
-
"type": "
|
|
186
|
-
"internalType": "
|
|
1134
|
+
"type": "bytes",
|
|
1135
|
+
"internalType": "bytes"
|
|
187
1136
|
}
|
|
188
1137
|
],
|
|
189
|
-
"stateMutability": "
|
|
1138
|
+
"stateMutability": "pure"
|
|
190
1139
|
},
|
|
191
1140
|
{
|
|
192
1141
|
"type": "function",
|
|
193
|
-
"name": "
|
|
1142
|
+
"name": "armoredKey",
|
|
194
1143
|
"inputs": [
|
|
195
1144
|
{
|
|
196
|
-
"name": "
|
|
197
|
-
"type": "
|
|
198
|
-
"internalType": "
|
|
1145
|
+
"name": "owner",
|
|
1146
|
+
"type": "address",
|
|
1147
|
+
"internalType": "address"
|
|
1148
|
+
},
|
|
1149
|
+
{
|
|
1150
|
+
"name": "index",
|
|
1151
|
+
"type": "uint256",
|
|
1152
|
+
"internalType": "uint256"
|
|
199
1153
|
}
|
|
200
1154
|
],
|
|
201
1155
|
"outputs": [
|
|
202
1156
|
{
|
|
203
1157
|
"name": "",
|
|
204
|
-
"type": "
|
|
205
|
-
"internalType": "
|
|
1158
|
+
"type": "string",
|
|
1159
|
+
"internalType": "string"
|
|
206
1160
|
}
|
|
207
1161
|
],
|
|
208
1162
|
"stateMutability": "view"
|
|
209
1163
|
},
|
|
210
1164
|
{
|
|
211
1165
|
"type": "function",
|
|
212
|
-
"name": "
|
|
1166
|
+
"name": "attest",
|
|
213
1167
|
"inputs": [
|
|
214
1168
|
{
|
|
215
|
-
"name": "
|
|
216
|
-
"type": "
|
|
217
|
-
"internalType": "
|
|
1169
|
+
"name": "fingerprint",
|
|
1170
|
+
"type": "bytes",
|
|
1171
|
+
"internalType": "bytes"
|
|
218
1172
|
},
|
|
219
1173
|
{
|
|
220
|
-
"name": "
|
|
221
|
-
"type": "
|
|
222
|
-
"internalType": "
|
|
1174
|
+
"name": "signature",
|
|
1175
|
+
"type": "bytes",
|
|
1176
|
+
"internalType": "bytes"
|
|
223
1177
|
},
|
|
224
1178
|
{
|
|
225
|
-
"name": "
|
|
226
|
-
"type": "
|
|
227
|
-
"internalType": "
|
|
1179
|
+
"name": "key",
|
|
1180
|
+
"type": "bytes",
|
|
1181
|
+
"internalType": "bytes"
|
|
228
1182
|
}
|
|
229
1183
|
],
|
|
230
1184
|
"outputs": [
|
|
231
1185
|
{
|
|
232
|
-
"name": "
|
|
233
|
-
"type": "
|
|
234
|
-
"internalType": "
|
|
1186
|
+
"name": "index",
|
|
1187
|
+
"type": "uint256",
|
|
1188
|
+
"internalType": "uint256"
|
|
235
1189
|
}
|
|
236
1190
|
],
|
|
237
|
-
"stateMutability": "
|
|
1191
|
+
"stateMutability": "nonpayable"
|
|
238
1192
|
},
|
|
239
1193
|
{
|
|
240
1194
|
"type": "function",
|
|
241
|
-
"name": "
|
|
1195
|
+
"name": "attestFor",
|
|
242
1196
|
"inputs": [
|
|
1197
|
+
{
|
|
1198
|
+
"name": "owner",
|
|
1199
|
+
"type": "address",
|
|
1200
|
+
"internalType": "address"
|
|
1201
|
+
},
|
|
243
1202
|
{
|
|
244
1203
|
"name": "fingerprint",
|
|
245
1204
|
"type": "bytes",
|
|
246
1205
|
"internalType": "bytes"
|
|
247
1206
|
},
|
|
248
1207
|
{
|
|
249
|
-
"name": "
|
|
1208
|
+
"name": "signature",
|
|
1209
|
+
"type": "bytes",
|
|
1210
|
+
"internalType": "bytes"
|
|
1211
|
+
},
|
|
1212
|
+
{
|
|
1213
|
+
"name": "key",
|
|
250
1214
|
"type": "bytes",
|
|
251
1215
|
"internalType": "bytes"
|
|
252
1216
|
},
|
|
253
1217
|
{
|
|
254
|
-
"name": "
|
|
1218
|
+
"name": "deadline",
|
|
1219
|
+
"type": "uint256",
|
|
1220
|
+
"internalType": "uint256"
|
|
1221
|
+
},
|
|
1222
|
+
{
|
|
1223
|
+
"name": "permission",
|
|
255
1224
|
"type": "bytes",
|
|
256
1225
|
"internalType": "bytes"
|
|
257
1226
|
}
|
|
@@ -267,7 +1236,14 @@ var REGISTRY_ABI = [
|
|
|
267
1236
|
},
|
|
268
1237
|
{
|
|
269
1238
|
"type": "function",
|
|
270
|
-
"name": "
|
|
1239
|
+
"name": "cancelAuthorization",
|
|
1240
|
+
"inputs": [],
|
|
1241
|
+
"outputs": [],
|
|
1242
|
+
"stateMutability": "nonpayable"
|
|
1243
|
+
},
|
|
1244
|
+
{
|
|
1245
|
+
"type": "function",
|
|
1246
|
+
"name": "claim",
|
|
271
1247
|
"inputs": [
|
|
272
1248
|
{
|
|
273
1249
|
"name": "owner",
|
|
@@ -275,43 +1251,80 @@ var REGISTRY_ABI = [
|
|
|
275
1251
|
"internalType": "address"
|
|
276
1252
|
},
|
|
277
1253
|
{
|
|
278
|
-
"name": "
|
|
279
|
-
"type": "
|
|
280
|
-
"internalType": "
|
|
281
|
-
}
|
|
1254
|
+
"name": "index",
|
|
1255
|
+
"type": "uint256",
|
|
1256
|
+
"internalType": "uint256"
|
|
1257
|
+
}
|
|
1258
|
+
],
|
|
1259
|
+
"outputs": [
|
|
282
1260
|
{
|
|
283
|
-
"name": "
|
|
284
|
-
"type": "
|
|
285
|
-
"internalType": "
|
|
1261
|
+
"name": "details",
|
|
1262
|
+
"type": "tuple",
|
|
1263
|
+
"internalType": "struct PGPRegistry.ClaimView",
|
|
1264
|
+
"components": [
|
|
1265
|
+
{
|
|
1266
|
+
"name": "index",
|
|
1267
|
+
"type": "uint256",
|
|
1268
|
+
"internalType": "uint256"
|
|
1269
|
+
},
|
|
1270
|
+
{
|
|
1271
|
+
"name": "fingerprint",
|
|
1272
|
+
"type": "bytes",
|
|
1273
|
+
"internalType": "bytes"
|
|
1274
|
+
},
|
|
1275
|
+
{
|
|
1276
|
+
"name": "createdAt",
|
|
1277
|
+
"type": "uint64",
|
|
1278
|
+
"internalType": "uint64"
|
|
1279
|
+
},
|
|
1280
|
+
{
|
|
1281
|
+
"name": "revokedAt",
|
|
1282
|
+
"type": "uint64",
|
|
1283
|
+
"internalType": "uint64"
|
|
1284
|
+
},
|
|
1285
|
+
{
|
|
1286
|
+
"name": "state",
|
|
1287
|
+
"type": "string",
|
|
1288
|
+
"internalType": "string"
|
|
1289
|
+
},
|
|
1290
|
+
{
|
|
1291
|
+
"name": "replacedBy",
|
|
1292
|
+
"type": "uint256",
|
|
1293
|
+
"internalType": "uint256"
|
|
1294
|
+
},
|
|
1295
|
+
{
|
|
1296
|
+
"name": "revokeReason",
|
|
1297
|
+
"type": "string",
|
|
1298
|
+
"internalType": "string"
|
|
1299
|
+
},
|
|
1300
|
+
{
|
|
1301
|
+
"name": "messageVersion",
|
|
1302
|
+
"type": "uint8",
|
|
1303
|
+
"internalType": "uint8"
|
|
1304
|
+
}
|
|
1305
|
+
]
|
|
286
1306
|
},
|
|
287
1307
|
{
|
|
288
|
-
"name": "
|
|
289
|
-
"type": "
|
|
290
|
-
"internalType": "
|
|
1308
|
+
"name": "key",
|
|
1309
|
+
"type": "string",
|
|
1310
|
+
"internalType": "string"
|
|
291
1311
|
},
|
|
292
1312
|
{
|
|
293
|
-
"name": "
|
|
294
|
-
"type": "
|
|
295
|
-
"internalType": "
|
|
1313
|
+
"name": "statement",
|
|
1314
|
+
"type": "string",
|
|
1315
|
+
"internalType": "string"
|
|
296
1316
|
},
|
|
297
1317
|
{
|
|
298
|
-
"name": "
|
|
299
|
-
"type": "
|
|
300
|
-
"internalType": "
|
|
301
|
-
}
|
|
302
|
-
],
|
|
303
|
-
"outputs": [
|
|
304
|
-
{
|
|
305
|
-
"name": "index",
|
|
306
|
-
"type": "uint256",
|
|
307
|
-
"internalType": "uint256"
|
|
1318
|
+
"name": "recordKinds",
|
|
1319
|
+
"type": "string[]",
|
|
1320
|
+
"internalType": "string[]"
|
|
308
1321
|
}
|
|
309
1322
|
],
|
|
310
|
-
"stateMutability": "
|
|
1323
|
+
"stateMutability": "view"
|
|
311
1324
|
},
|
|
312
1325
|
{
|
|
313
1326
|
"type": "function",
|
|
314
|
-
"name": "
|
|
1327
|
+
"name": "claimCount",
|
|
315
1328
|
"inputs": [
|
|
316
1329
|
{
|
|
317
1330
|
"name": "owner",
|
|
@@ -330,7 +1343,7 @@ var REGISTRY_ABI = [
|
|
|
330
1343
|
},
|
|
331
1344
|
{
|
|
332
1345
|
"type": "function",
|
|
333
|
-
"name": "
|
|
1346
|
+
"name": "claimsOf",
|
|
334
1347
|
"inputs": [
|
|
335
1348
|
{
|
|
336
1349
|
"name": "owner",
|
|
@@ -340,10 +1353,15 @@ var REGISTRY_ABI = [
|
|
|
340
1353
|
],
|
|
341
1354
|
"outputs": [
|
|
342
1355
|
{
|
|
343
|
-
"name": "",
|
|
1356
|
+
"name": "out",
|
|
344
1357
|
"type": "tuple[]",
|
|
345
|
-
"internalType": "struct PGPRegistry.
|
|
1358
|
+
"internalType": "struct PGPRegistry.ClaimView[]",
|
|
346
1359
|
"components": [
|
|
1360
|
+
{
|
|
1361
|
+
"name": "index",
|
|
1362
|
+
"type": "uint256",
|
|
1363
|
+
"internalType": "uint256"
|
|
1364
|
+
},
|
|
347
1365
|
{
|
|
348
1366
|
"name": "fingerprint",
|
|
349
1367
|
"type": "bytes",
|
|
@@ -360,19 +1378,24 @@ var REGISTRY_ABI = [
|
|
|
360
1378
|
"internalType": "uint64"
|
|
361
1379
|
},
|
|
362
1380
|
{
|
|
363
|
-
"name": "
|
|
364
|
-
"type": "
|
|
365
|
-
"internalType": "
|
|
1381
|
+
"name": "state",
|
|
1382
|
+
"type": "string",
|
|
1383
|
+
"internalType": "string"
|
|
1384
|
+
},
|
|
1385
|
+
{
|
|
1386
|
+
"name": "replacedBy",
|
|
1387
|
+
"type": "uint256",
|
|
1388
|
+
"internalType": "uint256"
|
|
366
1389
|
},
|
|
367
1390
|
{
|
|
368
|
-
"name": "
|
|
369
|
-
"type": "
|
|
370
|
-
"internalType": "
|
|
1391
|
+
"name": "revokeReason",
|
|
1392
|
+
"type": "string",
|
|
1393
|
+
"internalType": "string"
|
|
371
1394
|
},
|
|
372
1395
|
{
|
|
373
|
-
"name": "
|
|
374
|
-
"type": "
|
|
375
|
-
"internalType": "
|
|
1396
|
+
"name": "messageVersion",
|
|
1397
|
+
"type": "uint8",
|
|
1398
|
+
"internalType": "uint8"
|
|
376
1399
|
}
|
|
377
1400
|
]
|
|
378
1401
|
}
|
|
@@ -381,7 +1404,7 @@ var REGISTRY_ABI = [
|
|
|
381
1404
|
},
|
|
382
1405
|
{
|
|
383
1406
|
"type": "function",
|
|
384
|
-
"name": "
|
|
1407
|
+
"name": "claimsOfRange",
|
|
385
1408
|
"inputs": [
|
|
386
1409
|
{
|
|
387
1410
|
"name": "owner",
|
|
@@ -403,8 +1426,13 @@ var REGISTRY_ABI = [
|
|
|
403
1426
|
{
|
|
404
1427
|
"name": "out",
|
|
405
1428
|
"type": "tuple[]",
|
|
406
|
-
"internalType": "struct PGPRegistry.
|
|
1429
|
+
"internalType": "struct PGPRegistry.ClaimView[]",
|
|
407
1430
|
"components": [
|
|
1431
|
+
{
|
|
1432
|
+
"name": "index",
|
|
1433
|
+
"type": "uint256",
|
|
1434
|
+
"internalType": "uint256"
|
|
1435
|
+
},
|
|
408
1436
|
{
|
|
409
1437
|
"name": "fingerprint",
|
|
410
1438
|
"type": "bytes",
|
|
@@ -421,19 +1449,24 @@ var REGISTRY_ABI = [
|
|
|
421
1449
|
"internalType": "uint64"
|
|
422
1450
|
},
|
|
423
1451
|
{
|
|
424
|
-
"name": "
|
|
425
|
-
"type": "
|
|
426
|
-
"internalType": "
|
|
1452
|
+
"name": "state",
|
|
1453
|
+
"type": "string",
|
|
1454
|
+
"internalType": "string"
|
|
1455
|
+
},
|
|
1456
|
+
{
|
|
1457
|
+
"name": "replacedBy",
|
|
1458
|
+
"type": "uint256",
|
|
1459
|
+
"internalType": "uint256"
|
|
427
1460
|
},
|
|
428
1461
|
{
|
|
429
|
-
"name": "
|
|
430
|
-
"type": "
|
|
431
|
-
"internalType": "
|
|
1462
|
+
"name": "revokeReason",
|
|
1463
|
+
"type": "string",
|
|
1464
|
+
"internalType": "string"
|
|
432
1465
|
},
|
|
433
1466
|
{
|
|
434
|
-
"name": "
|
|
435
|
-
"type": "
|
|
436
|
-
"internalType": "
|
|
1467
|
+
"name": "messageVersion",
|
|
1468
|
+
"type": "uint8",
|
|
1469
|
+
"internalType": "uint8"
|
|
437
1470
|
}
|
|
438
1471
|
]
|
|
439
1472
|
}
|
|
@@ -442,10 +1475,27 @@ var REGISTRY_ABI = [
|
|
|
442
1475
|
},
|
|
443
1476
|
{
|
|
444
1477
|
"type": "function",
|
|
445
|
-
"name": "
|
|
446
|
-
"inputs": [
|
|
447
|
-
|
|
448
|
-
|
|
1478
|
+
"name": "clearsigned",
|
|
1479
|
+
"inputs": [
|
|
1480
|
+
{
|
|
1481
|
+
"name": "owner",
|
|
1482
|
+
"type": "address",
|
|
1483
|
+
"internalType": "address"
|
|
1484
|
+
},
|
|
1485
|
+
{
|
|
1486
|
+
"name": "index",
|
|
1487
|
+
"type": "uint256",
|
|
1488
|
+
"internalType": "uint256"
|
|
1489
|
+
}
|
|
1490
|
+
],
|
|
1491
|
+
"outputs": [
|
|
1492
|
+
{
|
|
1493
|
+
"name": "",
|
|
1494
|
+
"type": "string",
|
|
1495
|
+
"internalType": "string"
|
|
1496
|
+
}
|
|
1497
|
+
],
|
|
1498
|
+
"stateMutability": "view"
|
|
449
1499
|
},
|
|
450
1500
|
{
|
|
451
1501
|
"type": "function",
|
|
@@ -469,10 +1519,15 @@ var REGISTRY_ABI = [
|
|
|
469
1519
|
"internalType": "uint256"
|
|
470
1520
|
},
|
|
471
1521
|
{
|
|
472
|
-
"name": "
|
|
1522
|
+
"name": "details",
|
|
473
1523
|
"type": "tuple",
|
|
474
|
-
"internalType": "struct PGPRegistry.
|
|
1524
|
+
"internalType": "struct PGPRegistry.ClaimView",
|
|
475
1525
|
"components": [
|
|
1526
|
+
{
|
|
1527
|
+
"name": "index",
|
|
1528
|
+
"type": "uint256",
|
|
1529
|
+
"internalType": "uint256"
|
|
1530
|
+
},
|
|
476
1531
|
{
|
|
477
1532
|
"name": "fingerprint",
|
|
478
1533
|
"type": "bytes",
|
|
@@ -489,25 +1544,73 @@ var REGISTRY_ABI = [
|
|
|
489
1544
|
"internalType": "uint64"
|
|
490
1545
|
},
|
|
491
1546
|
{
|
|
492
|
-
"name": "
|
|
493
|
-
"type": "
|
|
494
|
-
"internalType": "
|
|
1547
|
+
"name": "state",
|
|
1548
|
+
"type": "string",
|
|
1549
|
+
"internalType": "string"
|
|
1550
|
+
},
|
|
1551
|
+
{
|
|
1552
|
+
"name": "replacedBy",
|
|
1553
|
+
"type": "uint256",
|
|
1554
|
+
"internalType": "uint256"
|
|
495
1555
|
},
|
|
496
1556
|
{
|
|
497
|
-
"name": "
|
|
498
|
-
"type": "
|
|
499
|
-
"internalType": "
|
|
1557
|
+
"name": "revokeReason",
|
|
1558
|
+
"type": "string",
|
|
1559
|
+
"internalType": "string"
|
|
500
1560
|
},
|
|
501
1561
|
{
|
|
502
|
-
"name": "
|
|
503
|
-
"type": "
|
|
504
|
-
"internalType": "
|
|
1562
|
+
"name": "messageVersion",
|
|
1563
|
+
"type": "uint8",
|
|
1564
|
+
"internalType": "uint8"
|
|
505
1565
|
}
|
|
506
1566
|
]
|
|
507
1567
|
}
|
|
508
1568
|
],
|
|
509
1569
|
"stateMutability": "view"
|
|
510
1570
|
},
|
|
1571
|
+
{
|
|
1572
|
+
"type": "function",
|
|
1573
|
+
"name": "eip712Domain",
|
|
1574
|
+
"inputs": [],
|
|
1575
|
+
"outputs": [
|
|
1576
|
+
{
|
|
1577
|
+
"name": "fields",
|
|
1578
|
+
"type": "bytes1",
|
|
1579
|
+
"internalType": "bytes1"
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
"name": "name",
|
|
1583
|
+
"type": "string",
|
|
1584
|
+
"internalType": "string"
|
|
1585
|
+
},
|
|
1586
|
+
{
|
|
1587
|
+
"name": "version",
|
|
1588
|
+
"type": "string",
|
|
1589
|
+
"internalType": "string"
|
|
1590
|
+
},
|
|
1591
|
+
{
|
|
1592
|
+
"name": "chainId",
|
|
1593
|
+
"type": "uint256",
|
|
1594
|
+
"internalType": "uint256"
|
|
1595
|
+
},
|
|
1596
|
+
{
|
|
1597
|
+
"name": "verifyingContract",
|
|
1598
|
+
"type": "address",
|
|
1599
|
+
"internalType": "address"
|
|
1600
|
+
},
|
|
1601
|
+
{
|
|
1602
|
+
"name": "salt",
|
|
1603
|
+
"type": "bytes32",
|
|
1604
|
+
"internalType": "bytes32"
|
|
1605
|
+
},
|
|
1606
|
+
{
|
|
1607
|
+
"name": "extensions",
|
|
1608
|
+
"type": "uint256[]",
|
|
1609
|
+
"internalType": "uint256[]"
|
|
1610
|
+
}
|
|
1611
|
+
],
|
|
1612
|
+
"stateMutability": "view"
|
|
1613
|
+
},
|
|
511
1614
|
{
|
|
512
1615
|
"type": "function",
|
|
513
1616
|
"name": "fingerprintsForKeyId",
|
|
@@ -520,21 +1623,164 @@ var REGISTRY_ABI = [
|
|
|
520
1623
|
],
|
|
521
1624
|
"outputs": [
|
|
522
1625
|
{
|
|
523
|
-
"name": "",
|
|
1626
|
+
"name": "",
|
|
1627
|
+
"type": "bytes[]",
|
|
1628
|
+
"internalType": "bytes[]"
|
|
1629
|
+
}
|
|
1630
|
+
],
|
|
1631
|
+
"stateMutability": "view"
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
"type": "function",
|
|
1635
|
+
"name": "fingerprintsForKeyIdCount",
|
|
1636
|
+
"inputs": [
|
|
1637
|
+
{
|
|
1638
|
+
"name": "keyId",
|
|
1639
|
+
"type": "bytes8",
|
|
1640
|
+
"internalType": "bytes8"
|
|
1641
|
+
}
|
|
1642
|
+
],
|
|
1643
|
+
"outputs": [
|
|
1644
|
+
{
|
|
1645
|
+
"name": "",
|
|
1646
|
+
"type": "uint256",
|
|
1647
|
+
"internalType": "uint256"
|
|
1648
|
+
}
|
|
1649
|
+
],
|
|
1650
|
+
"stateMutability": "view"
|
|
1651
|
+
},
|
|
1652
|
+
{
|
|
1653
|
+
"type": "function",
|
|
1654
|
+
"name": "fingerprintsForKeyIdRange",
|
|
1655
|
+
"inputs": [
|
|
1656
|
+
{
|
|
1657
|
+
"name": "keyId",
|
|
1658
|
+
"type": "bytes8",
|
|
1659
|
+
"internalType": "bytes8"
|
|
1660
|
+
},
|
|
1661
|
+
{
|
|
1662
|
+
"name": "start",
|
|
1663
|
+
"type": "uint256",
|
|
1664
|
+
"internalType": "uint256"
|
|
1665
|
+
},
|
|
1666
|
+
{
|
|
1667
|
+
"name": "count",
|
|
1668
|
+
"type": "uint256",
|
|
1669
|
+
"internalType": "uint256"
|
|
1670
|
+
}
|
|
1671
|
+
],
|
|
1672
|
+
"outputs": [
|
|
1673
|
+
{
|
|
1674
|
+
"name": "out",
|
|
1675
|
+
"type": "bytes[]",
|
|
1676
|
+
"internalType": "bytes[]"
|
|
1677
|
+
}
|
|
1678
|
+
],
|
|
1679
|
+
"stateMutability": "view"
|
|
1680
|
+
},
|
|
1681
|
+
{
|
|
1682
|
+
"type": "function",
|
|
1683
|
+
"name": "keyBytes",
|
|
1684
|
+
"inputs": [
|
|
1685
|
+
{
|
|
1686
|
+
"name": "owner",
|
|
1687
|
+
"type": "address",
|
|
1688
|
+
"internalType": "address"
|
|
1689
|
+
},
|
|
1690
|
+
{
|
|
1691
|
+
"name": "index",
|
|
1692
|
+
"type": "uint256",
|
|
1693
|
+
"internalType": "uint256"
|
|
1694
|
+
}
|
|
1695
|
+
],
|
|
1696
|
+
"outputs": [
|
|
1697
|
+
{
|
|
1698
|
+
"name": "key",
|
|
1699
|
+
"type": "bytes",
|
|
1700
|
+
"internalType": "bytes"
|
|
1701
|
+
}
|
|
1702
|
+
],
|
|
1703
|
+
"stateMutability": "view"
|
|
1704
|
+
},
|
|
1705
|
+
{
|
|
1706
|
+
"type": "function",
|
|
1707
|
+
"name": "keyStatus",
|
|
1708
|
+
"inputs": [
|
|
1709
|
+
{
|
|
1710
|
+
"name": "owner",
|
|
1711
|
+
"type": "address",
|
|
1712
|
+
"internalType": "address"
|
|
1713
|
+
},
|
|
1714
|
+
{
|
|
1715
|
+
"name": "fingerprint",
|
|
1716
|
+
"type": "bytes",
|
|
1717
|
+
"internalType": "bytes"
|
|
1718
|
+
}
|
|
1719
|
+
],
|
|
1720
|
+
"outputs": [
|
|
1721
|
+
{
|
|
1722
|
+
"name": "",
|
|
1723
|
+
"type": "string",
|
|
1724
|
+
"internalType": "string"
|
|
1725
|
+
}
|
|
1726
|
+
],
|
|
1727
|
+
"stateMutability": "view"
|
|
1728
|
+
},
|
|
1729
|
+
{
|
|
1730
|
+
"type": "function",
|
|
1731
|
+
"name": "markCompromisedFor",
|
|
1732
|
+
"inputs": [
|
|
1733
|
+
{
|
|
1734
|
+
"name": "owner",
|
|
1735
|
+
"type": "address",
|
|
1736
|
+
"internalType": "address"
|
|
1737
|
+
},
|
|
1738
|
+
{
|
|
1739
|
+
"name": "index",
|
|
1740
|
+
"type": "uint256",
|
|
1741
|
+
"internalType": "uint256"
|
|
1742
|
+
},
|
|
1743
|
+
{
|
|
1744
|
+
"name": "deadline",
|
|
1745
|
+
"type": "uint256",
|
|
1746
|
+
"internalType": "uint256"
|
|
1747
|
+
},
|
|
1748
|
+
{
|
|
1749
|
+
"name": "permission",
|
|
1750
|
+
"type": "bytes",
|
|
1751
|
+
"internalType": "bytes"
|
|
1752
|
+
}
|
|
1753
|
+
],
|
|
1754
|
+
"outputs": [],
|
|
1755
|
+
"stateMutability": "nonpayable"
|
|
1756
|
+
},
|
|
1757
|
+
{
|
|
1758
|
+
"type": "function",
|
|
1759
|
+
"name": "multicall",
|
|
1760
|
+
"inputs": [
|
|
1761
|
+
{
|
|
1762
|
+
"name": "calls",
|
|
1763
|
+
"type": "bytes[]",
|
|
1764
|
+
"internalType": "bytes[]"
|
|
1765
|
+
}
|
|
1766
|
+
],
|
|
1767
|
+
"outputs": [
|
|
1768
|
+
{
|
|
1769
|
+
"name": "results",
|
|
524
1770
|
"type": "bytes[]",
|
|
525
1771
|
"internalType": "bytes[]"
|
|
526
1772
|
}
|
|
527
1773
|
],
|
|
528
|
-
"stateMutability": "
|
|
1774
|
+
"stateMutability": "nonpayable"
|
|
529
1775
|
},
|
|
530
1776
|
{
|
|
531
1777
|
"type": "function",
|
|
532
|
-
"name": "
|
|
1778
|
+
"name": "nonces",
|
|
533
1779
|
"inputs": [
|
|
534
1780
|
{
|
|
535
|
-
"name": "
|
|
536
|
-
"type": "
|
|
537
|
-
"internalType": "
|
|
1781
|
+
"name": "owner",
|
|
1782
|
+
"type": "address",
|
|
1783
|
+
"internalType": "address"
|
|
538
1784
|
}
|
|
539
1785
|
],
|
|
540
1786
|
"outputs": [
|
|
@@ -548,133 +1794,67 @@ var REGISTRY_ABI = [
|
|
|
548
1794
|
},
|
|
549
1795
|
{
|
|
550
1796
|
"type": "function",
|
|
551
|
-
"name": "
|
|
1797
|
+
"name": "ownersOf",
|
|
552
1798
|
"inputs": [
|
|
553
1799
|
{
|
|
554
|
-
"name": "
|
|
555
|
-
"type": "
|
|
556
|
-
"internalType": "
|
|
557
|
-
},
|
|
558
|
-
{
|
|
559
|
-
"name": "start",
|
|
560
|
-
"type": "uint256",
|
|
561
|
-
"internalType": "uint256"
|
|
562
|
-
},
|
|
563
|
-
{
|
|
564
|
-
"name": "count",
|
|
565
|
-
"type": "uint256",
|
|
566
|
-
"internalType": "uint256"
|
|
1800
|
+
"name": "fingerprint",
|
|
1801
|
+
"type": "bytes",
|
|
1802
|
+
"internalType": "bytes"
|
|
567
1803
|
}
|
|
568
1804
|
],
|
|
569
1805
|
"outputs": [
|
|
570
1806
|
{
|
|
571
|
-
"name": "
|
|
572
|
-
"type": "
|
|
573
|
-
"internalType": "
|
|
1807
|
+
"name": "",
|
|
1808
|
+
"type": "address[]",
|
|
1809
|
+
"internalType": "address[]"
|
|
574
1810
|
}
|
|
575
1811
|
],
|
|
576
1812
|
"stateMutability": "view"
|
|
577
1813
|
},
|
|
578
1814
|
{
|
|
579
1815
|
"type": "function",
|
|
580
|
-
"name": "
|
|
1816
|
+
"name": "ownersOfCount",
|
|
581
1817
|
"inputs": [
|
|
582
1818
|
{
|
|
583
|
-
"name": "
|
|
584
|
-
"type": "
|
|
585
|
-
"internalType": "
|
|
586
|
-
},
|
|
587
|
-
{
|
|
588
|
-
"name": "index",
|
|
589
|
-
"type": "uint256",
|
|
590
|
-
"internalType": "uint256"
|
|
1819
|
+
"name": "fingerprint",
|
|
1820
|
+
"type": "bytes",
|
|
1821
|
+
"internalType": "bytes"
|
|
591
1822
|
}
|
|
592
1823
|
],
|
|
593
1824
|
"outputs": [
|
|
594
1825
|
{
|
|
595
1826
|
"name": "",
|
|
596
|
-
"type": "
|
|
597
|
-
"internalType": "
|
|
598
|
-
"components": [
|
|
599
|
-
{
|
|
600
|
-
"name": "fingerprint",
|
|
601
|
-
"type": "bytes",
|
|
602
|
-
"internalType": "bytes"
|
|
603
|
-
},
|
|
604
|
-
{
|
|
605
|
-
"name": "createdAt",
|
|
606
|
-
"type": "uint64",
|
|
607
|
-
"internalType": "uint64"
|
|
608
|
-
},
|
|
609
|
-
{
|
|
610
|
-
"name": "revokedAt",
|
|
611
|
-
"type": "uint64",
|
|
612
|
-
"internalType": "uint64"
|
|
613
|
-
},
|
|
614
|
-
{
|
|
615
|
-
"name": "messageVersion",
|
|
616
|
-
"type": "uint8",
|
|
617
|
-
"internalType": "uint8"
|
|
618
|
-
},
|
|
619
|
-
{
|
|
620
|
-
"name": "keyPtr",
|
|
621
|
-
"type": "address",
|
|
622
|
-
"internalType": "address"
|
|
623
|
-
},
|
|
624
|
-
{
|
|
625
|
-
"name": "sigPtr",
|
|
626
|
-
"type": "address",
|
|
627
|
-
"internalType": "address"
|
|
628
|
-
}
|
|
629
|
-
]
|
|
1827
|
+
"type": "uint256",
|
|
1828
|
+
"internalType": "uint256"
|
|
630
1829
|
}
|
|
631
1830
|
],
|
|
632
1831
|
"stateMutability": "view"
|
|
633
1832
|
},
|
|
634
1833
|
{
|
|
635
1834
|
"type": "function",
|
|
636
|
-
"name": "
|
|
1835
|
+
"name": "ownersOfRange",
|
|
637
1836
|
"inputs": [
|
|
638
1837
|
{
|
|
639
|
-
"name": "
|
|
640
|
-
"type": "
|
|
641
|
-
"internalType": "
|
|
1838
|
+
"name": "fingerprint",
|
|
1839
|
+
"type": "bytes",
|
|
1840
|
+
"internalType": "bytes"
|
|
642
1841
|
},
|
|
643
1842
|
{
|
|
644
|
-
"name": "
|
|
1843
|
+
"name": "start",
|
|
645
1844
|
"type": "uint256",
|
|
646
1845
|
"internalType": "uint256"
|
|
647
|
-
}
|
|
648
|
-
],
|
|
649
|
-
"outputs": [
|
|
650
|
-
{
|
|
651
|
-
"name": "pgpSignature",
|
|
652
|
-
"type": "bytes",
|
|
653
|
-
"internalType": "bytes"
|
|
654
1846
|
},
|
|
655
1847
|
{
|
|
656
|
-
"name": "
|
|
657
|
-
"type": "
|
|
658
|
-
"internalType": "
|
|
659
|
-
}
|
|
660
|
-
],
|
|
661
|
-
"stateMutability": "view"
|
|
662
|
-
},
|
|
663
|
-
{
|
|
664
|
-
"type": "function",
|
|
665
|
-
"name": "nonces",
|
|
666
|
-
"inputs": [
|
|
667
|
-
{
|
|
668
|
-
"name": "",
|
|
669
|
-
"type": "address",
|
|
670
|
-
"internalType": "address"
|
|
1848
|
+
"name": "count",
|
|
1849
|
+
"type": "uint256",
|
|
1850
|
+
"internalType": "uint256"
|
|
671
1851
|
}
|
|
672
1852
|
],
|
|
673
1853
|
"outputs": [
|
|
674
1854
|
{
|
|
675
|
-
"name": "",
|
|
676
|
-
"type": "
|
|
677
|
-
"internalType": "
|
|
1855
|
+
"name": "out",
|
|
1856
|
+
"type": "address[]",
|
|
1857
|
+
"internalType": "address[]"
|
|
678
1858
|
}
|
|
679
1859
|
],
|
|
680
1860
|
"stateMutability": "view"
|
|
@@ -694,14 +1874,19 @@ var REGISTRY_ABI = [
|
|
|
694
1874
|
"internalType": "bytes"
|
|
695
1875
|
},
|
|
696
1876
|
{
|
|
697
|
-
"name": "
|
|
1877
|
+
"name": "signature",
|
|
698
1878
|
"type": "bytes",
|
|
699
1879
|
"internalType": "bytes"
|
|
700
1880
|
},
|
|
701
1881
|
{
|
|
702
|
-
"name": "
|
|
1882
|
+
"name": "key",
|
|
703
1883
|
"type": "bytes",
|
|
704
1884
|
"internalType": "bytes"
|
|
1885
|
+
},
|
|
1886
|
+
{
|
|
1887
|
+
"name": "keepRecords",
|
|
1888
|
+
"type": "bool",
|
|
1889
|
+
"internalType": "bool"
|
|
705
1890
|
}
|
|
706
1891
|
],
|
|
707
1892
|
"outputs": [
|
|
@@ -733,22 +1918,27 @@ var REGISTRY_ABI = [
|
|
|
733
1918
|
"internalType": "bytes"
|
|
734
1919
|
},
|
|
735
1920
|
{
|
|
736
|
-
"name": "
|
|
1921
|
+
"name": "signature",
|
|
737
1922
|
"type": "bytes",
|
|
738
1923
|
"internalType": "bytes"
|
|
739
1924
|
},
|
|
740
1925
|
{
|
|
741
|
-
"name": "
|
|
1926
|
+
"name": "key",
|
|
742
1927
|
"type": "bytes",
|
|
743
1928
|
"internalType": "bytes"
|
|
744
1929
|
},
|
|
1930
|
+
{
|
|
1931
|
+
"name": "keepRecords",
|
|
1932
|
+
"type": "bool",
|
|
1933
|
+
"internalType": "bool"
|
|
1934
|
+
},
|
|
745
1935
|
{
|
|
746
1936
|
"name": "deadline",
|
|
747
1937
|
"type": "uint256",
|
|
748
1938
|
"internalType": "uint256"
|
|
749
1939
|
},
|
|
750
1940
|
{
|
|
751
|
-
"name": "
|
|
1941
|
+
"name": "permission",
|
|
752
1942
|
"type": "bytes",
|
|
753
1943
|
"internalType": "bytes"
|
|
754
1944
|
}
|
|
@@ -764,7 +1954,7 @@ var REGISTRY_ABI = [
|
|
|
764
1954
|
},
|
|
765
1955
|
{
|
|
766
1956
|
"type": "function",
|
|
767
|
-
"name": "
|
|
1957
|
+
"name": "recordText",
|
|
768
1958
|
"inputs": [
|
|
769
1959
|
{
|
|
770
1960
|
"name": "owner",
|
|
@@ -778,15 +1968,44 @@ var REGISTRY_ABI = [
|
|
|
778
1968
|
},
|
|
779
1969
|
{
|
|
780
1970
|
"name": "kind",
|
|
781
|
-
"type": "
|
|
782
|
-
"internalType": "
|
|
1971
|
+
"type": "string",
|
|
1972
|
+
"internalType": "string"
|
|
783
1973
|
}
|
|
784
1974
|
],
|
|
785
1975
|
"outputs": [
|
|
786
1976
|
{
|
|
787
1977
|
"name": "",
|
|
788
|
-
"type": "
|
|
789
|
-
"internalType": "
|
|
1978
|
+
"type": "string",
|
|
1979
|
+
"internalType": "string"
|
|
1980
|
+
}
|
|
1981
|
+
],
|
|
1982
|
+
"stateMutability": "view"
|
|
1983
|
+
},
|
|
1984
|
+
{
|
|
1985
|
+
"type": "function",
|
|
1986
|
+
"name": "recordsOf",
|
|
1987
|
+
"inputs": [
|
|
1988
|
+
{
|
|
1989
|
+
"name": "owner",
|
|
1990
|
+
"type": "address",
|
|
1991
|
+
"internalType": "address"
|
|
1992
|
+
},
|
|
1993
|
+
{
|
|
1994
|
+
"name": "index",
|
|
1995
|
+
"type": "uint256",
|
|
1996
|
+
"internalType": "uint256"
|
|
1997
|
+
}
|
|
1998
|
+
],
|
|
1999
|
+
"outputs": [
|
|
2000
|
+
{
|
|
2001
|
+
"name": "kinds",
|
|
2002
|
+
"type": "string[]",
|
|
2003
|
+
"internalType": "string[]"
|
|
2004
|
+
},
|
|
2005
|
+
{
|
|
2006
|
+
"name": "values",
|
|
2007
|
+
"type": "string[]",
|
|
2008
|
+
"internalType": "string[]"
|
|
790
2009
|
}
|
|
791
2010
|
],
|
|
792
2011
|
"stateMutability": "view"
|
|
@@ -799,6 +2018,11 @@ var REGISTRY_ABI = [
|
|
|
799
2018
|
"name": "index",
|
|
800
2019
|
"type": "uint256",
|
|
801
2020
|
"internalType": "uint256"
|
|
2021
|
+
},
|
|
2022
|
+
{
|
|
2023
|
+
"name": "reason",
|
|
2024
|
+
"type": "string",
|
|
2025
|
+
"internalType": "string"
|
|
802
2026
|
}
|
|
803
2027
|
],
|
|
804
2028
|
"outputs": [],
|
|
@@ -818,13 +2042,18 @@ var REGISTRY_ABI = [
|
|
|
818
2042
|
"type": "uint256",
|
|
819
2043
|
"internalType": "uint256"
|
|
820
2044
|
},
|
|
2045
|
+
{
|
|
2046
|
+
"name": "reason",
|
|
2047
|
+
"type": "string",
|
|
2048
|
+
"internalType": "string"
|
|
2049
|
+
},
|
|
821
2050
|
{
|
|
822
2051
|
"name": "deadline",
|
|
823
2052
|
"type": "uint256",
|
|
824
2053
|
"internalType": "uint256"
|
|
825
2054
|
},
|
|
826
2055
|
{
|
|
827
|
-
"name": "
|
|
2056
|
+
"name": "permission",
|
|
828
2057
|
"type": "bytes",
|
|
829
2058
|
"internalType": "bytes"
|
|
830
2059
|
}
|
|
@@ -843,13 +2072,13 @@ var REGISTRY_ABI = [
|
|
|
843
2072
|
},
|
|
844
2073
|
{
|
|
845
2074
|
"name": "kind",
|
|
846
|
-
"type": "
|
|
847
|
-
"internalType": "
|
|
2075
|
+
"type": "string",
|
|
2076
|
+
"internalType": "string"
|
|
848
2077
|
},
|
|
849
2078
|
{
|
|
850
2079
|
"name": "value",
|
|
851
|
-
"type": "
|
|
852
|
-
"internalType": "
|
|
2080
|
+
"type": "string",
|
|
2081
|
+
"internalType": "string"
|
|
853
2082
|
}
|
|
854
2083
|
],
|
|
855
2084
|
"outputs": [],
|
|
@@ -871,13 +2100,13 @@ var REGISTRY_ABI = [
|
|
|
871
2100
|
},
|
|
872
2101
|
{
|
|
873
2102
|
"name": "kind",
|
|
874
|
-
"type": "
|
|
875
|
-
"internalType": "
|
|
2103
|
+
"type": "string",
|
|
2104
|
+
"internalType": "string"
|
|
876
2105
|
},
|
|
877
2106
|
{
|
|
878
2107
|
"name": "value",
|
|
879
|
-
"type": "
|
|
880
|
-
"internalType": "
|
|
2108
|
+
"type": "string",
|
|
2109
|
+
"internalType": "string"
|
|
881
2110
|
},
|
|
882
2111
|
{
|
|
883
2112
|
"name": "deadline",
|
|
@@ -885,7 +2114,7 @@ var REGISTRY_ABI = [
|
|
|
885
2114
|
"internalType": "uint256"
|
|
886
2115
|
},
|
|
887
2116
|
{
|
|
888
|
-
"name": "
|
|
2117
|
+
"name": "permission",
|
|
889
2118
|
"type": "bytes",
|
|
890
2119
|
"internalType": "bytes"
|
|
891
2120
|
}
|
|
@@ -893,6 +2122,83 @@ var REGISTRY_ABI = [
|
|
|
893
2122
|
"outputs": [],
|
|
894
2123
|
"stateMutability": "nonpayable"
|
|
895
2124
|
},
|
|
2125
|
+
{
|
|
2126
|
+
"type": "function",
|
|
2127
|
+
"name": "signatureBytes",
|
|
2128
|
+
"inputs": [
|
|
2129
|
+
{
|
|
2130
|
+
"name": "owner",
|
|
2131
|
+
"type": "address",
|
|
2132
|
+
"internalType": "address"
|
|
2133
|
+
},
|
|
2134
|
+
{
|
|
2135
|
+
"name": "index",
|
|
2136
|
+
"type": "uint256",
|
|
2137
|
+
"internalType": "uint256"
|
|
2138
|
+
}
|
|
2139
|
+
],
|
|
2140
|
+
"outputs": [
|
|
2141
|
+
{
|
|
2142
|
+
"name": "signature",
|
|
2143
|
+
"type": "bytes",
|
|
2144
|
+
"internalType": "bytes"
|
|
2145
|
+
}
|
|
2146
|
+
],
|
|
2147
|
+
"stateMutability": "view"
|
|
2148
|
+
},
|
|
2149
|
+
{
|
|
2150
|
+
"type": "function",
|
|
2151
|
+
"name": "statementFor",
|
|
2152
|
+
"inputs": [
|
|
2153
|
+
{
|
|
2154
|
+
"name": "owner",
|
|
2155
|
+
"type": "address",
|
|
2156
|
+
"internalType": "address"
|
|
2157
|
+
}
|
|
2158
|
+
],
|
|
2159
|
+
"outputs": [
|
|
2160
|
+
{
|
|
2161
|
+
"name": "",
|
|
2162
|
+
"type": "string",
|
|
2163
|
+
"internalType": "string"
|
|
2164
|
+
}
|
|
2165
|
+
],
|
|
2166
|
+
"stateMutability": "pure"
|
|
2167
|
+
},
|
|
2168
|
+
{
|
|
2169
|
+
"type": "function",
|
|
2170
|
+
"name": "summary",
|
|
2171
|
+
"inputs": [
|
|
2172
|
+
{
|
|
2173
|
+
"name": "owner",
|
|
2174
|
+
"type": "address",
|
|
2175
|
+
"internalType": "address"
|
|
2176
|
+
}
|
|
2177
|
+
],
|
|
2178
|
+
"outputs": [
|
|
2179
|
+
{
|
|
2180
|
+
"name": "total",
|
|
2181
|
+
"type": "uint256",
|
|
2182
|
+
"internalType": "uint256"
|
|
2183
|
+
},
|
|
2184
|
+
{
|
|
2185
|
+
"name": "active",
|
|
2186
|
+
"type": "uint256",
|
|
2187
|
+
"internalType": "uint256"
|
|
2188
|
+
},
|
|
2189
|
+
{
|
|
2190
|
+
"name": "hasCurrent",
|
|
2191
|
+
"type": "bool",
|
|
2192
|
+
"internalType": "bool"
|
|
2193
|
+
},
|
|
2194
|
+
{
|
|
2195
|
+
"name": "currentIndex",
|
|
2196
|
+
"type": "uint256",
|
|
2197
|
+
"internalType": "uint256"
|
|
2198
|
+
}
|
|
2199
|
+
],
|
|
2200
|
+
"stateMutability": "view"
|
|
2201
|
+
},
|
|
896
2202
|
{
|
|
897
2203
|
"type": "function",
|
|
898
2204
|
"name": "updateKey",
|
|
@@ -903,7 +2209,7 @@ var REGISTRY_ABI = [
|
|
|
903
2209
|
"internalType": "uint256"
|
|
904
2210
|
},
|
|
905
2211
|
{
|
|
906
|
-
"name": "
|
|
2212
|
+
"name": "key",
|
|
907
2213
|
"type": "bytes",
|
|
908
2214
|
"internalType": "bytes"
|
|
909
2215
|
}
|
|
@@ -926,7 +2232,7 @@ var REGISTRY_ABI = [
|
|
|
926
2232
|
"internalType": "uint256"
|
|
927
2233
|
},
|
|
928
2234
|
{
|
|
929
|
-
"name": "
|
|
2235
|
+
"name": "key",
|
|
930
2236
|
"type": "bytes",
|
|
931
2237
|
"internalType": "bytes"
|
|
932
2238
|
},
|
|
@@ -936,7 +2242,7 @@ var REGISTRY_ABI = [
|
|
|
936
2242
|
"internalType": "uint256"
|
|
937
2243
|
},
|
|
938
2244
|
{
|
|
939
|
-
"name": "
|
|
2245
|
+
"name": "permission",
|
|
940
2246
|
"type": "bytes",
|
|
941
2247
|
"internalType": "bytes"
|
|
942
2248
|
}
|
|
@@ -973,22 +2279,16 @@ var REGISTRY_ABI = [
|
|
|
973
2279
|
"internalType": "bytes"
|
|
974
2280
|
},
|
|
975
2281
|
{
|
|
976
|
-
"name": "
|
|
977
|
-
"type": "uint8",
|
|
978
|
-
"indexed": false,
|
|
979
|
-
"internalType": "uint8"
|
|
980
|
-
},
|
|
981
|
-
{
|
|
982
|
-
"name": "keyPtr",
|
|
2282
|
+
"name": "payload",
|
|
983
2283
|
"type": "address",
|
|
984
2284
|
"indexed": false,
|
|
985
2285
|
"internalType": "address"
|
|
986
2286
|
},
|
|
987
2287
|
{
|
|
988
|
-
"name": "
|
|
989
|
-
"type": "
|
|
2288
|
+
"name": "messageVersion",
|
|
2289
|
+
"type": "uint8",
|
|
990
2290
|
"indexed": false,
|
|
991
|
-
"internalType": "
|
|
2291
|
+
"internalType": "uint8"
|
|
992
2292
|
},
|
|
993
2293
|
{
|
|
994
2294
|
"name": "submitter",
|
|
@@ -1022,13 +2322,13 @@ var REGISTRY_ABI = [
|
|
|
1022
2322
|
"internalType": "uint256"
|
|
1023
2323
|
},
|
|
1024
2324
|
{
|
|
1025
|
-
"name": "
|
|
2325
|
+
"name": "oldPayload",
|
|
1026
2326
|
"type": "address",
|
|
1027
2327
|
"indexed": false,
|
|
1028
2328
|
"internalType": "address"
|
|
1029
2329
|
},
|
|
1030
2330
|
{
|
|
1031
|
-
"name": "
|
|
2331
|
+
"name": "newPayload",
|
|
1032
2332
|
"type": "address",
|
|
1033
2333
|
"indexed": false,
|
|
1034
2334
|
"internalType": "address"
|
|
@@ -1078,11 +2378,23 @@ var REGISTRY_ABI = [
|
|
|
1078
2378
|
"internalType": "uint256"
|
|
1079
2379
|
},
|
|
1080
2380
|
{
|
|
1081
|
-
"name": "
|
|
2381
|
+
"name": "kindHash",
|
|
1082
2382
|
"type": "bytes32",
|
|
1083
2383
|
"indexed": true,
|
|
1084
2384
|
"internalType": "bytes32"
|
|
1085
2385
|
},
|
|
2386
|
+
{
|
|
2387
|
+
"name": "kind",
|
|
2388
|
+
"type": "string",
|
|
2389
|
+
"indexed": false,
|
|
2390
|
+
"internalType": "string"
|
|
2391
|
+
},
|
|
2392
|
+
{
|
|
2393
|
+
"name": "value",
|
|
2394
|
+
"type": "string",
|
|
2395
|
+
"indexed": false,
|
|
2396
|
+
"internalType": "string"
|
|
2397
|
+
},
|
|
1086
2398
|
{
|
|
1087
2399
|
"name": "submitter",
|
|
1088
2400
|
"type": "address",
|
|
@@ -1092,6 +2404,31 @@ var REGISTRY_ABI = [
|
|
|
1092
2404
|
],
|
|
1093
2405
|
"anonymous": false
|
|
1094
2406
|
},
|
|
2407
|
+
{
|
|
2408
|
+
"type": "event",
|
|
2409
|
+
"name": "RecordsMoved",
|
|
2410
|
+
"inputs": [
|
|
2411
|
+
{
|
|
2412
|
+
"name": "owner",
|
|
2413
|
+
"type": "address",
|
|
2414
|
+
"indexed": true,
|
|
2415
|
+
"internalType": "address"
|
|
2416
|
+
},
|
|
2417
|
+
{
|
|
2418
|
+
"name": "fromIndex",
|
|
2419
|
+
"type": "uint256",
|
|
2420
|
+
"indexed": true,
|
|
2421
|
+
"internalType": "uint256"
|
|
2422
|
+
},
|
|
2423
|
+
{
|
|
2424
|
+
"name": "toIndex",
|
|
2425
|
+
"type": "uint256",
|
|
2426
|
+
"indexed": true,
|
|
2427
|
+
"internalType": "uint256"
|
|
2428
|
+
}
|
|
2429
|
+
],
|
|
2430
|
+
"anonymous": false
|
|
2431
|
+
},
|
|
1095
2432
|
{
|
|
1096
2433
|
"type": "event",
|
|
1097
2434
|
"name": "Revoked",
|
|
@@ -1114,6 +2451,18 @@ var REGISTRY_ABI = [
|
|
|
1114
2451
|
"indexed": true,
|
|
1115
2452
|
"internalType": "uint256"
|
|
1116
2453
|
},
|
|
2454
|
+
{
|
|
2455
|
+
"name": "reason",
|
|
2456
|
+
"type": "string",
|
|
2457
|
+
"indexed": false,
|
|
2458
|
+
"internalType": "string"
|
|
2459
|
+
},
|
|
2460
|
+
{
|
|
2461
|
+
"name": "replacedBy",
|
|
2462
|
+
"type": "uint256",
|
|
2463
|
+
"indexed": false,
|
|
2464
|
+
"internalType": "uint256"
|
|
2465
|
+
},
|
|
1117
2466
|
{
|
|
1118
2467
|
"name": "submitter",
|
|
1119
2468
|
"type": "address",
|
|
@@ -1126,831 +2475,629 @@ var REGISTRY_ABI = [
|
|
|
1126
2475
|
{
|
|
1127
2476
|
"type": "error",
|
|
1128
2477
|
"name": "AlreadyRevoked",
|
|
1129
|
-
"inputs": [
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
{
|
|
1137
|
-
"type": "error",
|
|
1138
|
-
"name": "DeploymentFailed",
|
|
1139
|
-
"inputs": []
|
|
2478
|
+
"inputs": [
|
|
2479
|
+
{
|
|
2480
|
+
"name": "index",
|
|
2481
|
+
"type": "uint256",
|
|
2482
|
+
"internalType": "uint256"
|
|
2483
|
+
}
|
|
2484
|
+
]
|
|
1140
2485
|
},
|
|
1141
2486
|
{
|
|
1142
2487
|
"type": "error",
|
|
1143
|
-
"name": "
|
|
2488
|
+
"name": "BadArmorChecksum",
|
|
1144
2489
|
"inputs": []
|
|
1145
2490
|
},
|
|
1146
2491
|
{
|
|
1147
2492
|
"type": "error",
|
|
1148
|
-
"name": "
|
|
2493
|
+
"name": "BadBase64",
|
|
1149
2494
|
"inputs": []
|
|
1150
2495
|
},
|
|
1151
2496
|
{
|
|
1152
2497
|
"type": "error",
|
|
1153
|
-
"name": "
|
|
1154
|
-
"inputs": [
|
|
2498
|
+
"name": "ClaimActive",
|
|
2499
|
+
"inputs": [
|
|
2500
|
+
{
|
|
2501
|
+
"name": "index",
|
|
2502
|
+
"type": "uint256",
|
|
2503
|
+
"internalType": "uint256"
|
|
2504
|
+
}
|
|
2505
|
+
]
|
|
1155
2506
|
},
|
|
1156
2507
|
{
|
|
1157
2508
|
"type": "error",
|
|
1158
|
-
"name": "
|
|
2509
|
+
"name": "DeploymentFailed",
|
|
1159
2510
|
"inputs": []
|
|
1160
2511
|
},
|
|
1161
2512
|
{
|
|
1162
2513
|
"type": "error",
|
|
1163
|
-
"name": "
|
|
1164
|
-
"inputs": [
|
|
2514
|
+
"name": "DuplicateActiveFingerprint",
|
|
2515
|
+
"inputs": [
|
|
2516
|
+
{
|
|
2517
|
+
"name": "fingerprint",
|
|
2518
|
+
"type": "bytes",
|
|
2519
|
+
"internalType": "bytes"
|
|
2520
|
+
}
|
|
2521
|
+
]
|
|
1165
2522
|
},
|
|
1166
2523
|
{
|
|
1167
2524
|
"type": "error",
|
|
1168
|
-
"name": "
|
|
2525
|
+
"name": "EmptyKey",
|
|
1169
2526
|
"inputs": []
|
|
1170
2527
|
},
|
|
1171
2528
|
{
|
|
1172
2529
|
"type": "error",
|
|
1173
|
-
"name": "
|
|
2530
|
+
"name": "EmptySignature",
|
|
1174
2531
|
"inputs": []
|
|
1175
2532
|
},
|
|
1176
2533
|
{
|
|
1177
2534
|
"type": "error",
|
|
1178
|
-
"name": "
|
|
1179
|
-
"inputs": [
|
|
2535
|
+
"name": "IndexOutOfBounds",
|
|
2536
|
+
"inputs": [
|
|
2537
|
+
{
|
|
2538
|
+
"name": "index",
|
|
2539
|
+
"type": "uint256",
|
|
2540
|
+
"internalType": "uint256"
|
|
2541
|
+
},
|
|
2542
|
+
{
|
|
2543
|
+
"name": "count",
|
|
2544
|
+
"type": "uint256",
|
|
2545
|
+
"internalType": "uint256"
|
|
2546
|
+
}
|
|
2547
|
+
]
|
|
1180
2548
|
},
|
|
1181
2549
|
{
|
|
1182
2550
|
"type": "error",
|
|
1183
|
-
"name": "
|
|
1184
|
-
"inputs": [
|
|
2551
|
+
"name": "InvalidFingerprint",
|
|
2552
|
+
"inputs": [
|
|
2553
|
+
{
|
|
2554
|
+
"name": "fingerprint",
|
|
2555
|
+
"type": "bytes",
|
|
2556
|
+
"internalType": "bytes"
|
|
2557
|
+
}
|
|
2558
|
+
]
|
|
1185
2559
|
},
|
|
1186
2560
|
{
|
|
1187
2561
|
"type": "error",
|
|
1188
|
-
"name": "
|
|
1189
|
-
"inputs": [
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
import { mainnet, sepolia, foundry } from "viem/chains";
|
|
1195
|
-
var REGISTRY_ADDRESS = "0x9302E02e2869e129aC8516fE5eFFd51EA3082c09";
|
|
1196
|
-
var NETWORKS = {
|
|
1197
|
-
mainnet: {
|
|
1198
|
-
chainId: 1,
|
|
1199
|
-
address: REGISTRY_ADDRESS,
|
|
1200
|
-
deployBlock: 25962908n,
|
|
1201
|
-
// 2026-09-12, tx 0xda4c3a19cae4e71ffb02559a048403f664d5a7967c19d42158c39600ec63bad8
|
|
1202
|
-
explorerUrl: "https://etherscan.io",
|
|
1203
|
-
defaultRpcUrl: "https://ethereum.publicnode.com"
|
|
1204
|
-
// same service as ethereum-rpc.publicnode.com; this hostname resolves on more networks
|
|
1205
|
-
},
|
|
1206
|
-
sepolia: {
|
|
1207
|
-
chainId: 11155111,
|
|
1208
|
-
address: REGISTRY_ADDRESS,
|
|
1209
|
-
deployBlock: 11683667n,
|
|
1210
|
-
// 2026-09-11, tx 0x3e40e8f5b9fbf82a4b8943561bcc9b964b2987de10640ac8ff3a1b4ef0725322
|
|
1211
|
-
explorerUrl: "https://sepolia.etherscan.io",
|
|
1212
|
-
defaultRpcUrl: "https://ethereum-sepolia.publicnode.com"
|
|
1213
|
-
},
|
|
1214
|
-
/** A local anvil instance (`anvil`, chain id 31337). Deploy with pgp-registry's Deploy script. */
|
|
1215
|
-
local: {
|
|
1216
|
-
chainId: 31337,
|
|
1217
|
-
address: REGISTRY_ADDRESS,
|
|
1218
|
-
deployBlock: 0n,
|
|
1219
|
-
explorerUrl: "",
|
|
1220
|
-
defaultRpcUrl: "http://127.0.0.1:8545"
|
|
1221
|
-
}
|
|
1222
|
-
};
|
|
1223
|
-
function isNetworkName(value) {
|
|
1224
|
-
return value === "mainnet" || value === "sepolia" || value === "local";
|
|
1225
|
-
}
|
|
1226
|
-
function getRegistry(network = "mainnet", addressOverride) {
|
|
1227
|
-
const r = NETWORKS[network];
|
|
1228
|
-
if (!r) throw new Error(`Unknown network: ${network}`);
|
|
1229
|
-
if (addressOverride && /^0x[0-9a-fA-F]{40}$/.test(addressOverride)) {
|
|
1230
|
-
return { ...r, address: addressOverride };
|
|
1231
|
-
}
|
|
1232
|
-
return r;
|
|
1233
|
-
}
|
|
1234
|
-
function chainFor(network = "mainnet") {
|
|
1235
|
-
if (network === "sepolia") return sepolia;
|
|
1236
|
-
if (network === "local") return foundry;
|
|
1237
|
-
return mainnet;
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
// src/core/identityError.ts
|
|
1241
|
-
function needsRpcProbe(s) {
|
|
1242
|
-
return s.ensEmpty || s.ensFailed || s.claimsFailed;
|
|
1243
|
-
}
|
|
1244
|
-
function identityErrorKind(s) {
|
|
1245
|
-
if (!needsRpcProbe(s) || s.rpcAnswered === void 0) return null;
|
|
1246
|
-
if (!s.rpcAnswered) return "rpc";
|
|
1247
|
-
if (s.ensEmpty && !s.ensFailed) return "not-found";
|
|
1248
|
-
return "read";
|
|
1249
|
-
}
|
|
1250
|
-
var IDENTITY_ERROR_TEXT = {
|
|
1251
|
-
rpc: "Couldn't reach the RPC, so nothing here is known yet.",
|
|
1252
|
-
"not-found": "No address for this name.",
|
|
1253
|
-
read: "Couldn't read the registry."
|
|
1254
|
-
};
|
|
1255
|
-
|
|
1256
|
-
// src/core/fingerprint.ts
|
|
1257
|
-
import { keccak256 } from "viem";
|
|
1258
|
-
var FINGERPRINT_HEX = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
|
|
1259
|
-
function normalizeFingerprint(input) {
|
|
1260
|
-
const hex = input.replace(/^0x/i, "").replace(/\s+/g, "").toLowerCase();
|
|
1261
|
-
return FINGERPRINT_HEX.test(hex) ? hex : null;
|
|
1262
|
-
}
|
|
1263
|
-
function fingerprintToBytes(fingerprint) {
|
|
1264
|
-
const hex = normalizeFingerprint(fingerprint);
|
|
1265
|
-
if (!hex) throw new Error(`Invalid PGP fingerprint: ${fingerprint}`);
|
|
1266
|
-
return `0x${hex}`;
|
|
1267
|
-
}
|
|
1268
|
-
function bytesToFingerprint(bytes) {
|
|
1269
|
-
return bytes.replace(/^0x/i, "").toLowerCase();
|
|
1270
|
-
}
|
|
1271
|
-
function fingerprintHash(fingerprint) {
|
|
1272
|
-
return keccak256(fingerprintToBytes(fingerprint));
|
|
1273
|
-
}
|
|
1274
|
-
function keyIdOf(fingerprint) {
|
|
1275
|
-
const hex = normalizeFingerprint(fingerprint);
|
|
1276
|
-
if (!hex) throw new Error(`Invalid PGP fingerprint: ${fingerprint}`);
|
|
1277
|
-
return `0x${keyIdHex(hex)}`;
|
|
1278
|
-
}
|
|
1279
|
-
function keyIdHex(normalizedFingerprint) {
|
|
1280
|
-
return normalizedFingerprint.length === 64 ? normalizedFingerprint.slice(0, 16) : normalizedFingerprint.slice(-16);
|
|
1281
|
-
}
|
|
1282
|
-
function keyIdToBytes(keyId) {
|
|
1283
|
-
const hex = keyId.replace(/^0x/i, "").replace(/\s+/g, "").toLowerCase();
|
|
1284
|
-
return /^[0-9a-f]{16}$/.test(hex) ? `0x${hex}` : null;
|
|
1285
|
-
}
|
|
1286
|
-
|
|
1287
|
-
// src/core/pgp.ts
|
|
1288
|
-
function pgpConfig(openpgp) {
|
|
1289
|
-
const rejectCurves = new Set([...openpgp.config.rejectCurves ?? []].filter((c) => c !== "secp256k1"));
|
|
1290
|
-
return { ...openpgp.config, rejectCurves };
|
|
1291
|
-
}
|
|
1292
|
-
function algorithmName(keyOrSubkey) {
|
|
1293
|
-
try {
|
|
1294
|
-
const info = keyOrSubkey.getAlgorithmInfo();
|
|
1295
|
-
const curve = (info.curve || "").toLowerCase();
|
|
1296
|
-
if (curve.startsWith("ed25519") || info.algorithm === "ed25519" || info.algorithm === "eddsaLegacy") return "Ed25519";
|
|
1297
|
-
if (curve.startsWith("curve25519") || info.algorithm === "x25519") return "Cv25519";
|
|
1298
|
-
if (curve.startsWith("ed448")) return "Ed448";
|
|
1299
|
-
if (curve.startsWith("curve448") || info.algorithm === "x448") return "X448";
|
|
1300
|
-
if (curve.startsWith("nistp") || curve.startsWith("p")) return `NIST P-${curve.replace(/\D/g, "")}`;
|
|
1301
|
-
if (curve.startsWith("secp")) return curve;
|
|
1302
|
-
if (curve.startsWith("brainpool")) return curve;
|
|
1303
|
-
if (info.algorithm.startsWith("rsa")) return info.bits ? `RSA ${info.bits}` : "RSA";
|
|
1304
|
-
if (info.algorithm.startsWith("dsa")) return info.bits ? `DSA ${info.bits}` : "DSA";
|
|
1305
|
-
if (info.algorithm.startsWith("elgamal")) return info.bits ? `ElGamal ${info.bits}` : "ElGamal";
|
|
1306
|
-
return info.curve || info.algorithm;
|
|
1307
|
-
} catch {
|
|
1308
|
-
return String(keyOrSubkey.keyPacket?.algorithm ?? "unknown");
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
async function parsePgpKey(armoredKey) {
|
|
1312
|
-
try {
|
|
1313
|
-
const openpgp = await import("openpgp");
|
|
1314
|
-
const { readKey } = openpgp;
|
|
1315
|
-
const config = pgpConfig(openpgp);
|
|
1316
|
-
const key = await readKey({ armoredKey });
|
|
1317
|
-
const fingerprint = key.getFingerprint().toUpperCase();
|
|
1318
|
-
const algorithm = algorithmName(key);
|
|
1319
|
-
const created = key.keyPacket.created?.toISOString() ?? null;
|
|
1320
|
-
const expiration = await key.getExpirationTime();
|
|
1321
|
-
const expires = expiration && expiration !== Infinity ? new Date(expiration).toISOString() : null;
|
|
1322
|
-
const userIDs = [];
|
|
1323
|
-
const notations = [];
|
|
1324
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1325
|
-
for (const user of key.users) {
|
|
1326
|
-
const certs = user.selfCertifications;
|
|
1327
|
-
if (!certs || certs.length === 0) continue;
|
|
1328
|
-
let userVerified = false;
|
|
1329
|
-
for (const cert of certs) {
|
|
1330
|
-
try {
|
|
1331
|
-
await cert.verify(
|
|
1332
|
-
key.keyPacket,
|
|
1333
|
-
cert.signatureType,
|
|
1334
|
-
{ userID: user.userID, key: key.keyPacket },
|
|
1335
|
-
void 0,
|
|
1336
|
-
// date: now
|
|
1337
|
-
void 0,
|
|
1338
|
-
// detached
|
|
1339
|
-
config
|
|
1340
|
-
);
|
|
1341
|
-
} catch {
|
|
1342
|
-
continue;
|
|
1343
|
-
}
|
|
1344
|
-
userVerified = true;
|
|
1345
|
-
if (cert.rawNotations) {
|
|
1346
|
-
for (const n of cert.rawNotations) {
|
|
1347
|
-
const name = typeof n.name === "string" ? n.name : new TextDecoder().decode(n.name);
|
|
1348
|
-
const value = n.value instanceof Uint8Array ? new TextDecoder().decode(n.value) : typeof n.value === "string" ? n.value : null;
|
|
1349
|
-
if (value) {
|
|
1350
|
-
if (!seen.has(value)) {
|
|
1351
|
-
seen.add(value);
|
|
1352
|
-
notations.push({ name, value });
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
2562
|
+
"name": "InvalidFingerprintLength",
|
|
2563
|
+
"inputs": [
|
|
2564
|
+
{
|
|
2565
|
+
"name": "length",
|
|
2566
|
+
"type": "uint256",
|
|
2567
|
+
"internalType": "uint256"
|
|
1357
2568
|
}
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
2569
|
+
]
|
|
2570
|
+
},
|
|
2571
|
+
{
|
|
2572
|
+
"type": "error",
|
|
2573
|
+
"name": "InvalidKindName",
|
|
2574
|
+
"inputs": [
|
|
2575
|
+
{
|
|
2576
|
+
"name": "kind",
|
|
2577
|
+
"type": "string",
|
|
2578
|
+
"internalType": "string"
|
|
1361
2579
|
}
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
for (const sig of msg.signature.packets) {
|
|
1383
|
-
if (!publicKey.getKeys(sig.issuerKeyID).length) continue;
|
|
1384
|
-
const signingKey = await publicKey.getSigningKey(sig.issuerKeyID, now, void 0, config);
|
|
1385
|
-
const literal = new LiteralDataPacket();
|
|
1386
|
-
literal.setText(msg.text ?? message.getText().replace(/\r?\n/g, "\r\n"));
|
|
1387
|
-
await sig.verify(signingKey.keyPacket, sig.signatureType, literal, now, true, config);
|
|
1388
|
-
return { verified: true, text: message.getText() };
|
|
1389
|
-
}
|
|
1390
|
-
return { verified: false, reason: "Message is not signed by this key", text: message.getText() };
|
|
1391
|
-
} catch (err) {
|
|
1392
|
-
return { verified: false, reason: err instanceof Error ? err.message : "Verification failed", text: "" };
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
async function verifyAttestation({
|
|
1396
|
-
pgpPublicKey,
|
|
1397
|
-
pgpSignature,
|
|
1398
|
-
fingerprint,
|
|
1399
|
-
ethAddress
|
|
1400
|
-
}) {
|
|
1401
|
-
try {
|
|
1402
|
-
if (!pgpPublicKey || !pgpSignature) {
|
|
1403
|
-
return { verified: false, reason: "Missing PGP data" };
|
|
1404
|
-
}
|
|
1405
|
-
const openpgp = await import("openpgp");
|
|
1406
|
-
const { readKey } = openpgp;
|
|
1407
|
-
const publicKey = await readKey({ armoredKey: pgpPublicKey });
|
|
1408
|
-
const keyFingerprint = publicKey.getFingerprint().toUpperCase();
|
|
1409
|
-
if (keyFingerprint !== fingerprint.toUpperCase()) {
|
|
1410
|
-
return { verified: false, reason: "Key fingerprint mismatch" };
|
|
1411
|
-
}
|
|
1412
|
-
const v = await verifyClearsigned({ armoredKey: pgpPublicKey, clearsigned: pgpSignature });
|
|
1413
|
-
if (!v.verified) return { verified: false, reason: v.reason };
|
|
1414
|
-
const signedText = v.text;
|
|
1415
|
-
if (!signedText.toLowerCase().includes(ethAddress.toLowerCase())) {
|
|
1416
|
-
return { verified: false, reason: "Signed message does not contain ETH address" };
|
|
1417
|
-
}
|
|
1418
|
-
return { verified: true };
|
|
1419
|
-
} catch {
|
|
1420
|
-
return { verified: false, reason: "Signature verification failed" };
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
var EMAIL_UID = /@/;
|
|
1424
|
-
async function stripEmailUserIDs(armoredKey) {
|
|
1425
|
-
try {
|
|
1426
|
-
const { readKey } = await import("openpgp");
|
|
1427
|
-
const key = await readKey({ armoredKey });
|
|
1428
|
-
const kept = [];
|
|
1429
|
-
const removed = [];
|
|
1430
|
-
const users = key.users.filter((u) => {
|
|
1431
|
-
const uid = u.userID?.userID;
|
|
1432
|
-
if (!uid) return false;
|
|
1433
|
-
if (EMAIL_UID.test(uid)) {
|
|
1434
|
-
removed.push(uid);
|
|
1435
|
-
return false;
|
|
2580
|
+
]
|
|
2581
|
+
},
|
|
2582
|
+
{
|
|
2583
|
+
"type": "error",
|
|
2584
|
+
"name": "InvalidPermission",
|
|
2585
|
+
"inputs": []
|
|
2586
|
+
},
|
|
2587
|
+
{
|
|
2588
|
+
"type": "error",
|
|
2589
|
+
"name": "InvalidPointer",
|
|
2590
|
+
"inputs": []
|
|
2591
|
+
},
|
|
2592
|
+
{
|
|
2593
|
+
"type": "error",
|
|
2594
|
+
"name": "KeyCompromised",
|
|
2595
|
+
"inputs": [
|
|
2596
|
+
{
|
|
2597
|
+
"name": "fingerprint",
|
|
2598
|
+
"type": "bytes",
|
|
2599
|
+
"internalType": "bytes"
|
|
1436
2600
|
}
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
});
|
|
1440
|
-
if (users.length === 0) return null;
|
|
1441
|
-
key.users = users;
|
|
1442
|
-
return { armored: key.armor(), kept, removed };
|
|
1443
|
-
} catch {
|
|
1444
|
-
return null;
|
|
1445
|
-
}
|
|
1446
|
-
}
|
|
1447
|
-
async function hasEmailUserID(armoredKey) {
|
|
1448
|
-
try {
|
|
1449
|
-
const { readKey } = await import("openpgp");
|
|
1450
|
-
const key = await readKey({ armoredKey });
|
|
1451
|
-
return key.users.some((u) => EMAIL_UID.test(u.userID?.userID ?? ""));
|
|
1452
|
-
} catch {
|
|
1453
|
-
return false;
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
// src/core/efp.ts
|
|
1458
|
-
var EFP_API = "https://api.ethfollow.xyz/api/v1";
|
|
1459
|
-
async function fetchEFPGraph(address) {
|
|
1460
|
-
try {
|
|
1461
|
-
const [statsResp, listsResp] = await Promise.all([
|
|
1462
|
-
fetch(`${EFP_API}/users/${address}/stats`),
|
|
1463
|
-
fetch(`${EFP_API}/users/${address}/lists`)
|
|
1464
|
-
]);
|
|
1465
|
-
if (!statsResp.ok && !listsResp.ok) return null;
|
|
1466
|
-
const statsData = statsResp.ok ? await statsResp.json() : {};
|
|
1467
|
-
const listsData = listsResp.ok ? await listsResp.json() : {};
|
|
1468
|
-
const followers = parseInt(statsData.followers_count) || 0;
|
|
1469
|
-
const listId = listsData.primary_list;
|
|
1470
|
-
let following = 0;
|
|
1471
|
-
let top8 = [];
|
|
1472
|
-
if (listId) {
|
|
1473
|
-
const [followingResp, top8Resp] = await Promise.all([
|
|
1474
|
-
fetch(`${EFP_API}/lists/${listId}/following?limit=100`),
|
|
1475
|
-
fetch(`${EFP_API}/lists/${listId}/following?limit=8&tags=top8`)
|
|
1476
|
-
]);
|
|
1477
|
-
const followingData = followingResp.ok ? await followingResp.json() : { following: [] };
|
|
1478
|
-
const top8Data = top8Resp.ok ? await top8Resp.json() : { following: [] };
|
|
1479
|
-
following = (followingData.following || []).length;
|
|
1480
|
-
top8 = (top8Data.following || []).map((f) => f.data);
|
|
1481
|
-
}
|
|
1482
|
-
return { followers, following, top8, hasEfp: !!listId || followers > 0 };
|
|
1483
|
-
} catch {
|
|
1484
|
-
return null;
|
|
1485
|
-
}
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
// src/core/proofs.ts
|
|
1489
|
-
var PROVIDERS = [
|
|
2601
|
+
]
|
|
2602
|
+
},
|
|
1490
2603
|
{
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
2604
|
+
"type": "error",
|
|
2605
|
+
"name": "KeyStillActive",
|
|
2606
|
+
"inputs": [
|
|
2607
|
+
{
|
|
2608
|
+
"name": "fingerprint",
|
|
2609
|
+
"type": "bytes",
|
|
2610
|
+
"internalType": "bytes"
|
|
2611
|
+
}
|
|
2612
|
+
]
|
|
1495
2613
|
},
|
|
1496
2614
|
{
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
2615
|
+
"type": "error",
|
|
2616
|
+
"name": "KeyTooLarge",
|
|
2617
|
+
"inputs": [
|
|
2618
|
+
{
|
|
2619
|
+
"name": "size",
|
|
2620
|
+
"type": "uint256",
|
|
2621
|
+
"internalType": "uint256"
|
|
2622
|
+
},
|
|
2623
|
+
{
|
|
2624
|
+
"name": "max",
|
|
2625
|
+
"type": "uint256",
|
|
2626
|
+
"internalType": "uint256"
|
|
2627
|
+
}
|
|
2628
|
+
]
|
|
1503
2629
|
},
|
|
1504
2630
|
{
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
2631
|
+
"type": "error",
|
|
2632
|
+
"name": "NotAKey",
|
|
2633
|
+
"inputs": [
|
|
2634
|
+
{
|
|
2635
|
+
"name": "firstByte",
|
|
2636
|
+
"type": "bytes1",
|
|
2637
|
+
"internalType": "bytes1"
|
|
2638
|
+
}
|
|
2639
|
+
]
|
|
1511
2640
|
},
|
|
1512
2641
|
{
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
2642
|
+
"type": "error",
|
|
2643
|
+
"name": "NotASignature",
|
|
2644
|
+
"inputs": [
|
|
2645
|
+
{
|
|
2646
|
+
"name": "firstByte",
|
|
2647
|
+
"type": "bytes1",
|
|
2648
|
+
"internalType": "bytes1"
|
|
2649
|
+
}
|
|
2650
|
+
]
|
|
1517
2651
|
},
|
|
1518
2652
|
{
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
parse: (m) => ({ user: m[1], repo: m[2] })
|
|
2653
|
+
"type": "error",
|
|
2654
|
+
"name": "NotArmored",
|
|
2655
|
+
"inputs": []
|
|
1523
2656
|
},
|
|
1524
2657
|
{
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
}
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
}
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
}
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
2658
|
+
"type": "error",
|
|
2659
|
+
"name": "PayloadTooLarge",
|
|
2660
|
+
"inputs": [
|
|
2661
|
+
{
|
|
2662
|
+
"name": "size",
|
|
2663
|
+
"type": "uint256",
|
|
2664
|
+
"internalType": "uint256"
|
|
2665
|
+
},
|
|
2666
|
+
{
|
|
2667
|
+
"name": "max",
|
|
2668
|
+
"type": "uint256",
|
|
2669
|
+
"internalType": "uint256"
|
|
2670
|
+
}
|
|
2671
|
+
]
|
|
2672
|
+
},
|
|
2673
|
+
{
|
|
2674
|
+
"type": "error",
|
|
2675
|
+
"name": "PermissionExpired",
|
|
2676
|
+
"inputs": [
|
|
2677
|
+
{
|
|
2678
|
+
"name": "deadline",
|
|
2679
|
+
"type": "uint256",
|
|
2680
|
+
"internalType": "uint256"
|
|
2681
|
+
}
|
|
2682
|
+
]
|
|
2683
|
+
},
|
|
2684
|
+
{
|
|
2685
|
+
"type": "error",
|
|
2686
|
+
"name": "RecordTooLarge",
|
|
2687
|
+
"inputs": [
|
|
2688
|
+
{
|
|
2689
|
+
"name": "size",
|
|
2690
|
+
"type": "uint256",
|
|
2691
|
+
"internalType": "uint256"
|
|
2692
|
+
},
|
|
2693
|
+
{
|
|
2694
|
+
"name": "max",
|
|
2695
|
+
"type": "uint256",
|
|
2696
|
+
"internalType": "uint256"
|
|
2697
|
+
}
|
|
2698
|
+
]
|
|
2699
|
+
},
|
|
2700
|
+
{
|
|
2701
|
+
"type": "error",
|
|
2702
|
+
"name": "SignatureTooLarge",
|
|
2703
|
+
"inputs": [
|
|
2704
|
+
{
|
|
2705
|
+
"name": "size",
|
|
2706
|
+
"type": "uint256",
|
|
2707
|
+
"internalType": "uint256"
|
|
2708
|
+
},
|
|
2709
|
+
{
|
|
2710
|
+
"name": "max",
|
|
2711
|
+
"type": "uint256",
|
|
2712
|
+
"internalType": "uint256"
|
|
2713
|
+
}
|
|
2714
|
+
]
|
|
2715
|
+
},
|
|
2716
|
+
{
|
|
2717
|
+
"type": "error",
|
|
2718
|
+
"name": "SupersededIsSetByReattest",
|
|
2719
|
+
"inputs": []
|
|
2720
|
+
},
|
|
2721
|
+
{
|
|
2722
|
+
"type": "error",
|
|
2723
|
+
"name": "TooManyClaims",
|
|
2724
|
+
"inputs": []
|
|
2725
|
+
},
|
|
2726
|
+
{
|
|
2727
|
+
"type": "error",
|
|
2728
|
+
"name": "UnknownRevokeReason",
|
|
2729
|
+
"inputs": [
|
|
2730
|
+
{
|
|
2731
|
+
"name": "reason",
|
|
2732
|
+
"type": "string",
|
|
2733
|
+
"internalType": "string"
|
|
1586
2734
|
}
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
2735
|
+
]
|
|
2736
|
+
},
|
|
2737
|
+
{
|
|
2738
|
+
"type": "error",
|
|
2739
|
+
"name": "UnsupportedHeader",
|
|
2740
|
+
"inputs": []
|
|
1591
2741
|
}
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
2742
|
+
];
|
|
2743
|
+
|
|
2744
|
+
// src/core/contract.ts
|
|
2745
|
+
var REGISTRY_ADDRESS = "0xFa6956c11163517249f8A67F5560a4406B519451";
|
|
2746
|
+
var NETWORKS = {
|
|
2747
|
+
mainnet: {
|
|
2748
|
+
chainId: 1,
|
|
2749
|
+
address: REGISTRY_ADDRESS,
|
|
2750
|
+
explorerUrl: "https://etherscan.io",
|
|
2751
|
+
defaultRpcUrl: "https://ethereum.publicnode.com"
|
|
2752
|
+
// resolves on more networks than ethereum-rpc.publicnode.com
|
|
2753
|
+
},
|
|
2754
|
+
sepolia: {
|
|
2755
|
+
chainId: 11155111,
|
|
2756
|
+
address: REGISTRY_ADDRESS,
|
|
2757
|
+
explorerUrl: "https://sepolia.etherscan.io",
|
|
2758
|
+
defaultRpcUrl: "https://ethereum-sepolia.publicnode.com"
|
|
2759
|
+
},
|
|
2760
|
+
/** A local anvil instance (`anvil`, chain id 31337). Deploy with pgp-registry's Deploy script. */
|
|
2761
|
+
local: {
|
|
2762
|
+
chainId: 31337,
|
|
2763
|
+
address: REGISTRY_ADDRESS,
|
|
2764
|
+
explorerUrl: "",
|
|
2765
|
+
defaultRpcUrl: "http://127.0.0.1:8545"
|
|
1609
2766
|
}
|
|
2767
|
+
};
|
|
2768
|
+
function isNetworkName(value) {
|
|
2769
|
+
return value === "mainnet" || value === "sepolia" || value === "local";
|
|
1610
2770
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
);
|
|
1617
|
-
if (!resp.ok) return { verified: false, reason: `DNS query returned ${resp.status}` };
|
|
1618
|
-
const data = await resp.json();
|
|
1619
|
-
for (const answer of data.Answer || []) {
|
|
1620
|
-
if (answer.type !== 16) continue;
|
|
1621
|
-
if (answer.data && containsFingerprint(answer.data, fingerprint)) {
|
|
1622
|
-
return { verified: true };
|
|
1623
|
-
}
|
|
1624
|
-
}
|
|
1625
|
-
return { verified: false, reason: "Fingerprint token not found in TXT records" };
|
|
1626
|
-
} catch (err) {
|
|
1627
|
-
return { verified: false, reason: `DNS fetch failed: ${err.message}` };
|
|
2771
|
+
function getRegistry(network = "mainnet", addressOverride) {
|
|
2772
|
+
const r = NETWORKS[network];
|
|
2773
|
+
if (!r) throw new Error(`Unknown network: ${network}`);
|
|
2774
|
+
if (addressOverride && /^0x[0-9a-fA-F]{40}$/.test(addressOverride)) {
|
|
2775
|
+
return { ...r, address: addressOverride };
|
|
1628
2776
|
}
|
|
2777
|
+
return r;
|
|
1629
2778
|
}
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
if (opts.neynarApiKey) return { base: NEYNAR_HUB, headers: { "x-api-key": opts.neynarApiKey } };
|
|
1635
|
-
return { base: FARCASTER_HUB, headers: {} };
|
|
2779
|
+
function chainFor(network = "mainnet") {
|
|
2780
|
+
if (network === "sepolia") return sepolia;
|
|
2781
|
+
if (network === "local") return foundry;
|
|
2782
|
+
return mainnet;
|
|
1636
2783
|
}
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
2784
|
+
|
|
2785
|
+
// src/core/claims.ts
|
|
2786
|
+
var CLAIM_LIMIT = 50;
|
|
2787
|
+
async function readClaims(client, owner, { registry = REGISTRY_ADDRESS, limit = CLAIM_LIMIT } = {}) {
|
|
2788
|
+
const read = (functionName, args) => client.readContract({ address: registry, abi: REGISTRY_ABI, functionName, args });
|
|
2789
|
+
const rows = await read("claimsOf", [owner]);
|
|
2790
|
+
const first = Math.max(0, rows.length - limit);
|
|
2791
|
+
return Promise.all(rows.map(async (row, index) => {
|
|
2792
|
+
const revokedAt = Number(row.revokedAt);
|
|
2793
|
+
const claim = {
|
|
2794
|
+
index,
|
|
2795
|
+
fingerprint: bytesToFingerprint(row.fingerprint),
|
|
2796
|
+
createdAt: Number(row.createdAt),
|
|
2797
|
+
revoked: revokedAt !== 0,
|
|
2798
|
+
revokedAt: revokedAt || null,
|
|
2799
|
+
state: row.state,
|
|
2800
|
+
replacedBy: row.state === "replaced" ? Number(row.replacedBy) : null,
|
|
2801
|
+
revokeReason: row.revokeReason,
|
|
2802
|
+
messageVersion: Number(row.messageVersion),
|
|
2803
|
+
pgpPublicKey: null,
|
|
2804
|
+
pgpSignature: null,
|
|
2805
|
+
verification: null
|
|
2806
|
+
};
|
|
2807
|
+
if (index < first) return claim;
|
|
2808
|
+
const bytes = (fn) => read(fn, [owner, BigInt(index)]).catch(() => null);
|
|
2809
|
+
const [keyHex, sigHex] = await Promise.all([bytes("keyBytes"), bytes("signatureBytes")]);
|
|
2810
|
+
claim.pgpPublicKey = keyHex ? await payloadText(keyHex, "key") : null;
|
|
2811
|
+
claim.pgpSignature = sigHex ? await payloadText(sigHex, "signature") : null;
|
|
2812
|
+
claim.verification = await verifyAttestation({
|
|
2813
|
+
pgpPublicKey: claim.pgpPublicKey,
|
|
2814
|
+
pgpSignature: claim.pgpSignature,
|
|
2815
|
+
fingerprint: claim.fingerprint,
|
|
2816
|
+
ethAddress: owner
|
|
2817
|
+
});
|
|
2818
|
+
return claim;
|
|
2819
|
+
}));
|
|
1667
2820
|
}
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
if (data.description && containsFingerprint(data.description, fingerprint)) {
|
|
1676
|
-
return { verified: true };
|
|
1677
|
-
}
|
|
1678
|
-
return { verified: false, reason: "Fingerprint token not found in repo description" };
|
|
1679
|
-
} catch (err) {
|
|
1680
|
-
return { verified: false, reason: `Codeberg fetch failed: ${err.message}` };
|
|
1681
|
-
}
|
|
2821
|
+
function keyStanding(claims) {
|
|
2822
|
+
const active = claims.filter((c) => !c.revoked);
|
|
2823
|
+
const verified = active.filter((c) => c.verification?.verified);
|
|
2824
|
+
if (verified.length) return { kind: "verified", claim: verified[verified.length - 1] };
|
|
2825
|
+
if (active.length) return { kind: "not-counted", claim: active[active.length - 1] };
|
|
2826
|
+
if (claims.length) return { kind: "inactive", claim: claims[claims.length - 1] };
|
|
2827
|
+
return { kind: "none", claim: null };
|
|
1682
2828
|
}
|
|
1683
|
-
async function
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
}
|
|
1699
|
-
}
|
|
1700
|
-
if (data.note) {
|
|
1701
|
-
const text = data.note.replace(/<[^>]*>/g, "");
|
|
1702
|
-
if (containsFingerprintUrl(text, fingerprint) || containsFingerprintUrl(text, keyId)) {
|
|
1703
|
-
return { verified: true };
|
|
1704
|
-
}
|
|
2829
|
+
async function findOwners(client, key, { registry = REGISTRY_ADDRESS } = {}) {
|
|
2830
|
+
const read = (functionName, args) => client.readContract({ address: registry, abi: REGISTRY_ABI, functionName, args });
|
|
2831
|
+
let fingerprints;
|
|
2832
|
+
if ("keyId" in key) {
|
|
2833
|
+
const keyId = keyIdToBytes(key.keyId);
|
|
2834
|
+
if (!keyId) return [];
|
|
2835
|
+
fingerprints = (await read("fingerprintsForKeyId", [keyId])).map(bytesToFingerprint);
|
|
2836
|
+
} else {
|
|
2837
|
+
const fp = normalizeFingerprint(key.fingerprint);
|
|
2838
|
+
if (!fp) return [];
|
|
2839
|
+
fingerprints = [fp];
|
|
2840
|
+
}
|
|
2841
|
+
const found = [];
|
|
2842
|
+
for (const fingerprint of fingerprints) {
|
|
2843
|
+
for (const owner of await read("ownersOf", [fingerprintToBytes(fingerprint)])) {
|
|
2844
|
+
if (!found.some((f) => f.owner.toLowerCase() === owner.toLowerCase() && f.fingerprint === fingerprint)) found.push({ owner, fingerprint });
|
|
1705
2845
|
}
|
|
1706
|
-
return { verified: false, reason: "Fingerprint not found in profile fields or bio" };
|
|
1707
|
-
} catch (err) {
|
|
1708
|
-
return { verified: false, reason: `Mastodon fetch failed: ${err.message}` };
|
|
1709
2846
|
}
|
|
1710
|
-
|
|
1711
|
-
var verifiers = {
|
|
1712
|
-
github: verifyGitHub,
|
|
1713
|
-
dns: verifyDNS,
|
|
1714
|
-
farcaster: verifyFarcaster,
|
|
1715
|
-
codeberg: verifyCodeberg,
|
|
1716
|
-
mastodon: verifyMastodon
|
|
1717
|
-
};
|
|
1718
|
-
async function verifyProof(proof, fingerprint, opts) {
|
|
1719
|
-
const fn = verifiers[proof.provider];
|
|
1720
|
-
if (!fn) return { verified: false, reason: "Unknown provider" };
|
|
1721
|
-
return fn(proof, fingerprint, typeof opts === "string" ? { neynarApiKey: opts } : opts ?? {});
|
|
2847
|
+
return found;
|
|
1722
2848
|
}
|
|
1723
2849
|
|
|
1724
|
-
// src/core/
|
|
1725
|
-
var
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
if (
|
|
1737
|
-
|
|
1738
|
-
if (
|
|
1739
|
-
return
|
|
1740
|
-
}
|
|
1741
|
-
function avatarFallbacks(url) {
|
|
1742
|
-
if (!url || !url.startsWith(IPFS_GATEWAYS[0])) return [];
|
|
1743
|
-
const path = url.slice(IPFS_GATEWAYS[0].length);
|
|
1744
|
-
return IPFS_GATEWAYS.slice(1).map((g) => g + path);
|
|
2850
|
+
// src/core/claimStatus.ts
|
|
2851
|
+
var CLAIM_CHECK_LABEL = {
|
|
2852
|
+
verified: "pgp verified",
|
|
2853
|
+
expired: "key expired",
|
|
2854
|
+
"signing-key-expired": "signing key expired",
|
|
2855
|
+
revoked: "key revoked",
|
|
2856
|
+
compromised: "key compromised",
|
|
2857
|
+
"signing-key-revoked": "signing key revoked",
|
|
2858
|
+
unsupported: "not supported",
|
|
2859
|
+
"bad-signature": "doesn't verify"
|
|
2860
|
+
};
|
|
2861
|
+
function formatClaimDate(isoOrSeconds) {
|
|
2862
|
+
if (isoOrSeconds === null || isoOrSeconds === void 0) return "an unknown date";
|
|
2863
|
+
const d = typeof isoOrSeconds === "number" ? new Date(isoOrSeconds * 1e3) : new Date(isoOrSeconds);
|
|
2864
|
+
if (Number.isNaN(d.getTime())) return "an unknown date";
|
|
2865
|
+
return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", timeZone: "UTC" });
|
|
1745
2866
|
}
|
|
1746
|
-
function
|
|
1747
|
-
|
|
1748
|
-
|
|
2867
|
+
function shortFingerprint(fpr) {
|
|
2868
|
+
if (!fpr) return "unknown";
|
|
2869
|
+
const f = fpr.toUpperCase();
|
|
2870
|
+
return `${f.slice(0, 4)} ${f.slice(4, 8)} \u2026`;
|
|
1749
2871
|
}
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
];
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
2872
|
+
function claimCheckText(v, formatDate = formatClaimDate) {
|
|
2873
|
+
const kind = v.kind ?? (v.verified ? "verified" : "bad-signature");
|
|
2874
|
+
const at = formatDate(v.at);
|
|
2875
|
+
const t = (sentence, fix = null) => ({ kind, label: CLAIM_CHECK_LABEL[kind], sentence, fix });
|
|
2876
|
+
switch (kind) {
|
|
2877
|
+
case "verified":
|
|
2878
|
+
return t("The key signed a line naming this address, and the signature checks out.");
|
|
2879
|
+
case "expired":
|
|
2880
|
+
return t(
|
|
2881
|
+
`The key on this claim expired on ${at}, so the claim no longer counts.`,
|
|
2882
|
+
"Extend the key, then Update key. No new signature needed."
|
|
2883
|
+
);
|
|
2884
|
+
case "signing-key-expired":
|
|
2885
|
+
return t(
|
|
2886
|
+
`The subkey that signed this claim (${shortFingerprint(v.signingKey)}) expired on ${at}.`,
|
|
2887
|
+
"Extend that subkey, then Update key."
|
|
2888
|
+
);
|
|
2889
|
+
case "revoked":
|
|
2890
|
+
return t(
|
|
2891
|
+
`Its owner revoked this PGP key on ${at}${v.revocationReason ? ` (reason: ${v.revocationReason})` : ""}. The claim no longer counts.`,
|
|
2892
|
+
"Revoke this claim and attest your new key."
|
|
2893
|
+
);
|
|
2894
|
+
case "compromised":
|
|
2895
|
+
return t(
|
|
2896
|
+
`Its owner revoked this PGP key on ${at} as compromised. Don't trust anything it signed after that date.`,
|
|
2897
|
+
"Revoke this claim and attest a new key."
|
|
2898
|
+
);
|
|
2899
|
+
case "signing-key-revoked":
|
|
2900
|
+
return t(
|
|
2901
|
+
`The subkey that signed this claim was revoked on ${at}.`,
|
|
2902
|
+
"Replace the claim with a signature from a current key."
|
|
2903
|
+
);
|
|
2904
|
+
case "unsupported":
|
|
2905
|
+
return t(`This key uses an algorithm Thurin doesn't check${v.algorithm ? ` (${v.algorithm})` : ""}. The claim is on-chain, but no lookup will vouch for it.`);
|
|
2906
|
+
case "bad-signature":
|
|
2907
|
+
default:
|
|
2908
|
+
return t("The signature stored with this claim doesn't match its key, so nothing from this claim is shown.");
|
|
1773
2909
|
}
|
|
1774
|
-
return avatarUrl(meta?.image ?? meta?.image_url);
|
|
1775
2910
|
}
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
}
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
2911
|
+
function keyProblemText(v, formatDate = formatClaimDate) {
|
|
2912
|
+
const at = formatDate(v.at);
|
|
2913
|
+
const t = (kind, sentence, fix) => ({ kind, label: CLAIM_CHECK_LABEL[kind], sentence, fix });
|
|
2914
|
+
switch (v.kind) {
|
|
2915
|
+
case "expired":
|
|
2916
|
+
return t("expired", `This key expired on ${at}, so a claim with it wouldn't count.`, "Extend it (gpg --quick-set-expire), then export it again.");
|
|
2917
|
+
case "signing-key-expired":
|
|
2918
|
+
return t("signing-key-expired", `The subkey that signed (${shortFingerprint(v.signingKey)}) expired on ${at}.`, "Extend that subkey, or sign with a current one.");
|
|
2919
|
+
case "revoked":
|
|
2920
|
+
return t("revoked", `This key was revoked on ${at}${v.revocationReason ? ` (reason: ${v.revocationReason})` : ""}.`, "Use a current key.");
|
|
2921
|
+
case "compromised":
|
|
2922
|
+
return t("compromised", `This key was revoked as compromised on ${at}.`, "Use a new key.");
|
|
2923
|
+
case "signing-key-revoked":
|
|
2924
|
+
return t("signing-key-revoked", `The subkey that signed was revoked on ${at}.`, "Sign with a current subkey.");
|
|
2925
|
+
case "unsupported":
|
|
2926
|
+
return t("unsupported", `This key uses an algorithm Thurin doesn't check${v.algorithm ? ` (${v.algorithm})` : ""}, so no lookup would vouch for the claim.`, "Use an Ed25519 or RSA key.");
|
|
2927
|
+
default:
|
|
2928
|
+
return null;
|
|
2929
|
+
}
|
|
1794
2930
|
}
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
const normalized = normalize(name);
|
|
1801
|
-
return {
|
|
1802
|
-
abi: ENS_TEXT_RESOLVER_ABI,
|
|
1803
|
-
functionName: "setText",
|
|
1804
|
-
args: [namehash(normalized), ENS_HINT_KEY, ensHintValue(fingerprint)],
|
|
1805
|
-
name: normalized
|
|
1806
|
-
};
|
|
2931
|
+
function expiresSoon(v, now = Date.now(), withinDays = 30) {
|
|
2932
|
+
if (!v?.verified || !v.expiresAt) return null;
|
|
2933
|
+
const ms = new Date(v.expiresAt).getTime() - now;
|
|
2934
|
+
if (!Number.isFinite(ms) || ms < 0 || ms > withinDays * 864e5) return null;
|
|
2935
|
+
return { days: Math.floor(ms / 864e5), at: v.expiresAt };
|
|
1807
2936
|
}
|
|
1808
|
-
|
|
1809
|
-
const
|
|
1810
|
-
return
|
|
2937
|
+
function expiresSoonText(soon, formatDate = formatClaimDate) {
|
|
2938
|
+
const when = soon.days === 0 ? "today" : soon.days === 1 ? "in 1 day" : `in ${soon.days} days`;
|
|
2939
|
+
return `Key expires ${when} (${formatDate(soon.at)}).`;
|
|
1811
2940
|
}
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
2941
|
+
function claimFates(claims) {
|
|
2942
|
+
const out = /* @__PURE__ */ new Map();
|
|
2943
|
+
for (const c of claims) {
|
|
2944
|
+
if (c.state === "active" || !c.revokedAt) out.set(c.index, { state: "active" });
|
|
2945
|
+
else if (c.state === "replaced" && c.replacedBy !== null) out.set(c.index, { state: "replaced", at: c.revokedAt, by: c.replacedBy, ...c.revokeReason === "compromised" ? { compromised: true } : {} });
|
|
2946
|
+
else out.set(c.index, { state: "revoked", at: c.revokedAt, ...c.revokeReason ? { reason: c.revokeReason } : {} });
|
|
2947
|
+
}
|
|
2948
|
+
return out;
|
|
1819
2949
|
}
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
{ name: "pgpSignature", type: "bytes" },
|
|
1825
|
-
{ name: "pgpPublicKey", type: "bytes" },
|
|
1826
|
-
{ name: "nonce", type: "uint256" },
|
|
1827
|
-
{ name: "deadline", type: "uint256" }
|
|
1828
|
-
],
|
|
1829
|
-
Reattest: [
|
|
1830
|
-
{ name: "owner", type: "address" },
|
|
1831
|
-
{ name: "revokeIndex", type: "uint256" },
|
|
1832
|
-
{ name: "fingerprint", type: "bytes" },
|
|
1833
|
-
{ name: "pgpSignature", type: "bytes" },
|
|
1834
|
-
{ name: "pgpPublicKey", type: "bytes" },
|
|
1835
|
-
{ name: "nonce", type: "uint256" },
|
|
1836
|
-
{ name: "deadline", type: "uint256" }
|
|
1837
|
-
],
|
|
1838
|
-
UpdateKey: [
|
|
1839
|
-
{ name: "owner", type: "address" },
|
|
1840
|
-
{ name: "index", type: "uint256" },
|
|
1841
|
-
{ name: "pgpPublicKey", type: "bytes" },
|
|
1842
|
-
{ name: "nonce", type: "uint256" },
|
|
1843
|
-
{ name: "deadline", type: "uint256" }
|
|
1844
|
-
],
|
|
1845
|
-
Revoke: [
|
|
1846
|
-
{ name: "owner", type: "address" },
|
|
1847
|
-
{ name: "index", type: "uint256" },
|
|
1848
|
-
{ name: "nonce", type: "uint256" },
|
|
1849
|
-
{ name: "deadline", type: "uint256" }
|
|
1850
|
-
],
|
|
1851
|
-
SetRecord: [
|
|
1852
|
-
{ name: "owner", type: "address" },
|
|
1853
|
-
{ name: "index", type: "uint256" },
|
|
1854
|
-
{ name: "kind", type: "bytes32" },
|
|
1855
|
-
{ name: "value", type: "bytes" },
|
|
1856
|
-
{ name: "nonce", type: "uint256" },
|
|
1857
|
-
{ name: "deadline", type: "uint256" }
|
|
1858
|
-
]
|
|
1859
|
-
};
|
|
1860
|
-
function attestTypedData(chainId, registry, a) {
|
|
1861
|
-
return {
|
|
1862
|
-
domain: registryDomain(chainId, registry),
|
|
1863
|
-
types: { Attest: AUTHORIZATION_TYPES.Attest },
|
|
1864
|
-
primaryType: "Attest",
|
|
1865
|
-
message: {
|
|
1866
|
-
owner: a.owner,
|
|
1867
|
-
fingerprint: fingerprintToBytes(a.fingerprint),
|
|
1868
|
-
pgpSignature: stringToHex(a.pgpSignature),
|
|
1869
|
-
pgpPublicKey: stringToHex(a.pgpPublicKey),
|
|
1870
|
-
nonce: a.nonce,
|
|
1871
|
-
deadline: a.deadline
|
|
1872
|
-
}
|
|
1873
|
-
};
|
|
2950
|
+
function claimFateText(fate, formatDate = (s) => formatClaimDate(s)) {
|
|
2951
|
+
if (fate.state === "revoked") return `Revoked by its owner on ${formatDate(fate.at)}${fate.reason ? ` (${fate.reason})` : ""}.`;
|
|
2952
|
+
if (fate.state === "replaced") return `Replaced by claim #${fate.by} on ${formatDate(fate.at)}.${fate.compromised ? " Its key was marked compromised." : ""}`;
|
|
2953
|
+
return null;
|
|
1874
2954
|
}
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
2955
|
+
|
|
2956
|
+
// src/core/encrypt.ts
|
|
2957
|
+
async function encryptionKeyFor(claims, { now = Date.now(), recentDays = 7 } = {}) {
|
|
2958
|
+
const standing = keyStanding(claims);
|
|
2959
|
+
if (standing.kind === "none" || standing.kind === "inactive") return { ok: false, reason: "no-claim", claim: standing.claim };
|
|
2960
|
+
if (standing.kind === "not-counted" || !standing.claim.pgpPublicKey) return { ok: false, reason: "unverified", claim: standing.claim };
|
|
2961
|
+
const claim = standing.claim;
|
|
2962
|
+
try {
|
|
2963
|
+
const openpgp = await import("openpgp");
|
|
2964
|
+
const config = pgpConfig(openpgp);
|
|
2965
|
+
const key = await readKeyAny(openpgp, claim.pgpPublicKey);
|
|
2966
|
+
const date = new Date(now);
|
|
2967
|
+
const enc = await key.getEncryptionKey(void 0, date, void 0, config).catch(() => null);
|
|
2968
|
+
if (!enc) {
|
|
2969
|
+
let lastExpiry = null;
|
|
2970
|
+
for (const sk of key.subkeys) {
|
|
2971
|
+
const flags = newestSignature(sk.bindingSignatures)?.keyFlags?.[0] ?? 0;
|
|
2972
|
+
if (!(flags & 12) || await sk.isRevoked(void 0, void 0, date, config).catch(() => false)) continue;
|
|
2973
|
+
const exp2 = await sk.getExpirationTime(date, config).catch(() => null);
|
|
2974
|
+
if (typeof exp2 === "number" || exp2 instanceof Date) {
|
|
2975
|
+
const t = new Date(exp2).getTime();
|
|
2976
|
+
if (t <= now && (lastExpiry === null || t > lastExpiry)) lastExpiry = t;
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
return lastExpiry !== null ? { ok: false, reason: "encryption-subkey-expired", claim, expired: new Date(lastExpiry).toISOString() } : { ok: false, reason: "no-encryption-subkey", claim };
|
|
2980
|
+
}
|
|
2981
|
+
const exp = await enc.getExpirationTime(date, config).catch(() => null);
|
|
2982
|
+
return {
|
|
2983
|
+
ok: true,
|
|
2984
|
+
claim,
|
|
2985
|
+
key: claim.pgpPublicKey,
|
|
2986
|
+
subkey: {
|
|
2987
|
+
fingerprint: enc.getFingerprint().toUpperCase(),
|
|
2988
|
+
algorithm: algorithmName(enc),
|
|
2989
|
+
expires: exp && exp !== Infinity ? new Date(exp).toISOString() : null
|
|
2990
|
+
},
|
|
2991
|
+
addedAt: claim.createdAt,
|
|
2992
|
+
changedRecently: now / 1e3 - claim.createdAt < recentDays * 86400
|
|
2993
|
+
};
|
|
2994
|
+
} catch {
|
|
2995
|
+
return { ok: false, reason: "unverified", claim };
|
|
2996
|
+
}
|
|
1883
2997
|
}
|
|
1884
|
-
function
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
2998
|
+
function encryptRefusalText(r, formatDate = formatClaimDate) {
|
|
2999
|
+
switch (r.reason) {
|
|
3000
|
+
case "no-claim":
|
|
3001
|
+
return "No claim counts for this identity, so there is no key to encrypt to.";
|
|
3002
|
+
case "unverified":
|
|
3003
|
+
return "Its newest claim doesn't verify, so its key can't be trusted with a message.";
|
|
3004
|
+
case "no-encryption-subkey":
|
|
3005
|
+
return "Its key has no encryption subkey, so it can sign but not receive.";
|
|
3006
|
+
case "encryption-subkey-expired":
|
|
3007
|
+
return `Its encryption subkey expired on ${formatDate(r.expired)}.`;
|
|
3008
|
+
}
|
|
1891
3009
|
}
|
|
1892
|
-
function
|
|
1893
|
-
return
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
message: { owner: a.owner, index: a.index, nonce: a.nonce, deadline: a.deadline }
|
|
1898
|
-
};
|
|
3010
|
+
function keyChangedText(k, now = Date.now()) {
|
|
3011
|
+
if (!k.changedRecently) return null;
|
|
3012
|
+
const days = Math.floor((now / 1e3 - k.addedAt) / 86400);
|
|
3013
|
+
const when = days <= 0 ? "today" : days === 1 ? "yesterday" : `${days} days ago`;
|
|
3014
|
+
return `This key was added ${when}. If you were expecting a different one, check with them another way.`;
|
|
1899
3015
|
}
|
|
1900
|
-
function
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
};
|
|
3016
|
+
async function encryptTo(key, data, { filename, armor = typeof data === "string", hideRecipient = true, date = /* @__PURE__ */ new Date() } = {}) {
|
|
3017
|
+
const openpgp = await import("openpgp");
|
|
3018
|
+
const config = pgpConfig(openpgp);
|
|
3019
|
+
const encryptionKeys = await readKeyAny(openpgp, key);
|
|
3020
|
+
const message = typeof data === "string" ? await openpgp.createMessage({ text: data, date }) : await openpgp.createMessage({ binary: data, filename, format: "binary", date });
|
|
3021
|
+
const opts = { message, encryptionKeys, config, wildcard: hideRecipient, date };
|
|
3022
|
+
return armor ? await openpgp.encrypt({ ...opts, format: "armored" }) : await openpgp.encrypt({ ...opts, format: "binary" });
|
|
1907
3023
|
}
|
|
1908
|
-
|
|
1909
|
-
|
|
3024
|
+
|
|
3025
|
+
// src/core/contractErrors.ts
|
|
3026
|
+
var CONTRACT_ERROR_TEXT = {
|
|
3027
|
+
AlreadyRevoked: "That claim has already ended, or is already marked compromised.",
|
|
3028
|
+
BadArmorChecksum: "The armor's checksum doesn't match its data: the paste was changed or cut short.",
|
|
3029
|
+
BadBase64: "The armored data isn't valid base64.",
|
|
3030
|
+
ClaimActive: 'That claim is still active: revoke it with the reason "compromised" instead.',
|
|
3031
|
+
DeploymentFailed: "The key and signature couldn't be stored: together they're over the contract's size limit.",
|
|
3032
|
+
DuplicateActiveFingerprint: "This address already has an active claim for this key: update it or replace it instead.",
|
|
3033
|
+
EmptyKey: "No key was given.",
|
|
3034
|
+
EmptySignature: "No signature was given.",
|
|
3035
|
+
IndexOutOfBounds: "This address has no claim at that index.",
|
|
3036
|
+
InvalidFingerprint: "That 32-byte fingerprint ends in 12 zero bytes, which no real v6 key has.",
|
|
3037
|
+
InvalidFingerprintLength: "The fingerprint isn't 20 bytes (v4 key) or 32 bytes (v6 key).",
|
|
3038
|
+
InvalidKindName: "The record name is empty, longer than 31 bytes, or uses something other than a-z, 0-9, '-', and '.'.",
|
|
3039
|
+
InvalidPermission: "The permission isn't the owner's signature over exactly this change and their current nonce: it was already used, cancelled, or superseded by a newer one.",
|
|
3040
|
+
InvalidPointer: "There is no stored data at that address.",
|
|
3041
|
+
KeyCompromised: "This address marked the key compromised: it can never claim it again.",
|
|
3042
|
+
KeyStillActive: 'This address still has an active claim for the key: revoke that claim as "compromised" instead.',
|
|
3043
|
+
KeyTooLarge: "The key is over 16,384 bytes: export it without photos or old signatures.",
|
|
3044
|
+
NotAKey: "The key doesn't start with an OpenPGP public-key packet: give gpg's export of the public key.",
|
|
3045
|
+
NotASignature: "The signature is neither an OpenPGP signature nor a clearsigned message.",
|
|
3046
|
+
NotArmored: "The paste has no -----BEGIN PGP and -----END PGP lines.",
|
|
3047
|
+
PayloadTooLarge: "The signature and key together are over 24,000 bytes.",
|
|
3048
|
+
PermissionExpired: "The permission is past its deadline: ask the owner for a new one.",
|
|
3049
|
+
RecordTooLarge: "The record value is over 1,024 bytes.",
|
|
3050
|
+
SignatureTooLarge: "The signature is over 8,192 bytes.",
|
|
3051
|
+
SupersededIsSetByReattest: '"superseded" is set only by replacing a claim: pick another reason.',
|
|
3052
|
+
TooManyClaims: "This address has reached the limit of 65,535 claims.",
|
|
3053
|
+
UnknownRevokeReason: 'The revoke reason must be empty, "compromised", "retired", or "other".',
|
|
3054
|
+
UnsupportedHeader: "Armor header lines (like Comment:) can't be told from the data, as when line breaks were lost: remove them."
|
|
3055
|
+
};
|
|
3056
|
+
function contractErrorName(err) {
|
|
3057
|
+
for (let e = err, depth = 0; e && depth < 8; e = e.cause, depth++) {
|
|
3058
|
+
const name = e.data?.errorName ?? e.errorName;
|
|
3059
|
+
if (typeof name === "string" && name) return name;
|
|
3060
|
+
}
|
|
3061
|
+
return null;
|
|
1910
3062
|
}
|
|
1911
|
-
function
|
|
1912
|
-
|
|
3063
|
+
function contractErrorText(err) {
|
|
3064
|
+
const name = contractErrorName(err);
|
|
3065
|
+
return name ? CONTRACT_ERROR_TEXT[name] ?? `The registry refused it (${name}).` : null;
|
|
1913
3066
|
}
|
|
1914
3067
|
|
|
1915
3068
|
// src/core/records.ts
|
|
1916
|
-
import { hexToString, stringToHex as stringToHex2 } from "viem";
|
|
1917
3069
|
var MAX_RECORD_BYTES = 1024;
|
|
3070
|
+
var MAX_KIND_BYTES = 31;
|
|
1918
3071
|
function kindName(input) {
|
|
1919
3072
|
return input.includes(".") ? input : `thurin.${input}`;
|
|
1920
3073
|
}
|
|
3074
|
+
function checkKindName(input) {
|
|
3075
|
+
if (!/^[a-z0-9.-]+$/.test(input)) throw new Error(`Record name "${input}": use a-z, 0-9, "-" and "." only`);
|
|
3076
|
+
const name = kindName(input);
|
|
3077
|
+
if (name.length > MAX_KIND_BYTES) throw new Error(`Record name "${name}" is ${name.length} bytes; the registry allows ${MAX_KIND_BYTES}`);
|
|
3078
|
+
return name;
|
|
3079
|
+
}
|
|
3080
|
+
function checkRecordValue(value) {
|
|
3081
|
+
const bytes = new TextEncoder().encode(value).length;
|
|
3082
|
+
if (bytes > MAX_RECORD_BYTES) throw new Error(`Record is ${bytes} bytes; the registry accepts up to ${MAX_RECORD_BYTES}`);
|
|
3083
|
+
return value;
|
|
3084
|
+
}
|
|
1921
3085
|
var KNOWN_KINDS = [
|
|
1922
3086
|
"thurin.railgun",
|
|
1923
3087
|
"thurin.security",
|
|
1924
3088
|
"thurin.successor",
|
|
1925
3089
|
"thurin.affiliation",
|
|
1926
3090
|
"thurin.canary",
|
|
1927
|
-
"thurin.
|
|
1928
|
-
"thurin.disclosure",
|
|
1929
|
-
"thurin.pointer"
|
|
1930
|
-
];
|
|
1931
|
-
var IDENTITY_KINDS = [
|
|
1932
|
-
"thurin.railgun",
|
|
1933
|
-
"thurin.security",
|
|
1934
|
-
"thurin.successor",
|
|
1935
|
-
"thurin.affiliation",
|
|
1936
|
-
"thurin.canary",
|
|
3091
|
+
"thurin.releases",
|
|
1937
3092
|
"thurin.private",
|
|
1938
3093
|
"thurin.disclosure"
|
|
1939
3094
|
];
|
|
1940
|
-
function
|
|
1941
|
-
const bytes = new TextEncoder().encode(value).length;
|
|
1942
|
-
if (bytes > MAX_RECORD_BYTES) throw new Error(`Record is ${bytes} bytes; the registry accepts up to ${MAX_RECORD_BYTES}`);
|
|
1943
|
-
return stringToHex2(value);
|
|
1944
|
-
}
|
|
1945
|
-
function decodeRecord(hex) {
|
|
1946
|
-
return hex === "0x" ? "" : hexToString(hex);
|
|
1947
|
-
}
|
|
1948
|
-
function parsePointer(text) {
|
|
3095
|
+
function parseReleases(text) {
|
|
1949
3096
|
const p = JSON.parse(text);
|
|
1950
|
-
if (p?.v !== 1 || !Array.isArray(p.releases)) throw new Error("Not a v1 thurin.
|
|
3097
|
+
if (p?.v !== 1 || !Array.isArray(p.releases)) throw new Error("Not a v1 thurin.releases record");
|
|
1951
3098
|
return p;
|
|
1952
3099
|
}
|
|
1953
|
-
function
|
|
3100
|
+
function addRelease(existing, entry) {
|
|
1954
3101
|
if (!/^[0-9a-f]{64}$/i.test(entry.sha256)) throw new Error("sha256 must be 64 hex characters");
|
|
1955
3102
|
const releases = [entry, ...(existing?.releases ?? []).filter((r) => r.name !== entry.name)];
|
|
1956
3103
|
const dropped = [];
|
|
@@ -1958,7 +3105,7 @@ function addPointer(existing, entry) {
|
|
|
1958
3105
|
while (new TextEncoder().encode(JSON.stringify(record)).length > MAX_RECORD_BYTES && releases.length > 1) dropped.push(releases.pop());
|
|
1959
3106
|
return { record, dropped };
|
|
1960
3107
|
}
|
|
1961
|
-
function
|
|
3108
|
+
function renderReleases(p) {
|
|
1962
3109
|
return p.releases.map((r) => `${r.name.padEnd(22)} ${r.date} sha256 ${r.sha256}${r.url ? ` ${r.url}` : ""}`).join("\n");
|
|
1963
3110
|
}
|
|
1964
3111
|
var RAILGUN_ADDRESS = /^0zk1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{60,200}$/;
|
|
@@ -2018,90 +3165,213 @@ async function parseRecord(kind, text, opts = {}) {
|
|
|
2018
3165
|
}
|
|
2019
3166
|
return { ...base, valid: true, data: { type: "encrypted", recipients } };
|
|
2020
3167
|
}
|
|
2021
|
-
case "thurin.
|
|
3168
|
+
case "thurin.releases": {
|
|
2022
3169
|
try {
|
|
2023
|
-
return { ...base, valid: true, data: { type: "
|
|
3170
|
+
return { ...base, valid: true, data: { type: "releases", releases: parseReleases(t).releases } };
|
|
2024
3171
|
} catch {
|
|
2025
|
-
return invalid(
|
|
3172
|
+
return invalid('Not a v1 release list: expected {"v":1,"releases":[\u2026]}');
|
|
2026
3173
|
}
|
|
2027
3174
|
}
|
|
2028
3175
|
default:
|
|
2029
3176
|
return { ...base, valid: true, data: { type: "text" } };
|
|
2030
3177
|
}
|
|
2031
3178
|
}
|
|
2032
|
-
|
|
3179
|
+
function pickRecords(names, values, kinds = KNOWN_KINDS) {
|
|
3180
|
+
const all = names.map((kind, i) => ({ kind, text: values[i] ?? "" })).filter((r) => r.text);
|
|
3181
|
+
if (!kinds) return all;
|
|
3182
|
+
return kinds.flatMap((k) => all.filter((r) => r.kind === k));
|
|
3183
|
+
}
|
|
3184
|
+
function pageRecords(names, values) {
|
|
3185
|
+
const all = pickRecords(names, values, null);
|
|
3186
|
+
const ours = KNOWN_KINDS.flatMap((k) => all.filter((r) => r.kind === k));
|
|
3187
|
+
return [...ours, ...all.filter((r) => !KNOWN_KINDS.includes(r.kind))];
|
|
3188
|
+
}
|
|
3189
|
+
async function fetchRecords(client, registry, abi, owner, index, kinds = KNOWN_KINDS, opts = {}) {
|
|
3190
|
+
const [names, values] = await client.readContract({ address: registry, abi, functionName: "recordsOf", args: [owner, BigInt(index)] });
|
|
2033
3191
|
const out = [];
|
|
2034
|
-
for (const
|
|
2035
|
-
const hex = await client.readContract({ address: registry, abi, functionName: "record", args: [owner, BigInt(index), recordKind(kind)] });
|
|
2036
|
-
const text = decodeRecord(hex);
|
|
2037
|
-
if (text) out.push(await parseRecord(kind, text, opts));
|
|
2038
|
-
}
|
|
3192
|
+
for (const r of pickRecords(names, values, kinds)) out.push(await parseRecord(r.kind, r.text, opts));
|
|
2039
3193
|
return out;
|
|
2040
3194
|
}
|
|
2041
3195
|
|
|
3196
|
+
// src/core/avatar.ts
|
|
3197
|
+
var IPFS_GATEWAYS = ["https://ipfs.filebase.io/ipfs/", "https://gateway.pinata.cloud/ipfs/"];
|
|
3198
|
+
var IPFS_GATEWAY = IPFS_GATEWAYS[0];
|
|
3199
|
+
var ARWEAVE_GATEWAY = "https://arweave.net/";
|
|
3200
|
+
function avatarUrl(uri) {
|
|
3201
|
+
if (typeof uri !== "string") return null;
|
|
3202
|
+
const u = uri.trim();
|
|
3203
|
+
if (/^data:image\/(png|jpe?g|gif|webp|avif|svg\+xml)[;,]/i.test(u)) return u;
|
|
3204
|
+
let m = u.match(/^ipfs:\/\/(?:ipfs\/)?([a-zA-Z0-9]{46,}(?:\/[^?#\s]*)?)$/);
|
|
3205
|
+
if (m) return IPFS_GATEWAY + m[1];
|
|
3206
|
+
m = u.match(/^ar:\/\/([a-zA-Z0-9_-]{43}(?:\/[^?#\s]*)?)$/);
|
|
3207
|
+
if (m) return ARWEAVE_GATEWAY + m[1];
|
|
3208
|
+
if (/^https:\/\/euc\.li\/[^?#\s]+$/.test(u)) return u;
|
|
3209
|
+
m = u.match(/^https:\/\/[^/]+\/ipfs\/([a-zA-Z0-9]{46,}(?:\/[^?#\s]*)?)$/);
|
|
3210
|
+
if (m) return IPFS_GATEWAY + m[1];
|
|
3211
|
+
return null;
|
|
3212
|
+
}
|
|
3213
|
+
function avatarFallbacks(url) {
|
|
3214
|
+
if (!url || !url.startsWith(IPFS_GATEWAYS[0])) return [];
|
|
3215
|
+
const path = url.slice(IPFS_GATEWAYS[0].length);
|
|
3216
|
+
return IPFS_GATEWAYS.slice(1).map((g) => g + path);
|
|
3217
|
+
}
|
|
3218
|
+
function parseNftAvatar(raw) {
|
|
3219
|
+
const m = typeof raw === "string" && raw.trim().match(/^eip155:(\d+)\/(erc721|erc1155):(0x[0-9a-fA-F]{40})\/(\d+)$/i);
|
|
3220
|
+
return m ? { chainId: Number(m[1]), standard: m[2].toLowerCase(), contract: m[3], tokenId: BigInt(m[4]) } : null;
|
|
3221
|
+
}
|
|
3222
|
+
var NFT_AVATAR_ABI = [
|
|
3223
|
+
{ type: "function", name: "tokenURI", stateMutability: "view", inputs: [{ type: "uint256" }], outputs: [{ type: "string" }] },
|
|
3224
|
+
{ type: "function", name: "uri", stateMutability: "view", inputs: [{ type: "uint256" }], outputs: [{ type: "string" }] }
|
|
3225
|
+
];
|
|
3226
|
+
async function nftAvatarImage(tokenUri, tokenId, fetchFn = fetch) {
|
|
3227
|
+
const uri = tokenUri.replace("{id}", tokenId.toString(16).padStart(64, "0"));
|
|
3228
|
+
let meta;
|
|
3229
|
+
const inline = uri.match(/^data:application\/json(;base64)?,([\s\S]*)$/);
|
|
3230
|
+
if (inline) meta = JSON.parse(inline[1] ? atob(inline[2]) : decodeURIComponent(inline[2]));
|
|
3231
|
+
else {
|
|
3232
|
+
const url = uri.startsWith("data:") ? null : avatarUrl(uri);
|
|
3233
|
+
if (!url) return null;
|
|
3234
|
+
for (const candidate of [url, ...avatarFallbacks(url)]) {
|
|
3235
|
+
try {
|
|
3236
|
+
const res = await fetchFn(candidate);
|
|
3237
|
+
if (res.ok) {
|
|
3238
|
+
meta = await res.json();
|
|
3239
|
+
break;
|
|
3240
|
+
}
|
|
3241
|
+
} catch {
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
if (!meta) return null;
|
|
3245
|
+
}
|
|
3246
|
+
return avatarUrl(meta?.image ?? meta?.image_url);
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3249
|
+
// src/core/ensHint.ts
|
|
3250
|
+
import { namehash, normalize } from "viem/ens";
|
|
3251
|
+
var ENS_HINT_KEY = "id.thurin";
|
|
3252
|
+
function ensHintFor(record, verifiedFingerprint) {
|
|
3253
|
+
const raw = record?.trim() ?? "";
|
|
3254
|
+
const expected = verifiedFingerprint ? normalizeFingerprint(verifiedFingerprint) : null;
|
|
3255
|
+
if (!raw) return { key: ENS_HINT_KEY, state: "unset", record: null, fingerprint: null, expected };
|
|
3256
|
+
const fingerprint = normalizeFingerprint(raw);
|
|
3257
|
+
if (!fingerprint) return { key: ENS_HINT_KEY, state: "mismatch", record: raw, fingerprint: null, expected, reason: "The record is not a PGP fingerprint" };
|
|
3258
|
+
if (!expected) return { key: ENS_HINT_KEY, state: "mismatch", record: raw, fingerprint, expected, reason: "The address has no verified claim" };
|
|
3259
|
+
if (fingerprint === expected) return { key: ENS_HINT_KEY, state: "match", record: raw, fingerprint, expected };
|
|
3260
|
+
return { key: ENS_HINT_KEY, state: "mismatch", record: raw, fingerprint, expected, reason: "The record names a key this address has not claimed" };
|
|
3261
|
+
}
|
|
3262
|
+
function ensHintValue(fingerprint) {
|
|
3263
|
+
const fp = normalizeFingerprint(fingerprint);
|
|
3264
|
+
if (!fp) throw new Error(`Not a fingerprint: ${fingerprint}`);
|
|
3265
|
+
return fp.toUpperCase();
|
|
3266
|
+
}
|
|
3267
|
+
var ENS_TEXT_RESOLVER_ABI = [
|
|
3268
|
+
{ type: "function", name: "text", stateMutability: "view", inputs: [{ name: "node", type: "bytes32" }, { name: "key", type: "string" }], outputs: [{ name: "", type: "string" }] },
|
|
3269
|
+
{ type: "function", name: "setText", stateMutability: "nonpayable", inputs: [{ name: "node", type: "bytes32" }, { name: "key", type: "string" }, { name: "value", type: "string" }], outputs: [] }
|
|
3270
|
+
];
|
|
3271
|
+
function ensHintWrite(name, fingerprint) {
|
|
3272
|
+
const normalized = normalize(name);
|
|
3273
|
+
return {
|
|
3274
|
+
abi: ENS_TEXT_RESOLVER_ABI,
|
|
3275
|
+
functionName: "setText",
|
|
3276
|
+
args: [namehash(normalized), ENS_HINT_KEY, ensHintValue(fingerprint)],
|
|
3277
|
+
name: normalized
|
|
3278
|
+
};
|
|
3279
|
+
}
|
|
3280
|
+
async function fetchEnsHint(client, name, verifiedFingerprint) {
|
|
3281
|
+
const record = await client.getEnsText({ name: normalize(name), key: ENS_HINT_KEY });
|
|
3282
|
+
return ensHintFor(record, verifiedFingerprint);
|
|
3283
|
+
}
|
|
3284
|
+
|
|
2042
3285
|
export {
|
|
2043
|
-
REGISTRY_ABI,
|
|
2044
|
-
REGISTRY_ADDRESS,
|
|
2045
|
-
NETWORKS,
|
|
2046
|
-
isNetworkName,
|
|
2047
|
-
getRegistry,
|
|
2048
|
-
chainFor,
|
|
2049
|
-
needsRpcProbe,
|
|
2050
|
-
identityErrorKind,
|
|
2051
|
-
IDENTITY_ERROR_TEXT,
|
|
2052
3286
|
normalizeFingerprint,
|
|
3287
|
+
sameFingerprint,
|
|
2053
3288
|
fingerprintToBytes,
|
|
2054
3289
|
bytesToFingerprint,
|
|
2055
3290
|
fingerprintHash,
|
|
2056
3291
|
keyIdOf,
|
|
2057
3292
|
keyIdToBytes,
|
|
2058
|
-
parsePgpKey,
|
|
2059
|
-
verifyClearsigned,
|
|
2060
|
-
verifyAttestation,
|
|
2061
|
-
stripEmailUserIDs,
|
|
2062
|
-
hasEmailUserID,
|
|
2063
|
-
fetchEFPGraph,
|
|
2064
3293
|
identifyProof,
|
|
2065
3294
|
displayUrl,
|
|
2066
3295
|
proofHref,
|
|
2067
3296
|
proofSecondaryHref,
|
|
2068
3297
|
FARCASTER_HUB,
|
|
2069
3298
|
verifyProof,
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
ensHintWrite,
|
|
2083
|
-
fetchEnsHint,
|
|
3299
|
+
statementText,
|
|
3300
|
+
parsePgpKey,
|
|
3301
|
+
verifyClearsigned,
|
|
3302
|
+
verifyStatementSignature,
|
|
3303
|
+
verifyAttestation,
|
|
3304
|
+
stripEmailUserIDs,
|
|
3305
|
+
hasEmailUserID,
|
|
3306
|
+
leanKey,
|
|
3307
|
+
claimSignature,
|
|
3308
|
+
signatureEmail,
|
|
3309
|
+
payloadText,
|
|
3310
|
+
sshKeys,
|
|
2084
3311
|
EIP712_NAME,
|
|
2085
3312
|
EIP712_VERSION,
|
|
2086
3313
|
registryDomain,
|
|
2087
3314
|
AUTHORIZATION_TYPES,
|
|
3315
|
+
REVOKE_REASONS,
|
|
3316
|
+
OWNER_REVOKE_REASONS,
|
|
2088
3317
|
attestTypedData,
|
|
2089
3318
|
reattestTypedData,
|
|
2090
3319
|
updateKeyTypedData,
|
|
2091
3320
|
revokeTypedData,
|
|
2092
3321
|
setRecordTypedData,
|
|
3322
|
+
markCompromisedTypedData,
|
|
2093
3323
|
authorizationDigest,
|
|
2094
3324
|
recordKind,
|
|
3325
|
+
REGISTRY_ABI,
|
|
3326
|
+
REGISTRY_ADDRESS,
|
|
3327
|
+
NETWORKS,
|
|
3328
|
+
isNetworkName,
|
|
3329
|
+
getRegistry,
|
|
3330
|
+
chainFor,
|
|
3331
|
+
CLAIM_LIMIT,
|
|
3332
|
+
readClaims,
|
|
3333
|
+
keyStanding,
|
|
3334
|
+
findOwners,
|
|
3335
|
+
CLAIM_CHECK_LABEL,
|
|
3336
|
+
formatClaimDate,
|
|
3337
|
+
claimCheckText,
|
|
3338
|
+
keyProblemText,
|
|
3339
|
+
expiresSoon,
|
|
3340
|
+
expiresSoonText,
|
|
3341
|
+
claimFates,
|
|
3342
|
+
claimFateText,
|
|
3343
|
+
encryptionKeyFor,
|
|
3344
|
+
encryptRefusalText,
|
|
3345
|
+
keyChangedText,
|
|
3346
|
+
encryptTo,
|
|
3347
|
+
CONTRACT_ERROR_TEXT,
|
|
3348
|
+
contractErrorName,
|
|
3349
|
+
contractErrorText,
|
|
2095
3350
|
MAX_RECORD_BYTES,
|
|
3351
|
+
MAX_KIND_BYTES,
|
|
2096
3352
|
kindName,
|
|
3353
|
+
checkKindName,
|
|
3354
|
+
checkRecordValue,
|
|
2097
3355
|
KNOWN_KINDS,
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
parsePointer,
|
|
2102
|
-
addPointer,
|
|
2103
|
-
renderPointer,
|
|
3356
|
+
parseReleases,
|
|
3357
|
+
addRelease,
|
|
3358
|
+
renderReleases,
|
|
2104
3359
|
parseRecord,
|
|
2105
|
-
|
|
3360
|
+
pickRecords,
|
|
3361
|
+
pageRecords,
|
|
3362
|
+
fetchRecords,
|
|
3363
|
+
IPFS_GATEWAYS,
|
|
3364
|
+
IPFS_GATEWAY,
|
|
3365
|
+
ARWEAVE_GATEWAY,
|
|
3366
|
+
avatarUrl,
|
|
3367
|
+
avatarFallbacks,
|
|
3368
|
+
parseNftAvatar,
|
|
3369
|
+
NFT_AVATAR_ABI,
|
|
3370
|
+
nftAvatarImage,
|
|
3371
|
+
ENS_HINT_KEY,
|
|
3372
|
+
ensHintFor,
|
|
3373
|
+
ensHintValue,
|
|
3374
|
+
ENS_TEXT_RESOLVER_ABI,
|
|
3375
|
+
ensHintWrite,
|
|
3376
|
+
fetchEnsHint
|
|
2106
3377
|
};
|
|
2107
|
-
//# sourceMappingURL=chunk-ROQWHCHP.js.map
|