Skip to content

Instantly share code, notes, and snippets.

@anonymamir
Forked from vfarid/sub-nodes-worker.js
Last active February 25, 2023 09:45
Show Gist options
  • Save anonymamir/6397e06afcaffef91893e551f700cfd3 to your computer and use it in GitHub Desktop.
Save anonymamir/6397e06afcaffef91893e551f700cfd3 to your computer and use it in GitHub Desktop.
Worker to fetch v2ray configs. Mine just adds a small feature to use a clean domain with A record to clean Cloudflare ips and let the worker replace address of configs with that domain.
const subLink1 = "https://raw.githubusercontent.com/freefq/free/master/v2"
const subLink2 = "https://raw.githubusercontent.com/Pawdroid/Free-servers/main/sub"
const cnfLink1 = "https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/sub/sub_merge.txt"
const cleanIPLink = "http://bot.sudoer.net/best.cf.iran.all"
const operatorList = ["AST", "HWB", "IRC", "MBT", "MCI", "MKB", "PRS", "RTL", "SHT", "ZTL"]
const addressList = ["discord.com", "cloudflare.com", "nginx.com", "cdnjs.com", "vimeo.com", "networksolutions.com", "spotify.com"]
const fpList = ["chrome", "chrome", "chrome", "firefox", "safari", "edge", "ios", "android", "random", "random"]
const alpnList = ["http/1.1", "h2,http/1.1", "h2,http/1.1"]
export default {
async fetch(request) {
var url = new URL(request.url)
var pathParts = url.pathname.replace(/^\/|\/$/g, "").split("/")
if (pathParts[0] == "sub") {
var cleanIPs = []
if (pathParts[1] !== undefined) {
var operator = pathParts[1].toUpperCase()
if (operatorList.includes(operator)) {
cleanIPs = await fetch(cleanIPLink).then(r => r.text()).then(t => t.split("\n"))
cleanIPs = cleanIPs.filter(line => (line.search(operator) > 0))
cleanIPs = cleanIPs.map(line => line.split(" ")[0].trim())
} else if (isIp(operator) || isValidDomain(operator)) {
cleanIPs = [operator.toLowerCase()]
}
}
var configList = []
configList = configList.concat(await fetch(subLink1).then(r => r.text()).then(a => atob(a)).then(t => t.split("\n")))
configList = configList.concat(await fetch(subLink2).then(r => r.text()).then(a => atob(a)).then(t => t.split("\n")))
configList = configList.concat(await fetch(cnfLink1).then(r => r.text()).then(t => t.split("\n")))
configList = configList.filter(cnf => (cnf.search("vmess://") == 0))
configList = configList.map(config => {
try {
var conf = JSON.parse(atob(config.substr(8)))
if (conf.tls != "tls") {
throw "no-tls"
}
var addr = conf.sni
if (!addr) {
if (conf.add && !isIp(conf.add)) {
addr = conf.add
} else if (conf.host && !isIp(conf.host)) {
addr = conf.host
}
}
if (!addr) {
throw "no-tls"
}
conf.sni = url.hostname
if (cleanIPs.length) {
conf.add = cleanIPs[Math.floor(Math.random() * cleanIPs.length)]
} else {
conf.add = addressList[Math.floor(Math.random() * addressList.length)]
}
conf.host = url.hostname
conf.path = "/" + addr + ":" + conf.port + conf.path
conf.fp = fpList[Math.floor(Math.random() * fpList.length)]
conf.alpn = alpnList[Math.floor(Math.random() * alpnList.length)]
conf.port = 443
return "vmess://" + btoa(JSON.stringify(conf))
} catch (e) {
return ""
}
})
configList = getMultipleRandomElements(configList.filter(cnf => (cnf.length > 10)), 100)
return new Response(btoa(configList.join("\n")));
} else {
var url = new URL(request.url)
var newUrl = new URL("https://" + url.pathname.replace(/^\/|\/$/g, ''))
return fetch(new Request(newUrl, request));
}
}
}
function getMultipleRandomElements(arr, num) {
var shuffled = [...arr].sort(() => 0.5 - Math.random());
return shuffled.slice(0, num);
}
function isIp(str) {
try {
if (str == "" || str == undefined) return false;
const octet = '(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)';
const regex = new RegExp(`^${octet}\\.${octet}\\.${octet}\\.${octet}$`); // https://stackoverflow.com/a/54742549/8741573
return regex.test(str);
} catch (ee) { }
return false;
}
function isValidDomain(str) {
try {
if (str == "" || str == undefined) return false;
const regex = new RegExp(`^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}$`);
return regex.test(str);
} catch (ee) { }
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment