diff --git a/.gitignore b/.gitignore index eea85fc7e..bc7cb211e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ List Clash Modules/sukka_local_dns_mapping.sgmodule +Modules/sukka_url_redirect.sgmodule diff --git a/Build/build-internal-cdn-rules.js b/Build/build-internal-cdn-rules.js index ca7873249..989c9a17e 100644 --- a/Build/build-internal-cdn-rules.js +++ b/Build/build-internal-cdn-rules.js @@ -10,12 +10,7 @@ const { compareAndWriteFile } = require('./lib/create-file'); const { getGorhillPublicSuffixPromise } = require('./lib/get-gorhill-publicsuffix'); const { createCachedGorhillGetDomain } = require('./lib/cached-tld-parse'); -/** - * @param {string} string - */ -const escapeRegExp = (string) => { - return string.replaceAll(/[$()*+.?[\\\]^{|}]/g, '\\$&'); -}; +const escapeRegExp = (string = '') => string.replaceAll(/[$()*+.?[\\\]^{|}]/g, '\\$&'); const buildInternalCDNDomains = task(__filename, async () => { const set = new Set(); diff --git a/Build/build-redirect-module.js b/Build/build-redirect-module.js new file mode 100644 index 000000000..ad443e233 --- /dev/null +++ b/Build/build-redirect-module.js @@ -0,0 +1,99 @@ +// @ts-check + +const path = require('path'); +const { task } = require('./lib/trace-runner'); +const { compareAndWriteFile } = require('./lib/create-file'); +const tldts = require('tldts'); + +function escapeRegExp(string = '') { + const reRegExpChar = /[$()*+.?[\\\]^{|}]/g; + const reHasRegExpChar = new RegExp(reRegExpChar.source); + + return string && reHasRegExpChar.test(string) + ? string.replaceAll(reRegExpChar, '\\$&') + : string; +} + +const REDIRECT = /** @type {const} */ ([ + // Gravatar + ['gravatar.neworld.org/', 'https://secure.gravatar.com/'], + ['cdn.v2ex.com/gravatar/', 'https://secure.gravatar.com/'], + // U.SB + ['cdnjs.loli.net/', 'https://cdnjs.cloudflare.com/'], + ['fonts.loli.net/', 'https://fonts.googleapis.com/'], + ['gstatic.loli.net/', 'https://fonts.gstatic.com/'], + ['themes.loli.net/', 'https://themes.googleusercontent.com/'], + ['ajax.loli.net/', 'https://ajax.googleapis.com/'], + ['gravatar.loli.net/', 'https://secure.gravatar.com/'], + // Geekzu + ['gapis.geekzu.org/ajax/', 'https://ajax.googleapis.com/'], + ['fonts.geekzu.org/', 'https://fonts.googleapis.com/'], + ['gapis.geekzu.org/g-fonts/', 'https://fonts.gstatic.com/'], + ['gapis.geekzu.org/g-themes/', 'https://themes.googleusercontent.com/'], + ['sdn.geekzu.org/', 'https://secure.gravatar.com/'], + // cravatar + ['cravatar.cn/', 'https://secure.gravatar.com/'], + // libravatar + ['seccdn.libravatar.org/gravatarproxy/', 'https://secure.gravatar.com/'], + // ghproxy + ['ghproxy.com/', ''], + ['ghps.cc/', ''], + // gh-proxy + ['github.moeyy.xyz/', ''], + // 7ED Services + ['use.sevencdn.com/css', 'https://fonts.googleapis.com/css'], + ['use.sevencdn.com/ajax/libs/', 'https://cdnjs.cloudflare.com/ajax/libs/'], + ['use.sevencdn.com/gajax/', 'https://ajax.googleapis.com/ajax/'], + ['use.sevencdn.com/chart', 'https://chart.googleapis.com/chart'], + ['use.sevencdn.com/avatar', 'https://secure.gravatar.com/avatar'], + ['raw.gitmirror.com/', 'https://raw.githubusercontent.com/'], + ['gist.gitmirror.com/', 'https://gist.githubusercontent.com/'], + ['raw.githubusercontents.com/', 'https://raw.githubusercontent.com/'], + ['gist.githubusercontents.com/', 'https://gist.githubusercontent.com/'], + ['cdn.gitmirror.com/', 'https://cdn.statically.io/'], + // FastGit + ['raw.fastgit.org/', 'https://raw.githubusercontent.com/'], + ['assets.fastgit.org/', 'https://github.githubassets.com/'], + // jsDelivr + ['fastly.jsdelivr.net/', 'https://cdn.jsdelivr.net/'], + ['gcore.jsdelivr.net/', 'https://cdn.jsdelivr.net/'], + // ops.ci + ['jsdelivr.ops.ci/', 'https://cdn.jsdelivr.net/'], + ['fonts.ops.ci/', 'https://fonts.googleapis.com/'], + // onmicrosoft.cn + ['jsd.onmicrosoft.cn/', 'https://cdn.jsdelivr.net/'], + ['npm.onmicrosoft.cn/', 'https://unpkg.com/'], + ['cdnjs.onmicrosoft.cn/', 'https://cdnjs.cloudflare.com/ajax/libs/'], + // KGitHub + ['raw.kgithub.com/', 'https://raw.githubusercontent.com/'], + ['raw.kkgithub.com/', 'https://raw.githubusercontent.com/'], + // Misc + ['pics.javbus.com/', 'https://i0.wp.com/pics.javbus.com/'] +]); + +const buildRedirectModule = task(__filename, async () => { + const domains = Array.from(new Set(REDIRECT.map(([from]) => tldts.getHostname(from)))).filter(Boolean); + + return compareAndWriteFile( + [ + '#!name=[Sukka] URL Redirect', + `#!desc=Last Updated: ${new Date().toISOString()}`, + '', + '[MITM]', + `hostname = %APPEND% ${domains.join(', ')}`, + '', + '[URL Rewrite]', + ...REDIRECT.map(([from, to]) => { + const src = `^https?://${escapeRegExp(from)}(.*)`; + return `${src} ${to}$1 302`; + }) + ], + path.resolve(__dirname, '../Modules/sukka_url_redirect.sgmodule') + ); +}); + +module.exports.buildRedirectModule = buildRedirectModule; + +if (require.main === module) { + buildRedirectModule(); +} diff --git a/Build/index.js b/Build/index.js index ae7c21e3d..693ee510d 100644 --- a/Build/index.js +++ b/Build/index.js @@ -13,6 +13,7 @@ const { buildSpeedtestDomainSet } = require('./build-speedtest-domainset'); const { buildInternalCDNDomains } = require('./build-internal-cdn-rules'); const { buildInternalChnDomains } = require('./build-internal-chn-domains'); const { buildDomesticRuleset } = require('./build-domestic-ruleset'); +const { buildRedirectModule } = require('./build-redirect-module'); const { validate } = require('./validate-domainset'); const { buildPublicHtml } = require('./build-public'); @@ -102,6 +103,8 @@ const endWorker = async (worker) => { const buildInternalChnDomainsPromise = buildInternalChnDomains(); // build:domestic-ruleset const buildDomesticRulesetPromise = downloadPreviousBuildPromise.then(() => buildDomesticRuleset()); + // build:redirect-module + const buildRedirectModulePromise = downloadPreviousBuildPromise.then(() => buildRedirectModule()); const stats = await Promise.all([ downloadPreviousBuildPromise, @@ -118,7 +121,8 @@ const endWorker = async (worker) => { buildInternalCDNDomainsPromise, buildInternalReverseChnCIDRPromise, buildInternalChnDomainsPromise, - buildDomesticRulesetPromise + buildDomesticRulesetPromise, + buildRedirectModulePromise ]); await Promise.all([