@thurinlabs/identity-kit 1.4.0 → 2.1.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.
@@ -1,237 +1,1190 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } async function _asyncOptionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = await fn(value); } else if (op === 'call' || op === 'optionalCall') { value = await fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/core/abi.ts
2
- var REGISTRY_ABI = [
3
- {
4
- "type": "function",
5
- "name": "ATTEST_TYPEHASH",
6
- "inputs": [],
7
- "outputs": [
8
- {
9
- "name": "",
10
- "type": "bytes32",
11
- "internalType": "bytes32"
12
- }
13
- ],
14
- "stateMutability": "view"
15
- },
16
- {
17
- "type": "function",
18
- "name": "DOMAIN_SEPARATOR",
19
- "inputs": [],
20
- "outputs": [
21
- {
22
- "name": "",
23
- "type": "bytes32",
24
- "internalType": "bytes32"
25
- }
26
- ],
27
- "stateMutability": "view"
28
- },
29
- {
30
- "type": "function",
31
- "name": "EIP712_NAME",
32
- "inputs": [],
33
- "outputs": [
34
- {
35
- "name": "",
36
- "type": "string",
37
- "internalType": "string"
38
- }
39
- ],
40
- "stateMutability": "view"
41
- },
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/core/fingerprint.ts
2
+ var _viem = require('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 _viem.keccak256.call(void 0, 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 = [
42
39
  {
43
- "type": "function",
44
- "name": "EIP712_VERSION",
45
- "inputs": [],
46
- "outputs": [
47
- {
48
- "name": "",
49
- "type": "string",
50
- "internalType": "string"
51
- }
52
- ],
53
- "stateMutability": "view"
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] })
54
44
  },
55
45
  {
56
- "type": "function",
57
- "name": "MAX_KEY_BYTES",
58
- "inputs": [],
59
- "outputs": [
60
- {
61
- "name": "",
62
- "type": "uint256",
63
- "internalType": "uint256"
64
- }
65
- ],
66
- "stateMutability": "view"
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] })
67
52
  },
68
53
  {
69
- "type": "function",
70
- "name": "MAX_RECORD_BYTES",
71
- "inputs": [],
72
- "outputs": [
73
- {
74
- "name": "",
75
- "type": "uint256",
76
- "internalType": "uint256"
77
- }
78
- ],
79
- "stateMutability": "view"
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] })
80
59
  },
81
60
  {
82
- "type": "function",
83
- "name": "MAX_SIG_BYTES",
84
- "inputs": [],
85
- "outputs": [
86
- {
87
- "name": "",
88
- "type": "uint256",
89
- "internalType": "uint256"
90
- }
91
- ],
92
- "stateMutability": "view"
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] })
93
65
  },
94
66
  {
95
- "type": "function",
96
- "name": "MESSAGE_VERSION",
97
- "inputs": [],
98
- "outputs": [
99
- {
100
- "name": "",
101
- "type": "uint8",
102
- "internalType": "uint8"
103
- }
104
- ],
105
- "stateMutability": "view"
67
+ provider: "codeberg",
68
+ label: "Codeberg",
69
+ pattern: /^https:\/\/codeberg\.org\/([^/]+)\/([^/]+)$/i,
70
+ parse: (m) => ({ user: m[1], repo: m[2] })
106
71
  },
