1
2
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
import { PublicKey, readCleartextMessage, readKey, verify } from 'openpgp';
export const keyStore = new Map<string, PublicKey>();
export const validateSignature = async (
message: string,
id: string,
) => {
id = id.toUpperCase();
const key = keyStore.get(id) ?? keyStore.get(id.replace(/ /g, ''));
if (!key) throw new Error('Could not find key from keystore');
const signedMessage = await readCleartextMessage({
cleartextMessage: message,
});
const verificationResult = await verify({
message: signedMessage,
verificationKeys: key,
expectSigned: true,
});
return verificationResult.data;
};
const pushKey = async (
{ ids, key, is_url, expectUserIds, signed_by }: {
ids?: string[];
expectUserIds?: string[];
key: string;
is_url?: boolean;
signed_by?: string;
},
) => {
ids = ids ?? [];
if (is_url) {
key = await fetch(
new URL(key, 'https://keys.openpgp.org/vks/v1/by-fingerprint/'),
{},
).then((v) => v.text());
}
if (signed_by) {
key = await validateSignature(key, signed_by);
}
const parsedKey = await readKey({
armoredKey: key,
}).then((v) => v.toPublic());
{
const missingUserIds =
expectUserIds?.filter((v) => !expectUserIds.includes(v)) ?? [];
if (missingUserIds.length) {
throw new Error(
`Key ${parsedKey.getFingerprint()} is missing User IDs: ${
missingUserIds.join(', ')
}`,
);
}
}
ids.push(
parsedKey.getKeyID().toHex().replace(/ /g, ''),
parsedKey.getFingerprint().replace(/ /g, ''),
...(expectUserIds ?? []),
);
ids = ids.filter((v, i, a) => a.indexOf(v) === i).map((v) => v.toUpperCase());
for (const id of ids) {
keyStore.set(id, parsedKey);
}
};
await pushKey({
key: 'B546778F06BBCC8EC167DB3CD919706487B8B6DE',
ids: ['memdmp'],
expectUserIds: [
'memdmp <memdmp@estrogen.zone>',
'memdmp <memdmp@memeware.net>',
],
is_url: true,
});
await pushKey({
// TODO: when primary memdmp key rotates, or when this key expires, replace this inline string with a new one
key: `-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
- -----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: User ID: memdmp canary keysig <memdmp-key-for-signing-canary-related-keys-for-external-services@fakemail.uwu>
Comment: Valid from: 22 Nov 2024 18:31:11
Comment: Valid until: 22 Nov 2027 12:00:00
Comment: Type: 255-bit EdDSA (secret key available)
Comment: Usage: Signing, Encryption, Certifying User IDs
Comment: Fingerprint: 55D3582CAE78601990A8CA1DBFD0F9E61CB7D84E
mDMEZ0C/3xYJKwYBBAHaRw8BAQdA5w4ET7V3FmasUc3h9sb0O0/y38LXp+IUV8Wf
La95jm20ZG1lbWRtcCBjYW5hcnkga2V5c2lnIDxtZW1kbXAta2V5LWZvci1zaWdu
aW5nLWNhbmFyeS1yZWxhdGVkLWtleXMtZm9yLWV4dGVybmFsLXNlcnZpY2VzQGZh
a2VtYWlsLnV3dT6ImQQTFgoAQRYhBFXTWCyueGAZkKjKHb/Q+eYct9hOBQJnQL/f
AhsDBQkFoz7RBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEL/Q+eYct9hO
X68BAPPBy76J7EWb25+fj/QUD0rYyi/E2kLfGbW+PLhrB/AdAQDl5icCilAI/2xv
X4jpGCH9KdJoClIV4g2AyKoEITKBDbg4BGdAv98SCisGAQQBl1UBBQEBB0CcYmml
AWFCXVjIerJJrs/GA65EZDwoZowiVVTS99FvaQMBCAeIfgQYFgoAJhYhBFXTWCyu
eGAZkKjKHb/Q+eYct9hOBQJnQL/fAhsMBQkFoz7RAAoJEL/Q+eYct9hOr2IA/22U
2rOPevvUoiObv/DeeQlP2mvaQcOCFHp1HVF+4oHrAQDWZiihBvdIESbqm5MH0zLe
EkEE03+lW4Zbe25P6MHsBg==
=5NPo
- -----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP SIGNATURE-----
iIoEARYKADIWIQS1RnePBrvMjsFn2zzZGXBkh7i23gUCZ0DABRQcbWVtZG1wQG1l
bWV3YXJlLm5ldAAKCRDZGXBkh7i23vV5AP9K2Q6j6cOGovTVqsWlThK7qxA2Faz+
ZQ4KTbprMz8J4AD/bG33f9Kqg3AqehEyU2TldJs9U9Oni5AXGSGfKLJhmQc=
=945T
-----END PGP SIGNATURE-----
`,
signed_by: 'memdmp <memdmp@memeware.net>',
ids: ['canary-sigkey-signing'],
});
await pushKey({
// TODO: adapt to the relevant url on current domain when up
key: 'https://files.catbox.moe/yf4x40.sig',
ids: ['napatha'],
expectUserIds: [
'chef naphtha <naphtha@kyun.host>',
],
is_url: true,
signed_by: 'canary-sigkey-signing',
});
export default keyStore;
|