@thurinlabs/identity-kit 1.4.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -384
- package/dist/{chunk-ZAQ2EPF5.js → chunk-AAJWERE2.js} +2455 -1343
- package/dist/{chunk-M2OJDB7I.cjs → chunk-DJGCYNJN.cjs} +2460 -1348
- package/dist/core.cjs +44 -3
- package/dist/core.d.cts +1563 -903
- package/dist/core.d.ts +1563 -903
- package/dist/core.js +65 -24
- package/dist/index.cjs +25 -459
- package/dist/index.d.cts +1 -83
- package/dist/index.d.ts +1 -83
- package/dist/index.js +65 -499
- package/package.json +5 -22
- package/dist/chunk-M2OJDB7I.cjs.map +0 -1
- package/dist/chunk-ZAQ2EPF5.js.map +0 -1
- package/dist/core.cjs.map +0 -1
- package/dist/core.js.map +0 -1
- package/dist/embed.global.js +0 -32213
- package/dist/embed.global.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.css +0 -185
- package/dist/index.css.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -1,237 +1,1162 @@
|
|
|
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(); } }
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
"
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
{
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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
|
-
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
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
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
+
function recordKind(name) {
|
|
866
|
+
return _viem.keccak256.call(void 0, _viem.stringToHex.call(void 0, name));
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
// src/core/contract.ts
|
|
870
|
+
var _chains = require('viem/chains');
|
|
871
|
+
|
|
872
|
+
// src/core/abi.ts
|
|
873
|
+
var REGISTRY_ABI = [
|
|
874
|
+
{
|
|
875
|
+
"type": "function",
|
|
876
|
+
"name": "ATTEST_TYPEHASH",
|
|
877
|
+
"inputs": [],
|
|
878
|
+
"outputs": [
|
|
879
|
+
{
|
|
880
|
+
"name": "",
|
|
881
|
+
"type": "bytes32",
|
|
882
|
+
"internalType": "bytes32"
|
|
883
|
+
}
|
|
884
|
+
],
|
|
885
|
+
"stateMutability": "view"
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
"type": "function",
|
|
889
|
+
"name": "DOMAIN_SEPARATOR",
|
|
890
|
+
"inputs": [],
|
|
891
|
+
"outputs": [
|
|
892
|
+
{
|
|
893
|
+
"name": "",
|
|
894
|
+
"type": "bytes32",
|
|
895
|
+
"internalType": "bytes32"
|
|
896
|
+
}
|
|
897
|
+
],
|
|
898
|
+
"stateMutability": "view"
|
|
899
|
+
},
|
|
900
|
+
{
|
|
901
|
+
"type": "function",
|
|
902
|
+
"name": "EIP712_NAME",
|
|
903
|
+
"inputs": [],
|
|
904
|
+
"outputs": [
|
|
905
|
+
{
|
|
906
|
+
"name": "",
|
|
907
|
+
"type": "string",
|
|
908
|
+
"internalType": "string"
|
|
909
|
+
}
|
|
910
|
+
],
|
|
911
|
+
"stateMutability": "view"
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
"type": "function",
|
|
915
|
+
"name": "EIP712_VERSION",
|
|
916
|
+
"inputs": [],
|
|
917
|
+
"outputs": [
|
|
918
|
+
{
|
|
919
|
+
"name": "",
|
|
920
|
+
"type": "string",
|
|
921
|
+
"internalType": "string"
|
|
922
|
+
}
|
|
923
|
+
],
|
|
924
|
+
"stateMutability": "view"
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
"type": "function",
|
|
928
|
+
"name": "EPOCH",
|
|
929
|
+
"inputs": [],
|
|
930
|
+
"outputs": [
|
|
931
|
+
{
|
|
932
|
+
"name": "",
|
|
933
|
+
"type": "uint256",
|
|
934
|
+
"internalType": "uint256"
|
|
935
|
+
}
|
|
936
|
+
],
|
|
937
|
+
"stateMutability": "view"
|
|
938
|
+
},
|
|
939
|
+
{
|
|
940
|
+
"type": "function",
|
|
941
|
+
"name": "MARK_COMPROMISED_TYPEHASH",
|
|
942
|
+
"inputs": [],
|
|
943
|
+
"outputs": [
|
|
944
|
+
{
|
|
945
|
+
"name": "",
|
|
946
|
+
"type": "bytes32",
|
|
947
|
+
"internalType": "bytes32"
|
|
948
|
+
}
|
|
949
|
+
],
|
|
950
|
+
"stateMutability": "view"
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
"type": "function",
|
|
954
|
+
"name": "MAX_CLAIMS_PER_OWNER",
|
|
955
|
+
"inputs": [],
|
|
956
|
+
"outputs": [
|
|
957
|
+
{
|
|
958
|
+
"name": "",
|
|
959
|
+
"type": "uint256",
|
|
227
960
|
"internalType": "uint256"
|
|
228
961
|
}
|
|
229
962
|
],
|
|
963
|
+
"stateMutability": "view"
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
"type": "function",
|
|
967
|
+
"name": "MAX_KEY_BYTES",
|
|
968
|
+
"inputs": [],
|
|
230
969
|
"outputs": [
|
|
231
970
|
{
|
|
232
|
-
"name": "
|
|
233
|
-
"type": "
|
|
234
|
-
"internalType": "
|
|
971
|
+
"name": "",
|
|
972
|
+
"type": "uint256",
|
|
973
|
+
"internalType": "uint256"
|
|
974
|
+
}
|
|
975
|
+
],
|
|
976
|
+
"stateMutability": "view"
|
|
977
|
+
},
|
|
978
|
+
{
|
|
979
|
+
"type": "function",
|
|
980
|
+
"name": "MAX_KIND_BYTES",
|
|
981
|
+
"inputs": [],
|
|
982
|
+
"outputs": [
|
|
983
|
+
{
|
|
984
|
+
"name": "",
|
|
985
|
+
"type": "uint256",
|
|
986
|
+
"internalType": "uint256"
|
|
987
|
+
}
|
|
988
|
+
],
|
|
989
|
+
"stateMutability": "view"
|
|
990
|
+
},
|
|
991
|
+
{
|
|
992
|
+
"type": "function",
|
|
993
|
+
"name": "MAX_PAYLOAD_BYTES",
|
|
994
|
+
"inputs": [],
|
|
995
|
+
"outputs": [
|
|
996
|
+
{
|
|
997
|
+
"name": "",
|
|
998
|
+
"type": "uint256",
|
|
999
|
+
"internalType": "uint256"
|
|
1000
|
+
}
|
|
1001
|
+
],
|
|
1002
|
+
"stateMutability": "view"
|
|
1003
|
+
},
|
|
1004
|
+
{
|
|
1005
|
+
"type": "function",
|
|
1006
|
+
"name": "MAX_RECORD_BYTES",
|
|
1007
|
+
"inputs": [],
|
|
1008
|
+
"outputs": [
|
|
1009
|
+
{
|
|
1010
|
+
"name": "",
|
|
1011
|
+
"type": "uint256",
|
|
1012
|
+
"internalType": "uint256"
|
|
1013
|
+
}
|
|
1014
|
+
],
|
|
1015
|
+
"stateMutability": "view"
|
|
1016
|
+
},
|
|
1017
|
+
{
|
|
1018
|
+
"type": "function",
|
|
1019
|
+
"name": "MAX_SIGNATURE_BYTES",
|
|
1020
|
+
"inputs": [],
|
|
1021
|
+
"outputs": [
|
|
1022
|
+
{
|
|
1023
|
+
"name": "",
|
|
1024
|
+
"type": "uint256",
|
|
1025
|
+
"internalType": "uint256"
|
|
1026
|
+
}
|
|
1027
|
+
],
|
|
1028
|
+
"stateMutability": "view"
|
|
1029
|
+
},
|
|
1030
|
+
{
|
|
1031
|
+
"type": "function",
|
|
1032
|
+
"name": "MESSAGE_CLEARSIGNED",
|
|
1033
|
+
"inputs": [],
|
|
1034
|
+
"outputs": [
|
|
1035
|
+
{
|
|
1036
|
+
"name": "",
|
|
1037
|
+
"type": "uint8",
|
|
1038
|
+
"internalType": "uint8"
|
|
1039
|
+
}
|
|
1040
|
+
],
|
|
1041
|
+
"stateMutability": "view"
|
|
1042
|
+
},
|
|
1043
|
+
{
|
|
1044
|
+
"type": "function",
|
|
1045
|
+
"name": "MESSAGE_DETACHED",
|
|
1046
|
+
"inputs": [],
|
|
1047
|
+
"outputs": [
|
|
1048
|
+
{
|
|
1049
|
+
"name": "",
|
|
1050
|
+
"type": "uint8",
|
|
1051
|
+
"internalType": "uint8"
|
|
1052
|
+
}
|
|
1053
|
+
],
|
|
1054
|
+
"stateMutability": "view"
|
|
1055
|
+
},
|
|
1056
|
+
{
|
|
1057
|
+
"type": "function",
|
|
1058
|
+
"name": "REATTEST_TYPEHASH",
|
|
1059
|
+
"inputs": [],
|
|
1060
|
+
"outputs": [
|
|
1061
|
+
{
|
|
1062
|
+
"name": "",
|
|
1063
|
+
"type": "bytes32",
|
|
1064
|
+
"internalType": "bytes32"
|
|
1065
|
+
}
|
|
1066
|
+
],
|
|
1067
|
+
"stateMutability": "view"
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
"type": "function",
|
|
1071
|
+
"name": "REVOKE_TYPEHASH",
|
|
1072
|
+
"inputs": [],
|
|
1073
|
+
"outputs": [
|
|
1074
|
+
{
|
|
1075
|
+
"name": "",
|
|
1076
|
+
"type": "bytes32",
|
|
1077
|
+
"internalType": "bytes32"
|
|
1078
|
+
}
|
|
1079
|
+
],
|
|
1080
|
+
"stateMutability": "view"
|
|
1081
|
+
},
|
|
1082
|
+
{
|
|
1083
|
+
"type": "function",
|
|
1084
|
+
"name": "SET_RECORD_TYPEHASH",
|
|
1085
|
+
"inputs": [],
|
|
1086
|
+
"outputs": [
|
|
1087
|
+
{
|
|
1088
|
+
"name": "",
|
|
1089
|
+
"type": "bytes32",
|
|
1090
|
+
"internalType": "bytes32"
|
|
1091
|
+
}
|
|
1092
|
+
],
|
|
1093
|
+
"stateMutability": "view"
|
|
1094
|
+
},
|
|
1095
|
+
{
|
|
1096
|
+
"type": "function",
|
|
1097
|
+
"name": "UPDATE_KEY_TYPEHASH",
|
|
1098
|
+
"inputs": [],
|
|
1099
|
+
"outputs": [
|
|
1100
|
+
{
|
|
1101
|
+
"name": "",
|
|
1102
|
+
"type": "bytes32",
|
|
1103
|
+
"internalType": "bytes32"
|
|
1104
|
+
}
|
|
1105
|
+
],
|
|
1106
|
+
"stateMutability": "view"
|
|
1107
|
+
},
|
|
1108
|
+
{
|
|
1109
|
+
"type": "function",
|
|
1110
|
+
"name": "VERSION",
|
|
1111
|
+
"inputs": [],
|
|
1112
|
+
"outputs": [
|
|
1113
|
+
{
|
|
1114
|
+
"name": "",
|
|
1115
|
+
"type": "uint8",
|
|
1116
|
+
"internalType": "uint8"
|
|
1117
|
+
}
|
|
1118
|
+
],
|
|
1119
|
+
"stateMutability": "view"
|
|
1120
|
+
},
|
|
1121
|
+
{
|
|
1122
|
+
"type": "function",
|
|
1123
|
+
"name": "armorToBytes",
|
|
1124
|
+
"inputs": [
|
|
1125
|
+
{
|
|
1126
|
+
"name": "armored",
|
|
1127
|
+
"type": "string",
|
|
1128
|
+
"internalType": "string"
|
|
1129
|
+
}
|
|
1130
|
+
],
|
|
1131
|
+
"outputs": [
|
|
1132
|
+
{
|
|
1133
|
+
"name": "",
|
|
1134
|
+
"type": "bytes",
|
|
1135
|
+
"internalType": "bytes"
|
|
1136
|
+
}
|
|
1137
|
+
],
|
|
1138
|
+
"stateMutability": "pure"
|
|
1139
|
+
},
|
|
1140
|
+
{
|
|
1141
|
+
"type": "function",
|
|
1142
|
+
"name": "armoredKey",
|
|
1143
|
+
"inputs": [
|
|
1144
|
+
{
|
|
1145
|
+
"name": "owner",
|
|
1146
|
+
"type": "address",
|
|
1147
|
+
"internalType": "address"
|
|
1148
|
+
},
|
|
1149
|
+
{
|
|
1150
|
+
"name": "index",
|
|
1151
|
+
"type": "uint256",
|
|
1152
|
+
"internalType": "uint256"
|
|
1153
|
+
}
|
|
1154
|
+
],
|
|
1155
|
+
"outputs": [
|
|
1156
|
+
{
|
|
1157
|
+
"name": "",
|
|
1158
|
+
"type": "string",
|
|
1159
|
+
"internalType": "string"
|
|
235
1160
|
}
|
|
236
1161
|
],
|
|
237
1162
|
"stateMutability": "view"
|
|
@@ -246,12 +1171,12 @@ var REGISTRY_ABI = [
|
|
|
246
1171
|
"internalType": "bytes"
|
|
247
1172
|
},
|
|
248
1173
|
{
|
|
249
|
-
"name": "
|
|
1174
|
+
"name": "signature",
|
|
250
1175
|
"type": "bytes",
|
|
251
1176
|
"internalType": "bytes"
|
|
252
1177
|
},
|
|
253
1178
|
{
|
|
254
|
-
"name": "
|
|
1179
|
+
"name": "key",
|
|
255
1180
|
"type": "bytes",
|
|
256
1181
|
"internalType": "bytes"
|
|
257
1182
|
}
|
|
@@ -280,38 +1205,126 @@ var REGISTRY_ABI = [
|
|
|
280
1205
|
"internalType": "bytes"
|
|
281
1206
|
},
|
|
282
1207
|
{
|
|
283
|
-
"name": "
|
|
1208
|
+
"name": "signature",
|
|
1209
|
+
"type": "bytes",
|
|
1210
|
+
"internalType": "bytes"
|
|
1211
|
+
},
|
|
1212
|
+
{
|
|
1213
|
+
"name": "key",
|
|
1214
|
+
"type": "bytes",
|
|
1215
|
+
"internalType": "bytes"
|
|
1216
|
+
},
|
|
1217
|
+
{
|
|
1218
|
+
"name": "deadline",
|
|
1219
|
+
"type": "uint256",
|
|
1220
|
+
"internalType": "uint256"
|
|
1221
|
+
},
|
|
1222
|
+
{
|
|
1223
|
+
"name": "permission",
|
|
284
1224
|
"type": "bytes",
|
|
285
1225
|
"internalType": "bytes"
|
|
1226
|
+
}
|
|
1227
|
+
],
|
|
1228
|
+
"outputs": [
|
|
1229
|
+
{
|
|
1230
|
+
"name": "index",
|
|
1231
|
+
"type": "uint256",
|
|
1232
|
+
"internalType": "uint256"
|
|
1233
|
+
}
|
|
1234
|
+
],
|
|
1235
|
+
"stateMutability": "nonpayable"
|
|
1236
|
+
},
|
|
1237
|
+
{
|
|
1238
|
+
"type": "function",
|
|
1239
|
+
"name": "cancelAuthorization",
|
|
1240
|
+
"inputs": [],
|
|
1241
|
+
"outputs": [],
|
|
1242
|
+
"stateMutability": "nonpayable"
|
|
1243
|
+
},
|
|
1244
|
+
{
|
|
1245
|
+
"type": "function",
|
|
1246
|
+
"name": "claim",
|
|
1247
|
+
"inputs": [
|
|
1248
|
+
{
|
|
1249
|
+
"name": "owner",
|
|
1250
|
+
"type": "address",
|
|
1251
|
+
"internalType": "address"
|
|
1252
|
+
},
|
|
1253
|
+
{
|
|
1254
|
+
"name": "index",
|
|
1255
|
+
"type": "uint256",
|
|
1256
|
+
"internalType": "uint256"
|
|
1257
|
+
}
|
|
1258
|
+
],
|
|
1259
|
+
"outputs": [
|
|
1260
|
+
{
|
|
1261
|
+
"name": "details",
|
|
1262
|
+
"type": "tuple",
|
|
1263
|
+
"internalType": "struct PGPRegistry.ClaimView",
|
|
1264
|
+
"components": [
|
|
1265
|
+
{
|
|
1266
|
+
"name": "index",
|
|
1267
|
+
"type": "uint256",
|
|
1268
|
+
"internalType": "uint256"
|
|
1269
|
+
},
|
|
1270
|
+
{
|
|
1271
|
+
"name": "fingerprint",
|
|
1272
|
+
"type": "bytes",
|
|
1273
|
+
"internalType": "bytes"
|
|
1274
|
+
},
|
|
1275
|
+
{
|
|
1276
|
+
"name": "createdAt",
|
|
1277
|
+
"type": "uint64",
|
|
1278
|
+
"internalType": "uint64"
|
|
1279
|
+
},
|
|
1280
|
+
{
|
|
1281
|
+
"name": "revokedAt",
|
|
1282
|
+
"type": "uint64",
|
|
1283
|
+
"internalType": "uint64"
|
|
1284
|
+
},
|
|
1285
|
+
{
|
|
1286
|
+
"name": "state",
|
|
1287
|
+
"type": "string",
|
|
1288
|
+
"internalType": "string"
|
|
1289
|
+
},
|
|
1290
|
+
{
|
|
1291
|
+
"name": "replacedBy",
|
|
1292
|
+
"type": "uint256",
|
|
1293
|
+
"internalType": "uint256"
|
|
1294
|
+
},
|
|
1295
|
+
{
|
|
1296
|
+
"name": "revokeReason",
|
|
1297
|
+
"type": "string",
|
|
1298
|
+
"internalType": "string"
|
|
1299
|
+
},
|
|
1300
|
+
{
|
|
1301
|
+
"name": "messageVersion",
|
|
1302
|
+
"type": "uint8",
|
|
1303
|
+
"internalType": "uint8"
|
|
1304
|
+
}
|
|
1305
|
+
]
|
|
286
1306
|
},
|
|
287
1307
|
{
|
|
288
|
-
"name": "
|
|
289
|
-
"type": "
|
|
290
|
-
"internalType": "
|
|
1308
|
+
"name": "key",
|
|
1309
|
+
"type": "string",
|
|
1310
|
+
"internalType": "string"
|
|
291
1311
|
},
|
|
292
1312
|
{
|
|
293
|
-
"name": "
|
|
294
|
-
"type": "
|
|
295
|
-
"internalType": "
|
|
1313
|
+
"name": "statement",
|
|
1314
|
+
"type": "string",
|
|
1315
|
+
"internalType": "string"
|
|
296
1316
|
},
|
|
297
1317
|
{
|
|
298
|
-
"name": "
|
|
299
|
-
"type": "
|
|
300
|
-
"internalType": "
|
|
301
|
-
}
|
|
302
|
-
],
|
|
303
|
-
"outputs": [
|
|
304
|
-
{
|
|
305
|
-
"name": "index",
|
|
306
|
-
"type": "uint256",
|
|
307
|
-
"internalType": "uint256"
|
|
1318
|
+
"name": "recordKinds",
|
|
1319
|
+
"type": "string[]",
|
|
1320
|
+
"internalType": "string[]"
|
|
308
1321
|
}
|
|
309
1322
|
],
|
|
310
|
-
"stateMutability": "
|
|
1323
|
+
"stateMutability": "view"
|
|
311
1324
|
},
|
|
312
1325
|
{
|
|
313
1326
|
"type": "function",
|
|
314
|
-
"name": "
|
|
1327
|
+
"name": "claimCount",
|
|
315
1328
|
"inputs": [
|
|
316
1329
|
{
|
|
317
1330
|
"name": "owner",
|
|
@@ -330,7 +1343,7 @@ var REGISTRY_ABI = [
|
|
|
330
1343
|
},
|
|
331
1344
|
{
|
|
332
1345
|
"type": "function",
|
|
333
|
-
"name": "
|
|
1346
|
+
"name": "claimsOf",
|
|
334
1347
|
"inputs": [
|
|
335
1348
|
{
|
|
336
1349
|
"name": "owner",
|
|
@@ -340,10 +1353,15 @@ var REGISTRY_ABI = [
|
|
|
340
1353
|
],
|
|
341
1354
|
"outputs": [
|
|
342
1355
|
{
|
|
343
|
-
"name": "",
|
|
1356
|
+
"name": "out",
|
|
344
1357
|
"type": "tuple[]",
|
|
345
|
-
"internalType": "struct PGPRegistry.
|
|
1358
|
+
"internalType": "struct PGPRegistry.ClaimView[]",
|
|
346
1359
|
"components": [
|
|
1360
|
+
{
|
|
1361
|
+
"name": "index",
|
|
1362
|
+
"type": "uint256",
|
|
1363
|
+
"internalType": "uint256"
|
|
1364
|
+
},
|
|
347
1365
|
{
|
|
348
1366
|
"name": "fingerprint",
|
|
349
1367
|
"type": "bytes",
|
|
@@ -360,19 +1378,24 @@ var REGISTRY_ABI = [
|
|
|
360
1378
|
"internalType": "uint64"
|
|
361
1379
|
},
|
|
362
1380
|
{
|
|
363
|
-
"name": "
|
|
364
|
-
"type": "
|
|
365
|
-
"internalType": "
|
|
1381
|
+
"name": "state",
|
|
1382
|
+
"type": "string",
|
|
1383
|
+
"internalType": "string"
|
|
1384
|
+
},
|
|
1385
|
+
{
|
|
1386
|
+
"name": "replacedBy",
|
|
1387
|
+
"type": "uint256",
|
|
1388
|
+
"internalType": "uint256"
|
|
366
1389
|
},
|
|
367
1390
|
{
|
|
368
|
-
"name": "
|
|
369
|
-
"type": "
|
|
370
|
-
"internalType": "
|
|
1391
|
+
"name": "revokeReason",
|
|
1392
|
+
"type": "string",
|
|
1393
|
+
"internalType": "string"
|
|
371
1394
|
},
|
|
372
1395
|
{
|
|
373
|
-
"name": "
|
|
374
|
-
"type": "
|
|
375
|
-
"internalType": "
|
|
1396
|
+
"name": "messageVersion",
|
|
1397
|
+
"type": "uint8",
|
|
1398
|
+
"internalType": "uint8"
|
|
376
1399
|
}
|
|
377
1400
|
]
|
|
378
1401
|
}
|
|
@@ -381,7 +1404,7 @@ var REGISTRY_ABI = [
|
|
|
381
1404
|
},
|
|
382
1405
|
{
|
|
383
1406
|
"type": "function",
|
|
384
|
-
"name": "
|
|
1407
|
+
"name": "claimsOfRange",
|
|
385
1408
|
"inputs": [
|
|
386
1409
|
{
|
|
387
1410
|
"name": "owner",
|
|
@@ -403,8 +1426,13 @@ var REGISTRY_ABI = [
|
|
|
403
1426
|
{
|
|
404
1427
|
"name": "out",
|
|
405
1428
|
"type": "tuple[]",
|
|
406
|
-
"internalType": "struct PGPRegistry.
|
|
1429
|
+
"internalType": "struct PGPRegistry.ClaimView[]",
|
|
407
1430
|
"components": [
|
|
1431
|
+
{
|
|
1432
|
+
"name": "index",
|
|
1433
|
+
"type": "uint256",
|
|
1434
|
+
"internalType": "uint256"
|
|
1435
|
+
},
|
|
408
1436
|
{
|
|
409
1437
|
"name": "fingerprint",
|
|
410
1438
|
"type": "bytes",
|
|
@@ -421,19 +1449,24 @@ var REGISTRY_ABI = [
|
|
|
421
1449
|
"internalType": "uint64"
|
|
422
1450
|
},
|
|
423
1451
|
{
|
|
424
|
-
"name": "
|
|
425
|
-
"type": "
|
|
426
|
-
"internalType": "
|
|
1452
|
+
"name": "state",
|
|
1453
|
+
"type": "string",
|
|
1454
|
+
"internalType": "string"
|
|
1455
|
+
},
|
|
1456
|
+
{
|
|
1457
|
+
"name": "replacedBy",
|
|
1458
|
+
"type": "uint256",
|
|
1459
|
+
"internalType": "uint256"
|
|
427
1460
|
},
|
|
428
1461
|
{
|
|
429
|
-
"name": "
|
|
430
|
-
"type": "
|
|
431
|
-
"internalType": "
|
|
1462
|
+
"name": "revokeReason",
|
|
1463
|
+
"type": "string",
|
|
1464
|
+
"internalType": "string"
|
|
432
1465
|
},
|
|
433
1466
|
{
|
|
434
|
-
"name": "
|
|
435
|
-
"type": "
|
|
436
|
-
"internalType": "
|
|
1467
|
+
"name": "messageVersion",
|
|
1468
|
+
"type": "uint8",
|
|
1469
|
+
"internalType": "uint8"
|
|
437
1470
|
}
|
|
438
1471
|
]
|
|
439
1472
|
}
|
|
@@ -442,10 +1475,27 @@ var REGISTRY_ABI = [
|
|
|
442
1475
|
},
|
|
443
1476
|
{
|
|
444
1477
|
"type": "function",
|
|
445
|
-
"name": "
|
|
446
|
-
"inputs": [
|
|
447
|
-
|
|
448
|
-
|
|
1478
|
+
"name": "clearsigned",
|
|
1479
|
+
"inputs": [
|
|
1480
|
+
{
|
|
1481
|
+
"name": "owner",
|
|
1482
|
+
"type": "address",
|
|
1483
|
+
"internalType": "address"
|
|
1484
|
+
},
|
|
1485
|
+
{
|
|
1486
|
+
"name": "index",
|
|
1487
|
+
"type": "uint256",
|
|
1488
|
+
"internalType": "uint256"
|
|
1489
|
+
}
|
|
1490
|
+
],
|
|
1491
|
+
"outputs": [
|
|
1492
|
+
{
|
|
1493
|
+
"name": "",
|
|
1494
|
+
"type": "string",
|
|
1495
|
+
"internalType": "string"
|
|
1496
|
+
}
|
|
1497
|
+
],
|
|
1498
|
+
"stateMutability": "view"
|
|
449
1499
|
},
|
|
450
1500
|
{
|
|
451
1501
|
"type": "function",
|
|
@@ -469,10 +1519,15 @@ var REGISTRY_ABI = [
|
|
|
469
1519
|
"internalType": "uint256"
|
|
470
1520
|
},
|
|
471
1521
|
{
|
|
472
|
-
"name": "
|
|
1522
|
+
"name": "details",
|
|
473
1523
|
"type": "tuple",
|
|
474
|
-
"internalType": "struct PGPRegistry.
|
|
1524
|
+
"internalType": "struct PGPRegistry.ClaimView",
|
|
475
1525
|
"components": [
|
|
1526
|
+
{
|
|
1527
|
+
"name": "index",
|
|
1528
|
+
"type": "uint256",
|
|
1529
|
+
"internalType": "uint256"
|
|
1530
|
+
},
|
|
476
1531
|
{
|
|
477
1532
|
"name": "fingerprint",
|
|
478
1533
|
"type": "bytes",
|
|
@@ -489,52 +1544,243 @@ var REGISTRY_ABI = [
|
|
|
489
1544
|
"internalType": "uint64"
|
|
490
1545
|
},
|
|
491
1546
|
{
|
|
492
|
-
"name": "
|
|
493
|
-
"type": "
|
|
494
|
-
"internalType": "
|
|
1547
|
+
"name": "state",
|
|
1548
|
+
"type": "string",
|
|
1549
|
+
"internalType": "string"
|
|
1550
|
+
},
|
|
1551
|
+
{
|
|
1552
|
+
"name": "replacedBy",
|
|
1553
|
+
"type": "uint256",
|
|
1554
|
+
"internalType": "uint256"
|
|
495
1555
|
},
|
|
496
1556
|
{
|
|
497
|
-
"name": "
|
|
498
|
-
"type": "
|
|
499
|
-
"internalType": "
|
|
1557
|
+
"name": "revokeReason",
|
|
1558
|
+
"type": "string",
|
|
1559
|
+
"internalType": "string"
|
|
500
1560
|
},
|
|
501
1561
|
{
|
|
502
|
-
"name": "
|
|
503
|
-
"type": "
|
|
504
|
-
"internalType": "
|
|
1562
|
+
"name": "messageVersion",
|
|
1563
|
+
"type": "uint8",
|
|
1564
|
+
"internalType": "uint8"
|
|
505
1565
|
}
|
|
506
1566
|
]
|
|
507
1567
|
}
|
|
508
1568
|
],
|
|
509
|
-
"stateMutability": "view"
|
|
1569
|
+
"stateMutability": "view"
|
|
1570
|
+
},
|
|
1571
|
+
{
|
|
1572
|
+
"type": "function",
|
|
1573
|
+
"name": "eip712Domain",
|
|
1574
|
+
"inputs": [],
|
|
1575
|
+
"outputs": [
|
|
1576
|
+
{
|
|
1577
|
+
"name": "fields",
|
|
1578
|
+
"type": "bytes1",
|
|
1579
|
+
"internalType": "bytes1"
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
"name": "name",
|
|
1583
|
+
"type": "string",
|
|
1584
|
+
"internalType": "string"
|
|
1585
|
+
},
|
|
1586
|
+
{
|
|
1587
|
+
"name": "version",
|
|
1588
|
+
"type": "string",
|
|
1589
|
+
"internalType": "string"
|
|
1590
|
+
},
|
|
1591
|
+
{
|
|
1592
|
+
"name": "chainId",
|
|
1593
|
+
"type": "uint256",
|
|
1594
|
+
"internalType": "uint256"
|
|
1595
|
+
},
|
|
1596
|
+
{
|
|
1597
|
+
"name": "verifyingContract",
|
|
1598
|
+
"type": "address",
|
|
1599
|
+
"internalType": "address"
|
|
1600
|
+
},
|
|
1601
|
+
{
|
|
1602
|
+
"name": "salt",
|
|
1603
|
+
"type": "bytes32",
|
|
1604
|
+
"internalType": "bytes32"
|
|
1605
|
+
},
|
|
1606
|
+
{
|
|
1607
|
+
"name": "extensions",
|
|
1608
|
+
"type": "uint256[]",
|
|
1609
|
+
"internalType": "uint256[]"
|
|
1610
|
+
}
|
|
1611
|
+
],
|
|
1612
|
+
"stateMutability": "view"
|
|
1613
|
+
},
|
|
1614
|
+
{
|
|
1615
|
+
"type": "function",
|
|
1616
|
+
"name": "fingerprintsForKeyId",
|
|
1617
|
+
"inputs": [
|
|
1618
|
+
{
|
|
1619
|
+
"name": "keyId",
|
|
1620
|
+
"type": "bytes8",
|
|
1621
|
+
"internalType": "bytes8"
|
|
1622
|
+
}
|
|
1623
|
+
],
|
|
1624
|
+
"outputs": [
|
|
1625
|
+
{
|
|
1626
|
+
"name": "",
|
|
1627
|
+
"type": "bytes[]",
|
|
1628
|
+
"internalType": "bytes[]"
|
|
1629
|
+
}
|
|
1630
|
+
],
|
|
1631
|
+
"stateMutability": "view"
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
"type": "function",
|
|
1635
|
+
"name": "fingerprintsForKeyIdCount",
|
|
1636
|
+
"inputs": [
|
|
1637
|
+
{
|
|
1638
|
+
"name": "keyId",
|
|
1639
|
+
"type": "bytes8",
|
|
1640
|
+
"internalType": "bytes8"
|
|
1641
|
+
}
|
|
1642
|
+
],
|
|
1643
|
+
"outputs": [
|
|
1644
|
+
{
|
|
1645
|
+
"name": "",
|
|
1646
|
+
"type": "uint256",
|
|
1647
|
+
"internalType": "uint256"
|
|
1648
|
+
}
|
|
1649
|
+
],
|
|
1650
|
+
"stateMutability": "view"
|
|
1651
|
+
},
|
|
1652
|
+
{
|
|
1653
|
+
"type": "function",
|
|
1654
|
+
"name": "fingerprintsForKeyIdRange",
|
|
1655
|
+
"inputs": [
|
|
1656
|
+
{
|
|
1657
|
+
"name": "keyId",
|
|
1658
|
+
"type": "bytes8",
|
|
1659
|
+
"internalType": "bytes8"
|
|
1660
|
+
},
|
|
1661
|
+
{
|
|
1662
|
+
"name": "start",
|
|
1663
|
+
"type": "uint256",
|
|
1664
|
+
"internalType": "uint256"
|
|
1665
|
+
},
|
|
1666
|
+
{
|
|
1667
|
+
"name": "count",
|
|
1668
|
+
"type": "uint256",
|
|
1669
|
+
"internalType": "uint256"
|
|
1670
|
+
}
|
|
1671
|
+
],
|
|
1672
|
+
"outputs": [
|
|
1673
|
+
{
|
|
1674
|
+
"name": "out",
|
|
1675
|
+
"type": "bytes[]",
|
|
1676
|
+
"internalType": "bytes[]"
|
|
1677
|
+
}
|
|
1678
|
+
],
|
|
1679
|
+
"stateMutability": "view"
|
|
1680
|
+
},
|
|
1681
|
+
{
|
|
1682
|
+
"type": "function",
|
|
1683
|
+
"name": "keyBytes",
|
|
1684
|
+
"inputs": [
|
|
1685
|
+
{
|
|
1686
|
+
"name": "owner",
|
|
1687
|
+
"type": "address",
|
|
1688
|
+
"internalType": "address"
|
|
1689
|
+
},
|
|
1690
|
+
{
|
|
1691
|
+
"name": "index",
|
|
1692
|
+
"type": "uint256",
|
|
1693
|
+
"internalType": "uint256"
|
|
1694
|
+
}
|
|
1695
|
+
],
|
|
1696
|
+
"outputs": [
|
|
1697
|
+
{
|
|
1698
|
+
"name": "key",
|
|
1699
|
+
"type": "bytes",
|
|
1700
|
+
"internalType": "bytes"
|
|
1701
|
+
}
|
|
1702
|
+
],
|
|
1703
|
+
"stateMutability": "view"
|
|
1704
|
+
},
|
|
1705
|
+
{
|
|
1706
|
+
"type": "function",
|
|
1707
|
+
"name": "keyStatus",
|
|
1708
|
+
"inputs": [
|
|
1709
|
+
{
|
|
1710
|
+
"name": "owner",
|
|
1711
|
+
"type": "address",
|
|
1712
|
+
"internalType": "address"
|
|
1713
|
+
},
|
|
1714
|
+
{
|
|
1715
|
+
"name": "fingerprint",
|
|
1716
|
+
"type": "bytes",
|
|
1717
|
+
"internalType": "bytes"
|
|
1718
|
+
}
|
|
1719
|
+
],
|
|
1720
|
+
"outputs": [
|
|
1721
|
+
{
|
|
1722
|
+
"name": "",
|
|
1723
|
+
"type": "string",
|
|
1724
|
+
"internalType": "string"
|
|
1725
|
+
}
|
|
1726
|
+
],
|
|
1727
|
+
"stateMutability": "view"
|
|
1728
|
+
},
|
|
1729
|
+
{
|
|
1730
|
+
"type": "function",
|
|
1731
|
+
"name": "markCompromisedFor",
|
|
1732
|
+
"inputs": [
|
|
1733
|
+
{
|
|
1734
|
+
"name": "owner",
|
|
1735
|
+
"type": "address",
|
|
1736
|
+
"internalType": "address"
|
|
1737
|
+
},
|
|
1738
|
+
{
|
|
1739
|
+
"name": "index",
|
|
1740
|
+
"type": "uint256",
|
|
1741
|
+
"internalType": "uint256"
|
|
1742
|
+
},
|
|
1743
|
+
{
|
|
1744
|
+
"name": "deadline",
|
|
1745
|
+
"type": "uint256",
|
|
1746
|
+
"internalType": "uint256"
|
|
1747
|
+
},
|
|
1748
|
+
{
|
|
1749
|
+
"name": "permission",
|
|
1750
|
+
"type": "bytes",
|
|
1751
|
+
"internalType": "bytes"
|
|
1752
|
+
}
|
|
1753
|
+
],
|
|
1754
|
+
"outputs": [],
|
|
1755
|
+
"stateMutability": "nonpayable"
|
|
510
1756
|
},
|
|
511
1757
|
{
|
|
512
1758
|
"type": "function",
|
|
513
|
-
"name": "
|
|
1759
|
+
"name": "multicall",
|
|
514
1760
|
"inputs": [
|
|
515
1761
|
{
|
|
516
|
-
"name": "
|
|
517
|
-
"type": "
|
|
518
|
-
"internalType": "
|
|
1762
|
+
"name": "calls",
|
|
1763
|
+
"type": "bytes[]",
|
|
1764
|
+
"internalType": "bytes[]"
|
|
519
1765
|
}
|
|
520
1766
|
],
|
|
521
1767
|
"outputs": [
|
|
522
1768
|
{
|
|
523
|
-
"name": "",
|
|
1769
|
+
"name": "results",
|
|
524
1770
|
"type": "bytes[]",
|
|
525
1771
|
"internalType": "bytes[]"
|
|
526
1772
|
}
|
|
527
1773
|
],
|
|
528
|
-
"stateMutability": "
|
|
1774
|
+
"stateMutability": "nonpayable"
|
|
529
1775
|
},
|
|
530
1776
|
{
|
|
531
1777
|
"type": "function",
|
|
532
|
-
"name": "
|
|
1778
|
+
"name": "nonces",
|
|
533
1779
|
"inputs": [
|
|
534
1780
|
{
|
|
535
|
-
"name": "
|
|
536
|
-
"type": "
|
|
537
|
-
"internalType": "
|
|
1781
|
+
"name": "owner",
|
|
1782
|
+
"type": "address",
|
|
1783
|
+
"internalType": "address"
|
|
538
1784
|
}
|
|
539
1785
|
],
|
|
540
1786
|
"outputs": [
|
|
@@ -548,133 +1794,67 @@ var REGISTRY_ABI = [
|
|
|
548
1794
|
},
|
|
549
1795
|
{
|
|
550
1796
|
"type": "function",
|
|
551
|
-
"name": "
|
|
1797
|
+
"name": "ownersOf",
|
|
552
1798
|
"inputs": [
|
|
553
1799
|
{
|
|
554
|
-
"name": "
|
|
555
|
-
"type": "
|
|
556
|
-
"internalType": "
|
|
557
|
-
},
|
|
558
|
-
{
|
|
559
|
-
"name": "start",
|
|
560
|
-
"type": "uint256",
|
|
561
|
-
"internalType": "uint256"
|
|
562
|
-
},
|
|
563
|
-
{
|
|
564
|
-
"name": "count",
|
|
565
|
-
"type": "uint256",
|
|
566
|
-
"internalType": "uint256"
|
|
1800
|
+
"name": "fingerprint",
|
|
1801
|
+
"type": "bytes",
|
|
1802
|
+
"internalType": "bytes"
|
|
567
1803
|
}
|
|
568
1804
|
],
|
|
569
1805
|
"outputs": [
|
|
570
1806
|
{
|
|
571
|
-
"name": "
|
|
572
|
-
"type": "
|
|
573
|
-
"internalType": "
|
|
1807
|
+
"name": "",
|
|
1808
|
+
"type": "address[]",
|
|
1809
|
+
"internalType": "address[]"
|
|
574
1810
|
}
|
|
575
1811
|
],
|
|
576
1812
|
"stateMutability": "view"
|
|
577
1813
|
},
|
|
578
1814
|
{
|
|
579
1815
|
"type": "function",
|
|
580
|
-
"name": "
|
|
1816
|
+
"name": "ownersOfCount",
|
|
581
1817
|
"inputs": [
|
|
582
1818
|
{
|
|
583
|
-
"name": "
|
|
584
|
-
"type": "
|
|
585
|
-
"internalType": "
|
|
586
|
-
},
|
|
587
|
-
{
|
|
588
|
-
"name": "index",
|
|
589
|
-
"type": "uint256",
|
|
590
|
-
"internalType": "uint256"
|
|
1819
|
+
"name": "fingerprint",
|
|
1820
|
+
"type": "bytes",
|
|
1821
|
+
"internalType": "bytes"
|
|
591
1822
|
}
|
|
592
1823
|
],
|
|
593
1824
|
"outputs": [
|
|
594
1825
|
{
|
|
595
1826
|
"name": "",
|
|
596
|
-
"type": "
|
|
597
|
-
"internalType": "
|
|
598
|
-
"components": [
|
|
599
|
-
{
|
|
600
|
-
"name": "fingerprint",
|
|
601
|
-
"type": "bytes",
|
|
602
|
-
"internalType": "bytes"
|
|
603
|
-
},
|
|
604
|
-
{
|
|
605
|
-
"name": "createdAt",
|
|
606
|
-
"type": "uint64",
|
|
607
|
-
"internalType": "uint64"
|
|
608
|
-
},
|
|
609
|
-
{
|
|
610
|
-
"name": "revokedAt",
|
|
611
|
-
"type": "uint64",
|
|
612
|
-
"internalType": "uint64"
|
|
613
|
-
},
|
|
614
|
-
{
|
|
615
|
-
"name": "messageVersion",
|
|
616
|
-
"type": "uint8",
|
|
617
|
-
"internalType": "uint8"
|
|
618
|
-
},
|
|
619
|
-
{
|
|
620
|
-
"name": "keyPtr",
|
|
621
|
-
"type": "address",
|
|
622
|
-
"internalType": "address"
|
|
623
|
-
},
|
|
624
|
-
{
|
|
625
|
-
"name": "sigPtr",
|
|
626
|
-
"type": "address",
|
|
627
|
-
"internalType": "address"
|
|
628
|
-
}
|
|
629
|
-
]
|
|
1827
|
+
"type": "uint256",
|
|
1828
|
+
"internalType": "uint256"
|
|
630
1829
|
}
|
|
631
1830
|
],
|
|
632
1831
|
"stateMutability": "view"
|
|
633
1832
|
},
|
|
634
1833
|
{
|
|
635
1834
|
"type": "function",
|
|
636
|
-
"name": "
|
|
1835
|
+
"name": "ownersOfRange",
|
|
637
1836
|
"inputs": [
|
|
638
1837
|
{
|
|
639
|
-
"name": "
|
|
640
|
-
"type": "
|
|
641
|
-
"internalType": "
|
|
1838
|
+
"name": "fingerprint",
|
|
1839
|
+
"type": "bytes",
|
|
1840
|
+
"internalType": "bytes"
|
|
642
1841
|
},
|
|
643
1842
|
{
|
|
644
|
-
"name": "
|
|
1843
|
+
"name": "start",
|
|
645
1844
|
"type": "uint256",
|
|
646
1845
|
"internalType": "uint256"
|
|
647
|
-
}
|
|
648
|
-
],
|
|
649
|
-
"outputs": [
|
|
650
|
-
{
|
|
651
|
-
"name": "pgpSignature",
|
|
652
|
-
"type": "bytes",
|
|
653
|
-
"internalType": "bytes"
|
|
654
1846
|
},
|
|
655
1847
|
{
|
|
656
|
-
"name": "
|
|
657
|
-
"type": "
|
|
658
|
-
"internalType": "
|
|
659
|
-
}
|
|
660
|
-
],
|
|
661
|
-
"stateMutability": "view"
|
|
662
|
-
},
|
|
663
|
-
{
|
|
664
|
-
"type": "function",
|
|
665
|
-
"name": "nonces",
|
|
666
|
-
"inputs": [
|
|
667
|
-
{
|
|
668
|
-
"name": "",
|
|
669
|
-
"type": "address",
|
|
670
|
-
"internalType": "address"
|
|
1848
|
+
"name": "count",
|
|
1849
|
+
"type": "uint256",
|
|
1850
|
+
"internalType": "uint256"
|
|
671
1851
|
}
|
|
672
1852
|
],
|
|
673
1853
|
"outputs": [
|
|
674
1854
|
{
|
|
675
|
-
"name": "",
|
|
676
|
-
"type": "
|
|
677
|
-
"internalType": "
|
|
1855
|
+
"name": "out",
|
|
1856
|
+
"type": "address[]",
|
|
1857
|
+
"internalType": "address[]"
|
|
678
1858
|
}
|
|
679
1859
|
],
|
|
680
1860
|
"stateMutability": "view"
|
|
@@ -694,14 +1874,19 @@ var REGISTRY_ABI = [
|
|
|
694
1874
|
"internalType": "bytes"
|
|
695
1875
|
},
|
|
696
1876
|
{
|
|
697
|
-
"name": "
|
|
1877
|
+
"name": "signature",
|
|
698
1878
|
"type": "bytes",
|
|
699
1879
|
"internalType": "bytes"
|
|
700
1880
|
},
|
|
701
1881
|
{
|
|
702
|
-
"name": "
|
|
1882
|
+
"name": "key",
|
|
703
1883
|
"type": "bytes",
|
|
704
1884
|
"internalType": "bytes"
|
|
1885
|
+
},
|
|
1886
|
+
{
|
|
1887
|
+
"name": "keepRecords",
|
|
1888
|
+
"type": "bool",
|
|
1889
|
+
"internalType": "bool"
|
|
705
1890
|
}
|
|
706
1891
|
],
|
|
707
1892
|
"outputs": [
|
|
@@ -733,22 +1918,27 @@ var REGISTRY_ABI = [
|
|
|
733
1918
|
"internalType": "bytes"
|
|
734
1919
|
},
|
|
735
1920
|
{
|
|
736
|
-
"name": "
|
|
1921
|
+
"name": "signature",
|
|
737
1922
|
"type": "bytes",
|
|
738
1923
|
"internalType": "bytes"
|
|
739
1924
|
},
|
|
740
1925
|
{
|
|
741
|
-
"name": "
|
|
1926
|
+
"name": "key",
|
|
742
1927
|
"type": "bytes",
|
|
743
1928
|
"internalType": "bytes"
|
|
744
1929
|
},
|
|
1930
|
+
{
|
|
1931
|
+
"name": "keepRecords",
|
|
1932
|
+
"type": "bool",
|
|
1933
|
+
"internalType": "bool"
|
|
1934
|
+
},
|
|
745
1935
|
{
|
|
746
1936
|
"name": "deadline",
|
|
747
1937
|
"type": "uint256",
|
|
748
1938
|
"internalType": "uint256"
|
|
749
1939
|
},
|
|
750
1940
|
{
|
|
751
|
-
"name": "
|
|
1941
|
+
"name": "permission",
|
|
752
1942
|
"type": "bytes",
|
|
753
1943
|
"internalType": "bytes"
|
|
754
1944
|
}
|
|
@@ -764,7 +1954,7 @@ var REGISTRY_ABI = [
|
|
|
764
1954
|
},
|
|
765
1955
|
{
|
|
766
1956
|
"type": "function",
|
|
767
|
-
"name": "
|
|
1957
|
+
"name": "recordText",
|
|
768
1958
|
"inputs": [
|
|
769
1959
|
{
|
|
770
1960
|
"name": "owner",
|
|
@@ -778,15 +1968,44 @@ var REGISTRY_ABI = [
|
|
|
778
1968
|
},
|
|
779
1969
|
{
|
|
780
1970
|
"name": "kind",
|
|
781
|
-
"type": "
|
|
782
|
-
"internalType": "
|
|
1971
|
+
"type": "string",
|
|
1972
|
+
"internalType": "string"
|
|
783
1973
|
}
|
|
784
1974
|
],
|
|
785
1975
|
"outputs": [
|
|
786
1976
|
{
|
|
787
1977
|
"name": "",
|
|
788
|
-
"type": "
|
|
789
|
-
"internalType": "
|
|
1978
|
+
"type": "string",
|
|
1979
|
+
"internalType": "string"
|
|
1980
|
+
}
|
|
1981
|
+
],
|
|
1982
|
+
"stateMutability": "view"
|
|
1983
|
+
},
|
|
1984
|
+
{
|
|
1985
|
+
"type": "function",
|
|
1986
|
+
"name": "recordsOf",
|
|
1987
|
+
"inputs": [
|
|
1988
|
+
{
|
|
1989
|
+
"name": "owner",
|
|
1990
|
+
"type": "address",
|
|
1991
|
+
"internalType": "address"
|
|
1992
|
+
},
|
|
1993
|
+
{
|
|
1994
|
+
"name": "index",
|
|
1995
|
+
"type": "uint256",
|
|
1996
|
+
"internalType": "uint256"
|
|
1997
|
+
}
|
|
1998
|
+
],
|
|
1999
|
+
"outputs": [
|
|
2000
|
+
{
|
|
2001
|
+
"name": "kinds",
|
|
2002
|
+
"type": "string[]",
|
|
2003
|
+
"internalType": "string[]"
|
|
2004
|
+
},
|
|
2005
|
+
{
|
|
2006
|
+
"name": "values",
|
|
2007
|
+
"type": "string[]",
|
|
2008
|
+
"internalType": "string[]"
|
|
790
2009
|
}
|
|
791
2010
|
],
|
|
792
2011
|
"stateMutability": "view"
|
|
@@ -799,6 +2018,11 @@ var REGISTRY_ABI = [
|
|
|
799
2018
|
"name": "index",
|
|
800
2019
|
"type": "uint256",
|
|
801
2020
|
"internalType": "uint256"
|
|
2021
|
+
},
|
|
2022
|
+
{
|
|
2023
|
+
"name": "reason",
|
|
2024
|
+
"type": "string",
|
|
2025
|
+
"internalType": "string"
|
|
802
2026
|
}
|
|
803
2027
|
],
|
|
804
2028
|
"outputs": [],
|
|
@@ -818,13 +2042,18 @@ var REGISTRY_ABI = [
|
|
|
818
2042
|
"type": "uint256",
|
|
819
2043
|
"internalType": "uint256"
|
|
820
2044
|
},
|
|
2045
|
+
{
|
|
2046
|
+
"name": "reason",
|
|
2047
|
+
"type": "string",
|
|
2048
|
+
"internalType": "string"
|
|
2049
|
+
},
|
|
821
2050
|
{
|
|
822
2051
|
"name": "deadline",
|
|
823
2052
|
"type": "uint256",
|
|
824
2053
|
"internalType": "uint256"
|
|
825
2054
|
},
|
|
826
2055
|
{
|
|
827
|
-
"name": "
|
|
2056
|
+
"name": "permission",
|
|
828
2057
|
"type": "bytes",
|
|
829
2058
|
"internalType": "bytes"
|
|
830
2059
|
}
|
|
@@ -843,13 +2072,13 @@ var REGISTRY_ABI = [
|
|
|
843
2072
|
},
|
|
844
2073
|
{
|
|
845
2074
|
"name": "kind",
|
|
846
|
-
"type": "
|
|
847
|
-
"internalType": "
|
|
2075
|
+
"type": "string",
|
|
2076
|
+
"internalType": "string"
|
|
848
2077
|
},
|
|
849
2078
|
{
|
|
850
2079
|
"name": "value",
|
|
851
|
-
"type": "
|
|
852
|
-
"internalType": "
|
|
2080
|
+
"type": "string",
|
|
2081
|
+
"internalType": "string"
|
|
853
2082
|
}
|
|
854
2083
|
],
|
|
855
2084
|
"outputs": [],
|
|
@@ -871,13 +2100,13 @@ var REGISTRY_ABI = [
|
|
|
871
2100
|
},
|
|
872
2101
|
{
|
|
873
2102
|
"name": "kind",
|
|
874
|
-
"type": "
|
|
875
|
-
"internalType": "
|
|
2103
|
+
"type": "string",
|
|
2104
|
+
"internalType": "string"
|
|
876
2105
|
},
|
|
877
2106
|
{
|
|
878
2107
|
"name": "value",
|
|
879
|
-
"type": "
|
|
880
|
-
"internalType": "
|
|
2108
|
+
"type": "string",
|
|
2109
|
+
"internalType": "string"
|
|
881
2110
|
},
|
|
882
2111
|
{
|
|
883
2112
|
"name": "deadline",
|
|
@@ -885,7 +2114,7 @@ var REGISTRY_ABI = [
|
|
|
885
2114
|
"internalType": "uint256"
|
|
886
2115
|
},
|
|
887
2116
|
{
|
|
888
|
-
"name": "
|
|
2117
|
+
"name": "permission",
|
|
889
2118
|
"type": "bytes",
|
|
890
2119
|
"internalType": "bytes"
|
|
891
2120
|
}
|
|
@@ -893,6 +2122,83 @@ var REGISTRY_ABI = [
|
|
|
893
2122
|
"outputs": [],
|
|
894
2123
|
"stateMutability": "nonpayable"
|
|
895
2124
|
},
|
|
2125
|
+
{
|
|
2126
|
+
"type": "function",
|
|
2127
|
+
"name": "signatureBytes",
|
|
2128
|
+
"inputs": [
|
|
2129
|
+
{
|
|
2130
|
+
"name": "owner",
|
|
2131
|
+
"type": "address",
|
|
2132
|
+
"internalType": "address"
|
|
2133
|
+
},
|
|
2134
|
+
{
|
|
2135
|
+
"name": "index",
|
|
2136
|
+
"type": "uint256",
|
|
2137
|
+
"internalType": "uint256"
|
|
2138
|
+
}
|
|
2139
|
+
],
|
|
2140
|
+
"outputs": [
|
|
2141
|
+
{
|
|
2142
|
+
"name": "signature",
|
|
2143
|
+
"type": "bytes",
|
|
2144
|
+
"internalType": "bytes"
|
|
2145
|
+
}
|
|
2146
|
+
],
|
|
2147
|
+
"stateMutability": "view"
|
|
2148
|
+
},
|
|
2149
|
+
{
|
|
2150
|
+
"type": "function",
|
|
2151
|
+
"name": "statementFor",
|
|
2152
|
+
"inputs": [
|
|
2153
|
+
{
|
|
2154
|
+
"name": "owner",
|
|
2155
|
+
"type": "address",
|
|
2156
|
+
"internalType": "address"
|
|
2157
|
+
}
|
|
2158
|
+
],
|
|
2159
|
+
"outputs": [
|
|
2160
|
+
{
|
|
2161
|
+
"name": "",
|
|
2162
|
+
"type": "string",
|
|
2163
|
+
"internalType": "string"
|
|
2164
|
+
}
|
|
2165
|
+
],
|
|
2166
|
+
"stateMutability": "pure"
|
|
2167
|
+
},
|
|
2168
|
+
{
|
|
2169
|
+
"type": "function",
|
|
2170
|
+
"name": "summary",
|
|
2171
|
+
"inputs": [
|
|
2172
|
+
{
|
|
2173
|
+
"name": "owner",
|
|
2174
|
+
"type": "address",
|
|
2175
|
+
"internalType": "address"
|
|
2176
|
+
}
|
|
2177
|
+
],
|
|
2178
|
+
"outputs": [
|
|
2179
|
+
{
|
|
2180
|
+
"name": "total",
|
|
2181
|
+
"type": "uint256",
|
|
2182
|
+
"internalType": "uint256"
|
|
2183
|
+
},
|
|
2184
|
+
{
|
|
2185
|
+
"name": "active",
|
|
2186
|
+
"type": "uint256",
|
|
2187
|
+
"internalType": "uint256"
|
|
2188
|
+
},
|
|
2189
|
+
{
|
|
2190
|
+
"name": "hasCurrent",
|
|
2191
|
+
"type": "bool",
|
|
2192
|
+
"internalType": "bool"
|
|
2193
|
+
},
|
|
2194
|
+
{
|
|
2195
|
+
"name": "currentIndex",
|
|
2196
|
+
"type": "uint256",
|
|
2197
|
+
"internalType": "uint256"
|
|
2198
|
+
}
|
|
2199
|
+
],
|
|
2200
|
+
"stateMutability": "view"
|
|
2201
|
+
},
|
|
896
2202
|
{
|
|
897
2203
|
"type": "function",
|
|
898
2204
|
"name": "updateKey",
|
|
@@ -903,7 +2209,7 @@ var REGISTRY_ABI = [
|
|
|
903
2209
|
"internalType": "uint256"
|
|
904
2210
|
},
|
|
905
2211
|
{
|
|
906
|
-
"name": "
|
|
2212
|
+
"name": "key",
|
|
907
2213
|
"type": "bytes",
|
|
908
2214
|
"internalType": "bytes"
|
|
909
2215
|
}
|
|
@@ -926,7 +2232,7 @@ var REGISTRY_ABI = [
|
|
|
926
2232
|
"internalType": "uint256"
|
|
927
2233
|
},
|
|
928
2234
|
{
|
|
929
|
-
"name": "
|
|
2235
|
+
"name": "key",
|
|
930
2236
|
"type": "bytes",
|
|
931
2237
|
"internalType": "bytes"
|
|
932
2238
|
},
|
|
@@ -936,7 +2242,7 @@ var REGISTRY_ABI = [
|
|
|
936
2242
|
"internalType": "uint256"
|
|
937
2243
|
},
|
|
938
2244
|
{
|
|
939
|
-
"name": "
|
|
2245
|
+
"name": "permission",
|
|
940
2246
|
"type": "bytes",
|
|
941
2247
|
"internalType": "bytes"
|
|
942
2248
|
}
|
|
@@ -973,22 +2279,16 @@ var REGISTRY_ABI = [
|
|
|
973
2279
|
"internalType": "bytes"
|
|
974
2280
|
},
|
|
975
2281
|
{
|
|
976
|
-
"name": "
|
|
977
|
-
"type": "uint8",
|
|
978
|
-
"indexed": false,
|
|
979
|
-
"internalType": "uint8"
|
|
980
|
-
},
|
|
981
|
-
{
|
|
982
|
-
"name": "keyPtr",
|
|
2282
|
+
"name": "payload",
|
|
983
2283
|
"type": "address",
|
|
984
2284
|
"indexed": false,
|
|
985
2285
|
"internalType": "address"
|
|
986
2286
|
},
|
|
987
2287
|
{
|
|
988
|
-
"name": "
|
|
989
|
-
"type": "
|
|
2288
|
+
"name": "messageVersion",
|
|
2289
|
+
"type": "uint8",
|
|
990
2290
|
"indexed": false,
|
|
991
|
-
"internalType": "
|
|
2291
|
+
"internalType": "uint8"
|
|
992
2292
|
},
|
|
993
2293
|
{
|
|
994
2294
|
"name": "submitter",
|
|
@@ -1022,13 +2322,13 @@ var REGISTRY_ABI = [
|
|
|
1022
2322
|
"internalType": "uint256"
|
|
1023
2323
|
},
|
|
1024
2324
|
{
|
|
1025
|
-
"name": "
|
|
2325
|
+
"name": "oldPayload",
|
|
1026
2326
|
"type": "address",
|
|
1027
2327
|
"indexed": false,
|
|
1028
2328
|
"internalType": "address"
|
|
1029
2329
|
},
|
|
1030
2330
|
{
|
|
1031
|
-
"name": "
|
|
2331
|
+
"name": "newPayload",
|
|
1032
2332
|
"type": "address",
|
|
1033
2333
|
"indexed": false,
|
|
1034
2334
|
"internalType": "address"
|
|
@@ -1078,11 +2378,23 @@ var REGISTRY_ABI = [
|
|
|
1078
2378
|
"internalType": "uint256"
|
|
1079
2379
|
},
|
|
1080
2380
|
{
|
|
1081
|
-
"name": "
|
|
2381
|
+
"name": "kindHash",
|
|
1082
2382
|
"type": "bytes32",
|
|
1083
2383
|
"indexed": true,
|
|
1084
2384
|
"internalType": "bytes32"
|
|
1085
2385
|
},
|
|
2386
|
+
{
|
|
2387
|
+
"name": "kind",
|
|
2388
|
+
"type": "string",
|
|
2389
|
+
"indexed": false,
|
|
2390
|
+
"internalType": "string"
|
|
2391
|
+
},
|
|
2392
|
+
{
|
|
2393
|
+
"name": "value",
|
|
2394
|
+
"type": "string",
|
|
2395
|
+
"indexed": false,
|
|
2396
|
+
"internalType": "string"
|
|
2397
|
+
},
|
|
1086
2398
|
{
|
|
1087
2399
|
"name": "submitter",
|
|
1088
2400
|
"type": "address",
|
|
@@ -1094,7 +2406,7 @@ var REGISTRY_ABI = [
|
|
|
1094
2406
|
},
|
|
1095
2407
|
{
|
|
1096
2408
|
"type": "event",
|
|
1097
|
-
"name": "
|
|
2409
|
+
"name": "RecordsMoved",
|
|
1098
2410
|
"inputs": [
|
|
1099
2411
|
{
|
|
1100
2412
|
"name": "owner",
|
|
@@ -1103,924 +2415,697 @@ var REGISTRY_ABI = [
|
|
|
1103
2415
|
"internalType": "address"
|
|
1104
2416
|
},
|
|
1105
2417
|
{
|
|
1106
|
-
"name": "
|
|
1107
|
-
"type": "
|
|
2418
|
+
"name": "fromIndex",
|
|
2419
|
+
"type": "uint256",
|
|
1108
2420
|
"indexed": true,
|
|
1109
|
-
"internalType": "
|
|
2421
|
+
"internalType": "uint256"
|
|
1110
2422
|
},
|
|
1111
2423
|
{
|
|
1112
|
-
"name": "
|
|
2424
|
+
"name": "toIndex",
|
|
1113
2425
|
"type": "uint256",
|
|
1114
2426
|
"indexed": true,
|
|
1115
2427
|
"internalType": "uint256"
|
|
1116
|
-
},
|
|
1117
|
-
{
|
|
1118
|
-
"name": "submitter",
|
|
1119
|
-
"type": "address",
|
|
1120
|
-
"indexed": false,
|
|
1121
|
-
"internalType": "address"
|
|
1122
2428
|
}
|
|
1123
2429
|
],
|
|
1124
2430
|
"anonymous": false
|
|
1125
2431
|
},
|
|
1126
2432
|
{
|
|
1127
|
-
"type": "
|
|
1128
|
-
"name": "
|
|
1129
|
-
"inputs": [
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
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
|
-
}
|
|
2433
|
+
"type": "event",
|
|
2434
|
+
"name": "Revoked",
|
|
2435
|
+
"inputs": [
|
|
2436
|
+
{
|
|
2437
|
+
"name": "owner",
|
|
2438
|
+
"type": "address",
|
|
2439
|
+
"indexed": true,
|
|
2440
|
+
"internalType": "address"
|
|
2441
|
+
},
|
|
2442
|
+
{
|
|
2443
|
+
"name": "fingerprintHash",
|
|
2444
|
+
"type": "bytes32",
|
|
2445
|
+
"indexed": true,
|
|
2446
|
+
"internalType": "bytes32"
|
|
2447
|
+
},
|
|
2448
|
+
{
|
|
2449
|
+
"name": "index",
|
|
2450
|
+
"type": "uint256",
|
|
2451
|
+
"indexed": true,
|
|
2452
|
+
"internalType": "uint256"
|
|
2453
|
+
},
|
|
2454
|
+
{
|
|
2455
|
+
"name": "reason",
|
|
2456
|
+
"type": "string",
|
|
2457
|
+
"indexed": false,
|
|
2458
|
+
"internalType": "string"
|
|
2459
|
+
},
|
|
2460
|
+
{
|
|
2461
|
+
"name": "replacedBy",
|
|
2462
|
+
"type": "uint256",
|
|
2463
|
+
"indexed": false,
|
|
2464
|
+
"internalType": "uint256"
|
|
2465
|
+
},
|
|
2466
|
+
{
|
|
2467
|
+
"name": "submitter",
|
|
2468
|
+
"type": "address",
|
|
2469
|
+
"indexed": false,
|
|
2470
|
+
"internalType": "address"
|
|
1357
2471
|
}
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
2472
|
+
],
|
|
2473
|
+
"anonymous": false
|
|
2474
|
+
},
|
|
2475
|
+
{
|
|
2476
|
+
"type": "error",
|
|
2477
|
+
"name": "AlreadyRevoked",
|
|
2478
|
+
"inputs": [
|
|
2479
|
+
{
|
|
2480
|
+
"name": "index",
|
|
2481
|
+
"type": "uint256",
|
|
2482
|
+
"internalType": "uint256"
|
|
1361
2483
|
}
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
for (const sig of msg.signature.packets) {
|
|
1383
|
-
if (!publicKey.getKeys(sig.issuerKeyID).length) continue;
|
|
1384
|
-
const signingKey = await publicKey.getSigningKey(sig.issuerKeyID, now, void 0, config);
|
|
1385
|
-
const literal = new LiteralDataPacket();
|
|
1386
|
-
literal.setText(_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 };
|
|
2484
|
+
]
|
|
2485
|
+
},
|
|
2486
|
+
{
|
|
2487
|
+
"type": "error",
|
|
2488
|
+
"name": "BadArmorChecksum",
|
|
2489
|
+
"inputs": []
|
|
2490
|
+
},
|
|
2491
|
+
{
|
|
2492
|
+
"type": "error",
|
|
2493
|
+
"name": "BadBase64",
|
|
2494
|
+
"inputs": []
|
|
2495
|
+
},
|
|
2496
|
+
{
|
|
2497
|
+
"type": "error",
|
|
2498
|
+
"name": "ClaimActive",
|
|
2499
|
+
"inputs": [
|
|
2500
|
+
{
|
|
2501
|
+
"name": "index",
|
|
2502
|
+
"type": "uint256",
|
|
2503
|
+
"internalType": "uint256"
|
|
1473
2504
|
}
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
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;
|
|
2505
|
+
]
|
|
2506
|
+
},
|
|
2507
|
+
{
|
|
2508
|
+
"type": "error",
|
|
2509
|
+
"name": "DeploymentFailed",
|
|
2510
|
+
"inputs": []
|
|
2511
|
+
},
|
|
2512
|
+
{
|
|
2513
|
+
"type": "error",
|
|
2514
|
+
"name": "DuplicateActiveFingerprint",
|
|
2515
|
+
"inputs": [
|
|
2516
|
+
{
|
|
2517
|
+
"name": "fingerprint",
|
|
2518
|
+
"type": "bytes",
|
|
2519
|
+
"internalType": "bytes"
|
|
1498
2520
|
}
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
}
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
2521
|
+
]
|
|
2522
|
+
},
|
|
2523
|
+
{
|
|
2524
|
+
"type": "error",
|
|
2525
|
+
"name": "EmptyKey",
|
|
2526
|
+
"inputs": []
|
|
2527
|
+
},
|
|
2528
|
+
{
|
|
2529
|
+
"type": "error",
|
|
2530
|
+
"name": "EmptySignature",
|
|
2531
|
+
"inputs": []
|
|
2532
|
+
},
|
|
2533
|
+
{
|
|
2534
|
+
"type": "error",
|
|
2535
|
+
"name": "IndexOutOfBounds",
|
|
2536
|
+
"inputs": [
|
|
2537
|
+
{
|
|
2538
|
+
"name": "index",
|
|
2539
|
+
"type": "uint256",
|
|
2540
|
+
"internalType": "uint256"
|
|
2541
|
+
},
|
|
2542
|
+
{
|
|
2543
|
+
"name": "count",
|
|
2544
|
+
"type": "uint256",
|
|
2545
|
+
"internalType": "uint256"
|
|
2546
|
+
}
|
|
2547
|
+
]
|
|
2548
|
+
},
|
|
2549
|
+
{
|
|
2550
|
+
"type": "error",
|
|
2551
|
+
"name": "InvalidFingerprint",
|
|
2552
|
+
"inputs": [
|
|
2553
|
+
{
|
|
2554
|
+
"name": "fingerprint",
|
|
2555
|
+
"type": "bytes",
|
|
2556
|
+
"internalType": "bytes"
|
|
2557
|
+
}
|
|
2558
|
+
]
|
|
2559
|
+
},
|
|
2560
|
+
{
|
|
2561
|
+
"type": "error",
|
|
2562
|
+
"name": "InvalidFingerprintLength",
|
|
2563
|
+
"inputs": [
|
|
2564
|
+
{
|
|
2565
|
+
"name": "length",
|
|
2566
|
+
"type": "uint256",
|
|
2567
|
+
"internalType": "uint256"
|
|
2568
|
+
}
|
|
2569
|
+
]
|
|
2570
|
+
},
|
|
2571
|
+
{
|
|
2572
|
+
"type": "error",
|
|
2573
|
+
"name": "InvalidKindName",
|
|
2574
|
+
"inputs": [
|
|
2575
|
+
{
|
|
2576
|
+
"name": "kind",
|
|
2577
|
+
"type": "string",
|
|
2578
|
+
"internalType": "string"
|
|
2579
|
+
}
|
|
2580
|
+
]
|
|
2581
|
+
},
|
|
2582
|
+
{
|
|
2583
|
+
"type": "error",
|
|
2584
|
+
"name": "InvalidPermission",
|
|
2585
|
+
"inputs": []
|
|
2586
|
+
},
|
|
2587
|
+
{
|
|
2588
|
+
"type": "error",
|
|
2589
|
+
"name": "InvalidPointer",
|
|
2590
|
+
"inputs": []
|
|
2591
|
+
},
|
|
2592
|
+
{
|
|
2593
|
+
"type": "error",
|
|
2594
|
+
"name": "KeyCompromised",
|
|
2595
|
+
"inputs": [
|
|
2596
|
+
{
|
|
2597
|
+
"name": "fingerprint",
|
|
2598
|
+
"type": "bytes",
|
|
2599
|
+
"internalType": "bytes"
|
|
2600
|
+
}
|
|
2601
|
+
]
|
|
2602
|
+
},
|
|
1552
2603
|
{
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
2604
|
+
"type": "error",
|
|
2605
|
+
"name": "KeyStillActive",
|
|
2606
|
+
"inputs": [
|
|
2607
|
+
{
|
|
2608
|
+
"name": "fingerprint",
|
|
2609
|
+
"type": "bytes",
|
|
2610
|
+
"internalType": "bytes"
|
|
2611
|
+
}
|
|
2612
|
+
]
|
|
1557
2613
|
},
|
|
1558
2614
|
{
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
2615
|
+
"type": "error",
|
|
2616
|
+
"name": "KeyTooLarge",
|
|
2617
|
+
"inputs": [
|
|
2618
|
+
{
|
|
2619
|
+
"name": "size",
|
|
2620
|
+
"type": "uint256",
|
|
2621
|
+
"internalType": "uint256"
|
|
2622
|
+
},
|
|
2623
|
+
{
|
|
2624
|
+
"name": "max",
|
|
2625
|
+
"type": "uint256",
|
|
2626
|
+
"internalType": "uint256"
|
|
2627
|
+
}
|
|
2628
|
+
]
|
|
1565
2629
|
},
|
|
1566
2630
|
{
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
2631
|
+
"type": "error",
|
|
2632
|
+
"name": "NotAKey",
|
|
2633
|
+
"inputs": [
|
|
2634
|
+
{
|
|
2635
|
+
"name": "firstByte",
|
|
2636
|
+
"type": "bytes1",
|
|
2637
|
+
"internalType": "bytes1"
|
|
2638
|
+
}
|
|
2639
|
+
]
|
|
1573
2640
|
},
|
|
1574
2641
|
{
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
2642
|
+
"type": "error",
|
|
2643
|
+
"name": "NotASignature",
|
|
2644
|
+
"inputs": [
|
|
2645
|
+
{
|
|
2646
|
+
"name": "firstByte",
|
|
2647
|
+
"type": "bytes1",
|
|
2648
|
+
"internalType": "bytes1"
|
|
2649
|
+
}
|
|
2650
|
+
]
|
|
1579
2651
|
},
|
|
1580
2652
|
{
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
parse: (m) => ({ user: m[1], repo: m[2] })
|
|
2653
|
+
"type": "error",
|
|
2654
|
+
"name": "NotArmored",
|
|
2655
|
+
"inputs": []
|
|
1585
2656
|
},
|
|
1586
2657
|
{
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
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 };
|
|
2658
|
+
"type": "error",
|
|
2659
|
+
"name": "PayloadTooLarge",
|
|
2660
|
+
"inputs": [
|
|
2661
|
+
{
|
|
2662
|
+
"name": "size",
|
|
2663
|
+
"type": "uint256",
|
|
2664
|
+
"internalType": "uint256"
|
|
2665
|
+
},
|
|
2666
|
+
{
|
|
2667
|
+
"name": "max",
|
|
2668
|
+
"type": "uint256",
|
|
2669
|
+
"internalType": "uint256"
|
|
1648
2670
|
}
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
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 };
|
|
2671
|
+
]
|
|
2672
|
+
},
|
|
2673
|
+
{
|
|
2674
|
+
"type": "error",
|
|
2675
|
+
"name": "PermissionExpired",
|
|
2676
|
+
"inputs": [
|
|
2677
|
+
{
|
|
2678
|
+
"name": "deadline",
|
|
2679
|
+
"type": "uint256",
|
|
2680
|
+
"internalType": "uint256"
|
|
1685
2681
|
}
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
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
|
-
}
|
|
2682
|
+
]
|
|
2683
|
+
},
|
|
2684
|
+
{
|
|
2685
|
+
"type": "error",
|
|
2686
|
+
"name": "RecordTooLarge",
|
|
2687
|
+
"inputs": [
|
|
2688
|
+
{
|
|
2689
|
+
"name": "size",
|
|
2690
|
+
"type": "uint256",
|
|
2691
|
+
"internalType": "uint256"
|
|
2692
|
+
},
|
|
2693
|
+
{
|
|
2694
|
+
"name": "max",
|
|
2695
|
+
"type": "uint256",
|
|
2696
|
+
"internalType": "uint256"
|
|
1721
2697
|
}
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
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 };
|
|
2698
|
+
]
|
|
2699
|
+
},
|
|
2700
|
+
{
|
|
2701
|
+
"type": "error",
|
|
2702
|
+
"name": "SignatureTooLarge",
|
|
2703
|
+
"inputs": [
|
|
2704
|
+
{
|
|
2705
|
+
"name": "size",
|
|
2706
|
+
"type": "uint256",
|
|
2707
|
+
"internalType": "uint256"
|
|
2708
|
+
},
|
|
2709
|
+
{
|
|
2710
|
+
"name": "max",
|
|
2711
|
+
"type": "uint256",
|
|
2712
|
+
"internalType": "uint256"
|
|
1760
2713
|
}
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
2714
|
+
]
|
|
2715
|
+
},
|
|
2716
|
+
{
|
|
2717
|
+
"type": "error",
|
|
2718
|
+
"name": "SupersededIsSetByReattest",
|
|
2719
|
+
"inputs": []
|
|
2720
|
+
},
|
|
2721
|
+
{
|
|
2722
|
+
"type": "error",
|
|
2723
|
+
"name": "TooManyClaims",
|
|
2724
|
+
"inputs": []
|
|
2725
|
+
},
|
|
2726
|
+
{
|
|
2727
|
+
"type": "error",
|
|
2728
|
+
"name": "UnknownRevokeReason",
|
|
2729
|
+
"inputs": [
|
|
2730
|
+
{
|
|
2731
|
+
"name": "reason",
|
|
2732
|
+
"type": "string",
|
|
2733
|
+
"internalType": "string"
|
|
1766
2734
|
}
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
2735
|
+
]
|
|
2736
|
+
},
|
|
2737
|
+
{
|
|
2738
|
+
"type": "error",
|
|
2739
|
+
"name": "UnsupportedHeader",
|
|
2740
|
+
"inputs": []
|
|
1771
2741
|
}
|
|
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
|
-
}
|
|
2742
|
+
];
|
|
1785
2743
|
|
|
1786
|
-
// src/core/
|
|
1787
|
-
var
|
|
1788
|
-
var
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
2744
|
+
// src/core/contract.ts
|
|
2745
|
+
var REGISTRY_ADDRESS = "0xFa6956c11163517249f8A67F5560a4406B519451";
|
|
2746
|
+
var NETWORKS = {
|
|
2747
|
+
mainnet: {
|
|
2748
|
+
chainId: 1,
|
|
2749
|
+
address: REGISTRY_ADDRESS,
|
|
2750
|
+
explorerUrl: "https://etherscan.io",
|
|
2751
|
+
defaultRpcUrl: "https://ethereum.publicnode.com"
|
|
2752
|
+
// resolves on more networks than ethereum-rpc.publicnode.com
|
|
2753
|
+
},
|
|
2754
|
+
sepolia: {
|
|
2755
|
+
chainId: 11155111,
|
|
2756
|
+
address: REGISTRY_ADDRESS,
|
|
2757
|
+
explorerUrl: "https://sepolia.etherscan.io",
|
|
2758
|
+
defaultRpcUrl: "https://ethereum-sepolia.publicnode.com"
|
|
2759
|
+
},
|
|
2760
|
+
/** A local anvil instance (`anvil`, chain id 31337). Deploy with pgp-registry's Deploy script. */
|
|
2761
|
+
local: {
|
|
2762
|
+
chainId: 31337,
|
|
2763
|
+
address: REGISTRY_ADDRESS,
|
|
2764
|
+
explorerUrl: "",
|
|
2765
|
+
defaultRpcUrl: "http://127.0.0.1:8545"
|
|
2766
|
+
}
|
|
2767
|
+
};
|
|
2768
|
+
function isNetworkName(value) {
|
|
2769
|
+
return value === "mainnet" || value === "sepolia" || value === "local";
|
|
1802
2770
|
}
|
|
1803
|
-
function
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
2771
|
+
function getRegistry(network = "mainnet", addressOverride) {
|
|
2772
|
+
const r = NETWORKS[network];
|
|
2773
|
+
if (!r) throw new Error(`Unknown network: ${network}`);
|
|
2774
|
+
if (addressOverride && /^0x[0-9a-fA-F]{40}$/.test(addressOverride)) {
|
|
2775
|
+
return { ...r, address: addressOverride };
|
|
2776
|
+
}
|
|
2777
|
+
return r;
|
|
1807
2778
|
}
|
|
1808
|
-
function
|
|
1809
|
-
|
|
1810
|
-
|
|
2779
|
+
function chainFor(network = "mainnet") {
|
|
2780
|
+
if (network === "sepolia") return _chains.sepolia;
|
|
2781
|
+
if (network === "local") return _chains.foundry;
|
|
2782
|
+
return _chains.mainnet;
|
|
1811
2783
|
}
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
const
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
2784
|
+
|
|
2785
|
+
// src/core/claims.ts
|
|
2786
|
+
var CLAIM_LIMIT = 50;
|
|
2787
|
+
async function readClaims(client, owner, { registry = REGISTRY_ADDRESS, limit = CLAIM_LIMIT } = {}) {
|
|
2788
|
+
const read = (functionName, args) => client.readContract({ address: registry, abi: REGISTRY_ABI, functionName, args });
|
|
2789
|
+
const rows = await read("claimsOf", [owner]);
|
|
2790
|
+
const first = Math.max(0, rows.length - limit);
|
|
2791
|
+
return Promise.all(rows.map(async (row, index) => {
|
|
2792
|
+
const revokedAt = Number(row.revokedAt);
|
|
2793
|
+
const claim = {
|
|
2794
|
+
index,
|
|
2795
|
+
fingerprint: bytesToFingerprint(row.fingerprint),
|
|
2796
|
+
createdAt: Number(row.createdAt),
|
|
2797
|
+
revoked: revokedAt !== 0,
|
|
2798
|
+
revokedAt: revokedAt || null,
|
|
2799
|
+
state: row.state,
|
|
2800
|
+
replacedBy: row.state === "replaced" ? Number(row.replacedBy) : null,
|
|
2801
|
+
revokeReason: row.revokeReason,
|
|
2802
|
+
messageVersion: Number(row.messageVersion),
|
|
2803
|
+
pgpPublicKey: null,
|
|
2804
|
+
pgpSignature: null,
|
|
2805
|
+
verification: null
|
|
2806
|
+
};
|
|
2807
|
+
if (index < first) return claim;
|
|
2808
|
+
const bytes = (fn) => read(fn, [owner, BigInt(index)]).catch(() => null);
|
|
2809
|
+
const [keyHex, sigHex] = await Promise.all([bytes("keyBytes"), bytes("signatureBytes")]);
|
|
2810
|
+
claim.pgpPublicKey = keyHex ? await payloadText(keyHex, "key") : null;
|
|
2811
|
+
claim.pgpSignature = sigHex ? await payloadText(sigHex, "signature") : null;
|
|
2812
|
+
claim.verification = await verifyAttestation({
|
|
2813
|
+
pgpPublicKey: claim.pgpPublicKey,
|
|
2814
|
+
pgpSignature: claim.pgpSignature,
|
|
2815
|
+
fingerprint: claim.fingerprint,
|
|
2816
|
+
ethAddress: owner
|
|
2817
|
+
});
|
|
2818
|
+
return claim;
|
|
2819
|
+
}));
|
|
2820
|
+
}
|
|
2821
|
+
function keyStanding(claims) {
|
|
2822
|
+
const active = claims.filter((c) => !c.revoked);
|
|
2823
|
+
const verified = active.filter((c) => _optionalChain([c, 'access', _78 => _78.verification, 'optionalAccess', _79 => _79.verified]));
|
|
2824
|
+
if (verified.length) return { kind: "verified", claim: verified[verified.length - 1] };
|
|
2825
|
+
if (active.length) return { kind: "not-counted", claim: active[active.length - 1] };
|
|
2826
|
+
if (claims.length) return { kind: "inactive", claim: claims[claims.length - 1] };
|
|
2827
|
+
return { kind: "none", claim: null };
|
|
2828
|
+
}
|
|
2829
|
+
async function findOwners(client, key, { registry = REGISTRY_ADDRESS } = {}) {
|
|
2830
|
+
const read = (functionName, args) => client.readContract({ address: registry, abi: REGISTRY_ABI, functionName, args });
|
|
2831
|
+
let fingerprints;
|
|
2832
|
+
if ("keyId" in key) {
|
|
2833
|
+
const keyId = keyIdToBytes(key.keyId);
|
|
2834
|
+
if (!keyId) return [];
|
|
2835
|
+
fingerprints = (await read("fingerprintsForKeyId", [keyId])).map(bytesToFingerprint);
|
|
2836
|
+
} else {
|
|
2837
|
+
const fp = normalizeFingerprint(key.fingerprint);
|
|
2838
|
+
if (!fp) return [];
|
|
2839
|
+
fingerprints = [fp];
|
|
2840
|
+
}
|
|
2841
|
+
const found = [];
|
|
2842
|
+
for (const fingerprint of fingerprints) {
|
|
2843
|
+
for (const owner of await read("ownersOf", [fingerprintToBytes(fingerprint)])) {
|
|
2844
|
+
if (!found.some((f) => f.owner.toLowerCase() === owner.toLowerCase() && f.fingerprint === fingerprint)) found.push({ owner, fingerprint });
|
|
1833
2845
|
}
|
|
1834
|
-
if (!meta) return null;
|
|
1835
2846
|
}
|
|
1836
|
-
return
|
|
2847
|
+
return found;
|
|
1837
2848
|
}
|
|
1838
2849
|
|
|
1839
|
-
// src/core/
|
|
1840
|
-
var
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
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
|
-
};
|
|
2850
|
+
// src/core/claimStatus.ts
|
|
2851
|
+
var CLAIM_CHECK_LABEL = {
|
|
2852
|
+
verified: "pgp verified",
|
|
2853
|
+
expired: "key expired",
|
|
2854
|
+
"signing-key-expired": "signing key expired",
|
|
2855
|
+
revoked: "key revoked",
|
|
2856
|
+
compromised: "key compromised",
|
|
2857
|
+
"signing-key-revoked": "signing key revoked",
|
|
2858
|
+
unsupported: "not supported",
|
|
2859
|
+
"bad-signature": "doesn't verify"
|
|
2860
|
+
};
|
|
2861
|
+
function formatClaimDate(isoOrSeconds) {
|
|
2862
|
+
if (isoOrSeconds === null || isoOrSeconds === void 0) return "an unknown date";
|
|
2863
|
+
const d = typeof isoOrSeconds === "number" ? new Date(isoOrSeconds * 1e3) : new Date(isoOrSeconds);
|
|
2864
|
+
if (Number.isNaN(d.getTime())) return "an unknown date";
|
|
2865
|
+
return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", timeZone: "UTC" });
|
|
1869
2866
|
}
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
2867
|
+
function shortFingerprint(fpr) {
|
|
2868
|
+
if (!fpr) return "unknown";
|
|
2869
|
+
const f = fpr.toUpperCase();
|
|
2870
|
+
return `${f.slice(0, 4)} ${f.slice(4, 8)} \u2026`;
|
|
1873
2871
|
}
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
2872
|
+
function claimCheckText(v, formatDate = formatClaimDate) {
|
|
2873
|
+
const kind = _nullishCoalesce(v.kind, () => ( (v.verified ? "verified" : "bad-signature")));
|
|
2874
|
+
const at = formatDate(v.at);
|
|
2875
|
+
const t = (sentence, fix = null) => ({ kind, label: CLAIM_CHECK_LABEL[kind], sentence, fix });
|
|
2876
|
+
switch (kind) {
|
|
2877
|
+
case "verified":
|
|
2878
|
+
return t("The key signed a line naming this address, and the signature checks out.");
|
|
2879
|
+
case "expired":
|
|
2880
|
+
return t(
|
|
2881
|
+
`The key on this claim expired on ${at}, so the claim no longer counts.`,
|
|
2882
|
+
"Extend the key, then Update key. No new signature needed."
|
|
2883
|
+
);
|
|
2884
|
+
case "signing-key-expired":
|
|
2885
|
+
return t(
|
|
2886
|
+
`The subkey that signed this claim (${shortFingerprint(v.signingKey)}) expired on ${at}.`,
|
|
2887
|
+
"Extend that subkey, then Update key."
|
|
2888
|
+
);
|
|
2889
|
+
case "revoked":
|
|
2890
|
+
return t(
|
|
2891
|
+
`Its owner revoked this PGP key on ${at}${v.revocationReason ? ` (reason: ${v.revocationReason})` : ""}. The claim no longer counts.`,
|
|
2892
|
+
"Revoke this claim and attest your new key."
|
|
2893
|
+
);
|
|
2894
|
+
case "compromised":
|
|
2895
|
+
return t(
|
|
2896
|
+
`Its owner revoked this PGP key on ${at} as compromised. Don't trust anything it signed after that date.`,
|
|
2897
|
+
"Revoke this claim and attest a new key."
|
|
2898
|
+
);
|
|
2899
|
+
case "signing-key-revoked":
|
|
2900
|
+
return t(
|
|
2901
|
+
`The subkey that signed this claim was revoked on ${at}.`,
|
|
2902
|
+
"Replace the claim with a signature from a current key."
|
|
2903
|
+
);
|
|
2904
|
+
case "unsupported":
|
|
2905
|
+
return t(`This key uses an algorithm Thurin doesn't check${v.algorithm ? ` (${v.algorithm})` : ""}. The claim is on-chain, but no lookup will vouch for it.`);
|
|
2906
|
+
case "bad-signature":
|
|
2907
|
+
default:
|
|
2908
|
+
return t("The signature stored with this claim doesn't match its key, so nothing from this claim is shown.");
|
|
2909
|
+
}
|
|
1881
2910
|
}
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
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
|
-
};
|
|
2911
|
+
function keyProblemText(v, formatDate = formatClaimDate) {
|
|
2912
|
+
const at = formatDate(v.at);
|
|
2913
|
+
const t = (kind, sentence, fix) => ({ kind, label: CLAIM_CHECK_LABEL[kind], sentence, fix });
|
|
2914
|
+
switch (v.kind) {
|
|
2915
|
+
case "expired":
|
|
2916
|
+
return t("expired", `This key expired on ${at}, so a claim with it wouldn't count.`, "Extend it (gpg --quick-set-expire), then export it again.");
|
|
2917
|
+
case "signing-key-expired":
|
|
2918
|
+
return t("signing-key-expired", `The subkey that signed (${shortFingerprint(v.signingKey)}) expired on ${at}.`, "Extend that subkey, or sign with a current one.");
|
|
2919
|
+
case "revoked":
|
|
2920
|
+
return t("revoked", `This key was revoked on ${at}${v.revocationReason ? ` (reason: ${v.revocationReason})` : ""}.`, "Use a current key.");
|
|
2921
|
+
case "compromised":
|
|
2922
|
+
return t("compromised", `This key was revoked as compromised on ${at}.`, "Use a new key.");
|
|
2923
|
+
case "signing-key-revoked":
|
|
2924
|
+
return t("signing-key-revoked", `The subkey that signed was revoked on ${at}.`, "Sign with a current subkey.");
|
|
2925
|
+
case "unsupported":
|
|
2926
|
+
return t("unsupported", `This key uses an algorithm Thurin doesn't check${v.algorithm ? ` (${v.algorithm})` : ""}, so no lookup would vouch for the claim.`, "Use an Ed25519 or RSA key.");
|
|
2927
|
+
default:
|
|
2928
|
+
return null;
|
|
2929
|
+
}
|
|
1936
2930
|
}
|
|
1937
|
-
function
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
primaryType: "Reattest",
|
|
1943
|
-
message: { ...base.message, revokeIndex: a.revokeIndex }
|
|
1944
|
-
};
|
|
2931
|
+
function expiresSoon(v, now = Date.now(), withinDays = 30) {
|
|
2932
|
+
if (!_optionalChain([v, 'optionalAccess', _80 => _80.verified]) || !v.expiresAt) return null;
|
|
2933
|
+
const ms = new Date(v.expiresAt).getTime() - now;
|
|
2934
|
+
if (!Number.isFinite(ms) || ms < 0 || ms > withinDays * 864e5) return null;
|
|
2935
|
+
return { days: Math.floor(ms / 864e5), at: v.expiresAt };
|
|
1945
2936
|
}
|
|
1946
|
-
function
|
|
1947
|
-
|
|
1948
|
-
|
|
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
|
-
};
|
|
2937
|
+
function expiresSoonText(soon, formatDate = formatClaimDate) {
|
|
2938
|
+
const when = soon.days === 0 ? "today" : soon.days === 1 ? "in 1 day" : `in ${soon.days} days`;
|
|
2939
|
+
return `Key expires ${when} (${formatDate(soon.at)}).`;
|
|
1953
2940
|
}
|
|
1954
|
-
function
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
}
|
|
2941
|
+
function claimFates(claims) {
|
|
2942
|
+
const out = /* @__PURE__ */ new Map();
|
|
2943
|
+
for (const c of claims) {
|
|
2944
|
+
if (c.state === "active" || !c.revokedAt) out.set(c.index, { state: "active" });
|
|
2945
|
+
else if (c.state === "replaced" && c.replacedBy !== null) out.set(c.index, { state: "replaced", at: c.revokedAt, by: c.replacedBy, ...c.revokeReason === "compromised" ? { compromised: true } : {} });
|
|
2946
|
+
else out.set(c.index, { state: "revoked", at: c.revokedAt, ...c.revokeReason ? { reason: c.revokeReason } : {} });
|
|
2947
|
+
}
|
|
2948
|
+
return out;
|
|
1961
2949
|
}
|
|
1962
|
-
function
|
|
1963
|
-
return {
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
primaryType: "SetRecord",
|
|
1967
|
-
message: { owner: a.owner, index: a.index, kind: a.kind, value: a.value, nonce: a.nonce, deadline: a.deadline }
|
|
1968
|
-
};
|
|
2950
|
+
function claimFateText(fate, formatDate = (s) => formatClaimDate(s)) {
|
|
2951
|
+
if (fate.state === "revoked") return `Revoked by its owner on ${formatDate(fate.at)}${fate.reason ? ` (${fate.reason})` : ""}.`;
|
|
2952
|
+
if (fate.state === "replaced") return `Replaced by claim #${fate.by} on ${formatDate(fate.at)}.${fate.compromised ? " Its key was marked compromised." : ""}`;
|
|
2953
|
+
return null;
|
|
1969
2954
|
}
|
|
1970
|
-
|
|
1971
|
-
|
|
2955
|
+
|
|
2956
|
+
// src/core/encrypt.ts
|
|
2957
|
+
async function encryptionKeyFor(claims, { now = Date.now(), recentDays = 7 } = {}) {
|
|
2958
|
+
const standing = keyStanding(claims);
|
|
2959
|
+
if (standing.kind === "none" || standing.kind === "inactive") return { ok: false, reason: "no-claim", claim: standing.claim };
|
|
2960
|
+
if (standing.kind === "not-counted" || !standing.claim.pgpPublicKey) return { ok: false, reason: "unverified", claim: standing.claim };
|
|
2961
|
+
const claim = standing.claim;
|
|
2962
|
+
try {
|
|
2963
|
+
const openpgp = await Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
|
|
2964
|
+
const config = pgpConfig(openpgp);
|
|
2965
|
+
const key = await readKeyAny(openpgp, claim.pgpPublicKey);
|
|
2966
|
+
const date = new Date(now);
|
|
2967
|
+
const enc = await key.getEncryptionKey(void 0, date, void 0, config).catch(() => null);
|
|
2968
|
+
if (!enc) {
|
|
2969
|
+
let lastExpiry = null;
|
|
2970
|
+
for (const sk of key.subkeys) {
|
|
2971
|
+
const flags = _nullishCoalesce(_optionalChain([newestSignature, 'call', _81 => _81(sk.bindingSignatures), 'optionalAccess', _82 => _82.keyFlags, 'optionalAccess', _83 => _83[0]]), () => ( 0));
|
|
2972
|
+
if (!(flags & 12) || await sk.isRevoked(void 0, void 0, date, config).catch(() => false)) continue;
|
|
2973
|
+
const exp2 = await sk.getExpirationTime(date, config).catch(() => null);
|
|
2974
|
+
if (typeof exp2 === "number" || exp2 instanceof Date) {
|
|
2975
|
+
const t = new Date(exp2).getTime();
|
|
2976
|
+
if (t <= now && (lastExpiry === null || t > lastExpiry)) lastExpiry = t;
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
return lastExpiry !== null ? { ok: false, reason: "encryption-subkey-expired", claim, expired: new Date(lastExpiry).toISOString() } : { ok: false, reason: "no-encryption-subkey", claim };
|
|
2980
|
+
}
|
|
2981
|
+
const exp = await enc.getExpirationTime(date, config).catch(() => null);
|
|
2982
|
+
return {
|
|
2983
|
+
ok: true,
|
|
2984
|
+
claim,
|
|
2985
|
+
key: claim.pgpPublicKey,
|
|
2986
|
+
subkey: {
|
|
2987
|
+
fingerprint: enc.getFingerprint().toUpperCase(),
|
|
2988
|
+
algorithm: algorithmName(enc),
|
|
2989
|
+
expires: exp && exp !== Infinity ? new Date(exp).toISOString() : null
|
|
2990
|
+
},
|
|
2991
|
+
addedAt: claim.createdAt,
|
|
2992
|
+
changedRecently: now / 1e3 - claim.createdAt < recentDays * 86400
|
|
2993
|
+
};
|
|
2994
|
+
} catch (e17) {
|
|
2995
|
+
return { ok: false, reason: "unverified", claim };
|
|
2996
|
+
}
|
|
1972
2997
|
}
|
|
1973
|
-
function
|
|
1974
|
-
|
|
2998
|
+
function encryptRefusalText(r, formatDate = formatClaimDate) {
|
|
2999
|
+
switch (r.reason) {
|
|
3000
|
+
case "no-claim":
|
|
3001
|
+
return "No claim counts for this identity, so there is no key to encrypt to.";
|
|
3002
|
+
case "unverified":
|
|
3003
|
+
return "Its newest claim doesn't verify, so its key can't be trusted with a message.";
|
|
3004
|
+
case "no-encryption-subkey":
|
|
3005
|
+
return "Its key has no encryption subkey, so it can sign but not receive.";
|
|
3006
|
+
case "encryption-subkey-expired":
|
|
3007
|
+
return `Its encryption subkey expired on ${formatDate(r.expired)}.`;
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
function keyChangedText(k, now = Date.now()) {
|
|
3011
|
+
if (!k.changedRecently) return null;
|
|
3012
|
+
const days = Math.floor((now / 1e3 - k.addedAt) / 86400);
|
|
3013
|
+
const when = days <= 0 ? "today" : days === 1 ? "yesterday" : `${days} days ago`;
|
|
3014
|
+
return `This key was added ${when}. If you were expecting a different one, check with them another way.`;
|
|
3015
|
+
}
|
|
3016
|
+
async function encryptTo(key, data, { filename, armor = typeof data === "string", hideRecipient = true, date = /* @__PURE__ */ new Date() } = {}) {
|
|
3017
|
+
const openpgp = await Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
|
|
3018
|
+
const config = pgpConfig(openpgp);
|
|
3019
|
+
const encryptionKeys = await readKeyAny(openpgp, key);
|
|
3020
|
+
const message = typeof data === "string" ? await openpgp.createMessage({ text: data, date }) : await openpgp.createMessage({ binary: data, filename, format: "binary", date });
|
|
3021
|
+
const opts = { message, encryptionKeys, config, wildcard: hideRecipient, date };
|
|
3022
|
+
return armor ? await openpgp.encrypt({ ...opts, format: "armored" }) : await openpgp.encrypt({ ...opts, format: "binary" });
|
|
3023
|
+
}
|
|
3024
|
+
|
|
3025
|
+
// src/core/contractErrors.ts
|
|
3026
|
+
var CONTRACT_ERROR_TEXT = {
|
|
3027
|
+
AlreadyRevoked: "That claim has already ended, or is already marked compromised.",
|
|
3028
|
+
BadArmorChecksum: "The armor's checksum doesn't match its data: the paste was changed or cut short.",
|
|
3029
|
+
BadBase64: "The armored data isn't valid base64.",
|
|
3030
|
+
ClaimActive: 'That claim is still active: revoke it with the reason "compromised" instead.',
|
|
3031
|
+
DeploymentFailed: "The key and signature couldn't be stored: together they're over the contract's size limit.",
|
|
3032
|
+
DuplicateActiveFingerprint: "This address already has an active claim for this key: update it or replace it instead.",
|
|
3033
|
+
EmptyKey: "No key was given.",
|
|
3034
|
+
EmptySignature: "No signature was given.",
|
|
3035
|
+
IndexOutOfBounds: "This address has no claim at that index.",
|
|
3036
|
+
InvalidFingerprint: "That 32-byte fingerprint ends in 12 zero bytes, which no real v6 key has.",
|
|
3037
|
+
InvalidFingerprintLength: "The fingerprint isn't 20 bytes (v4 key) or 32 bytes (v6 key).",
|
|
3038
|
+
InvalidKindName: "The record name is empty, longer than 31 bytes, or uses something other than a-z, 0-9, '-', and '.'.",
|
|
3039
|
+
InvalidPermission: "The permission isn't the owner's signature over exactly this change and their current nonce: it was already used, cancelled, or superseded by a newer one.",
|
|
3040
|
+
InvalidPointer: "There is no stored data at that address.",
|
|
3041
|
+
KeyCompromised: "This address marked the key compromised: it can never claim it again.",
|
|
3042
|
+
KeyStillActive: 'This address still has an active claim for the key: revoke that claim as "compromised" instead.',
|
|
3043
|
+
KeyTooLarge: "The key is over 16,384 bytes: export it without photos or old signatures.",
|
|
3044
|
+
NotAKey: "The key doesn't start with an OpenPGP public-key packet: give gpg's export of the public key.",
|
|
3045
|
+
NotASignature: "The signature is neither an OpenPGP signature nor a clearsigned message.",
|
|
3046
|
+
NotArmored: "The paste has no -----BEGIN PGP and -----END PGP lines.",
|
|
3047
|
+
PayloadTooLarge: "The signature and key together are over 24,000 bytes.",
|
|
3048
|
+
PermissionExpired: "The permission is past its deadline: ask the owner for a new one.",
|
|
3049
|
+
RecordTooLarge: "The record value is over 1,024 bytes.",
|
|
3050
|
+
SignatureTooLarge: "The signature is over 8,192 bytes.",
|
|
3051
|
+
SupersededIsSetByReattest: '"superseded" is set only by replacing a claim: pick another reason.',
|
|
3052
|
+
TooManyClaims: "This address has reached the limit of 65,535 claims.",
|
|
3053
|
+
UnknownRevokeReason: 'The revoke reason must be empty, "compromised", "retired", or "other".',
|
|
3054
|
+
UnsupportedHeader: "Armor header lines (like Comment:) can't be told from the data, as when line breaks were lost: remove them."
|
|
3055
|
+
};
|
|
3056
|
+
function contractErrorName(err) {
|
|
3057
|
+
for (let e = err, depth = 0; e && depth < 8; e = e.cause, depth++) {
|
|
3058
|
+
const name = _nullishCoalesce(_optionalChain([e, 'access', _84 => _84.data, 'optionalAccess', _85 => _85.errorName]), () => ( e.errorName));
|
|
3059
|
+
if (typeof name === "string" && name) return name;
|
|
3060
|
+
}
|
|
3061
|
+
return null;
|
|
3062
|
+
}
|
|
3063
|
+
function contractErrorText(err) {
|
|
3064
|
+
const name = contractErrorName(err);
|
|
3065
|
+
return name ? _nullishCoalesce(CONTRACT_ERROR_TEXT[name], () => ( `The registry refused it (${name}).`)) : null;
|
|
1975
3066
|
}
|
|
1976
3067
|
|
|
1977
3068
|
// src/core/records.ts
|
|
1978
|
-
|
|
1979
3069
|
var MAX_RECORD_BYTES = 1024;
|
|
3070
|
+
var MAX_KIND_BYTES = 31;
|
|
1980
3071
|
function kindName(input) {
|
|
1981
3072
|
return input.includes(".") ? input : `thurin.${input}`;
|
|
1982
3073
|
}
|
|
3074
|
+
function checkKindName(input) {
|
|
3075
|
+
if (!/^[a-z0-9.-]+$/.test(input)) throw new Error(`Record name "${input}": use a-z, 0-9, "-" and "." only`);
|
|
3076
|
+
const name = kindName(input);
|
|
3077
|
+
if (name.length > MAX_KIND_BYTES) throw new Error(`Record name "${name}" is ${name.length} bytes; the registry allows ${MAX_KIND_BYTES}`);
|
|
3078
|
+
return name;
|
|
3079
|
+
}
|
|
3080
|
+
function checkRecordValue(value) {
|
|
3081
|
+
const bytes = new TextEncoder().encode(value).length;
|
|
3082
|
+
if (bytes > MAX_RECORD_BYTES) throw new Error(`Record is ${bytes} bytes; the registry accepts up to ${MAX_RECORD_BYTES}`);
|
|
3083
|
+
return value;
|
|
3084
|
+
}
|
|
1983
3085
|
var KNOWN_KINDS = [
|
|
1984
3086
|
"thurin.railgun",
|
|
1985
3087
|
"thurin.security",
|
|
1986
3088
|
"thurin.successor",
|
|
1987
3089
|
"thurin.affiliation",
|
|
1988
3090
|
"thurin.canary",
|
|
1989
|
-
"thurin.
|
|
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",
|
|
3091
|
+
"thurin.releases",
|
|
1999
3092
|
"thurin.private",
|
|
2000
3093
|
"thurin.disclosure"
|
|
2001
3094
|
];
|
|
2002
|
-
function
|
|
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) {
|
|
3095
|
+
function parseReleases(text) {
|
|
2011
3096
|
const p = JSON.parse(text);
|
|
2012
|
-
if (_optionalChain([p, 'optionalAccess',
|
|
3097
|
+
if (_optionalChain([p, 'optionalAccess', _86 => _86.v]) !== 1 || !Array.isArray(p.releases)) throw new Error("Not a v1 thurin.releases record");
|
|
2013
3098
|
return p;
|
|
2014
3099
|
}
|
|
2015
|
-
function
|
|
3100
|
+
function addRelease(existing, entry) {
|
|
2016
3101
|
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',
|
|
3102
|
+
const releases = [entry, ...(_nullishCoalesce(_optionalChain([existing, 'optionalAccess', _87 => _87.releases]), () => ( []))).filter((r) => r.name !== entry.name)];
|
|
2018
3103
|
const dropped = [];
|
|
2019
3104
|
const record = { v: 1, releases };
|
|
2020
3105
|
while (new TextEncoder().encode(JSON.stringify(record)).length > MAX_RECORD_BYTES && releases.length > 1) dropped.push(releases.pop());
|
|
2021
3106
|
return { record, dropped };
|
|
2022
3107
|
}
|
|
2023
|
-
function
|
|
3108
|
+
function renderReleases(p) {
|
|
2024
3109
|
return p.releases.map((r) => `${r.name.padEnd(22)} ${r.date} sha256 ${r.sha256}${r.url ? ` ${r.url}` : ""}`).join("\n");
|
|
2025
3110
|
}
|
|
2026
3111
|
var RAILGUN_ADDRESS = /^0zk1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{60,200}$/;
|
|
@@ -2048,14 +3133,14 @@ async function parseRecord(kind, text, opts = {}) {
|
|
|
2048
3133
|
case "thurin.affiliation": {
|
|
2049
3134
|
try {
|
|
2050
3135
|
const j = JSON.parse(t);
|
|
2051
|
-
if (_optionalChain([j, 'optionalAccess',
|
|
3136
|
+
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
3137
|
return { ...base, valid: true, data: { type: "affiliation", with: j.with, role: typeof j.role === "string" ? j.role : null } };
|
|
2053
|
-
} catch (
|
|
3138
|
+
} catch (e18) {
|
|
2054
3139
|
return invalid("Not JSON");
|
|
2055
3140
|
}
|
|
2056
3141
|
}
|
|
2057
3142
|
case "thurin.canary": {
|
|
2058
|
-
const date = _optionalChain([t, 'access',
|
|
3143
|
+
const date = _optionalChain([t, 'access', _89 => _89.match, 'call', _90 => _90(ISO_DATE), 'optionalAccess', _91 => _91[1]]);
|
|
2059
3144
|
if (!date) return invalid("No date in the statement");
|
|
2060
3145
|
const clearsigned = t.startsWith("-----BEGIN PGP SIGNED MESSAGE-----");
|
|
2061
3146
|
let statement = clearsigned ? (_nullishCoalesce(t.split(/\r?\n\r?\n/)[1], () => ( ""))).split("-----BEGIN PGP SIGNATURE-----")[0].trim() : t;
|
|
@@ -2075,119 +3160,126 @@ async function parseRecord(kind, text, opts = {}) {
|
|
|
2075
3160
|
try {
|
|
2076
3161
|
const { readMessage } = await Promise.resolve().then(() => _interopRequireWildcard(require("openpgp")));
|
|
2077
3162
|
recipients = (await readMessage({ armoredMessage: t })).getEncryptionKeyIDs().length;
|
|
2078
|
-
} catch (
|
|
3163
|
+
} catch (e19) {
|
|
2079
3164
|
return invalid("PGP message does not parse");
|
|
2080
3165
|
}
|
|
2081
3166
|
return { ...base, valid: true, data: { type: "encrypted", recipients } };
|
|
2082
3167
|
}
|
|
2083
|
-
case "thurin.
|
|
3168
|
+
case "thurin.releases": {
|
|
2084
3169
|
try {
|
|
2085
|
-
return { ...base, valid: true, data: { type: "
|
|
2086
|
-
} catch (
|
|
2087
|
-
return invalid(
|
|
3170
|
+
return { ...base, valid: true, data: { type: "releases", releases: parseReleases(t).releases } };
|
|
3171
|
+
} catch (e20) {
|
|
3172
|
+
return invalid('Not a v1 release list: expected {"v":1,"releases":[\u2026]}');
|
|
2088
3173
|
}
|
|
2089
3174
|
}
|
|
2090
3175
|
default:
|
|
2091
3176
|
return { ...base, valid: true, data: { type: "text" } };
|
|
2092
3177
|
}
|
|
2093
3178
|
}
|
|
2094
|
-
|
|
3179
|
+
function pickRecords(names, values, kinds = KNOWN_KINDS) {
|
|
3180
|
+
const all = names.map((kind, i) => ({ kind, text: _nullishCoalesce(values[i], () => ( "")) })).filter((r) => r.text);
|
|
3181
|
+
if (!kinds) return all;
|
|
3182
|
+
return kinds.flatMap((k) => all.filter((r) => r.kind === k));
|
|
3183
|
+
}
|
|
3184
|
+
function pageRecords(names, values) {
|
|
3185
|
+
const all = pickRecords(names, values, null);
|
|
3186
|
+
const ours = KNOWN_KINDS.flatMap((k) => all.filter((r) => r.kind === k));
|
|
3187
|
+
return [...ours, ...all.filter((r) => !KNOWN_KINDS.includes(r.kind))];
|
|
3188
|
+
}
|
|
3189
|
+
async function fetchRecords(client, registry, abi, owner, index, kinds = KNOWN_KINDS, opts = {}) {
|
|
3190
|
+
const [names, values] = await client.readContract({ address: registry, abi, functionName: "recordsOf", args: [owner, BigInt(index)] });
|
|
2095
3191
|
const out = [];
|
|
2096
|
-
for (const
|
|
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
|
-
}
|
|
3192
|
+
for (const r of pickRecords(names, values, kinds)) out.push(await parseRecord(r.kind, r.text, opts));
|
|
2101
3193
|
return out;
|
|
2102
3194
|
}
|
|
2103
3195
|
|
|
2104
|
-
// src/core/
|
|
2105
|
-
var
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
};
|
|
2115
|
-
|
|
2116
|
-
if (
|
|
2117
|
-
|
|
2118
|
-
if (
|
|
2119
|
-
return
|
|
3196
|
+
// src/core/avatar.ts
|
|
3197
|
+
var IPFS_GATEWAYS = ["https://ipfs.filebase.io/ipfs/", "https://gateway.pinata.cloud/ipfs/"];
|
|
3198
|
+
var IPFS_GATEWAY = IPFS_GATEWAYS[0];
|
|
3199
|
+
var ARWEAVE_GATEWAY = "https://arweave.net/";
|
|
3200
|
+
function avatarUrl(uri) {
|
|
3201
|
+
if (typeof uri !== "string") return null;
|
|
3202
|
+
const u = uri.trim();
|
|
3203
|
+
if (/^data:image\/(png|jpe?g|gif|webp|avif|svg\+xml)[;,]/i.test(u)) return u;
|
|
3204
|
+
let m = u.match(/^ipfs:\/\/(?:ipfs\/)?([a-zA-Z0-9]{46,}(?:\/[^?#\s]*)?)$/);
|
|
3205
|
+
if (m) return IPFS_GATEWAY + m[1];
|
|
3206
|
+
m = u.match(/^ar:\/\/([a-zA-Z0-9_-]{43}(?:\/[^?#\s]*)?)$/);
|
|
3207
|
+
if (m) return ARWEAVE_GATEWAY + m[1];
|
|
3208
|
+
if (/^https:\/\/euc\.li\/[^?#\s]+$/.test(u)) return u;
|
|
3209
|
+
m = u.match(/^https:\/\/[^/]+\/ipfs\/([a-zA-Z0-9]{46,}(?:\/[^?#\s]*)?)$/);
|
|
3210
|
+
if (m) return IPFS_GATEWAY + m[1];
|
|
3211
|
+
return null;
|
|
2120
3212
|
}
|
|
2121
|
-
function
|
|
2122
|
-
if (!
|
|
2123
|
-
const
|
|
2124
|
-
return
|
|
3213
|
+
function avatarFallbacks(url) {
|
|
3214
|
+
if (!url || !url.startsWith(IPFS_GATEWAYS[0])) return [];
|
|
3215
|
+
const path = url.slice(IPFS_GATEWAYS[0].length);
|
|
3216
|
+
return IPFS_GATEWAYS.slice(1).map((g) => g + path);
|
|
2125
3217
|
}
|
|
2126
|
-
function
|
|
2127
|
-
const
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
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.");
|
|
3218
|
+
function parseNftAvatar(raw) {
|
|
3219
|
+
const m = typeof raw === "string" && raw.trim().match(/^eip155:(\d+)\/(erc721|erc1155):(0x[0-9a-fA-F]{40})\/(\d+)$/i);
|
|
3220
|
+
return m ? { chainId: Number(m[1]), standard: m[2].toLowerCase(), contract: m[3], tokenId: BigInt(m[4]) } : null;
|
|
3221
|
+
}
|
|
3222
|
+
var NFT_AVATAR_ABI = [
|
|
3223
|
+
{ type: "function", name: "tokenURI", stateMutability: "view", inputs: [{ type: "uint256" }], outputs: [{ type: "string" }] },
|
|
3224
|
+
{ type: "function", name: "uri", stateMutability: "view", inputs: [{ type: "uint256" }], outputs: [{ type: "string" }] }
|
|
3225
|
+
];
|
|
3226
|
+
async function nftAvatarImage(tokenUri, tokenId, fetchFn = fetch) {
|
|
3227
|
+
const uri = tokenUri.replace("{id}", tokenId.toString(16).padStart(64, "0"));
|
|
3228
|
+
let meta;
|
|
3229
|
+
const inline = uri.match(/^data:application\/json(;base64)?,([\s\S]*)$/);
|
|
3230
|
+
if (inline) meta = JSON.parse(inline[1] ? atob(inline[2]) : decodeURIComponent(inline[2]));
|
|
3231
|
+
else {
|
|
3232
|
+
const url = uri.startsWith("data:") ? null : avatarUrl(uri);
|
|
3233
|
+
if (!url) return null;
|
|
3234
|
+
for (const candidate of [url, ...avatarFallbacks(url)]) {
|
|
3235
|
+
try {
|
|
3236
|
+
const res = await fetchFn(candidate);
|
|
3237
|
+
if (res.ok) {
|
|
3238
|
+
meta = await res.json();
|
|
3239
|
+
break;
|
|
3240
|
+
}
|
|
3241
|
+
} catch (e21) {
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
if (!meta) return null;
|
|
2163
3245
|
}
|
|
3246
|
+
return avatarUrl(_nullishCoalesce(_optionalChain([meta, 'optionalAccess', _92 => _92.image]), () => ( _optionalChain([meta, 'optionalAccess', _93 => _93.image_url]))));
|
|
2164
3247
|
}
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
3248
|
+
|
|
3249
|
+
// src/core/ensHint.ts
|
|
3250
|
+
var _ens = require('viem/ens');
|
|
3251
|
+
var ENS_HINT_KEY = "id.thurin";
|
|
3252
|
+
function ensHintFor(record, verifiedFingerprint) {
|
|
3253
|
+
const raw = _nullishCoalesce(_optionalChain([record, 'optionalAccess', _94 => _94.trim, 'call', _95 => _95()]), () => ( ""));
|
|
3254
|
+
const expected = verifiedFingerprint ? normalizeFingerprint(verifiedFingerprint) : null;
|
|
3255
|
+
if (!raw) return { key: ENS_HINT_KEY, state: "unset", record: null, fingerprint: null, expected };
|
|
3256
|
+
const fingerprint = normalizeFingerprint(raw);
|
|
3257
|
+
if (!fingerprint) return { key: ENS_HINT_KEY, state: "mismatch", record: raw, fingerprint: null, expected, reason: "The record is not a PGP fingerprint" };
|
|
3258
|
+
if (!expected) return { key: ENS_HINT_KEY, state: "mismatch", record: raw, fingerprint, expected, reason: "The address has no verified claim" };
|
|
3259
|
+
if (fingerprint === expected) return { key: ENS_HINT_KEY, state: "match", record: raw, fingerprint, expected };
|
|
3260
|
+
return { key: ENS_HINT_KEY, state: "mismatch", record: raw, fingerprint, expected, reason: "The record names a key this address has not claimed" };
|
|
2170
3261
|
}
|
|
2171
|
-
function
|
|
2172
|
-
const
|
|
2173
|
-
|
|
3262
|
+
function ensHintValue(fingerprint) {
|
|
3263
|
+
const fp = normalizeFingerprint(fingerprint);
|
|
3264
|
+
if (!fp) throw new Error(`Not a fingerprint: ${fingerprint}`);
|
|
3265
|
+
return fp.toUpperCase();
|
|
2174
3266
|
}
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
3267
|
+
var ENS_TEXT_RESOLVER_ABI = [
|
|
3268
|
+
{ type: "function", name: "text", stateMutability: "view", inputs: [{ name: "node", type: "bytes32" }, { name: "key", type: "string" }], outputs: [{ name: "", type: "string" }] },
|
|
3269
|
+
{ type: "function", name: "setText", stateMutability: "nonpayable", inputs: [{ name: "node", type: "bytes32" }, { name: "key", type: "string" }, { name: "value", type: "string" }], outputs: [] }
|
|
3270
|
+
];
|
|
3271
|
+
function ensHintWrite(name, fingerprint) {
|
|
3272
|
+
const normalized = _ens.normalize.call(void 0, name);
|
|
3273
|
+
return {
|
|
3274
|
+
abi: ENS_TEXT_RESOLVER_ABI,
|
|
3275
|
+
functionName: "setText",
|
|
3276
|
+
args: [_ens.namehash.call(void 0, normalized), ENS_HINT_KEY, ensHintValue(fingerprint)],
|
|
3277
|
+
name: normalized
|
|
3278
|
+
};
|
|
2186
3279
|
}
|
|
2187
|
-
function
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
return null;
|
|
3280
|
+
async function fetchEnsHint(client, name, verifiedFingerprint) {
|
|
3281
|
+
const record = await client.getEnsText({ name: _ens.normalize.call(void 0, name), key: ENS_HINT_KEY });
|
|
3282
|
+
return ensHintFor(record, verifiedFingerprint);
|
|
2191
3283
|
}
|
|
2192
3284
|
|
|
2193
3285
|
|
|
@@ -2261,5 +3353,25 @@ function claimFateText(fate, formatDate = (s) => formatClaimDate(s)) {
|
|
|
2261
3353
|
|
|
2262
3354
|
|
|
2263
3355
|
|
|
2264
|
-
|
|
2265
|
-
|
|
3356
|
+
|
|
3357
|
+
|
|
3358
|
+
|
|
3359
|
+
|
|
3360
|
+
|
|
3361
|
+
|
|
3362
|
+
|
|
3363
|
+
|
|
3364
|
+
|
|
3365
|
+
|
|
3366
|
+
|
|
3367
|
+
|
|
3368
|
+
|
|
3369
|
+
|
|
3370
|
+
|
|
3371
|
+
|
|
3372
|
+
|
|
3373
|
+
|
|
3374
|
+
|
|
3375
|
+
|
|
3376
|
+
|
|
3377
|
+
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.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;
|