107
72
  {
108
- "type": "function",
109
- "name": "REATTEST_TYPEHASH",
110
- "inputs": [],
111
- "outputs": [
112
- {
113
- "name": "",
114
- "type": "bytes32",
115
- "internalType": "bytes32"
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 (_optionalChain([data, 'access', _ => _.owner, 'optionalAccess', _2 => _2.login, 'optionalAccess', _3 => _3.toLowerCase, 'call', _4 => _4()]) !== 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 };
116
133
  }
117
- ],
118
- "stateMutability": "view"
119
- },
120
- {
121
- "type": "function",
122
- "name": "REVOKE_TYPEHASH",
123
- "inputs": [],
124
- "outputs": [
125
- {
126
- "name": "",
127
- "type": "bytes32",
128
- "internalType": "bytes32"
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 (_optionalChain([data, 'access', _5 => _5.owner, 'optionalAccess', _6 => _6.login, 'optionalAccess', _7 => _7.toLowerCase, 'call', _8 => _8()]) !== 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 };
129
170
  }
130
- ],
131
- "stateMutability": "view"
132
- },
133
- {
134
- "type": "function",
135
- "name": "SET_RECORD_TYPEHASH",
136
- "inputs": [],
137
- "outputs": [
138
- {
139
- "name": "",
140
- "type": "bytes32",
141
- "internalType": "bytes32"
142
- }
143
- ],
144
- "stateMutability": "view"
145
- },
146
- {
147
- "type": "function",
148
- "name": "UPDATE_KEY_TYPEHASH",
149
- "inputs": [],
150
- "outputs": [
151
- {
152
- "name": "",
153
- "type": "bytes32",
154
- "internalType": "bytes32"
155
- }
156
- ],
157
- "stateMutability": "view"
158
- },
159
- {
160
- "type": "function",
161
- "name": "VERSION",
162
- "inputs": [],
163
- "outputs": [
164
- {
165
- "name": "",
166
- "type": "uint8",
167
- "internalType": "uint8"
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 = _optionalChain([msg, 'access', _9 => _9.data, 'optionalAccess', _10 => _10.castAddBody, 'optionalAccess', _11 => _11.text]) || "";
202
+ if (containsFingerprint(text, fingerprint)) {
203
+ return { verified: true };
204
+ }
205
+ }
168
206
  }
169
- ],
170
- "stateMutability": "view"
171
- },
172
- {
173
- "type": "function",
174
- "name": "addressesFor",
175
- "inputs": [
176
- {
177
- "name": "fingerprintHash",
178
- "type": "bytes32",
179
- "internalType": "bytes32"
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 (_optionalChain([data, 'access', _12 => _12.owner, 'optionalAccess', _13 => _13.login, 'optionalAccess', _14 => _14.toLowerCase, 'call', _15 => _15()]) !== 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 };
180
248
  }
181
- ],
182
- "outputs": [
183
- {
184
- "name": "",
185
- "type": "address[]",
186
- "internalType": "address[]"
249
+ }
250
+ if (data.note) {
251
+ const text = data.note.replace(/<[^>]*>/g, "");
252
+ if (containsFingerprintUrl(text, fingerprint) || containsFingerprintUrl(text, keyId)) {
253
+ return { verified: true };
187
254
  }
188
- ],
189
- "stateMutability": "view"
190
- },
191
- {
192
- "type": "function",
193
- "name": "addressesForCount",
194
- "inputs": [
195
- {
196
- "name": "fingerprintHash",
197
- "type": "bytes32",
198
- "internalType": "bytes32"
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 } : _nullishCoalesce(opts, () => ( {})));
272
+ }
273
+
274
+ // src/core/pgp.ts
275
+ function pgpConfig(openpgp) {
276
+ const rejectCurves = new Set([..._nullishCoalesce(openpgp.config.rejectCurves, () => ( []))].filter((c) => c !== "secp256k1"));
277
+ return { ...openpgp.config, rejectCurves };
278
+ }
279
+ function newestSignature(sigs = []) {
280
+ return [...sigs].sort((x, y) => (_nullishCoalesce(_optionalChain([y, 'access', _16 => _16.created, 'optionalAccess', _17 => _17.getTime, 'optionalCall', _18 => _18()]), () => ( 0))) - (_nullishCoalesce(_optionalChain([x, 'access', _19 => _19.created, 'optionalAccess', _20 => _20.getTime, 'optionalCall', _21 => _21()]), () => ( 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 (e2) {
298
+ return String(_nullishCoalesce(_optionalChain([keyOrSubkey, 'access', _22 => _22.keyPacket, 'optionalAccess', _23 => _23.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 Promise.resolve().then(() => _interopRequireWildcard(require("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 = _nullishCoalesce(_optionalChain([key, 'access', _24 => _24.keyPacket, 'access', _25 => _25.created, 'optionalAccess', _26 => _26.toISOString, 'call', _27 => _27()]), () => ( 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 (e3) {
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
+ }
199
378
  }
200
- ],
201
- "outputs": [
202
- {
203
- "name": "",
204
- "type": "uint256",
205
- "internalType": "uint256"
379
+ if (userVerified) {
380
+ const uid = _optionalChain([user, 'access', _28 => _28.userID, 'optionalAccess', _29 => _29.userID]);
381
+ if (uid) userIDs.push(uid);
206
382
  }
207
- ],
208
- "stateMutability": "view"
209
- },
210
- {
211
- "type": "function",
212
- "name": "addressesForRange",
213
- "inputs": [
214
- {
215
- "name": "fingerprintHash",
216
- "type": "bytes32",
217
- "internalType": "bytes32"
218
- },
219
- {
220
- "name": "start",
221
- "type": "uint256",
222
- "internalType": "uint256"
223
- },
224
- {
225
- "name": "count",
226
- "type": "uint256",
383
+ }
384
+ const now = /* @__PURE__ */ new Date();
385
+ const subkeys = await Promise.all(key.subkeys.map(async (sk) => {
386
+ const flags = _nullishCoalesce(_optionalChain([newestSignature, 'call', _30 => _30(sk.bindingSignatures), 'optionalAccess', _31 => _31.keyFlags, 'optionalAccess', _32 => _32[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: _nullishCoalesce(_optionalChain([sk, 'access', _33 => _33.keyPacket, 'access', _34 => _34.created, 'optionalAccess', _35 => _35.toISOString, 'call', _36 => _36()]), () => ( 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 (e4) {
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 Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
425
+ const publicKey = await readKeyAny(openpgp, armoredKey);
426
+ const message = await openpgp.readCleartextMessage({ cleartextMessage: clearsigned });
427
+ const text = _nullishCoalesce(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 Promise.resolve().then(() => _interopRequireWildcard(require("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 = [..._nullishCoalesce(sigs, () => ( []))].sort((a, b) => (_nullishCoalesce(_optionalChain([b, 'access', _37 => _37.created, 'optionalAccess', _38 => _38.getTime, 'optionalCall', _39 => _39()]), () => ( 0))) - (_nullishCoalesce(_optionalChain([a, 'access', _40 => _40.created, 'optionalAccess', _41 => _41.getTime, 'optionalCall', _42 => _42()]), () => ( 0))))[0];
455
+ const flag = _nullishCoalesce(_optionalChain([sig, 'optionalAccess', _43 => _43.reasonForRevocationFlag]), () => ( null));
456
+ return {
457
+ at: iso(_optionalChain([sig, 'optionalAccess', _44 => _44.created])),
458
+ compromised: flag === 2,
459
+ revocationReason: _optionalChain([sig, 'optionalAccess', _45 => _45.reasonForRevocationString]) || (flag !== null ? _nullishCoalesce(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) ? _nullishCoalesce(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 (e5) {
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(_nullishCoalesce(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 Promise.resolve().then(() => _interopRequireWildcard(require("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 (e6) {
515
+ return { verified: false, reason: "Unreadable signature", kind: "bad-signature" };
516
+ }
517
+ const life = await keyLife(publicKey, _nullishCoalesce(_optionalChain([sig, 'access', _46 => _46.packets, 'access', _47 => _47[0], 'optionalAccess', _48 => _48.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 (e7) {
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 _nullishCoalesce(_optionalChain([sig, 'optionalAccess', _49 => _49.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 Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
548
+ const key = await readKeyAny(openpgp, armoredKey);
549
+ const kept = [];
550
+ const removed = [];
551
+ const users = key.users.filter((u) => {
552
+ const uid = _optionalChain([u, 'access', _50 => _50.userID, 'optionalAccess', _51 => _51.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 (e8) {
565
+ return null;
566
+ }
567
+ }
568
+ async function hasEmailUserID(armoredKey) {
569
+ try {
570
+ const openpgp = await Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
571
+ const key = await readKeyAny(openpgp, armoredKey);
572
+ return key.users.some((u) => EMAIL_UID.test(_nullishCoalesce(_optionalChain([u, 'access', _52 => _52.userID, 'optionalAccess', _53 => _53.userID]), () => ( ""))));
573
+ } catch (e9) {
574
+ return false;
575
+ }
576
+ }
577
+ async function leanKey(input, { includeEmail = false } = {}) {
578
+ try {
579
+ const openpgp = await Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
580
+ const key = await readKeyAny(openpgp, input);
581
+ const kept = [];
582
+ const removed = [];
583
+ const newest = (sigs = []) => sigs.length ? [[...sigs].sort((x, y) => (_nullishCoalesce(_optionalChain([y, 'access', _54 => _54.created, 'optionalAccess', _55 => _55.getTime, 'optionalCall', _56 => _56()]), () => ( 0))) - (_nullishCoalesce(_optionalChain([x, 'access', _57 => _57.created, 'optionalAccess', _58 => _58.getTime, 'optionalCall', _59 => _59()]), () => ( 0))))[0]] : [];
584
+ for (const u of key.users) {
585
+ u.selfCertifications = _optionalChain([u, 'access', _60 => _60.revocationSignatures, 'optionalAccess', _61 => _61.length]) ? [] : newest(u.selfCertifications);
586
+ u.otherCertifications = [];
587
+ }
588
+ const users = key.users.filter((u) => {
589
+ const uid = _optionalChain([u, 'access', _62 => _62.userID, 'optionalAccess', _63 => _63.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 (e10) {
605
+ return null;
606
+ }
607
+ }
608
+ async function claimSignature({ signature, key, address }) {
609
+ try {
610
+ const openpgp = await Promise.resolve().then(() => _interopRequireWildcard(require("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 (e11) {
621
+ return null;
622
+ }
623
+ }
624
+ async function signatureEmail(signature) {
625
+ try {
626
+ const openpgp = await Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
627
+ const { packets } = await readSignatureAny(openpgp, signature);
628
+ for (const p of packets) {
629
+ const uid = _nullishCoalesce(p.signersUserID, () => ( null));
630
+ if (uid && uid.includes("@")) return uid;
631
+ }
632
+ return null;
633
+ } catch (e12) {
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 Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
642
+ if (kind === "key") return (await openpgp.readKey({ binaryKey: v })).armor();
643
+ return (await openpgp.readSignature({ binarySignature: v })).armor();
644
+ } catch (e13) {
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 (_optionalChain([pp, 'access', _64 => _64.oid, 'optionalAccess', _65 => _65.getName, 'optionalCall', _66 => _66()]) !== "ed25519Legacy" || _optionalChain([pp, 'access', _67 => _67.Q, 'optionalAccess', _68 => _68.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" }[_optionalChain([pp, 'access', _69 => _69.oid, 'optionalAccess', _70 => _70.getName, 'optionalCall', _71 => _71()])];
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 Promise.resolve().then(() => _interopRequireWildcard(require("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 (e14) {
706
+ return [];
707
+ }
708
+ const candidates = [];
709
+ const direct = newestSignature(key.directSignatures);
710
+ const primarySig = _optionalChain([direct, 'optionalAccess', _72 => _72.keyFlags]) ? direct : (await key.getPrimaryUser(now, void 0, config)).selfCertification;
711
+ candidates.push({ packet: key.keyPacket, flags: _nullishCoalesce(_optionalChain([primarySig, 'optionalAccess', _73 => _73.keyFlags, 'optionalAccess', _74 => _74[0]]), () => ( 0)) });
712
+ for (const sk of key.subkeys) {
713
+ try {
714
+ await sk.verify(now, config);
715
+ } catch (e15) {
716
+ continue;
717
+ }
718
+ candidates.push({ packet: sk.keyPacket, flags: _nullishCoalesce(_optionalChain([newestSignature, 'call', _75 => _75(sk.bindingSignatures), 'optionalAccess', _76 => _76.keyFlags, 'optionalAccess', _77 => _77[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 (e16) {
734
+ return [];
735
+ }
736
+ }
737
+
738
+ // src/core/authorization.ts
739
+
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 : _viem.stringToHex.call(void 0, 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: _nullishCoalesce(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 _viem.hashTypedData.call(void 0, typedData);
864
+ }
865
+ var ERC1271_MAGIC = "0x1626ba7e";
866
+ var ERC1271_ABI = [{
867
+ type: "function",
868
+ name: "isValidSignature",
869
+ stateMutability: "view",
870
+ inputs: [{ name: "hash", type: "bytes32" }, { name: "signature", type: "bytes" }],
871
+ outputs: [{ name: "", type: "bytes4" }]
872
+ }];
873
+ async function permissionSigned(client, typedData, signature, owner) {
874
+ const code = await client.getCode({ address: owner }).catch(() => void 0);
875
+ const deployed = !!code && code !== "0x";
876
+ if (_viem.isErc6492Signature.call(void 0, signature)) {
877
+ return { ok: false, reason: deployed ? "This signature was made before the account was on-chain. Sign again, now that it is" : "This smart account isn't on-chain yet, so the registry can't check its signature. Send any transaction from it first (that creates it), then sign again" };
878
+ }
879
+ const signer = await _viem.recoverTypedDataAddress.call(void 0, { ...typedData, signature }).catch(() => void 0);
880
+ if (signer && signer.toLowerCase() === owner.toLowerCase()) return { ok: true };
881
+ if (deployed) {
882
+ const answer = await client.readContract({
883
+ address: owner,
884
+ abi: ERC1271_ABI,
885
+ functionName: "isValidSignature",
886
+ args: [authorizationDigest(typedData), signature]
887
+ }).catch(() => void 0);
888
+ if (answer === ERC1271_MAGIC) return { ok: true };
889
+ return { ok: false, reason: `The account ${owner} doesn't accept this signature as its own` };
890
+ }
891
+ return { ok: false, reason: signer ? `The signature is from ${signer}, not ${owner}` : "The signature can't be read", signer };
892
+ }
893
+ function recordKind(name) {
894
+ return _viem.keccak256.call(void 0, _viem.stringToHex.call(void 0, name));
895
+ }
896
+
897
+ // src/core/contract.ts
898
+ var _chains = require('viem/chains');
899
+
900
+ // src/core/abi.ts
901
+ var REGISTRY_ABI = [
902
+ {
903
+ "type": "function",
904
+ "name": "ATTEST_TYPEHASH",
905
+ "inputs": [],
906
+ "outputs": [
907
+ {
908
+ "name": "",
909
+ "type": "bytes32",
910
+ "internalType": "bytes32"
911
+ }
912
+ ],
913
+ "stateMutability": "view"
914
+ },
915
+ {
916
+ "type": "function",
917
+ "name": "DOMAIN_SEPARATOR",
918
+ "inputs": [],
919
+ "outputs": [
920
+ {
921
+ "name": "",
922
+ "type": "bytes32",
923
+ "internalType": "bytes32"
924
+ }
925
+ ],
926
+ "stateMutability": "view"
927
+ },
928
+ {
929
+ "type": "function",
930
+ "name": "EIP712_NAME",
931
+ "inputs": [],
932
+ "outputs": [
933
+ {
934
+ "name": "",
935
+ "type": "string",
936
+ "internalType": "string"
937
+ }
938
+ ],
939
+ "stateMutability": "view"
940
+ },
941
+ {
942
+ "type": "function",
943
+ "name": "EIP712_VERSION",
944
+ "inputs": [],
945
+ "outputs": [
946
+ {
947
+ "name": "",
948
+ "type": "string",
949
+ "internalType": "string"
950
+ }
951
+ ],
952
+ "stateMutability": "view"
953
+ },
954
+ {
955
+ "type": "function",
956
+ "name": "EPOCH",
957
+ "inputs": [],
958
+ "outputs": [
959
+ {
960
+ "name": "",
961
+ "type": "uint256",
962
+ "internalType": "uint256"
963
+ }
964
+ ],
965
+ "stateMutability": "view"
966
+ },
967
+ {
968
+ "type": "function",
969
+ "name": "MARK_COMPROMISED_TYPEHASH",
970
+ "inputs": [],
971
+ "outputs": [
972
+ {
973
+ "name": "",
974
+ "type": "bytes32",
975
+ "internalType": "bytes32"
976
+ }
977
+ ],
978
+ "stateMutability": "view"
979
+ },
980
+ {
981
+ "type": "function",
982
+ "name": "MAX_CLAIMS_PER_OWNER",
983
+ "inputs": [],
984
+ "outputs": [
985
+ {
986
+ "name": "",
987
+ "type": "uint256",
988
+ "internalType": "uint256"
989
+ }
990
+ ],
991
+ "stateMutability": "view"
992
+ },
993
+ {
994
+ "type": "function",
995
+ "name": "MAX_KEY_BYTES",
996
+ "inputs": [],
997
+ "outputs": [
998
+ {
999
+ "name": "",
1000
+ "type": "uint256",
1001
+ "internalType": "uint256"
1002
+ }
1003
+ ],
1004
+ "stateMutability": "view"
1005
+ },
1006
+ {
1007
+ "type": "function",
1008
+ "name": "MAX_KIND_BYTES",
1009
+ "inputs": [],
1010
+ "outputs": [
1011
+ {
1012
+ "name": "",
1013
+ "type": "uint256",
227
1014
  "internalType": "uint256"
228
1015
  }
229
1016
  ],
1017
+ "stateMutability": "view"
1018
+ },
1019
+ {
1020
+ "type": "function",
1021
+ "name": "MAX_PAYLOAD_BYTES",
1022
+ "inputs": [],
230
1023
  "outputs": [
231
1024
  {
232
- "name": "out",
233
- "type": "address[]",
234
- "internalType": "address[]"
1025
+ "name": "",
1026
+ "type": "uint256",
1027
+ "internalType": "uint256"
1028
+ }
1029
+ ],
1030
+ "stateMutability": "view"
1031
+ },
1032
+ {
1033
+ "type": "function",
1034
+ "name": "MAX_RECORD_BYTES",
1035
+ "inputs": [],
1036
+ "outputs": [
1037
+ {
1038
+ "name": "",
1039
+ "type": "uint256",
1040
+ "internalType": "uint256"
1041
+ }
1042
+ ],
1043
+ "stateMutability": "view"
1044
+ },
1045
+ {
1046
+ "type": "function",
1047
+ "name": "MAX_SIGNATURE_BYTES",
1048
+ "inputs": [],
1049
+ "outputs": [
1050
+ {
1051
+ "name": "",
1052
+ "type": "uint256",
1053
+ "internalType": "uint256"
1054
+ }
1055
+ ],
1056
+ "stateMutability": "view"
1057
+ },
1058
+ {
1059
+ "type": "function",
1060
+ "name": "MESSAGE_CLEARSIGNED",
1061
+ "inputs": [],
1062
+ "outputs": [
1063
+ {
1064
+ "name": "",
1065
+ "type": "uint8",
1066
+ "internalType": "uint8"
1067
+ }
1068
+ ],
1069
+ "stateMutability": "view"
1070
+ },
1071
+ {
1072
+ "type": "function",
1073
+ "name": "MESSAGE_DETACHED",
1074
+ "inputs": [],
1075
+ "outputs": [
1076
+ {
1077
+ "name": "",
1078
+ "type": "uint8",
1079
+ "internalType": "uint8"
1080
+ }
1081
+ ],
1082
+ "stateMutability": "view"
1083
+ },
1084
+ {
1085
+ "type": "function",
1086
+ "name": "REATTEST_TYPEHASH",
1087
+ "inputs": [],
1088
+ "outputs": [
1089
+ {
1090
+ "name": "",
1091
+ "type": "bytes32",
1092
+ "internalType": "bytes32"
1093
+ }
1094
+ ],
1095
+ "stateMutability": "view"
1096
+ },
1097
+ {
1098
+ "type": "function",
1099
+ "name": "REVOKE_TYPEHASH",
1100
+ "inputs": [],
1101
+ "outputs": [
1102
+ {
1103
+ "name": "",
1104
+ "type": "bytes32",
1105
+ "internalType": "bytes32"
1106
+ }
1107
+ ],
1108
+ "stateMutability": "view"
1109
+ },
1110
+ {
1111
+ "type": "function",
1112
+ "name": "SET_RECORD_TYPEHASH",
1113
+ "inputs": [],
1114
+ "outputs": [
1115
+ {
1116
+ "name": "",
1117
+ "type": "bytes32",
1118
+ "internalType": "bytes32"
1119
+ }
1120
+ ],
1121
+ "stateMutability": "view"
1122
+ },
1123
+ {
1124
+ "type": "function",
1125
+ "name": "UPDATE_KEY_TYPEHASH",
1126
+ "inputs": [],
1127
+ "outputs": [
1128
+ {
1129
+ "name": "",
1130
+ "type": "bytes32",
1131
+ "internalType": "bytes32"
1132
+ }
1133
+ ],
1134
+ "stateMutability": "view"
1135
+ },
1136
+ {
1137
+ "type": "function",
1138
+ "name": "VERSION",
1139
+ "inputs": [],
1140
+ "outputs": [
1141
+ {
1142
+ "name": "",
1143
+ "type": "uint8",
1144
+ "internalType": "uint8"
1145
+ }
1146
+ ],
1147
+ "stateMutability": "view"
1148
+ },
1149
+ {
1150
+ "type": "function",
1151
+ "name": "armorToBytes",
1152
+ "inputs": [
1153
+ {
1154
+ "name": "armored",
1155
+ "type": "string",
1156
+ "internalType": "string"
1157
+ }
1158
+ ],
1159
+ "outputs": [
1160
+ {
1161
+ "name": "",
1162
+ "type": "bytes",
1163
+ "internalType": "bytes"
1164
+ }
1165
+ ],
1166
+ "stateMutability": "pure"
1167
+ },
1168
+ {
1169
+ "type": "function",
1170
+ "name": "armoredKey",
1171
+ "inputs": [
1172
+ {
1173
+ "name": "owner",
1174
+ "type": "address",
1175
+ "internalType": "address"
1176
+ },
1177
+ {
1178
+ "name": "index",
1179
+ "type": "uint256",
1180
+ "internalType": "uint256"
1181
+ }
1182
+ ],
1183
+ "outputs": [
1184
+ {
1185
+ "name": "",
1186
+ "type": "string",
1187
+ "internalType": "string"
235
1188
  }
236
1189
  ],
237
1190
  "stateMutability": "view"
@@ -246,12 +1199,12 @@ var REGISTRY_ABI = [
246
1199
  "internalType": "bytes"
247
1200
  },
248
1201
  {
249
- "name": "pgpSignature",
1202
+ "name": "signature",
250
1203
  "type": "bytes",
251
1204
  "internalType": "bytes"
252
1205
  },
253
1206
  {
254
- "name": "pgpPublicKey",
1207
+ "name": "key",
255
1208
  "type": "bytes",
256
1209
  "internalType": "bytes"
257
1210
  }
@@ -280,38 +1233,126 @@ var REGISTRY_ABI = [
280
1233
  "internalType": "bytes"
281
1234
  },
282
1235
  {
283
- "name": "pgpSignature",
1236
+ "name": "signature",
1237
+ "type": "bytes",
1238
+ "internalType": "bytes"
1239
+ },
1240
+ {
1241
+ "name": "key",
1242
+ "type": "bytes",
1243
+ "internalType": "bytes"
1244
+ },
1245
+ {
1246
+ "name": "deadline",
1247
+ "type": "uint256",
1248
+ "internalType": "uint256"
1249
+ },
1250
+ {
1251
+ "name": "permission",
284
1252
  "type": "bytes",
285
1253
  "internalType": "bytes"
1254
+ }
1255
+ ],
1256
+ "outputs": [
1257
+ {
1258
+ "name": "index",
1259
+ "type": "uint256",
1260
+ "internalType": "uint256"
1261
+ }
1262
+ ],
1263
+ "stateMutability": "nonpayable"
1264
+ },
1265
+ {
1266
+ "type": "function",
1267
+ "name": "cancelAuthorization",
1268
+ "inputs": [],
1269
+ "outputs": [],
1270
+ "stateMutability": "nonpayable"
1271
+ },
1272
+ {
1273
+ "type": "function",
1274
+ "name": "claim",
1275
+ "inputs": [
1276
+ {
1277
+ "name": "owner",
1278
+ "type": "address",
1279
+ "internalType": "address"
1280
+ },
1281
+ {
1282
+ "name": "index",
1283
+ "type": "uint256",
1284
+ "internalType": "uint256"
1285
+ }
1286
+ ],
1287
+ "outputs": [
1288
+ {
1289
+ "name": "details",
1290
+ "type": "tuple",
1291
+ "internalType": "struct PGPRegistry.ClaimView",
1292
+ "components": [
1293
+ {
1294
+ "name": "index",
1295
+ "type": "uint256",
1296
+ "internalType": "uint256"
1297
+ },
1298
+ {
1299
+ "name": "fingerprint",
1300
+ "type": "bytes",
1301
+ "internalType": "bytes"
1302
+ },
1303
+ {
1304
+ "name": "createdAt",
1305
+ "type": "uint64",
1306
+ "internalType": "uint64"
1307
+ },
1308
+ {
1309
+ "name": "revokedAt",
1310
+ "type": "uint64",
1311
+ "internalType": "uint64"
1312
+ },
1313
+ {
1314
+ "name": "state",
1315
+ "type": "string",
1316
+ "internalType": "string"
1317
+ },
1318
+ {
1319
+ "name": "replacedBy",
1320
+ "type": "uint256",
1321
+ "internalType": "uint256"
1322
+ },
1323
+ {
1324
+ "name": "revokeReason",
1325
+ "type": "string",
1326
+ "internalType": "string"
1327
+ },
1328
+ {
1329
+ "name": "messageVersion",
1330
+ "type": "uint8",
1331
+ "internalType": "uint8"
1332
+ }
1333
+ ]
286
1334
  },
287
1335
  {
288
- "name": "pgpPublicKey",
289
- "type": "bytes",
290
- "internalType": "bytes"
1336
+ "name": "key",
1337
+ "type": "string",
1338
+ "internalType": "string"
291
1339
  },
292
1340
  {
293
- "name": "deadline",
294
- "type": "uint256",
295
- "internalType": "uint256"
1341
+ "name": "statement",
1342
+ "type": "string",
1343
+ "internalType": "string"
296
1344
  },
297
1345
  {
298
- "name": "signature",
299
- "type": "bytes",
300
- "internalType": "bytes"
301
- }
302
- ],
303
- "outputs": [
304
- {
305
- "name": "index",
306
- "type": "uint256",
307
- "internalType": "uint256"
1346
+ "name": "recordKinds",
1347
+ "type": "string[]",
1348
+ "internalType": "string[]"
308
1349
  }
309
1350
  ],
310
- "stateMutability": "nonpayable"
1351
+ "stateMutability": "view"
311
1352
  },
312
1353
  {
313
1354
  "type": "function",
314
- "name": "attestationCount",
1355
+ "name": "claimCount",
315
1356
  "inputs": [
316
1357
  {
317
1358
  "name": "owner",
@@ -330,7 +1371,7 @@ var REGISTRY_ABI = [
330
1371
  },
331
1372
  {
332
1373
  "type": "function",
333
- "name": "attestationsOf",
1374
+ "name": "claimsOf",
334
1375
  "inputs": [
335
1376
  {
336
1377
  "name": "owner",
@@ -340,10 +1381,15 @@ var REGISTRY_ABI = [
340
1381
  ],
341
1382
  "outputs": [
342
1383
  {
343
- "name": "",
1384
+ "name": "out",
344
1385
  "type": "tuple[]",
345
- "internalType": "struct PGPRegistry.Attestation[]",
1386
+ "internalType": "struct PGPRegistry.ClaimView[]",
346
1387
  "components": [
1388
+ {
1389
+ "name": "index",
1390
+ "type": "uint256",
1391
+ "internalType": "uint256"
1392
+ },
347
1393
  {
348
1394
  "name": "fingerprint",
349
1395
  "type": "bytes",
@@ -360,19 +1406,24 @@ var REGISTRY_ABI = [
360
1406
  "internalType": "uint64"
361
1407
  },
362
1408
  {
363
- "name": "messageVersion",
364
- "type": "uint8",
365
- "internalType": "uint8"
1409
+ "name": "state",
1410
+ "type": "string",
1411
+ "internalType": "string"
366
1412
  },
367
1413
  {
368
- "name": "keyPtr",
369
- "type": "address",
370
- "internalType": "address"
1414
+ "name": "replacedBy",
1415
+ "type": "uint256",
1416
+ "internalType": "uint256"
371
1417
  },
372
1418
  {
373
- "name": "sigPtr",
374
- "type": "address",
375
- "internalType": "address"
1419
+ "name": "revokeReason",
1420
+ "type": "string",
1421
+ "internalType": "string"
1422
+ },
1423
+ {
1424
+ "name": "messageVersion",
1425
+ "type": "uint8",
1426
+ "internalType": "uint8"
376
1427
  }
377
1428
  ]
378
1429
  }
@@ -381,7 +1432,7 @@ var REGISTRY_ABI = [
381
1432
  },
382
1433
  {
383
1434
  "type": "function",
384
- "name": "attestationsOfRange",
1435
+ "name": "claimsOfRange",
385
1436
  "inputs": [
386
1437
  {
387
1438
  "name": "owner",
@@ -403,8 +1454,13 @@ var REGISTRY_ABI = [
403
1454
  {
404
1455
  "name": "out",
405
1456
  "type": "tuple[]",
406
- "internalType": "struct PGPRegistry.Attestation[]",
1457
+ "internalType": "struct PGPRegistry.ClaimView[]",
407
1458
  "components": [
1459
+ {
1460
+ "name": "index",
1461
+ "type": "uint256",
1462
+ "internalType": "uint256"
1463
+ },
408
1464
  {
409
1465
  "name": "fingerprint",
410
1466
  "type": "bytes",
@@ -421,19 +1477,24 @@ var REGISTRY_ABI = [
421
1477
  "internalType": "uint64"
422
1478
  },
423
1479
  {
424
- "name": "messageVersion",
425
- "type": "uint8",
426
- "internalType": "uint8"
1480
+ "name": "state",
1481
+ "type": "string",
1482
+ "internalType": "string"
1483
+ },
1484
+ {
1485
+ "name": "replacedBy",
1486
+ "type": "uint256",
1487
+ "internalType": "uint256"
427
1488
  },
428
1489
  {
429
- "name": "keyPtr",
430
- "type": "address",
431
- "internalType": "address"
1490
+ "name": "revokeReason",
1491
+ "type": "string",
1492
+ "internalType": "string"
432
1493
  },
433
1494
  {
434
- "name": "sigPtr",
435
- "type": "address",
436
- "internalType": "address"
1495
+ "name": "messageVersion",
1496
+ "type": "uint8",
1497
+ "internalType": "uint8"
437
1498
  }
438
1499
  ]
439
1500
  }
@@ -442,10 +1503,27 @@ var REGISTRY_ABI = [
442
1503
  },
443
1504
  {
444
1505
  "type": "function",
445
- "name": "cancelAuthorization",
446
- "inputs": [],
447
- "outputs": [],
448
- "stateMutability": "nonpayable"
1506
+ "name": "clearsigned",
1507
+ "inputs": [
1508
+ {
1509
+ "name": "owner",
1510
+ "type": "address",
1511
+ "internalType": "address"
1512
+ },
1513
+ {
1514
+ "name": "index",
1515
+ "type": "uint256",
1516
+ "internalType": "uint256"
1517
+ }
1518
+ ],
1519
+ "outputs": [
1520
+ {
1521
+ "name": "",
1522
+ "type": "string",
1523
+ "internalType": "string"
1524
+ }
1525
+ ],
1526
+ "stateMutability": "view"
449
1527
  },
450
1528
  {
451
1529
  "type": "function",
@@ -469,10 +1547,15 @@ var REGISTRY_ABI = [
469
1547
  "internalType": "uint256"
470
1548
  },
471
1549
  {
472
- "name": "attestation",
1550
+ "name": "details",
473
1551
  "type": "tuple",
474
- "internalType": "struct PGPRegistry.Attestation",
1552
+ "internalType": "struct PGPRegistry.ClaimView",
475
1553
  "components": [
1554
+ {
1555
+ "name": "index",
1556
+ "type": "uint256",
1557
+ "internalType": "uint256"
1558
+ },
476
1559
  {
477
1560
  "name": "fingerprint",
478
1561
  "type": "bytes",
@@ -489,52 +1572,243 @@ var REGISTRY_ABI = [
489
1572
  "internalType": "uint64"
490
1573
  },
491
1574
  {
492
- "name": "messageVersion",
493
- "type": "uint8",
494
- "internalType": "uint8"
1575
+ "name": "state",
1576
+ "type": "string",
1577
+ "internalType": "string"
495
1578
  },
496
1579
  {
497
- "name": "keyPtr",
498
- "type": "address",
499
- "internalType": "address"
1580
+ "name": "replacedBy",
1581
+ "type": "uint256",
1582
+ "internalType": "uint256"
500
1583
  },
501
1584
  {
502
- "name": "sigPtr",
503
- "type": "address",
504
- "internalType": "address"
1585
+ "name": "revokeReason",
1586
+ "type": "string",
1587
+ "internalType": "string"
1588
+ },
1589
+ {
1590
+ "name": "messageVersion",
1591
+ "type": "uint8",
1592
+ "internalType": "uint8"
505
1593
  }
506
1594
  ]
507
1595
  }
508
1596
  ],
509
- "stateMutability": "view"
1597
+ "stateMutability": "view"
1598
+ },
1599
+ {
1600
+ "type": "function",
1601
+ "name": "eip712Domain",
1602
+ "inputs": [],
1603
+ "outputs": [
1604
+ {
1605
+ "name": "fields",
1606
+ "type": "bytes1",
1607
+ "internalType": "bytes1"
1608
+ },
1609
+ {
1610
+ "name": "name",
1611
+ "type": "string",
1612
+ "internalType": "string"
1613
+ },
1614
+ {
1615
+ "name": "version",
1616
+ "type": "string",
1617
+ "internalType": "string"
1618
+ },
1619
+ {
1620
+ "name": "chainId",
1621
+ "type": "uint256",
1622
+ "internalType": "uint256"
1623
+ },
1624
+ {
1625
+ "name": "verifyingContract",
1626
+ "type": "address",
1627
+ "internalType": "address"
1628
+ },
1629
+ {
1630
+ "name": "salt",
1631
+ "type": "bytes32",
1632
+ "internalType": "bytes32"
1633
+ },
1634
+ {
1635
+ "name": "extensions",
1636
+ "type": "uint256[]",
1637
+ "internalType": "uint256[]"
1638
+ }
1639
+ ],
1640
+ "stateMutability": "view"
1641
+ },
1642
+ {
1643
+ "type": "function",
1644
+ "name": "fingerprintsForKeyId",
1645
+ "inputs": [
1646
+ {
1647
+ "name": "keyId",
1648
+ "type": "bytes8",
1649
+ "internalType": "bytes8"
1650
+ }
1651
+ ],
1652
+ "outputs": [
1653
+ {
1654
+ "name": "",
1655
+ "type": "bytes[]",
1656
+ "internalType": "bytes[]"
1657
+ }
1658
+ ],
1659
+ "stateMutability": "view"
1660
+ },
1661
+ {
1662
+ "type": "function",
1663
+ "name": "fingerprintsForKeyIdCount",
1664
+ "inputs": [
1665
+ {
1666
+ "name": "keyId",
1667
+ "type": "bytes8",
1668
+ "internalType": "bytes8"
1669
+ }
1670
+ ],
1671
+ "outputs": [
1672
+ {
1673
+ "name": "",
1674
+ "type": "uint256",
1675
+ "internalType": "uint256"
1676
+ }
1677
+ ],
1678
+ "stateMutability": "view"
1679
+ },
1680
+ {
1681
+ "type": "function",
1682
+ "name": "fingerprintsForKeyIdRange",
1683
+ "inputs": [
1684
+ {
1685
+ "name": "keyId",
1686
+ "type": "bytes8",
1687
+ "internalType": "bytes8"
1688
+ },
1689
+ {
1690
+ "name": "start",
1691
+ "type": "uint256",
1692
+ "internalType": "uint256"
1693
+ },
1694
+ {
1695
+ "name": "count",
1696
+ "type": "uint256",
1697
+ "internalType": "uint256"
1698
+ }
1699
+ ],
1700
+ "outputs": [
1701
+ {
1702
+ "name": "out",
1703
+ "type": "bytes[]",
1704
+ "internalType": "bytes[]"
1705
+ }
1706
+ ],
1707
+ "stateMutability": "view"
1708
+ },
1709
+ {
1710
+ "type": "function",
1711
+ "name": "keyBytes",
1712
+ "inputs": [
1713
+ {
1714
+ "name": "owner",
1715
+ "type": "address",
1716
+ "internalType": "address"
1717
+ },
1718
+ {
1719
+ "name": "index",
1720
+ "type": "uint256",
1721
+ "internalType": "uint256"
1722
+ }
1723
+ ],
1724
+ "outputs": [
1725
+ {
1726
+ "name": "key",
1727
+ "type": "bytes",
1728
+ "internalType": "bytes"
1729
+ }
1730
+ ],
1731
+ "stateMutability": "view"
1732
+ },
1733
+ {
1734
+ "type": "function",
1735
+ "name": "keyStatus",
1736
+ "inputs": [
1737
+ {
1738
+ "name": "owner",
1739
+ "type": "address",
1740
+ "internalType": "address"
1741
+ },
1742
+ {
1743
+ "name": "fingerprint",
1744
+ "type": "bytes",
1745
+ "internalType": "bytes"
1746
+ }
1747
+ ],
1748
+ "outputs": [
1749
+ {
1750
+ "name": "",
1751
+ "type": "string",
1752
+ "internalType": "string"
1753
+ }
1754
+ ],
1755
+ "stateMutability": "view"
1756
+ },
1757
+ {
1758
+ "type": "function",
1759
+ "name": "markCompromisedFor",
1760
+ "inputs": [
1761
+ {
1762
+ "name": "owner",
1763
+ "type": "address",
1764
+ "internalType": "address"
1765
+ },
1766
+ {
1767
+ "name": "index",
1768
+ "type": "uint256",
1769
+ "internalType": "uint256"
1770
+ },
1771
+ {
1772
+ "name": "deadline",
1773
+ "type": "uint256",
1774
+ "internalType": "uint256"
1775
+ },
1776
+ {
1777
+ "name": "permission",
1778
+ "type": "bytes",
1779
+ "internalType": "bytes"
1780
+ }
1781
+ ],
1782
+ "outputs": [],
1783
+ "stateMutability": "nonpayable"
510
1784
  },
511
1785
  {
512
1786
  "type": "function",
513
- "name": "fingerprintsForKeyId",
1787
+ "name": "multicall",
514
1788
  "inputs": [
515
1789
  {
516
- "name": "keyId",
517
- "type": "bytes8",
518
- "internalType": "bytes8"
1790
+ "name": "calls",
1791
+ "type": "bytes[]",
1792
+ "internalType": "bytes[]"
519
1793
  }
520
1794
  ],
521
1795
  "outputs": [
522
1796
  {
523
- "name": "",
1797
+ "name": "results",
524
1798
  "type": "bytes[]",
525
1799
  "internalType": "bytes[]"
526
1800
  }
527
1801
  ],
528
- "stateMutability": "view"
1802
+ "stateMutability": "nonpayable"
529
1803
  },
530
1804
  {
531
1805
  "type": "function",
532
- "name": "fingerprintsForKeyIdCount",
1806
+ "name": "nonces",
533
1807
  "inputs": [
534
1808
  {
535
- "name": "keyId",
536
- "type": "bytes8",
537
- "internalType": "bytes8"
1809
+ "name": "owner",
1810
+ "type": "address",
1811
+ "internalType": "address"
538
1812
  }
539
1813
  ],
540
1814
  "outputs": [
@@ -548,133 +1822,67 @@ var REGISTRY_ABI = [
548
1822
  },
549
1823
  {
550
1824
  "type": "function",
551
- "name": "fingerprintsForKeyIdRange",
1825
+ "name": "ownersOf",
552
1826
  "inputs": [
553
1827
  {
554
- "name": "keyId",
555
- "type": "bytes8",
556
- "internalType": "bytes8"
557
- },
558
- {
559
- "name": "start",
560
- "type": "uint256",
561
- "internalType": "uint256"
562
- },
563
- {
564
- "name": "count",
565
- "type": "uint256",
566
- "internalType": "uint256"
1828
+ "name": "fingerprint",
1829
+ "type": "bytes",
1830
+ "internalType": "bytes"
567
1831
  }
568
1832
  ],
569
1833
  "outputs": [
570
1834
  {
571
- "name": "out",
572
- "type": "bytes[]",
573
- "internalType": "bytes[]"
1835
+ "name": "",
1836
+ "type": "address[]",
1837
+ "internalType": "address[]"
574
1838
  }
575
1839
  ],
576
1840
  "stateMutability": "view"
577
1841
  },
578
1842
  {
579
1843
  "type": "function",
580
- "name": "getAttestation",
1844
+ "name": "ownersOfCount",
581
1845
  "inputs": [
582
1846
  {
583
- "name": "owner",
584
- "type": "address",
585
- "internalType": "address"
586
- },
587
- {
588
- "name": "index",
589
- "type": "uint256",
590
- "internalType": "uint256"
1847
+ "name": "fingerprint",
1848
+ "type": "bytes",
1849
+ "internalType": "bytes"
591
1850
  }
592
1851
  ],
593
1852
  "outputs": [
594
1853
  {
595
1854
  "name": "",
596
- "type": "tuple",
597
- "internalType": "struct PGPRegistry.Attestation",
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
- ]
1855
+ "type": "uint256",
1856
+ "internalType": "uint256"
630
1857
  }
631
1858
  ],
632
1859
  "stateMutability": "view"
633
1860
  },
634
1861
  {
635
1862
  "type": "function",
636
- "name": "getPayload",
1863
+ "name": "ownersOfRange",
637
1864
  "inputs": [
638
1865
  {
639
- "name": "owner",
640
- "type": "address",
641
- "internalType": "address"
1866
+ "name": "fingerprint",
1867
+ "type": "bytes",
1868
+ "internalType": "bytes"
642
1869
  },
643
1870
  {
644
- "name": "index",
1871
+ "name": "start",
645
1872
  "type": "uint256",
646
1873
  "internalType": "uint256"
647
- }
648
- ],
649
- "outputs": [
650
- {
651
- "name": "pgpSignature",
652
- "type": "bytes",
653
- "internalType": "bytes"
654
1874
  },
655
1875
  {
656
- "name": "pgpPublicKey",
657
- "type": "bytes",
658
- "internalType": "bytes"
659
- }
660
- ],
661
- "stateMutability": "view"
662
- },
663
- {
664
- "type": "function",
665
- "name": "nonces",
666
- "inputs": [
667
- {
668
- "name": "",
669
- "type": "address",
670
- "internalType": "address"
1876
+ "name": "count",
1877
+ "type": "uint256",
1878
+ "internalType": "uint256"
671
1879
  }
672
1880
  ],
673
1881
  "outputs": [
674
1882
  {
675
- "name": "",
676
- "type": "uint256",
677
- "internalType": "uint256"
1883
+ "name": "out",
1884
+ "type": "address[]",
1885
+ "internalType": "address[]"
678
1886
  }
679
1887
  ],
680
1888
  "stateMutability": "view"
@@ -694,14 +1902,19 @@ var REGISTRY_ABI = [
694
1902
  "internalType": "bytes"
695
1903
  },
696
1904
  {
697
- "name": "pgpSignature",
1905
+ "name": "signature",
698
1906
  "type": "bytes",
699
1907
  "internalType": "bytes"
700
1908
  },
701
1909
  {
702
- "name": "pgpPublicKey",
1910
+ "name": "key",
703
1911
  "type": "bytes",
704
1912
  "internalType": "bytes"
1913
+ },
1914
+ {
1915
+ "name": "keepRecords",
1916
+ "type": "bool",
1917
+ "internalType": "bool"
705
1918
  }
706
1919
  ],
707
1920
  "outputs": [
@@ -733,22 +1946,27 @@ var REGISTRY_ABI = [
733
1946
  "internalType": "bytes"
734
1947
  },
735
1948
  {
736
- "name": "pgpSignature",
1949
+ "name": "signature",
737
1950
  "type": "bytes",
738
1951
  "internalType": "bytes"
739
1952
  },
740
1953
  {
741
- "name": "pgpPublicKey",
1954
+ "name": "key",
742
1955
  "type": "bytes",
743
1956
  "internalType": "bytes"
744
1957
  },
1958
+ {
1959
+ "name": "keepRecords",
1960
+ "type": "bool",
1961
+ "internalType": "bool"
1962
+ },
745
1963
  {
746
1964
  "name": "deadline",
747
1965
  "type": "uint256",
748
1966
  "internalType": "uint256"
749
1967
  },
750
1968
  {
751
- "name": "signature",
1969
+ "name": "permission",
752
1970
  "type": "bytes",
753
1971
  "internalType": "bytes"
754
1972
  }
@@ -764,7 +1982,7 @@ var REGISTRY_ABI = [
764
1982
  },
765
1983
  {
766
1984
  "type": "function",
767
- "name": "record",
1985
+ "name": "recordText",
768
1986
  "inputs": [
769
1987
  {
770
1988
  "name": "owner",
@@ -778,15 +1996,44 @@ var REGISTRY_ABI = [
778
1996
  },
779
1997
  {
780
1998
  "name": "kind",
781
- "type": "bytes32",
782
- "internalType": "bytes32"
1999
+ "type": "string",
2000
+ "internalType": "string"
783
2001
  }
784
2002
  ],
785
2003
  "outputs": [
786
2004
  {
787
2005
  "name": "",
788
- "type": "bytes",
789
- "internalType": "bytes"
2006
+ "type": "string",
2007
+ "internalType": "string"
2008
+ }
2009
+ ],
2010
+ "stateMutability": "view"
2011
+ },
2012
+ {
2013
+ "type": "function",
2014
+ "name": "recordsOf",
2015
+ "inputs": [
2016
+ {
2017
+ "name": "owner",
2018
+ "type": "address",
2019
+ "internalType": "address"
2020
+ },
2021
+ {
2022
+ "name": "index",
2023
+ "type": "uint256",
2024
+ "internalType": "uint256"
2025
+ }
2026
+ ],
2027
+ "outputs": [
2028
+ {
2029
+ "name": "kinds",
2030
+ "type": "string[]",
2031
+ "internalType": "string[]"
2032
+ },
2033
+ {
2034
+ "name": "values",
2035
+ "type": "string[]",
2036
+ "internalType": "string[]"
790
2037
  }
791
2038
  ],
792
2039
  "stateMutability": "view"
@@ -799,6 +2046,11 @@ var REGISTRY_ABI = [
799
2046
  "name": "index",
800
2047
  "type": "uint256",
801
2048
  "internalType": "uint256"
2049
+ },
2050
+ {
2051
+ "name": "reason",
2052
+ "type": "string",
2053
+ "internalType": "string"
802
2054
  }
803
2055
  ],
804
2056
  "outputs": [],
@@ -818,13 +2070,18 @@ var REGISTRY_ABI = [
818
2070
  "type": "uint256",
819
2071
  "internalType": "uint256"
820
2072
  },
2073
+ {
2074
+ "name": "reason",
2075
+ "type": "string",
2076
+ "internalType": "string"
2077
+ },
821
2078
  {
822
2079
  "name": "deadline",
823
2080
  "type": "uint256",
824
2081
  "internalType": "uint256"
825
2082
  },
826
2083
  {
827
- "name": "signature",
2084
+ "name": "permission",
828
2085
  "type": "bytes",
829
2086
  "internalType": "bytes"
830
2087
  }
@@ -843,13 +2100,13 @@ var REGISTRY_ABI = [
843
2100
  },
844
2101
  {
845
2102
  "name": "kind",
846
- "type": "bytes32",
847
- "internalType": "bytes32"
2103
+ "type": "string",
2104
+ "internalType": "string"
848
2105
  },
849
2106
  {
850
2107
  "name": "value",
851
- "type": "bytes",
852
- "internalType": "bytes"
2108
+ "type": "string",
2109
+ "internalType": "string"
853
2110
  }
854
2111
  ],
855
2112
  "outputs": [],
@@ -871,13 +2128,13 @@ var REGISTRY_ABI = [
871
2128
  },
872
2129
  {
873
2130
  "name": "kind",
874
- "type": "bytes32",
875
- "internalType": "bytes32"
2131
+ "type": "string",
2132
+ "internalType": "string"
876
2133
  },
877
2134
  {
878
2135
  "name": "value",
879
- "type": "bytes",
880
- "internalType": "bytes"
2136
+ "type": "string",
2137
+ "internalType": "string"
881
2138
  },
882
2139
  {
883
2140
  "name": "deadline",
@@ -885,7 +2142,7 @@ var REGISTRY_ABI = [
885
2142
  "internalType": "uint256"
886
2143
  },
887
2144
  {
888
- "name": "signature",
2145
+ "name": "permission",
889
2146
  "type": "bytes",
890
2147
  "internalType": "bytes"
891
2148
  }
@@ -893,6 +2150,83 @@ var REGISTRY_ABI = [
893
2150
  "outputs": [],
894
2151
  "stateMutability": "nonpayable"
895
2152
  },
2153
+ {
2154
+ "type": "function",
2155
+ "name": "signatureBytes",
2156
+ "inputs": [
2157
+ {
2158
+ "name": "owner",
2159
+ "type": "address",
2160
+ "internalType": "address"
2161
+ },
2162
+ {
2163
+ "name": "index",
2164
+ "type": "uint256",
2165
+ "internalType": "uint256"
2166
+ }
2167
+ ],
2168
+ "outputs": [
2169
+ {
2170
+ "name": "signature",
2171
+ "type": "bytes",
2172
+ "internalType": "bytes"
2173
+ }
2174
+ ],
2175
+ "stateMutability": "view"
2176
+ },
2177
+ {
2178
+ "type": "function",
2179
+ "name": "statementFor",
2180
+ "inputs": [
2181
+ {
2182
+ "name": "owner",
2183
+ "type": "address",
2184
+ "internalType": "address"
2185
+ }
2186
+ ],
2187
+ "outputs": [
2188
+ {
2189
+ "name": "",
2190
+ "type": "string",
2191
+ "internalType": "string"
2192
+ }
2193
+ ],
2194
+ "stateMutability": "pure"
2195
+ },
2196
+ {
2197
+ "type": "function",
2198
+ "name": "summary",
2199
+ "inputs": [
2200
+ {
2201
+ "name": "owner",
2202
+ "type": "address",
2203
+ "internalType": "address"
2204
+ }
2205
+ ],
2206
+ "outputs": [
2207
+ {
2208
+ "name": "total",
2209
+ "type": "uint256",
2210
+ "internalType": "uint256"
2211
+ },
2212
+ {
2213
+ "name": "active",
2214
+ "type": "uint256",
2215
+ "internalType": "uint256"
2216
+ },
2217
+ {
2218
+ "name": "hasCurrent",
2219
+ "type": "bool",
2220
+ "internalType": "bool"
2221
+ },
2222
+ {
2223
+ "name": "currentIndex",
2224
+ "type": "uint256",
2225
+ "internalType": "uint256"
2226
+ }
2227
+ ],
2228
+ "stateMutability": "view"
2229
+ },
896
2230
  {
897
2231
  "type": "function",
898
2232
  "name": "updateKey",
@@ -903,7 +2237,7 @@ var REGISTRY_ABI = [
903
2237
  "internalType": "uint256"
904
2238
  },
905
2239
  {
906
- "name": "pgpPublicKey",
2240
+ "name": "key",
907
2241
  "type": "bytes",
908
2242
  "internalType": "bytes"
909
2243
  }
@@ -926,7 +2260,7 @@ var REGISTRY_ABI = [
926
2260
  "internalType": "uint256"
927
2261
  },
928
2262
  {
929
- "name": "pgpPublicKey",
2263
+ "name": "key",
930
2264
  "type": "bytes",
931
2265
  "internalType": "bytes"
932
2266
  },
@@ -936,7 +2270,7 @@ var REGISTRY_ABI = [
936
2270
  "internalType": "uint256"
937
2271
  },
938
2272
  {
939
- "name": "signature",
2273
+ "name": "permission",
940
2274
  "type": "bytes",
941
2275
  "internalType": "bytes"
942
2276
  }
@@ -973,22 +2307,16 @@ var REGISTRY_ABI = [
973
2307
  "internalType": "bytes"
974
2308
  },
975
2309
  {
976
- "name": "messageVersion",
977
- "type": "uint8",
978
- "indexed": false,
979
- "internalType": "uint8"
980
- },
981
- {
982
- "name": "keyPtr",
2310
+ "name": "payload",
983
2311
  "type": "address",
984
2312
  "indexed": false,
985
2313
  "internalType": "address"
986
2314
  },
987
2315
  {
988
- "name": "sigPtr",
989
- "type": "address",
2316
+ "name": "messageVersion",
2317
+ "type": "uint8",
990
2318
  "indexed": false,
991
- "internalType": "address"
2319
+ "internalType": "uint8"
992
2320
  },
993
2321
  {
994
2322
  "name": "submitter",
@@ -1022,13 +2350,13 @@ var REGISTRY_ABI = [
1022
2350
  "internalType": "uint256"
1023
2351
  },
1024
2352
  {
1025
- "name": "oldKeyPtr",
2353
+ "name": "oldPayload",
1026
2354
  "type": "address",
1027
2355
  "indexed": false,
1028
2356
  "internalType": "address"
1029
2357
  },
1030
2358
  {
1031
- "name": "newKeyPtr",
2359
+ "name": "newPayload",
1032
2360
  "type": "address",
1033
2361
  "indexed": false,
1034
2362
  "internalType": "address"
@@ -1078,11 +2406,23 @@ var REGISTRY_ABI = [
1078
2406
  "internalType": "uint256"
1079
2407
  },
1080
2408
  {
1081
- "name": "kind",
2409
+ "name": "kindHash",
1082
2410
  "type": "bytes32",
1083
2411
  "indexed": true,
1084
2412
  "internalType": "bytes32"
1085
2413
  },
2414
+ {
2415
+ "name": "kind",
2416
+ "type": "string",
2417
+ "indexed": false,
2418
+ "internalType": "string"
2419
+ },
2420
+ {
2421
+ "name": "value",
2422
+ "type": "string",
2423
+ "indexed": false,
2424
+ "internalType": "string"
2425
+ },
1086
2426
  {
1087
2427
  "name": "submitter",
1088
2428
  "type": "address",
@@ -1094,7 +2434,7 @@ var REGISTRY_ABI = [
1094
2434
  },
1095
2435
  {
1096
2436
  "type": "event",
1097
- "name": "Revoked",
2437
+ "name": "RecordsMoved",
1098
2438
  "inputs": [
1099
2439
  {
1100
2440
  "name": "owner",
@@ -1103,924 +2443,697 @@ var REGISTRY_ABI = [
1103
2443
  "internalType": "address"
1104
2444
  },
1105
2445
  {
1106
- "name": "fingerprintHash",
1107
- "type": "bytes32",
2446
+ "name": "fromIndex",
2447
+ "type": "uint256",
1108
2448
  "indexed": true,
1109
- "internalType": "bytes32"
2449
+ "internalType": "uint256"
1110
2450
  },
1111
2451
  {
1112
- "name": "index",
2452
+ "name": "toIndex",
1113
2453
  "type": "uint256",
1114
2454
  "indexed": true,
1115
2455
  "internalType": "uint256"
1116
- },
1117
- {
1118
- "name": "submitter",
1119
- "type": "address",
1120
- "indexed": false,
1121
- "internalType": "address"
1122
2456
  }
1123
2457
  ],
1124
2458
  "anonymous": false
1125
2459
  },
1126
2460
  {
1127
- "type": "error",
1128
- "name": "AlreadyRevoked",
1129
- "inputs": []
1130
- },
1131
- {
1132
- "type": "error",
1133
- "name": "AuthorizationExpired",
1134
- "inputs": []
1135
- },
1136
- {
1137
- "type": "error",
1138
- "name": "DeploymentFailed",
1139
- "inputs": []
1140
- },
1141
- {
1142
- "type": "error",
1143
- "name": "DuplicateActiveFingerprint",
1144
- "inputs": []
1145
- },
1146
- {
1147
- "type": "error",
1148
- "name": "EmptyPublicKey",
1149
- "inputs": []
1150
- },
1151
- {
1152
- "type": "error",
1153
- "name": "EmptySignature",
1154
- "inputs": []
1155
- },
1156
- {
1157
- "type": "error",
1158
- "name": "IndexOutOfBounds",
1159
- "inputs": []
1160
- },
1161
- {
1162
- "type": "error",
1163
- "name": "InvalidAuthorization",
1164
- "inputs": []
1165
- },
1166
- {
1167
- "type": "error",
1168
- "name": "InvalidFingerprintLength",
1169
- "inputs": []
1170
- },
1171
- {
1172
- "type": "error",
1173
- "name": "InvalidPointer",
1174
- "inputs": []
1175
- },
1176
- {
1177
- "type": "error",
1178
- "name": "PublicKeyTooLarge",
1179
- "inputs": []
1180
- },
1181
- {
1182
- "type": "error",
1183
- "name": "RecordTooLarge",
1184
- "inputs": []
1185
- },
1186
- {
1187
- "type": "error",
1188
- "name": "SignatureTooLarge",
1189
- "inputs": []
1190
- }
1191
- ];
1192
-
1193
- // src/core/contract.ts
1194
- var _chains = require('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 _chains.sepolia;
1236
- if (network === "local") return _chains.foundry;
1237
- return _chains.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
- var _viem = require('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 _viem.keccak256.call(void 0, 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([..._nullishCoalesce(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 (e) {
1308
- return String(_nullishCoalesce(_optionalChain([keyOrSubkey, 'access', _ => _.keyPacket, 'optionalAccess', _2 => _2.algorithm]), () => ( "unknown")));
1309
- }
1310
- }
1311
- async function parsePgpKey(armoredKey) {
1312
- try {
1313
- const openpgp = await Promise.resolve().then(() => _interopRequireWildcard(require("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 = _nullishCoalesce(_optionalChain([key, 'access', _3 => _3.keyPacket, 'access', _4 => _4.created, 'optionalAccess', _5 => _5.toISOString, 'call', _6 => _6()]), () => ( 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 (e2) {
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
- }
2461
+ "type": "event",
2462
+ "name": "Revoked",
2463
+ "inputs": [
2464
+ {
2465
+ "name": "owner",
2466
+ "type": "address",
2467
+ "indexed": true,
2468
+ "internalType": "address"
2469
+ },
2470
+ {
2471
+ "name": "fingerprintHash",
2472
+ "type": "bytes32",
2473
+ "indexed": true,
2474
+ "internalType": "bytes32"
2475
+ },
2476
+ {
2477
+ "name": "index",
2478
+ "type": "uint256",
2479
+ "indexed": true,
2480
+ "internalType": "uint256"
2481
+ },
2482
+ {
2483
+ "name": "reason",
2484
+ "type": "string",
2485
+ "indexed": false,
2486
+ "internalType": "string"
2487
+ },
2488
+ {
2489
+ "name": "replacedBy",
2490
+ "type": "uint256",
2491
+ "indexed": false,
2492
+ "internalType": "uint256"
2493
+ },
2494
+ {
2495
+ "name": "submitter",
2496
+ "type": "address",
2497
+ "indexed": false,
2498
+ "internalType": "address"
1357
2499
  }
1358
- if (userVerified) {
1359
- const uid = _optionalChain([user, 'access', _7 => _7.userID, 'optionalAccess', _8 => _8.userID]);
1360
- if (uid) userIDs.push(uid);
2500
+ ],
2501
+ "anonymous": false
2502
+ },
2503
+ {
2504
+ "type": "error",
2505
+ "name": "AlreadyRevoked",
2506
+ "inputs": [
2507
+ {
2508
+ "name": "index",
2509
+ "type": "uint256",
2510
+ "internalType": "uint256"
1361
2511
  }
1362
- }
1363
- const subkeys = key.subkeys.map((sk) => ({
1364
- algorithm: algorithmName(sk),
1365
- created: _nullishCoalesce(_optionalChain([sk, 'access', _9 => _9.keyPacket, 'access', _10 => _10.created, 'optionalAccess', _11 => _11.toISOString, 'call', _12 => _12()]), () => ( null)),
1366
- fingerprint: sk.getFingerprint().toUpperCase()
1367
- }));
1368
- return { fingerprint, userIDs, algorithm, created, expires, notations, subkeys };
1369
- } catch (e3) {
1370
- return null;
1371
- }
1372
- }
1373
- async function verifyClearsigned({ armoredKey, clearsigned }) {
1374
- try {
1375
- const openpgp = await Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
1376
- const { readKey, readCleartextMessage, LiteralDataPacket } = openpgp;
1377
- const config = pgpConfig(openpgp);
1378
- const publicKey = await readKey({ armoredKey });
1379
- const message = await readCleartextMessage({ cleartextMessage: clearsigned });
1380
- const msg = message;
1381
- const now = /* @__PURE__ */ new Date();
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(_nullishCoalesce(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
- var REVOCATION_REASON = {
1396
- // 0 = "no reason specified", gpg's default: say nothing rather than "(reason: no reason given)"
1397
- 1: "replaced by a newer key",
1398
- 2: "compromised",
1399
- 3: "no longer used",
1400
- 32: "a user ID is no longer valid"
1401
- };
1402
- var iso = (d) => d instanceof Date ? d.toISOString() : typeof d === "number" && Number.isFinite(d) ? new Date(d).toISOString() : null;
1403
- function revocationOf(sigs) {
1404
- const sig = [..._nullishCoalesce(sigs, () => ( []))].sort((a, b) => (_nullishCoalesce(_optionalChain([b, 'access', _13 => _13.created, 'optionalAccess', _14 => _14.getTime, 'optionalCall', _15 => _15()]), () => ( 0))) - (_nullishCoalesce(_optionalChain([a, 'access', _16 => _16.created, 'optionalAccess', _17 => _17.getTime, 'optionalCall', _18 => _18()]), () => ( 0))))[0];
1405
- const flag = _nullishCoalesce(_optionalChain([sig, 'optionalAccess', _19 => _19.reasonForRevocationFlag]), () => ( null));
1406
- return {
1407
- at: iso(_optionalChain([sig, 'optionalAccess', _20 => _20.created])),
1408
- compromised: flag === 2,
1409
- revocationReason: _optionalChain([sig, 'optionalAccess', _21 => _21.reasonForRevocationString]) || (flag !== null ? _nullishCoalesce(REVOCATION_REASON[flag], () => ( null)) : null)
1410
- };
1411
- }
1412
- async function keyLife(openpgp, key, clearsigned, config) {
1413
- const now = /* @__PURE__ */ new Date();
1414
- let issuer = null;
1415
- try {
1416
- issuer = await _asyncNullishCoalesce(await _asyncOptionalChain([(await openpgp.readCleartextMessage({ cleartextMessage: clearsigned })), 'access', async _22 => _22.signature, 'access', async _23 => _23.packets, 'access', async _24 => _24[0], 'optionalAccess', async _25 => _25.issuerKeyID]), async () => ( null));
1417
- } catch (e4) {
1418
- }
1419
- const signer = issuer && !key.getKeyID().equals(issuer) ? _nullishCoalesce(key.subkeys.find((s) => s.getKeyID().equals(issuer)), () => ( null)) : key;
1420
- const signingKey = signer ? signer.getFingerprint().toUpperCase() : null;
1421
- const safe = async (f, fallback) => {
1422
- try {
1423
- return await f();
1424
- } catch (e5) {
1425
- return fallback;
1426
- }
1427
- };
1428
- const keyRevoked = await safe(() => key.isRevoked(void 0, void 0, now, config), false);
1429
- const keyExp = await safe(() => key.getExpirationTime(void 0, config), null);
1430
- const isSub = signer && signer !== key;
1431
- const subRevoked = isSub ? await safe(() => signer.isRevoked(null, key.keyPacket, now, config), false) : false;
1432
- const subExp = isSub ? await safe(() => signer.getExpirationTime(null, config), null) : null;
1433
- const finite = (d) => d instanceof Date && Number.isFinite(d.getTime()) ? d : null;
1434
- const kExp = finite(keyExp), sExp = finite(subExp);
1435
- let problem = null;
1436
- if (keyRevoked) {
1437
- const r = revocationOf(key.revocationSignatures);
1438
- problem = { kind: r.compromised ? "compromised" : "revoked", at: r.at, revocationReason: r.revocationReason };
1439
- } else if (kExp && kExp <= now) {
1440
- problem = { kind: "expired", at: kExp.toISOString() };
1441
- } else if (subRevoked) {
1442
- const r = revocationOf(signer.revocationSignatures);
1443
- problem = { kind: r.compromised ? "compromised" : "signing-key-revoked", at: r.at, revocationReason: r.revocationReason };
1444
- } else if (sExp && sExp <= now) {
1445
- problem = { kind: "signing-key-expired", at: sExp.toISOString() };
1446
- }
1447
- const earliest = [kExp, sExp].filter(Boolean).sort((a, b) => a - b)[0];
1448
- return { problem, signingKey, expiresAt: earliest ? earliest.toISOString() : null, algorithm: algorithmName(_nullishCoalesce(signer, () => ( key))) };
1449
- }
1450
- async function verifyAttestation({
1451
- pgpPublicKey,
1452
- pgpSignature,
1453
- fingerprint,
1454
- ethAddress
1455
- }) {
1456
- try {
1457
- if (!pgpPublicKey || !pgpSignature) {
1458
- return { verified: false, reason: "Missing PGP data", kind: "bad-signature" };
1459
- }
1460
- const openpgp = await Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
1461
- const { readKey } = openpgp;
1462
- const publicKey = await readKey({ armoredKey: pgpPublicKey });
1463
- const keyFingerprint = publicKey.getFingerprint().toUpperCase();
1464
- if (keyFingerprint !== fingerprint.toUpperCase()) {
1465
- return { verified: false, reason: "Key fingerprint mismatch", kind: "bad-signature" };
1466
- }
1467
- const life = await keyLife(openpgp, publicKey, pgpSignature, pgpConfig(openpgp));
1468
- const v = await verifyClearsigned({ armoredKey: pgpPublicKey, clearsigned: pgpSignature });
1469
- if (!v.verified) {
1470
- if (life.problem) return { verified: false, reason: v.reason, signingKey: life.signingKey, ...life.problem };
1471
- if (/too weak|reject|unsupported|not supported|unknown (curve|algorithm)/i.test(v.reason || "")) {
1472
- return { verified: false, reason: v.reason, kind: "unsupported", algorithm: life.algorithm, signingKey: life.signingKey };
2512
+ ]
2513
+ },
2514
+ {
2515
+ "type": "error",
2516
+ "name": "BadArmorChecksum",
2517
+ "inputs": []
2518
+ },
2519
+ {
2520
+ "type": "error",
2521
+ "name": "BadBase64",
2522
+ "inputs": []
2523
+ },
2524
+ {
2525
+ "type": "error",
2526
+ "name": "ClaimActive",
2527
+ "inputs": [
2528
+ {
2529
+ "name": "index",
2530
+ "type": "uint256",
2531
+ "internalType": "uint256"
1473
2532
  }
1474
- return { verified: false, reason: v.reason, kind: "bad-signature", signingKey: life.signingKey };
1475
- }
1476
- const signedText = v.text;
1477
- if (!signedText.toLowerCase().includes(ethAddress.toLowerCase())) {
1478
- return { verified: false, reason: "Signed message does not contain ETH address", kind: "bad-signature", signingKey: life.signingKey };
1479
- }
1480
- return { verified: true, kind: "verified", signingKey: life.signingKey, expiresAt: life.expiresAt };
1481
- } catch (e6) {
1482
- return { verified: false, reason: "Signature verification failed", kind: "bad-signature" };
1483
- }
1484
- }
1485
- var EMAIL_UID = /@/;
1486
- async function stripEmailUserIDs(armoredKey) {
1487
- try {
1488
- const { readKey } = await Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
1489
- const key = await readKey({ armoredKey });
1490
- const kept = [];
1491
- const removed = [];
1492
- const users = key.users.filter((u) => {
1493
- const uid = _optionalChain([u, 'access', _26 => _26.userID, 'optionalAccess', _27 => _27.userID]);
1494
- if (!uid) return false;
1495
- if (EMAIL_UID.test(uid)) {
1496
- removed.push(uid);
1497
- return false;
2533
+ ]
2534
+ },
2535
+ {
2536
+ "type": "error",
2537
+ "name": "DeploymentFailed",
2538
+ "inputs": []
2539
+ },
2540
+ {
2541
+ "type": "error",
2542
+ "name": "DuplicateActiveFingerprint",
2543
+ "inputs": [
2544
+ {
2545
+ "name": "fingerprint",
2546
+ "type": "bytes",
2547
+ "internalType": "bytes"
1498
2548
  }
1499
- kept.push(uid);
1500
- return true;
1501
- });
1502
- if (users.length === 0) return null;
1503
- key.users = users;
1504
- return { armored: key.armor(), kept, removed };
1505
- } catch (e7) {
1506
- return null;
1507
- }
1508
- }
1509
- async function hasEmailUserID(armoredKey) {
1510
- try {
1511
- const { readKey } = await Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
1512
- const key = await readKey({ armoredKey });
1513
- return key.users.some((u) => EMAIL_UID.test(_nullishCoalesce(_optionalChain([u, 'access', _28 => _28.userID, 'optionalAccess', _29 => _29.userID]), () => ( ""))));
1514
- } catch (e8) {
1515
- return false;
1516
- }
1517
- }
1518
-
1519
- // src/core/efp.ts
1520
- var EFP_API = "https://api.ethfollow.xyz/api/v1";
1521
- async function fetchEFPGraph(address) {
1522
- try {
1523
- const [statsResp, listsResp] = await Promise.all([
1524
- fetch(`${EFP_API}/users/${address}/stats`),
1525
- fetch(`${EFP_API}/users/${address}/lists`)
1526
- ]);
1527
- if (!statsResp.ok && !listsResp.ok) return null;
1528
- const statsData = statsResp.ok ? await statsResp.json() : {};
1529
- const listsData = listsResp.ok ? await listsResp.json() : {};
1530
- const followers = parseInt(statsData.followers_count) || 0;
1531
- const listId = listsData.primary_list;
1532
- let following = 0;
1533
- let top8 = [];
1534
- if (listId) {
1535
- const [followingResp, top8Resp] = await Promise.all([
1536
- fetch(`${EFP_API}/lists/${listId}/following?limit=100`),
1537
- fetch(`${EFP_API}/lists/${listId}/following?limit=8&tags=top8`)
1538
- ]);
1539
- const followingData = followingResp.ok ? await followingResp.json() : { following: [] };
1540
- const top8Data = top8Resp.ok ? await top8Resp.json() : { following: [] };
1541
- following = (followingData.following || []).length;
1542
- top8 = (top8Data.following || []).map((f) => f.data);
1543
- }
1544
- return { followers, following, top8, hasEfp: !!listId || followers > 0 };
1545
- } catch (e9) {
1546
- return null;
1547
- }
1548
- }
1549
-
1550
- // src/core/proofs.ts
1551
- var PROVIDERS = [
2549
+ ]
2550
+ },
2551
+ {
2552
+ "type": "error",
2553
+ "name": "EmptyKey",
2554
+ "inputs": []
2555
+ },
2556
+ {
2557
+ "type": "error",
2558
+ "name": "EmptySignature",
2559
+ "inputs": []
2560
+ },
2561
+ {
2562
+ "type": "error",
2563
+ "name": "IndexOutOfBounds",
2564
+ "inputs": [
2565
+ {
2566
+ "name": "index",
2567
+ "type": "uint256",
2568
+ "internalType": "uint256"
2569
+ },
2570
+ {
2571
+ "name": "count",
2572
+ "type": "uint256",
2573
+ "internalType": "uint256"
2574
+ }
2575
+ ]
2576
+ },
2577
+ {
2578
+ "type": "error",
2579
+ "name": "InvalidFingerprint",
2580
+ "inputs": [
2581
+ {
2582
+ "name": "fingerprint",
2583
+ "type": "bytes",
2584
+ "internalType": "bytes"
2585
+ }
2586
+ ]
2587
+ },
2588
+ {
2589
+ "type": "error",
2590
+ "name": "InvalidFingerprintLength",
2591
+ "inputs": [
2592
+ {
2593
+ "name": "length",
2594
+ "type": "uint256",
2595
+ "internalType": "uint256"
2596
+ }
2597
+ ]
2598
+ },
2599
+ {
2600
+ "type": "error",
2601
+ "name": "InvalidKindName",
2602
+ "inputs": [
2603
+ {
2604
+ "name": "kind",
2605
+ "type": "string",
2606
+ "internalType": "string"
2607
+ }
2608
+ ]
2609
+ },
2610
+ {
2611
+ "type": "error",
2612
+ "name": "InvalidPermission",
2613
+ "inputs": []
2614
+ },
2615
+ {
2616
+ "type": "error",
2617
+ "name": "InvalidPointer",
2618
+ "inputs": []
2619
+ },
2620
+ {
2621
+ "type": "error",
2622
+ "name": "KeyCompromised",
2623
+ "inputs": [
2624
+ {
2625
+ "name": "fingerprint",
2626
+ "type": "bytes",
2627
+ "internalType": "bytes"
2628
+ }
2629
+ ]
2630
+ },
1552
2631
  {
1553
- provider: "github",
1554
- label: "GitHub",
1555
- pattern: /^https:\/\/gist\.github\.com\/([^/]+)\/([a-f0-9]+)$/i,
1556
- parse: (m) => ({ user: m[1], gistId: m[2] })
2632
+ "type": "error",
2633
+ "name": "KeyStillActive",
2634
+ "inputs": [
2635
+ {
2636
+ "name": "fingerprint",
2637
+ "type": "bytes",
2638
+ "internalType": "bytes"
2639
+ }
2640
+ ]
1557
2641
  },
1558
2642
  {
1559
- // A repository's description — the form an organisation can use, since
1560
- // gists belong to user accounts only. Same shape as the Codeberg proof.
1561
- provider: "github",
1562
- label: "GitHub",
1563
- pattern: /^https:\/\/github\.com\/([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+)$/i,
1564
- parse: (m) => ({ user: m[1], repo: m[2] })
2643
+ "type": "error",
2644
+ "name": "KeyTooLarge",
2645
+ "inputs": [
2646
+ {
2647
+ "name": "size",
2648
+ "type": "uint256",
2649
+ "internalType": "uint256"
2650
+ },
2651
+ {
2652
+ "name": "max",
2653
+ "type": "uint256",
2654
+ "internalType": "uint256"
2655
+ }
2656
+ ]
1565
2657
  },
1566
2658
  {
1567
- provider: "dns",
1568
- label: "DNS",
1569
- // domain is restricted to a hostname (labels may include underscores for
1570
- // records like _thurin.example.com); rejects slashes, userinfo, and spaces.
1571
- pattern: /^dns:([a-z0-9._-]+)\?type=TXT$/i,
1572
- parse: (m) => ({ domain: m[1] })
2659
+ "type": "error",
2660
+ "name": "NotAKey",
2661
+ "inputs": [
2662
+ {
2663
+ "name": "firstByte",
2664
+ "type": "bytes1",
2665
+ "internalType": "bytes1"
2666
+ }
2667
+ ]
1573
2668
  },
1574
2669
  {
1575
- provider: "farcaster",
1576
- label: "Farcaster",
1577
- pattern: /^https:\/\/farcaster\.xyz\/([^/]+)\/(0x[a-f0-9]+)$/i,
1578
- parse: (m) => ({ user: m[1], castHash: m[2] })
2670
+ "type": "error",
2671
+ "name": "NotASignature",
2672
+ "inputs": [
2673
+ {
2674
+ "name": "firstByte",
2675
+ "type": "bytes1",
2676
+ "internalType": "bytes1"
2677
+ }
2678
+ ]
1579
2679
  },
1580
2680
  {
1581
- provider: "codeberg",
1582
- label: "Codeberg",
1583
- pattern: /^https:\/\/codeberg\.org\/([^/]+)\/([^/]+)$/i,
1584
- parse: (m) => ({ user: m[1], repo: m[2] })
2681
+ "type": "error",
2682
+ "name": "NotArmored",
2683
+ "inputs": []
1585
2684
  },
1586
2685
  {
1587
- provider: "mastodon",
1588
- label: "Mastodon",
1589
- // instance is restricted to a bare hostname (optional port) so a value
1590
- // like "mastodon.social@evil.com" can't redirect the lookup elsewhere.
1591
- pattern: /^https:\/\/([a-z0-9.-]+(?::\d+)?)\/@([^/@?#\s]+)$/i,
1592
- parse: (m) => ({ instance: m[1], user: m[2] })
1593
- }
1594
- ];
1595
- function identifyProof(notation) {
1596
- if (notation.name !== "proof@thurin.id") return null;
1597
- for (const { provider, label, pattern, parse } of PROVIDERS) {
1598
- const m = notation.value.match(pattern);
1599
- if (m) {
1600
- return { provider, label, url: notation.value, ...parse(m) };
1601
- }
1602
- }
1603
- return { provider: "unknown", label: "Unknown", url: notation.value };
1604
- }
1605
- function displayUrl(proof) {
1606
- if (proof.provider === "dns") return proof.domain;
1607
- if (proof.provider === "github") return proof.user;
1608
- if (proof.provider === "farcaster") return `@${proof.user}`;
1609
- if (proof.provider === "codeberg") return proof.user;
1610
- if (proof.provider === "mastodon") return `@${proof.user}@${proof.instance}`;
1611
- return proof.url;
1612
- }
1613
- function proofHref(proof) {
1614
- if (proof.provider === "dns") return `https://${proof.domain}`;
1615
- if (proof.provider === "github") return `https://github.com/${proof.user}`;
1616
- if (proof.provider === "farcaster") return `https://farcaster.xyz/${proof.user}`;
1617
- if (proof.provider === "codeberg") return `https://codeberg.org/${proof.user}`;
1618
- if (proof.provider === "mastodon") return `https://${proof.instance}/@${proof.user}`;
1619
- if (proof.url.startsWith("http")) return proof.url;
1620
- return null;
1621
- }
1622
- function proofSecondaryHref(proof) {
1623
- if (proof.provider === "github") return proof.url;
1624
- if (proof.provider === "farcaster") return proof.url;
1625
- if (proof.provider === "codeberg") return proof.url;
1626
- if (proof.provider === "mastodon") return proof.url;
1627
- return null;
1628
- }
1629
- var FPR_TOKEN = "OPENPGP4FPR:";
1630
- function containsFingerprint(text, fingerprint) {
1631
- return text.toUpperCase().includes(FPR_TOKEN + fingerprint.toUpperCase());
1632
- }
1633
- function containsFingerprintUrl(text, fingerprint) {
1634
- return text.toUpperCase().includes(fingerprint.toUpperCase());
1635
- }
1636
- async function verifyGitHub(proof, fingerprint) {
1637
- if (proof.repo) return verifyGitHubRepo(proof, fingerprint);
1638
- try {
1639
- const resp = await fetch(`https://api.github.com/gists/${proof.gistId}`);
1640
- if (!resp.ok) return { verified: false, reason: `GitHub API returned ${resp.status}` };
1641
- const data = await resp.json();
1642
- if (_optionalChain([data, 'access', _30 => _30.owner, 'optionalAccess', _31 => _31.login, 'optionalAccess', _32 => _32.toLowerCase, 'call', _33 => _33()]) !== proof.user.toLowerCase()) {
1643
- return { verified: false, reason: "Gist owner does not match claimed user" };
1644
- }
1645
- for (const file of Object.values(data.files || {})) {
1646
- if (file.content && containsFingerprint(file.content, fingerprint)) {
1647
- return { verified: true };
2686
+ "type": "error",
2687
+ "name": "PayloadTooLarge",
2688
+ "inputs": [
2689
+ {
2690
+ "name": "size",
2691
+ "type": "uint256",
2692
+ "internalType": "uint256"
2693
+ },
2694
+ {
2695
+ "name": "max",
2696
+ "type": "uint256",
2697
+ "internalType": "uint256"
1648
2698
  }
1649
- }
1650
- return { verified: false, reason: "Fingerprint token not found in gist" };
1651
- } catch (err) {
1652
- return { verified: false, reason: `GitHub fetch failed: ${err.message}` };
1653
- }
1654
- }
1655
- async function verifyGitHubRepo(proof, fingerprint) {
1656
- try {
1657
- const resp = await fetch(
1658
- `https://api.github.com/repos/${encodeURIComponent(proof.user)}/${encodeURIComponent(proof.repo)}`
1659
- );
1660
- if (!resp.ok) return { verified: false, reason: `GitHub API returned ${resp.status}` };
1661
- const data = await resp.json();
1662
- if (_optionalChain([data, 'access', _34 => _34.owner, 'optionalAccess', _35 => _35.login, 'optionalAccess', _36 => _36.toLowerCase, 'call', _37 => _37()]) !== proof.user.toLowerCase()) {
1663
- return { verified: false, reason: "Repository owner does not match claimed account" };
1664
- }
1665
- if (data.description && containsFingerprint(data.description, fingerprint)) {
1666
- return { verified: true };
1667
- }
1668
- return { verified: false, reason: "Fingerprint token not found in repository description" };
1669
- } catch (err) {
1670
- return { verified: false, reason: `GitHub fetch failed: ${err.message}` };
1671
- }
1672
- }
1673
- async function verifyDNS(proof, fingerprint) {
1674
- try {
1675
- const resp = await fetch(
1676
- `https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(proof.domain)}&type=TXT`,
1677
- { headers: { Accept: "application/dns-json" } }
1678
- );
1679
- if (!resp.ok) return { verified: false, reason: `DNS query returned ${resp.status}` };
1680
- const data = await resp.json();
1681
- for (const answer of data.Answer || []) {
1682
- if (answer.type !== 16) continue;
1683
- if (answer.data && containsFingerprint(answer.data, fingerprint)) {
1684
- return { verified: true };
2699
+ ]
2700
+ },
2701
+ {
2702
+ "type": "error",
2703
+ "name": "PermissionExpired",
2704
+ "inputs": [
2705
+ {
2706
+ "name": "deadline",
2707
+ "type": "uint256",
2708
+ "internalType": "uint256"
1685
2709
  }
1686
- }
1687
- return { verified: false, reason: "Fingerprint token not found in TXT records" };
1688
- } catch (err) {
1689
- return { verified: false, reason: `DNS fetch failed: ${err.message}` };
1690
- }
1691
- }
1692
- var FARCASTER_HUB = "https://haatz.quilibrium.com";
1693
- var NEYNAR_HUB = "https://hub-api.neynar.com";
1694
- function farcasterSource(opts) {
1695
- if (opts.farcasterHub) return { base: opts.farcasterHub.replace(/\/+$/, ""), headers: {} };
1696
- if (opts.neynarApiKey) return { base: NEYNAR_HUB, headers: { "x-api-key": opts.neynarApiKey } };
1697
- return { base: FARCASTER_HUB, headers: {} };
1698
- }
1699
- async function verifyFarcaster(proof, fingerprint, opts = {}) {
1700
- const { base, headers } = farcasterSource(opts);
1701
- const host = base.replace(/^https?:\/\//, "");
1702
- try {
1703
- const nameResp = await fetch(`${base}/v1/userNameProofByName?name=${encodeURIComponent(proof.user)}`, { headers });
1704
- if (nameResp.status === 404) return { verified: false, reason: `Could not resolve Farcaster user "${proof.user}"` };
1705
- if (!nameResp.ok) return { verified: false, reason: `Couldn't check: the Farcaster node (${host}) returned ${nameResp.status}` };
1706
- const fid = (await nameResp.json()).fid;
1707
- if (!fid) return { verified: false, reason: `Could not resolve Farcaster user "${proof.user}"` };
1708
- let pageToken = "";
1709
- for (let page = 0; page < 5; page++) {
1710
- const url = `${base}/v1/castsByFid?fid=${fid}&pageSize=100&reverse=true${pageToken ? `&pageToken=${pageToken}` : ""}`;
1711
- const resp = await fetch(url, { headers });
1712
- if (!resp.ok) return { verified: false, reason: `Couldn't check: the Farcaster node (${host}) returned ${resp.status}` };
1713
- const data = await resp.json();
1714
- for (const msg of data.messages || []) {
1715
- if (msg.hash && msg.hash.startsWith(proof.castHash)) {
1716
- const text = _optionalChain([msg, 'access', _38 => _38.data, 'optionalAccess', _39 => _39.castAddBody, 'optionalAccess', _40 => _40.text]) || "";
1717
- if (containsFingerprint(text, fingerprint)) {
1718
- return { verified: true };
1719
- }
1720
- }
2710
+ ]
2711
+ },
2712
+ {
2713
+ "type": "error",
2714
+ "name": "RecordTooLarge",
2715
+ "inputs": [
2716
+ {
2717
+ "name": "size",
2718
+ "type": "uint256",
2719
+ "internalType": "uint256"
2720
+ },
2721
+ {
2722
+ "name": "max",
2723
+ "type": "uint256",
2724
+ "internalType": "uint256"
1721
2725
  }
1722
- if (!data.nextPageToken) break;
1723
- pageToken = data.nextPageToken;
1724
- }
1725
- return { verified: false, reason: "Cast not found" };
1726
- } catch (err) {
1727
- return { verified: false, reason: `Couldn't check: the Farcaster node (${host}) didn't answer (${err.message})` };
1728
- }
1729
- }
1730
- async function verifyCodeberg(proof, fingerprint) {
1731
- try {
1732
- const resp = await fetch(
1733
- `https://codeberg.org/api/v1/repos/${encodeURIComponent(proof.user)}/${encodeURIComponent(proof.repo)}`
1734
- );
1735
- if (!resp.ok) return { verified: false, reason: `Codeberg API returned ${resp.status}` };
1736
- const data = await resp.json();
1737
- if (data.description && containsFingerprint(data.description, fingerprint)) {
1738
- return { verified: true };
1739
- }
1740
- return { verified: false, reason: "Fingerprint token not found in repo description" };
1741
- } catch (err) {
1742
- return { verified: false, reason: `Codeberg fetch failed: ${err.message}` };
1743
- }
1744
- }
1745
- async function verifyMastodon(proof, fingerprint) {
1746
- try {
1747
- if (!proof.instance || !/^[a-z0-9.-]+(?::\d+)?$/i.test(proof.instance)) {
1748
- return { verified: false, reason: "Invalid Mastodon instance host" };
1749
- }
1750
- const resp = await fetch(
1751
- `https://${proof.instance}/api/v1/accounts/lookup?acct=${encodeURIComponent(proof.user)}`
1752
- );
1753
- if (!resp.ok) return { verified: false, reason: `Mastodon API returned ${resp.status}` };
1754
- const data = await resp.json();
1755
- const keyId = keyIdHex(fingerprint.replace(/^0x/i, "").replace(/\s+/g, "").toLowerCase());
1756
- for (const field of data.fields || []) {
1757
- const text = field.value.replace(/<[^>]*>/g, "");
1758
- if (containsFingerprintUrl(text, fingerprint) || containsFingerprintUrl(text, keyId)) {
1759
- return { verified: true };
2726
+ ]
2727
+ },
2728
+ {
2729
+ "type": "error",
2730
+ "name": "SignatureTooLarge",
2731
+ "inputs": [
2732
+ {
2733
+ "name": "size",
2734
+ "type": "uint256",
2735
+ "internalType": "uint256"
2736
+ },
2737
+ {
2738
+ "name": "max",
2739
+ "type": "uint256",
2740
+ "internalType": "uint256"
1760
2741
  }
1761
- }
1762
- if (data.note) {
1763
- const text = data.note.replace(/<[^>]*>/g, "");
1764
- if (containsFingerprintUrl(text, fingerprint) || containsFingerprintUrl(text, keyId)) {
1765
- return { verified: true };
2742
+ ]
2743
+ },
2744
+ {
2745
+ "type": "error",
2746
+ "name": "SupersededIsSetByReattest",
2747
+ "inputs": []
2748
+ },
2749
+ {
2750
+ "type": "error",
2751
+ "name": "TooManyClaims",
2752
+ "inputs": []
2753
+ },
2754
+ {
2755
+ "type": "error",
2756
+ "name": "UnknownRevokeReason",
2757
+ "inputs": [
2758
+ {
2759
+ "name": "reason",
2760
+ "type": "string",
2761
+ "internalType": "string"
1766
2762
  }
1767
- }
1768
- return { verified: false, reason: "Fingerprint not found in profile fields or bio" };
1769
- } catch (err) {
1770
- return { verified: false, reason: `Mastodon fetch failed: ${err.message}` };
2763
+ ]
2764
+ },
2765
+ {
2766
+ "type": "error",
2767
+ "name": "UnsupportedHeader",
2768
+ "inputs": []
1771
2769
  }
1772
- }
1773
- var verifiers = {
1774
- github: verifyGitHub,
1775
- dns: verifyDNS,
1776
- farcaster: verifyFarcaster,
1777
- codeberg: verifyCodeberg,
1778
- mastodon: verifyMastodon
1779
- };
1780
- async function verifyProof(proof, fingerprint, opts) {
1781
- const fn = verifiers[proof.provider];
1782
- if (!fn) return { verified: false, reason: "Unknown provider" };
1783
- return fn(proof, fingerprint, typeof opts === "string" ? { neynarApiKey: opts } : _nullishCoalesce(opts, () => ( {})));
1784
- }
2770
+ ];
1785
2771
 
1786
- // src/core/avatar.ts
1787
- var IPFS_GATEWAYS = ["https://ipfs.filebase.io/ipfs/", "https://gateway.pinata.cloud/ipfs/"];
1788
- var IPFS_GATEWAY = IPFS_GATEWAYS[0];
1789
- var ARWEAVE_GATEWAY = "https://arweave.net/";
1790
- function avatarUrl(uri) {
1791
- if (typeof uri !== "string") return null;
1792
- const u = uri.trim();
1793
- if (/^data:image\/(png|jpe?g|gif|webp|avif|svg\+xml)[;,]/i.test(u)) return u;
1794
- let m = u.match(/^ipfs:\/\/(?:ipfs\/)?([a-zA-Z0-9]{46,}(?:\/[^?#\s]*)?)$/);
1795
- if (m) return IPFS_GATEWAY + m[1];
1796
- m = u.match(/^ar:\/\/([a-zA-Z0-9_-]{43}(?:\/[^?#\s]*)?)$/);
1797
- if (m) return ARWEAVE_GATEWAY + m[1];
1798
- if (/^https:\/\/euc\.li\/[^?#\s]+$/.test(u)) return u;
1799
- m = u.match(/^https:\/\/[^/]+\/ipfs\/([a-zA-Z0-9]{46,}(?:\/[^?#\s]*)?)$/);
1800
- if (m) return IPFS_GATEWAY + m[1];
1801
- return null;
2772
+ // src/core/contract.ts
2773
+ var REGISTRY_ADDRESS = "0xFa6956c11163517249f8A67F5560a4406B519451";
2774
+ var NETWORKS = {
2775
+ mainnet: {
2776
+ chainId: 1,
2777
+ address: REGISTRY_ADDRESS,
2778
+ explorerUrl: "https://etherscan.io",
2779
+ defaultRpcUrl: "https://ethereum.publicnode.com"
2780
+ // resolves on more networks than ethereum-rpc.publicnode.com
2781
+ },
2782
+ sepolia: {
2783
+ chainId: 11155111,
2784
+ address: REGISTRY_ADDRESS,
2785
+ explorerUrl: "https://sepolia.etherscan.io",
2786
+ defaultRpcUrl: "https://ethereum-sepolia.publicnode.com"
2787
+ },
2788
+ /** A local anvil instance (`anvil`, chain id 31337). Deploy with pgp-registry's Deploy script. */
2789
+ local: {
2790
+ chainId: 31337,
2791
+ address: REGISTRY_ADDRESS,
2792
+ explorerUrl: "",
2793
+ defaultRpcUrl: "http://127.0.0.1:8545"
2794
+ }
2795
+ };
2796
+ function isNetworkName(value) {
2797
+ return value === "mainnet" || value === "sepolia" || value === "local";
1802
2798
  }
1803
- function avatarFallbacks(url) {
1804
- if (!url || !url.startsWith(IPFS_GATEWAYS[0])) return [];
1805
- const path = url.slice(IPFS_GATEWAYS[0].length);
1806
- return IPFS_GATEWAYS.slice(1).map((g) => g + path);
2799
+ function getRegistry(network = "mainnet", addressOverride) {
2800
+ const r = NETWORKS[network];
2801
+ if (!r) throw new Error(`Unknown network: ${network}`);
2802
+ if (addressOverride && /^0x[0-9a-fA-F]{40}$/.test(addressOverride)) {
2803
+ return { ...r, address: addressOverride };
2804
+ }
2805
+ return r;
1807
2806
  }
1808
- function parseNftAvatar(raw) {
1809
- const m = typeof raw === "string" && raw.trim().match(/^eip155:(\d+)\/(erc721|erc1155):(0x[0-9a-fA-F]{40})\/(\d+)$/i);
1810
- return m ? { chainId: Number(m[1]), standard: m[2].toLowerCase(), contract: m[3], tokenId: BigInt(m[4]) } : null;
2807
+ function chainFor(network = "mainnet") {
2808
+ if (network === "sepolia") return _chains.sepolia;
2809
+ if (network === "local") return _chains.foundry;
2810
+ return _chains.mainnet;
1811
2811
  }
1812
- var NFT_AVATAR_ABI = [
1813
- { type: "function", name: "tokenURI", stateMutability: "view", inputs: [{ type: "uint256" }], outputs: [{ type: "string" }] },
1814
- { type: "function", name: "uri", stateMutability: "view", inputs: [{ type: "uint256" }], outputs: [{ type: "string" }] }
1815
- ];
1816
- async function nftAvatarImage(tokenUri, tokenId, fetchFn = fetch) {
1817
- const uri = tokenUri.replace("{id}", tokenId.toString(16).padStart(64, "0"));
1818
- let meta;
1819
- const inline = uri.match(/^data:application\/json(;base64)?,([\s\S]*)$/);
1820
- if (inline) meta = JSON.parse(inline[1] ? atob(inline[2]) : decodeURIComponent(inline[2]));
1821
- else {
1822
- const url = uri.startsWith("data:") ? null : avatarUrl(uri);
1823
- if (!url) return null;
1824
- for (const candidate of [url, ...avatarFallbacks(url)]) {
1825
- try {
1826
- const res = await fetchFn(candidate);
1827
- if (res.ok) {
1828
- meta = await res.json();
1829
- break;
1830
- }
1831
- } catch (e10) {
1832
- }
2812
+
2813
+ // src/core/claims.ts
2814
+ var CLAIM_LIMIT = 50;
2815
+ async function readClaims(client, owner, { registry = REGISTRY_ADDRESS, limit = CLAIM_LIMIT } = {}) {
2816
+ const read = (functionName, args) => client.readContract({ address: registry, abi: REGISTRY_ABI, functionName, args });
2817
+ const rows = await read("claimsOf", [owner]);
2818
+ const first = Math.max(0, rows.length - limit);
2819
+ return Promise.all(rows.map(async (row, index) => {
2820
+ const revokedAt = Number(row.revokedAt);
2821
+ const claim = {
2822
+ index,
2823
+ fingerprint: bytesToFingerprint(row.fingerprint),
2824
+ createdAt: Number(row.createdAt),
2825
+ revoked: revokedAt !== 0,
2826
+ revokedAt: revokedAt || null,
2827
+ state: row.state,
2828
+ replacedBy: row.state === "replaced" ? Number(row.replacedBy) : null,
2829
+ revokeReason: row.revokeReason,
2830
+ messageVersion: Number(row.messageVersion),
2831
+ pgpPublicKey: null,
2832
+ pgpSignature: null,
2833
+ verification: null
2834
+ };
2835
+ if (index < first) return claim;
2836
+ const bytes = (fn) => read(fn, [owner, BigInt(index)]).catch(() => null);
2837
+ const [keyHex, sigHex] = await Promise.all([bytes("keyBytes"), bytes("signatureBytes")]);
2838
+ claim.pgpPublicKey = keyHex ? await payloadText(keyHex, "key") : null;
2839
+ claim.pgpSignature = sigHex ? await payloadText(sigHex, "signature") : null;
2840
+ claim.verification = await verifyAttestation({
2841
+ pgpPublicKey: claim.pgpPublicKey,
2842
+ pgpSignature: claim.pgpSignature,
2843
+ fingerprint: claim.fingerprint,
2844
+ ethAddress: owner
2845
+ });
2846
+ return claim;
2847
+ }));
2848
+ }
2849
+ function keyStanding(claims) {
2850
+ const active = claims.filter((c) => !c.revoked);
2851
+ const verified = active.filter((c) => _optionalChain([c, 'access', _78 => _78.verification, 'optionalAccess', _79 => _79.verified]));
2852
+ if (verified.length) return { kind: "verified", claim: verified[verified.length - 1] };
2853
+ if (active.length) return { kind: "not-counted", claim: active[active.length - 1] };
2854
+ if (claims.length) return { kind: "inactive", claim: claims[claims.length - 1] };
2855
+ return { kind: "none", claim: null };
2856
+ }
2857
+ async function findOwners(client, key, { registry = REGISTRY_ADDRESS } = {}) {
2858
+ const read = (functionName, args) => client.readContract({ address: registry, abi: REGISTRY_ABI, functionName, args });
2859
+ let fingerprints;
2860
+ if ("keyId" in key) {
2861
+ const keyId = keyIdToBytes(key.keyId);
2862
+ if (!keyId) return [];
2863
+ fingerprints = (await read("fingerprintsForKeyId", [keyId])).map(bytesToFingerprint);
2864
+ } else {
2865
+ const fp = normalizeFingerprint(key.fingerprint);
2866
+ if (!fp) return [];
2867
+ fingerprints = [fp];
2868
+ }
2869
+ const found = [];
2870
+ for (const fingerprint of fingerprints) {
2871
+ for (const owner of await read("ownersOf", [fingerprintToBytes(fingerprint)])) {
2872
+ if (!found.some((f) => f.owner.toLowerCase() === owner.toLowerCase() && f.fingerprint === fingerprint)) found.push({ owner, fingerprint });
1833
2873
  }
1834
- if (!meta) return null;
1835
2874
  }
1836
- return avatarUrl(_nullishCoalesce(_optionalChain([meta, 'optionalAccess', _41 => _41.image]), () => ( _optionalChain([meta, 'optionalAccess', _42 => _42.image_url]))));
2875
+ return found;
1837
2876
  }
1838
2877
 
1839
- // src/core/ensHint.ts
1840
- var _ens = require('viem/ens');
1841
- var ENS_HINT_KEY = "id.thurin";
1842
- function ensHintFor(record, verifiedFingerprint) {
1843
- const raw = _nullishCoalesce(_optionalChain([record, 'optionalAccess', _43 => _43.trim, 'call', _44 => _44()]), () => ( ""));
1844
- const expected = verifiedFingerprint ? normalizeFingerprint(verifiedFingerprint) : null;
1845
- if (!raw) return { key: ENS_HINT_KEY, state: "unset", record: null, fingerprint: null, expected };
1846
- const fingerprint = normalizeFingerprint(raw);
1847
- if (!fingerprint) return { key: ENS_HINT_KEY, state: "mismatch", record: raw, fingerprint: null, expected, reason: "The record is not a PGP fingerprint" };
1848
- if (!expected) return { key: ENS_HINT_KEY, state: "mismatch", record: raw, fingerprint, expected, reason: "The address has no verified claim" };
1849
- if (fingerprint === expected) return { key: ENS_HINT_KEY, state: "match", record: raw, fingerprint, expected };
1850
- return { key: ENS_HINT_KEY, state: "mismatch", record: raw, fingerprint, expected, reason: "The record names a key this address has not claimed" };
1851
- }
1852
- function ensHintValue(fingerprint) {
1853
- const fp = normalizeFingerprint(fingerprint);
1854
- if (!fp) throw new Error(`Not a fingerprint: ${fingerprint}`);
1855
- return fp.toUpperCase();
1856
- }
1857
- var ENS_TEXT_RESOLVER_ABI = [
1858
- { type: "function", name: "text", stateMutability: "view", inputs: [{ name: "node", type: "bytes32" }, { name: "key", type: "string" }], outputs: [{ name: "", type: "string" }] },
1859
- { type: "function", name: "setText", stateMutability: "nonpayable", inputs: [{ name: "node", type: "bytes32" }, { name: "key", type: "string" }, { name: "value", type: "string" }], outputs: [] }
1860
- ];
1861
- function ensHintWrite(name, fingerprint) {
1862
- const normalized = _ens.normalize.call(void 0, name);
1863
- return {
1864
- abi: ENS_TEXT_RESOLVER_ABI,
1865
- functionName: "setText",
1866
- args: [_ens.namehash.call(void 0, normalized), ENS_HINT_KEY, ensHintValue(fingerprint)],
1867
- name: normalized
1868
- };
2878
+ // src/core/claimStatus.ts
2879
+ var CLAIM_CHECK_LABEL = {
2880
+ verified: "pgp verified",
2881
+ expired: "key expired",
2882
+ "signing-key-expired": "signing key expired",
2883
+ revoked: "key revoked",
2884
+ compromised: "key compromised",
2885
+ "signing-key-revoked": "signing key revoked",
2886
+ unsupported: "not supported",
2887
+ "bad-signature": "doesn't verify"
2888
+ };
2889
+ function formatClaimDate(isoOrSeconds) {
2890
+ if (isoOrSeconds === null || isoOrSeconds === void 0) return "an unknown date";
2891
+ const d = typeof isoOrSeconds === "number" ? new Date(isoOrSeconds * 1e3) : new Date(isoOrSeconds);
2892
+ if (Number.isNaN(d.getTime())) return "an unknown date";
2893
+ return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", timeZone: "UTC" });
1869
2894
  }
1870
- async function fetchEnsHint(client, name, verifiedFingerprint) {
1871
- const record = await client.getEnsText({ name: _ens.normalize.call(void 0, name), key: ENS_HINT_KEY });
1872
- return ensHintFor(record, verifiedFingerprint);
2895
+ function shortFingerprint(fpr) {
2896
+ if (!fpr) return "unknown";
2897
+ const f = fpr.toUpperCase();
2898
+ return `${f.slice(0, 4)} ${f.slice(4, 8)} \u2026`;
1873
2899
  }
1874
-
1875
- // src/core/authorization.ts
1876
-
1877
- var EIP712_NAME = "Thurin PGPRegistry";
1878
- var EIP712_VERSION = "2";
1879
- function registryDomain(chainId, verifyingContract) {
1880
- return { name: EIP712_NAME, version: EIP712_VERSION, chainId, verifyingContract };
2900
+ function claimCheckText(v, formatDate = formatClaimDate) {
2901
+ const kind = _nullishCoalesce(v.kind, () => ( (v.verified ? "verified" : "bad-signature")));
2902
+ const at = formatDate(v.at);
2903
+ const t = (sentence, fix = null) => ({ kind, label: CLAIM_CHECK_LABEL[kind], sentence, fix });
2904
+ switch (kind) {
2905
+ case "verified":
2906
+ return t("The key signed a line naming this address, and the signature checks out.");
2907
+ case "expired":
2908
+ return t(
2909
+ `The key on this claim expired on ${at}, so the claim no longer counts.`,
2910
+ "Extend the key, then Update key. No new signature needed."
2911
+ );
2912
+ case "signing-key-expired":
2913
+ return t(
2914
+ `The subkey that signed this claim (${shortFingerprint(v.signingKey)}) expired on ${at}.`,
2915
+ "Extend that subkey, then Update key."
2916
+ );
2917
+ case "revoked":
2918
+ return t(
2919
+ `Its owner revoked this PGP key on ${at}${v.revocationReason ? ` (reason: ${v.revocationReason})` : ""}. The claim no longer counts.`,
2920
+ "Revoke this claim and attest your new key."
2921
+ );
2922
+ case "compromised":
2923
+ return t(
2924
+ `Its owner revoked this PGP key on ${at} as compromised. Don't trust anything it signed after that date.`,
2925
+ "Revoke this claim and attest a new key."
2926
+ );
2927
+ case "signing-key-revoked":
2928
+ return t(
2929
+ `The subkey that signed this claim was revoked on ${at}.`,
2930
+ "Replace the claim with a signature from a current key."
2931
+ );
2932
+ case "unsupported":
2933
+ 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.`);
2934
+ case "bad-signature":
2935
+ default:
2936
+ return t("The signature stored with this claim doesn't match its key, so nothing from this claim is shown.");
2937
+ }
1881
2938
  }
1882
- var AUTHORIZATION_TYPES = {
1883
- Attest: [
1884
- { name: "owner", type: "address" },
1885
- { name: "fingerprint", type: "bytes" },
1886
- { name: "pgpSignature", type: "bytes" },
1887
- { name: "pgpPublicKey", type: "bytes" },
1888
- { name: "nonce", type: "uint256" },
1889
- { name: "deadline", type: "uint256" }
1890
- ],
1891
- Reattest: [
1892
- { name: "owner", type: "address" },
1893
- { name: "revokeIndex", type: "uint256" },
1894
- { name: "fingerprint", type: "bytes" },
1895
- { name: "pgpSignature", type: "bytes" },
1896
- { name: "pgpPublicKey", type: "bytes" },
1897
- { name: "nonce", type: "uint256" },
1898
- { name: "deadline", type: "uint256" }
1899
- ],
1900
- UpdateKey: [
1901
- { name: "owner", type: "address" },
1902
- { name: "index", type: "uint256" },
1903
- { name: "pgpPublicKey", type: "bytes" },
1904
- { name: "nonce", type: "uint256" },
1905
- { name: "deadline", type: "uint256" }
1906
- ],
1907
- Revoke: [
1908
- { name: "owner", type: "address" },
1909
- { name: "index", type: "uint256" },
1910
- { name: "nonce", type: "uint256" },
1911
- { name: "deadline", type: "uint256" }
1912
- ],
1913
- SetRecord: [
1914
- { name: "owner", type: "address" },
1915
- { name: "index", type: "uint256" },
1916
- { name: "kind", type: "bytes32" },
1917
- { name: "value", type: "bytes" },
1918
- { name: "nonce", type: "uint256" },
1919
- { name: "deadline", type: "uint256" }
1920
- ]
1921
- };
1922
- function attestTypedData(chainId, registry, a) {
1923
- return {
1924
- domain: registryDomain(chainId, registry),
1925
- types: { Attest: AUTHORIZATION_TYPES.Attest },
1926
- primaryType: "Attest",
1927
- message: {
1928
- owner: a.owner,
1929
- fingerprint: fingerprintToBytes(a.fingerprint),
1930
- pgpSignature: _viem.stringToHex.call(void 0, a.pgpSignature),
1931
- pgpPublicKey: _viem.stringToHex.call(void 0, a.pgpPublicKey),
1932
- nonce: a.nonce,
1933
- deadline: a.deadline
1934
- }
1935
- };
2939
+ function keyProblemText(v, formatDate = formatClaimDate) {
2940
+ const at = formatDate(v.at);
2941
+ const t = (kind, sentence, fix) => ({ kind, label: CLAIM_CHECK_LABEL[kind], sentence, fix });
2942
+ switch (v.kind) {
2943
+ case "expired":
2944
+ 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.");
2945
+ case "signing-key-expired":
2946
+ return t("signing-key-expired", `The subkey that signed (${shortFingerprint(v.signingKey)}) expired on ${at}.`, "Extend that subkey, or sign with a current one.");
2947
+ case "revoked":
2948
+ return t("revoked", `This key was revoked on ${at}${v.revocationReason ? ` (reason: ${v.revocationReason})` : ""}.`, "Use a current key.");
2949
+ case "compromised":
2950
+ return t("compromised", `This key was revoked as compromised on ${at}.`, "Use a new key.");
2951
+ case "signing-key-revoked":
2952
+ return t("signing-key-revoked", `The subkey that signed was revoked on ${at}.`, "Sign with a current subkey.");
2953
+ case "unsupported":
2954
+ 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.");
2955
+ default:
2956
+ return null;
2957
+ }
1936
2958
  }
1937
- function reattestTypedData(chainId, registry, a) {
1938
- const base = attestTypedData(chainId, registry, a);
1939
- return {
1940
- domain: base.domain,
1941
- types: { Reattest: AUTHORIZATION_TYPES.Reattest },
1942
- primaryType: "Reattest",
1943
- message: { ...base.message, revokeIndex: a.revokeIndex }
1944
- };
2959
+ function expiresSoon(v, now = Date.now(), withinDays = 30) {
2960
+ if (!_optionalChain([v, 'optionalAccess', _80 => _80.verified]) || !v.expiresAt) return null;
2961
+ const ms = new Date(v.expiresAt).getTime() - now;
2962
+ if (!Number.isFinite(ms) || ms < 0 || ms > withinDays * 864e5) return null;
2963
+ return { days: Math.floor(ms / 864e5), at: v.expiresAt };
1945
2964
  }
1946
- function updateKeyTypedData(chainId, registry, a) {
1947
- return {
1948
- domain: registryDomain(chainId, registry),
1949
- types: { UpdateKey: AUTHORIZATION_TYPES.UpdateKey },
1950
- primaryType: "UpdateKey",
1951
- message: { owner: a.owner, index: a.index, pgpPublicKey: _viem.stringToHex.call(void 0, a.pgpPublicKey), nonce: a.nonce, deadline: a.deadline }
1952
- };
2965
+ function expiresSoonText(soon, formatDate = formatClaimDate) {
2966
+ const when = soon.days === 0 ? "today" : soon.days === 1 ? "in 1 day" : `in ${soon.days} days`;
2967
+ return `Key expires ${when} (${formatDate(soon.at)}).`;
1953
2968
  }
1954
- function revokeTypedData(chainId, registry, a) {
1955
- return {
1956
- domain: registryDomain(chainId, registry),
1957
- types: { Revoke: AUTHORIZATION_TYPES.Revoke },
1958
- primaryType: "Revoke",
1959
- message: { owner: a.owner, index: a.index, nonce: a.nonce, deadline: a.deadline }
1960
- };
2969
+ function claimFates(claims) {
2970
+ const out = /* @__PURE__ */ new Map();
2971
+ for (const c of claims) {
2972
+ if (c.state === "active" || !c.revokedAt) out.set(c.index, { state: "active" });
2973
+ 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 } : {} });
2974
+ else out.set(c.index, { state: "revoked", at: c.revokedAt, ...c.revokeReason ? { reason: c.revokeReason } : {} });
2975
+ }
2976
+ return out;
1961
2977
  }
1962
- function setRecordTypedData(chainId, registry, a) {
1963
- return {
1964
- domain: registryDomain(chainId, registry),
1965
- types: { SetRecord: AUTHORIZATION_TYPES.SetRecord },
1966
- primaryType: "SetRecord",
1967
- message: { owner: a.owner, index: a.index, kind: a.kind, value: a.value, nonce: a.nonce, deadline: a.deadline }
1968
- };
2978
+ function claimFateText(fate, formatDate = (s) => formatClaimDate(s)) {
2979
+ if (fate.state === "revoked") return `Revoked by its owner on ${formatDate(fate.at)}${fate.reason ? ` (${fate.reason})` : ""}.`;
2980
+ if (fate.state === "replaced") return `Replaced by claim #${fate.by} on ${formatDate(fate.at)}.${fate.compromised ? " Its key was marked compromised." : ""}`;
2981
+ return null;
1969
2982
  }
1970
- function authorizationDigest(typedData) {
1971
- return _viem.hashTypedData.call(void 0, typedData);
2983
+
2984
+ // src/core/encrypt.ts
2985
+ async function encryptionKeyFor(claims, { now = Date.now(), recentDays = 7 } = {}) {
2986
+ const standing = keyStanding(claims);
2987
+ if (standing.kind === "none" || standing.kind === "inactive") return { ok: false, reason: "no-claim", claim: standing.claim };
2988
+ if (standing.kind === "not-counted" || !standing.claim.pgpPublicKey) return { ok: false, reason: "unverified", claim: standing.claim };
2989
+ const claim = standing.claim;
2990
+ try {
2991
+ const openpgp = await Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
2992
+ const config = pgpConfig(openpgp);
2993
+ const key = await readKeyAny(openpgp, claim.pgpPublicKey);
2994
+ const date = new Date(now);
2995
+ const enc = await key.getEncryptionKey(void 0, date, void 0, config).catch(() => null);
2996
+ if (!enc) {
2997
+ let lastExpiry = null;
2998
+ for (const sk of key.subkeys) {
2999
+ const flags = _nullishCoalesce(_optionalChain([newestSignature, 'call', _81 => _81(sk.bindingSignatures), 'optionalAccess', _82 => _82.keyFlags, 'optionalAccess', _83 => _83[0]]), () => ( 0));
3000
+ if (!(flags & 12) || await sk.isRevoked(void 0, void 0, date, config).catch(() => false)) continue;
3001
+ const exp2 = await sk.getExpirationTime(date, config).catch(() => null);
3002
+ if (typeof exp2 === "number" || exp2 instanceof Date) {
3003
+ const t = new Date(exp2).getTime();
3004
+ if (t <= now && (lastExpiry === null || t > lastExpiry)) lastExpiry = t;
3005
+ }
3006
+ }
3007
+ return lastExpiry !== null ? { ok: false, reason: "encryption-subkey-expired", claim, expired: new Date(lastExpiry).toISOString() } : { ok: false, reason: "no-encryption-subkey", claim };
3008
+ }
3009
+ const exp = await enc.getExpirationTime(date, config).catch(() => null);
3010
+ return {
3011
+ ok: true,
3012
+ claim,
3013
+ key: claim.pgpPublicKey,
3014
+ subkey: {
3015
+ fingerprint: enc.getFingerprint().toUpperCase(),
3016
+ algorithm: algorithmName(enc),
3017
+ expires: exp && exp !== Infinity ? new Date(exp).toISOString() : null
3018
+ },
3019
+ addedAt: claim.createdAt,
3020
+ changedRecently: now / 1e3 - claim.createdAt < recentDays * 86400
3021
+ };
3022
+ } catch (e17) {
3023
+ return { ok: false, reason: "unverified", claim };
3024
+ }
1972
3025
  }
1973
- function recordKind(name) {
1974
- return _viem.keccak256.call(void 0, _viem.stringToHex.call(void 0, name));
3026
+ function encryptRefusalText(r, formatDate = formatClaimDate) {
3027
+ switch (r.reason) {
3028
+ case "no-claim":
3029
+ return "No claim counts for this identity, so there is no key to encrypt to.";
3030
+ case "unverified":
3031
+ return "Its newest claim doesn't verify, so its key can't be trusted with a message.";
3032
+ case "no-encryption-subkey":
3033
+ return "Its key has no encryption subkey, so it can sign but not receive.";
3034
+ case "encryption-subkey-expired":
3035
+ return `Its encryption subkey expired on ${formatDate(r.expired)}.`;
3036
+ }
3037
+ }
3038
+ function keyChangedText(k, now = Date.now()) {
3039
+ if (!k.changedRecently) return null;
3040
+ const days = Math.floor((now / 1e3 - k.addedAt) / 86400);
3041
+ const when = days <= 0 ? "today" : days === 1 ? "yesterday" : `${days} days ago`;
3042
+ return `This key was added ${when}. If you were expecting a different one, check with them another way.`;
3043
+ }
3044
+ async function encryptTo(key, data, { filename, armor = typeof data === "string", hideRecipient = true, date = /* @__PURE__ */ new Date() } = {}) {
3045
+ const openpgp = await Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
3046
+ const config = pgpConfig(openpgp);
3047
+ const encryptionKeys = await readKeyAny(openpgp, key);
3048
+ const message = typeof data === "string" ? await openpgp.createMessage({ text: data, date }) : await openpgp.createMessage({ binary: data, filename, format: "binary", date });
3049
+ const opts = { message, encryptionKeys, config, wildcard: hideRecipient, date };
3050
+ return armor ? await openpgp.encrypt({ ...opts, format: "armored" }) : await openpgp.encrypt({ ...opts, format: "binary" });
3051
+ }
3052
+
3053
+ // src/core/contractErrors.ts
3054
+ var CONTRACT_ERROR_TEXT = {
3055
+ AlreadyRevoked: "That claim has already ended, or is already marked compromised.",
3056
+ BadArmorChecksum: "The armor's checksum doesn't match its data: the paste was changed or cut short.",
3057
+ BadBase64: "The armored data isn't valid base64.",
3058
+ ClaimActive: 'That claim is still active: revoke it with the reason "compromised" instead.',
3059
+ DeploymentFailed: "The key and signature couldn't be stored: together they're over the contract's size limit.",
3060
+ DuplicateActiveFingerprint: "This address already has an active claim for this key: update it or replace it instead.",
3061
+ EmptyKey: "No key was given.",
3062
+ EmptySignature: "No signature was given.",
3063
+ IndexOutOfBounds: "This address has no claim at that index.",
3064
+ InvalidFingerprint: "That 32-byte fingerprint ends in 12 zero bytes, which no real v6 key has.",
3065
+ InvalidFingerprintLength: "The fingerprint isn't 20 bytes (v4 key) or 32 bytes (v6 key).",
3066
+ InvalidKindName: "The record name is empty, longer than 31 bytes, or uses something other than a-z, 0-9, '-', and '.'.",
3067
+ 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.",
3068
+ InvalidPointer: "There is no stored data at that address.",
3069
+ KeyCompromised: "This address marked the key compromised: it can never claim it again.",
3070
+ KeyStillActive: 'This address still has an active claim for the key: revoke that claim as "compromised" instead.',
3071
+ KeyTooLarge: "The key is over 16,384 bytes: export it without photos or old signatures.",
3072
+ NotAKey: "The key doesn't start with an OpenPGP public-key packet: give gpg's export of the public key.",
3073
+ NotASignature: "The signature is neither an OpenPGP signature nor a clearsigned message.",
3074
+ NotArmored: "The paste has no -----BEGIN PGP and -----END PGP lines.",
3075
+ PayloadTooLarge: "The signature and key together are over 24,000 bytes.",
3076
+ PermissionExpired: "The permission is past its deadline: ask the owner for a new one.",
3077
+ RecordTooLarge: "The record value is over 1,024 bytes.",
3078
+ SignatureTooLarge: "The signature is over 8,192 bytes.",
3079
+ SupersededIsSetByReattest: '"superseded" is set only by replacing a claim: pick another reason.',
3080
+ TooManyClaims: "This address has reached the limit of 65,535 claims.",
3081
+ UnknownRevokeReason: 'The revoke reason must be empty, "compromised", "retired", or "other".',
3082
+ UnsupportedHeader: "Armor header lines (like Comment:) can't be told from the data, as when line breaks were lost: remove them."
3083
+ };
3084
+ function contractErrorName(err) {
3085
+ for (let e = err, depth = 0; e && depth < 8; e = e.cause, depth++) {
3086
+ const name = _nullishCoalesce(_optionalChain([e, 'access', _84 => _84.data, 'optionalAccess', _85 => _85.errorName]), () => ( e.errorName));
3087
+ if (typeof name === "string" && name) return name;
3088
+ }
3089
+ return null;
3090
+ }
3091
+ function contractErrorText(err) {
3092
+ const name = contractErrorName(err);
3093
+ return name ? _nullishCoalesce(CONTRACT_ERROR_TEXT[name], () => ( `The registry refused it (${name}).`)) : null;
1975
3094
  }
1976
3095
 
1977
3096
  // src/core/records.ts
1978
-
1979
3097
  var MAX_RECORD_BYTES = 1024;
3098
+ var MAX_KIND_BYTES = 31;
1980
3099
  function kindName(input) {
1981
3100
  return input.includes(".") ? input : `thurin.${input}`;
1982
3101
  }
3102
+ function checkKindName(input) {
3103
+ if (!/^[a-z0-9.-]+$/.test(input)) throw new Error(`Record name "${input}": use a-z, 0-9, "-" and "." only`);
3104
+ const name = kindName(input);
3105
+ if (name.length > MAX_KIND_BYTES) throw new Error(`Record name "${name}" is ${name.length} bytes; the registry allows ${MAX_KIND_BYTES}`);
3106
+ return name;
3107
+ }
3108
+ function checkRecordValue(value) {
3109
+ const bytes = new TextEncoder().encode(value).length;
3110
+ if (bytes > MAX_RECORD_BYTES) throw new Error(`Record is ${bytes} bytes; the registry accepts up to ${MAX_RECORD_BYTES}`);
3111
+ return value;
3112
+ }
1983
3113
  var KNOWN_KINDS = [
1984
3114
  "thurin.railgun",
1985
3115
  "thurin.security",
1986
3116
  "thurin.successor",
1987
3117
  "thurin.affiliation",
1988
3118
  "thurin.canary",
1989
- "thurin.private",
1990
- "thurin.disclosure",
1991
- "thurin.pointer"
1992
- ];
1993
- var IDENTITY_KINDS = [
1994
- "thurin.railgun",
1995
- "thurin.security",
1996
- "thurin.successor",
1997
- "thurin.affiliation",
1998
- "thurin.canary",
3119
+ "thurin.releases",
1999
3120
  "thurin.private",
2000
3121
  "thurin.disclosure"
2001
3122
  ];
2002
- function encodeRecord(value) {
2003
- const bytes = new TextEncoder().encode(value).length;
2004
- if (bytes > MAX_RECORD_BYTES) throw new Error(`Record is ${bytes} bytes; the registry accepts up to ${MAX_RECORD_BYTES}`);
2005
- return _viem.stringToHex.call(void 0, value);
2006
- }
2007
- function decodeRecord(hex) {
2008
- return hex === "0x" ? "" : _viem.hexToString.call(void 0, hex);
2009
- }
2010
- function parsePointer(text) {
3123
+ function parseReleases(text) {
2011
3124
  const p = JSON.parse(text);
2012
- if (_optionalChain([p, 'optionalAccess', _45 => _45.v]) !== 1 || !Array.isArray(p.releases)) throw new Error("Not a v1 thurin.pointer record");
3125
+ if (_optionalChain([p, 'optionalAccess', _86 => _86.v]) !== 1 || !Array.isArray(p.releases)) throw new Error("Not a v1 thurin.releases record");
2013
3126
  return p;
2014
3127
  }
2015
- function addPointer(existing, entry) {
3128
+ function addRelease(existing, entry) {
2016
3129
  if (!/^[0-9a-f]{64}$/i.test(entry.sha256)) throw new Error("sha256 must be 64 hex characters");
2017
- const releases = [entry, ...(_nullishCoalesce(_optionalChain([existing, 'optionalAccess', _46 => _46.releases]), () => ( []))).filter((r) => r.name !== entry.name)];
3130
+ const releases = [entry, ...(_nullishCoalesce(_optionalChain([existing, 'optionalAccess', _87 => _87.releases]), () => ( []))).filter((r) => r.name !== entry.name)];
2018
3131
  const dropped = [];
2019
3132
  const record = { v: 1, releases };
2020
3133
  while (new TextEncoder().encode(JSON.stringify(record)).length > MAX_RECORD_BYTES && releases.length > 1) dropped.push(releases.pop());
2021
3134
  return { record, dropped };
2022
3135
  }
2023
- function renderPointer(p) {
3136
+ function renderReleases(p) {
2024
3137
  return p.releases.map((r) => `${r.name.padEnd(22)} ${r.date} sha256 ${r.sha256}${r.url ? ` ${r.url}` : ""}`).join("\n");
2025
3138
  }
2026
3139
  var RAILGUN_ADDRESS = /^0zk1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{60,200}$/;
@@ -2048,14 +3161,14 @@ async function parseRecord(kind, text, opts = {}) {
2048
3161
  case "thurin.affiliation": {
2049
3162
  try {
2050
3163
  const j = JSON.parse(t);
2051
- if (_optionalChain([j, 'optionalAccess', _47 => _47.v]) !== 1 || typeof j.with !== "string" || !j.with) return invalid('Not a v1 affiliation: expected {"v":1,"with":"<address or name>"}');
3164
+ if (_optionalChain([j, 'optionalAccess', _88 => _88.v]) !== 1 || typeof j.with !== "string" || !j.with) return invalid('Not a v1 affiliation: expected {"v":1,"with":"<address or name>"}');
2052
3165
  return { ...base, valid: true, data: { type: "affiliation", with: j.with, role: typeof j.role === "string" ? j.role : null } };
2053
- } catch (e11) {
3166
+ } catch (e18) {
2054
3167
  return invalid("Not JSON");
2055
3168
  }
2056
3169
  }
2057
3170
  case "thurin.canary": {
2058
- const date = _optionalChain([t, 'access', _48 => _48.match, 'call', _49 => _49(ISO_DATE), 'optionalAccess', _50 => _50[1]]);
3171
+ const date = _optionalChain([t, 'access', _89 => _89.match, 'call', _90 => _90(ISO_DATE), 'optionalAccess', _91 => _91[1]]);
2059
3172
  if (!date) return invalid("No date in the statement");
2060
3173
  const clearsigned = t.startsWith("-----BEGIN PGP SIGNED MESSAGE-----");
2061
3174
  let statement = clearsigned ? (_nullishCoalesce(t.split(/\r?\n\r?\n/)[1], () => ( ""))).split("-----BEGIN PGP SIGNATURE-----")[0].trim() : t;
@@ -2075,119 +3188,126 @@ async function parseRecord(kind, text, opts = {}) {
2075
3188
  try {
2076
3189
  const { readMessage } = await Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
2077
3190
  recipients = (await readMessage({ armoredMessage: t })).getEncryptionKeyIDs().length;
2078
- } catch (e12) {
3191
+ } catch (e19) {
2079
3192
  return invalid("PGP message does not parse");
2080
3193
  }
2081
3194
  return { ...base, valid: true, data: { type: "encrypted", recipients } };
2082
3195
  }
2083
- case "thurin.pointer": {
3196
+ case "thurin.releases": {
2084
3197
  try {
2085
- return { ...base, valid: true, data: { type: "pointer", releases: parsePointer(t).releases } };
2086
- } catch (e13) {
2087
- return invalid("Not a v1 pointer record");
3198
+ return { ...base, valid: true, data: { type: "releases", releases: parseReleases(t).releases } };
3199
+ } catch (e20) {
3200
+ return invalid('Not a v1 release list: expected {"v":1,"releases":[\u2026]}');
2088
3201
  }
2089
3202
  }
2090
3203
  default:
2091
3204
  return { ...base, valid: true, data: { type: "text" } };
2092
3205
  }
2093
3206
  }
2094
- async function fetchRecords(client, registry, abi, owner, index, kinds = IDENTITY_KINDS, opts = {}) {
3207
+ function pickRecords(names, values, kinds = KNOWN_KINDS) {
3208
+ const all = names.map((kind, i) => ({ kind, text: _nullishCoalesce(values[i], () => ( "")) })).filter((r) => r.text);
3209
+ if (!kinds) return all;
3210
+ return kinds.flatMap((k) => all.filter((r) => r.kind === k));
3211
+ }
3212
+ function pageRecords(names, values) {
3213
+ const all = pickRecords(names, values, null);
3214
+ const ours = KNOWN_KINDS.flatMap((k) => all.filter((r) => r.kind === k));
3215
+ return [...ours, ...all.filter((r) => !KNOWN_KINDS.includes(r.kind))];
3216
+ }
3217
+ async function fetchRecords(client, registry, abi, owner, index, kinds = KNOWN_KINDS, opts = {}) {
3218
+ const [names, values] = await client.readContract({ address: registry, abi, functionName: "recordsOf", args: [owner, BigInt(index)] });
2095
3219
  const out = [];
2096
- for (const kind of kinds) {
2097
- const hex = await client.readContract({ address: registry, abi, functionName: "record", args: [owner, BigInt(index), recordKind(kind)] });
2098
- const text = decodeRecord(hex);
2099
- if (text) out.push(await parseRecord(kind, text, opts));
2100
- }
3220
+ for (const r of pickRecords(names, values, kinds)) out.push(await parseRecord(r.kind, r.text, opts));
2101
3221
  return out;
2102
3222
  }
2103
3223
 
2104
- // src/core/claimStatus.ts
2105
- var CLAIM_CHECK_LABEL = {
2106
- verified: "pgp verified",
2107
- expired: "key expired",
2108
- "signing-key-expired": "signing key expired",
2109
- revoked: "key revoked",
2110
- compromised: "key compromised",
2111
- "signing-key-revoked": "signing key revoked",
2112
- unsupported: "not supported",
2113
- "bad-signature": "doesn't verify"
2114
- };
2115
- function formatClaimDate(isoOrSeconds) {
2116
- if (isoOrSeconds === null || isoOrSeconds === void 0) return "an unknown date";
2117
- const d = typeof isoOrSeconds === "number" ? new Date(isoOrSeconds * 1e3) : new Date(isoOrSeconds);
2118
- if (Number.isNaN(d.getTime())) return "an unknown date";
2119
- return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", timeZone: "UTC" });
3224
+ // src/core/avatar.ts
3225
+ var IPFS_GATEWAYS = ["https://ipfs.filebase.io/ipfs/", "https://gateway.pinata.cloud/ipfs/"];
3226
+ var IPFS_GATEWAY = IPFS_GATEWAYS[0];
3227
+ var ARWEAVE_GATEWAY = "https://arweave.net/";
3228
+ function avatarUrl(uri) {
3229
+ if (typeof uri !== "string") return null;
3230
+ const u = uri.trim();
3231
+ if (/^data:image\/(png|jpe?g|gif|webp|avif|svg\+xml)[;,]/i.test(u)) return u;
3232
+ let m = u.match(/^ipfs:\/\/(?:ipfs\/)?([a-zA-Z0-9]{46,}(?:\/[^?#\s]*)?)$/);
3233
+ if (m) return IPFS_GATEWAY + m[1];
3234
+ m = u.match(/^ar:\/\/([a-zA-Z0-9_-]{43}(?:\/[^?#\s]*)?)$/);
3235
+ if (m) return ARWEAVE_GATEWAY + m[1];
3236
+ if (/^https:\/\/euc\.li\/[^?#\s]+$/.test(u)) return u;
3237
+ m = u.match(/^https:\/\/[^/]+\/ipfs\/([a-zA-Z0-9]{46,}(?:\/[^?#\s]*)?)$/);
3238
+ if (m) return IPFS_GATEWAY + m[1];
3239
+ return null;
2120
3240
  }
2121
- function shortFingerprint(fpr) {
2122
- if (!fpr) return "unknown";
2123
- const f = fpr.toUpperCase();
2124
- return `${f.slice(0, 4)} ${f.slice(4, 8)} \u2026`;
3241
+ function avatarFallbacks(url) {
3242
+ if (!url || !url.startsWith(IPFS_GATEWAYS[0])) return [];
3243
+ const path = url.slice(IPFS_GATEWAYS[0].length);
3244
+ return IPFS_GATEWAYS.slice(1).map((g) => g + path);
2125
3245
  }
2126
- function claimCheckText(v, formatDate = formatClaimDate) {
2127
- const kind = _nullishCoalesce(v.kind, () => ( (v.verified ? "verified" : "bad-signature")));
2128
- const at = formatDate(v.at);
2129
- const t = (sentence, fix = null) => ({ kind, label: CLAIM_CHECK_LABEL[kind], sentence, fix });
2130
- switch (kind) {
2131
- case "verified":
2132
- return t("The key signed a line naming this address, and the signature checks out.");
2133
- case "expired":
2134
- return t(
2135
- `The key on this claim expired on ${at}, so the claim no longer counts.`,
2136
- "Extend the key, then Update key. No new signature needed."
2137
- );
2138
- case "signing-key-expired":
2139
- return t(
2140
- `The subkey that signed this claim (${shortFingerprint(v.signingKey)}) expired on ${at}.`,
2141
- "Extend that subkey, then Update key."
2142
- );
2143
- case "revoked":
2144
- return t(
2145
- `Its owner revoked this PGP key on ${at}${v.revocationReason ? ` (reason: ${v.revocationReason})` : ""}. The claim no longer counts.`,
2146
- "Revoke this claim and attest your new key."
2147
- );
2148
- case "compromised":
2149
- return t(
2150
- `Its owner revoked this PGP key on ${at} as compromised. Don't trust anything it signed after that date.`,
2151
- "Revoke this claim and attest a new key."
2152
- );
2153
- case "signing-key-revoked":
2154
- return t(
2155
- `The subkey that signed this claim was revoked on ${at}.`,
2156
- "Replace the claim with a signature from a current key."
2157
- );
2158
- case "unsupported":
2159
- 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.`);
2160
- case "bad-signature":
2161
- default:
2162
- return t("The signature stored with this claim doesn't match its key, so nothing from this claim is shown.");
3246
+ function parseNftAvatar(raw) {
3247
+ const m = typeof raw === "string" && raw.trim().match(/^eip155:(\d+)\/(erc721|erc1155):(0x[0-9a-fA-F]{40})\/(\d+)$/i);
3248
+ return m ? { chainId: Number(m[1]), standard: m[2].toLowerCase(), contract: m[3], tokenId: BigInt(m[4]) } : null;
3249
+ }
3250
+ var NFT_AVATAR_ABI = [
3251
+ { type: "function", name: "tokenURI", stateMutability: "view", inputs: [{ type: "uint256" }], outputs: [{ type: "string" }] },
3252
+ { type: "function", name: "uri", stateMutability: "view", inputs: [{ type: "uint256" }], outputs: [{ type: "string" }] }
3253
+ ];
3254
+ async function nftAvatarImage(tokenUri, tokenId, fetchFn = fetch) {
3255
+ const uri = tokenUri.replace("{id}", tokenId.toString(16).padStart(64, "0"));
3256
+ let meta;
3257
+ const inline = uri.match(/^data:application\/json(;base64)?,([\s\S]*)$/);
3258
+ if (inline) meta = JSON.parse(inline[1] ? atob(inline[2]) : decodeURIComponent(inline[2]));
3259
+ else {
3260
+ const url = uri.startsWith("data:") ? null : avatarUrl(uri);
3261
+ if (!url) return null;
3262
+ for (const candidate of [url, ...avatarFallbacks(url)]) {
3263
+ try {
3264
+ const res = await fetchFn(candidate);
3265
+ if (res.ok) {
3266
+ meta = await res.json();
3267
+ break;
3268
+ }
3269
+ } catch (e21) {
3270
+ }
3271
+ }
3272
+ if (!meta) return null;
2163
3273
  }
3274
+ return avatarUrl(_nullishCoalesce(_optionalChain([meta, 'optionalAccess', _92 => _92.image]), () => ( _optionalChain([meta, 'optionalAccess', _93 => _93.image_url]))));
2164
3275
  }
2165
- function expiresSoon(v, now = Date.now(), withinDays = 30) {
2166
- if (!_optionalChain([v, 'optionalAccess', _51 => _51.verified]) || !v.expiresAt) return null;
2167
- const ms = new Date(v.expiresAt).getTime() - now;
2168
- if (!Number.isFinite(ms) || ms < 0 || ms > withinDays * 864e5) return null;
2169
- return { days: Math.floor(ms / 864e5), at: v.expiresAt };
3276
+
3277
+ // src/core/ensHint.ts
3278
+ var _ens = require('viem/ens');
3279
+ var ENS_HINT_KEY = "id.thurin";
3280
+ function ensHintFor(record, verifiedFingerprint) {
3281
+ const raw = _nullishCoalesce(_optionalChain([record, 'optionalAccess', _94 => _94.trim, 'call', _95 => _95()]), () => ( ""));
3282
+ const expected = verifiedFingerprint ? normalizeFingerprint(verifiedFingerprint) : null;
3283
+ if (!raw) return { key: ENS_HINT_KEY, state: "unset", record: null, fingerprint: null, expected };
3284
+ const fingerprint = normalizeFingerprint(raw);
3285
+ if (!fingerprint) return { key: ENS_HINT_KEY, state: "mismatch", record: raw, fingerprint: null, expected, reason: "The record is not a PGP fingerprint" };
3286
+ if (!expected) return { key: ENS_HINT_KEY, state: "mismatch", record: raw, fingerprint, expected, reason: "The address has no verified claim" };
3287
+ if (fingerprint === expected) return { key: ENS_HINT_KEY, state: "match", record: raw, fingerprint, expected };
3288
+ return { key: ENS_HINT_KEY, state: "mismatch", record: raw, fingerprint, expected, reason: "The record names a key this address has not claimed" };
2170
3289
  }
2171
- function expiresSoonText(soon, formatDate = formatClaimDate) {
2172
- const when = soon.days === 0 ? "today" : soon.days === 1 ? "in 1 day" : `in ${soon.days} days`;
2173
- return `Key expires ${when} (${formatDate(soon.at)}).`;
3290
+ function ensHintValue(fingerprint) {
3291
+ const fp = normalizeFingerprint(fingerprint);
3292
+ if (!fp) throw new Error(`Not a fingerprint: ${fingerprint}`);
3293
+ return fp.toUpperCase();
2174
3294
  }
2175
- function claimFates(claims) {
2176
- const out = /* @__PURE__ */ new Map();
2177
- for (const c of claims) {
2178
- if (!c.revokedAt) {
2179
- out.set(c.index, { state: "active" });
2180
- continue;
2181
- }
2182
- const successor = claims.filter((n) => n.index > c.index && n.createdAt === c.revokedAt).sort((a, b) => a.index - b.index)[0];
2183
- out.set(c.index, successor ? { state: "replaced", at: c.revokedAt, by: successor.index } : { state: "revoked", at: c.revokedAt });
2184
- }
2185
- return out;
3295
+ var ENS_TEXT_RESOLVER_ABI = [
3296
+ { type: "function", name: "text", stateMutability: "view", inputs: [{ name: "node", type: "bytes32" }, { name: "key", type: "string" }], outputs: [{ name: "", type: "string" }] },
3297
+ { type: "function", name: "setText", stateMutability: "nonpayable", inputs: [{ name: "node", type: "bytes32" }, { name: "key", type: "string" }, { name: "value", type: "string" }], outputs: [] }
3298
+ ];
3299
+ function ensHintWrite(name, fingerprint) {
3300
+ const normalized = _ens.normalize.call(void 0, name);
3301
+ return {
3302
+ abi: ENS_TEXT_RESOLVER_ABI,
3303
+ functionName: "setText",
3304
+ args: [_ens.namehash.call(void 0, normalized), ENS_HINT_KEY, ensHintValue(fingerprint)],
3305
+ name: normalized
3306
+ };
2186
3307
  }
2187
- function claimFateText(fate, formatDate = (s) => formatClaimDate(s)) {
2188
- if (fate.state === "revoked") return `Revoked by its owner on ${formatDate(fate.at)}.`;
2189
- if (fate.state === "replaced") return `Replaced by claim #${fate.by} on ${formatDate(fate.at)}.`;
2190
- return null;
3308
+ async function fetchEnsHint(client, name, verifiedFingerprint) {
3309
+ const record = await client.getEnsText({ name: _ens.normalize.call(void 0, name), key: ENS_HINT_KEY });
3310
+ return ensHintFor(record, verifiedFingerprint);
2191
3311
  }
2192
3312
 
2193
3313
 
@@ -2261,5 +3381,26 @@ function claimFateText(fate, formatDate = (s) => formatClaimDate(s)) {
2261
3381
 
2262
3382
 
2263
3383
 
2264
- exports.REGISTRY_ABI = REGISTRY_ABI; exports.REGISTRY_ADDRESS = REGISTRY_ADDRESS; exports.NETWORKS = NETWORKS; exports.isNetworkName = isNetworkName; exports.getRegistry = getRegistry; exports.chainFor = chainFor; exports.needsRpcProbe = needsRpcProbe; exports.identityErrorKind = identityErrorKind; exports.IDENTITY_ERROR_TEXT = IDENTITY_ERROR_TEXT; exports.normalizeFingerprint = normalizeFingerprint; exports.fingerprintToBytes = fingerprintToBytes; exports.bytesToFingerprint = bytesToFingerprint; exports.fingerprintHash = fingerprintHash; exports.keyIdOf = keyIdOf; exports.keyIdToBytes = keyIdToBytes; exports.parsePgpKey = parsePgpKey; exports.verifyClearsigned = verifyClearsigned; exports.verifyAttestation = verifyAttestation; exports.stripEmailUserIDs = stripEmailUserIDs; exports.hasEmailUserID = hasEmailUserID; exports.fetchEFPGraph = fetchEFPGraph; exports.identifyProof = identifyProof; exports.displayUrl = displayUrl; exports.proofHref = proofHref; exports.proofSecondaryHref = proofSecondaryHref; exports.FARCASTER_HUB = FARCASTER_HUB; exports.verifyProof = verifyProof; exports.IPFS_GATEWAYS = IPFS_GATEWAYS; exports.IPFS_GATEWAY = IPFS_GATEWAY; exports.ARWEAVE_GATEWAY = ARWEAVE_GATEWAY; exports.avatarUrl = avatarUrl; exports.avatarFallbacks = avatarFallbacks; exports.parseNftAvatar = parseNftAvatar; exports.NFT_AVATAR_ABI = NFT_AVATAR_ABI; exports.nftAvatarImage = nftAvatarImage; exports.ENS_HINT_KEY = ENS_HINT_KEY; exports.ensHintFor = ensHintFor; exports.ensHintValue = ensHintValue; exports.ENS_TEXT_RESOLVER_ABI = ENS_TEXT_RESOLVER_ABI; exports.ensHintWrite = ensHintWrite; exports.fetchEnsHint = fetchEnsHint; exports.EIP712_NAME = EIP712_NAME; exports.EIP712_VERSION = EIP712_VERSION; exports.registryDomain = registryDomain; exports.AUTHORIZATION_TYPES = AUTHORIZATION_TYPES; exports.attestTypedData = attestTypedData; exports.reattestTypedData = reattestTypedData; exports.updateKeyTypedData = updateKeyTypedData; exports.revokeTypedData = revokeTypedData; exports.setRecordTypedData = setRecordTypedData; exports.authorizationDigest = authorizationDigest; exports.recordKind = recordKind; exports.MAX_RECORD_BYTES = MAX_RECORD_BYTES; exports.kindName = kindName; exports.KNOWN_KINDS = KNOWN_KINDS; exports.IDENTITY_KINDS = IDENTITY_KINDS; exports.encodeRecord = encodeRecord; exports.decodeRecord = decodeRecord; exports.parsePointer = parsePointer; exports.addPointer = addPointer; exports.renderPointer = renderPointer; exports.parseRecord = parseRecord; exports.fetchRecords = fetchRecords; exports.CLAIM_CHECK_LABEL = CLAIM_CHECK_LABEL; exports.formatClaimDate = formatClaimDate; exports.claimCheckText = claimCheckText; exports.expiresSoon = expiresSoon; exports.expiresSoonText = expiresSoonText; exports.claimFates = claimFates; exports.claimFateText = claimFateText;
2265
- //# sourceMappingURL=chunk-M2OJDB7I.cjs.map
3384
+
3385
+
3386
+
3387
+
3388
+
3389
+
3390
+
3391
+
3392
+
3393
+
3394
+
3395
+
3396
+
3397
+
3398
+
3399
+
3400
+
3401
+
3402
+
3403
+
3404
+
3405
+
3406
+ exports.normalizeFingerprint = normalizeFingerprint; exports.sameFingerprint = sameFingerprint; exports.fingerprintToBytes = fingerprintToBytes; exports.bytesToFingerprint = bytesToFingerprint; exports.fingerprintHash = fingerprintHash; exports.keyIdOf = keyIdOf; exports.keyIdToBytes = keyIdToBytes; exports.identifyProof = identifyProof; exports.displayUrl = displayUrl; exports.proofHref = proofHref; exports.proofSecondaryHref = proofSecondaryHref; exports.FARCASTER_HUB = FARCASTER_HUB; exports.verifyProof = verifyProof; exports.statementText = statementText; exports.parsePgpKey = parsePgpKey; exports.verifyClearsigned = verifyClearsigned; exports.verifyStatementSignature = verifyStatementSignature; exports.verifyAttestation = verifyAttestation; exports.stripEmailUserIDs = stripEmailUserIDs; exports.hasEmailUserID = hasEmailUserID; exports.leanKey = leanKey; exports.claimSignature = claimSignature; exports.signatureEmail = signatureEmail; exports.payloadText = payloadText; exports.sshKeys = sshKeys; exports.EIP712_NAME = EIP712_NAME; exports.EIP712_VERSION = EIP712_VERSION; exports.registryDomain = registryDomain; exports.AUTHORIZATION_TYPES = AUTHORIZATION_TYPES; exports.REVOKE_REASONS = REVOKE_REASONS; exports.OWNER_REVOKE_REASONS = OWNER_REVOKE_REASONS; exports.attestTypedData = attestTypedData; exports.reattestTypedData = reattestTypedData; exports.updateKeyTypedData = updateKeyTypedData; exports.revokeTypedData = revokeTypedData; exports.setRecordTypedData = setRecordTypedData; exports.markCompromisedTypedData = markCompromisedTypedData; exports.authorizationDigest = authorizationDigest; exports.permissionSigned = permissionSigned; exports.recordKind = recordKind; exports.REGISTRY_ABI = REGISTRY_ABI; exports.REGISTRY_ADDRESS = REGISTRY_ADDRESS; exports.NETWORKS = NETWORKS; exports.isNetworkName = isNetworkName; exports.getRegistry = getRegistry; exports.chainFor = chainFor; exports.CLAIM_LIMIT = CLAIM_LIMIT; exports.readClaims = readClaims; exports.keyStanding = keyStanding; exports.findOwners = findOwners; exports.CLAIM_CHECK_LABEL = CLAIM_CHECK_LABEL; exports.formatClaimDate = formatClaimDate; exports.claimCheckText = claimCheckText; exports.keyProblemText = keyProblemText; exports.expiresSoon = expiresSoon; exports.expiresSoonText = expiresSoonText; exports.claimFates = claimFates; exports.claimFateText = claimFateText; exports.encryptionKeyFor = encryptionKeyFor; exports.encryptRefusalText = encryptRefusalText; exports.keyChangedText = keyChangedText; exports.encryptTo = encryptTo; exports.CONTRACT_ERROR_TEXT = CONTRACT_ERROR_TEXT; exports.contractErrorName = contractErrorName; exports.contractErrorText = contractErrorText; exports.MAX_RECORD_BYTES = MAX_RECORD_BYTES; exports.MAX_KIND_BYTES = MAX_KIND_BYTES; exports.kindName = kindName; exports.checkKindName = checkKindName; exports.checkRecordValue = checkRecordValue; exports.KNOWN_KINDS = KNOWN_KINDS; exports.parseReleases = parseReleases; exports.addRelease = addRelease; exports.renderReleases = renderReleases; exports.parseRecord = parseRecord; exports.pickRecords = pickRecords; exports.pageRecords = pageRecords; exports.fetchRecords = fetchRecords; exports.IPFS_GATEWAYS = IPFS_GATEWAYS; exports.IPFS_GATEWAY = IPFS_GATEWAY; exports.ARWEAVE_GATEWAY = ARWEAVE_GATEWAY; exports.avatarUrl = avatarUrl; exports.avatarFallbacks = avatarFallbacks; exports.parseNftAvatar = parseNftAvatar; exports.NFT_AVATAR_ABI = NFT_AVATAR_ABI; exports.nftAvatarImage = nftAvatarImage; exports.ENS_HINT_KEY = ENS_HINT_KEY; exports.ensHintFor = ensHintFor; exports.ensHintValue = ensHintValue; exports.ENS_TEXT_RESOLVER_ABI = ENS_TEXT_RESOLVER_ABI; exports.ensHintWrite = ensHintWrite; exports.fetchEnsHint = fetchEnsHint;