mirror of
https://github.com/SukkaW/Surge.git
synced 2026-03-17 00:16:45 +08:00
Chore: maintainance
This commit is contained in:
46
Dist/Build/lib/append-array-in-place.cjs
Normal file
46
Dist/Build/lib/append-array-in-place.cjs
Normal file
@@ -0,0 +1,46 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const appendArrayInPlace=require('../../_virtual/append-array-in-place.cjs');var hasRequiredAppendArrayInPlace;
|
||||
|
||||
function requireAppendArrayInPlace () {
|
||||
if (hasRequiredAppendArrayInPlace) return appendArrayInPlace.__exports;
|
||||
hasRequiredAppendArrayInPlace = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
appendArrayInPlace: function() {
|
||||
return appendArrayInPlace;
|
||||
},
|
||||
appendArrayInPlaceCurried: function() {
|
||||
return appendArrayInPlaceCurried;
|
||||
}
|
||||
});
|
||||
const MAX_BLOCK_SIZE = 65535; // max parameter array size for use in Webkit
|
||||
function appendArrayInPlace(dest, source) {
|
||||
let offset = 0;
|
||||
let itemsLeft = source.length;
|
||||
if (itemsLeft <= MAX_BLOCK_SIZE) {
|
||||
// eslint-disable-next-line prefer-spread -- performance
|
||||
dest.push.apply(dest, source);
|
||||
} else {
|
||||
while(itemsLeft > 0){
|
||||
const pushCount = itemsLeft > MAX_BLOCK_SIZE ? MAX_BLOCK_SIZE : itemsLeft;
|
||||
const subSource = source.slice(offset, offset + pushCount);
|
||||
// eslint-disable-next-line prefer-spread -- performance
|
||||
dest.push.apply(dest, subSource);
|
||||
itemsLeft -= pushCount;
|
||||
offset += pushCount;
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
const appendArrayInPlaceCurried = (dest)=>(source)=>appendArrayInPlace(dest, source);
|
||||
} (appendArrayInPlace.__exports));
|
||||
return appendArrayInPlace.__exports;
|
||||
}exports.__require=requireAppendArrayInPlace;
|
||||
134
Dist/Build/lib/cache-filesystem.cjs
Normal file
134
Dist/Build/lib/cache-filesystem.cjs
Normal file
@@ -0,0 +1,134 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const cacheFilesystem=require('../../_virtual/cache-filesystem.cjs'),require$$0=require('better-sqlite3'),require$$1$1=require('node:os'),require$$0$2=require('node:path'),require$$1=require('node:fs'),require$$0$1=require('picocolors'),require$$3=require('foxts/fast-string-array-join'),require$$6=require('node:perf_hooks');var hasRequiredCacheFilesystem;
|
||||
|
||||
function requireCacheFilesystem () {
|
||||
if (hasRequiredCacheFilesystem) return cacheFilesystem.__exports;
|
||||
hasRequiredCacheFilesystem = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
Cache: function() {
|
||||
return Cache;
|
||||
},
|
||||
deserializeArray: function() {
|
||||
return deserializeArray;
|
||||
},
|
||||
serializeArray: function() {
|
||||
return serializeArray;
|
||||
}
|
||||
});
|
||||
const _bettersqlite3 = /*#__PURE__*/ _interop_require_default(require$$0);
|
||||
const _nodeos = /*#__PURE__*/ _interop_require_default(require$$1$1);
|
||||
const _nodepath = /*#__PURE__*/ _interop_require_default(require$$0$2);
|
||||
const _nodefs = require$$1;
|
||||
const _picocolors = /*#__PURE__*/ _interop_require_default(require$$0$1);
|
||||
const _faststringarrayjoin = require$$3;
|
||||
const _nodeperf_hooks = require$$6;
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
class Cache {
|
||||
db;
|
||||
/** Time before deletion */ tbd = 60 * 1000;
|
||||
/** SQLite file path */ cachePath;
|
||||
/** Table name */ tableName;
|
||||
type;
|
||||
statement;
|
||||
constructor({ cachePath = _nodepath.default.join(_nodeos.default.tmpdir() || '/tmp', 'hdc'), tbd, tableName = 'cache', type } = {}){
|
||||
const start = _nodeperf_hooks.performance.now();
|
||||
this.cachePath = cachePath;
|
||||
(0, _nodefs.mkdirSync)(this.cachePath, {
|
||||
recursive: true
|
||||
});
|
||||
if (tbd != null) this.tbd = tbd;
|
||||
this.tableName = tableName;
|
||||
if (type) {
|
||||
this.type = type;
|
||||
} else {
|
||||
// @ts-expect-error -- fallback type
|
||||
this.type = 'string';
|
||||
}
|
||||
const db = (0, _bettersqlite3.default)(_nodepath.default.join(this.cachePath, 'cache.db'));
|
||||
db.pragma('journal_mode = WAL');
|
||||
db.pragma('synchronous = normal');
|
||||
db.pragma('temp_store = memory');
|
||||
db.pragma('optimize');
|
||||
db.prepare(`CREATE TABLE IF NOT EXISTS ${this.tableName} (key TEXT PRIMARY KEY, value ${this.type === 'string' ? 'TEXT' : 'BLOB'}, ttl REAL NOT NULL);`).run();
|
||||
db.prepare(`CREATE INDEX IF NOT EXISTS cache_ttl ON ${this.tableName} (ttl);`).run();
|
||||
/** cache stmt */ this.statement = {
|
||||
updateTtl: db.prepare(`UPDATE ${this.tableName} SET ttl = ? WHERE key = ?;`),
|
||||
del: db.prepare(`DELETE FROM ${this.tableName} WHERE key = ?`),
|
||||
insert: db.prepare(`INSERT INTO ${this.tableName} (key, value, ttl) VALUES ($key, $value, $valid) ON CONFLICT(key) DO UPDATE SET value = $value, ttl = $valid`),
|
||||
get: db.prepare(`SELECT ttl, value FROM ${this.tableName} WHERE key = ? LIMIT 1`)
|
||||
};
|
||||
const date = new Date();
|
||||
// perform purge on startup
|
||||
// ttl + tbd < now => ttl < now - tbd
|
||||
const now = date.getTime() - this.tbd;
|
||||
db.prepare(`DELETE FROM ${this.tableName} WHERE ttl < ?`).run(now);
|
||||
this.db = db;
|
||||
const dateString = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
|
||||
const lastVaccum = this.get('__LAST_VACUUM');
|
||||
if (lastVaccum === undefined || lastVaccum !== dateString && date.getUTCDay() === 6) {
|
||||
console.log(_picocolors.default.magenta('[cache] vacuuming'));
|
||||
this.set('__LAST_VACUUM', dateString, 10 * 365 * 60 * 60 * 24 * 1000);
|
||||
this.db.exec('VACUUM;');
|
||||
}
|
||||
const end = _nodeperf_hooks.performance.now();
|
||||
console.log(`${_picocolors.default.gray(`[${(end - start).toFixed(3)}ns]`)} cache initialized from ${this.tableName} @ ${this.cachePath}`);
|
||||
}
|
||||
set(key, value, ttl = 60 * 1000) {
|
||||
const valid = Date.now() + ttl;
|
||||
this.statement.insert.run({
|
||||
$key: key,
|
||||
key,
|
||||
$value: value,
|
||||
value,
|
||||
$valid: valid,
|
||||
valid
|
||||
});
|
||||
}
|
||||
get(key) {
|
||||
const rv = this.statement.get.get(key);
|
||||
if (!rv) return null;
|
||||
if (rv.ttl < Date.now()) {
|
||||
this.del(key);
|
||||
return null;
|
||||
}
|
||||
if (rv.value == null) {
|
||||
this.del(key);
|
||||
return null;
|
||||
}
|
||||
return rv.value;
|
||||
}
|
||||
updateTtl(key, ttl) {
|
||||
this.statement.updateTtl.run(Date.now() + ttl, key);
|
||||
}
|
||||
del(key) {
|
||||
this.statement.del.run(key);
|
||||
}
|
||||
destroy() {
|
||||
this.db.close();
|
||||
}
|
||||
deleteTable(tableName) {
|
||||
this.db.exec(`DROP TABLE IF EXISTS ${tableName};`);
|
||||
}
|
||||
}
|
||||
// process.on('exit', () => {
|
||||
// fsFetchCache.destroy();
|
||||
// });
|
||||
const separator = '\u0000';
|
||||
const serializeArray = (arr)=>(0, _faststringarrayjoin.fastStringArrayJoin)(arr, separator);
|
||||
const deserializeArray = (str)=>str.split(separator);
|
||||
} (cacheFilesystem.__exports));
|
||||
return cacheFilesystem.__exports;
|
||||
}exports.__require=requireCacheFilesystem;
|
||||
114
Dist/Build/lib/create-file.cjs
Normal file
114
Dist/Build/lib/create-file.cjs
Normal file
@@ -0,0 +1,114 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const createFile=require('../../_virtual/create-file.cjs'),require$$0=require('foxts/async-write-to-stream'),require$$3=require('foxts/fast-string-array-join'),require$$1=require('node:fs'),require$$0$1=require('picocolors'),fetchTextByLine=require('./fetch-text-by-line.cjs'),misc=require('./misc.cjs');var hasRequiredCreateFile;
|
||||
|
||||
function requireCreateFile () {
|
||||
if (hasRequiredCreateFile) return createFile.__exports;
|
||||
hasRequiredCreateFile = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
compareAndWriteFile: function() {
|
||||
return compareAndWriteFile;
|
||||
},
|
||||
fileEqual: function() {
|
||||
return fileEqual;
|
||||
}
|
||||
});
|
||||
const _asyncwritetostream = require$$0;
|
||||
const _faststringarrayjoin = require$$3;
|
||||
const _nodefs = /*#__PURE__*/ _interop_require_default(require$$1);
|
||||
const _picocolors = /*#__PURE__*/ _interop_require_default(require$$0$1);
|
||||
const _fetchtextbyline = /*@__PURE__*/ fetchTextByLine.__require();
|
||||
const _misc = /*@__PURE__*/ misc.__require();
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
async function fileEqual(linesA, source) {
|
||||
if (linesA.length === 0) {
|
||||
return false;
|
||||
}
|
||||
const linesABound = linesA.length - 1;
|
||||
let index = -1;
|
||||
for await (const lineB of source){
|
||||
index++;
|
||||
if (index > linesABound) {
|
||||
return index === linesA.length && lineB.length === 0;
|
||||
}
|
||||
const lineA = linesA[index];
|
||||
if (lineA.length === 0) {
|
||||
if (lineB.length === 0) {
|
||||
continue;
|
||||
}
|
||||
// lineA is empty but lineB is not
|
||||
return false;
|
||||
}
|
||||
// now lineA can not be empty
|
||||
if (lineB.length === 0) {
|
||||
// lineB is empty but lineA is not
|
||||
return false;
|
||||
}
|
||||
// now both lines can not be empty
|
||||
const firstCharA = lineA.charCodeAt(0);
|
||||
const firstCharB = lineB.charCodeAt(0);
|
||||
if (firstCharA !== firstCharB) {
|
||||
return false;
|
||||
}
|
||||
// now firstCharA is equal to firstCharB, we only need to check the first char
|
||||
if (firstCharA === 35 /* # */ ) {
|
||||
continue;
|
||||
}
|
||||
// adguard conf
|
||||
if (firstCharA === 33 /* ! */ ) {
|
||||
continue;
|
||||
}
|
||||
if (firstCharA === 47 /* / */ && lineA[1] === '/' && lineB[1] === '/' && lineA[3] === '#' && lineB[3] === '#') {
|
||||
continue;
|
||||
}
|
||||
if (lineA !== lineB) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// The file becomes larger
|
||||
return !(index < linesABound);
|
||||
}
|
||||
async function compareAndWriteFile(span, linesA, filePath) {
|
||||
const linesALen = linesA.length;
|
||||
const isEqual = await span.traceChildAsync(`compare ${filePath}`, async ()=>{
|
||||
if (_nodefs.default.existsSync(filePath)) {
|
||||
return fileEqual(linesA, (0, _fetchtextbyline.readFileByLine)(filePath));
|
||||
}
|
||||
console.log(`${filePath} does not exists, writing...`);
|
||||
return false;
|
||||
});
|
||||
if (isEqual) {
|
||||
console.log(_picocolors.default.gray(_picocolors.default.dim(`same content, bail out writing: ${filePath}`)));
|
||||
return;
|
||||
}
|
||||
await span.traceChildAsync(`writing ${filePath}`, async ()=>{
|
||||
// The default highwater mark is normally 16384,
|
||||
// So we make sure direct write to file if the content is
|
||||
// most likely less than 500 lines
|
||||
if (linesALen < 500) {
|
||||
return (0, _misc.writeFile)(filePath, (0, _faststringarrayjoin.fastStringArrayJoin)(linesA, '\n') + '\n');
|
||||
}
|
||||
const writeStream = _nodefs.default.createWriteStream(filePath);
|
||||
for(let i = 0; i < linesALen; i++){
|
||||
const p = (0, _asyncwritetostream.asyncWriteToStream)(writeStream, linesA[i] + '\n');
|
||||
// eslint-disable-next-line no-await-in-loop -- stream high water mark
|
||||
if (p) await p;
|
||||
}
|
||||
writeStream.end();
|
||||
});
|
||||
}
|
||||
} (createFile.__exports));
|
||||
return createFile.__exports;
|
||||
}exports.__require=requireCreateFile;
|
||||
81
Dist/Build/lib/fetch-assets.cjs
Normal file
81
Dist/Build/lib/fetch-assets.cjs
Normal file
@@ -0,0 +1,81 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const fetchAssets=require('../../_virtual/fetch-assets.cjs'),require$$0=require('picocolors'),fetchRetry=require('./fetch-retry.cjs'),require$$2=require('foxts/wait'),require$$6=require('foxts/guard'),textLineTransformStream=require('./text-line-transform-stream.cjs'),processLine=require('./process-line.cjs');var hasRequiredFetchAssets;
|
||||
|
||||
function requireFetchAssets () {
|
||||
if (hasRequiredFetchAssets) return fetchAssets.__exports;
|
||||
hasRequiredFetchAssets = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
CustomAbortError: function() {
|
||||
return CustomAbortError;
|
||||
},
|
||||
fetchAssets: function() {
|
||||
return fetchAssets;
|
||||
}
|
||||
});
|
||||
const _picocolors = /*#__PURE__*/ _interop_require_default(require$$0);
|
||||
const _fetchretry = /*@__PURE__*/ fetchRetry.__require();
|
||||
const _wait = require$$2;
|
||||
const _guard = require$$6;
|
||||
const _textlinetransformstream = /*@__PURE__*/ textLineTransformStream.__require();
|
||||
const _processline = /*@__PURE__*/ processLine.__require();
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
class CustomAbortError extends Error {
|
||||
name = 'AbortError';
|
||||
digest = 'AbortError';
|
||||
}
|
||||
const reusedCustomAbortError = new CustomAbortError();
|
||||
async function fetchAssets(url, fallbackUrls, processLine = false) {
|
||||
const controller = new AbortController();
|
||||
const createFetchFallbackPromise = async (url, index)=>{
|
||||
if (index >= 0) {
|
||||
// Most assets can be downloaded within 250ms. To avoid wasting bandwidth, we will wait for 500ms before downloading from the fallback URL.
|
||||
try {
|
||||
await (0, _wait.waitWithAbort)(50 + (index + 1) * 100, controller.signal);
|
||||
} catch {
|
||||
console.log(_picocolors.default.gray('[fetch cancelled early]'), _picocolors.default.gray(url));
|
||||
throw reusedCustomAbortError;
|
||||
}
|
||||
}
|
||||
if (controller.signal.aborted) {
|
||||
console.log(_picocolors.default.gray('[fetch cancelled]'), _picocolors.default.gray(url));
|
||||
throw reusedCustomAbortError;
|
||||
}
|
||||
const res = await (0, _fetchretry.$$fetch)(url, {
|
||||
signal: controller.signal,
|
||||
..._fetchretry.defaultRequestInit
|
||||
});
|
||||
let stream = (0, _guard.nullthrow)(res.body).pipeThrough(new TextDecoderStream()).pipeThrough(new _textlinetransformstream.TextLineStream());
|
||||
if (processLine) {
|
||||
stream = stream.pipeThrough(new _processline.ProcessLineStream());
|
||||
}
|
||||
const arr = await Array.fromAsync(stream);
|
||||
if (arr.length < 1) {
|
||||
throw new _fetchretry.ResponseError(res, url, 'empty response w/o 304');
|
||||
}
|
||||
controller.abort();
|
||||
return arr;
|
||||
};
|
||||
if (!fallbackUrls || fallbackUrls.length === 0) {
|
||||
return createFetchFallbackPromise(url, -1);
|
||||
}
|
||||
return Promise.any([
|
||||
createFetchFallbackPromise(url, -1),
|
||||
...fallbackUrls.map(createFetchFallbackPromise)
|
||||
]);
|
||||
}
|
||||
} (fetchAssets.__exports));
|
||||
return fetchAssets.__exports;
|
||||
}exports.__require=requireFetchAssets;
|
||||
235
Dist/Build/lib/fetch-retry.cjs
Normal file
235
Dist/Build/lib/fetch-retry.cjs
Normal file
@@ -0,0 +1,235 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const fetchRetry=require('../../_virtual/fetch-retry.cjs'),require$$0$1=require('picocolors'),require$$1=require('undici'),require$$2=require('undici-cache-store-better-sqlite3'),require$$1$2=require('node:util'),require$$0=require('node:path'),require$$1$1=require('node:fs'),dir=require('../constants/dir.cjs');var hasRequiredFetchRetry;
|
||||
|
||||
function requireFetchRetry () {
|
||||
if (hasRequiredFetchRetry) return fetchRetry.__exports;
|
||||
hasRequiredFetchRetry = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
$$fetch: function() {
|
||||
return $$fetch;
|
||||
},
|
||||
ResponseError: function() {
|
||||
return ResponseError;
|
||||
},
|
||||
defaultRequestInit: function() {
|
||||
return defaultRequestInit;
|
||||
},
|
||||
requestWithLog: function() {
|
||||
return requestWithLog;
|
||||
}
|
||||
});
|
||||
const _picocolors = /*#__PURE__*/ _interop_require_default(require$$0$1);
|
||||
const _undici = /*#__PURE__*/ _interop_require_wildcard(require$$1);
|
||||
const _undicicachestorebettersqlite3 = require$$2;
|
||||
const _nodeutil = require$$1$2;
|
||||
const _nodepath = /*#__PURE__*/ _interop_require_default(require$$0);
|
||||
const _nodefs = /*#__PURE__*/ _interop_require_default(require$$1$1);
|
||||
const _dir = /*@__PURE__*/ dir.__require();
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
function _getRequireWildcardCache(nodeInterop) {
|
||||
if (typeof WeakMap !== "function") return null;
|
||||
var cacheBabelInterop = new WeakMap();
|
||||
var cacheNodeInterop = new WeakMap();
|
||||
return (_getRequireWildcardCache = function(nodeInterop) {
|
||||
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
||||
})(nodeInterop);
|
||||
}
|
||||
function _interop_require_wildcard(obj, nodeInterop) {
|
||||
if (obj && obj.__esModule) {
|
||||
return obj;
|
||||
}
|
||||
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
||||
return {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
var cache = _getRequireWildcardCache(nodeInterop);
|
||||
if (cache && cache.has(obj)) {
|
||||
return cache.get(obj);
|
||||
}
|
||||
var newObj = {
|
||||
__proto__: null
|
||||
};
|
||||
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
||||
for(var key in obj){
|
||||
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
||||
if (desc && (desc.get || desc.set)) {
|
||||
Object.defineProperty(newObj, key, desc);
|
||||
} else {
|
||||
newObj[key] = obj[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
newObj.default = obj;
|
||||
if (cache) {
|
||||
cache.set(obj, newObj);
|
||||
}
|
||||
return newObj;
|
||||
}
|
||||
if (!_nodefs.default.existsSync(_dir.CACHE_DIR)) {
|
||||
_nodefs.default.mkdirSync(_dir.CACHE_DIR, {
|
||||
recursive: true
|
||||
});
|
||||
}
|
||||
const agent = new _undici.Agent({
|
||||
allowH2: true
|
||||
});
|
||||
(0, _undici.setGlobalDispatcher)(agent.compose(_undici.interceptors.dns({
|
||||
// disable IPv6
|
||||
dualStack: false,
|
||||
affinity: 4
|
||||
}), _undici.interceptors.retry({
|
||||
maxRetries: 5,
|
||||
minTimeout: 500,
|
||||
maxTimeout: 10 * 1000,
|
||||
// TODO: this part of code is only for allow more errors to be retried by default
|
||||
// This should be removed once https://github.com/nodejs/undici/issues/3728 is implemented
|
||||
retry (err, { state, opts }, cb) {
|
||||
const errorCode = 'code' in err ? err.code : undefined;
|
||||
// Any code that is not a Undici's originated and allowed to retry
|
||||
if (errorCode === 'ERR_UNESCAPED_CHARACTERS' || err.message === 'Request path contains unescaped characters' || err.name === 'AbortError') {
|
||||
return cb(err);
|
||||
}
|
||||
const statusCode = 'statusCode' in err && typeof err.statusCode === 'number' ? err.statusCode : null;
|
||||
// bail out if the status code matches one of the following
|
||||
if (statusCode != null && (statusCode === 401 // Unauthorized, should check credentials instead of retrying
|
||||
|| statusCode === 403 // Forbidden, should check permissions instead of retrying
|
||||
|| statusCode === 404 // Not Found, should check URL instead of retrying
|
||||
|| statusCode === 405 // Method Not Allowed, should check method instead of retrying
|
||||
)) {
|
||||
return cb(err);
|
||||
}
|
||||
// if (errorCode === 'UND_ERR_REQ_RETRY') {
|
||||
// return cb(err);
|
||||
// }
|
||||
const { maxRetries = 5, minTimeout = 500, maxTimeout = 10 * 1000, timeoutFactor = 2, methods = [
|
||||
'GET',
|
||||
'HEAD',
|
||||
'OPTIONS',
|
||||
'PUT',
|
||||
'DELETE',
|
||||
'TRACE'
|
||||
] } = opts.retryOptions || {};
|
||||
// If we reached the max number of retries
|
||||
if (state.counter > maxRetries) {
|
||||
return cb(err);
|
||||
}
|
||||
// If a set of method are provided and the current method is not in the list
|
||||
if (Array.isArray(methods) && !methods.includes(opts.method)) {
|
||||
return cb(err);
|
||||
}
|
||||
const headers = 'headers' in err && typeof err.headers === 'object' ? err.headers : undefined;
|
||||
const retryAfterHeader = headers?.['retry-after'];
|
||||
let retryAfter = -1;
|
||||
if (retryAfterHeader) {
|
||||
retryAfter = Number(retryAfterHeader);
|
||||
retryAfter = Number.isNaN(retryAfter) ? calculateRetryAfterHeader(retryAfterHeader) : retryAfter * 1e3; // Retry-After is in seconds
|
||||
}
|
||||
const retryTimeout = retryAfter > 0 ? Math.min(retryAfter, maxTimeout) : Math.min(minTimeout * timeoutFactor ** (state.counter - 1), maxTimeout);
|
||||
console.log('[fetch retry]', 'schedule retry', {
|
||||
statusCode,
|
||||
retryTimeout,
|
||||
errorCode,
|
||||
url: opts.origin
|
||||
});
|
||||
// eslint-disable-next-line sukka/prefer-timer-id -- won't leak
|
||||
setTimeout(()=>cb(null), retryTimeout);
|
||||
}
|
||||
}), _undici.interceptors.redirect({
|
||||
maxRedirections: 5
|
||||
}), _undici.interceptors.cache({
|
||||
store: new _undicicachestorebettersqlite3.BetterSqlite3CacheStore({
|
||||
location: _nodepath.default.join(_dir.CACHE_DIR, 'undici-better-sqlite3-cache-store.db'),
|
||||
maxEntrySize: 1024 * 1024 * 100 // 100 MiB
|
||||
})
|
||||
})));
|
||||
function calculateRetryAfterHeader(retryAfter) {
|
||||
const current = Date.now();
|
||||
return new Date(retryAfter).getTime() - current;
|
||||
}
|
||||
class ResponseError extends Error {
|
||||
res;
|
||||
url;
|
||||
code;
|
||||
statusCode;
|
||||
constructor(res, url, ...args){
|
||||
const statusCode = 'statusCode' in res ? res.statusCode : res.status;
|
||||
super('HTTP ' + statusCode + ' ' + args.map((_)=>(0, _nodeutil.inspect)(_)).join(' ')), this.res = res, this.url = url;
|
||||
if ('captureStackTrace' in Error) {
|
||||
Error.captureStackTrace(this, ResponseError);
|
||||
}
|
||||
// eslint-disable-next-line sukka/unicorn/custom-error-definition -- deliberatly use previous name
|
||||
this.name = this.constructor.name;
|
||||
this.res = res;
|
||||
this.code = statusCode;
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
}
|
||||
const defaultRequestInit = {
|
||||
headers: {
|
||||
'User-Agent': 'curl/8.9.1 (https://github.com/SukkaW/Surge)'
|
||||
}
|
||||
};
|
||||
async function $$fetch(url, init) {
|
||||
try {
|
||||
const res = await _undici.default.fetch(url, init);
|
||||
if (res.status >= 400) {
|
||||
throw new ResponseError(res, url);
|
||||
}
|
||||
if (!(res.status >= 200 && res.status <= 299) && res.status !== 304) {
|
||||
throw new ResponseError(res, url);
|
||||
}
|
||||
return res;
|
||||
} catch (err) {
|
||||
if (typeof err === 'object' && err !== null && 'name' in err) {
|
||||
if (err.name === 'AbortError' || 'digest' in err && err.digest === 'AbortError') {
|
||||
console.log(_picocolors.default.gray('[fetch abort]'), url);
|
||||
}
|
||||
} else {
|
||||
console.log(_picocolors.default.gray('[fetch fail]'), url, {
|
||||
name: err.name
|
||||
}, err);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
async function requestWithLog(url, opt) {
|
||||
try {
|
||||
const res = await _undici.default.request(url, opt);
|
||||
if (res.statusCode >= 400) {
|
||||
throw new ResponseError(res, url);
|
||||
}
|
||||
if (!(res.statusCode >= 200 && res.statusCode <= 299) && res.statusCode !== 304) {
|
||||
throw new ResponseError(res, url);
|
||||
}
|
||||
return res;
|
||||
} catch (err) {
|
||||
if (typeof err === 'object' && err !== null && 'name' in err) {
|
||||
if (err.name === 'AbortError' || 'digest' in err && err.digest === 'AbortError') {
|
||||
console.log(_picocolors.default.gray('[fetch abort]'), url);
|
||||
}
|
||||
} else {
|
||||
console.log(_picocolors.default.gray('[fetch fail]'), url, {
|
||||
name: err.name
|
||||
}, err);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
} (fetchRetry.__exports));
|
||||
return fetchRetry.__exports;
|
||||
}exports.__require=requireFetchRetry;
|
||||
79
Dist/Build/lib/fetch-text-by-line.cjs
Normal file
79
Dist/Build/lib/fetch-text-by-line.cjs
Normal file
@@ -0,0 +1,79 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const fetchTextByLine=require('../../_virtual/fetch-text-by-line.cjs'),require$$1=require('node:fs'),require$$1$1=require('node:readline'),textLineTransformStream=require('./text-line-transform-stream.cjs'),require$$0=require('node:stream/web'),processLine=require('./process-line.cjs'),fetchRetry=require('./fetch-retry.cjs'),require$$6=require('foxts/guard');var hasRequiredFetchTextByLine;
|
||||
|
||||
function requireFetchTextByLine () {
|
||||
if (hasRequiredFetchTextByLine) return fetchTextByLine.__exports;
|
||||
hasRequiredFetchTextByLine = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
createReadlineInterfaceFromResponse: function() {
|
||||
return createReadlineInterfaceFromResponse;
|
||||
},
|
||||
fetchRemoteTextByLine: function() {
|
||||
return fetchRemoteTextByLine;
|
||||
},
|
||||
readFileByLine: function() {
|
||||
return readFileByLine;
|
||||
},
|
||||
readFileIntoProcessedArray: function() {
|
||||
return readFileIntoProcessedArray;
|
||||
}
|
||||
});
|
||||
const _nodefs = /*#__PURE__*/ _interop_require_default(require$$1);
|
||||
const _nodereadline = /*#__PURE__*/ _interop_require_default(require$$1$1);
|
||||
const _textlinetransformstream = /*@__PURE__*/ textLineTransformStream.__require();
|
||||
const _web = require$$0;
|
||||
const _processline = /*@__PURE__*/ processLine.__require();
|
||||
const _fetchretry = /*@__PURE__*/ fetchRetry.__require();
|
||||
const _guard = require$$6;
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
function readFileByLine(file) {
|
||||
return _nodereadline.default.createInterface({
|
||||
input: _nodefs.default.createReadStream(file /* , { encoding: 'utf-8' } */ ),
|
||||
crlfDelay: Infinity
|
||||
});
|
||||
}
|
||||
const createReadlineInterfaceFromResponse = (resp, processLine = false)=>{
|
||||
(0, _guard.invariant)(resp.body, 'Failed to fetch remote text');
|
||||
if ('bodyUsed' in resp && resp.bodyUsed) {
|
||||
throw new Error('Body has already been consumed.');
|
||||
}
|
||||
let webStream;
|
||||
if ('pipeThrough' in resp.body) {
|
||||
webStream = resp.body;
|
||||
} else {
|
||||
throw new TypeError('Invalid response body!');
|
||||
}
|
||||
const resultStream = webStream.pipeThrough(new _web.TextDecoderStream()).pipeThrough(new _textlinetransformstream.TextLineStream());
|
||||
if (processLine) {
|
||||
return resultStream.pipeThrough(new _processline.ProcessLineStream());
|
||||
}
|
||||
return resultStream;
|
||||
};
|
||||
function fetchRemoteTextByLine(url, processLine = false) {
|
||||
return (0, _fetchretry.$$fetch)(url).then((resp)=>createReadlineInterfaceFromResponse(resp, processLine));
|
||||
}
|
||||
async function readFileIntoProcessedArray(file/* | FileHandle */ ) {
|
||||
const results = [];
|
||||
for await (const line of readFileByLine(file)){
|
||||
if ((0, _processline.processLine)(line)) {
|
||||
results.push(line);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
} (fetchTextByLine.__exports));
|
||||
return fetchTextByLine.__exports;
|
||||
}exports.__require=requireFetchTextByLine;
|
||||
89
Dist/Build/lib/fs-memo.cjs
Normal file
89
Dist/Build/lib/fs-memo.cjs
Normal file
@@ -0,0 +1,89 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const fsMemo=require('../../_virtual/fs-memo.cjs'),require$$0$1=require('node:path'),require$$11=require('ci-info'),require$$0=require('picocolors'),cacheFilesystem=require('./cache-filesystem.cjs'),require$$4=require('foxts/serialized-memo'),dir=require('../constants/dir.cjs');var hasRequiredFsMemo;
|
||||
|
||||
function requireFsMemo () {
|
||||
if (hasRequiredFsMemo) return fsMemo.__exports;
|
||||
hasRequiredFsMemo = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
cache: function() {
|
||||
return cache;
|
||||
},
|
||||
cachedOnlyFail: function() {
|
||||
return cachedOnlyFail;
|
||||
}
|
||||
});
|
||||
const _nodepath = /*#__PURE__*/ _interop_require_default(require$$0$1);
|
||||
const _ciinfo = require$$11;
|
||||
const _picocolors = /*#__PURE__*/ _interop_require_default(require$$0);
|
||||
const _cachefilesystem = /*@__PURE__*/ cacheFilesystem.__require();
|
||||
const _serializedmemo = require$$4;
|
||||
const _dir = /*@__PURE__*/ dir.__require();
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
const fsMemoCache = new _cachefilesystem.Cache({
|
||||
cachePath: _nodepath.default.join(_dir.ROOT_DIR, '.cache'),
|
||||
tableName: 'fs_memo_cache'
|
||||
});
|
||||
const fsMemoCacheProvider = {
|
||||
has (key) {
|
||||
return fsMemoCache.get(key) !== null;
|
||||
},
|
||||
delete () {
|
||||
// noop
|
||||
},
|
||||
get (key) {
|
||||
return fsMemoCache.get(key) ?? undefined;
|
||||
},
|
||||
set (key, value, ttl) {
|
||||
fsMemoCache.set(key, value, ttl);
|
||||
},
|
||||
updateTtl (key, ttl) {
|
||||
fsMemoCache.updateTtl(key, ttl);
|
||||
}
|
||||
};
|
||||
const TTL = _ciinfo.isCI ? 1.5 * 86400 * 1000 : 7 * 86400 * 1000;
|
||||
const cache = (0, _serializedmemo.createMemoize)(fsMemoCacheProvider, {
|
||||
defaultTtl: TTL,
|
||||
onCacheMiss (key, { humanReadableName, isUseCachedIfFail }) {
|
||||
const cacheName = _picocolors.default.gray(humanReadableName);
|
||||
if (isUseCachedIfFail) {
|
||||
console.log(_picocolors.default.red('[fail] and no cache, throwing'), cacheName);
|
||||
} else {
|
||||
console.log(_picocolors.default.yellow('[cache] miss'), cacheName);
|
||||
}
|
||||
},
|
||||
onCacheUpdate (key, { humanReadableName, isUseCachedIfFail }) {
|
||||
const cacheName = _picocolors.default.gray(humanReadableName);
|
||||
if (isUseCachedIfFail) {
|
||||
console.log(_picocolors.default.gray('[cache] update'), cacheName);
|
||||
}
|
||||
},
|
||||
onCacheHit (key, { humanReadableName, isUseCachedIfFail }) {
|
||||
const cacheName = _picocolors.default.gray(humanReadableName);
|
||||
if (isUseCachedIfFail) {
|
||||
console.log(_picocolors.default.yellow('[fail] try cache'), cacheName);
|
||||
} else {
|
||||
console.log(_picocolors.default.green('[cache] hit'), cacheName);
|
||||
}
|
||||
}
|
||||
});
|
||||
const cachedOnlyFail = (0, _serializedmemo.createMemoize)(fsMemoCacheProvider, {
|
||||
defaultTtl: TTL,
|
||||
onlyUseCachedIfFail: true
|
||||
}); // export const cache = createCache(false);
|
||||
// export const cachedOnlyFail = createCache(true);
|
||||
} (fsMemo.__exports));
|
||||
return fsMemo.__exports;
|
||||
}exports.__require=requireFsMemo;
|
||||
376
Dist/Build/lib/get-phishing-domains.cjs
Normal file
376
Dist/Build/lib/get-phishing-domains.cjs
Normal file
@@ -0,0 +1,376 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const getPhishingDomains=require('../../_virtual/get-phishing-domains.cjs'),hosts=require('./parse-filter/hosts.cjs'),domainlists=require('./parse-filter/domainlists.cjs'),require$$5=require('tldts-experimental'),index=require('../trace/index.cjs'),appendArrayInPlace=require('./append-array-in-place.cjs'),rejectDataSource=require('../constants/reject-data-source.cjs'),looseTldtsOpt=require('../constants/loose-tldts-opt.cjs'),require$$0=require('picocolors'),require$$3=require('foxts/retrie'),cacheFilesystem=require('./cache-filesystem.cjs'),fsMemo=require('./fs-memo.cjs'),require$$11=require('ci-info');var hasRequiredGetPhishingDomains;
|
||||
|
||||
function requireGetPhishingDomains () {
|
||||
if (hasRequiredGetPhishingDomains) return getPhishingDomains.__module.exports;
|
||||
hasRequiredGetPhishingDomains = 1;
|
||||
(function (module, exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
calcDomainAbuseScore: function() {
|
||||
return calcDomainAbuseScore;
|
||||
},
|
||||
getPhishingDomains: function() {
|
||||
return getPhishingDomains;
|
||||
}
|
||||
});
|
||||
const _hosts = /*@__PURE__*/ hosts.__require();
|
||||
const _domainlists = /*@__PURE__*/ domainlists.__require();
|
||||
const _tldtsexperimental = /*#__PURE__*/ _interop_require_wildcard(require$$5);
|
||||
const _trace = /*@__PURE__*/ index.__require();
|
||||
const _appendarrayinplace = /*@__PURE__*/ appendArrayInPlace.__require();
|
||||
const _rejectdatasource = /*@__PURE__*/ rejectDataSource.__require();
|
||||
const _loosetldtsopt = /*@__PURE__*/ looseTldtsOpt.__require();
|
||||
const _picocolors = /*#__PURE__*/ _interop_require_default(require$$0);
|
||||
const _retrie = require$$3;
|
||||
const _cachefilesystem = /*@__PURE__*/ cacheFilesystem.__require();
|
||||
const _fsmemo = /*@__PURE__*/ fsMemo.__require();
|
||||
const _ciinfo = require$$11;
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
function _getRequireWildcardCache(nodeInterop) {
|
||||
if (typeof WeakMap !== "function") return null;
|
||||
var cacheBabelInterop = new WeakMap();
|
||||
var cacheNodeInterop = new WeakMap();
|
||||
return (_getRequireWildcardCache = function(nodeInterop) {
|
||||
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
||||
})(nodeInterop);
|
||||
}
|
||||
function _interop_require_wildcard(obj, nodeInterop) {
|
||||
if (obj && obj.__esModule) {
|
||||
return obj;
|
||||
}
|
||||
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
||||
return {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
var cache = _getRequireWildcardCache(nodeInterop);
|
||||
if (cache && cache.has(obj)) {
|
||||
return cache.get(obj);
|
||||
}
|
||||
var newObj = {
|
||||
__proto__: null
|
||||
};
|
||||
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
||||
for(var key in obj){
|
||||
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
||||
if (desc && (desc.get || desc.set)) {
|
||||
Object.defineProperty(newObj, key, desc);
|
||||
} else {
|
||||
newObj[key] = obj[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
newObj.default = obj;
|
||||
if (cache) {
|
||||
cache.set(obj, newObj);
|
||||
}
|
||||
return newObj;
|
||||
}
|
||||
const BLACK_TLD = new Set([
|
||||
'accountant',
|
||||
'art',
|
||||
'autos',
|
||||
'bar',
|
||||
'beauty',
|
||||
'bid',
|
||||
'bio',
|
||||
'biz',
|
||||
'bond',
|
||||
'business',
|
||||
'buzz',
|
||||
'cc',
|
||||
'cf',
|
||||
'cfd',
|
||||
'click',
|
||||
'cloud',
|
||||
'club',
|
||||
'cn',
|
||||
'codes',
|
||||
'co.uk',
|
||||
'co.in',
|
||||
'com.br',
|
||||
'com.cn',
|
||||
'com.pl',
|
||||
'com.vn',
|
||||
'cool',
|
||||
'cricket',
|
||||
'cyou',
|
||||
'date',
|
||||
'design',
|
||||
'digital',
|
||||
'download',
|
||||
'faith',
|
||||
'fit',
|
||||
'fun',
|
||||
'ga',
|
||||
'gd',
|
||||
'gives',
|
||||
'gq',
|
||||
'group',
|
||||
'host',
|
||||
'icu',
|
||||
'id',
|
||||
'info',
|
||||
'ink',
|
||||
'lat',
|
||||
'life',
|
||||
'live',
|
||||
'link',
|
||||
'loan',
|
||||
'lol',
|
||||
'ltd',
|
||||
'me',
|
||||
'men',
|
||||
'ml',
|
||||
'mobi',
|
||||
'mom',
|
||||
'monster',
|
||||
'net.pl',
|
||||
'one',
|
||||
'online',
|
||||
'party',
|
||||
'pro',
|
||||
'pl',
|
||||
'pw',
|
||||
'racing',
|
||||
'rest',
|
||||
'review',
|
||||
'rf.gd',
|
||||
'sa.com',
|
||||
'sbs',
|
||||
'science',
|
||||
'shop',
|
||||
'site',
|
||||
'skin',
|
||||
'space',
|
||||
'store',
|
||||
'stream',
|
||||
'su',
|
||||
'surf',
|
||||
'tech',
|
||||
'tk',
|
||||
'tokyo',
|
||||
'top',
|
||||
'trade',
|
||||
'vip',
|
||||
'vn',
|
||||
'webcam',
|
||||
'website',
|
||||
'win',
|
||||
'xyz',
|
||||
'za.com'
|
||||
]);
|
||||
const WHITELIST_MAIN_DOMAINS = new Set([
|
||||
// 'w3s.link', // ipfs gateway
|
||||
// 'dweb.link', // ipfs gateway
|
||||
// 'nftstorage.link', // ipfs gateway
|
||||
'fleek.cool',
|
||||
'flk-ipfs.xyz',
|
||||
'business.site',
|
||||
'page.link',
|
||||
// 'notion.site',
|
||||
// 'vercel.app',
|
||||
'gitbook.io',
|
||||
'zendesk.com',
|
||||
'ipfs.eth.aragon.network',
|
||||
'wordpress.com'
|
||||
]);
|
||||
const leathalKeywords = (0, _retrie.createRetrieKeywordFilter)([
|
||||
'vinted-',
|
||||
'inpost-pl',
|
||||
'vlnted-'
|
||||
]);
|
||||
const sensitiveKeywords = (0, _retrie.createRetrieKeywordFilter)([
|
||||
'.amazon-',
|
||||
'-amazon',
|
||||
'fb-com',
|
||||
'facebook-com',
|
||||
'-facebook',
|
||||
'facebook-',
|
||||
'focebaak',
|
||||
'.facebook.',
|
||||
'metamask',
|
||||
'www.apple',
|
||||
'-coinbase',
|
||||
'coinbase-',
|
||||
'booking-com',
|
||||
'booking.com-',
|
||||
'booking-eu',
|
||||
'vinted-',
|
||||
'inpost-pl',
|
||||
'login.microsoft',
|
||||
'login-microsoft',
|
||||
'microsoftonline',
|
||||
'google.com-',
|
||||
'minecraft',
|
||||
'staemco',
|
||||
'oferta'
|
||||
]);
|
||||
const lowKeywords = (0, _retrie.createRetrieKeywordFilter)([
|
||||
'transactions-',
|
||||
'payment',
|
||||
'wallet',
|
||||
'-transactions',
|
||||
'-faceb',
|
||||
'.faceb',
|
||||
'facebook',
|
||||
'virus-',
|
||||
'icloud-',
|
||||
'apple-',
|
||||
'-roblox',
|
||||
'-co-jp',
|
||||
'customer.',
|
||||
'customer-',
|
||||
'.www-',
|
||||
'.www.',
|
||||
'.www2',
|
||||
'instagram',
|
||||
'microsof',
|
||||
'passwordreset',
|
||||
'.google-',
|
||||
'recover',
|
||||
'banking'
|
||||
]);
|
||||
const processPhihsingDomains = (0, _fsmemo.cache)(function processPhihsingDomains(domainArr) {
|
||||
const domainCountMap = new Map();
|
||||
const domainScoreMap = {};
|
||||
let line = '';
|
||||
let tld = '';
|
||||
let apexDomain = '';
|
||||
let subdomain = '';
|
||||
// const set = new Set<string>();
|
||||
// let duplicateCount = 0;
|
||||
for(let i = 0, len = domainArr.length; i < len; i++){
|
||||
line = domainArr[i];
|
||||
// if (set.has(line)) {
|
||||
// duplicateCount++;
|
||||
// } else {
|
||||
// set.add(line);
|
||||
// }
|
||||
const parsed = _tldtsexperimental.parse(line, _loosetldtsopt.loosTldOptWithPrivateDomains);
|
||||
if (parsed.isPrivate) {
|
||||
continue;
|
||||
}
|
||||
tld = parsed.publicSuffix;
|
||||
apexDomain = parsed.domain;
|
||||
if (!tld) {
|
||||
console.log(_picocolors.default.yellow('[phishing domains] E0001'), 'missing tld', {
|
||||
line,
|
||||
tld
|
||||
});
|
||||
continue;
|
||||
}
|
||||
if (!apexDomain) {
|
||||
console.log(_picocolors.default.yellow('[phishing domains] E0002'), 'missing domain', {
|
||||
line,
|
||||
apexDomain
|
||||
});
|
||||
continue;
|
||||
}
|
||||
domainCountMap.set(apexDomain, domainCountMap.has(apexDomain) ? domainCountMap.get(apexDomain) + 1 : 1);
|
||||
if (!(apexDomain in domainScoreMap)) {
|
||||
domainScoreMap[apexDomain] = 0;
|
||||
if (BLACK_TLD.has(tld)) {
|
||||
domainScoreMap[apexDomain] += 3;
|
||||
} else if (tld.length > 6) {
|
||||
domainScoreMap[apexDomain] += 2;
|
||||
}
|
||||
if (apexDomain.length >= 18) {
|
||||
domainScoreMap[apexDomain] += 0.5;
|
||||
}
|
||||
}
|
||||
subdomain = parsed.subdomain;
|
||||
if (subdomain && !WHITELIST_MAIN_DOMAINS.has(apexDomain)) {
|
||||
domainScoreMap[apexDomain] += calcDomainAbuseScore(subdomain, line);
|
||||
}
|
||||
}
|
||||
domainCountMap.forEach((count, apexDomain)=>{
|
||||
if (// !WHITELIST_MAIN_DOMAINS.has(apexDomain)
|
||||
domainScoreMap[apexDomain] >= 24 || domainScoreMap[apexDomain] >= 16 && count >= 7 || domainScoreMap[apexDomain] >= 13 && count >= 11 || domainScoreMap[apexDomain] >= 5 && count >= 14 || domainScoreMap[apexDomain] >= 3 && count >= 21 || domainScoreMap[apexDomain] >= 1 && count >= 60) {
|
||||
domainArr.push('.' + apexDomain);
|
||||
}
|
||||
});
|
||||
// console.log({
|
||||
// score: domainScoreMap['awicksin.com'],
|
||||
// count: domainCountMap.get('awicksin.com')
|
||||
// });
|
||||
// console.log({ duplicateCount, domainArrLen: domainArr.length });
|
||||
return domainArr;
|
||||
}, {
|
||||
serializer: _cachefilesystem.serializeArray,
|
||||
deserializer: _cachefilesystem.deserializeArray,
|
||||
temporaryBypass: !_ciinfo.isCI || _rejectdatasource.DEBUG_DOMAIN_TO_FIND !== null
|
||||
});
|
||||
const downloads = [
|
||||
..._rejectdatasource.PHISHING_DOMAIN_LISTS_EXTRA.map((entry)=>(0, _domainlists.processDomainListsWithPreload)(...entry)),
|
||||
..._rejectdatasource.PHISHING_HOSTS_EXTRA.map((entry)=>(0, _hosts.processHostsWithPreload)(...entry))
|
||||
];
|
||||
function getPhishingDomains(parentSpan) {
|
||||
return parentSpan.traceChild('get phishing domains').traceAsyncFn(async (span)=>{
|
||||
const domainArr = await span.traceChildAsync('download/parse/merge phishing domains', async (curSpan)=>{
|
||||
const domainArr = [];
|
||||
const domainGroups = await Promise.all(downloads.map((task)=>task(curSpan)));
|
||||
domainGroups.forEach((0, _appendarrayinplace.appendArrayInPlaceCurried)(domainArr));
|
||||
return domainArr;
|
||||
});
|
||||
return span.traceChildAsync('process phishing domain set', ()=>processPhihsingDomains(domainArr));
|
||||
});
|
||||
}
|
||||
function calcDomainAbuseScore(subdomain, fullDomain = subdomain) {
|
||||
if (leathalKeywords(fullDomain)) {
|
||||
return 100;
|
||||
}
|
||||
let weight = 0;
|
||||
const hitLowKeywords = lowKeywords(fullDomain);
|
||||
const sensitiveKeywordsHit = sensitiveKeywords(fullDomain);
|
||||
if (sensitiveKeywordsHit) {
|
||||
weight += 10;
|
||||
if (hitLowKeywords) {
|
||||
weight += 6;
|
||||
}
|
||||
} else if (hitLowKeywords) {
|
||||
weight += 1.7;
|
||||
}
|
||||
const subdomainLength = subdomain.length;
|
||||
if (subdomainLength > 6) {
|
||||
weight += 0.015;
|
||||
if (subdomainLength > 13) {
|
||||
weight += 0.2;
|
||||
if (subdomainLength > 20) {
|
||||
weight += 1;
|
||||
if (subdomainLength > 30) {
|
||||
weight += 5;
|
||||
if (subdomainLength > 40) {
|
||||
weight += 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (subdomain.indexOf('.', 1) > 1) {
|
||||
weight += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
if (require.main === module) {
|
||||
getPhishingDomains(_trace.dummySpan).catch(console.error).finally(()=>{
|
||||
_trace.dummySpan.stop();
|
||||
(0, _trace.printTraceResult)(_trace.dummySpan.traceResult);
|
||||
});
|
||||
}
|
||||
} (getPhishingDomains.__module, getPhishingDomains.__module.exports));
|
||||
return getPhishingDomains.__module.exports;
|
||||
}exports.__require=requireGetPhishingDomains;
|
||||
396
Dist/Build/lib/is-domain-alive.cjs
Normal file
396
Dist/Build/lib/is-domain-alive.cjs
Normal file
@@ -0,0 +1,396 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const isDomainAlive=require('../../_virtual/is-domain-alive.cjs'),require$$5=require('tldts-experimental'),looseTldtsOpt=require('../constants/loose-tldts-opt.cjs'),require$$0=require('picocolors'),require$$3$1=require('dns2'),require$$4=require('async-retry'),require$$5$1=require('whoiser'),require$$3=require('foxts/retrie'),require$$1=require('node:process');var hasRequiredIsDomainAlive;
|
||||
|
||||
function requireIsDomainAlive () {
|
||||
if (hasRequiredIsDomainAlive) return isDomainAlive.__exports;
|
||||
hasRequiredIsDomainAlive = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
isDomainAlive: function() {
|
||||
return isDomainAlive;
|
||||
},
|
||||
keyedAsyncMutexWithQueue: function() {
|
||||
return keyedAsyncMutexWithQueue;
|
||||
},
|
||||
noWhois: function() {
|
||||
return noWhois;
|
||||
}
|
||||
});
|
||||
const _tldtsexperimental = /*#__PURE__*/ _interop_require_default(require$$5);
|
||||
const _loosetldtsopt = /*@__PURE__*/ looseTldtsOpt.__require();
|
||||
const _picocolors = /*#__PURE__*/ _interop_require_default(require$$0);
|
||||
const _dns2 = /*#__PURE__*/ _interop_require_default(require$$3$1);
|
||||
const _asyncretry = /*#__PURE__*/ _interop_require_default(require$$4);
|
||||
const _whoiser = /*#__PURE__*/ _interop_require_wildcard(require$$5$1);
|
||||
const _retrie = require$$3;
|
||||
const _nodeprocess = /*#__PURE__*/ _interop_require_default(require$$1);
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
function _getRequireWildcardCache(nodeInterop) {
|
||||
if (typeof WeakMap !== "function") return null;
|
||||
var cacheBabelInterop = new WeakMap();
|
||||
var cacheNodeInterop = new WeakMap();
|
||||
return (_getRequireWildcardCache = function(nodeInterop) {
|
||||
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
||||
})(nodeInterop);
|
||||
}
|
||||
function _interop_require_wildcard(obj, nodeInterop) {
|
||||
if (obj && obj.__esModule) {
|
||||
return obj;
|
||||
}
|
||||
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
||||
return {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
var cache = _getRequireWildcardCache(nodeInterop);
|
||||
if (cache && cache.has(obj)) {
|
||||
return cache.get(obj);
|
||||
}
|
||||
var newObj = {
|
||||
__proto__: null
|
||||
};
|
||||
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
||||
for(var key in obj){
|
||||
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
||||
if (desc && (desc.get || desc.set)) {
|
||||
Object.defineProperty(newObj, key, desc);
|
||||
} else {
|
||||
newObj[key] = obj[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
newObj.default = obj;
|
||||
if (cache) {
|
||||
cache.set(obj, newObj);
|
||||
}
|
||||
return newObj;
|
||||
}
|
||||
const mutex = new Map();
|
||||
function keyedAsyncMutexWithQueue(key, fn) {
|
||||
if (mutex.has(key)) {
|
||||
return mutex.get(key);
|
||||
}
|
||||
const promise = fn();
|
||||
mutex.set(key, promise);
|
||||
return promise;
|
||||
}
|
||||
class DnsError extends Error {
|
||||
message;
|
||||
server;
|
||||
name;
|
||||
constructor(message, server){
|
||||
super(message), this.message = message, this.server = server, this.name = 'DnsError';
|
||||
}
|
||||
}
|
||||
const dohServers = [
|
||||
'8.8.8.8',
|
||||
'8.8.4.4',
|
||||
'1.0.0.1',
|
||||
'1.1.1.1',
|
||||
'162.159.36.1',
|
||||
'162.159.46.1',
|
||||
'101.101.101.101',
|
||||
'185.222.222.222',
|
||||
'45.11.45.11',
|
||||
'dns10.quad9.net',
|
||||
'doh.sandbox.opendns.com',
|
||||
'unfiltered.adguard-dns.com',
|
||||
// '0ms.dev', // Proxy Cloudflare
|
||||
// '76.76.2.0', // ControlD unfiltered, path not /dns-query
|
||||
// '76.76.10.0', // ControlD unfiltered, path not /dns-query
|
||||
// 'dns.bebasid.com', // BebasID, path not /dns-query but /unfiltered
|
||||
// '193.110.81.0', // dns0.eu
|
||||
// '185.253.5.0', // dns0.eu
|
||||
// 'zero.dns0.eu',
|
||||
'dns.nextdns.io',
|
||||
'anycast.dns.nextdns.io',
|
||||
'wikimedia-dns.org',
|
||||
// 'ordns.he.net',
|
||||
// 'dns.mullvad.net',
|
||||
'basic.rethinkdns.com',
|
||||
'198.54.117.10' // NameCheap DNS, supports DoT, DoH, UDP53
|
||||
].map((dns)=>[
|
||||
dns,
|
||||
_dns2.default.DOHClient({
|
||||
dns,
|
||||
http: false
|
||||
})
|
||||
]);
|
||||
const domesticDohServers = [
|
||||
'223.5.5.5',
|
||||
'223.6.6.6',
|
||||
'120.53.53.53',
|
||||
'1.12.12.12'
|
||||
].map((dns)=>[
|
||||
dns,
|
||||
_dns2.default.DOHClient({
|
||||
dns,
|
||||
http: false
|
||||
})
|
||||
]);
|
||||
function createResolve(server) {
|
||||
return async (...args)=>{
|
||||
try {
|
||||
return await (0, _asyncretry.default)(async ()=>{
|
||||
const [dohServer, dohClient] = server[Math.floor(Math.random() * server.length)];
|
||||
try {
|
||||
return {
|
||||
...await dohClient(...args),
|
||||
dns: dohServer
|
||||
};
|
||||
} catch (e) {
|
||||
// console.error(e);
|
||||
throw new DnsError(e.message, dohServer);
|
||||
}
|
||||
}, {
|
||||
retries: 5
|
||||
});
|
||||
} catch (e) {
|
||||
console.log('[doh error]', ...args, e);
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
}
|
||||
const resolve = createResolve(dohServers);
|
||||
const domesticResolve = createResolve(domesticDohServers);
|
||||
async function getWhois(domain) {
|
||||
return (0, _asyncretry.default)(()=>_whoiser.domain(domain, {
|
||||
raw: true
|
||||
}), {
|
||||
retries: 5
|
||||
});
|
||||
}
|
||||
const domainAliveMap = new Map();
|
||||
function onDomainAlive(domain) {
|
||||
domainAliveMap.set(domain, true);
|
||||
return [
|
||||
domain,
|
||||
true
|
||||
];
|
||||
}
|
||||
function onDomainDead(domain) {
|
||||
domainAliveMap.set(domain, false);
|
||||
return [
|
||||
domain,
|
||||
false
|
||||
];
|
||||
}
|
||||
async function isDomainAlive(domain, isSuffix) {
|
||||
if (domainAliveMap.has(domain)) {
|
||||
return [
|
||||
domain,
|
||||
domainAliveMap.get(domain)
|
||||
];
|
||||
}
|
||||
const apexDomain = _tldtsexperimental.default.getDomain(domain, _loosetldtsopt.looseTldtsOpt);
|
||||
if (!apexDomain) {
|
||||
console.log(_picocolors.default.gray('[domain invalid]'), _picocolors.default.gray('no apex domain'), {
|
||||
domain
|
||||
});
|
||||
return onDomainAlive(domain);
|
||||
}
|
||||
const apexDomainAlive = await keyedAsyncMutexWithQueue(apexDomain, ()=>isApexDomainAlive(apexDomain));
|
||||
if (isSuffix) {
|
||||
return apexDomainAlive;
|
||||
}
|
||||
if (!apexDomainAlive[1]) {
|
||||
return apexDomainAlive;
|
||||
}
|
||||
const $domain = domain[0] === '.' ? domain.slice(1) : domain;
|
||||
const aDns = [];
|
||||
const aaaaDns = [];
|
||||
// test 2 times before make sure record is empty
|
||||
for(let i = 0; i < 2; i++){
|
||||
// eslint-disable-next-line no-await-in-loop -- sequential
|
||||
const aRecords = await resolve($domain, 'A');
|
||||
if (aRecords.answers.length > 0) {
|
||||
return onDomainAlive(domain);
|
||||
}
|
||||
aDns.push(aRecords.dns);
|
||||
}
|
||||
for(let i = 0; i < 2; i++){
|
||||
// eslint-disable-next-line no-await-in-loop -- sequential
|
||||
const aaaaRecords = await resolve($domain, 'AAAA');
|
||||
if (aaaaRecords.answers.length > 0) {
|
||||
return onDomainAlive(domain);
|
||||
}
|
||||
aaaaDns.push(aaaaRecords.dns);
|
||||
}
|
||||
// only then, let's test once with domesticDohServers
|
||||
const aRecords = await domesticResolve($domain, 'A');
|
||||
if (aRecords.answers.length > 0) {
|
||||
return onDomainAlive(domain);
|
||||
}
|
||||
aDns.push(aRecords.dns);
|
||||
const aaaaRecords = await domesticResolve($domain, 'AAAA');
|
||||
if (aaaaRecords.answers.length > 0) {
|
||||
return onDomainAlive(domain);
|
||||
}
|
||||
aaaaDns.push(aaaaRecords.dns);
|
||||
console.log(_picocolors.default.red('[domain dead]'), 'no A/AAAA records', {
|
||||
domain,
|
||||
a: aDns,
|
||||
aaaa: aaaaDns
|
||||
});
|
||||
return onDomainDead($domain);
|
||||
}
|
||||
const apexDomainNsResolvePromiseMap = new Map();
|
||||
async function isApexDomainAlive(apexDomain) {
|
||||
if (domainAliveMap.has(apexDomain)) {
|
||||
return [
|
||||
apexDomain,
|
||||
domainAliveMap.get(apexDomain)
|
||||
];
|
||||
}
|
||||
let resp;
|
||||
if (apexDomainNsResolvePromiseMap.has(apexDomain)) {
|
||||
resp = await apexDomainNsResolvePromiseMap.get(apexDomain);
|
||||
} else {
|
||||
const promise = resolve(apexDomain, 'NS');
|
||||
apexDomainNsResolvePromiseMap.set(apexDomain, promise);
|
||||
resp = await promise;
|
||||
}
|
||||
if (resp.answers.length > 0) {
|
||||
return onDomainAlive(apexDomain);
|
||||
}
|
||||
let whois;
|
||||
try {
|
||||
whois = await getWhois(apexDomain);
|
||||
} catch (e) {
|
||||
console.log(_picocolors.default.red('[whois error]'), {
|
||||
domain: apexDomain
|
||||
}, e);
|
||||
return onDomainAlive(apexDomain);
|
||||
}
|
||||
if (_nodeprocess.default.env.DEBUG) {
|
||||
console.log(JSON.stringify(whois, null, 2));
|
||||
}
|
||||
const whoisError = noWhois(whois);
|
||||
if (!whoisError) {
|
||||
console.log(_picocolors.default.gray('[domain alive]'), _picocolors.default.gray('whois found'), {
|
||||
domain: apexDomain
|
||||
});
|
||||
return onDomainAlive(apexDomain);
|
||||
}
|
||||
console.log(_picocolors.default.red('[domain dead]'), 'whois not found', {
|
||||
domain: apexDomain,
|
||||
err: whoisError
|
||||
});
|
||||
return onDomainDead(apexDomain);
|
||||
}
|
||||
// TODO: this is a workaround for https://github.com/LayeredStudio/whoiser/issues/117
|
||||
const whoisNotFoundKeywordTest = (0, _retrie.createRetrieKeywordFilter)([
|
||||
'no match for',
|
||||
'does not exist',
|
||||
'not found',
|
||||
'no found',
|
||||
'no entries',
|
||||
'no data found',
|
||||
'is available for registration',
|
||||
'currently available for application',
|
||||
'no matching record',
|
||||
'no information available about domain name',
|
||||
'not been registered',
|
||||
'no match!!',
|
||||
'status: available',
|
||||
' is free',
|
||||
'no object found',
|
||||
'nothing found',
|
||||
'status: free',
|
||||
'pendingdelete',
|
||||
' has been blocked by '
|
||||
]);
|
||||
function noWhois(whois) {
|
||||
let empty = true;
|
||||
for(const key in whois){
|
||||
if (Object.hasOwn(whois, key)) {
|
||||
empty = false;
|
||||
// if (key === 'error') {
|
||||
// // if (
|
||||
// // (typeof whois.error === 'string' && whois.error)
|
||||
// // || (Array.isArray(whois.error) && whois.error.length > 0)
|
||||
// // ) {
|
||||
// // console.error(whois);
|
||||
// // return true;
|
||||
// // }
|
||||
// continue;
|
||||
// }
|
||||
// if (key === 'text') {
|
||||
// if (Array.isArray(whois.text)) {
|
||||
// for (const value of whois.text) {
|
||||
// if (whoisNotFoundKeywordTest(value.toLowerCase())) {
|
||||
// return value;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// continue;
|
||||
// }
|
||||
// if (key === 'Name Server') {
|
||||
// // if (Array.isArray(whois[key]) && whois[key].length === 0) {
|
||||
// // return false;
|
||||
// // }
|
||||
// continue;
|
||||
// }
|
||||
// if (key === 'Domain Status') {
|
||||
// if (Array.isArray(whois[key])) {
|
||||
// for (const status of whois[key]) {
|
||||
// if (status === 'free' || status === 'AVAILABLE') {
|
||||
// return key + ': ' + status;
|
||||
// }
|
||||
// if (whoisNotFoundKeywordTest(status.toLowerCase())) {
|
||||
// return key + ': ' + status;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// continue;
|
||||
// }
|
||||
// if (typeof whois[key] === 'string' && whois[key]) {
|
||||
// if (whoisNotFoundKeywordTest(whois[key].toLowerCase())) {
|
||||
// return key + ': ' + whois[key];
|
||||
// }
|
||||
// continue;
|
||||
// }
|
||||
if (key === '__raw' && typeof whois.__raw === 'string') {
|
||||
const lines = whois.__raw.trim().toLowerCase().replaceAll(/[\t ]+/g, ' ').split(/\r?\n/);
|
||||
if (_nodeprocess.default.env.DEBUG) {
|
||||
console.log({
|
||||
lines
|
||||
});
|
||||
}
|
||||
for (const line of lines){
|
||||
if (whoisNotFoundKeywordTest(line)) {
|
||||
return line;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (typeof whois[key] === 'object' && !Array.isArray(whois[key])) {
|
||||
const tmp = noWhois(whois[key]);
|
||||
if (tmp) {
|
||||
return tmp;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty) {
|
||||
return 'whois is empty';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
} (isDomainAlive.__exports));
|
||||
return isDomainAlive.__exports;
|
||||
}exports.__require=requireIsDomainAlive;
|
||||
35
Dist/Build/lib/memo-promise.cjs
Normal file
35
Dist/Build/lib/memo-promise.cjs
Normal file
@@ -0,0 +1,35 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const memoPromise=require('../../_virtual/memo-promise.cjs');var hasRequiredMemoPromise;
|
||||
|
||||
function requireMemoPromise () {
|
||||
if (hasRequiredMemoPromise) return memoPromise.__exports;
|
||||
hasRequiredMemoPromise = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "createMemoizedPromise", {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return createMemoizedPromise;
|
||||
}
|
||||
});
|
||||
const notError = Symbol('notError');
|
||||
function createMemoizedPromise(fn, /** whether to create promise immediately or only create after first access */ preload = true) {
|
||||
let error = notError;
|
||||
let promise = preload ? fn().catch((e)=>{
|
||||
// Here we record the error so that we can throw it later when the function is called
|
||||
error = e;
|
||||
// Here we make sure the Promise still returns the never type
|
||||
throw e;
|
||||
}) : null;
|
||||
return ()=>{
|
||||
if (error !== notError) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
promise ??= fn();
|
||||
return promise;
|
||||
};
|
||||
}
|
||||
} (memoPromise.__exports));
|
||||
return memoPromise.__exports;
|
||||
}exports.__require=requireMemoPromise;
|
||||
122
Dist/Build/lib/misc.cjs
Normal file
122
Dist/Build/lib/misc.cjs
Normal file
@@ -0,0 +1,122 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const misc=require('../../_virtual/misc.cjs'),require$$0=require('node:path'),require$$1=require('node:fs'),require$$2=require('node:fs/promises');var hasRequiredMisc;
|
||||
|
||||
function requireMisc () {
|
||||
if (hasRequiredMisc) return misc.__exports;
|
||||
hasRequiredMisc = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
fastIpVersion: function() {
|
||||
return fastIpVersion;
|
||||
},
|
||||
fastStringCompare: function() {
|
||||
return fastStringCompare;
|
||||
},
|
||||
isDirectoryEmptySync: function() {
|
||||
return isDirectoryEmptySync;
|
||||
},
|
||||
mkdirp: function() {
|
||||
return mkdirp;
|
||||
},
|
||||
notSupported: function() {
|
||||
return notSupported;
|
||||
},
|
||||
removeFiles: function() {
|
||||
return removeFiles;
|
||||
},
|
||||
withBannerArray: function() {
|
||||
return withBannerArray;
|
||||
},
|
||||
withIdentityContent: function() {
|
||||
return withIdentityContent;
|
||||
},
|
||||
writeFile: function() {
|
||||
return writeFile;
|
||||
}
|
||||
});
|
||||
const _nodepath = require$$0;
|
||||
const _nodefs = /*#__PURE__*/ _interop_require_default(require$$1);
|
||||
const _promises = /*#__PURE__*/ _interop_require_default(require$$2);
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
function fastStringCompare(a, b) {
|
||||
const lenA = a.length;
|
||||
const lenB = b.length;
|
||||
const minLen = lenA < lenB ? lenA : lenB;
|
||||
for(let i = 0; i < minLen; ++i){
|
||||
const ca = a.charCodeAt(i);
|
||||
const cb = b.charCodeAt(i);
|
||||
if (ca > cb) return 1;
|
||||
if (ca < cb) return -1;
|
||||
}
|
||||
if (lenA === lenB) {
|
||||
return 0;
|
||||
}
|
||||
return lenA > lenB ? 1 : -1;
|
||||
}
|
||||
function mkdirp(dir) {
|
||||
if (_nodefs.default.existsSync(dir)) {
|
||||
return;
|
||||
}
|
||||
return _promises.default.mkdir(dir, {
|
||||
recursive: true
|
||||
});
|
||||
}
|
||||
const writeFile = async (destination, input, dir = (0, _nodepath.dirname)(destination))=>{
|
||||
const p = mkdirp(dir);
|
||||
if (p) {
|
||||
await p;
|
||||
}
|
||||
return _promises.default.writeFile(destination, input, {
|
||||
encoding: 'utf-8'
|
||||
});
|
||||
};
|
||||
const removeFiles = async (files)=>Promise.all(files.map((file)=>_promises.default.rm(file, {
|
||||
force: true
|
||||
})));
|
||||
function withBannerArray(title, description, date, content) {
|
||||
return [
|
||||
'#########################################',
|
||||
`# ${title}`,
|
||||
`# Last Updated: ${date.toISOString()}`,
|
||||
`# Size: ${content.length}`,
|
||||
...description.map((line)=>line ? `# ${line}` : '#'),
|
||||
'#########################################',
|
||||
...content,
|
||||
'################## EOF ##################'
|
||||
];
|
||||
}
|
||||
function notSupported(name) {
|
||||
return (...args)=>{
|
||||
console.error(`${name}: not supported.`, args);
|
||||
throw new Error(`${name}: not implemented.`);
|
||||
};
|
||||
}
|
||||
function withIdentityContent(title, description, date, content) {
|
||||
return content;
|
||||
}
|
||||
function isDirectoryEmptySync(path) {
|
||||
const directoryHandle = _nodefs.default.opendirSync(path);
|
||||
try {
|
||||
return directoryHandle.readSync() === null;
|
||||
} finally{
|
||||
directoryHandle.closeSync();
|
||||
}
|
||||
}
|
||||
function fastIpVersion(ip) {
|
||||
return ip.includes(':') ? 6 : ip.includes('.') ? 4 : 0;
|
||||
}
|
||||
} (misc.__exports));
|
||||
return misc.__exports;
|
||||
}exports.__require=requireMisc;
|
||||
79
Dist/Build/lib/normalize-domain.cjs
Normal file
79
Dist/Build/lib/normalize-domain.cjs
Normal file
@@ -0,0 +1,79 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const normalizeDomain=require('../../_virtual/normalize-domain.cjs'),require$$0=require('tldts'),looseTldtsOpt=require('../constants/loose-tldts-opt.cjs'),require$$2=require('foxts/is-probably-ip');var hasRequiredNormalizeDomain;
|
||||
|
||||
function requireNormalizeDomain () {
|
||||
if (hasRequiredNormalizeDomain) return normalizeDomain.__exports;
|
||||
hasRequiredNormalizeDomain = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
fastNormalizeDomain: function() {
|
||||
return fastNormalizeDomain;
|
||||
},
|
||||
fastNormalizeDomainWithoutWww: function() {
|
||||
return fastNormalizeDomainWithoutWww;
|
||||
},
|
||||
normalizeDomain: function() {
|
||||
return normalizeDomain;
|
||||
}
|
||||
});
|
||||
const _tldts = /*#__PURE__*/ _interop_require_default(require$$0);
|
||||
const _loosetldtsopt = /*@__PURE__*/ looseTldtsOpt.__require();
|
||||
const _isprobablyip = require$$2;
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
function fastNormalizeDomainWithoutWww(domain, parsed = null) {
|
||||
// We don't want tldts to call its own "extractHostname" on ip, bail out ip first.
|
||||
// Now ip has been bailed out, we can safely set normalizeTldtsOpt.detectIp to false.
|
||||
if ((0, _isprobablyip.isProbablyIpv4)(domain) || (0, _isprobablyip.isProbablyIpv6)(domain)) {
|
||||
return null;
|
||||
}
|
||||
parsed ??= _tldts.default.parse(domain, _loosetldtsopt.normalizeTldtsOpt);
|
||||
// Private invalid domain (things like .tor, .dn42, etc)
|
||||
if (!parsed.isIcann && !parsed.isPrivate) return null;
|
||||
if (parsed.subdomain) {
|
||||
if (parsed.subdomain === 'www') {
|
||||
return parsed.domain;
|
||||
}
|
||||
if (parsed.subdomain.startsWith('www.')) {
|
||||
return parsed.subdomain.slice(4) + '.' + parsed.domain;
|
||||
}
|
||||
}
|
||||
return parsed.hostname;
|
||||
}
|
||||
function fastNormalizeDomain(domain, parsed = null) {
|
||||
// We don't want tldts to call its own "extractHostname" on ip, bail out ip first.
|
||||
// Now ip has been bailed out, we can safely set normalizeTldtsOpt.detectIp to false.
|
||||
if ((0, _isprobablyip.isProbablyIpv4)(domain) || (0, _isprobablyip.isProbablyIpv6)(domain)) {
|
||||
return null;
|
||||
}
|
||||
parsed ??= _tldts.default.parse(domain, _loosetldtsopt.normalizeTldtsOpt);
|
||||
// Private invalid domain (things like .tor, .dn42, etc)
|
||||
if (!parsed.isIcann && !parsed.isPrivate) return null;
|
||||
return parsed.hostname;
|
||||
}
|
||||
function normalizeDomain(domain, parsed = null) {
|
||||
if (domain.length === 0) return null;
|
||||
if ((0, _isprobablyip.isProbablyIpv4)(domain) || (0, _isprobablyip.isProbablyIpv6)(domain)) {
|
||||
return null;
|
||||
}
|
||||
parsed ??= _tldts.default.parse(domain, _loosetldtsopt.normalizeTldtsOpt);
|
||||
// Private invalid domain (things like .tor, .dn42, etc)
|
||||
if (!parsed.isIcann && !parsed.isPrivate) return null;
|
||||
// const h = parsed.hostname;
|
||||
// if (h === null) return null;
|
||||
return parsed.hostname;
|
||||
}
|
||||
} (normalizeDomain.__exports));
|
||||
return normalizeDomain.__exports;
|
||||
}exports.__require=requireNormalizeDomain;
|
||||
44
Dist/Build/lib/parse-dnsmasq.cjs
Normal file
44
Dist/Build/lib/parse-dnsmasq.cjs
Normal file
@@ -0,0 +1,44 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const parseDnsmasq=require('../../_virtual/parse-dnsmasq.cjs'),fetchTextByLine=require('./fetch-text-by-line.cjs'),normalizeDomain=require('./normalize-domain.cjs');var hasRequiredParseDnsmasq;
|
||||
|
||||
function requireParseDnsmasq () {
|
||||
if (hasRequiredParseDnsmasq) return parseDnsmasq.__exports;
|
||||
hasRequiredParseDnsmasq = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
extractDomainsFromFelixDnsmasq: function() {
|
||||
return extractDomainsFromFelixDnsmasq;
|
||||
},
|
||||
parseFelixDnsmasqFromResp: function() {
|
||||
return parseFelixDnsmasqFromResp;
|
||||
}
|
||||
});
|
||||
const _fetchtextbyline = /*@__PURE__*/ fetchTextByLine.__require();
|
||||
const _normalizedomain = /*@__PURE__*/ normalizeDomain.__require();
|
||||
function extractDomainsFromFelixDnsmasq(line) {
|
||||
if (line.startsWith('server=/') && line.endsWith('/114.114.114.114')) {
|
||||
return line.slice(8, -16);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
async function parseFelixDnsmasqFromResp(resp) {
|
||||
const results = [];
|
||||
for await (const line of (0, _fetchtextbyline.createReadlineInterfaceFromResponse)(resp, true)){
|
||||
const domain = extractDomainsFromFelixDnsmasq(line);
|
||||
if (domain && (0, _normalizedomain.fastNormalizeDomain)(domain)) {
|
||||
results.push(domain);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
} (parseDnsmasq.__exports));
|
||||
return parseDnsmasq.__exports;
|
||||
}exports.__require=requireParseDnsmasq;
|
||||
71
Dist/Build/lib/parse-filter/domainlists.cjs
Normal file
71
Dist/Build/lib/parse-filter/domainlists.cjs
Normal file
@@ -0,0 +1,71 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const domainlists=require('../../../_virtual/domainlists.cjs'),normalizeDomain=require('../normalize-domain.cjs'),processLine=require('../process-line.cjs'),shared=require('./shared.cjs'),fetchAssets=require('../fetch-assets.cjs');var hasRequiredDomainlists;
|
||||
|
||||
function requireDomainlists () {
|
||||
if (hasRequiredDomainlists) return domainlists.__exports;
|
||||
hasRequiredDomainlists = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
processDomainLists: function() {
|
||||
return processDomainLists;
|
||||
},
|
||||
processDomainListsWithPreload: function() {
|
||||
return processDomainListsWithPreload;
|
||||
}
|
||||
});
|
||||
const _normalizedomain = /*@__PURE__*/ normalizeDomain.__require();
|
||||
const _processline = /*@__PURE__*/ processLine.__require();
|
||||
const _shared = /*@__PURE__*/ shared.__require();
|
||||
const _fetchassets = /*@__PURE__*/ fetchAssets.__require();
|
||||
function domainListLineCb(l, set, meta, normalizeDomain = _normalizedomain.fastNormalizeDomain) {
|
||||
const line = (0, _processline.processLine)(l);
|
||||
if (!line) return;
|
||||
const domain = normalizeDomain(line);
|
||||
if (!domain) return;
|
||||
(0, _shared.onBlackFound)(domain, meta);
|
||||
set.push(domain);
|
||||
}
|
||||
function domainListLineCbIncludeAllSubdomain(line, set, meta, normalizeDomain = _normalizedomain.fastNormalizeDomain) {
|
||||
const domain = normalizeDomain(line);
|
||||
if (!domain) return;
|
||||
(0, _shared.onBlackFound)(domain, meta);
|
||||
set.push('.' + domain);
|
||||
}
|
||||
function processDomainLists(span, domainListsUrl, mirrors, includeAllSubDomain = false) {
|
||||
const lineCb = includeAllSubDomain ? domainListLineCbIncludeAllSubdomain : domainListLineCb;
|
||||
return span.traceChildAsync(`process domainlist: ${domainListsUrl}`, async (span)=>{
|
||||
const filterRules = await span.traceChildAsync('download', ()=>(0, _fetchassets.fetchAssets)(domainListsUrl, mirrors, true));
|
||||
const domainSets = [];
|
||||
span.traceChildSync('parse domain list', ()=>{
|
||||
for(let i = 0, len = filterRules.length; i < len; i++){
|
||||
lineCb(filterRules[i], domainSets, domainListsUrl, _normalizedomain.fastNormalizeDomainWithoutWww);
|
||||
}
|
||||
});
|
||||
return domainSets;
|
||||
});
|
||||
}
|
||||
function processDomainListsWithPreload(domainListsUrl, mirrors, includeAllSubDomain = false) {
|
||||
const downloadPromise = (0, _fetchassets.fetchAssets)(domainListsUrl, mirrors, true);
|
||||
const lineCb = includeAllSubDomain ? domainListLineCbIncludeAllSubdomain : domainListLineCb;
|
||||
return (span)=>span.traceChildAsync(`process domainlist: ${domainListsUrl}`, async (span)=>{
|
||||
const filterRules = await span.traceChildPromise('download', downloadPromise);
|
||||
const domainSets = [];
|
||||
span.traceChildSync('parse domain list', ()=>{
|
||||
for(let i = 0, len = filterRules.length; i < len; i++){
|
||||
lineCb(filterRules[i], domainSets, domainListsUrl, _normalizedomain.fastNormalizeDomainWithoutWww);
|
||||
}
|
||||
});
|
||||
return domainSets;
|
||||
});
|
||||
}
|
||||
} (domainlists.__exports));
|
||||
return domainlists.__exports;
|
||||
}exports.__require=requireDomainlists;
|
||||
372
Dist/Build/lib/parse-filter/filters.cjs
Normal file
372
Dist/Build/lib/parse-filter/filters.cjs
Normal file
@@ -0,0 +1,372 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const filters=require('../../../_virtual/filters.cjs'),require$$0=require('picocolors'),fetchAssets=require('../fetch-assets.cjs'),shared=require('./shared.cjs'),require$$3=require('foxts/retrie'),looseTldtsOpt=require('../../constants/loose-tldts-opt.cjs'),require$$5=require('tldts-experimental'),require$$6=require('@ghostery/adblocker'),normalizeDomain=require('../normalize-domain.cjs');var hasRequiredFilters;
|
||||
|
||||
function requireFilters () {
|
||||
if (hasRequiredFilters) return filters.__exports;
|
||||
hasRequiredFilters = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
parse: function() {
|
||||
return parse;
|
||||
},
|
||||
processFilterRulesWithPreload: function() {
|
||||
return processFilterRulesWithPreload;
|
||||
}
|
||||
});
|
||||
const _picocolors = /*#__PURE__*/ _interop_require_default(require$$0);
|
||||
const _fetchassets = /*@__PURE__*/ fetchAssets.__require();
|
||||
const _shared = /*@__PURE__*/ shared.__require();
|
||||
const _retrie = require$$3;
|
||||
const _loosetldtsopt = /*@__PURE__*/ looseTldtsOpt.__require();
|
||||
const _tldtsexperimental = /*#__PURE__*/ _interop_require_default(require$$5);
|
||||
const _adblocker = require$$6;
|
||||
const _normalizedomain = /*@__PURE__*/ normalizeDomain.__require();
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
function processFilterRulesWithPreload(filterRulesUrl, fallbackUrls, includeThirdParty = false) {
|
||||
const downloadPromise = (0, _fetchassets.fetchAssets)(filterRulesUrl, fallbackUrls);
|
||||
return (span)=>span.traceChildAsync(`process filter rules: ${filterRulesUrl}`, async (span)=>{
|
||||
const filterRules = await span.traceChildPromise('download', downloadPromise);
|
||||
const whiteDomains = new Set();
|
||||
const whiteDomainSuffixes = new Set();
|
||||
const blackDomains = new Set();
|
||||
const blackDomainSuffixes = new Set();
|
||||
const warningMessages = [];
|
||||
const MUTABLE_PARSE_LINE_RESULT = [
|
||||
'',
|
||||
2000
|
||||
];
|
||||
/**
|
||||
* @param {string} line
|
||||
*/ const lineCb = (line)=>{
|
||||
const result = parse(line, MUTABLE_PARSE_LINE_RESULT, includeThirdParty);
|
||||
const flag = result[1];
|
||||
if (flag === 2000) {
|
||||
throw new Error(`Didn't parse line: ${line}`);
|
||||
}
|
||||
if (flag === 1000) {
|
||||
return;
|
||||
}
|
||||
const hostname = result[0];
|
||||
if (flag === 0 || flag === -1) {
|
||||
(0, _shared.onWhiteFound)(hostname, filterRulesUrl);
|
||||
} else {
|
||||
(0, _shared.onBlackFound)(hostname, filterRulesUrl);
|
||||
}
|
||||
switch(flag){
|
||||
case 0:
|
||||
whiteDomainSuffixes.add(hostname);
|
||||
break;
|
||||
case -1:
|
||||
whiteDomains.add(hostname);
|
||||
break;
|
||||
case 2:
|
||||
blackDomainSuffixes.add(hostname);
|
||||
break;
|
||||
case 1:
|
||||
blackDomains.add(hostname);
|
||||
break;
|
||||
case 10:
|
||||
warningMessages.push(hostname);
|
||||
break;
|
||||
}
|
||||
};
|
||||
span.traceChild('parse adguard filter').traceSyncFn(()=>{
|
||||
for(let i = 0, len = filterRules.length; i < len; i++){
|
||||
lineCb(filterRules[i]);
|
||||
}
|
||||
});
|
||||
for(let i = 0, len = warningMessages.length; i < len; i++){
|
||||
console.warn(_picocolors.default.yellow(warningMessages[i]), _picocolors.default.gray(_picocolors.default.underline(filterRulesUrl)));
|
||||
}
|
||||
console.log(_picocolors.default.gray('[process filter]'), _picocolors.default.gray(filterRulesUrl), _picocolors.default.gray(`white: ${whiteDomains.size + whiteDomainSuffixes.size}`), _picocolors.default.gray(`black: ${blackDomains.size + blackDomainSuffixes.size}`));
|
||||
return {
|
||||
whiteDomains: Array.from(whiteDomains),
|
||||
whiteDomainSuffixes: Array.from(whiteDomainSuffixes),
|
||||
blackDomains: Array.from(blackDomains),
|
||||
blackDomainSuffixes: Array.from(blackDomainSuffixes)
|
||||
};
|
||||
});
|
||||
}
|
||||
// many filter that has modifiers can not work on Surge/Clash because browser context is required
|
||||
// we can early bail out those rules
|
||||
const kwfilter = (0, _retrie.createRetrieKeywordFilter)([
|
||||
'!',
|
||||
'?',
|
||||
'*',
|
||||
'[',
|
||||
'(',
|
||||
']',
|
||||
')',
|
||||
',',
|
||||
'#',
|
||||
'%',
|
||||
'&',
|
||||
'=',
|
||||
'~',
|
||||
// special modifier
|
||||
'$popup',
|
||||
'$removeparam',
|
||||
'$redirect',
|
||||
'$popunder',
|
||||
'$cname',
|
||||
'$frame',
|
||||
'$domain',
|
||||
'$from',
|
||||
'$to',
|
||||
'$csp',
|
||||
'$replace',
|
||||
'$urlskip',
|
||||
// some bad syntax
|
||||
'^popup'
|
||||
]);
|
||||
function parse($line, result, includeThirdParty) {
|
||||
if (// doesn't include
|
||||
!$line.includes('.') // rule with out dot can not be a domain
|
||||
|| kwfilter($line)) {
|
||||
result[1] = 1000;
|
||||
return result;
|
||||
}
|
||||
const line = $line.trim();
|
||||
if (line.length === 0) {
|
||||
result[1] = 1000;
|
||||
return result;
|
||||
}
|
||||
const firstCharCode = line.charCodeAt(0);
|
||||
const lastCharCode = line.charCodeAt(line.length - 1);
|
||||
if (firstCharCode === 47 // 47 `/`
|
||||
|| lastCharCode === 46 // 46 `.`, line.endsWith('.')
|
||||
|| lastCharCode === 45 // 45 `-`, line.endsWith('-')
|
||||
|| lastCharCode === 95 // 95 `_`, line.endsWith('_')
|
||||
) {
|
||||
result[1] = 1000;
|
||||
return result;
|
||||
}
|
||||
if ((line.includes('/') || line.includes(':')) && !line.includes('://')) {
|
||||
result[1] = 1000;
|
||||
return result;
|
||||
}
|
||||
const filter = _adblocker.NetworkFilter.parse(line);
|
||||
if (filter) {
|
||||
if (// filter.isCosmeticFilter() // always false
|
||||
// filter.isNetworkFilter() // always true
|
||||
filter.isElemHide() || filter.isGenericHide() || filter.isSpecificHide() || filter.isRedirect() || filter.isRedirectRule() || filter.hasDomains() || filter.isCSP() // must not be csp rule
|
||||
|| !filter.fromHttp() && !filter.fromHttps()) {
|
||||
// not supported type
|
||||
result[1] = 1000;
|
||||
return result;
|
||||
}
|
||||
if (!filter.fromAny() && !filter.fromDocument() // $document, $doc
|
||||
) {
|
||||
result[1] = 1000;
|
||||
return result;
|
||||
}
|
||||
if (filter.hostname // filter.hasHostname() // must have
|
||||
&& filter.isPlain() // isPlain() === !isRegex()
|
||||
&& !filter.isFullRegex()) {
|
||||
const hostname = (0, _normalizedomain.fastNormalizeDomainWithoutWww)(filter.hostname);
|
||||
if (!hostname) {
|
||||
result[1] = 1000;
|
||||
return result;
|
||||
}
|
||||
// |: filter.isHostnameAnchor(),
|
||||
// |: filter.isLeftAnchor(),
|
||||
// |https://: !filter.isHostnameAnchor() && (filter.fromHttps() || filter.fromHttp())
|
||||
const isIncludeAllSubDomain = filter.isHostnameAnchor();
|
||||
if (filter.isException() || filter.isBadFilter()) {
|
||||
result[0] = hostname;
|
||||
result[1] = isIncludeAllSubDomain ? 0 : -1;
|
||||
return result;
|
||||
}
|
||||
const _1p = filter.firstParty();
|
||||
const _3p = filter.thirdParty();
|
||||
if (_1p) {
|
||||
if (_3p) {
|
||||
result[0] = hostname;
|
||||
result[1] = isIncludeAllSubDomain ? 2 : 1;
|
||||
return result;
|
||||
}
|
||||
result[1] = 1000;
|
||||
return result;
|
||||
}
|
||||
if (_3p) {
|
||||
if (includeThirdParty) {
|
||||
result[0] = hostname;
|
||||
result[1] = isIncludeAllSubDomain ? 2 : 1;
|
||||
return result;
|
||||
}
|
||||
result[1] = 1000;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* From now on, we are mostly facing non-standard domain rules (some are regex like)
|
||||
*
|
||||
* We can still salvage some of them by removing modifiers
|
||||
*/ let sliceStart = 0;
|
||||
let sliceEnd = 0;
|
||||
// After NetworkFilter.parse, it means the line can not be parsed by cliqz NetworkFilter
|
||||
// We now need to "salvage" the line as much as possible
|
||||
let white = false;
|
||||
let includeAllSubDomain = false;
|
||||
if (firstCharCode === 64 // 64 `@`
|
||||
&& line.charCodeAt(1) === 64 // 64 `@`
|
||||
) {
|
||||
sliceStart += 2;
|
||||
white = true;
|
||||
includeAllSubDomain = true;
|
||||
}
|
||||
/**
|
||||
* Some "malformed" regex-based filters can not be parsed by NetworkFilter
|
||||
* "$genericblock`" is also not supported by NetworkFilter, see:
|
||||
* https://github.com/ghostery/adblocker/blob/62caf7786ba10ef03beffecd8cd4eec111bcd5ec/packages/adblocker/test/parsing.test.ts#L950
|
||||
*
|
||||
* `@@||cmechina.net^$genericblock`
|
||||
* `@@|ftp.bmp.ovh^|`
|
||||
* `@@|adsterra.com^|`
|
||||
* `@@.atlassian.net$document`
|
||||
* `@@||ad.alimama.com^$genericblock`
|
||||
*/ switch(line.charCodeAt(sliceStart)){
|
||||
case 124:
|
||||
/** | */ // line.startsWith('@@|') || line.startsWith('|')
|
||||
sliceStart += 1;
|
||||
includeAllSubDomain = false;
|
||||
if (line[sliceStart] === '|') {
|
||||
sliceStart += 1;
|
||||
includeAllSubDomain = true;
|
||||
}
|
||||
break;
|
||||
case 46:
|
||||
{
|
||||
/**
|
||||
* `.ay.delivery^`
|
||||
* `.m.bookben.com^`
|
||||
* `.wap.x4399.com^`
|
||||
*/ sliceStart += 1;
|
||||
includeAllSubDomain = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch(line.charCodeAt(sliceStart)){
|
||||
case 58:
|
||||
{
|
||||
/**
|
||||
* `@@://googleadservices.com^|`
|
||||
* `@@://www.googleadservices.com^|`
|
||||
* `://mine.torrent.pw^`
|
||||
* `://say.ac^`
|
||||
*/ if (line[sliceStart + 1] === '/' && line[sliceStart + 2] === '/') {
|
||||
includeAllSubDomain = false;
|
||||
sliceStart += 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 104:
|
||||
{
|
||||
/** |http://x.o2.pl^ */ if (line.startsWith('http://', sliceStart)) {
|
||||
includeAllSubDomain = false;
|
||||
sliceStart += 7;
|
||||
} else if (line.startsWith('https://', sliceStart)) {
|
||||
includeAllSubDomain = false;
|
||||
sliceStart += 8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
const indexOfDollar = line.indexOf('$', sliceStart);
|
||||
if (indexOfDollar > -1) {
|
||||
sliceEnd = indexOfDollar - line.length;
|
||||
}
|
||||
/*
|
||||
* We skip third-party and frame rules, as Surge / Clash can't handle them
|
||||
*
|
||||
* `.sharecounter.$third-party`
|
||||
* `.bbelements.com^$third-party`
|
||||
* `://o0e.ru^$third-party`
|
||||
* `.1.1.1.l80.js^$third-party`
|
||||
*/ if (!includeThirdParty && (line.includes('third-party', indexOfDollar + 1) || line.includes('3p', indexOfDollar + 1))) {
|
||||
result[1] = 1000;
|
||||
return result;
|
||||
}
|
||||
if (line.includes('badfilter', indexOfDollar + 1)) {
|
||||
white = true;
|
||||
}
|
||||
if (line.includes('all', indexOfDollar + 1)) {
|
||||
includeAllSubDomain = true;
|
||||
}
|
||||
/**
|
||||
* `_vmind.qqvideo.tc.qq.com^`
|
||||
* `arketing.indianadunes.com^`
|
||||
* `charlestownwyllie.oaklawnnonantum.com^`
|
||||
* `-telemetry.officeapps.live.com^`
|
||||
* `-tracker.biliapi.net`
|
||||
* `-logging.nextmedia.com`
|
||||
* `_social_tracking.js^`
|
||||
*/ if (line.charCodeAt(line.length + sliceEnd - 1) === 94) {
|
||||
/** line.endsWith('^') */ sliceEnd -= 1;
|
||||
} else if (line.charCodeAt(line.length + sliceEnd - 1) === 124) {
|
||||
/** line.endsWith('|') */ sliceEnd -= 1;
|
||||
if (line.charCodeAt(line.length + sliceEnd - 1) === 94) {
|
||||
/** line.endsWith('^|') */ sliceEnd -= 1;
|
||||
}
|
||||
} else if (line.charCodeAt(line.length + sliceEnd - 1) === 46) {
|
||||
/** line.endsWith('.') */ sliceEnd -= 1;
|
||||
}
|
||||
const sliced = sliceStart > 0 || sliceEnd < 0 ? line.slice(sliceStart, sliceEnd === 0 ? undefined : sliceEnd) : line;
|
||||
if (sliced.length === 0 || sliced.includes('/')) {
|
||||
result[1] = 1000;
|
||||
return result;
|
||||
}
|
||||
if (sliced.charCodeAt(0) === 45 /* - */ ) {
|
||||
// line.startsWith('-') is not a valid domain
|
||||
result[1] = 10;
|
||||
result[0] = `[parse-filter E0001] (${white ? 'white' : 'black'}) invalid domain: ${JSON.stringify({
|
||||
line,
|
||||
sliced,
|
||||
sliceStart,
|
||||
sliceEnd
|
||||
})}`;
|
||||
return result;
|
||||
}
|
||||
const suffix = _tldtsexperimental.default.getPublicSuffix(sliced, _loosetldtsopt.looseTldtsOpt);
|
||||
if (!suffix) {
|
||||
// This exclude domain-like resource like `_social_tracking.js^`
|
||||
result[1] = 1000;
|
||||
return result;
|
||||
}
|
||||
const domain = (0, _normalizedomain.fastNormalizeDomainWithoutWww)(sliced);
|
||||
if (domain && domain === sliced) {
|
||||
result[0] = domain;
|
||||
if (white) {
|
||||
result[1] = includeAllSubDomain ? 0 : -1;
|
||||
} else {
|
||||
result[1] = includeAllSubDomain ? 2 : 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
result[0] = `[parse-filter E0010] (${white ? 'white' : 'black'}) invalid domain: ${JSON.stringify({
|
||||
line,
|
||||
domain,
|
||||
suffix,
|
||||
sliced,
|
||||
sliceStart,
|
||||
sliceEnd
|
||||
})}`;
|
||||
result[1] = 10;
|
||||
return result;
|
||||
}
|
||||
} (filters.__exports));
|
||||
return filters.__exports;
|
||||
}exports.__require=requireFilters;
|
||||
66
Dist/Build/lib/parse-filter/hosts.cjs
Normal file
66
Dist/Build/lib/parse-filter/hosts.cjs
Normal file
@@ -0,0 +1,66 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const hosts=require('../../../_virtual/hosts.cjs'),fetchAssets=require('../fetch-assets.cjs'),normalizeDomain=require('../normalize-domain.cjs'),shared=require('./shared.cjs');var hasRequiredHosts;
|
||||
|
||||
function requireHosts () {
|
||||
if (hasRequiredHosts) return hosts.__exports;
|
||||
hasRequiredHosts = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
processHosts: function() {
|
||||
return processHosts;
|
||||
},
|
||||
processHostsWithPreload: function() {
|
||||
return processHostsWithPreload;
|
||||
}
|
||||
});
|
||||
const _fetchassets = /*@__PURE__*/ fetchAssets.__require();
|
||||
const _normalizedomain = /*@__PURE__*/ normalizeDomain.__require();
|
||||
const _shared = /*@__PURE__*/ shared.__require();
|
||||
function hostsLineCb(line, set, includeAllSubDomain, meta) {
|
||||
const _domain = line.split(/\s/)[1]?.trim();
|
||||
if (!_domain) {
|
||||
return;
|
||||
}
|
||||
const domain = (0, _normalizedomain.fastNormalizeDomainWithoutWww)(_domain);
|
||||
if (!domain) {
|
||||
return;
|
||||
}
|
||||
(0, _shared.onBlackFound)(domain, meta);
|
||||
set.push(includeAllSubDomain ? `.${domain}` : domain);
|
||||
}
|
||||
function processHosts(span, hostsUrl, mirrors, includeAllSubDomain = false) {
|
||||
return span.traceChildAsync(`process hosts: ${hostsUrl}`, async (span)=>{
|
||||
const filterRules = await span.traceChild('download').traceAsyncFn(()=>(0, _fetchassets.fetchAssets)(hostsUrl, mirrors, true));
|
||||
const domainSets = [];
|
||||
span.traceChild('parse hosts').traceSyncFn(()=>{
|
||||
for(let i = 0, len = filterRules.length; i < len; i++){
|
||||
hostsLineCb(filterRules[i], domainSets, includeAllSubDomain, hostsUrl);
|
||||
}
|
||||
});
|
||||
return domainSets;
|
||||
});
|
||||
}
|
||||
function processHostsWithPreload(hostsUrl, mirrors, includeAllSubDomain = false) {
|
||||
const downloadPromise = (0, _fetchassets.fetchAssets)(hostsUrl, mirrors, true);
|
||||
return (span)=>span.traceChildAsync(`process hosts: ${hostsUrl}`, async (span)=>{
|
||||
const filterRules = await span.traceChild('download').tracePromise(downloadPromise);
|
||||
const domainSets = [];
|
||||
span.traceChild('parse hosts').traceSyncFn(()=>{
|
||||
for(let i = 0, len = filterRules.length; i < len; i++){
|
||||
hostsLineCb(filterRules[i], domainSets, includeAllSubDomain, hostsUrl);
|
||||
}
|
||||
});
|
||||
return domainSets;
|
||||
});
|
||||
}
|
||||
} (hosts.__exports));
|
||||
return hosts.__exports;
|
||||
}exports.__require=requireHosts;
|
||||
52
Dist/Build/lib/parse-filter/shared.cjs
Normal file
52
Dist/Build/lib/parse-filter/shared.cjs
Normal file
@@ -0,0 +1,52 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const shared=require('../../../_virtual/shared.cjs'),require$$0=require('picocolors'),rejectDataSource=require('../../constants/reject-data-source.cjs'),require$$2=require('foxts/noop');var hasRequiredShared;
|
||||
|
||||
function requireShared () {
|
||||
if (hasRequiredShared) return shared.__exports;
|
||||
hasRequiredShared = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
foundDebugDomain: function() {
|
||||
return foundDebugDomain;
|
||||
},
|
||||
onBlackFound: function() {
|
||||
return onBlackFound;
|
||||
},
|
||||
onWhiteFound: function() {
|
||||
return onWhiteFound;
|
||||
}
|
||||
});
|
||||
const _picocolors = /*#__PURE__*/ _interop_require_default(require$$0);
|
||||
const _rejectdatasource = /*@__PURE__*/ rejectDataSource.__require();
|
||||
const _noop = require$$2;
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
const foundDebugDomain = {
|
||||
value: false
|
||||
};
|
||||
const onBlackFound = _rejectdatasource.DEBUG_DOMAIN_TO_FIND ? (line, meta)=>{
|
||||
if (line.includes(_rejectdatasource.DEBUG_DOMAIN_TO_FIND)) {
|
||||
console.warn(_picocolors.default.red(meta), '(black)', line.replaceAll(_rejectdatasource.DEBUG_DOMAIN_TO_FIND, _picocolors.default.bold(_rejectdatasource.DEBUG_DOMAIN_TO_FIND)));
|
||||
foundDebugDomain.value = true;
|
||||
}
|
||||
} : _noop.noop;
|
||||
const onWhiteFound = _rejectdatasource.DEBUG_DOMAIN_TO_FIND ? (line, meta)=>{
|
||||
if (line.includes(_rejectdatasource.DEBUG_DOMAIN_TO_FIND)) {
|
||||
console.warn(_picocolors.default.red(meta), '(white)', line.replaceAll(_rejectdatasource.DEBUG_DOMAIN_TO_FIND, _picocolors.default.bold(_rejectdatasource.DEBUG_DOMAIN_TO_FIND)));
|
||||
foundDebugDomain.value = true;
|
||||
}
|
||||
} : _noop.noop;
|
||||
} (shared.__exports));
|
||||
return shared.__exports;
|
||||
}exports.__require=requireShared;
|
||||
79
Dist/Build/lib/process-line.cjs
Normal file
79
Dist/Build/lib/process-line.cjs
Normal file
@@ -0,0 +1,79 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const processLine=require('../../_virtual/process-line.cjs'),require$$0=require('node:stream/web');var hasRequiredProcessLine;
|
||||
|
||||
function requireProcessLine () {
|
||||
if (hasRequiredProcessLine) return processLine.__exports;
|
||||
hasRequiredProcessLine = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
ProcessLineStream: function() {
|
||||
return ProcessLineStream;
|
||||
},
|
||||
processLine: function() {
|
||||
return processLine;
|
||||
}
|
||||
});
|
||||
const _web = require$$0;
|
||||
function processLine(line) {
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const line_0 = trimmed.charCodeAt(0);
|
||||
if (// line_0 === 32 /** [space] */
|
||||
// || line_0 === 13 /** \r */
|
||||
// || line_0 === 10 /** \n */
|
||||
line_0 === 33 /** ! */ || line_0 === 47 /** / */ && trimmed.charCodeAt(1) === 47 /** / */ ) {
|
||||
return null;
|
||||
}
|
||||
if (line_0 === 35 /** # */ ) {
|
||||
if (trimmed.charCodeAt(1) !== 35 /** # */ ) {
|
||||
// # Comment
|
||||
return null;
|
||||
}
|
||||
if (trimmed.charCodeAt(2) === 35 /** # */ && trimmed.charCodeAt(3) === 35) {
|
||||
// ################## EOF ##################
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* AdGuard Filter can be:
|
||||
*
|
||||
* ##.class
|
||||
* ##tag.class
|
||||
* ###id
|
||||
*/ }
|
||||
return trimmed;
|
||||
}
|
||||
class ProcessLineStream extends _web.TransformStream {
|
||||
// private __buf = '';
|
||||
constructor(){
|
||||
super({
|
||||
transform (l, controller) {
|
||||
const line = processLine(l);
|
||||
if (line) {
|
||||
controller.enqueue(line);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} // export class ProcessLineNodeStream extends Transform {
|
||||
// _transform(chunk: string, encoding: BufferEncoding, callback: TransformCallback) {
|
||||
// // Convert chunk to string and then to uppercase
|
||||
// const upperCased = chunk.toUpperCase();
|
||||
// // Push transformed data to readable side
|
||||
// this.push(upperCased);
|
||||
// // Call callback when done
|
||||
// callback();
|
||||
// }
|
||||
// }
|
||||
} (processLine.__exports));
|
||||
return processLine.__exports;
|
||||
}exports.__require=requireProcessLine;
|
||||
469
Dist/Build/lib/rules/base.cjs
Normal file
469
Dist/Build/lib/rules/base.cjs
Normal file
@@ -0,0 +1,469 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const base=require('../../../_virtual/base.cjs'),trie=require('../trie.cjs'),require$$6=require('foxts/guard'),require$$2=require('fast-cidr-tools'),require$$3=require('foxts/retrie'),require$$0=require('node:path'),surge=require('../writing-strategy/surge.cjs');var hasRequiredBase;
|
||||
|
||||
function requireBase () {
|
||||
if (hasRequiredBase) return base.__exports;
|
||||
hasRequiredBase = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "FileOutput", {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return FileOutput;
|
||||
}
|
||||
});
|
||||
const _trie = /*@__PURE__*/ trie.__require();
|
||||
const _guard = require$$6;
|
||||
const _fastcidrtools = require$$2;
|
||||
const _retrie = require$$3;
|
||||
const _nodepath = /*#__PURE__*/ _interop_require_default(require$$0);
|
||||
const _surge = /*@__PURE__*/ surge.__require();
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
class FileOutput {
|
||||
id;
|
||||
strategies;
|
||||
domainTrie;
|
||||
domainKeywords;
|
||||
domainWildcard;
|
||||
userAgent;
|
||||
processName;
|
||||
processPath;
|
||||
urlRegex;
|
||||
ipcidr;
|
||||
ipcidrNoResolve;
|
||||
ipasn;
|
||||
ipasnNoResolve;
|
||||
ipcidr6;
|
||||
ipcidr6NoResolve;
|
||||
geoip;
|
||||
groipNoResolve;
|
||||
sourceIpOrCidr;
|
||||
sourcePort;
|
||||
destPort;
|
||||
otherRules;
|
||||
pendingPromise;
|
||||
whitelistDomain;
|
||||
span;
|
||||
constructor($span, id){
|
||||
this.id = id;
|
||||
this.strategies = [];
|
||||
this.domainTrie = new _trie.HostnameSmolTrie(null);
|
||||
this.domainKeywords = new Set();
|
||||
this.domainWildcard = new Set();
|
||||
this.userAgent = new Set();
|
||||
this.processName = new Set();
|
||||
this.processPath = new Set();
|
||||
this.urlRegex = new Set();
|
||||
this.ipcidr = new Set();
|
||||
this.ipcidrNoResolve = new Set();
|
||||
this.ipasn = new Set();
|
||||
this.ipasnNoResolve = new Set();
|
||||
this.ipcidr6 = new Set();
|
||||
this.ipcidr6NoResolve = new Set();
|
||||
this.geoip = new Set();
|
||||
this.groipNoResolve = new Set();
|
||||
this.sourceIpOrCidr = new Set();
|
||||
this.sourcePort = new Set();
|
||||
this.destPort = new Set();
|
||||
this.otherRules = [];
|
||||
this.pendingPromise = null;
|
||||
this.whitelistDomain = (domain)=>{
|
||||
this.domainTrie.whitelist(domain);
|
||||
return this;
|
||||
};
|
||||
this.title = null;
|
||||
this.description = null;
|
||||
this.date = new Date();
|
||||
this.strategiesWritten = false;
|
||||
this.span = $span.traceChild('RuleOutput#' + id);
|
||||
}
|
||||
title;
|
||||
withTitle(title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
withStrategies(strategies) {
|
||||
this.strategies = strategies;
|
||||
return this;
|
||||
}
|
||||
withExtraStrategies(strategy) {
|
||||
if (strategy) {
|
||||
this.strategies.push(strategy);
|
||||
}
|
||||
}
|
||||
description;
|
||||
withDescription(description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
date;
|
||||
withDate(date) {
|
||||
this.date = date;
|
||||
return this;
|
||||
}
|
||||
addDomain(domain) {
|
||||
this.domainTrie.add(domain);
|
||||
return this;
|
||||
}
|
||||
bulkAddDomain(domains) {
|
||||
let d;
|
||||
for(let i = 0, len = domains.length; i < len; i++){
|
||||
d = domains[i];
|
||||
if (d !== null) {
|
||||
this.domainTrie.add(d, false, null, 0);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
addDomainSuffix(domain, lineFromDot = domain[0] === '.') {
|
||||
this.domainTrie.add(domain, true, lineFromDot ? 1 : 0);
|
||||
return this;
|
||||
}
|
||||
bulkAddDomainSuffix(domains) {
|
||||
for(let i = 0, len = domains.length; i < len; i++){
|
||||
this.addDomainSuffix(domains[i]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
addDomainKeyword(keyword) {
|
||||
this.domainKeywords.add(keyword);
|
||||
return this;
|
||||
}
|
||||
addIPASN(asn) {
|
||||
this.ipasn.add(asn);
|
||||
return this;
|
||||
}
|
||||
bulkAddIPASN(asns) {
|
||||
for(let i = 0, len = asns.length; i < len; i++){
|
||||
this.ipasn.add(asns[i]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
async addFromDomainsetPromise(source) {
|
||||
for await (const line of source){
|
||||
if (line[0] === '.') {
|
||||
this.addDomainSuffix(line, true);
|
||||
} else {
|
||||
this.domainTrie.add(line, false, null, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
addFromDomainset(source) {
|
||||
if (this.pendingPromise) {
|
||||
if ('then' in source) {
|
||||
this.pendingPromise = this.pendingPromise.then(()=>source).then((src)=>this.addFromDomainsetPromise(src));
|
||||
return this;
|
||||
}
|
||||
this.pendingPromise = this.pendingPromise.then(()=>this.addFromDomainsetPromise(source));
|
||||
return this;
|
||||
}
|
||||
if ('then' in source) {
|
||||
this.pendingPromise = source.then((src)=>this.addFromDomainsetPromise(src));
|
||||
return this;
|
||||
}
|
||||
this.pendingPromise = this.addFromDomainsetPromise(source);
|
||||
return this;
|
||||
}
|
||||
async addFromRulesetPromise(source) {
|
||||
for await (const line of source){
|
||||
const splitted = line.split(',');
|
||||
const type = splitted[0];
|
||||
const value = splitted[1];
|
||||
const arg = splitted[2];
|
||||
switch(type){
|
||||
case 'DOMAIN':
|
||||
this.domainTrie.add(value, false, null, 0);
|
||||
break;
|
||||
case 'DOMAIN-SUFFIX':
|
||||
this.addDomainSuffix(value, false);
|
||||
break;
|
||||
case 'DOMAIN-KEYWORD':
|
||||
this.addDomainKeyword(value);
|
||||
break;
|
||||
case 'DOMAIN-WILDCARD':
|
||||
this.domainWildcard.add(value);
|
||||
break;
|
||||
case 'USER-AGENT':
|
||||
this.userAgent.add(value);
|
||||
break;
|
||||
case 'PROCESS-NAME':
|
||||
if (value.includes('/') || value.includes('\\')) {
|
||||
this.processPath.add(value);
|
||||
} else {
|
||||
this.processName.add(value);
|
||||
}
|
||||
break;
|
||||
case 'URL-REGEX':
|
||||
{
|
||||
const [, ...rest] = splitted;
|
||||
this.urlRegex.add(rest.join(','));
|
||||
break;
|
||||
}
|
||||
case 'IP-CIDR':
|
||||
(arg === 'no-resolve' ? this.ipcidrNoResolve : this.ipcidr).add(value);
|
||||
break;
|
||||
case 'IP-CIDR6':
|
||||
(arg === 'no-resolve' ? this.ipcidr6NoResolve : this.ipcidr6).add(value);
|
||||
break;
|
||||
case 'IP-ASN':
|
||||
(arg === 'no-resolve' ? this.ipasnNoResolve : this.ipasn).add(value);
|
||||
break;
|
||||
case 'GEOIP':
|
||||
(arg === 'no-resolve' ? this.groipNoResolve : this.geoip).add(value);
|
||||
break;
|
||||
case 'SRC-IP':
|
||||
this.sourceIpOrCidr.add(value);
|
||||
break;
|
||||
case 'SRC-PORT':
|
||||
this.sourcePort.add(value);
|
||||
break;
|
||||
case 'DEST-PORT':
|
||||
this.destPort.add(value);
|
||||
break;
|
||||
default:
|
||||
this.otherRules.push(line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
addFromRuleset(source) {
|
||||
if (this.pendingPromise) {
|
||||
if ('then' in source) {
|
||||
this.pendingPromise = this.pendingPromise.then(()=>source).then((src)=>this.addFromRulesetPromise(src));
|
||||
return this;
|
||||
}
|
||||
this.pendingPromise = this.pendingPromise.then(()=>this.addFromRulesetPromise(source));
|
||||
return this;
|
||||
}
|
||||
if ('then' in source) {
|
||||
this.pendingPromise = source.then((src)=>this.addFromRulesetPromise(src));
|
||||
return this;
|
||||
}
|
||||
this.pendingPromise = this.addFromRulesetPromise(source);
|
||||
return this;
|
||||
}
|
||||
static ipToCidr = (ip, version)=>{
|
||||
if (ip.includes('/')) return ip;
|
||||
if (version === 4) {
|
||||
return ip + '/32';
|
||||
}
|
||||
return ip + '/128';
|
||||
};
|
||||
bulkAddCIDR4(cidrs) {
|
||||
for(let i = 0, len = cidrs.length; i < len; i++){
|
||||
this.ipcidr.add(FileOutput.ipToCidr(cidrs[i], 4));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
bulkAddCIDR4NoResolve(cidrs) {
|
||||
for(let i = 0, len = cidrs.length; i < len; i++){
|
||||
this.ipcidrNoResolve.add(FileOutput.ipToCidr(cidrs[i], 4));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
bulkAddCIDR6(cidrs) {
|
||||
for(let i = 0, len = cidrs.length; i < len; i++){
|
||||
this.ipcidr6.add(FileOutput.ipToCidr(cidrs[i], 6));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
bulkAddCIDR6NoResolve(cidrs) {
|
||||
for(let i = 0, len = cidrs.length; i < len; i++){
|
||||
this.ipcidr6NoResolve.add(FileOutput.ipToCidr(cidrs[i], 6));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
async done() {
|
||||
await this.pendingPromise;
|
||||
this.pendingPromise = null;
|
||||
return this;
|
||||
}
|
||||
// private guardPendingPromise() {
|
||||
// // reverse invariant
|
||||
// if (this.pendingPromise !== null) {
|
||||
// console.trace('Pending promise:', this.pendingPromise);
|
||||
// throw new Error('You should call done() before calling this method');
|
||||
// }
|
||||
// }
|
||||
// async writeClash(outputDir?: null | string) {
|
||||
// await this.done();
|
||||
// invariant(this.title, 'Missing title');
|
||||
// invariant(this.description, 'Missing description');
|
||||
// return compareAndWriteFile(
|
||||
// this.span,
|
||||
// withBannerArray(
|
||||
// this.title,
|
||||
// this.description,
|
||||
// this.date,
|
||||
// this.clash()
|
||||
// ),
|
||||
// path.join(outputDir ?? OUTPUT_CLASH_DIR, this.type, this.id + '.txt')
|
||||
// );
|
||||
// }
|
||||
strategiesWritten;
|
||||
writeToStrategies() {
|
||||
if (this.pendingPromise) {
|
||||
throw new Error('You should call done() before calling writeToStrategies()');
|
||||
}
|
||||
if (this.strategiesWritten) {
|
||||
throw new Error('Strategies already written');
|
||||
}
|
||||
this.strategiesWritten = true;
|
||||
const kwfilter = (0, _retrie.createRetrieKeywordFilter)(Array.from(this.domainKeywords));
|
||||
if (this.strategies.filter((0, _guard.not)(false)).length === 0) {
|
||||
throw new Error('No strategies to write ' + this.id);
|
||||
}
|
||||
this.domainTrie.dumpWithoutDot((domain, includeAllSubdomain)=>{
|
||||
if (kwfilter(domain)) {
|
||||
return;
|
||||
}
|
||||
for(let i = 0, len = this.strategies.length; i < len; i++){
|
||||
const strategy = this.strategies[i];
|
||||
if (strategy) {
|
||||
if (includeAllSubdomain) {
|
||||
strategy.writeDomainSuffix(domain);
|
||||
} else {
|
||||
strategy.writeDomain(domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
for(let i = 0, len = this.strategies.length; i < len; i++){
|
||||
const strategy = this.strategies[i];
|
||||
if (!strategy) continue;
|
||||
if (this.domainKeywords.size) {
|
||||
strategy.writeDomainKeywords(this.domainKeywords);
|
||||
}
|
||||
if (this.domainWildcard.size) {
|
||||
strategy.writeDomainWildcards(this.domainWildcard);
|
||||
}
|
||||
if (this.userAgent.size) {
|
||||
strategy.writeUserAgents(this.userAgent);
|
||||
}
|
||||
if (this.processName.size) {
|
||||
strategy.writeProcessNames(this.processName);
|
||||
}
|
||||
if (this.processPath.size) {
|
||||
strategy.writeProcessPaths(this.processPath);
|
||||
}
|
||||
}
|
||||
if (this.sourceIpOrCidr.size) {
|
||||
const sourceIpOrCidr = Array.from(this.sourceIpOrCidr);
|
||||
for(let i = 0, len = this.strategies.length; i < len; i++){
|
||||
const strategy = this.strategies[i];
|
||||
if (strategy) {
|
||||
strategy.writeSourceIpCidrs(sourceIpOrCidr);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(let i = 0, len = this.strategies.length; i < len; i++){
|
||||
const strategy = this.strategies[i];
|
||||
if (strategy) {
|
||||
if (this.sourcePort.size) {
|
||||
strategy.writeSourcePorts(this.sourcePort);
|
||||
}
|
||||
if (this.destPort.size) {
|
||||
strategy.writeDestinationPorts(this.destPort);
|
||||
}
|
||||
if (this.otherRules.length) {
|
||||
strategy.writeOtherRules(this.otherRules);
|
||||
}
|
||||
if (this.urlRegex.size) {
|
||||
strategy.writeUrlRegexes(this.urlRegex);
|
||||
}
|
||||
}
|
||||
}
|
||||
let ipcidr = null;
|
||||
let ipcidrNoResolve = null;
|
||||
let ipcidr6 = null;
|
||||
let ipcidr6NoResolve = null;
|
||||
if (this.ipcidr.size) {
|
||||
ipcidr = (0, _fastcidrtools.merge)(Array.from(this.ipcidr), true);
|
||||
}
|
||||
if (this.ipcidrNoResolve.size) {
|
||||
ipcidrNoResolve = (0, _fastcidrtools.merge)(Array.from(this.ipcidrNoResolve), true);
|
||||
}
|
||||
if (this.ipcidr6.size) {
|
||||
ipcidr6 = Array.from(this.ipcidr6);
|
||||
}
|
||||
if (this.ipcidr6NoResolve.size) {
|
||||
ipcidr6NoResolve = Array.from(this.ipcidr6NoResolve);
|
||||
}
|
||||
for(let i = 0, len = this.strategies.length; i < len; i++){
|
||||
const strategy = this.strategies[i];
|
||||
if (strategy) {
|
||||
// no-resolve
|
||||
if (ipcidrNoResolve?.length) {
|
||||
strategy.writeIpCidrs(ipcidrNoResolve, true);
|
||||
}
|
||||
if (ipcidr6NoResolve?.length) {
|
||||
strategy.writeIpCidr6s(ipcidr6NoResolve, true);
|
||||
}
|
||||
if (this.ipasnNoResolve.size) {
|
||||
strategy.writeIpAsns(this.ipasnNoResolve, true);
|
||||
}
|
||||
if (this.groipNoResolve.size) {
|
||||
strategy.writeGeoip(this.groipNoResolve, true);
|
||||
}
|
||||
// triggers DNS resolution
|
||||
if (ipcidr?.length) {
|
||||
strategy.writeIpCidrs(ipcidr, false);
|
||||
}
|
||||
if (ipcidr6?.length) {
|
||||
strategy.writeIpCidr6s(ipcidr6, false);
|
||||
}
|
||||
if (this.ipasn.size) {
|
||||
strategy.writeIpAsns(this.ipasn, false);
|
||||
}
|
||||
if (this.geoip.size) {
|
||||
strategy.writeGeoip(this.geoip, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
write() {
|
||||
return this.span.traceChildAsync('write all', async (childSpan)=>{
|
||||
await this.done();
|
||||
childSpan.traceChildSync('write to strategies', this.writeToStrategies.bind(this));
|
||||
return childSpan.traceChildAsync('output to disk', (childSpan)=>{
|
||||
const promises = [];
|
||||
(0, _guard.invariant)(this.title, 'Missing title');
|
||||
(0, _guard.invariant)(this.description, 'Missing description');
|
||||
for(let i = 0, len = this.strategies.length; i < len; i++){
|
||||
const strategy = this.strategies[i];
|
||||
if (strategy) {
|
||||
const basename = (strategy.overwriteFilename || this.id) + '.' + strategy.fileExtension;
|
||||
promises.push(strategy.output(childSpan, this.title, this.description, this.date, _nodepath.default.join(strategy.outputDir, strategy.type ? _nodepath.default.join(strategy.type, basename) : basename)));
|
||||
}
|
||||
}
|
||||
return Promise.all(promises);
|
||||
});
|
||||
});
|
||||
}
|
||||
async compile() {
|
||||
await this.done();
|
||||
this.writeToStrategies();
|
||||
return this.strategies.reduce((acc, strategy)=>{
|
||||
if (strategy) {
|
||||
acc.push(strategy.content);
|
||||
} else {
|
||||
acc.push(null);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
withMitmSgmodulePath(moduleName) {
|
||||
if (moduleName) {
|
||||
this.withExtraStrategies(new _surge.SurgeMitmSgmodule(moduleName));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
} (base.__exports));
|
||||
return base.__exports;
|
||||
}exports.__require=requireBase;
|
||||
47
Dist/Build/lib/rules/domainset.cjs
Normal file
47
Dist/Build/lib/rules/domainset.cjs
Normal file
@@ -0,0 +1,47 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const domainset=require('../../../_virtual/domainset.cjs'),adguardhome=require('../writing-strategy/adguardhome.cjs'),clash=require('../writing-strategy/clash.cjs'),singbox=require('../writing-strategy/singbox.cjs'),surge=require('../writing-strategy/surge.cjs'),base=require('./base.cjs');var hasRequiredDomainset;
|
||||
|
||||
function requireDomainset () {
|
||||
if (hasRequiredDomainset) return domainset.__exports;
|
||||
hasRequiredDomainset = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
AdGuardHomeOutput: function() {
|
||||
return AdGuardHomeOutput;
|
||||
},
|
||||
DomainsetOutput: function() {
|
||||
return DomainsetOutput;
|
||||
}
|
||||
});
|
||||
const _adguardhome = /*@__PURE__*/ adguardhome.__require();
|
||||
const _clash = /*@__PURE__*/ clash.__require();
|
||||
const _singbox = /*@__PURE__*/ singbox.__require();
|
||||
const _surge = /*@__PURE__*/ surge.__require();
|
||||
const _base = /*@__PURE__*/ base.__require();
|
||||
class DomainsetOutput extends _base.FileOutput {
|
||||
strategies = [
|
||||
new _surge.SurgeDomainSet(),
|
||||
new _clash.ClashDomainSet(),
|
||||
new _singbox.SingboxSource('domainset')
|
||||
];
|
||||
}
|
||||
class AdGuardHomeOutput extends _base.FileOutput {
|
||||
strategies;
|
||||
constructor(span, id, outputDir){
|
||||
super(span, id);
|
||||
this.strategies = [
|
||||
new _adguardhome.AdGuardHome(outputDir)
|
||||
];
|
||||
}
|
||||
}
|
||||
} (domainset.__exports));
|
||||
return domainset.__exports;
|
||||
}exports.__require=requireDomainset;
|
||||
34
Dist/Build/lib/rules/ip.cjs
Normal file
34
Dist/Build/lib/rules/ip.cjs
Normal file
@@ -0,0 +1,34 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const ip=require('../../../_virtual/ip.cjs'),clash=require('../writing-strategy/clash.cjs'),singbox=require('../writing-strategy/singbox.cjs'),surge=require('../writing-strategy/surge.cjs'),base=require('./base.cjs');var hasRequiredIp;
|
||||
|
||||
function requireIp () {
|
||||
if (hasRequiredIp) return ip.__exports;
|
||||
hasRequiredIp = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "IPListOutput", {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return IPListOutput;
|
||||
}
|
||||
});
|
||||
const _clash = /*@__PURE__*/ clash.__require();
|
||||
const _singbox = /*@__PURE__*/ singbox.__require();
|
||||
const _surge = /*@__PURE__*/ surge.__require();
|
||||
const _base = /*@__PURE__*/ base.__require();
|
||||
class IPListOutput extends _base.FileOutput {
|
||||
clashUseRule;
|
||||
strategies;
|
||||
constructor(span, id, clashUseRule = true){
|
||||
super(span, id), this.clashUseRule = clashUseRule;
|
||||
this.strategies = [
|
||||
new _surge.SurgeRuleSet('ip'),
|
||||
this.clashUseRule ? new _clash.ClashClassicRuleSet('ip') : new _clash.ClashIPSet(),
|
||||
new _singbox.SingboxSource('ip')
|
||||
];
|
||||
}
|
||||
}
|
||||
} (ip.__exports));
|
||||
return ip.__exports;
|
||||
}exports.__require=requireIp;
|
||||
59
Dist/Build/lib/rules/ruleset.cjs
Normal file
59
Dist/Build/lib/rules/ruleset.cjs
Normal file
@@ -0,0 +1,59 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const ruleset=require('../../../_virtual/ruleset.cjs'),clash=require('../writing-strategy/clash.cjs'),singbox=require('../writing-strategy/singbox.cjs'),surge=require('../writing-strategy/surge.cjs'),base=require('./base.cjs');var hasRequiredRuleset;
|
||||
|
||||
function requireRuleset () {
|
||||
if (hasRequiredRuleset) return ruleset.__exports;
|
||||
hasRequiredRuleset = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
ClashOnlyRulesetOutput: function() {
|
||||
return ClashOnlyRulesetOutput;
|
||||
},
|
||||
RulesetOutput: function() {
|
||||
return RulesetOutput;
|
||||
},
|
||||
SurgeOnlyRulesetOutput: function() {
|
||||
return SurgeOnlyRulesetOutput;
|
||||
}
|
||||
});
|
||||
const _clash = /*@__PURE__*/ clash.__require();
|
||||
const _singbox = /*@__PURE__*/ singbox.__require();
|
||||
const _surge = /*@__PURE__*/ surge.__require();
|
||||
const _base = /*@__PURE__*/ base.__require();
|
||||
class RulesetOutput extends _base.FileOutput {
|
||||
constructor(span, id, type){
|
||||
super(span, id);
|
||||
this.strategies = [
|
||||
new _surge.SurgeRuleSet(type),
|
||||
new _clash.ClashClassicRuleSet(type),
|
||||
new _singbox.SingboxSource(type)
|
||||
];
|
||||
}
|
||||
}
|
||||
class SurgeOnlyRulesetOutput extends _base.FileOutput {
|
||||
constructor(span, id, type, overrideOutputDir){
|
||||
super(span, id);
|
||||
this.strategies = [
|
||||
new _surge.SurgeRuleSet(type, overrideOutputDir)
|
||||
];
|
||||
}
|
||||
}
|
||||
class ClashOnlyRulesetOutput extends _base.FileOutput {
|
||||
constructor(span, id, type){
|
||||
super(span, id);
|
||||
this.strategies = [
|
||||
new _clash.ClashClassicRuleSet(type)
|
||||
];
|
||||
}
|
||||
}
|
||||
} (ruleset.__exports));
|
||||
return ruleset.__exports;
|
||||
}exports.__require=requireRuleset;
|
||||
65
Dist/Build/lib/text-line-transform-stream.cjs
Normal file
65
Dist/Build/lib/text-line-transform-stream.cjs
Normal file
@@ -0,0 +1,65 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const textLineTransformStream=require('../../_virtual/text-line-transform-stream.cjs'),require$$0=require('node:stream/web');var hasRequiredTextLineTransformStream;
|
||||
|
||||
function requireTextLineTransformStream () {
|
||||
if (hasRequiredTextLineTransformStream) return textLineTransformStream.__exports;
|
||||
hasRequiredTextLineTransformStream = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "TextLineStream", {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return TextLineStream;
|
||||
}
|
||||
});
|
||||
const _web = require$$0;
|
||||
class TextLineStream extends _web.TransformStream {
|
||||
// private __buf = '';
|
||||
constructor({ allowCR = false } = {}){
|
||||
let __buf = '';
|
||||
let chunkIndex = 0;
|
||||
super({
|
||||
transform (chunk, controller) {
|
||||
chunk = __buf + chunk;
|
||||
chunkIndex = 0;
|
||||
for(;;){
|
||||
const lfIndex = chunk.indexOf('\n', chunkIndex);
|
||||
if (allowCR) {
|
||||
const crIndex = chunk.indexOf('\r', chunkIndex);
|
||||
if (crIndex !== -1 && crIndex !== chunk.length - 1 && (lfIndex === -1 || lfIndex - 1 > crIndex)) {
|
||||
controller.enqueue(chunk.slice(chunkIndex, crIndex));
|
||||
chunkIndex = crIndex + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (lfIndex === -1) {
|
||||
break;
|
||||
}
|
||||
// enqueue current line, and loop again to find next line
|
||||
let crOrLfIndex = lfIndex;
|
||||
if (chunk[lfIndex - 1] === '\r') {
|
||||
crOrLfIndex--;
|
||||
}
|
||||
controller.enqueue(chunk.slice(chunkIndex, crOrLfIndex));
|
||||
chunkIndex = lfIndex + 1;
|
||||
continue;
|
||||
}
|
||||
__buf = chunk.slice(chunkIndex);
|
||||
},
|
||||
flush (controller) {
|
||||
if (__buf.length > 0) {
|
||||
// eslint-disable-next-line sukka/string/prefer-string-starts-ends-with -- performance
|
||||
if (allowCR && __buf[__buf.length - 1] === '\r') {
|
||||
controller.enqueue(__buf.slice(0, -1));
|
||||
} else {
|
||||
controller.enqueue(__buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} (textLineTransformStream.__exports));
|
||||
return textLineTransformStream.__exports;
|
||||
}exports.__require=requireTextLineTransformStream;
|
||||
75
Dist/Build/lib/tree-dir.cjs
Normal file
75
Dist/Build/lib/tree-dir.cjs
Normal file
@@ -0,0 +1,75 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const treeDir=require('../../_virtual/tree-dir.cjs'),require$$2=require('node:fs/promises'),require$$0=require('node:path');var hasRequiredTreeDir;
|
||||
|
||||
function requireTreeDir () {
|
||||
if (hasRequiredTreeDir) return treeDir.__exports;
|
||||
hasRequiredTreeDir = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
TreeFileType: function() {
|
||||
return TreeFileType;
|
||||
},
|
||||
treeDir: function() {
|
||||
return treeDir;
|
||||
}
|
||||
});
|
||||
const _promises = /*#__PURE__*/ _interop_require_default(require$$2);
|
||||
const _nodepath = require$$0;
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
var TreeFileType = /*#__PURE__*/ function(TreeFileType) {
|
||||
TreeFileType[TreeFileType["FILE"] = 1] = "FILE";
|
||||
TreeFileType[TreeFileType["DIRECTORY"] = 2] = "DIRECTORY";
|
||||
return TreeFileType;
|
||||
}({});
|
||||
async function treeDir(rootPath) {
|
||||
const tree = [];
|
||||
const walk = async (dir, node, dirRelativeToRoot = '')=>{
|
||||
const promises = [];
|
||||
for await (const child of (await _promises.default.opendir(dir))){
|
||||
// Ignore hidden files
|
||||
if (child.name[0] === '.' || child.name === 'CNAME') {
|
||||
continue;
|
||||
}
|
||||
const childFullPath = child.parentPath + _nodepath.sep + child.name;
|
||||
const childRelativeToRoot = dirRelativeToRoot + _nodepath.sep + child.name;
|
||||
if (child.isDirectory()) {
|
||||
const newNode = {
|
||||
type: 2,
|
||||
name: child.name,
|
||||
path: childRelativeToRoot,
|
||||
children: []
|
||||
};
|
||||
node.push(newNode);
|
||||
promises.push(walk(childFullPath, newNode.children, childRelativeToRoot));
|
||||
continue;
|
||||
}
|
||||
if (child.isFile()) {
|
||||
const newNode = {
|
||||
type: 1,
|
||||
name: child.name,
|
||||
path: childRelativeToRoot
|
||||
};
|
||||
node.push(newNode);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return Promise.all(promises);
|
||||
};
|
||||
await walk(rootPath, tree);
|
||||
return tree;
|
||||
}
|
||||
} (treeDir.__exports));
|
||||
return treeDir.__exports;
|
||||
}exports.__require=requireTreeDir;
|
||||
540
Dist/Build/lib/trie.cjs
Normal file
540
Dist/Build/lib/trie.cjs
Normal file
@@ -0,0 +1,540 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const trie=require('../../_virtual/trie.cjs'),misc=require('./misc.cjs'),require$$1=require('node:util'),require$$2=require('foxts/noop'),require$$3=require('foxts/fast-string-array-join'),require$$4=require('foxts/bitwise');/**
|
||||
* Hostbane-Optimized Trie based on Mnemonist Trie
|
||||
*/
|
||||
|
||||
var hasRequiredTrie;
|
||||
|
||||
function requireTrie () {
|
||||
if (hasRequiredTrie) return trie.__exports;
|
||||
hasRequiredTrie = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
HostnameSmolTrie: function() {
|
||||
return HostnameSmolTrie;
|
||||
},
|
||||
HostnameTrie: function() {
|
||||
return HostnameTrie;
|
||||
}
|
||||
});
|
||||
const _misc = /*@__PURE__*/ misc.__require();
|
||||
const _nodeutil = /*#__PURE__*/ _interop_require_default(require$$1);
|
||||
const _noop = require$$2;
|
||||
const _faststringarrayjoin = require$$3;
|
||||
const _bitwise = require$$4;
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
var _computedKey;
|
||||
const START = 1 << 1;
|
||||
const INCLUDE_ALL_SUBDOMAIN = 1 << 2;
|
||||
function deepTrieNodeToJSON(node, unpackMeta) {
|
||||
const obj = {};
|
||||
obj['[start]'] = (0, _bitwise.getBit)(node[0], START);
|
||||
obj['[subdomain]'] = (0, _bitwise.getBit)(node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
if (node[3] != null) {
|
||||
if (unpackMeta) {
|
||||
obj['[meta]'] = unpackMeta(node[3]);
|
||||
} else {
|
||||
obj['[meta]'] = node[3];
|
||||
}
|
||||
}
|
||||
node[2].forEach((value, key)=>{
|
||||
obj[key] = deepTrieNodeToJSON(value, unpackMeta);
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
const createNode = (parent = null)=>[
|
||||
1,
|
||||
parent,
|
||||
new Map(),
|
||||
null
|
||||
];
|
||||
function hostnameToTokens(hostname, hostnameFromIndex) {
|
||||
const tokens = hostname.split('.');
|
||||
const results = [];
|
||||
let token = '';
|
||||
for(let i = hostnameFromIndex, l = tokens.length; i < l; i++){
|
||||
token = tokens[i];
|
||||
if (token.length > 0) {
|
||||
results.push(token);
|
||||
} else {
|
||||
throw new TypeError(JSON.stringify({
|
||||
hostname,
|
||||
hostnameFromIndex
|
||||
}, null, 2));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
function walkHostnameTokens(hostname, onToken, hostnameFromIndex) {
|
||||
const tokens = hostname.split('.');
|
||||
const l = tokens.length - 1;
|
||||
// we are at the first of hostname, no splitor there
|
||||
let token = '';
|
||||
for(let i = l; i >= hostnameFromIndex; i--){
|
||||
token = tokens[i];
|
||||
if (token.length > 0) {
|
||||
const t = onToken(token);
|
||||
if (t === null) {
|
||||
return null;
|
||||
}
|
||||
// if the callback returns true, we should skip the rest
|
||||
if (t) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
_computedKey = _nodeutil.default.inspect.custom;
|
||||
class Triebase {
|
||||
$root = createNode();
|
||||
$size = 0;
|
||||
get root() {
|
||||
return this.$root;
|
||||
}
|
||||
constructor(from){
|
||||
// Actually build trie
|
||||
if (Array.isArray(from)) {
|
||||
for(let i = 0, l = from.length; i < l; i++){
|
||||
this.add(from[i]);
|
||||
}
|
||||
} else if (from) {
|
||||
from.forEach((value)=>this.add(value));
|
||||
}
|
||||
}
|
||||
walkIntoLeafWithTokens(tokens, onLoop = _noop.noop) {
|
||||
let node = this.$root;
|
||||
let parent = node;
|
||||
let token;
|
||||
let child = node[2];
|
||||
// reverse lookup from end to start
|
||||
for(let i = tokens.length - 1; i >= 0; i--){
|
||||
token = tokens[i];
|
||||
// if (token === '') {
|
||||
// break;
|
||||
// }
|
||||
parent = node;
|
||||
child = node[2];
|
||||
// cache node index access is 20% faster than direct access when doing twice
|
||||
if (child.has(token)) {
|
||||
node = child.get(token);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
onLoop(node, parent, token);
|
||||
}
|
||||
return {
|
||||
node,
|
||||
parent
|
||||
};
|
||||
}
|
||||
walkIntoLeafWithSuffix(suffix, hostnameFromIndex, onLoop = _noop.noop) {
|
||||
let node = this.$root;
|
||||
let parent = node;
|
||||
let child = node[2];
|
||||
const onToken = (token)=>{
|
||||
// if (token === '') {
|
||||
// return true;
|
||||
// }
|
||||
parent = node;
|
||||
child = node[2];
|
||||
if (child.has(token)) {
|
||||
node = child.get(token);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
onLoop(node, parent, token);
|
||||
return false;
|
||||
};
|
||||
if (walkHostnameTokens(suffix, onToken, hostnameFromIndex) === null) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
node,
|
||||
parent
|
||||
};
|
||||
}
|
||||
contains(suffix, includeAllSubdomain = suffix[0] === '.') {
|
||||
const hostnameFromIndex = suffix[0] === '.' ? 1 : 0;
|
||||
const res = this.walkIntoLeafWithSuffix(suffix, hostnameFromIndex);
|
||||
if (!res) return false;
|
||||
if (includeAllSubdomain) return (0, _bitwise.getBit)(res.node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
return true;
|
||||
}
|
||||
static bfsResults = [
|
||||
null,
|
||||
[]
|
||||
];
|
||||
static dfs(nodeStack, suffixStack) {
|
||||
const node = nodeStack.pop();
|
||||
const suffix = suffixStack.pop();
|
||||
node[2].forEach((childNode, k)=>{
|
||||
// Pushing the child node to the stack for next iteration of DFS
|
||||
nodeStack.push(childNode);
|
||||
suffixStack.push([
|
||||
k,
|
||||
...suffix
|
||||
]);
|
||||
});
|
||||
Triebase.bfsResults[0] = node;
|
||||
Triebase.bfsResults[1] = suffix;
|
||||
return Triebase.bfsResults;
|
||||
}
|
||||
static dfsWithSort(nodeStack, suffixStack) {
|
||||
const node = nodeStack.pop();
|
||||
const suffix = suffixStack.pop();
|
||||
const child = node[2];
|
||||
if (child.size) {
|
||||
const keys = Array.from(child.keys()).sort(Triebase.compare);
|
||||
for(let i = 0, l = keys.length; i < l; i++){
|
||||
const key = keys[i];
|
||||
const childNode = child.get(key);
|
||||
// Pushing the child node to the stack for next iteration of DFS
|
||||
nodeStack.push(childNode);
|
||||
suffixStack.push([
|
||||
key,
|
||||
...suffix
|
||||
]);
|
||||
}
|
||||
}
|
||||
Triebase.bfsResults[0] = node;
|
||||
Triebase.bfsResults[1] = suffix;
|
||||
return Triebase.bfsResults;
|
||||
}
|
||||
walk(onMatches, initialNode = this.$root, initialSuffix = [], withSort = false) {
|
||||
const bfsImpl = withSort ? Triebase.dfsWithSort : Triebase.dfs;
|
||||
const nodeStack = [];
|
||||
nodeStack.push(initialNode);
|
||||
// Resolving initial string (begin the start of the stack)
|
||||
const suffixStack = [];
|
||||
suffixStack.push(initialSuffix);
|
||||
let node = initialNode;
|
||||
let r;
|
||||
do {
|
||||
r = bfsImpl(nodeStack, suffixStack);
|
||||
node = r[0];
|
||||
const suffix = r[1];
|
||||
// If the node is a sentinel, we push the suffix to the results
|
||||
if ((0, _bitwise.getBit)(node[0], START)) {
|
||||
onMatches(suffix, (0, _bitwise.getBit)(node[0], INCLUDE_ALL_SUBDOMAIN), node[3]);
|
||||
}
|
||||
}while (nodeStack.length)
|
||||
}
|
||||
static compare(a, b) {
|
||||
if (a === b) return 0;
|
||||
return a.length - b.length || (0, _misc.fastStringCompare)(a, b);
|
||||
}
|
||||
walkWithSort(onMatches, initialNode = this.$root, initialSuffix = []) {
|
||||
const nodeStack = [];
|
||||
nodeStack.push(initialNode);
|
||||
// Resolving initial string (begin the start of the stack)
|
||||
const suffixStack = [];
|
||||
suffixStack.push(initialSuffix);
|
||||
let node = initialNode;
|
||||
let child = node[2];
|
||||
do {
|
||||
node = nodeStack.pop();
|
||||
const suffix = suffixStack.pop();
|
||||
child = node[2];
|
||||
if (child.size) {
|
||||
const keys = Array.from(child.keys()).sort(Triebase.compare);
|
||||
for(let i = 0, l = keys.length; i < l; i++){
|
||||
const key = keys[i];
|
||||
const childNode = child.get(key);
|
||||
// Pushing the child node to the stack for next iteration of DFS
|
||||
nodeStack.push(childNode);
|
||||
suffixStack.push([
|
||||
key,
|
||||
...suffix
|
||||
]);
|
||||
}
|
||||
}
|
||||
// If the node is a sentinel, we push the suffix to the results
|
||||
if ((0, _bitwise.getBit)(node[0], START)) {
|
||||
onMatches(suffix, (0, _bitwise.getBit)(node[0], INCLUDE_ALL_SUBDOMAIN), node[3]);
|
||||
}
|
||||
}while (nodeStack.length)
|
||||
}
|
||||
getSingleChildLeaf(tokens) {
|
||||
let toPrune = null;
|
||||
let tokenToPrune = null;
|
||||
const onLoop = (node, parent, token)=>{
|
||||
// Keeping track of a potential branch to prune
|
||||
const child = node[2];
|
||||
// console.log({
|
||||
// child, parent, token
|
||||
// });
|
||||
// console.log(this.inspect(0));
|
||||
if (toPrune !== null) {
|
||||
if (child.size > 1) {
|
||||
// The branch has some children, the branch need retain.
|
||||
// And we need to abort prune that parent branch, so we set it to null
|
||||
toPrune = null;
|
||||
tokenToPrune = null;
|
||||
}
|
||||
} else if (child.size < 1) {
|
||||
// There is only one token child, or no child at all, we can prune it safely
|
||||
// It is now the top-est branch that could potentially being pruned
|
||||
toPrune = parent;
|
||||
tokenToPrune = token;
|
||||
}
|
||||
};
|
||||
const res = this.walkIntoLeafWithTokens(tokens, onLoop);
|
||||
if (res === null) return null;
|
||||
return {
|
||||
node: res.node,
|
||||
toPrune,
|
||||
tokenToPrune,
|
||||
parent: res.parent
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Method used to retrieve every item in the trie with the given prefix.
|
||||
*/ find(inputSuffix, subdomainOnly = inputSuffix[0] === '.', hostnameFromIndex = inputSuffix[0] === '.' ? 1 : 0) {
|
||||
const inputTokens = hostnameToTokens(inputSuffix, hostnameFromIndex);
|
||||
const res = this.walkIntoLeafWithTokens(inputTokens);
|
||||
if (res === null) return [];
|
||||
const results = [];
|
||||
const onMatches = subdomainOnly ? (suffix, subdomain)=>{
|
||||
const d = (0, _faststringarrayjoin.fastStringArrayJoin)(suffix, '.');
|
||||
if (!subdomain && subStringEqual(inputSuffix, d, 1)) return;
|
||||
results.push(subdomain ? '.' + d : d);
|
||||
} : (suffix, subdomain)=>{
|
||||
const d = (0, _faststringarrayjoin.fastStringArrayJoin)(suffix, '.');
|
||||
results.push(subdomain ? '.' + d : d);
|
||||
};
|
||||
this.walk(onMatches, res.node, inputTokens);
|
||||
return results;
|
||||
}
|
||||
/**
|
||||
* Method used to delete a prefix from the trie.
|
||||
*/ remove(suffix) {
|
||||
const res = this.getSingleChildLeaf(hostnameToTokens(suffix, 0));
|
||||
if (res === null) return false;
|
||||
if ((0, _bitwise.missingBit)(res.node[0], START)) return false;
|
||||
this.$size--;
|
||||
const { node, toPrune, tokenToPrune } = res;
|
||||
if (tokenToPrune && toPrune) {
|
||||
toPrune[2].delete(tokenToPrune);
|
||||
} else {
|
||||
node[0] = (0, _bitwise.deleteBit)(node[0], START);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method -- safe
|
||||
delete = this.remove;
|
||||
/**
|
||||
* Method used to assert whether the given prefix exists in the Trie.
|
||||
*/ has(suffix, includeAllSubdomain = suffix[0] === '.') {
|
||||
const hostnameFromIndex = suffix[0] === '.' ? 1 : 0;
|
||||
const res = this.walkIntoLeafWithSuffix(suffix, hostnameFromIndex);
|
||||
if (res === null) return false;
|
||||
if ((0, _bitwise.missingBit)(res.node[0], START)) return false;
|
||||
if (includeAllSubdomain) return (0, _bitwise.getBit)(res.node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
return true;
|
||||
}
|
||||
dumpWithoutDot(onSuffix, withSort = false) {
|
||||
const handleSuffix = (suffix, subdomain)=>{
|
||||
onSuffix((0, _faststringarrayjoin.fastStringArrayJoin)(suffix, '.'), subdomain);
|
||||
};
|
||||
if (withSort) {
|
||||
this.walkWithSort(handleSuffix);
|
||||
} else {
|
||||
this.walk(handleSuffix);
|
||||
}
|
||||
}
|
||||
dump(onSuffix, withSort = false) {
|
||||
const results = [];
|
||||
const handleSuffix = onSuffix ? (suffix, subdomain)=>{
|
||||
const d = (0, _faststringarrayjoin.fastStringArrayJoin)(suffix, '.');
|
||||
onSuffix(subdomain ? '.' + d : d);
|
||||
} : (suffix, subdomain)=>{
|
||||
const d = (0, _faststringarrayjoin.fastStringArrayJoin)(suffix, '.');
|
||||
results.push(subdomain ? '.' + d : d);
|
||||
};
|
||||
if (withSort) {
|
||||
this.walkWithSort(handleSuffix);
|
||||
} else {
|
||||
this.walk(handleSuffix);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
dumpMeta(onMeta, withSort = false) {
|
||||
const results = [];
|
||||
const handleMeta = onMeta ? (_suffix, _subdomain, meta)=>onMeta(meta) : (_suffix, _subdomain, meta)=>results.push(meta);
|
||||
if (withSort) {
|
||||
this.walkWithSort(handleMeta);
|
||||
} else {
|
||||
this.walk(handleMeta);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
dumpWithMeta(onSuffix, withSort = false) {
|
||||
const results = [];
|
||||
const handleSuffix = onSuffix ? (suffix, subdomain, meta)=>{
|
||||
const d = (0, _faststringarrayjoin.fastStringArrayJoin)(suffix, '.');
|
||||
return onSuffix(subdomain ? '.' + d : d, meta);
|
||||
} : (suffix, subdomain, meta)=>{
|
||||
const d = (0, _faststringarrayjoin.fastStringArrayJoin)(suffix, '.');
|
||||
results.push([
|
||||
subdomain ? '.' + d : d,
|
||||
meta
|
||||
]);
|
||||
};
|
||||
if (withSort) {
|
||||
this.walkWithSort(handleSuffix);
|
||||
} else {
|
||||
this.walk(handleSuffix);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
inspect(depth, unpackMeta) {
|
||||
return (0, _faststringarrayjoin.fastStringArrayJoin)(JSON.stringify(deepTrieNodeToJSON(this.$root, unpackMeta), null, 2).split('\n').map((line)=>' '.repeat(depth) + line), '\n');
|
||||
}
|
||||
[_computedKey](depth) {
|
||||
return this.inspect(depth);
|
||||
}
|
||||
merge(trie) {
|
||||
const handleSuffix = (suffix, subdomain, meta)=>{
|
||||
this.add((0, _faststringarrayjoin.fastStringArrayJoin)(suffix, '.'), subdomain, meta);
|
||||
};
|
||||
trie.walk(handleSuffix);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class HostnameSmolTrie extends Triebase {
|
||||
smolTree = true;
|
||||
add(suffix, includeAllSubdomain = suffix[0] === '.', meta, hostnameFromIndex = suffix[0] === '.' ? 1 : 0) {
|
||||
let node = this.$root;
|
||||
let curNodeChildren = node[2];
|
||||
const onToken = (token)=>{
|
||||
curNodeChildren = node[2];
|
||||
if (curNodeChildren.has(token)) {
|
||||
node = curNodeChildren.get(token);
|
||||
// During the adding of `[start]blog|.skk.moe` and find out that there is a `[start].skk.moe` in the trie, skip adding the rest of the node
|
||||
if ((0, _bitwise.getBit)(node[0], INCLUDE_ALL_SUBDOMAIN)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
const newNode = createNode(node);
|
||||
curNodeChildren.set(token, newNode);
|
||||
node = newNode;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
// When walkHostnameTokens returns true, we should skip the rest
|
||||
if (walkHostnameTokens(suffix, onToken, hostnameFromIndex)) {
|
||||
return;
|
||||
}
|
||||
// If we are in smolTree mode, we need to do something at the end of the loop
|
||||
if (includeAllSubdomain) {
|
||||
// Trying to add `[.]sub.example.com` where there is already a `blog.sub.example.com` in the trie
|
||||
// Make sure parent `[start]sub.example.com` (without dot) is removed (SETINEL to false)
|
||||
// (/** parent */ node[2]!)[0] = false;
|
||||
// Removing the rest of the parent's child nodes
|
||||
node[2].clear();
|
||||
// The SENTINEL of this node will be set to true at the end of the function, so we don't need to set it here
|
||||
// we can use else-if here, because the children is now empty, we don't need to check the leading "."
|
||||
} else if ((0, _bitwise.getBit)(node[0], INCLUDE_ALL_SUBDOMAIN)) {
|
||||
// Trying to add `example.com` when there is already a `.example.com` in the trie
|
||||
// No need to increment size and set SENTINEL to true (skip this "new" item)
|
||||
return;
|
||||
}
|
||||
node[0] = (0, _bitwise.setBit)(node[0], START);
|
||||
if (includeAllSubdomain) {
|
||||
node[0] = (0, _bitwise.setBit)(node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
} else {
|
||||
node[0] = (0, _bitwise.deleteBit)(node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
}
|
||||
node[3] = meta;
|
||||
}
|
||||
whitelist(suffix, includeAllSubdomain = suffix[0] === '.', hostnameFromIndex = suffix[0] === '.' ? 1 : 0) {
|
||||
const tokens = hostnameToTokens(suffix, hostnameFromIndex);
|
||||
const res = this.getSingleChildLeaf(tokens);
|
||||
if (res === null) return;
|
||||
const { node, toPrune, tokenToPrune } = res;
|
||||
// Trying to whitelist `[start].sub.example.com` where there might already be a `[start]blog.sub.example.com` in the trie
|
||||
if (includeAllSubdomain) {
|
||||
// If there is a `[start]sub.example.com` here, remove it
|
||||
node[0] = (0, _bitwise.deleteBit)(node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
node[0] = (0, _bitwise.deleteBit)(node[0], START);
|
||||
// Removing all the child nodes by empty the children
|
||||
node[2].clear();
|
||||
} else {
|
||||
// Trying to whitelist `example.com` when there is already a `.example.com` in the trie
|
||||
node[0] = (0, _bitwise.deleteBit)(node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
}
|
||||
// return early if not found
|
||||
if ((0, _bitwise.missingBit)(node[0], START)) return;
|
||||
if (toPrune && tokenToPrune) {
|
||||
toPrune[2].delete(tokenToPrune);
|
||||
} else {
|
||||
node[0] = (0, _bitwise.deleteBit)(node[0], START);
|
||||
}
|
||||
}
|
||||
}
|
||||
class HostnameTrie extends Triebase {
|
||||
get size() {
|
||||
return this.$size;
|
||||
}
|
||||
add(suffix, includeAllSubdomain = suffix[0] === '.', meta, hostnameFromIndex = suffix[0] === '.' ? 1 : 0) {
|
||||
let node = this.$root;
|
||||
let child = node[2];
|
||||
const onToken = (token)=>{
|
||||
child = node[2];
|
||||
if (child.has(token)) {
|
||||
node = child.get(token);
|
||||
} else {
|
||||
const newNode = createNode(node);
|
||||
child.set(token, newNode);
|
||||
node = newNode;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
// When walkHostnameTokens returns true, we should skip the rest
|
||||
if (walkHostnameTokens(suffix, onToken, hostnameFromIndex)) {
|
||||
return;
|
||||
}
|
||||
// if same entry has been added before, skip
|
||||
if ((0, _bitwise.getBit)(node[0], START)) {
|
||||
return;
|
||||
}
|
||||
this.$size++;
|
||||
node[0] = (0, _bitwise.setBit)(node[0], START);
|
||||
if (includeAllSubdomain) {
|
||||
node[0] = (0, _bitwise.setBit)(node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
} else {
|
||||
node[0] = (0, _bitwise.deleteBit)(node[0], INCLUDE_ALL_SUBDOMAIN);
|
||||
}
|
||||
node[3] = meta;
|
||||
}
|
||||
}
|
||||
// function deepEqualArray(a: string[], b: string[]) {
|
||||
// let len = a.length;
|
||||
// if (len !== b.length) return false;
|
||||
// while (len--) {
|
||||
// if (a[len] !== b[len]) return false;
|
||||
// }
|
||||
// return true;
|
||||
// };
|
||||
function subStringEqual(needle, haystack, needleIndex = 0) {
|
||||
for(let i = 0, l = haystack.length; i < l; i++){
|
||||
if (needle[i + needleIndex] !== haystack[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} (trie.__exports));
|
||||
return trie.__exports;
|
||||
}exports.__require=requireTrie;
|
||||
113
Dist/Build/lib/writing-strategy/adguardhome.cjs
Normal file
113
Dist/Build/lib/writing-strategy/adguardhome.cjs
Normal file
@@ -0,0 +1,113 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const adguardhome=require('../../../_virtual/adguardhome.cjs'),require$$0=require('foxts/escape-string-regexp'),base=require('./base.cjs'),require$$2=require('foxts/noop'),misc=require('../misc.cjs');var hasRequiredAdguardhome;
|
||||
|
||||
function requireAdguardhome () {
|
||||
if (hasRequiredAdguardhome) return adguardhome.__exports;
|
||||
hasRequiredAdguardhome = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "AdGuardHome", {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return AdGuardHome;
|
||||
}
|
||||
});
|
||||
const _escapestringregexp = require$$0;
|
||||
const _base = /*@__PURE__*/ base.__require();
|
||||
const _noop = require$$2;
|
||||
const _misc = /*@__PURE__*/ misc.__require();
|
||||
class AdGuardHome extends _base.BaseWriteStrategy {
|
||||
// readonly type = 'domainset';
|
||||
fileExtension = 'txt';
|
||||
type = '';
|
||||
result = [];
|
||||
// eslint-disable-next-line @typescript-eslint/class-methods-use-this -- abstract method
|
||||
withPadding(title, description, date, content) {
|
||||
return [
|
||||
`! Title: ${title}`,
|
||||
'! Last modified: ' + date.toUTCString(),
|
||||
'! Expires: 6 hours',
|
||||
'! License: https://github.com/SukkaW/Surge/blob/master/LICENSE',
|
||||
'! Homepage: https://github.com/SukkaW/Surge',
|
||||
`! Description: ${description.join(' ')}`,
|
||||
'!',
|
||||
...content,
|
||||
'! EOF'
|
||||
];
|
||||
}
|
||||
writeDomain(domain) {
|
||||
this.result.push(`|${domain}^`);
|
||||
}
|
||||
// const whitelistArray = sortDomains(Array.from(whitelist));
|
||||
// for (let i = 0, len = whitelistArray.length; i < len; i++) {
|
||||
// const domain = whitelistArray[i];
|
||||
// if (domain[0] === '.') {
|
||||
// results.push(`@@||${domain.slice(1)}^`);
|
||||
// } else {
|
||||
// results.push(`@@|${domain}^`);
|
||||
// }
|
||||
// }
|
||||
writeDomainSuffix(domain) {
|
||||
this.result.push(`||${domain}^`);
|
||||
}
|
||||
writeDomainKeywords(keywords) {
|
||||
for (const keyword of keywords){
|
||||
// Use regex to match keyword
|
||||
this.result.push(`/${(0, _escapestringregexp.escapeStringRegexp)(keyword)}/`);
|
||||
}
|
||||
}
|
||||
writeDomainWildcards(wildcards) {
|
||||
for (const wildcard of wildcards){
|
||||
const processed = wildcard.replaceAll('?', '*');
|
||||
if (processed.startsWith('*.')) {
|
||||
this.result.push(`||${processed.slice(2)}^`);
|
||||
} else {
|
||||
this.result.push(`|${processed}^`);
|
||||
}
|
||||
}
|
||||
}
|
||||
writeUserAgents = _noop.noop;
|
||||
writeProcessNames = _noop.noop;
|
||||
writeProcessPaths = _noop.noop;
|
||||
writeUrlRegexes = _noop.noop;
|
||||
writeIpCidrs(ipGroup, noResolve) {
|
||||
if (noResolve) {
|
||||
// When IP is provided to AdGuardHome, any domain resolve to those IP will be blocked
|
||||
// So we can't do noResolve
|
||||
return;
|
||||
}
|
||||
for (const ipcidr of ipGroup){
|
||||
if (ipcidr.endsWith('/32')) {
|
||||
this.result.push(`||${ipcidr.slice(0, -3)}`);
|
||||
/* else if (ipcidr.endsWith('.0/24')) {
|
||||
results.push(`||${ipcidr.slice(0, -6)}.*`);
|
||||
} */ } else {
|
||||
this.result.push(`||${ipcidr}^`);
|
||||
}
|
||||
}
|
||||
}
|
||||
writeIpCidr6s(ipGroup, noResolve) {
|
||||
if (noResolve) {
|
||||
// When IP is provided to AdGuardHome, any domain resolve to those IP will be blocked
|
||||
// So we can't do noResolve
|
||||
return;
|
||||
}
|
||||
for (const ipcidr of ipGroup){
|
||||
if (ipcidr.endsWith('/128')) {
|
||||
this.result.push(`||${ipcidr.slice(0, -4)}`);
|
||||
} else {
|
||||
this.result.push(`||${ipcidr}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
writeGeoip = (0, _misc.notSupported)('writeGeoip');
|
||||
writeIpAsns = (0, _misc.notSupported)('writeIpAsns');
|
||||
writeSourceIpCidrs = (0, _misc.notSupported)('writeSourceIpCidrs');
|
||||
writeSourcePorts = (0, _misc.notSupported)('writeSourcePorts');
|
||||
writeDestinationPorts = _noop.noop;
|
||||
writeOtherRules = _noop.noop;
|
||||
}
|
||||
} (adguardhome.__exports));
|
||||
return adguardhome.__exports;
|
||||
}exports.__require=requireAdguardhome;
|
||||
63
Dist/Build/lib/writing-strategy/base.cjs
Normal file
63
Dist/Build/lib/writing-strategy/base.cjs
Normal file
@@ -0,0 +1,63 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const base=require('../../../_virtual/base2.cjs'),createFile=require('../create-file.cjs');var hasRequiredBase;
|
||||
|
||||
function requireBase () {
|
||||
if (hasRequiredBase) return base.__exports;
|
||||
hasRequiredBase = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "BaseWriteStrategy", {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return BaseWriteStrategy;
|
||||
}
|
||||
});
|
||||
const _createfile = /*@__PURE__*/ createFile.__require();
|
||||
class BaseWriteStrategy {
|
||||
outputDir;
|
||||
/**
|
||||
* Sometimes a ruleset will create extra files (e.g. reject-url-regex w/ mitm.sgmodule),
|
||||
* and doesn't share the same filename and id. This property is used to overwrite the filename.
|
||||
*/ overwriteFilename;
|
||||
withFilename(filename) {
|
||||
this.overwriteFilename = filename;
|
||||
return this;
|
||||
}
|
||||
constructor(outputDir){
|
||||
this.outputDir = outputDir;
|
||||
this.overwriteFilename = null;
|
||||
}
|
||||
static domainWildCardToRegex = (domain)=>{
|
||||
let result = '^';
|
||||
for(let i = 0, len = domain.length; i < len; i++){
|
||||
switch(domain[i]){
|
||||
case '.':
|
||||
result += String.raw`\.`;
|
||||
break;
|
||||
case '*':
|
||||
result += String.raw`[\w.-]*?`;
|
||||
break;
|
||||
case '?':
|
||||
result += String.raw`[\w.-]`;
|
||||
break;
|
||||
default:
|
||||
result += domain[i];
|
||||
}
|
||||
}
|
||||
result += '$';
|
||||
return result;
|
||||
};
|
||||
output(span, title, description, date, filePath) {
|
||||
if (!this.result) {
|
||||
return;
|
||||
}
|
||||
return (0, _createfile.compareAndWriteFile)(span, this.withPadding(title, description, date, this.result), filePath);
|
||||
}
|
||||
get content() {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
} (base.__exports));
|
||||
return base.__exports;
|
||||
}exports.__require=requireBase;
|
||||
172
Dist/Build/lib/writing-strategy/clash.cjs
Normal file
172
Dist/Build/lib/writing-strategy/clash.cjs
Normal file
@@ -0,0 +1,172 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const clash=require('../../../_virtual/clash.cjs'),require$$0=require('foxts/append-set-elements-to-array'),base=require('./base.cjs'),require$$2=require('foxts/noop'),misc=require('../misc.cjs'),dir=require('../../constants/dir.cjs'),appendArrayInPlace=require('../append-array-in-place.cjs');var hasRequiredClash;
|
||||
|
||||
function requireClash () {
|
||||
if (hasRequiredClash) return clash.__exports;
|
||||
hasRequiredClash = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
ClashClassicRuleSet: function() {
|
||||
return ClashClassicRuleSet;
|
||||
},
|
||||
ClashDomainSet: function() {
|
||||
return ClashDomainSet;
|
||||
},
|
||||
ClashIPSet: function() {
|
||||
return ClashIPSet;
|
||||
}
|
||||
});
|
||||
const _appendsetelementstoarray = require$$0;
|
||||
const _base = /*@__PURE__*/ base.__require();
|
||||
const _noop = require$$2;
|
||||
const _misc = /*@__PURE__*/ misc.__require();
|
||||
const _dir = /*@__PURE__*/ dir.__require();
|
||||
const _appendarrayinplace = /*@__PURE__*/ appendArrayInPlace.__require();
|
||||
class ClashDomainSet extends _base.BaseWriteStrategy {
|
||||
outputDir;
|
||||
// readonly type = 'domainset';
|
||||
fileExtension;
|
||||
type;
|
||||
result;
|
||||
constructor(outputDir = _dir.OUTPUT_CLASH_DIR){
|
||||
super(outputDir), this.outputDir = outputDir, this.fileExtension = 'txt', this.type = 'domainset', this.result = [
|
||||
'this_ruleset_is_made_by_sukkaw.ruleset.skk.moe'
|
||||
], this.withPadding = _misc.withBannerArray, this.writeDomainKeywords = _noop.noop, this.writeDomainWildcards = _noop.noop, this.writeUserAgents = _noop.noop, this.writeProcessNames = _noop.noop, this.writeProcessPaths = _noop.noop, this.writeUrlRegexes = _noop.noop, this.writeIpCidrs = _noop.noop, this.writeIpCidr6s = _noop.noop, this.writeGeoip = _noop.noop, this.writeIpAsns = _noop.noop, this.writeSourceIpCidrs = _noop.noop, this.writeSourcePorts = _noop.noop, this.writeDestinationPorts = _noop.noop, this.writeOtherRules = _noop.noop;
|
||||
}
|
||||
withPadding;
|
||||
writeDomain(domain) {
|
||||
this.result.push(domain);
|
||||
}
|
||||
writeDomainSuffix(domain) {
|
||||
this.result.push('+.' + domain);
|
||||
}
|
||||
writeDomainKeywords;
|
||||
writeDomainWildcards;
|
||||
writeUserAgents;
|
||||
writeProcessNames;
|
||||
writeProcessPaths;
|
||||
writeUrlRegexes;
|
||||
writeIpCidrs;
|
||||
writeIpCidr6s;
|
||||
writeGeoip;
|
||||
writeIpAsns;
|
||||
writeSourceIpCidrs;
|
||||
writeSourcePorts;
|
||||
writeDestinationPorts;
|
||||
writeOtherRules;
|
||||
}
|
||||
class ClashIPSet extends _base.BaseWriteStrategy {
|
||||
outputDir;
|
||||
// readonly type = 'domainset';
|
||||
fileExtension;
|
||||
type;
|
||||
result;
|
||||
constructor(outputDir = _dir.OUTPUT_CLASH_DIR){
|
||||
super(outputDir), this.outputDir = outputDir, this.fileExtension = 'txt', this.type = 'ip', this.result = [], this.withPadding = _misc.withBannerArray, this.writeDomain = (0, _misc.notSupported)('writeDomain'), this.writeDomainSuffix = (0, _misc.notSupported)('writeDomainSuffix'), this.writeDomainKeywords = (0, _misc.notSupported)('writeDomainKeywords'), this.writeDomainWildcards = (0, _misc.notSupported)('writeDomainWildcards'), this.writeUserAgents = (0, _misc.notSupported)('writeUserAgents'), this.writeProcessNames = (0, _misc.notSupported)('writeProcessNames'), this.writeProcessPaths = (0, _misc.notSupported)('writeProcessPaths'), this.writeUrlRegexes = (0, _misc.notSupported)('writeUrlRegexes'), this.writeGeoip = (0, _misc.notSupported)('writeGeoip'), this.writeIpAsns = (0, _misc.notSupported)('writeIpAsns'), this.writeSourceIpCidrs = (0, _misc.notSupported)('writeSourceIpCidrs'), this.writeSourcePorts = (0, _misc.notSupported)('writeSourcePorts'), this.writeDestinationPorts = _noop.noop, this.writeOtherRules = _noop.noop;
|
||||
}
|
||||
withPadding;
|
||||
writeDomain;
|
||||
writeDomainSuffix;
|
||||
writeDomainKeywords;
|
||||
writeDomainWildcards;
|
||||
writeUserAgents;
|
||||
writeProcessNames;
|
||||
writeProcessPaths;
|
||||
writeUrlRegexes;
|
||||
writeIpCidrs(ipCidr) {
|
||||
(0, _appendarrayinplace.appendArrayInPlace)(this.result, ipCidr);
|
||||
}
|
||||
writeIpCidr6s(ipCidr6) {
|
||||
(0, _appendarrayinplace.appendArrayInPlace)(this.result, ipCidr6);
|
||||
}
|
||||
writeGeoip;
|
||||
writeIpAsns;
|
||||
writeSourceIpCidrs;
|
||||
writeSourcePorts;
|
||||
writeDestinationPorts;
|
||||
writeOtherRules;
|
||||
}
|
||||
class ClashClassicRuleSet extends _base.BaseWriteStrategy {
|
||||
type;
|
||||
outputDir;
|
||||
fileExtension;
|
||||
result;
|
||||
constructor(type/* | (string & {}) */ , outputDir = _dir.OUTPUT_CLASH_DIR){
|
||||
super(outputDir), this.type = type, this.outputDir = outputDir, this.fileExtension = 'txt', this.result = [
|
||||
'DOMAIN,this_ruleset_is_made_by_sukkaw.ruleset.skk.moe'
|
||||
], this.withPadding = _misc.withBannerArray, this.writeUserAgents = _noop.noop, this.writeUrlRegexes = _noop.noop, this.writeOtherRules = _noop.noop;
|
||||
}
|
||||
withPadding;
|
||||
writeDomain(domain) {
|
||||
this.result.push('DOMAIN,' + domain);
|
||||
}
|
||||
writeDomainSuffix(domain) {
|
||||
this.result.push('DOMAIN-SUFFIX,' + domain);
|
||||
}
|
||||
writeDomainKeywords(keyword) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, keyword, (i)=>`DOMAIN-KEYWORD,${i}`);
|
||||
}
|
||||
writeDomainWildcards(wildcard) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, wildcard, (i)=>`DOMAIN-REGEX,${ClashClassicRuleSet.domainWildCardToRegex(i)}`);
|
||||
}
|
||||
writeUserAgents;
|
||||
writeProcessNames(processName) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, processName, (i)=>`PROCESS-NAME,${i}`);
|
||||
}
|
||||
writeProcessPaths(processPath) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, processPath, (i)=>`PROCESS-PATH,${i}`);
|
||||
}
|
||||
writeUrlRegexes;
|
||||
writeIpCidrs(ipCidr, noResolve) {
|
||||
for(let i = 0, len = ipCidr.length; i < len; i++){
|
||||
this.result.push(`IP-CIDR,${ipCidr[i]}${noResolve ? ',no-resolve' : ''}`);
|
||||
}
|
||||
}
|
||||
writeIpCidr6s(ipCidr6, noResolve) {
|
||||
for(let i = 0, len = ipCidr6.length; i < len; i++){
|
||||
this.result.push(`IP-CIDR6,${ipCidr6[i]}${noResolve ? ',no-resolve' : ''}`);
|
||||
}
|
||||
}
|
||||
writeGeoip(geoip, noResolve) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, geoip, (i)=>`GEOIP,${i}${noResolve ? ',no-resolve' : ''}`);
|
||||
}
|
||||
writeIpAsns(asns, noResolve) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, asns, (i)=>`IP-ASN,${i}${noResolve ? ',no-resolve' : ''}`);
|
||||
}
|
||||
writeSourceIpCidrs(sourceIpCidr) {
|
||||
for(let i = 0, len = sourceIpCidr.length; i < len; i++){
|
||||
const value = sourceIpCidr[i];
|
||||
if (value.includes('/')) {
|
||||
this.result.push(`SRC-IP-CIDR,${value}`);
|
||||
continue;
|
||||
}
|
||||
const v = (0, _misc.fastIpVersion)(value);
|
||||
if (v === 4) {
|
||||
this.result.push(`SRC-IP-CIDR,${value}/32`);
|
||||
continue;
|
||||
}
|
||||
if (v === 6) {
|
||||
this.result.push(`SRC-IP-CIDR6,${value}/128`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
writeSourcePorts(port) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, port, (i)=>`SRC-PORT,${i}`);
|
||||
}
|
||||
writeDestinationPorts(port) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, port, (i)=>`DST-PORT,${i}`);
|
||||
}
|
||||
writeOtherRules;
|
||||
}
|
||||
} (clash.__exports));
|
||||
return clash.__exports;
|
||||
}exports.__require=requireClash;
|
||||
121
Dist/Build/lib/writing-strategy/singbox.cjs
Normal file
121
Dist/Build/lib/writing-strategy/singbox.cjs
Normal file
@@ -0,0 +1,121 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const singbox=require('../../../_virtual/singbox.cjs'),base=require('./base.cjs'),appendArrayInPlace=require('../append-array-in-place.cjs'),require$$2=require('foxts/noop'),misc=require('../misc.cjs'),require$$4=require('json-stringify-pretty-compact'),dir=require('../../constants/dir.cjs');var hasRequiredSingbox;
|
||||
|
||||
function requireSingbox () {
|
||||
if (hasRequiredSingbox) return singbox.__exports;
|
||||
hasRequiredSingbox = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "SingboxSource", {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return SingboxSource;
|
||||
}
|
||||
});
|
||||
const _base = /*@__PURE__*/ base.__require();
|
||||
const _appendarrayinplace = /*@__PURE__*/ appendArrayInPlace.__require();
|
||||
const _noop = require$$2;
|
||||
const _misc = /*@__PURE__*/ misc.__require();
|
||||
const _jsonstringifyprettycompact = /*#__PURE__*/ _interop_require_default(require$$4);
|
||||
const _dir = /*@__PURE__*/ dir.__require();
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
class SingboxSource extends _base.BaseWriteStrategy {
|
||||
type;
|
||||
outputDir;
|
||||
fileExtension;
|
||||
static jsonToLines = (json)=>(0, _jsonstringifyprettycompact.default)(json).split('\n');
|
||||
singbox;
|
||||
get result() {
|
||||
return SingboxSource.jsonToLines({
|
||||
version: 2,
|
||||
rules: [
|
||||
this.singbox
|
||||
]
|
||||
});
|
||||
}
|
||||
constructor(/** Since sing-box only have one format that does not reflect type, we need to specify it */ type/* | (string & {}) */ , outputDir = _dir.OUTPUT_SINGBOX_DIR){
|
||||
super(outputDir), this.type = type, this.outputDir = outputDir, this.fileExtension = 'json', this.singbox = {
|
||||
domain: [
|
||||
'this_ruleset_is_made_by_sukkaw.ruleset.skk.moe'
|
||||
],
|
||||
domain_suffix: [
|
||||
'this_ruleset_is_made_by_sukkaw.ruleset.skk.moe'
|
||||
]
|
||||
}, this.withPadding = _misc.withIdentityContent, this.writeUserAgents = _noop.noop, this.writeUrlRegexes = _noop.noop, this.writeGeoip = _noop.noop, this.writeIpAsns = _noop.noop, this.writeOtherRules = _noop.noop;
|
||||
}
|
||||
withPadding;
|
||||
writeDomain(domain) {
|
||||
this.singbox.domain.push(domain);
|
||||
}
|
||||
writeDomainSuffix(domain) {
|
||||
this.singbox.domain_suffix.push(domain);
|
||||
}
|
||||
writeDomainKeywords(keyword) {
|
||||
(0, _appendarrayinplace.appendArrayInPlace)(this.singbox.domain_keyword ??= [], Array.from(keyword));
|
||||
}
|
||||
writeDomainWildcards(wildcard) {
|
||||
(0, _appendarrayinplace.appendArrayInPlace)(this.singbox.domain_regex ??= [], Array.from(wildcard, SingboxSource.domainWildCardToRegex));
|
||||
}
|
||||
writeUserAgents;
|
||||
writeProcessNames(processName) {
|
||||
(0, _appendarrayinplace.appendArrayInPlace)(this.singbox.process_name ??= [], Array.from(processName));
|
||||
}
|
||||
writeProcessPaths(processPath) {
|
||||
(0, _appendarrayinplace.appendArrayInPlace)(this.singbox.process_path ??= [], Array.from(processPath));
|
||||
}
|
||||
writeUrlRegexes;
|
||||
writeIpCidrs(ipCidr) {
|
||||
(0, _appendarrayinplace.appendArrayInPlace)(this.singbox.ip_cidr ??= [], ipCidr);
|
||||
}
|
||||
writeIpCidr6s(ipCidr6) {
|
||||
(0, _appendarrayinplace.appendArrayInPlace)(this.singbox.ip_cidr ??= [], ipCidr6);
|
||||
}
|
||||
writeGeoip;
|
||||
writeIpAsns;
|
||||
writeSourceIpCidrs(sourceIpCidr) {
|
||||
this.singbox.source_ip_cidr ??= [];
|
||||
for(let i = 0, len = sourceIpCidr.length; i < len; i++){
|
||||
const value = sourceIpCidr[i];
|
||||
if (value.includes('/')) {
|
||||
this.singbox.source_ip_cidr.push(value);
|
||||
continue;
|
||||
}
|
||||
const v = (0, _misc.fastIpVersion)(value);
|
||||
if (v === 4) {
|
||||
this.singbox.source_ip_cidr.push(`${value}/32`);
|
||||
continue;
|
||||
}
|
||||
if (v === 6) {
|
||||
this.singbox.source_ip_cidr.push(`${value}/128`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
writeSourcePorts(port) {
|
||||
this.singbox.source_port ??= [];
|
||||
for (const i of port){
|
||||
const tmp = Number(i);
|
||||
if (!Number.isNaN(tmp)) {
|
||||
this.singbox.source_port.push(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
writeDestinationPorts(port) {
|
||||
this.singbox.port ??= [];
|
||||
for (const i of port){
|
||||
const tmp = Number(i);
|
||||
if (!Number.isNaN(tmp)) {
|
||||
this.singbox.port.push(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
writeOtherRules;
|
||||
}
|
||||
} (singbox.__exports));
|
||||
return singbox.__exports;
|
||||
}exports.__require=requireSingbox;
|
||||
246
Dist/Build/lib/writing-strategy/surge.cjs
Normal file
246
Dist/Build/lib/writing-strategy/surge.cjs
Normal file
@@ -0,0 +1,246 @@
|
||||
'use strict';Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});const surge=require('../../../_virtual/surge.cjs'),require$$0=require('foxts/append-set-elements-to-array'),base=require('./base.cjs'),appendArrayInPlace=require('../append-array-in-place.cjs'),require$$2=require('foxts/noop'),require$$2$1=require('foxts/is-probably-ip'),require$$0$1=require('picocolors'),normalizeDomain=require('../normalize-domain.cjs'),dir=require('../../constants/dir.cjs'),misc=require('../misc.cjs');var hasRequiredSurge;
|
||||
|
||||
function requireSurge () {
|
||||
if (hasRequiredSurge) return surge.__exports;
|
||||
hasRequiredSurge = 1;
|
||||
(function (exports) {
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
SurgeDomainSet: function() {
|
||||
return SurgeDomainSet;
|
||||
},
|
||||
SurgeMitmSgmodule: function() {
|
||||
return SurgeMitmSgmodule;
|
||||
},
|
||||
SurgeRuleSet: function() {
|
||||
return SurgeRuleSet;
|
||||
}
|
||||
});
|
||||
const _appendsetelementstoarray = require$$0;
|
||||
const _base = /*@__PURE__*/ base.__require();
|
||||
const _appendarrayinplace = /*@__PURE__*/ appendArrayInPlace.__require();
|
||||
const _noop = require$$2;
|
||||
const _isprobablyip = require$$2$1;
|
||||
const _picocolors = /*#__PURE__*/ _interop_require_default(require$$0$1);
|
||||
const _normalizedomain = /*@__PURE__*/ normalizeDomain.__require();
|
||||
const _dir = /*@__PURE__*/ dir.__require();
|
||||
const _misc = /*@__PURE__*/ misc.__require();
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
class SurgeDomainSet extends _base.BaseWriteStrategy {
|
||||
// readonly type = 'domainset';
|
||||
fileExtension = 'conf';
|
||||
type = 'domainset';
|
||||
result = [
|
||||
'this_ruleset_is_made_by_sukkaw.ruleset.skk.moe'
|
||||
];
|
||||
constructor(outputDir = _dir.OUTPUT_SURGE_DIR){
|
||||
super(outputDir);
|
||||
}
|
||||
withPadding = _misc.withBannerArray;
|
||||
writeDomain(domain) {
|
||||
this.result.push(domain);
|
||||
}
|
||||
writeDomainSuffix(domain) {
|
||||
this.result.push('.' + domain);
|
||||
}
|
||||
writeDomainKeywords = _noop.noop;
|
||||
writeDomainWildcards = _noop.noop;
|
||||
writeUserAgents = _noop.noop;
|
||||
writeProcessNames = _noop.noop;
|
||||
writeProcessPaths = _noop.noop;
|
||||
writeUrlRegexes = _noop.noop;
|
||||
writeIpCidrs = _noop.noop;
|
||||
writeIpCidr6s = _noop.noop;
|
||||
writeGeoip = _noop.noop;
|
||||
writeIpAsns = _noop.noop;
|
||||
writeSourceIpCidrs = _noop.noop;
|
||||
writeSourcePorts = _noop.noop;
|
||||
writeDestinationPorts = _noop.noop;
|
||||
writeOtherRules = _noop.noop;
|
||||
}
|
||||
class SurgeRuleSet extends _base.BaseWriteStrategy {
|
||||
type;
|
||||
outputDir;
|
||||
fileExtension;
|
||||
result;
|
||||
constructor(/** Surge RULE-SET can be both ip or non_ip, so this needs to be specified */ type, outputDir = _dir.OUTPUT_SURGE_DIR){
|
||||
super(outputDir), this.type = type, this.outputDir = outputDir, this.fileExtension = 'conf', this.result = [
|
||||
'DOMAIN,this_ruleset_is_made_by_sukkaw.ruleset.skk.moe'
|
||||
], this.withPadding = _misc.withBannerArray;
|
||||
}
|
||||
withPadding;
|
||||
writeDomain(domain) {
|
||||
this.result.push('DOMAIN,' + domain);
|
||||
}
|
||||
writeDomainSuffix(domain) {
|
||||
this.result.push('DOMAIN-SUFFIX,' + domain);
|
||||
}
|
||||
writeDomainKeywords(keyword) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, keyword, (i)=>`DOMAIN-KEYWORD,${i}`);
|
||||
}
|
||||
writeDomainWildcards(wildcard) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, wildcard, (i)=>`DOMAIN-WILDCARD,${i}`);
|
||||
}
|
||||
writeUserAgents(userAgent) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, userAgent, (i)=>`USER-AGENT,${i}`);
|
||||
}
|
||||
writeProcessNames(processName) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, processName, (i)=>`PROCESS-NAME,${i}`);
|
||||
}
|
||||
writeProcessPaths(processPath) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, processPath, (i)=>`PROCESS-NAME,${i}`);
|
||||
}
|
||||
writeUrlRegexes(urlRegex) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, urlRegex, (i)=>`URL-REGEX,${i}`);
|
||||
}
|
||||
writeIpCidrs(ipCidr, noResolve) {
|
||||
for(let i = 0, len = ipCidr.length; i < len; i++){
|
||||
this.result.push(`IP-CIDR,${ipCidr[i]}${noResolve ? ',no-resolve' : ''}`);
|
||||
}
|
||||
}
|
||||
writeIpCidr6s(ipCidr6, noResolve) {
|
||||
for(let i = 0, len = ipCidr6.length; i < len; i++){
|
||||
this.result.push(`IP-CIDR6,${ipCidr6[i]}${noResolve ? ',no-resolve' : ''}`);
|
||||
}
|
||||
}
|
||||
writeGeoip(geoip, noResolve) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, geoip, (i)=>`GEOIP,${i}${noResolve ? ',no-resolve' : ''}`);
|
||||
}
|
||||
writeIpAsns(asns, noResolve) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, asns, (i)=>`IP-ASN,${i}${noResolve ? ',no-resolve' : ''}`);
|
||||
}
|
||||
writeSourceIpCidrs(sourceIpCidr) {
|
||||
for(let i = 0, len = sourceIpCidr.length; i < len; i++){
|
||||
this.result.push(`SRC-IP,${sourceIpCidr[i]}`);
|
||||
}
|
||||
}
|
||||
writeSourcePorts(port) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, port, (i)=>`SRC-PORT,${i}`);
|
||||
}
|
||||
writeDestinationPorts(port) {
|
||||
(0, _appendsetelementstoarray.appendSetElementsToArray)(this.result, port, (i)=>`DEST-PORT,${i}`);
|
||||
}
|
||||
writeOtherRules(rule) {
|
||||
(0, _appendarrayinplace.appendArrayInPlace)(this.result, rule);
|
||||
}
|
||||
}
|
||||
class SurgeMitmSgmodule extends _base.BaseWriteStrategy {
|
||||
// readonly type = 'domainset';
|
||||
fileExtension = 'sgmodule';
|
||||
type = '';
|
||||
rules = new Set();
|
||||
get result() {
|
||||
if (this.rules.size === 0) {
|
||||
return null;
|
||||
}
|
||||
return [
|
||||
'#!name=[Sukka] Surge Reject MITM',
|
||||
`#!desc=为 URL Regex 规则组启用 MITM (size: ${this.rules.size})`,
|
||||
'',
|
||||
'[MITM]',
|
||||
'hostname = %APPEND% ' + Array.from(this.rules).join(', ')
|
||||
];
|
||||
}
|
||||
withPadding = _misc.withIdentityContent;
|
||||
constructor(moduleName, outputDir = _dir.OUTPUT_MODULES_DIR){
|
||||
super(outputDir);
|
||||
this.withFilename(moduleName);
|
||||
}
|
||||
writeDomain = _noop.noop;
|
||||
writeDomainSuffix = _noop.noop;
|
||||
writeDomainKeywords = _noop.noop;
|
||||
writeDomainWildcards = _noop.noop;
|
||||
writeUserAgents = _noop.noop;
|
||||
writeProcessNames = _noop.noop;
|
||||
writeProcessPaths = _noop.noop;
|
||||
writeUrlRegexes(urlRegexes) {
|
||||
const urlRegexResults = [];
|
||||
const parsedFailures = [];
|
||||
const parsed = [];
|
||||
for (let urlRegex of urlRegexes){
|
||||
if (urlRegex.startsWith('http://') || urlRegex.startsWith('^http://')) {
|
||||
continue;
|
||||
}
|
||||
if (urlRegex.startsWith('^https?://')) {
|
||||
urlRegex = urlRegex.slice(10);
|
||||
}
|
||||
if (urlRegex.startsWith('^https://')) {
|
||||
urlRegex = urlRegex.slice(9);
|
||||
}
|
||||
const potentialHostname = urlRegex.split('/')[0]// pre process regex
|
||||
.replaceAll(String.raw`\.`, '.').replaceAll('.+', '*').replaceAll(/([a-z])\?/g, '($1|)')// convert regex to surge hostlist syntax
|
||||
.replaceAll('([a-z])', '?').replaceAll(String.raw`\d`, '?').replaceAll(/\*+/g, '*');
|
||||
let processed = [
|
||||
potentialHostname
|
||||
];
|
||||
const matches = [
|
||||
...potentialHostname.matchAll(/\((?:([^()|]+)\|)+([^()|]*)\)/g)
|
||||
];
|
||||
if (matches.length > 0) {
|
||||
const replaceVariant = (combinations, fullMatch, options)=>{
|
||||
const newCombinations = [];
|
||||
combinations.forEach((combination)=>{
|
||||
options.forEach((option)=>{
|
||||
newCombinations.push(combination.replace(fullMatch, option));
|
||||
});
|
||||
});
|
||||
return newCombinations;
|
||||
};
|
||||
for(let i = 0; i < matches.length; i++){
|
||||
const match = matches[i];
|
||||
const [_, ...options] = match;
|
||||
processed = replaceVariant(processed, _, options);
|
||||
}
|
||||
}
|
||||
urlRegexResults.push({
|
||||
origin: potentialHostname,
|
||||
processed
|
||||
});
|
||||
}
|
||||
for (const i of urlRegexResults){
|
||||
for (const processed of i.processed){
|
||||
if ((0, _normalizedomain.normalizeDomain)(processed.replaceAll('*', 'a').replaceAll('?', 'b'))) {
|
||||
parsed.push([
|
||||
i.origin,
|
||||
processed
|
||||
]);
|
||||
} else if (!(0, _isprobablyip.isProbablyIpv4)(processed)) {
|
||||
parsedFailures.push([
|
||||
i.origin,
|
||||
processed
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parsedFailures.length > 0) {
|
||||
console.error(_picocolors.default.bold('Parsed Failed'));
|
||||
console.table(parsedFailures);
|
||||
}
|
||||
for(let i = 0, len = parsed.length; i < len; i++){
|
||||
this.rules.add(parsed[i][1]);
|
||||
}
|
||||
}
|
||||
writeIpCidrs = _noop.noop;
|
||||
writeIpCidr6s = _noop.noop;
|
||||
writeGeoip = _noop.noop;
|
||||
writeIpAsns = _noop.noop;
|
||||
writeSourceIpCidrs = _noop.noop;
|
||||
writeSourcePorts = _noop.noop;
|
||||
writeDestinationPorts = _noop.noop;
|
||||
writeOtherRules = _noop.noop;
|
||||
}
|
||||
} (surge.__exports));
|
||||
return surge.__exports;
|
||||
}exports.__require=requireSurge;
|
||||
Reference in New Issue
Block a user