2024-12-27 21:35:51 +08:00

505 lines
16 KiB
JavaScript

import $ from '@/core/app';
const ISOFlags = {
'🏳️‍🌈': ['EXP', 'BAND'],
'🇸🇱': ['TEST', 'SOS'],
'🇦🇩': ['AD', 'AND'],
'🇦🇪': ['AE', 'ARE'],
'🇦🇫': ['AF', 'AFG'],
'🇦🇱': ['AL', 'ALB'],
'🇦🇲': ['AM', 'ARM'],
'🇦🇷': ['AR', 'ARG'],
'🇦🇹': ['AT', 'AUT'],
'🇦🇺': ['AU', 'AUS'],
'🇦🇿': ['AZ', 'AZE'],
'🇧🇦': ['BA', 'BIH'],
'🇧🇩': ['BD', 'BGD'],
'🇧🇪': ['BE', 'BEL'],
'🇧🇬': ['BG', 'BGR'],
'🇧🇭': ['BH', 'BHR'],
'🇧🇴': ['BO', 'BOL'],
'🇧🇷': ['BR', 'BRA'],
'🇧🇾': ['BY', 'BLR'],
'🇨🇦': ['CA', 'CAN'],
'🇨🇭': ['CH', 'CHE'],
'🇨🇱': ['CL', 'CHL'],
'🇨🇴': ['CO', 'COL'],
'🇨🇷': ['CR', 'CRI'],
'🇨🇾': ['CY', 'CYP'],
'🇨🇿': ['CZ', 'CZE'],
'🇩🇪': ['DE', 'DEU'],
'🇩🇰': ['DK', 'DNK'],
'🇪🇨': ['EC', 'ECU'],
'🇪🇪': ['EE', 'EST'],
'🇪🇬': ['EG', 'EGY'],
'🇪🇸': ['ES', 'ESP'],
'🇪🇺': ['EU'],
'🇫🇮': ['FI', 'FIN'],
'🇫🇷': ['FR', 'FRA'],
'🇬🇧': ['GB', 'GBR', 'UK'],
'🇬🇪': ['GE', 'GEO'],
'🇬🇷': ['GR', 'GRC'],
'🇬🇹': ['GT', 'GTM'],
'🇭🇰': ['HK', 'HKG', 'HKT', 'HKBN', 'HGC', 'WTT', 'CMI'],
'🇭🇷': ['HR', 'HRV'],
'🇭🇺': ['HU', 'HUN'],
'🇯🇴': ['JO', 'JOR'],
'🇯🇵': ['JP', 'JPN', 'TYO'],
'🇰🇪': ['KE', 'KEN'],
'🇰🇬': ['KG', 'KGZ'],
'🇰🇭': ['KH', 'KGZ'],
'🇰🇵': ['KP', 'PRK'],
'🇰🇷': ['KR', 'KOR', 'SEL'],
'🇰🇿': ['KZ', 'KAZ'],
'🇮🇩': ['ID', 'IDN'],
'🇮🇪': ['IE', 'IRL'],
'🇮🇱': ['IL', 'ISR'],
'🇮🇲': ['IM', 'IMN'],
'🇮🇳': ['IN', 'IND'],
'🇮🇷': ['IR', 'IRN'],
'🇮🇸': ['IS', 'ISL'],
'🇮🇹': ['IT', 'ITA'],
'🇱🇹': ['LT', 'LTU'],
'🇱🇺': ['LU', 'LUX'],
'🇱🇻': ['LV', 'LVA'],
'🇲🇦': ['MA', 'MAR'],
'🇲🇩': ['MD', 'MDA'],
'🇳🇬': ['NG', 'NGA'],
'🇲🇰': ['MK', 'MKD'],
'🇲🇳': ['MN', 'MNG'],
'🇲🇴': ['MO', 'MAC', 'CTM'],
'🇲🇹': ['MT', 'MLT'],
'🇲🇽': ['MX', 'MEX'],
'🇲🇾': ['MY', 'MYS'],
'🇳🇱': ['NL', 'NLD', 'AMS'],
'🇳🇴': ['NO', 'NOR'],
'🇳🇵': ['NP', 'NPL'],
'🇳🇿': ['NZ', 'NZL'],
'🇵🇦': ['PA', 'PAN'],
'🇵🇪': ['PE', 'PER'],
'🇵🇭': ['PH', 'PHL'],
'🇵🇰': ['PK', 'PAK'],
'🇵🇱': ['PL', 'POL'],
'🇵🇷': ['PR', 'PRI'],
'🇵🇹': ['PT', 'PRT'],
'🇵🇾': ['PY', 'PRY'],
'🇷🇴': ['RO', 'ROU'],
'🇷🇸': ['RS', 'SRB'],
'🇷🇪': ['RE', 'REU'],
'🇷🇺': ['RU', 'RUS'],
'🇸🇦': ['SA', 'SAU'],
'🇸🇪': ['SE', 'SWE'],
'🇸🇬': ['SG', 'SGP'],
'🇸🇮': ['SI', 'SVN'],
'🇸🇰': ['SK', 'SVK'],
'🇹🇭': ['TH', 'THA'],
'🇹🇳': ['TN', 'TUN'],
'🇹🇷': ['TR', 'TUR'],
'🇹🇼': ['TW', 'TWN', 'CHT', 'HINET', 'ROC'],
'🇺🇦': ['UA', 'UKR'],
'🇺🇸': ['US', 'USA', 'LAX', 'SFO', 'SJC'],
'🇺🇾': ['UY', 'URY'],
'🇻🇪': ['VE', 'VEN'],
'🇻🇳': ['VN', 'VNM'],
'🇿🇦': ['ZA', 'ZAF', 'JNB'],
'🇨🇳': ['CN', 'CHN', 'BACK'],
};
// get proxy flag according to its name
export function getFlag(name) {
// flags from @KOP-XIAO: https://github.com/KOP-XIAO/QuantumultX/blob/master/Scripts/resource-parser.js
// flags from @surgioproject: https://github.com/surgioproject/surgio/blob/master/lib/misc/flag_cn.ts
// refer: https://zh.wikipedia.org/wiki/ISO_3166-1二位字母代码
// refer: https://zh.wikipedia.org/wiki/ISO_3166-1三位字母代码
const Flags = {
'🏳️‍🌈': ['流量', '时间', '过期', 'Bandwidth', 'Expire'],
'🇸🇱': ['应急', '测试节点'],
'🇦🇩': ['Andorra', '安道尔'],
'🇦🇪': ['United Arab Emirates', '阿联酋', '迪拜'],
'🇦🇫': ['Afghanistan', '阿富汗'],
'🇦🇱': ['Albania', '阿尔巴尼亚', '阿爾巴尼亞'],
'🇦🇲': ['Armenia', '亚美尼亚'],
'🇦🇷': ['Argentina', '阿根廷'],
'🇦🇹': ['Austria', '奥地利', '奧地利', '维也纳'],
'🇦🇺': [
'Australia',
'澳大利亚',
'澳洲',
'墨尔本',
'悉尼',
'土澳',
'京澳',
'廣澳',
'滬澳',
'沪澳',
'广澳',
'Sydney',
],
'🇦🇿': ['Azerbaijan', '阿塞拜疆'],
'🇧🇦': ['Bosnia and Herzegovina', '波黑共和国', '波黑'],
'🇧🇩': ['Bangladesh', '孟加拉国', '孟加拉'],
'🇧🇪': ['Belgium', '比利时', '比利時'],
'🇧🇬': ['Bulgaria', '保加利亚', '保加利亞'],
'🇧🇭': ['Bahrain', '巴林'],
'🇧🇷': ['Brazil', '巴西', '圣保罗'],
'🇧🇾': ['Belarus', '白俄罗斯', '白俄'],
'🇧🇴': ['Bolivia', '玻利维亚'],
'🇨🇦': [
'Canada',
'加拿大',
'蒙特利尔',
'温哥华',
'楓葉',
'枫叶',
'滑铁卢',
'多伦多',
'Waterloo',
'Toronto',
],
'🇨🇭': ['Switzerland', '瑞士', '苏黎世', 'Zurich'],
'🇨🇱': ['Chile', '智利'],
'🇨🇴': ['Colombia', '哥伦比亚'],
'🇨🇷': ['Costa Rica', '哥斯达黎加'],
'🇨🇾': ['Cyprus', '塞浦路斯'],
'🇨🇿': ['Czechia', '捷克'],
'🇩🇪': [
'German',
'德国',
'德國',
'京德',
'滬德',
'廣德',
'沪德',
'广德',
'法兰克福',
'Frankfurt',
'德意志',
],
'🇩🇰': ['Denmark', '丹麦', '丹麥'],
'🇪🇨': ['Ecuador', '厄瓜多尔'],
'🇪🇪': ['Estonia', '爱沙尼亚'],
'🇪🇬': ['Egypt', '埃及'],
'🇪🇸': ['Spain', '西班牙'],
'🇪🇺': ['European Union', '欧盟', '欧罗巴'],
'🇫🇮': ['Finland', '芬兰', '芬蘭', '赫尔辛基'],
'🇫🇷': ['France', '法国', '法國', '巴黎'],
'🇬🇧': [
'Great Britain',
'英国',
'England',
'United Kingdom',
'伦敦',
'英',
'London',
],
'🇬🇪': ['Georgia', '格鲁吉亚', '格魯吉亞'],
'🇬🇷': ['Greece', '希腊', '希臘'],
'🇬🇹': ['Guatemala', '危地马拉'],
'🇭🇰': [
'Hongkong',
'香港',
'Hong Kong',
'HongKong',
'HONG KONG',
'深港',
'沪港',
'呼港',
'穗港',
'京港',
'港',
],
'🇭🇷': ['Croatia', '克罗地亚', '克羅地亞'],
'🇭🇺': ['Hungary', '匈牙利'],
'🇯🇴': ['Jordan', '约旦'],
'🇯🇵': [
'Japan',
'日本',
'东京',
'大阪',
'埼玉',
'沪日',
'穗日',
'川日',
'中日',
'泉日',
'杭日',
'深日',
'辽日',
'广日',
'大坂',
'Osaka',
'Tokyo',
],
'🇰🇪': ['Kenya', '肯尼亚'],
'🇰🇬': ['Kyrgyzstan', '吉尔吉斯斯坦'],
'🇰🇭': ['Cambodia', '柬埔寨'],
'🇰🇵': ['North Korea', '朝鲜'],
'🇰🇷': [
'Korea',
'韩国',
'韓國',
'韩',
'韓',
'首尔',
'春川',
'Chuncheon',
'Seoul',
],
'🇰🇿': ['Kazakhstan', '哈萨克斯坦', '哈萨克'],
'🇮🇩': ['Indonesia', '印尼', '印度尼西亚', '雅加达'],
'🇮🇪': ['Ireland', '爱尔兰', '愛爾蘭', '都柏林'],
'🇮🇱': ['Israel', '以色列'],
'🇮🇲': ['Isle of Man', '马恩岛', '馬恩島'],
'🇮🇳': ['India', '印度', '孟买', 'MFumbai', 'Mumbai'],
'🇮🇷': ['Iran', '伊朗'],
'🇮🇸': ['Iceland', '冰岛', '冰島'],
'🇮🇹': ['Italy', '意大利', '義大利', '米兰', 'Nachash'],
'🇱🇹': ['Lithuania', '立陶宛'],
'🇱🇺': ['Luxembourg', '卢森堡'],
'🇱🇻': ['Latvia', '拉脱维亚', 'Latvija'],
'🇲🇦': ['Morocco', '摩洛哥'],
'🇲🇩': ['Moldova', '摩尔多瓦', '摩爾多瓦'],
'🇳🇬': ['Nigeria', '尼日利亚', '尼日利亞'],
'🇲🇰': ['Macedonia', '马其顿', '馬其頓'],
'🇲🇳': ['Mongolia', '蒙古'],
'🇲🇴': ['Macao', '澳门', '澳門', 'CTM'],
'🇲🇹': ['Malta', '马耳他'],
'🇲🇽': ['Mexico', '墨西哥'],
'🇲🇾': ['Malaysia', '马来', '馬來', '吉隆坡', '大馬'],
'🇳🇱': [
'Netherlands',
'荷兰',
'荷蘭',
'尼德蘭',
'阿姆斯特丹',
'Amsterdam',
],
'🇳🇴': ['Norway', '挪威'],
'🇳🇵': ['Nepal', '尼泊尔'],
'🇳🇿': ['New Zealand', '新西兰', '新西蘭'],
'🇵🇦': ['Panama', '巴拿马'],
'🇵🇪': ['Peru', '秘鲁', '祕魯'],
'🇵🇭': ['Philippines', '菲律宾', '菲律賓'],
'🇵🇰': ['Pakistan', '巴基斯坦'],
'🇵🇱': ['Poland', '波兰', '波蘭', '华沙', 'Warsaw'],
'🇵🇷': ['Puerto Rico', '波多黎各'],
'🇵🇹': ['Portugal', '葡萄牙'],
'🇵🇾': ['Paraguay', '巴拉圭'],
'🇷🇴': ['Romania', '罗马尼亚'],
'🇷🇸': ['Serbia', '塞尔维亚'],
'🇷🇪': ['Réunion', '留尼汪', '法属留尼汪'],
'🇷🇺': [
'Russia',
'俄罗斯',
'俄国',
'俄羅斯',
'伯力',
'莫斯科',
'圣彼得堡',
'西伯利亚',
'京俄',
'杭俄',
'廣俄',
'滬俄',
'广俄',
'沪俄',
'Moscow',
],
'🇸🇦': ['Saudi', '沙特阿拉伯', '沙特', 'Riyadh', '利雅得'],
'🇸🇪': ['Sweden', '瑞典', '斯德哥尔摩', 'Stockholm'],
'🇸🇬': [
'Singapore',
'新加坡',
'狮城',
'沪新',
'京新',
'中新',
'泉新',
'穗新',
'深新',
'杭新',
'广新',
'廣新',
'滬新',
],
'🇸🇮': ['Slovenia', '斯洛文尼亚'],
'🇸🇰': ['Slovakia', '斯洛伐克'],
'🇹🇭': ['Thailand', '泰国', '泰國', '曼谷'],
'🇹🇳': ['Tunisia', '突尼斯'],
'🇹🇷': ['Turkey', '土耳其', '伊斯坦布尔', 'Istanbul'],
'🇹🇼': [
'Taiwan',
'台湾',
'臺灣',
'台灣',
'中華民國',
'中华民国',
'台北',
'台中',
'新北',
'彰化',
'台',
'臺',
'Taipei',
'Tai Wan',
],
'🇺🇦': ['Ukraine', '乌克兰', '烏克蘭'],
'🇺🇸': [
'United States',
'美国',
'America',
'美',
'京美',
'波特兰',
'达拉斯',
'俄勒冈',
'Oregon',
'凤凰城',
'费利蒙',
'硅谷',
'矽谷',
'拉斯维加斯',
'洛杉矶',
'圣何塞',
'圣克拉拉',
'西雅图',
'芝加哥',
'沪美',
'哥伦布',
'纽约',
'New York',
'Los Angeles',
'San Jose',
'Sillicon Valley',
'Michigan',
'俄亥俄',
'Ohio',
'马纳萨斯',
'Manassas',
'弗吉尼亚',
'Virginia',
],
'🇺🇾': ['Uruguay', '乌拉圭'],
'🇻🇪': ['Venezuela', '委内瑞拉'],
'🇻🇳': ['Vietnam', '越南', '胡志明'],
'🇿🇦': ['South Africa', '南非'],
'🇨🇳': [
'China',
'中国',
'中國',
'回国',
'回國',
'国内',
'國內',
'华东',
'华西',
'华南',
'华北',
'华中',
'江苏',
'北京',
'上海',
'广州',
'深圳',
'杭州',
'徐州',
'青岛',
'宁波',
'镇江',
],
};
// 原旗帜或空
let Flag =
name.match(/[\uD83C][\uDDE6-\uDDFF][\uD83C][\uDDE6-\uDDFF]/)?.[0] ||
'🏴‍☠️';
//console.log(`oldFlag = ${Flag}`)
// 旗帜匹配
for (let flag of Object.keys(Flags)) {
const keywords = Flags[flag];
//console.log(`keywords = ${keywords}`)
if (
// 不精确匹配(只要包含就算,忽略大小写)
keywords.some((keyword) => RegExp(`${keyword}`, 'i').test(name))
) {
if (/内蒙古/.test(name) && ['🇲🇳'].includes(flag)) {
return (Flag = '🇨🇳');
}
return (Flag = flag);
}
}
// ISO旗帜匹配
for (let flag of Object.keys(ISOFlags)) {
const keywords = ISOFlags[flag];
//console.log(`keywords = ${keywords}`)
if (
// 精确匹配(两侧均有分割)
keywords.some((keyword) =>
RegExp(`(^|[^a-zA-Z])${keyword}([^a-zA-Z]|$)`).test(name),
)
) {
const isCN2 =
flag == '🇨🇳' &&
RegExp(`(^|[^a-zA-Z])CN2([^a-zA-Z]|$)`).test(name);
if (!isCN2) {
return (Flag = flag);
}
}
}
//console.log(`Final Flag = ${Flag}`)
return Flag;
}
export function getISO(name) {
return ISOFlags[getFlag(name)]?.[0];
}
// remove flag
export function removeFlag(str) {
return str
.replace(/[\uD83C][\uDDE6-\uDDFF][\uD83C][\uDDE6-\uDDFF]|🏴‍☠️|🏳️‍🌈/g, '')
.trim();
}
export class MMDB {
constructor({ country, asn } = {}) {
if ($.env.isNode) {
const Reader = eval(`require("@maxmind/geoip2-node")`).Reader;
const fs = eval("require('fs')");
const countryFile =
country || eval('process.env.SUB_STORE_MMDB_COUNTRY_PATH');
const asnFile = asn || eval('process.env.SUB_STORE_MMDB_ASN_PATH');
// $.info(
// `GeoLite2 Country MMDB: ${countryFile}, exists: ${fs.existsSync(
// countryFile,
// )}`,
// );
if (countryFile) {
this.countryReader = Reader.openBuffer(
fs.readFileSync(countryFile),
);
}
// $.info(
// `GeoLite2 ASN MMDB: ${asnFile}, exists: ${fs.existsSync(
// asnFile,
// )}`,
// );
if (asnFile) {
if (!fs.existsSync(asnFile))
throw new Error('GeoLite2 ASN MMDB does not exist');
this.asnReader = Reader.openBuffer(fs.readFileSync(asnFile));
}
}
}
geoip(ip) {
return this.countryReader?.country(ip)?.country?.isoCode;
}
ipaso(ip) {
return this.asnReader?.asn(ip)?.autonomousSystemOrganization;
}
ipasn(ip) {
return this.asnReader?.asn(ip)?.autonomousSystemNumber;
}
}