Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/core/ProxyRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ import { Utils } from "../lib/Utils";
import { SettingsOperation } from "./SettingsOperation";
import { api } from "../lib/environment";

function regexHostMatches(rule: CompiledProxyRule, host: string): boolean {
if (rule.regex.test(host))
return true;

let normalizedHost = Utils.normalizeIpForMatching(host);
return normalizedHost != null && normalizedHost !== host && rule.regex.test(normalizedHost);
}

export class ProxyRules {

public static compileRules(profile: SmartProfileBase, proxyRules: ProxyRule[]): {
Expand Down Expand Up @@ -370,7 +378,7 @@ export class ProxyRules {
}
}

if (rule.regex.test(domainHostLowerCase))
if (regexHostMatches(rule, domainHostLowerCase))
return rule;
break;

Expand Down Expand Up @@ -448,7 +456,7 @@ export class ProxyRules {

case CompiledProxyRuleType.RegexHost:

if (rule.regex.test(domainHostLowerCase))
if (regexHostMatches(rule, domainHostLowerCase))
return rule;
break;

Expand Down
151 changes: 31 additions & 120 deletions src/lib/RuleImporterSwitchy.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
* @source https://github.com/FelisCatus/SwitchyOmega
* @license GPL3
*/
const { Utils } = require('./Utils');

const strStartsWith = function (str, prefix) {
return str.substr(0, prefix.length) === prefix;
};
Expand Down Expand Up @@ -839,147 +841,56 @@ const Conditions = {
'IpCondition': {
abbrs: ['Ip'],
analyze: function (condition) {
let addr, cache, ip, mask;
let cache, ip, regex;
cache = {
addr: null,
normalized: null
regex: null
};
ip = condition.ip;
if (ip.charCodeAt(0) === '['.charCodeAt(0)) {
ip = ip.substr(1, ip.length - 2);
ip = (condition.ip || '').trim();
if (ip.charCodeAt(0) === '['.charCodeAt(0) && ip.charCodeAt(ip.length - 1) === ']'.charCodeAt(0)) {
ip = ip.substring(1, ip.length - 1).trim();
}
addr = ip + '/' + condition.prefixLength;
cache.addr = this.parseIp(addr);
if (cache.addr == null) {
throw new Error("Invalid IP address " + addr);
regex = Utils.ipCidrNotationToRegExp(ip, String(condition.prefixLength));
if (regex == null) {
throw new Error("Invalid IP address " + ip + '/' + condition.prefixLength);
}
cache.normalized = this.normalizeIp(cache.addr);
mask = cache.addr.v4 ? new IP.v4.Address('255.255.255.255/' + cache.addr.subnetMask) : new IP.v6.Address(this.ipv6Max + '/' + cache.addr.subnetMask);
cache.mask = this.normalizeIp(mask.startAddress());
cache.regex = regex;
return cache;
},
match: function (condition, request, cache) {
let addr;
addr = this.parseIp(request.host);
if (addr == null) {
let normalizedHost;
normalizedHost = Utils.normalizeIpForMatching(request.host);
if (normalizedHost == null) {
return false;
}
cache = cache.analyzed;
if (addr.v4 !== cache.addr.v4) {
return false;
}
return addr.isInSubnet(cache.addr);
return cache.regex.test(normalizedHost);
},
compile: function (condition, cache) {
let hostIsInNet, hostIsInNetEx, hostLooksLikeIp;
cache = cache.analyzed;
hostLooksLikeIp = cache.addr.v4 ? new U2.AST_Binary({
left: new U2.AST_Sub({
expression: new U2.AST_SymbolRef({
name: 'host'
}),
property: new U2.AST_Binary({
left: new U2.AST_Dot({
expression: new U2.AST_SymbolRef({
name: 'host'
}),
property: 'length'
}),
operator: '-',
right: new U2.AST_Number({
value: 1
})
})
}),
operator: '>=',
right: new U2.AST_Number({
value: 0
})
}) : new U2.AST_Binary({
left: new U2.AST_Call({
expression: new U2.AST_Dot({
expression: new U2.AST_SymbolRef({
name: 'host'
}),
property: 'indexOf'
}),
args: [
new U2.AST_String({
value: ':'
})
]
}),
operator: '>=',
right: new U2.AST_Number({
value: 0
})
});
if (cache.addr.subnetMask === 0) {
return hostLooksLikeIp;
}
hostIsInNet = new U2.AST_Call({
expression: new U2.AST_SymbolRef({
name: 'isInNet'
}),
args: [
new U2.AST_SymbolRef({
name: 'host'
}), new U2.AST_String({
value: cache.normalized
}), new U2.AST_String({
value: cache.mask
})
]
});
if (!cache.addr.v4) {
hostIsInNetEx = new U2.AST_Call({
expression: new U2.AST_SymbolRef({
name: 'isInNetEx'
}),
args: [
new U2.AST_SymbolRef({
name: 'host'
}), new U2.AST_String({
value: cache.normalized + cache.addr.subnet
})
]
});
hostIsInNet = new U2.AST_Conditional({
condition: new U2.AST_Binary({
left: new U2.AST_UnaryPrefix({
operator: 'typeof',
expression: new U2.AST_SymbolRef({
name: 'isInNetEx'
})
}),
operator: '===',
right: new U2.AST_String({
value: 'function'
})
}),
consequent: hostIsInNetEx,
alternative: hostIsInNet
});
}
return new U2.AST_Binary({
left: hostLooksLikeIp,
operator: '&&',
right: hostIsInNet
});
return this.regTest('host', cache.regex);
},
str: function (condition) {
return condition.ip + '/' + condition.prefixLength;
},
fromStr: function (str, condition) {
let addr;
addr = this.parseIp(str);
if (addr != null) {
condition.ip = addr.addressMinusSuffix;
condition.prefixLength = addr.subnetMask;
let ip, slashIndex;
str = str.trim();
if (str.charCodeAt(0) === '['.charCodeAt(0) && str.charCodeAt(str.length - 1) === ']'.charCodeAt(0)) {
str = str.substring(1, str.length - 1).trim();
}
slashIndex = str.lastIndexOf('/');
if (slashIndex > 0 && slashIndex < str.length - 1) {
ip = str.substring(0, slashIndex).trim();
condition.ip = ip;
condition.prefixLength = parseInt(str.substring(slashIndex + 1).trim(), 10);
} else {
condition.ip = '0.0.0.0';
condition.prefixLength = 0;
}
if (isNaN(condition.prefixLength)) {
condition.ip = '0.0.0.0';
condition.prefixLength = 0;
}
Comment thread
salarcode marked this conversation as resolved.
return condition;
}
},
Expand Down Expand Up @@ -1876,4 +1787,4 @@ if (typeof (exports) == 'undefined')
exports.RuleImporterSwitchy = {
switchy: Switchy,
compiler: SwitchyCompiler,
}
}
22 changes: 9 additions & 13 deletions src/lib/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -602,25 +602,21 @@ export class Utils {
public static normalizeIpForMatching(host: string): string | null {
if (!host) return null;
let h = host.trim();

// remove surrounding brackets if any
h = h.replace(/^\[|\]$/g, '');
const bracketedHost = h.match(/^\[([^\]]+)\](?::\d+)?$/);
if (bracketedHost) {
h = bracketedHost[1];
}
else {
// remove surrounding brackets if any
h = h.replace(/^\[|\]$/g, '');
}

// If there's an IPv4 tail (possibly with a port), extract it: ::ffff:192.0.2.1 or 192.0.2.1:8080
const ipv4Tail = h.match(/(\d+\.\d+\.\d+\.\d+)(?::\d+)?$/);
if (ipv4Tail) {
return ipv4Tail[1];
}

// Remove trailing :port for IPv6 hosts that lost brackets earlier (e.g. ::1:8080)
if (/:\d+$/.test(h)) {
// Only strip if it looks like a port (all digits) and the rest contains ':' (likely IPv6)
const withoutPort = h.replace(/:\d+$/, '');
if (withoutPort.indexOf(':') >= 0) {
h = withoutPort;
}
}

// If it looks like IPv6, try to expand
if (h.indexOf(':') >= 0) {
const groups = Utils.expandIPv6ToGroups(h);
Expand Down Expand Up @@ -709,4 +705,4 @@ export class Utils {

private static readonly IgnoreDomainExtensions: string[] = [
"000.nl", "999.nl", "aa.no", "ab.ca", "ab.se", "abo.pa", "ac.ae", "ac.at", "ac.be", "ac.be", "ac.cn", "ac.com", "ac.cr", "ac.cy", "ac.fj", "ac.fk", "ac.gn", "ac.id", "ac.il", "ac.im.in", "ac.in", "ac.ir", "ac.jp", "ac.mw", "ac.nz", "ac.pa", "ac.ru", "ac.rw", "ac.se", "ac.th", "ac.tj", "ac.tz", "ac.ug", "ac.uk", "ac.vn", "ac.yu", "ac.zm", "ac.zw", "act.au", "ad.jp", "adm.br", "adult.ht", "adv.br", "aero.mv", "agr.br", "ah.cn", "ah.no", "ak.us", "al.us", "alt.za", "am.br", "ar.us", "army.mil", "arq.br", "art.br", "art.do", "art.dz", "art.ht", "art.pl", "asn.au", "asn.au", "asn.lv", "asso.dz", "asso.fr", "asso.ht", "asso.mc", "ato.br", "av.tr", "az.us", "bbs.tr", "bc.ca", "bd.se", "bel.tr", "bio.br", "biz.az", "biz.cy", "biz.et", "biz.fj", "biz.mv", "biz.nr", "biz.om", "biz.pk", "biz.pl", "biz.pr", "biz.tj", "biz.tr", "biz.tt", "biz.vn", "bj.cn", "bl.uk", "bmd.br", "bu.no", "c.se", "ca.us", "cim.br", "city.za", "ck.ua", "club.tw", "cn.ua", "cng.br", "cnt.br", "co.ag", "co.ao", "co.at", "co.bw", "co.cc.cd", "co.ck", "co.cr", "co.fk", "co.gg", "co.hu", "co.id", "co.il", "co.im", "co.in", "co.ir", "co.je", "co.jp", "co.kr", "co.ls", "co.ma", "co.mu", "co.mw", "co.nz", "co.om", "co.rw", "co.th", "co.tj", "co.tt", "co.ug", "co.uk", "co.us", "co.ve", "co.yu", "co.za", "co.zm", "co.zw", "com.ac", "com.af", "com.ag", "com.ai", "com.al", "com.an", "com.ar", "com.au", "com.aw", "com.ax", "com.az", "com.bb", "com.bd", "com.bm", "com.bn", "com.bo", "com.br", "com.bs", "com.bt", "com.cd", "com.ch", "com.cn", "com.co", "com.cu", "com.cy", "com.dm", "com.do", "com.dz", "com.ec", "com.ee", "com.eg", "com.es", "com.et", "com.fj", "com.fr", "com.ge", "com.gh", "com.gi", "com.gn", "com.gp", "com.gr", "com.hk", "com.hn", "com.hr", "com.ht", "com.jm", "com.jo", "com.kh", "com.kw", "com.ky", "com.kz", "com.lb", "com.lc", "com.li", "com.lk", "com.lr", "com.lv", "com.ly", "com.mg", "com.mk", "com.mo", "com.mt", "com.mu", "com.mv", "com.mw", "com.mx", "com.my", "com.ng", "com.ni", "com.np", "com.nr", "com.om", "com.pa", "com.pe", "com.pf", "com.pg", "com.ph", "com.pk", "com.pl", "com.pr", "com.ps", "com.pt", "com.py", "com.ro", "com.ru", "com.rw", "com.sa", "com.sb", "com.sc", "com.sd", "com.sg", "com.sv", "com.sy", "com.tj", "com.tn", "com.tr", "com.tt", "com.tw", "com.ua", "com.uy", "com.ve", "com.vi", "com.vn", "com.ye", "conf.au", "conf.lv", "coop.br", "coop.ht", "coop.mv", "coop.mw", "cpa.pro", "cq.cn", "cri.nz", "csiro.au", "ct.us", "cv.ua", "d.se", "dc.us", "de.us", "dn.ua", "dni.us", "dp.ua", "dpn.br", "dr.tr", "e.se", "ebiz.tw", "ecn.br", "ed.ao", "ed.cr", "ed.jp", "edu.ac", "edu.af", "edu.al", "edu.an", "edu.au", "edu.az", "edu.bb", "edu.bd", "edu.bm", "edu.bn", "edu.bo", "edu.br", "edu.bt", "edu.cn", "edu.co", "edu.cu", "edu.dm", "edu.do", "edu.dz", "edu.ec", "edu.eg", "edu.es", "edu.et", "edu.ge", "edu.gh", "edu.gi", "edu.gp", "edu.gr", "edu.hk", "edu.hn", "edu.ht", "edu.in", "edu.jm", "edu.jo", "edu.kh", "edu.kw", "edu.ky", "edu.kz", "edu.lb", "edu.lc", "edu.lk", "edu.lr", "edu.lv", "edu.ly", "edu.mg", "edu.mo", "edu.mt", "edu.mv", "edu.mw", "edu.mx", "edu.my", "edu.ng", "edu.ni", "edu.np", "edu.nr", "edu.om", "edu.pa", "edu.pe", "edu.pf", "edu.pk", "edu.pl", "edu.pr", "edu.ps", "edu.pt", "edu.py", "edu.rw", "edu.sa", "edu.sb", "edu.sc", "edu.sd", "edu.sg", "edu.sv", "edu.tj", "edu.tr", "edu.tt", "edu.tw", "edu.ua", "edu.vi", "edu.vn", "edu.za", "eng.br", "ens.tn", "esp.br", "etc.br", "eti.br", "eun.eg", "f.se", "fam.pk", "far.br", "fed.us", "fh.se", "fhs.no", "fhsk.se", "fhv.se", "fi.cr", "fie.ee", "fin.ec", "fin.tn", "firm.ht", "firm.in", "fj.cn", "fl.us", "fm.br", "fm.no", "fnd.br", "fot.br", "from.hr", "fst.br", "g.se", "g12.br", "ga.us", "game.tw", "gd.cn", "geek.nz", "gen.in", "gen.nz", "gen.tr", "ggf.br", "go.cr", "go.id", "go.jp", "go.th", "go.tj", "go.tz", "go.ug", "gob.bo", "gob.do", "gob.es", "gob.hn", "gob.mx", "gob.ni", "gob.pa", "gob.pe", "gob.pk", "gob.sv", "gok.pk", "gon.pk", "gop.pk", "gos.pk", "gouv.fr", "gouv.ht", "gouv.rw", "gov.ac", "gov.ae", "gov.af", "gov.al", "gov.ar", "gov.au", "gov.az", "gov.bb", "gov.bd", "gov.bf", "gov.bm", "gov.bo", "gov.br", "gov.bt", "gov.by", "gov.ch", "gov.cn", "gov.co", "gov.cu", "gov.cx", "gov.dm", "gov.do", "gov.dz", "gov.ec", "gov.eg", "gov.et", "gov.fj", "gov.fk", "gov.ge", "gov.gh", "gov.gi", "gov.gn", "gov.gr", "gov.hk", "gov.ie", "gov.il", "gov.im", "gov.in", "gov.ir", "gov.it", "gov.jm", "gov.jo", "gov.kh", "gov.kw", "gov.ky", "gov.kz", "gov.lb", "gov.lc", "gov.li", "gov.lk", "gov.lr", "gov.lt", "gov.lu", "gov.lv", "gov.ly", "gov.ma", "gov.mg", "gov.mo", "gov.mt", "gov.mv", "gov.mw", "gov.my", "gov.ng", "gov.np", "gov.nr", "gov.om", "gov.ph", "gov.pk", "gov.pl", "gov.pr", "gov.ps", "gov.pt", "gov.py", "gov.rw", "gov.sa", "gov.sb", "gov.sc", "gov.sd", "gov.sg", "gov.sy", "gov.tj", "gov.tn", "gov.to", "gov.tp", "gov.tr", "gov.tt.tv", "gov.tv", "gov.tw", "gov.ua", "gov.uk", "gov.vi", "gov.vn", "gov.za", "gov.zm", "gov.zw", "govt.nz", "gr.jp", "gs.cn", "gub.uy", "gv.ao", "gv.at", "gx.cn", "gz.cn", "h.se", "ha.cn", "hb.cn", "he.cn", "hi.cn", "hi.us", "hl.cn", "hl.no", "hm.no", "hn.cn", "i.se", "ia.us", "id.au", "id.lv", "id.ly", "id.us", "idf.il", "idn.sg", "idv.hk", "idv.tw", "if.ua", "il.us", "imb.br", "in.th", "in.us", "ind.br", "ind.in", "ind.tn", "inf.br", "inf.cu", "info.au", "info.az", "info.cy", "info.ec", "info.et", "info.fj", "info.ht", "info.hu", "info.mv", "info.nr", "info.pl", "info.pr", "info.ro", "info.sd", "info.tn", "info.tr", "info.tt", "info.ve", "info.vn", "ing.pa", "inima.al", "int.ar", "int.az", "int.bo", "int.lk", "int.mv", "int.mw", "int.pt", "int.ru", "int.rw", "int.tj", "int.vn", "intl.tn", "ip6.ar", "ip6.pa", "iris.ar", "iris.pa", "isa.us", "isla.pr", "it.ao", "iwi.nz", "iz.hr", "jet.uk", "jl.cn", "jor.br", "js.cn", "jx.cn", "k.se", "k12.il", "k12.tr", "kh.ua", "kiev.ua", "km.ua", "kr.ua", "ks.ua", "ks.us", "kv.ua", "ky.us", "la.us", "law.pro", "law.za", "lel.br", "lg.jp", "lg.ua", "ln.cn", "ltd.co.im", "ltd.cy", "ltd.gi", "ltd.lk", "ltd.uk", "lviv.ua", "m.se", "ma.us", "mat.br", "mb.ca", "md.us", "me.uk", "me.us", "med.br", "med.ec", "med.ht", "med.ly", "med.om", "med.pa", "med.pro", "med.sa", "med.sd", "mi.th", "mi.us", "mil.ac", "mil.ae", "mil.ar", "mil.az", "mil.bd", "mil.bo", "mil.br", "mil.by", "mil.co", "mil.do", "mil.ec", "mil.eg", "mil.fj", "mil.ge", "mil.gh", "mil.hn", "mil.in", "mil.jo", "mil.kh", "mil.kw", "mil.kz", "mil.lt", "mil.lu", "mil.lv", "mil.mg", "mil.mv", "mil.my", "mil.no", "mil.np", "mil.nz", "mil.om", "mil.pe", "mil.pl", "mil.rw", "mil.se", "mil.tj", "mil.tr", "mil.tw", "mil.uk", "mil.uy", "mil.za", "mk.ua", "mn.us", "mo.us", "mod.gi", "mod.uk", "mr.no", "ms.us", "msk.ru", "mt.us", "muni.il", "mus.br", "n.se", "name.ae", "name.af", "name.az", "name.cy", "name.et", "name.fj", "name.hr", "name.mv", "name.my", "name.pr", "name.ro", "name.tj", "name.tr", "name.tt", "name.vn", "nat.tn", "navy.mil", "nb.ca", "nc.us", "nd.us", "ne.jp", "ne.tz", "ne.ug", "ne.us", "nel.uk", "net.ac", "net.ae", "net.af", "net.ag", "net.ai", "net.al", "net.an", "net.ar", "net.au", "net.az", "net.bb", "net.bd", "net.bm", "net.bn", "net.bo", "net.br", "net.bs", "net.bt", "net.cd", "net.ch", "net.cn", "net.co", "net.cu", "net.cy", "net.dm", "net.do", "net.dz", "net.ec", "net.eg", "net.et", "net.fj", "net.fk", "net.ge", "net.gg", "net.gn", "net.gp", "net.gr", "net.hk", "net.hn", "net.ht", "net.il", "net.im", "net.in", "net.ir", "net.je", "net.jm", "net.jo", "net.kh", "net.kw", "net.ky", "net.kz", "net.lb", "net.li", "net.lk", "net.lr", "net.lu", "net.lv", "net.ly", "net.ma", "net.mo", "net.mt", "net.mv", "net.mw", "net.mx", "net.my", "net.ng", "net.ni", "net.np", "net.nr", "net.nz", "net.om", "net.pa", "net.pe", "net.pg", "net.pk", "net.pl", "net.pr", "net.ps", "net.pt", "net.py", "net.ru", "net.rw", "net.sa", "net.sb", "net.sc", "net.sd", "net.sg", "net.sy", "net.th", "net.tj", "net.tn", "net.tr", "net.tt", "net.tw", "net.ua", "net.uk", "net.uy", "net.ve", "net.vn", "net.ye", "net.za", "nf.ca", "ngo.lk", "ngo.pl", "ngo.za", "nh.us", "nhs.uk", "nic.im", "nic.in", "nic.uk", "nj.us", "nl.ca", "nl.no", "nls.uk", "nm.cn", "nm.us", "nom.adae", "nom.ag", "nom.ai", "nom.br", "nom.co", "nom.es", "nom.fk", "nom.fr", "nom.mg", "nom.ni", "nom.pa", "nom.pe", "nom.ro", "nom.za", "nome.pt", "not.br", "ns.ca", "nsn.us", "nsw.au", "nt.au", "nt.ca", "nt.no", "nt.ro", "ntr.br", "nu.ca", "nv.us", "nx.cn", "ny.us", "o.se", "od.ua", "odo.br", "of.no", "off.ai", "og.ao", "oh.us", "ok.us", "ol.no", "on.ca", "or.at", "or.cr", "or.id", "or.jp", "or.kr", "or.th", "or.tz", "or.ug", "or.us", "org.ac", "org.ae", "org.ag", "org.ai", "org.al", "org.an", "org.au", "org.az", "org.bb", "org.bd", "org.bm", "org.bn", "org.bo", "org.br", "org.bs", "org.bt", "org.bw", "org.cd", "org.ch", "org.cn", "org.co", "org.cu", "org.cy", "org.dm", "org.do", "org.dz", "org.ec", "org.ee", "org.eg", "org.es", "org.et", "org.fj", "org.fk", "org.ge", "org.gg", "org.gh", "org.gi", "org.gn", "org.gp", "org.gr", "org.hk", "org.hn", "org.ht", "org.hu", "org.il", "org.im", "org.in", "org.ir", "org.je", "org.jm", "org.jo", "org.kh", "org.kw", "org.ky", "org.kz", "org.lb", "org.lc", "org.li", "org.lk", "org.lr", "org.ls", "org.lu", "org.lv", "org.ly", "org.ma", "org.mg", "org.mk", "org.mo", "org.mt", "org.mv", "org.mw", "org.mx", "org.my", "org.ng", "org.ni", "org.np", "org.nr", "org.nz", "org.om", "org.pa", "org.pe", "org.pf", "org.pk", "org.pl", "org.pr", "org.ps", "org.pt", "org.py", "org.ro", "org.ru", "org.sa", "org.sc", "org.sd", "org.se", "org.sg", "org.sv", "org.tj", "org.tn", "org.tr", "org.tt", "org.tw", "org.ua", "org.uk", "org.uy", "org.ve", "org.vi", "org.vn", "org.yu", "org.za", "org.zm", "org.zw", "oz.au", "pa.us", "pb.ao", "pe.ca", "per.kh", "per.sg", "perso.ht", "pl.ua", "plc.co.im", "plc.ly", "plc.uk", "plo.ps", "pol.dz", "pol.ht", "pol.tr", "pp.az", "pp.ru", "pp.se", "ppg.br", "prd.fr", "prd.mg", "pri.ee", "priv.at", "priv.hu", "pro.ae", "pro.br", "pro.cy", "pro.ec", "pro.fj", "pro.ht", "pro.mv", "pro.om", "pro.pr", "pro.tt", "pro.vn", "psc.br", "psi.br", "pub.sa", "publ.pt", "pvt.ge", "qc.ca", "qh.cn", "qld.au", "qsl.br", "rec.br", "rec.ro", "red.sv", "rel.ht", "res.in", "ri.us", "rl.no", "rv.ua", "s.se", "sa.au", "sa.cr", "sc.cn", "sc.ug", "sc.us", "sch.ae", "sch.ir", "sch.lk", "sch.ly", "sch.om", "sch.sa", "sch.uk", "sch.zm", "sci.eg", "sd.cn", "sd.us", "sec.ps", "sf.no", "sh.cn", "shop.ht", "sk.ca", "sld.do", "sld.pa", "slg.br", "sn.cn", "soc.lk", "soros.al", "sport.hu", "srv.br", "sshn.se", "st.no", "sumy.ua", "sx.cn", "t.se", "tas.au", "te.ua", "tel.tr", "tirana.al", "tj.cn", "tm.cy", "tm.fr", "tm.hu", "tm.mc", "tm.mg", "tm.no", "tm.ro", "tm.se", "tm.za", "tmp.br", "tn.us", "tr.no", "trd.br", "tur.br", "tv.bo", "tv.br", "tv.sd", "tx.us", "u.se", "uniti.al", "upt.al", "uri.ar", "uri.pa", "us.com", "ut.us", "va.no", "va.us", "vet.br", "vf.no", "vgs.no", "vic.au", "vn.ua", "vt.us", "w.se", "wa.au", "wa.us", "waw.pl", "web.do", "web.lk", "web.pk", "web.tj", "web.tr", "web.ve", "wi.us", "wv.us", "www.ro", "x.se", "xj.cn", "xz.cn", "y.se", "yk.ca", "yn.cn", "z.se", "zj.cn", "zlg.br", "zp.ua", "zt.ua"]
}
}
15 changes: 15 additions & 0 deletions src/tests/ProxyRules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ProxyRules } from '../core/ProxyRules';
import { GeneralOptions, ProxyRule, ProxyRuleType, CompiledProxyRuleType, SmartProfileBase, SettingsConfig, SmartProfile, SmartProfileType, getSmartProfileTypeConfig } from '../core/definitions';
import { ProfileRules } from '../core/ProfileRules';
import { Settings } from '../core/Settings';
import { externalAppRuleParser } from '../lib/RuleImporter';

describe('ProxyRules.compileRules', () => {
// Create minimal mock profile for testing
Expand Down Expand Up @@ -84,6 +85,20 @@ describe('ProxyRules.compileRules', () => {
expect(result.compiledWhiteList).toHaveLength(1);
expect(result.compiledWhiteList[0].search).toBe('allowed.com');
});

it('should match imported SwitchyOmega IPv6 CIDR rules after host normalization', () => {
const text = `[SwitchyOmega Conditions]
Ip: 2001:db8::1/128`;

const parsed = externalAppRuleParser.Switchy.parseAndCompile(text);
const importedRules = externalAppRuleParser.Switchy.convertToProxyRule(parsed.compiled);
const proxyRules = importedRules.map(rule => rule.getProxyRule());
const result = ProxyRules.compileRules(createMockProfile(), proxyRules);

expect(result.compiledList).toHaveLength(1);
expect(ProxyRules.findMatchedUrlInRules('http://[2001:db8::1]/', result.compiledList)).toBeDefined();
expect(ProxyRules.findMatchedUrlInRules('http://[2001:db8::2]/', result.compiledList)).toBeNull();
});
});

describe('ProfileRules.toggleRule', () => {
Expand Down
Loading