wkd-checker 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +16 -0
- package/dist/index.js +95 -11
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface KeyCheckResult {
|
|
|
5
5
|
policy_location: string;
|
|
6
6
|
policyAvailable: boolean;
|
|
7
7
|
policyCorsValid: boolean;
|
|
8
|
+
policy: PolicyFlags | null;
|
|
8
9
|
key_location: string | null;
|
|
9
10
|
key_available: boolean;
|
|
10
11
|
keyCorsValid: boolean;
|
|
@@ -14,6 +15,7 @@ export interface KeyCheckResult {
|
|
|
14
15
|
emailInKey: boolean;
|
|
15
16
|
expired: boolean;
|
|
16
17
|
revoked: boolean;
|
|
18
|
+
policyCompliant: boolean;
|
|
17
19
|
valid: boolean;
|
|
18
20
|
}
|
|
19
21
|
/**
|
|
@@ -24,6 +26,20 @@ export declare enum KeyType {
|
|
|
24
26
|
BinaryKey = "BinaryKey",
|
|
25
27
|
ArmoredKey = "ArmoredKey"
|
|
26
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Result of the policy file check.
|
|
31
|
+
*/
|
|
32
|
+
export interface PolicyFlags {
|
|
33
|
+
mailboxOnly: boolean;
|
|
34
|
+
daneOnly: boolean;
|
|
35
|
+
authSubmit: boolean;
|
|
36
|
+
protocolVersion: number | null;
|
|
37
|
+
submissionAddress: string | null;
|
|
38
|
+
others: Array<{
|
|
39
|
+
key: string;
|
|
40
|
+
value: string | null;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
27
43
|
export declare class WKDError extends Error {
|
|
28
44
|
constructor(message: string);
|
|
29
45
|
}
|
package/dist/index.js
CHANGED
|
@@ -80,6 +80,64 @@ const detectKeyType = (keyData) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
80
80
|
return { keyType: KeyType.Invalid, key: null };
|
|
81
81
|
}
|
|
82
82
|
});
|
|
83
|
+
/**
|
|
84
|
+
* Parses the Policy Flags file.
|
|
85
|
+
* Section 4.5. Policy Flags
|
|
86
|
+
* @param {string} text - Content of the policy file.
|
|
87
|
+
* @returns {PolicyFlags} Parsed policy flags.
|
|
88
|
+
*/
|
|
89
|
+
const parsePolicy = (text) => {
|
|
90
|
+
const flags = {
|
|
91
|
+
mailboxOnly: false,
|
|
92
|
+
daneOnly: false,
|
|
93
|
+
authSubmit: false,
|
|
94
|
+
protocolVersion: null,
|
|
95
|
+
submissionAddress: null,
|
|
96
|
+
others: []
|
|
97
|
+
};
|
|
98
|
+
if (!text)
|
|
99
|
+
return flags;
|
|
100
|
+
const lines = text.split(/\r?\n/);
|
|
101
|
+
for (const line of lines) {
|
|
102
|
+
const trimmed = line.trim();
|
|
103
|
+
// "Empty lines and lines starting with a '#' character are considered comment lines."
|
|
104
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
105
|
+
continue;
|
|
106
|
+
const colonIndex = trimmed.indexOf(':');
|
|
107
|
+
let key = '';
|
|
108
|
+
let value = null;
|
|
109
|
+
if (colonIndex !== -1) {
|
|
110
|
+
key = trimmed.substring(0, colonIndex).trim().toLowerCase();
|
|
111
|
+
value = trimmed.substring(colonIndex + 1).trim();
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
key = trimmed.trim().toLowerCase();
|
|
115
|
+
}
|
|
116
|
+
switch (key) {
|
|
117
|
+
case 'mailbox-only':
|
|
118
|
+
flags.mailboxOnly = true;
|
|
119
|
+
break;
|
|
120
|
+
case 'dane-only':
|
|
121
|
+
flags.daneOnly = true;
|
|
122
|
+
break;
|
|
123
|
+
case 'auth-submit':
|
|
124
|
+
flags.authSubmit = true;
|
|
125
|
+
break;
|
|
126
|
+
case 'protocol-version':
|
|
127
|
+
if (value)
|
|
128
|
+
flags.protocolVersion = parseInt(value, 10);
|
|
129
|
+
break;
|
|
130
|
+
case 'submission-address':
|
|
131
|
+
if (value)
|
|
132
|
+
flags.submissionAddress = value;
|
|
133
|
+
break;
|
|
134
|
+
default:
|
|
135
|
+
// "For experimental use of new features or for provider specific settings, keywords MUST be prefixed with a domain name and an underscore."
|
|
136
|
+
flags.others.push({ key, value });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return flags;
|
|
140
|
+
};
|
|
83
141
|
/**
|
|
84
142
|
* Checks for a key at a specific WKD URL.
|
|
85
143
|
* @param {string} url - The WKD URL for the key.
|
|
@@ -89,15 +147,26 @@ const detectKeyType = (keyData) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
89
147
|
* @returns {Promise<KeyCheckResult>} The result of the key check.
|
|
90
148
|
*/
|
|
91
149
|
const checkKeyUrl = (url, policy, options, email) => __awaiter(void 0, void 0, void 0, function* () {
|
|
92
|
-
var _a, _b;
|
|
150
|
+
var _a, _b, _c;
|
|
93
151
|
const [policyData, keyData] = yield Promise.all([
|
|
94
152
|
fetchWithCorsCheck(policy, options),
|
|
95
153
|
fetchWithCorsCheck(url, options)
|
|
96
154
|
]);
|
|
155
|
+
let policyFlags = null;
|
|
156
|
+
if (policyData.response) {
|
|
157
|
+
try {
|
|
158
|
+
const policyText = yield policyData.response.text();
|
|
159
|
+
policyFlags = parsePolicy(policyText);
|
|
160
|
+
}
|
|
161
|
+
catch (_d) {
|
|
162
|
+
policyFlags = parsePolicy("");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
97
165
|
const result = {
|
|
98
166
|
policy_location: ((_a = policyData.response) === null || _a === void 0 ? void 0 : _a.url) || policy,
|
|
99
167
|
policyAvailable: !!policyData.response,
|
|
100
168
|
policyCorsValid: policyData.corsValid,
|
|
169
|
+
policy: policyFlags,
|
|
101
170
|
key_location: ((_b = keyData.response) === null || _b === void 0 ? void 0 : _b.url) || url,
|
|
102
171
|
key_available: !!keyData.response,
|
|
103
172
|
keyCorsValid: keyData.corsValid,
|
|
@@ -107,6 +176,7 @@ const checkKeyUrl = (url, policy, options, email) => __awaiter(void 0, void 0, v
|
|
|
107
176
|
emailInKey: false,
|
|
108
177
|
expired: false,
|
|
109
178
|
revoked: false,
|
|
179
|
+
policyCompliant: true,
|
|
110
180
|
valid: false,
|
|
111
181
|
};
|
|
112
182
|
if (keyData.response) {
|
|
@@ -116,15 +186,25 @@ const checkKeyUrl = (url, policy, options, email) => __awaiter(void 0, void 0, v
|
|
|
116
186
|
result.keyTypeValid = keyType === KeyType.BinaryKey;
|
|
117
187
|
if (key) {
|
|
118
188
|
const identities = yield key.getUserIDs();
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
189
|
+
// Helper to extract email address from User ID string ("Name <email@domain>" or "email@domain")
|
|
190
|
+
const extractEmail = (id) => {
|
|
191
|
+
const match = id.match(/<([^>]+)>/);
|
|
192
|
+
return (match ? match[1] : id).trim().toLowerCase();
|
|
193
|
+
};
|
|
194
|
+
const targetEmail = email.trim().toLowerCase();
|
|
195
|
+
const emailsInKey = identities.map(extractEmail);
|
|
196
|
+
// Spec Section 3.1 & Section 5: The key needs to carry a User ID packet with that mail address.
|
|
197
|
+
// Client MUST check that the received key has the requested User-Id and MUST drop all other User-Ids.
|
|
198
|
+
result.emailInKey = emailsInKey.includes(targetEmail);
|
|
199
|
+
// Check policy compliance
|
|
200
|
+
if (((_c = result.policy) === null || _c === void 0 ? void 0 : _c.mailboxOnly) && identities.length > 0) {
|
|
201
|
+
for (const id of identities) {
|
|
202
|
+
const emailInId = extractEmail(id);
|
|
203
|
+
const expected = [`<${emailInId}>`, emailInId];
|
|
204
|
+
if (!expected.includes(id.trim().toLowerCase())) {
|
|
205
|
+
result.policyCompliant = false;
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
128
208
|
}
|
|
129
209
|
}
|
|
130
210
|
result.fingerprint = key.getFingerprint().toUpperCase();
|
|
@@ -138,7 +218,8 @@ const checkKeyUrl = (url, policy, options, email) => __awaiter(void 0, void 0, v
|
|
|
138
218
|
result.valid = result.policyAvailable &&
|
|
139
219
|
result.key_available &&
|
|
140
220
|
result.keyTypeValid &&
|
|
141
|
-
result.emailInKey
|
|
221
|
+
result.emailInKey &&
|
|
222
|
+
result.policyCompliant;
|
|
142
223
|
return result;
|
|
143
224
|
});
|
|
144
225
|
/**
|
|
@@ -237,6 +318,9 @@ exports.getKey = getKey;
|
|
|
237
318
|
* @returns {Promise<{ advanced: KeyCheckResult, direct: KeyCheckResult }>} Results for both lookup methods.
|
|
238
319
|
*/
|
|
239
320
|
const checkKey = (email) => __awaiter(void 0, void 0, void 0, function* () {
|
|
321
|
+
if (!(0, exports.validateEmail)(email)) {
|
|
322
|
+
throw new WKDError('Invalid e-mail address.');
|
|
323
|
+
}
|
|
240
324
|
const { advancedUrl, directUrl, advancedPolicyUrl, directPolicyUrl } = yield generateWkdUrls(email);
|
|
241
325
|
const options = {
|
|
242
326
|
headers: { "User-Agent": USER_AGENT }
|