@metamask-previews/phishing-controller 10.0.0-preview-e4ec85f → 10.1.0-preview-ee06f305
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/CHANGELOG.md +14 -1
- package/dist/PhishingController.js +3 -2
- package/dist/PhishingController.mjs +2 -1
- package/dist/PhishingDetector.js +3 -2
- package/dist/PhishingDetector.mjs +2 -1
- package/dist/{chunk-FHOK4NLK.mjs → chunk-AR5SZVZG.mjs} +37 -29
- package/dist/{chunk-FHOK4NLK.mjs.map → chunk-AR5SZVZG.mjs.map} +1 -1
- package/dist/{chunk-BU22EICT.js → chunk-SJIYZL3T.js} +78 -70
- package/dist/chunk-SJIYZL3T.js.map +1 -0
- package/dist/chunk-XUI43LEZ.mjs +30 -0
- package/dist/chunk-XUI43LEZ.mjs.map +1 -0
- package/dist/chunk-Z4BLTVTB.js +30 -0
- package/dist/chunk-Z4BLTVTB.js.map +1 -0
- package/dist/index.js +3 -2
- package/dist/index.mjs +2 -1
- package/dist/tests/utils.js +16 -0
- package/dist/tests/utils.js.map +1 -0
- package/dist/tests/utils.mjs +16 -0
- package/dist/tests/utils.mjs.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/PhishingDetector.d.ts +5 -4
- package/dist/types/PhishingDetector.d.ts.map +1 -1
- package/dist/types/tests/utils.d.ts +11 -0
- package/dist/types/tests/utils.d.ts.map +1 -0
- package/dist/utils.js +3 -2
- package/dist/utils.mjs +2 -1
- package/package.json +1 -1
- package/dist/chunk-BU22EICT.js.map +0 -1
|
@@ -1,25 +1,9 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
return getter ? getter.call(obj) : member.get(obj);
|
|
8
|
-
};
|
|
9
|
-
var __privateAdd = (obj, member, value) => {
|
|
10
|
-
if (member.has(obj))
|
|
11
|
-
throw TypeError("Cannot add the same private member more than once");
|
|
12
|
-
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
13
|
-
};
|
|
14
|
-
var __privateSet = (obj, member, value, setter) => {
|
|
15
|
-
__accessCheck(obj, member, "write to private field");
|
|
16
|
-
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
17
|
-
return value;
|
|
18
|
-
};
|
|
19
|
-
var __privateMethod = (obj, member, method) => {
|
|
20
|
-
__accessCheck(obj, member, "access private method");
|
|
21
|
-
return method;
|
|
22
|
-
};
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
var _chunkZ4BLTVTBjs = require('./chunk-Z4BLTVTB.js');
|
|
23
7
|
|
|
24
8
|
// src/PhishingController.ts
|
|
25
9
|
var _basecontroller = require('@metamask/base-controller');
|
|
@@ -41,14 +25,14 @@ var PhishingDetector = class {
|
|
|
41
25
|
* @param opts - Phishing detection options
|
|
42
26
|
*/
|
|
43
27
|
constructor(opts) {
|
|
44
|
-
__privateAdd(this, _check);
|
|
45
|
-
__privateAdd(this, _configs, void 0);
|
|
46
|
-
__privateAdd(this, _legacyConfig, void 0);
|
|
28
|
+
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _check);
|
|
29
|
+
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _configs, void 0);
|
|
30
|
+
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _legacyConfig, void 0);
|
|
47
31
|
if (Array.isArray(opts)) {
|
|
48
|
-
__privateSet(this, _configs, processConfigs(opts));
|
|
49
|
-
__privateSet(this, _legacyConfig, false);
|
|
32
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _configs, processConfigs(opts));
|
|
33
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _legacyConfig, false);
|
|
50
34
|
} else {
|
|
51
|
-
__privateSet(this, _configs, [
|
|
35
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _configs, [
|
|
52
36
|
getDefaultPhishingDetectorConfig({
|
|
53
37
|
allowlist: opts.whitelist,
|
|
54
38
|
blocklist: opts.blacklist,
|
|
@@ -56,19 +40,20 @@ var PhishingDetector = class {
|
|
|
56
40
|
tolerance: opts.tolerance
|
|
57
41
|
})
|
|
58
42
|
]);
|
|
59
|
-
__privateSet(this, _legacyConfig, true);
|
|
43
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _legacyConfig, true);
|
|
60
44
|
}
|
|
61
45
|
}
|
|
62
46
|
/**
|
|
63
|
-
* Check if a
|
|
64
|
-
* target.
|
|
47
|
+
* Check if a url is known to be malicious or similar to a common phishing
|
|
48
|
+
* target. This will check the hostname and IPFS CID that is sometimes
|
|
49
|
+
* located in the path.
|
|
65
50
|
*
|
|
66
|
-
* @param
|
|
51
|
+
* @param url - The url to check.
|
|
67
52
|
* @returns The result of the check.
|
|
68
53
|
*/
|
|
69
|
-
check(
|
|
70
|
-
const result = __privateMethod(this, _check, check_fn).call(this,
|
|
71
|
-
if (__privateGet(this, _legacyConfig)) {
|
|
54
|
+
check(url) {
|
|
55
|
+
const result = _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _check, check_fn).call(this, url);
|
|
56
|
+
if (_chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _legacyConfig)) {
|
|
72
57
|
let legacyType = result.type;
|
|
73
58
|
if (legacyType === "allowlist") {
|
|
74
59
|
legacyType = "whitelist";
|
|
@@ -87,10 +72,11 @@ var PhishingDetector = class {
|
|
|
87
72
|
_configs = new WeakMap();
|
|
88
73
|
_legacyConfig = new WeakMap();
|
|
89
74
|
_check = new WeakSet();
|
|
90
|
-
check_fn = function(
|
|
75
|
+
check_fn = function(url) {
|
|
76
|
+
const domain = new URL(url).hostname;
|
|
91
77
|
const fqdn = domain.endsWith(".") ? domain.slice(0, -1) : domain;
|
|
92
78
|
const source = domainToParts(fqdn);
|
|
93
|
-
for (const { allowlist, name, version } of __privateGet(this, _configs)) {
|
|
79
|
+
for (const { allowlist, name, version } of _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _configs)) {
|
|
94
80
|
const allowlistMatch = matchPartsAgainstList(source, allowlist);
|
|
95
81
|
if (allowlistMatch) {
|
|
96
82
|
const match = domainPartsToDomain(allowlistMatch);
|
|
@@ -103,7 +89,7 @@ check_fn = function(domain) {
|
|
|
103
89
|
};
|
|
104
90
|
}
|
|
105
91
|
}
|
|
106
|
-
for (const { blocklist, fuzzylist, name, tolerance, version } of __privateGet(this, _configs)) {
|
|
92
|
+
for (const { blocklist, fuzzylist, name, tolerance, version } of _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _configs)) {
|
|
107
93
|
const blocklistMatch = matchPartsAgainstList(source, blocklist);
|
|
108
94
|
if (blocklistMatch) {
|
|
109
95
|
const match = domainPartsToDomain(blocklistMatch);
|
|
@@ -135,8 +121,30 @@ check_fn = function(domain) {
|
|
|
135
121
|
}
|
|
136
122
|
}
|
|
137
123
|
}
|
|
124
|
+
const ipfsCidMatch = url.match(ipfsCidRegex());
|
|
125
|
+
if (ipfsCidMatch !== null) {
|
|
126
|
+
const cID = ipfsCidMatch[0];
|
|
127
|
+
for (const { blocklist, name, version } of _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _configs)) {
|
|
128
|
+
const blocklistMatch = blocklist.filter((entries) => entries.length === 1).find((entries) => {
|
|
129
|
+
return entries[0] === cID;
|
|
130
|
+
});
|
|
131
|
+
if (blocklistMatch) {
|
|
132
|
+
return {
|
|
133
|
+
name,
|
|
134
|
+
match: cID,
|
|
135
|
+
result: true,
|
|
136
|
+
type: "blocklist",
|
|
137
|
+
version: version === void 0 ? version : String(version)
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
138
142
|
return { result: false, type: "all" };
|
|
139
143
|
};
|
|
144
|
+
function ipfsCidRegex() {
|
|
145
|
+
const reg = "Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,}";
|
|
146
|
+
return new RegExp(reg, "u");
|
|
147
|
+
}
|
|
140
148
|
|
|
141
149
|
// src/PhishingController.ts
|
|
142
150
|
var PHISHING_CONFIG_BASE_URL = "https://phishing-detection.api.cx.metamask.io";
|
|
@@ -209,39 +217,39 @@ var PhishingController = class extends _basecontroller.BaseController {
|
|
|
209
217
|
* Constructor helper for registering this controller's messaging system
|
|
210
218
|
* actions.
|
|
211
219
|
*/
|
|
212
|
-
__privateAdd(this, _registerMessageHandlers);
|
|
220
|
+
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _registerMessageHandlers);
|
|
213
221
|
/**
|
|
214
222
|
* Update the stalelist configuration.
|
|
215
223
|
*
|
|
216
224
|
* This should only be called from the `updateStalelist` function, which is a wrapper around
|
|
217
225
|
* this function that prevents redundant configuration updates.
|
|
218
226
|
*/
|
|
219
|
-
__privateAdd(this, _updateStalelist);
|
|
227
|
+
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _updateStalelist);
|
|
220
228
|
/**
|
|
221
229
|
* Update the stalelist configuration.
|
|
222
230
|
*
|
|
223
231
|
* This should only be called from the `updateStalelist` function, which is a wrapper around
|
|
224
232
|
* this function that prevents redundant configuration updates.
|
|
225
233
|
*/
|
|
226
|
-
__privateAdd(this, _updateHotlist);
|
|
227
|
-
__privateAdd(this, _queryConfig);
|
|
234
|
+
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _updateHotlist);
|
|
235
|
+
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _queryConfig);
|
|
228
236
|
// TODO: Replace `any` with type
|
|
229
237
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
230
|
-
__privateAdd(this, _detector, void 0);
|
|
231
|
-
__privateAdd(this, _stalelistRefreshInterval, void 0);
|
|
232
|
-
__privateAdd(this, _hotlistRefreshInterval, void 0);
|
|
233
|
-
__privateAdd(this, _inProgressHotlistUpdate, void 0);
|
|
234
|
-
__privateAdd(this, _inProgressStalelistUpdate, void 0);
|
|
235
|
-
__privateSet(this, _stalelistRefreshInterval, stalelistRefreshInterval);
|
|
236
|
-
__privateSet(this, _hotlistRefreshInterval, hotlistRefreshInterval);
|
|
237
|
-
__privateMethod(this, _registerMessageHandlers, registerMessageHandlers_fn).call(this);
|
|
238
|
+
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _detector, void 0);
|
|
239
|
+
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _stalelistRefreshInterval, void 0);
|
|
240
|
+
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _hotlistRefreshInterval, void 0);
|
|
241
|
+
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _inProgressHotlistUpdate, void 0);
|
|
242
|
+
_chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _inProgressStalelistUpdate, void 0);
|
|
243
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _stalelistRefreshInterval, stalelistRefreshInterval);
|
|
244
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _hotlistRefreshInterval, hotlistRefreshInterval);
|
|
245
|
+
_chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _registerMessageHandlers, registerMessageHandlers_fn).call(this);
|
|
238
246
|
this.updatePhishingDetector();
|
|
239
247
|
}
|
|
240
248
|
/**
|
|
241
249
|
* Updates this.detector with an instance of PhishingDetector using the current state.
|
|
242
250
|
*/
|
|
243
251
|
updatePhishingDetector() {
|
|
244
|
-
__privateSet(this, _detector, new PhishingDetector(this.state.phishingLists));
|
|
252
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _detector, new PhishingDetector(this.state.phishingLists));
|
|
245
253
|
}
|
|
246
254
|
/**
|
|
247
255
|
* Set the interval at which the stale phishing list will be refetched.
|
|
@@ -251,7 +259,7 @@ var PhishingController = class extends _basecontroller.BaseController {
|
|
|
251
259
|
* @param interval - the new interval, in ms.
|
|
252
260
|
*/
|
|
253
261
|
setStalelistRefreshInterval(interval) {
|
|
254
|
-
__privateSet(this, _stalelistRefreshInterval, interval);
|
|
262
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _stalelistRefreshInterval, interval);
|
|
255
263
|
}
|
|
256
264
|
/**
|
|
257
265
|
* Set the interval at which the hot list will be refetched.
|
|
@@ -261,7 +269,7 @@ var PhishingController = class extends _basecontroller.BaseController {
|
|
|
261
269
|
* @param interval - the new interval, in ms.
|
|
262
270
|
*/
|
|
263
271
|
setHotlistRefreshInterval(interval) {
|
|
264
|
-
__privateSet(this, _hotlistRefreshInterval, interval);
|
|
272
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _hotlistRefreshInterval, interval);
|
|
265
273
|
}
|
|
266
274
|
/**
|
|
267
275
|
* Determine if an update to the stalelist configuration is needed.
|
|
@@ -269,7 +277,7 @@ var PhishingController = class extends _basecontroller.BaseController {
|
|
|
269
277
|
* @returns Whether an update is needed
|
|
270
278
|
*/
|
|
271
279
|
isStalelistOutOfDate() {
|
|
272
|
-
return fetchTimeNow() - this.state.stalelistLastFetched >= __privateGet(this, _stalelistRefreshInterval);
|
|
280
|
+
return fetchTimeNow() - this.state.stalelistLastFetched >= _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _stalelistRefreshInterval);
|
|
273
281
|
}
|
|
274
282
|
/**
|
|
275
283
|
* Determine if an update to the hotlist configuration is needed.
|
|
@@ -277,7 +285,7 @@ var PhishingController = class extends _basecontroller.BaseController {
|
|
|
277
285
|
* @returns Whether an update is needed
|
|
278
286
|
*/
|
|
279
287
|
isHotlistOutOfDate() {
|
|
280
|
-
return fetchTimeNow() - this.state.hotlistLastFetched >= __privateGet(this, _hotlistRefreshInterval);
|
|
288
|
+
return fetchTimeNow() - this.state.hotlistLastFetched >= _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _hotlistRefreshInterval);
|
|
281
289
|
}
|
|
282
290
|
/**
|
|
283
291
|
* Conditionally update the phishing configuration.
|
|
@@ -313,7 +321,7 @@ var PhishingController = class extends _basecontroller.BaseController {
|
|
|
313
321
|
if (this.state.whitelist.includes(punycodeOrigin)) {
|
|
314
322
|
return { result: false, type: "all" };
|
|
315
323
|
}
|
|
316
|
-
return __privateGet(this, _detector).check(punycodeOrigin);
|
|
324
|
+
return _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _detector).check(punycodeOrigin);
|
|
317
325
|
}
|
|
318
326
|
/**
|
|
319
327
|
* Temporarily marks a given origin as approved.
|
|
@@ -337,15 +345,15 @@ var PhishingController = class extends _basecontroller.BaseController {
|
|
|
337
345
|
* the in-progress update has finished.
|
|
338
346
|
*/
|
|
339
347
|
async updateHotlist() {
|
|
340
|
-
if (__privateGet(this, _inProgressHotlistUpdate)) {
|
|
341
|
-
await __privateGet(this, _inProgressHotlistUpdate);
|
|
348
|
+
if (_chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _inProgressHotlistUpdate)) {
|
|
349
|
+
await _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _inProgressHotlistUpdate);
|
|
342
350
|
return;
|
|
343
351
|
}
|
|
344
352
|
try {
|
|
345
|
-
__privateSet(this, _inProgressHotlistUpdate, __privateMethod(this, _updateHotlist, updateHotlist_fn).call(this));
|
|
346
|
-
await __privateGet(this, _inProgressHotlistUpdate);
|
|
353
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _inProgressHotlistUpdate, _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _updateHotlist, updateHotlist_fn).call(this));
|
|
354
|
+
await _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _inProgressHotlistUpdate);
|
|
347
355
|
} finally {
|
|
348
|
-
__privateSet(this, _inProgressHotlistUpdate, void 0);
|
|
356
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _inProgressHotlistUpdate, void 0);
|
|
349
357
|
}
|
|
350
358
|
}
|
|
351
359
|
/**
|
|
@@ -355,15 +363,15 @@ var PhishingController = class extends _basecontroller.BaseController {
|
|
|
355
363
|
* the in-progress update has finished.
|
|
356
364
|
*/
|
|
357
365
|
async updateStalelist() {
|
|
358
|
-
if (__privateGet(this, _inProgressStalelistUpdate)) {
|
|
359
|
-
await __privateGet(this, _inProgressStalelistUpdate);
|
|
366
|
+
if (_chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _inProgressStalelistUpdate)) {
|
|
367
|
+
await _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _inProgressStalelistUpdate);
|
|
360
368
|
return;
|
|
361
369
|
}
|
|
362
370
|
try {
|
|
363
|
-
__privateSet(this, _inProgressStalelistUpdate, __privateMethod(this, _updateStalelist, updateStalelist_fn).call(this));
|
|
364
|
-
await __privateGet(this, _inProgressStalelistUpdate);
|
|
371
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _inProgressStalelistUpdate, _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _updateStalelist, updateStalelist_fn).call(this));
|
|
372
|
+
await _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _inProgressStalelistUpdate);
|
|
365
373
|
} finally {
|
|
366
|
-
__privateSet(this, _inProgressStalelistUpdate, void 0);
|
|
374
|
+
_chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _inProgressStalelistUpdate, void 0);
|
|
367
375
|
}
|
|
368
376
|
}
|
|
369
377
|
};
|
|
@@ -388,9 +396,9 @@ updateStalelist_fn = async function() {
|
|
|
388
396
|
let stalelistResponse;
|
|
389
397
|
let hotlistDiffsResponse;
|
|
390
398
|
try {
|
|
391
|
-
stalelistResponse = await __privateMethod(this, _queryConfig, queryConfig_fn).call(this, METAMASK_STALELIST_URL).then((d) => d);
|
|
399
|
+
stalelistResponse = await _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _queryConfig, queryConfig_fn).call(this, METAMASK_STALELIST_URL).then((d) => d);
|
|
392
400
|
if (stalelistResponse?.data && stalelistResponse.data.lastUpdated > 0) {
|
|
393
|
-
hotlistDiffsResponse = await __privateMethod(this, _queryConfig, queryConfig_fn).call(this, `${METAMASK_HOTLIST_DIFF_URL}/${stalelistResponse.data.lastUpdated}`);
|
|
401
|
+
hotlistDiffsResponse = await _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _queryConfig, queryConfig_fn).call(this, `${METAMASK_HOTLIST_DIFF_URL}/${stalelistResponse.data.lastUpdated}`);
|
|
394
402
|
}
|
|
395
403
|
} finally {
|
|
396
404
|
const timeNow = fetchTimeNow();
|
|
@@ -439,7 +447,7 @@ updateHotlist_fn = async function() {
|
|
|
439
447
|
);
|
|
440
448
|
let hotlistResponse;
|
|
441
449
|
try {
|
|
442
|
-
hotlistResponse = await __privateMethod(this, _queryConfig, queryConfig_fn).call(this, `${METAMASK_HOTLIST_DIFF_URL}/${lastDiffTimestamp}`);
|
|
450
|
+
hotlistResponse = await _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _queryConfig, queryConfig_fn).call(this, `${METAMASK_HOTLIST_DIFF_URL}/${lastDiffTimestamp}`);
|
|
443
451
|
} finally {
|
|
444
452
|
this.update((draftState) => {
|
|
445
453
|
draftState.hotlistLastFetched = fetchTimeNow();
|
|
@@ -600,4 +608,4 @@ var matchPartsAgainstList = (source, list) => {
|
|
|
600
608
|
|
|
601
609
|
|
|
602
610
|
exports.fetchTimeNow = fetchTimeNow; exports.applyDiffs = applyDiffs; exports.validateConfig = validateConfig; exports.domainToParts = domainToParts; exports.processDomainList = processDomainList; exports.getDefaultPhishingDetectorConfig = getDefaultPhishingDetectorConfig; exports.processConfigs = processConfigs; exports.domainPartsToDomain = domainPartsToDomain; exports.domainPartsToFuzzyForm = domainPartsToFuzzyForm; exports.matchPartsAgainstList = matchPartsAgainstList; exports.PhishingDetector = PhishingDetector; exports.PHISHING_CONFIG_BASE_URL = PHISHING_CONFIG_BASE_URL; exports.METAMASK_STALELIST_FILE = METAMASK_STALELIST_FILE; exports.METAMASK_HOTLIST_DIFF_FILE = METAMASK_HOTLIST_DIFF_FILE; exports.HOTLIST_REFRESH_INTERVAL = HOTLIST_REFRESH_INTERVAL; exports.STALELIST_REFRESH_INTERVAL = STALELIST_REFRESH_INTERVAL; exports.METAMASK_STALELIST_URL = METAMASK_STALELIST_URL; exports.METAMASK_HOTLIST_DIFF_URL = METAMASK_HOTLIST_DIFF_URL; exports.ListKeys = ListKeys; exports.ListNames = ListNames; exports.phishingListKeyNameMap = phishingListKeyNameMap; exports.PhishingController = PhishingController; exports.PhishingController_default = PhishingController_default;
|
|
603
|
-
//# sourceMappingURL=chunk-
|
|
611
|
+
//# sourceMappingURL=chunk-SJIYZL3T.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/PhishingController.ts","../src/PhishingDetector.ts","../src/utils.ts"],"names":["ListKeys","ListNames"],"mappings":"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","sourcesContent":["import type { RestrictedControllerMessenger } from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { safelyExecute } from '@metamask/controller-utils';\nimport { toASCII } from 'punycode/';\n\nimport { PhishingDetector } from './PhishingDetector';\nimport { applyDiffs, fetchTimeNow } from './utils';\n\nexport const PHISHING_CONFIG_BASE_URL =\n 'https://phishing-detection.api.cx.metamask.io';\n\nexport const METAMASK_STALELIST_FILE = '/v1/stalelist';\n\nexport const METAMASK_HOTLIST_DIFF_FILE = '/v1/diffsSince';\n\nexport const HOTLIST_REFRESH_INTERVAL = 5 * 60; // 5 mins in seconds\nexport const STALELIST_REFRESH_INTERVAL = 30 * 24 * 60 * 60; // 30 days in seconds\n\nexport const METAMASK_STALELIST_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_STALELIST_FILE}`;\nexport const METAMASK_HOTLIST_DIFF_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_HOTLIST_DIFF_FILE}`;\n\n/**\n * @type ListTypes\n *\n * Type outlining the types of lists provided by aggregating different source lists\n */\nexport type ListTypes = 'fuzzylist' | 'blocklist' | 'allowlist';\n\n/**\n * @type EthPhishingResponse\n *\n * Configuration response from the eth-phishing-detect package\n * consisting of approved and unapproved website origins\n * @property blacklist - List of unapproved origins\n * @property fuzzylist - List of fuzzy-matched unapproved origins\n * @property tolerance - Fuzzy match tolerance level\n * @property version - Version number of this configuration\n * @property whitelist - List of approved origins\n */\nexport type EthPhishingResponse = {\n blacklist: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n whitelist: string[];\n};\n\n/**\n * @type PhishingStalelist\n *\n * type defining expected type of the stalelist.json file.\n * @property eth_phishing_detect_config - Stale list sourced from eth-phishing-detect's config.json.\n * @property phishfort_hotlist - Stale list sourced from phishfort's hotlist.json. Only includes blocklist. Deduplicated entries from eth_phishing_detect_config.\n * @property tolerance - Fuzzy match tolerance level\n * @property lastUpdated - Timestamp of last update.\n * @property version - Stalelist data structure iteration.\n */\nexport type PhishingStalelist = {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n eth_phishing_detect_config: Record<ListTypes, string[]>;\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n phishfort_hotlist: Record<ListTypes, string[]>;\n tolerance: number;\n version: number;\n lastUpdated: number;\n};\n\n/**\n * @type PhishingListState\n *\n * type defining the persisted list state. This is the persisted state that is updated frequently with `this.maybeUpdateState()`.\n * @property allowlist - List of approved origins (legacy naming \"whitelist\")\n * @property blocklist - List of unapproved origins (legacy naming \"blacklist\")\n * @property fuzzylist - List of fuzzy-matched unapproved origins\n * @property tolerance - Fuzzy match tolerance level\n * @property lastUpdated - Timestamp of last update.\n * @property version - Version of the phishing list state.\n * @property name - Name of the list. Used for attribution.\n */\nexport type PhishingListState = {\n allowlist: string[];\n blocklist: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n lastUpdated: number;\n name: ListNames;\n};\n\n/**\n * @type EthPhishingDetectResult\n *\n * type that describes the result of the `test` method.\n * @property name - Name of the config on which a match was found.\n * @property version - Version of the config on which a match was found.\n * @property result - Whether a domain was detected as a phishing domain. True means an unsafe domain.\n * @property match - The matching fuzzylist origin when a fuzzylist match is found. Returned as undefined for non-fuzzy true results.\n * @property type - The field of the config on which a match was found.\n */\nexport type EthPhishingDetectResult = {\n name?: string;\n version?: string;\n result: boolean;\n match?: string; // Returned as undefined for non-fuzzy true results.\n type: 'all' | 'fuzzy' | 'blocklist' | 'allowlist';\n};\n\n/**\n * @type HotlistDiff\n *\n * type defining the expected type of the diffs in hotlist.json file.\n * @property url - Url of the diff entry.\n * @property timestamp - Timestamp at which the diff was identified.\n * @property targetList - The list name where the diff was identified.\n * @property isRemoval - Was the diff identified a removal type.\n */\nexport type HotlistDiff = {\n url: string;\n timestamp: number;\n targetList: `${ListKeys}.${ListTypes}`;\n isRemoval?: boolean;\n};\n\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type DataResultWrapper<T> = {\n data: T;\n};\n\n/**\n * @type Hotlist\n *\n * Type defining expected hotlist.json file.\n * @property url - Url of the diff entry.\n * @property timestamp - Timestamp at which the diff was identified.\n * @property targetList - The list name where the diff was identified.\n * @property isRemoval - Was the diff identified a removal type.\n */\nexport type Hotlist = HotlistDiff[];\n\n/**\n * Enum containing upstream data provider source list keys.\n * These are the keys denoting lists consumed by the upstream data provider.\n */\nexport enum ListKeys {\n PhishfortHotlist = 'phishfort_hotlist',\n EthPhishingDetectConfig = 'eth_phishing_detect_config',\n}\n\n/**\n * Enum containing downstream client attribution names.\n */\nexport enum ListNames {\n MetaMask = 'MetaMask',\n Phishfort = 'Phishfort',\n}\n\n/**\n * Maps from downstream client attribution name\n * to list key sourced from upstream data provider.\n */\nconst phishingListNameKeyMap = {\n [ListNames.Phishfort]: ListKeys.PhishfortHotlist,\n [ListNames.MetaMask]: ListKeys.EthPhishingDetectConfig,\n};\n\n/**\n * Maps from list key sourced from upstream data\n * provider to downstream client attribution name.\n */\nexport const phishingListKeyNameMap = {\n [ListKeys.EthPhishingDetectConfig]: ListNames.MetaMask,\n [ListKeys.PhishfortHotlist]: ListNames.Phishfort,\n};\n\nconst controllerName = 'PhishingController';\n\nconst metadata = {\n phishingLists: { persist: true, anonymous: false },\n whitelist: { persist: true, anonymous: false },\n hotlistLastFetched: { persist: true, anonymous: false },\n stalelistLastFetched: { persist: true, anonymous: false },\n};\n\n/**\n * Get a default empty state for the controller.\n * @returns The default empty state.\n */\nconst getDefaultState = (): PhishingControllerState => {\n return {\n phishingLists: [],\n whitelist: [],\n hotlistLastFetched: 0,\n stalelistLastFetched: 0,\n };\n};\n\n/**\n * @type PhishingControllerState\n *\n * Phishing controller state\n * @property phishing - eth-phishing-detect configuration\n * @property whitelist - array of temporarily-approved origins\n */\nexport type PhishingControllerState = {\n phishingLists: PhishingListState[];\n whitelist: string[];\n hotlistLastFetched: number;\n stalelistLastFetched: number;\n};\n\n/**\n * @type PhishingControllerOptions\n *\n * Phishing controller options\n * @property stalelistRefreshInterval - Polling interval used to fetch stale list.\n * @property hotlistRefreshInterval - Polling interval used to fetch hotlist diff list.\n */\nexport type PhishingControllerOptions = {\n stalelistRefreshInterval?: number;\n hotlistRefreshInterval?: number;\n messenger: PhishingControllerMessenger;\n state?: Partial<PhishingControllerState>;\n};\n\nexport type MaybeUpdateState = {\n type: `${typeof controllerName}:maybeUpdateState`;\n handler: PhishingController['maybeUpdateState'];\n};\n\nexport type TestOrigin = {\n type: `${typeof controllerName}:testOrigin`;\n handler: PhishingController['test'];\n};\n\nexport type PhishingControllerActions = MaybeUpdateState | TestOrigin;\n\nexport type PhishingControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n PhishingControllerActions,\n never,\n never,\n never\n>;\n\n/**\n * Controller that manages community-maintained lists of approved and unapproved website origins.\n */\nexport class PhishingController extends BaseController<\n typeof controllerName,\n PhishingControllerState,\n PhishingControllerMessenger\n> {\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n #detector: any;\n\n #stalelistRefreshInterval: number;\n\n #hotlistRefreshInterval: number;\n\n #inProgressHotlistUpdate?: Promise<void>;\n\n #inProgressStalelistUpdate?: Promise<void>;\n\n /**\n * Construct a Phishing Controller.\n *\n * @param config - Initial options used to configure this controller.\n * @param config.stalelistRefreshInterval - Polling interval used to fetch stale list.\n * @param config.hotlistRefreshInterval - Polling interval used to fetch hotlist diff list.\n * @param config.messenger - The controller restricted messenger.\n * @param config.state - Initial state to set on this controller.\n */\n constructor({\n stalelistRefreshInterval = STALELIST_REFRESH_INTERVAL,\n hotlistRefreshInterval = HOTLIST_REFRESH_INTERVAL,\n messenger,\n state = {},\n }: PhishingControllerOptions) {\n super({\n name: controllerName,\n metadata,\n messenger,\n state: {\n ...getDefaultState(),\n ...state,\n },\n });\n\n this.#stalelistRefreshInterval = stalelistRefreshInterval;\n this.#hotlistRefreshInterval = hotlistRefreshInterval;\n this.#registerMessageHandlers();\n\n this.updatePhishingDetector();\n }\n\n /**\n * Constructor helper for registering this controller's messaging system\n * actions.\n */\n #registerMessageHandlers(): void {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:maybeUpdateState` as const,\n this.maybeUpdateState.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:testOrigin` as const,\n this.test.bind(this),\n );\n }\n\n /**\n * Updates this.detector with an instance of PhishingDetector using the current state.\n */\n updatePhishingDetector() {\n this.#detector = new PhishingDetector(this.state.phishingLists);\n }\n\n /**\n * Set the interval at which the stale phishing list will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateStalelist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setStalelistRefreshInterval(interval: number) {\n this.#stalelistRefreshInterval = interval;\n }\n\n /**\n * Set the interval at which the hot list will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateHotlist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setHotlistRefreshInterval(interval: number) {\n this.#hotlistRefreshInterval = interval;\n }\n\n /**\n * Determine if an update to the stalelist configuration is needed.\n *\n * @returns Whether an update is needed\n */\n isStalelistOutOfDate() {\n return (\n fetchTimeNow() - this.state.stalelistLastFetched >=\n this.#stalelistRefreshInterval\n );\n }\n\n /**\n * Determine if an update to the hotlist configuration is needed.\n *\n * @returns Whether an update is needed\n */\n isHotlistOutOfDate() {\n return (\n fetchTimeNow() - this.state.hotlistLastFetched >=\n this.#hotlistRefreshInterval\n );\n }\n\n /**\n * Conditionally update the phishing configuration.\n *\n * If the stalelist configuration is out of date, this function will call `updateStalelist`\n * to update the configuration. This will automatically grab the hotlist,\n * so it isn't necessary to continue on to download the hotlist.\n *\n */\n async maybeUpdateState() {\n const staleListOutOfDate = this.isStalelistOutOfDate();\n if (staleListOutOfDate) {\n await this.updateStalelist();\n return;\n }\n const hotlistOutOfDate = this.isHotlistOutOfDate();\n if (hotlistOutOfDate) {\n await this.updateHotlist();\n }\n }\n\n /**\n * Determines if a given origin is unapproved.\n *\n * It is strongly recommended that you call {@link maybeUpdateState} before calling this,\n * to check whether the phishing configuration is up-to-date. It will be updated if necessary\n * by calling {@link updateStalelist} or {@link updateHotlist}.\n *\n * @param origin - Domain origin of a website.\n * @returns Whether the origin is an unapproved origin.\n */\n test(origin: string): EthPhishingDetectResult {\n const punycodeOrigin = toASCII(origin);\n if (this.state.whitelist.includes(punycodeOrigin)) {\n return { result: false, type: 'all' }; // Same as whitelisted match returned by detector.check(...).\n }\n return this.#detector.check(punycodeOrigin);\n }\n\n /**\n * Temporarily marks a given origin as approved.\n *\n * @param origin - The origin to mark as approved.\n */\n bypass(origin: string) {\n const punycodeOrigin = toASCII(origin);\n const { whitelist } = this.state;\n if (whitelist.includes(punycodeOrigin)) {\n return;\n }\n this.update((draftState) => {\n draftState.whitelist.push(punycodeOrigin);\n });\n }\n\n /**\n * Update the hotlist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateHotlist() {\n if (this.#inProgressHotlistUpdate) {\n await this.#inProgressHotlistUpdate;\n return;\n }\n\n try {\n this.#inProgressHotlistUpdate = this.#updateHotlist();\n await this.#inProgressHotlistUpdate;\n } finally {\n this.#inProgressHotlistUpdate = undefined;\n }\n }\n\n /**\n * Update the stalelist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateStalelist() {\n if (this.#inProgressStalelistUpdate) {\n await this.#inProgressStalelistUpdate;\n return;\n }\n\n try {\n this.#inProgressStalelistUpdate = this.#updateStalelist();\n await this.#inProgressStalelistUpdate;\n } finally {\n this.#inProgressStalelistUpdate = undefined;\n }\n }\n\n /**\n * Update the stalelist configuration.\n *\n * This should only be called from the `updateStalelist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateStalelist() {\n let stalelistResponse;\n let hotlistDiffsResponse;\n try {\n stalelistResponse = await this.#queryConfig<\n DataResultWrapper<PhishingStalelist>\n >(METAMASK_STALELIST_URL).then((d) => d);\n\n // Fetching hotlist diffs relies on having a lastUpdated timestamp to do `GET /v1/diffsSince/:timestamp`,\n // so it doesn't make sense to call if there is not a timestamp to begin with.\n if (stalelistResponse?.data && stalelistResponse.data.lastUpdated > 0) {\n hotlistDiffsResponse = await this.#queryConfig<\n DataResultWrapper<Hotlist>\n >(`${METAMASK_HOTLIST_DIFF_URL}/${stalelistResponse.data.lastUpdated}`);\n }\n } finally {\n // Set `stalelistLastFetched` and `hotlistLastFetched` even for failed requests to prevent server\n // from being overwhelmed with traffic after a network disruption.\n const timeNow = fetchTimeNow();\n this.update((draftState) => {\n draftState.stalelistLastFetched = timeNow;\n draftState.hotlistLastFetched = timeNow;\n });\n }\n\n if (!stalelistResponse || !hotlistDiffsResponse) {\n return;\n }\n\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n const { phishfort_hotlist, eth_phishing_detect_config, ...partialState } =\n stalelistResponse.data;\n\n const phishfortListState: PhishingListState = {\n ...phishfort_hotlist,\n ...partialState,\n fuzzylist: [], // Phishfort hotlist doesn't contain a fuzzylist\n allowlist: [], // Phishfort hotlist doesn't contain an allowlist\n name: phishingListKeyNameMap.phishfort_hotlist,\n };\n const metamaskListState: PhishingListState = {\n ...eth_phishing_detect_config,\n ...partialState,\n name: phishingListKeyNameMap.eth_phishing_detect_config,\n };\n // Correctly shaping eth-phishing-detect state by applying hotlist diffs to the stalelist.\n const newPhishfortListState: PhishingListState = applyDiffs(\n phishfortListState,\n hotlistDiffsResponse.data,\n ListKeys.PhishfortHotlist,\n );\n const newMetaMaskListState: PhishingListState = applyDiffs(\n metamaskListState,\n hotlistDiffsResponse.data,\n ListKeys.EthPhishingDetectConfig,\n );\n\n this.update((draftState) => {\n draftState.phishingLists = [newMetaMaskListState, newPhishfortListState];\n });\n this.updatePhishingDetector();\n }\n\n /**\n * Update the stalelist configuration.\n *\n * This should only be called from the `updateStalelist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateHotlist() {\n const lastDiffTimestamp = Math.max(\n ...this.state.phishingLists.map(({ lastUpdated }) => lastUpdated),\n );\n let hotlistResponse: DataResultWrapper<Hotlist> | null;\n\n try {\n hotlistResponse = await this.#queryConfig<DataResultWrapper<Hotlist>>(\n `${METAMASK_HOTLIST_DIFF_URL}/${lastDiffTimestamp}`,\n );\n } finally {\n // Set `hotlistLastFetched` even for failed requests to prevent server from being overwhelmed with\n // traffic after a network disruption.\n this.update((draftState) => {\n draftState.hotlistLastFetched = fetchTimeNow();\n });\n }\n\n if (!hotlistResponse?.data) {\n return;\n }\n const hotlist = hotlistResponse.data;\n const newPhishingLists = this.state.phishingLists.map((phishingList) =>\n applyDiffs(\n phishingList,\n hotlist,\n phishingListNameKeyMap[phishingList.name],\n ),\n );\n\n this.update((draftState) => {\n draftState.phishingLists = newPhishingLists;\n });\n this.updatePhishingDetector();\n }\n\n async #queryConfig<ResponseType>(\n input: RequestInfo,\n ): Promise<ResponseType | null> {\n const response = await safelyExecute(\n () => fetch(input, { cache: 'no-cache' }),\n true,\n );\n\n switch (response?.status) {\n case 200: {\n return await response.json();\n }\n\n default: {\n return null;\n }\n }\n }\n}\n\nexport default PhishingController;\n","import { distance } from 'fastest-levenshtein';\n\nimport {\n domainPartsToDomain,\n domainPartsToFuzzyForm,\n domainToParts,\n getDefaultPhishingDetectorConfig,\n matchPartsAgainstList,\n processConfigs,\n} from './utils';\n\nexport type LegacyPhishingDetectorList = {\n whitelist?: string[];\n blacklist?: string[];\n} & FuzzyTolerance;\n\nexport type PhishingDetectorList = {\n allowlist?: string[];\n blocklist?: string[];\n name?: string;\n version?: string | number;\n} & FuzzyTolerance;\n\nexport type FuzzyTolerance =\n | {\n tolerance?: number;\n fuzzylist: string[];\n }\n | {\n tolerance?: never;\n fuzzylist?: never;\n };\n\nexport type PhishingDetectorOptions =\n | LegacyPhishingDetectorList\n | PhishingDetectorList[];\n\nexport type PhishingDetectorConfiguration = {\n name?: string;\n version?: number | string;\n allowlist: string[][];\n blocklist: string[][];\n fuzzylist: string[][];\n tolerance: number;\n};\n\n/**\n * Represents the result of checking a domain.\n */\nexport type PhishingDetectorResult = {\n /**\n * The name of the configuration object in which the domain was found within\n * an allowlist, blocklist, or fuzzylist.\n */\n name?: string;\n /**\n * The version associated with the configuration object in which the domain\n * was found within an allowlist, blocklist, or fuzzylist.\n */\n version?: string;\n /**\n * Whether the domain is regarded as allowed (true) or not (false).\n */\n result: boolean;\n /**\n * A normalized version of the domain, which is only constructed if the domain\n * is found within a list.\n */\n match?: string;\n /**\n * Which type of list in which the domain was found.\n *\n * - \"allowlist\" means that the domain was found in the allowlist.\n * - \"blocklist\" means that the domain was found in the blocklist.\n * - \"fuzzy\" means that the domain was found in the fuzzylist.\n * - \"blacklist\" means that the domain was found in a blacklist of a legacy\n * configuration object.\n * - \"whitelist\" means that the domain was found in a whitelist of a legacy\n * configuration object.\n * - \"all\" means that the domain was not found in any list.\n */\n type: 'all' | 'fuzzy' | 'blocklist' | 'allowlist' | 'blacklist' | 'whitelist';\n};\n\nexport class PhishingDetector {\n #configs: PhishingDetectorConfiguration[];\n\n #legacyConfig: boolean;\n\n /**\n * Construct a phishing detector, which can check whether origins are known\n * to be malicious or similar to common phishing targets.\n *\n * A list of configurations is accepted. Each origin checked is processed\n * using each configuration in sequence, so the order defines which\n * configurations take precedence.\n *\n * @param opts - Phishing detection options\n */\n constructor(opts: PhishingDetectorOptions) {\n // recommended configuration\n if (Array.isArray(opts)) {\n this.#configs = processConfigs(opts);\n this.#legacyConfig = false;\n // legacy configuration\n } else {\n this.#configs = [\n getDefaultPhishingDetectorConfig({\n allowlist: opts.whitelist,\n blocklist: opts.blacklist,\n fuzzylist: opts.fuzzylist,\n tolerance: opts.tolerance,\n }),\n ];\n this.#legacyConfig = true;\n }\n }\n\n /**\n * Check if a url is known to be malicious or similar to a common phishing\n * target. This will check the hostname and IPFS CID that is sometimes\n * located in the path.\n *\n * @param url - The url to check.\n * @returns The result of the check.\n */\n check(url: string): PhishingDetectorResult {\n const result = this.#check(url);\n\n if (this.#legacyConfig) {\n let legacyType = result.type;\n if (legacyType === 'allowlist') {\n legacyType = 'whitelist';\n } else if (legacyType === 'blocklist') {\n legacyType = 'blacklist';\n }\n return {\n match: result.match,\n result: result.result,\n type: legacyType,\n };\n }\n return result;\n }\n\n #check(url: string): PhishingDetectorResult {\n const domain = new URL(url).hostname;\n\n const fqdn = domain.endsWith('.') ? domain.slice(0, -1) : domain;\n\n const source = domainToParts(fqdn);\n\n for (const { allowlist, name, version } of this.#configs) {\n // if source matches allowlist hostname (or subdomain thereof), PASS\n const allowlistMatch = matchPartsAgainstList(source, allowlist);\n if (allowlistMatch) {\n const match = domainPartsToDomain(allowlistMatch);\n return {\n match,\n name,\n result: false,\n type: 'allowlist',\n version: version === undefined ? version : String(version),\n };\n }\n }\n\n for (const { blocklist, fuzzylist, name, tolerance, version } of this\n .#configs) {\n // if source matches blocklist hostname (or subdomain thereof), FAIL\n const blocklistMatch = matchPartsAgainstList(source, blocklist);\n if (blocklistMatch) {\n const match = domainPartsToDomain(blocklistMatch);\n return {\n match,\n name,\n result: true,\n type: 'blocklist',\n version: version === undefined ? version : String(version),\n };\n }\n\n if (tolerance > 0) {\n // check if near-match of whitelist domain, FAIL\n let fuzzyForm = domainPartsToFuzzyForm(source);\n // strip www\n fuzzyForm = fuzzyForm.replace(/^www\\./u, '');\n // check against fuzzylist\n const levenshteinMatched = fuzzylist.find((targetParts) => {\n const fuzzyTarget = domainPartsToFuzzyForm(targetParts);\n const dist = distance(fuzzyForm, fuzzyTarget);\n return dist <= tolerance;\n });\n if (levenshteinMatched) {\n const match = domainPartsToDomain(levenshteinMatched);\n return {\n name,\n match,\n result: true,\n type: 'fuzzy',\n version: version === undefined ? version : String(version),\n };\n }\n }\n }\n\n const ipfsCidMatch = url.match(ipfsCidRegex());\n\n // Check for IPFS CID related blocklist entries\n if (ipfsCidMatch !== null) {\n // there is a cID string somewhere\n // Determine if any of the entries are ipfs cids\n // Depending on the gateway, the CID is in the path OR a subdomain, so we do a regex match on it all\n const cID = ipfsCidMatch[0];\n for (const { blocklist, name, version } of this.#configs) {\n const blocklistMatch = blocklist\n .filter((entries) => entries.length === 1)\n .find((entries) => {\n return entries[0] === cID;\n });\n if (blocklistMatch) {\n return {\n name,\n match: cID,\n result: true,\n type: 'blocklist',\n version: version === undefined ? version : String(version),\n };\n }\n }\n }\n\n // matched nothing, PASS\n return { result: false, type: 'all' };\n }\n}\n\n/**\n * Runs a regex match to determine if a string is a IPFS CID\n * @returns Regex string for IPFS CID\n */\nfunction ipfsCidRegex() {\n // regex from https://stackoverflow.com/a/67176726\n const reg =\n 'Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,}';\n return new RegExp(reg, 'u');\n}\n","import type {\n Hotlist,\n ListKeys,\n PhishingListState,\n} from './PhishingController';\nimport { phishingListKeyNameMap } from './PhishingController';\nimport type {\n PhishingDetectorList,\n PhishingDetectorConfiguration,\n} from './PhishingDetector';\n\nconst DEFAULT_TOLERANCE = 3;\n\n/**\n * Fetches current epoch time in seconds.\n *\n * @returns the Date.now() time in seconds instead of miliseconds. backend files rely on timestamps in seconds since epoch.\n */\nexport const fetchTimeNow = (): number => Math.round(Date.now() / 1000);\n\n/**\n * Split a string into two pieces, using the first period as the delimiter.\n *\n * @param stringToSplit - The string to split.\n * @returns An array of length two containing the beginning and end of the string.\n */\nconst splitStringByPeriod = <Start extends string, End extends string>(\n stringToSplit: `${Start}.${End}`,\n): [Start, End] => {\n const periodIndex = stringToSplit.indexOf('.');\n return [\n stringToSplit.slice(0, periodIndex) as Start,\n stringToSplit.slice(periodIndex + 1) as End,\n ];\n};\n\n/**\n * Determines which diffs are applicable to the listState, then applies those diffs.\n *\n * @param listState - the stalelist or the existing liststate that diffs will be applied to.\n * @param hotlistDiffs - the diffs to apply to the listState if valid.\n * @param listKey - the key associated with the input/output phishing list state.\n * @returns the new list state\n */\nexport const applyDiffs = (\n listState: PhishingListState,\n hotlistDiffs: Hotlist,\n listKey: ListKeys,\n): PhishingListState => {\n // filter to remove diffs that were added before the lastUpdate time.\n // filter to remove diffs that aren't applicable to the specified list (by listKey).\n const diffsToApply = hotlistDiffs.filter(\n ({ timestamp, targetList }) =>\n timestamp > listState.lastUpdated &&\n splitStringByPeriod(targetList)[0] === listKey,\n );\n\n // the reason behind using latestDiffTimestamp as the lastUpdated time\n // is so that we can benefit server-side from memoization due to end client's\n // `GET /v1/diffSince/:timestamp` requests lining up with\n // our periodic updates (which create diffs at specific timestamps).\n let latestDiffTimestamp = listState.lastUpdated;\n\n const listSets = {\n allowlist: new Set(listState.allowlist),\n blocklist: new Set(listState.blocklist),\n fuzzylist: new Set(listState.fuzzylist),\n };\n for (const { isRemoval, targetList, url, timestamp } of diffsToApply) {\n const targetListType = splitStringByPeriod(targetList)[1];\n if (timestamp > latestDiffTimestamp) {\n latestDiffTimestamp = timestamp;\n }\n if (isRemoval) {\n listSets[targetListType].delete(url);\n } else {\n listSets[targetListType].add(url);\n }\n }\n\n return {\n allowlist: Array.from(listSets.allowlist),\n blocklist: Array.from(listSets.blocklist),\n fuzzylist: Array.from(listSets.fuzzylist),\n version: listState.version,\n name: phishingListKeyNameMap[listKey],\n tolerance: listState.tolerance,\n lastUpdated: latestDiffTimestamp,\n };\n};\n\n/**\n * Validates the configuration object for the phishing detector.\n *\n * @param config - the configuration object to validate.\n * @throws an error if the configuration is invalid.\n */\nexport function validateConfig(\n config: unknown,\n): asserts config is PhishingListState {\n if (config === null || typeof config !== 'object') {\n throw new Error('Invalid config');\n }\n\n if ('tolerance' in config && !('fuzzylist' in config)) {\n throw new Error('Fuzzylist tolerance provided without fuzzylist');\n }\n\n if (\n 'name' in config &&\n (typeof config.name !== 'string' || config.name === '')\n ) {\n throw new Error(\"Invalid config parameter: 'name'\");\n }\n\n if (\n 'version' in config &&\n (!['number', 'string'].includes(typeof config.version) ||\n config.version === '')\n ) {\n throw new Error(\"Invalid config parameter: 'version'\");\n }\n}\n\n/**\n * Converts a domain string to a list of domain parts.\n *\n * @param domain - the domain string to convert.\n * @returns the list of domain parts.\n */\nexport const domainToParts = (domain: string) => {\n try {\n return domain.split('.').reverse();\n } catch (e) {\n throw new Error(JSON.stringify(domain));\n }\n};\n\n/**\n * Converts a list of domain strings to a list of domain parts.\n *\n * @param list - the list of domain strings to convert.\n * @returns the list of domain parts.\n */\nexport const processDomainList = (list: string[]) => {\n return list.map(domainToParts);\n};\n\n/**\n * Gets the default phishing detector configuration.\n *\n * @param override - the optional override for the configuration.\n * @param override.allowlist - the optional allowlist to override.\n * @param override.blocklist - the optional blocklist to override.\n * @param override.fuzzylist - the optional fuzzylist to override.\n * @param override.tolerance - the optional tolerance to override.\n * @returns the default phishing detector configuration.\n */\nexport const getDefaultPhishingDetectorConfig = ({\n allowlist = [],\n blocklist = [],\n fuzzylist = [],\n tolerance = DEFAULT_TOLERANCE,\n}: {\n allowlist?: string[];\n blocklist?: string[];\n fuzzylist?: string[];\n tolerance?: number;\n}): PhishingDetectorConfiguration => ({\n allowlist: processDomainList(allowlist),\n blocklist: processDomainList(blocklist),\n fuzzylist: processDomainList(fuzzylist),\n tolerance,\n});\n\n/**\n * Processes the configurations for the phishing detector.\n *\n * @param configs - the configurations to process.\n * @returns the processed configurations.\n */\nexport const processConfigs = (configs: PhishingDetectorList[] = []) => {\n return configs.map((config: PhishingDetectorList) => {\n validateConfig(config);\n return { ...config, ...getDefaultPhishingDetectorConfig(config) };\n });\n};\n\n/**\n * Converts a list of domain parts to a domain string.\n *\n * @param domainParts - the list of domain parts.\n * @returns the domain string.\n */\nexport const domainPartsToDomain = (domainParts: string[]) => {\n return domainParts.slice().reverse().join('.');\n};\n\n/**\n * Converts a list of domain parts to a fuzzy form.\n *\n * @param domainParts - the list of domain parts.\n * @returns the fuzzy form of the domain.\n */\nexport const domainPartsToFuzzyForm = (domainParts: string[]) => {\n return domainParts.slice(1).reverse().join('.');\n};\n\n/**\n * Matches the target parts, ignoring extra subdomains on source.\n *\n * @param source - the source domain parts.\n * @param list - the list of domain parts to match against.\n * @returns the parts for the first found matching entry.\n */\nexport const matchPartsAgainstList = (source: string[], list: string[][]) => {\n return list.find((target) => {\n // target domain has more parts than source, fail\n if (target.length > source.length) {\n return false;\n }\n // source matches target or (is deeper subdomain)\n return target.every((part, index) => source[index] === part);\n });\n};\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
var __accessCheck = (obj, member, msg) => {
|
|
2
|
+
if (!member.has(obj))
|
|
3
|
+
throw TypeError("Cannot " + msg);
|
|
4
|
+
};
|
|
5
|
+
var __privateGet = (obj, member, getter) => {
|
|
6
|
+
__accessCheck(obj, member, "read from private field");
|
|
7
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
8
|
+
};
|
|
9
|
+
var __privateAdd = (obj, member, value) => {
|
|
10
|
+
if (member.has(obj))
|
|
11
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
12
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
13
|
+
};
|
|
14
|
+
var __privateSet = (obj, member, value, setter) => {
|
|
15
|
+
__accessCheck(obj, member, "write to private field");
|
|
16
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
17
|
+
return value;
|
|
18
|
+
};
|
|
19
|
+
var __privateMethod = (obj, member, method) => {
|
|
20
|
+
__accessCheck(obj, member, "access private method");
|
|
21
|
+
return method;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
__privateGet,
|
|
26
|
+
__privateAdd,
|
|
27
|
+
__privateSet,
|
|
28
|
+
__privateMethod
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=chunk-XUI43LEZ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var __accessCheck = (obj, member, msg) => {
|
|
2
|
+
if (!member.has(obj))
|
|
3
|
+
throw TypeError("Cannot " + msg);
|
|
4
|
+
};
|
|
5
|
+
var __privateGet = (obj, member, getter) => {
|
|
6
|
+
__accessCheck(obj, member, "read from private field");
|
|
7
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
8
|
+
};
|
|
9
|
+
var __privateAdd = (obj, member, value) => {
|
|
10
|
+
if (member.has(obj))
|
|
11
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
12
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
13
|
+
};
|
|
14
|
+
var __privateSet = (obj, member, value, setter) => {
|
|
15
|
+
__accessCheck(obj, member, "write to private field");
|
|
16
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
17
|
+
return value;
|
|
18
|
+
};
|
|
19
|
+
var __privateMethod = (obj, member, method) => {
|
|
20
|
+
__accessCheck(obj, member, "access private method");
|
|
21
|
+
return method;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
exports.__privateGet = __privateGet; exports.__privateAdd = __privateAdd; exports.__privateSet = __privateSet; exports.__privateMethod = __privateMethod;
|
|
30
|
+
//# sourceMappingURL=chunk-Z4BLTVTB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":""}
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
var
|
|
13
|
+
var _chunkSJIYZL3Tjs = require('./chunk-SJIYZL3T.js');
|
|
14
|
+
require('./chunk-Z4BLTVTB.js');
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
|
|
@@ -23,5 +24,5 @@ var _chunkBU22EICTjs = require('./chunk-BU22EICT.js');
|
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
exports.HOTLIST_REFRESH_INTERVAL =
|
|
27
|
+
exports.HOTLIST_REFRESH_INTERVAL = _chunkSJIYZL3Tjs.HOTLIST_REFRESH_INTERVAL; exports.ListKeys = _chunkSJIYZL3Tjs.ListKeys; exports.ListNames = _chunkSJIYZL3Tjs.ListNames; exports.METAMASK_HOTLIST_DIFF_FILE = _chunkSJIYZL3Tjs.METAMASK_HOTLIST_DIFF_FILE; exports.METAMASK_HOTLIST_DIFF_URL = _chunkSJIYZL3Tjs.METAMASK_HOTLIST_DIFF_URL; exports.METAMASK_STALELIST_FILE = _chunkSJIYZL3Tjs.METAMASK_STALELIST_FILE; exports.METAMASK_STALELIST_URL = _chunkSJIYZL3Tjs.METAMASK_STALELIST_URL; exports.PHISHING_CONFIG_BASE_URL = _chunkSJIYZL3Tjs.PHISHING_CONFIG_BASE_URL; exports.PhishingController = _chunkSJIYZL3Tjs.PhishingController; exports.STALELIST_REFRESH_INTERVAL = _chunkSJIYZL3Tjs.STALELIST_REFRESH_INTERVAL; exports.phishingListKeyNameMap = _chunkSJIYZL3Tjs.phishingListKeyNameMap;
|
|
27
28
|
//# sourceMappingURL=index.js.map
|
package/dist/index.mjs
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});require('../chunk-Z4BLTVTB.js');
|
|
2
|
+
|
|
3
|
+
// src/tests/utils.ts
|
|
4
|
+
var formatHostnameToUrl = (hostname) => {
|
|
5
|
+
let url = "";
|
|
6
|
+
try {
|
|
7
|
+
url = new URL(hostname).href;
|
|
8
|
+
} catch (e) {
|
|
9
|
+
url = new URL(["https://", hostname].join("")).href;
|
|
10
|
+
}
|
|
11
|
+
return url;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
exports.formatHostnameToUrl = formatHostnameToUrl;
|
|
16
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/tests/utils.ts"],"names":[],"mappings":";;;AASO,IAAM,sBAAsB,CAAC,aAA6B;AAC/D,MAAI,MAAM;AACV,MAAI;AACF,UAAM,IAAI,IAAI,QAAQ,EAAE;AAAA,EAC1B,SAAS,GAAG;AACV,UAAM,IAAI,IAAI,CAAC,YAAY,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE;AAAA,EACjD;AACA,SAAO;AACT","sourcesContent":["/**\n * Formats a hostname into a URL so we can parse it correctly\n * and pass full URLs into the PhishingDetector class. Previously\n * only hostnames were supported, but now only full URLs are\n * supported since we want to block IPFS CIDs.\n *\n * @param hostname - the hostname of the URL.\n * @returns the href property of a URL object.\n */\nexport const formatHostnameToUrl = (hostname: string): string => {\n let url = '';\n try {\n url = new URL(hostname).href;\n } catch (e) {\n url = new URL(['https://', hostname].join('')).href;\n }\n return url;\n};\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import "../chunk-XUI43LEZ.mjs";
|
|
2
|
+
|
|
3
|
+
// src/tests/utils.ts
|
|
4
|
+
var formatHostnameToUrl = (hostname) => {
|
|
5
|
+
let url = "";
|
|
6
|
+
try {
|
|
7
|
+
url = new URL(hostname).href;
|
|
8
|
+
} catch (e) {
|
|
9
|
+
url = new URL(["https://", hostname].join("")).href;
|
|
10
|
+
}
|
|
11
|
+
return url;
|
|
12
|
+
};
|
|
13
|
+
export {
|
|
14
|
+
formatHostnameToUrl
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/tests/utils.ts"],"sourcesContent":["/**\n * Formats a hostname into a URL so we can parse it correctly\n * and pass full URLs into the PhishingDetector class. Previously\n * only hostnames were supported, but now only full URLs are\n * supported since we want to block IPFS CIDs.\n *\n * @param hostname - the hostname of the URL.\n * @returns the href property of a URL object.\n */\nexport const formatHostnameToUrl = (hostname: string): string => {\n let url = '';\n try {\n url = new URL(hostname).href;\n } catch (e) {\n url = new URL(['https://', hostname].join('')).href;\n }\n return url;\n};\n"],"mappings":";;;AASO,IAAM,sBAAsB,CAAC,aAA6B;AAC/D,MAAI,MAAM;AACV,MAAI;AACF,UAAM,IAAI,IAAI,QAAQ,EAAE;AAAA,EAC1B,SAAS,GAAG;AACV,UAAM,IAAI,IAAI,CAAC,YAAY,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE;AAAA,EACjD;AACA,SAAO;AACT;","names":[]}
|