💐 Sync 2025-11-05 00:13:10

This commit is contained in:
actions-user
2025-11-05 00:13:10 +08:00
parent 251207fb9c
commit e112520fb4
24 changed files with 4104 additions and 3316 deletions

View File

@@ -28,8 +28,9 @@ function index()
entry({"admin", "services", "shadowsocksr", "reset"}, call("act_reset"))
entry({"admin", "services", "shadowsocksr", "restart"}, call("act_restart"))
entry({"admin", "services", "shadowsocksr", "delete"}, call("act_delete"))
--[[Backup]]
--[[Backup]]
entry({"admin", "services", "shadowsocksr", "backup"}, call("create_backup")).leaf = true
end
function subscribe()
@@ -46,40 +47,74 @@ function act_status()
end
function act_ping()
local e = {}
local domain = luci.http.formvalue("domain")
local port = luci.http.formvalue("port")
local transport = luci.http.formvalue("transport")
local wsPath = luci.http.formvalue("wsPath")
local tls = luci.http.formvalue("tls")
e.index = luci.http.formvalue("index")
local iret = luci.sys.call("ipset add ss_spec_wan_ac " .. domain .. " 2>/dev/null")
if transport == "ws" then
local prefix = tls=='1' and "https://" or "http://"
local address = prefix..domain..':'..port..wsPath
local result = luci.sys.exec("curl --http1.1 -m 2 -ksN -o /dev/null -w 'time_connect=%{time_connect}\nhttp_code=%{http_code}' -H 'Connection: Upgrade' -H 'Upgrade: websocket' -H 'Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==' -H 'Sec-WebSocket-Version: 13' "..address)
e.socket = string.match(result,"http_code=(%d+)")=="101"
e.ping = tonumber(string.match(result, "time_connect=(%d+.%d%d%d)"))*1000
else
local socket = nixio.socket("inet", "stream")
socket:setopt("socket", "rcvtimeo", 3)
socket:setopt("socket", "sndtimeo", 3)
e.socket = socket:connect(domain, port)
socket:close()
e.ping = luci.sys.exec(string.format("echo -n $(tcping -q -c 1 -i 1 -t 2 -p %s %s 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}') 2>/dev/null", port, domain))
if (e.ping == "") then
e.ping = luci.sys.exec("echo -n $(ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}') 2>/dev/null" % domain)
if (e.ping == "") then
-- UDP ping test using nping
e.ping = luci.sys.exec(string.format("echo -n $(nping --udp -c 1 -p %s %s 2>/dev/null | grep -o 'Avg rtt: [0-9.]*ms' | awk '{print $3}' | sed 's/ms//' | head -1) 2>/dev/null", port, domain))
end
end
end
if (iret == 0) then
luci.sys.call(" ipset del ss_spec_wan_ac " .. domain)
end
luci.http.prepare_content("application/json")
luci.http.write_json(e)
local e = {}
local domain = luci.http.formvalue("domain")
local port = tonumber(luci.http.formvalue("port") or 0)
local transport = luci.http.formvalue("transport")
local wsPath = luci.http.formvalue("wsPath") or ""
local tls = luci.http.formvalue("tls")
e.index = luci.http.formvalue("index")
local use_nft = luci.sys.call("command -v nft >/dev/null") == 0
local iret = false
if use_nft then
iret = luci.sys.call("nft add element inet ss_spec ss_spec_wan_ac { " .. domain .. " } 2>/dev/null") == 0
else
iret = luci.sys.call("ipset add ss_spec_wan_ac " .. domain .. " 2>/dev/null") == 0
end
if transport == "ws" then
local prefix = tls == '1' and "https://" or "http://"
local address = prefix .. domain .. ':' .. port .. wsPath
local result = luci.sys.exec(
"curl --http1.1 -m 2 -ksN -o /dev/null " ..
"-w 'time_connect=%{time_connect}\nhttp_code=%{http_code}' " ..
"-H 'Connection: Upgrade' -H 'Upgrade: websocket' " ..
"-H 'Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==' " ..
"-H 'Sec-WebSocket-Version: 13' " .. address
)
e.socket = string.match(result,"http_code=(%d+)") == "101"
local ping_time = tonumber(string.match(result, "time_connect=(%d+.%d%d%d)"))
e.ping = ping_time and ping_time * 1000 or nil
else
-- TCP ping
local socket = nixio.socket("inet", "stream")
socket:setopt("socket", "rcvtimeo", 3)
socket:setopt("socket", "sndtimeo", 3)
e.socket = socket:connect(domain, port)
socket:close()
e.ping = tonumber(luci.sys.exec(string.format(
"tcping -q -c 1 -i 1 -t 2 -p %d %s 2>/dev/null | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}'",
port, domain
)))
if not e.ping then
e.ping = tonumber(luci.sys.exec(string.format(
"ping -c 1 -W 1 %s 2>/dev/null | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}'",
domain
)))
end
if not e.ping then
e.ping = tonumber(luci.sys.exec(string.format(
"nping --udp -c 1 -p %d %s 2>/dev/null | grep -o 'Avg rtt: [0-9.]*ms' | awk '{print $3}' | sed 's/ms//' | head -1",
port, domain
)))
end
end
if iret then
if use_nft then
luci.sys.call("nft delete element inet ss_spec ss_spec_wan_ac { " .. domain .. " } 2>/dev/null")
else
luci.sys.call("ipset del ss_spec_wan_ac " .. domain .. " 2>/dev/null")
end
end
luci.http.prepare_content("application/json")
luci.http.write_json(e)
end
function check_status()
@@ -101,28 +136,46 @@ function check_port()
local s
local server_name = ""
local uci = require "luci.model.uci".cursor()
local iret = 1
local use_nft = luci.sys.call("command -v nft >/dev/null") == 0
uci:foreach("shadowsocksr", "servers", function(s)
if s.alias then
server_name = s.alias
elseif s.server and s.server_port then
server_name = "%s:%s" % {s.server, s.server_port}
server_name = s.server .. ":" .. s.server_port
end
iret = luci.sys.call("ipset add ss_spec_wan_ac " .. s.server .. " 2>/dev/null")
socket = nixio.socket("inet", "stream")
-- 临时加入 set
local iret = false
if use_nft then
iret = luci.sys.call("nft add element inet ss_spec ss_spec_wan_ac { " .. s.server .. " } 2>/dev/null") == 0
else
iret = luci.sys.call("ipset add ss_spec_wan_ac " .. s.server .. " 2>/dev/null") == 0
end
-- TCP 测试
local socket = nixio.socket("inet", "stream")
socket:setopt("socket", "rcvtimeo", 3)
socket:setopt("socket", "sndtimeo", 3)
ret = socket:connect(s.server, s.server_port)
if tostring(ret) == "true" then
socket:close()
retstring = retstring .. "<font><b style='color:green'>[" .. server_name .. "] OK.</b></font><br />"
local ret = socket:connect(s.server, s.server_port)
socket:close()
if ret then
retstring = retstring .. string.format("<font><b style='color:green'>[%s] OK.</b></font><br />", server_name)
else
retstring = retstring .. "<font><b style='color:red'>[" .. server_name .. "] Error.</b></font><br />"
retstring = retstring .. string.format("<font><b style='color:red'>[%s] Error.</b></font><br />", server_name)
end
if iret == 0 then
luci.sys.call("ipset del ss_spec_wan_ac " .. s.server)
-- 删除临时 set
if iret then
if use_nft then
luci.sys.call("nft delete element inet ss_spec ss_spec_wan_ac { " .. s.server .. " } 2>/dev/null")
else
luci.sys.call("ipset del ss_spec_wan_ac " .. s.server)
end
end
end)
luci.http.prepare_content("application/json")
luci.http.write_json({ret = retstring})
end

View File

@@ -4,14 +4,22 @@ local uci = require "luci.model.uci".cursor()
-- 获取 LAN IP 地址
function lanip()
local lan_ip
lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F '/' '{print $1}' | tr -d '\n'")
-- 尝试从 UCI 直接读取
lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F'/' '{print $1}' | tr -d '\\n'")
-- 尝试从 LAN 接口信息中读取(优先 ifname再 fallback 到 device
if not lan_ip or lan_ip == "" then
lan_ip = luci.sys.exec("ip address show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) | grep -w 'inet' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -1 | tr -d '\n'")
lan_ip = luci.sys.exec([[
ip -4 addr show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) 2>/dev/null \
| grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']])
end
-- 取任意一个 global IPv4 地址
if not lan_ip or lan_ip == "" then
lan_ip = luci.sys.exec("ip addr show | grep -w 'inet' | grep 'global' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1 | tr -d '\n'")
lan_ip = luci.sys.exec([[
ip -4 addr show scope global 2>/dev/null \
| grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']])
end
return lan_ip

View File

@@ -264,7 +264,7 @@ s = m:section(NamedSection, sid, "servers")
s.anonymous = true
s.addremove = false
o = s:option(DummyValue, "ssr_url", "SS/SSR/V2RAY/TROJAN/HYSTERIA2 URL")
o = s:option(DummyValue, "ssr_url", "SS/SSR/V2RAY/TROJAN/TUIC/HYSTERIA2 URL")
o.rawhtml = true
o.template = "shadowsocksr/ssrurl"
o.value = sid
@@ -1285,15 +1285,26 @@ o = s:option(ListValue, "tuic_alpn", translate("TUIC ALPN"))
o.default = ""
o:value("", translate("Default"))
o:value("h3")
o:value("h2")
o:value("h3,h2")
o:value("spdy/3.1")
o:value("h3,spdy/3.1")
o:depends("type", "tuic")
-- IP STACK PREFERENCE
o = s:option(ListValue, "ipstack_prefer", translate("IP Stack Preference"))
o.default = ""
o:value("", translate("Default"))
o:value("v4first")
o:value("v6first")
o:depends("tuic_dual_stack", true)
-- [[ allowInsecure ]]--
o = s:option(Flag, "insecure", translate("allowInsecure"))
o.rmempty = false
o:depends("tls", true)
o:depends("type", "hysteria2")
o:depends("type", "tuic")
o.description = translate("If true, allowss insecure connection at TLS client, e.g., TLS server uses unverifiable certificates.")
-- [[ Hysteria2 TLS pinSHA256 ]] --

View File

@@ -8,14 +8,22 @@ local uci = require "luci.model.uci".cursor()
-- 获取 LAN IP 地址
function lanip()
local lan_ip
lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F '/' '{print $1}' | tr -d '\n'")
-- 尝试从 UCI 直接读取
lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F'/' '{print $1}' | tr -d '\\n'")
-- 尝试从 LAN 接口信息中读取(优先 ifname再 fallback 到 device
if not lan_ip or lan_ip == "" then
lan_ip = luci.sys.exec("ip address show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) | grep -w 'inet' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -1 | tr -d '\n'")
lan_ip = luci.sys.exec([[
ip -4 addr show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) 2>/dev/null \
| grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']])
end
-- 取任意一个 global IPv4 地址
if not lan_ip or lan_ip == "" then
lan_ip = luci.sys.exec("ip addr show | grep -w 'inet' | grep 'global' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1 | tr -d '\n'")
lan_ip = luci.sys.exec([[
ip -4 addr show scope global 2>/dev/null \
| grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']])
end
return lan_ip

View File

@@ -75,9 +75,9 @@ function export_ssr_url(btn, urlname, sid) {
textarea.select();
try {
document.execCommand("copy"); // Security exception may be thrown by some browsers.
s.innerHTML = "<font color='green'><%:Copy SSR to clipboard successfully.%></font>";
s.innerHTML = "<font style=\'color:green\'><%:Copy SSR to clipboard successfully.%></font>";
} catch (ex) {
s.innerHTML = "<font color='red'><%:Unable to copy SSR to clipboard.%></font>";
s.innerHTML = "<font style=\'color:red\'><%:Unable to copy SSR to clipboard.%></font>";
} finally {
document.body.removeChild(textarea);
}
@@ -89,7 +89,7 @@ function import_ssr_url(btn, urlname, sid) {
if (!s) return false;
var ssrurl = prompt("<%:Paste sharing link here%>", "");
if (ssrurl == null || ssrurl == "") {
s.innerHTML = "<font color='red'><%:User cancelled.%></font>";
s.innerHTML = "<font style=\'color:red\'><%:User cancelled.%></font>";
return false;
}
s.innerHTML = "";
@@ -97,18 +97,6 @@ function import_ssr_url(btn, urlname, sid) {
ssrurl = ssrurl.replace(/&([a-zA-Z]+);/g, '&').replace(/\s*#\s*/, '#').trim(); //一些奇葩的链接用"&amp;"当做"&""#"前后带空格
var ssu = ssrurl.split('://');
//console.log(ssu.length);
if (ssu[0] === "ss") {
var queryStr = "";
if (ssu[1].indexOf("?") > -1) {
queryStr = ssu[1].split("?")[1]; // 提取 ? 后面的参数
}
var params = new URLSearchParams(queryStr);
if (params.get("type")) {
// 替换协议头
ssrurl = ssrurl.replace(/^ss:\/\//i, "shadowsocks://");
var ssu = ssrurl.split('://');
}
}
var event = document.createEvent("HTMLEvents");
event.initEvent("change", true, true);
switch (ssu[0]) {
@@ -189,136 +177,281 @@ function import_ssr_url(btn, urlname, sid) {
// 再分离 ? 或 /?(参数)
var queryIndex = (url0 = url0.replace('/?', '?')).indexOf("?");
var queryStr = "";
var query = "";
if (queryIndex >= 0) {
queryStr = url0.substring(queryIndex + 1);
query = url0.substring(queryIndex + 1);
url0 = url0.substring(0, queryIndex);
}
var params = Object.fromEntries(new URLSearchParams(queryStr));
var params = Object.fromEntries(new URLSearchParams(query));
// 判断是否 SIP002 格式(即含 @
if (url0.indexOf("@") !== -1) {
// === SIP002 格式 ===
var sipIndex = url0.indexOf("@");
// 先 URL 解码 base64 再解码
var userInfoB64 = decodeURIComponent(url0.substring(0, sipIndex));
var userInfo = b64decsafe(userInfoB64);
var userInfoSplitIndex = userInfo.indexOf(":");
if(userInfoSplitIndex < 0) {
// 格式错误
s.innerHTML = "<font style='color:red'><%:Userinfo format error.%></font>";
break;
}
var method = userInfo.substring(0, userInfoSplitIndex);
var password = userInfo.substring(userInfoSplitIndex + 1);
var serverPart = url0.substring(sipIndex + 1);
var serverInfo = serverPart.split(":");
if ( ! params.type) {
// 普通 SS 导入逻辑
// 判断是否 SIP002 格式(即含 @
if (url0.indexOf("@") !== -1) {
// === SIP002 格式 ===
var sipIndex = url0.indexOf("@");
// 先 URL 解码 base64 再解码
var userInfoB64 = decodeURIComponent(url0.substring(0, sipIndex));
var userInfo = b64decsafe(userInfoB64);
var userInfoSplitIndex = userInfo.indexOf(":");
if(userInfoSplitIndex < 0) {
// 格式错误
s.innerHTML = "<font style='color:red'><%:Userinfo format error.%></font>";
break;
}
var method = userInfo.substring(0, userInfoSplitIndex);
var password = userInfo.substring(userInfoSplitIndex + 1);
var serverPart = url0.substring(sipIndex + 1);
var serverInfo = serverPart.split(":");
var server = serverInfo[0];
var port = serverInfo[1];
var server = serverInfo[0];
var port = serverInfo[1];
var plugin = "", pluginOpts = "";
if (params.plugin) {
var pluginParams = decodeURIComponent(params.plugin).split(";");
plugin = pluginParams.shift();
pluginOpts = pluginParams.join(";");
}
} else {
// === Base64 SS2022 / 普通格式 的整体编码格式 ===
// 先 URL 解码整个字符串
var decodedUrl0 = decodeURIComponent(url0);
var sstr = b64decsafe(decodedUrl0);
if (!sstr) {
s.innerHTML = "<font style='color:red'><%:Base64 sstr failed.%></font>";
break;
}
// 支持 SS2022 / 普通格式
var regex2022 = /^([^:]+):([^:]+):([^@]+)@([^:]+):(\d+)$/;
var regexNormal = /^([^:]+):([^@]+)@([^:]+):(\d+)$/;
var m2022 = sstr.match(regex2022);
var mNormal = sstr.match(regexNormal);
if (m2022) {
var method = m2022[1];
var password = m2022[2] + ":" + m2022[3];
var server = m2022[4];
var port = m2022[5];
} else if (mNormal) {
var method = mNormal[1];
var password = mNormal[2];
var server = mNormal[3];
var port = mNormal[4];
var plugin = "", pluginOpts = "";
if (params.plugin) {
var pluginParams = decodeURIComponent(params.plugin).split(";");
plugin = pluginParams.shift();
pluginOpts = pluginParams.join(";");
}
} else {
s.innerHTML = "<font style='color:red'><%:SS URL base64 sstr format not recognized.%></font>";
break;
}
// === Base64 SS2022 / 普通格式 的整体编码格式 ===
// 先 URL 解码整个字符串
var decodedUrl0 = decodeURIComponent(url0);
var sstr = b64decsafe(decodedUrl0);
if (!sstr) {
s.innerHTML = "<font style='color:red'><%:Base64 sstr failed.%></font>";
break;
}
var plugin = "", pluginOpts = "";
if (params["shadow-tls"]) {
try {
var decoded_tls = JSON.parse(atob(decodeURIComponent(params["shadow-tls"])));
plugin = "shadow-tls";
var versionFlag = "";
if (decoded_tls.version && !isNaN(decoded_tls.version)) {
versionFlag = "v" + decoded_tls.version + "=1;";
// 支持 SS2022 / 普通格式
var regex2022 = /^([^:]+):([^:]+):([^@]+)@([^:]+):(\d+)$/;
var regexNormal = /^([^:]+):([^@]+)@([^:]+):(\d+)$/;
var m2022 = sstr.match(regex2022);
var mNormal = sstr.match(regexNormal);
if (m2022) {
var method = m2022[1];
var password = m2022[2] + ":" + m2022[3];
var server = m2022[4];
var port = m2022[5];
} else if (mNormal) {
var method = mNormal[1];
var password = mNormal[2];
var server = mNormal[3];
var port = mNormal[4];
} else {
s.innerHTML = "<font style='color:red'><%:SS URL base64 sstr format not recognized.%></font>";
break;
}
var plugin = "", pluginOpts = "";
if (params["shadow-tls"]) {
try {
var decoded_tls = JSON.parse(atob(decodeURIComponent(params["shadow-tls"])));
plugin = "shadow-tls";
var versionFlag = "";
if (decoded_tls.version && !isNaN(decoded_tls.version)) {
versionFlag = "v" + decoded_tls.version + "=1;";
}
pluginOpts = versionFlag + "host=" + (decoded_tls.host || "") + ";passwd=" + (decoded_tls.password || "");
} catch (e) {
console.log("shadow-tls decode failed:", e);
}
pluginOpts = versionFlag + "host=" + (decoded_tls.host || "") + ";passwd=" + (decoded_tls.password || "");
} catch (e) {
console.log("shadow-tls decode failed:", e);
}
}
}
// 判断密码是否经过url编码
const isURLEncodedPassword = function(pwd) {
if (!/%[0-9A-Fa-f]{2}/.test(pwd)) return false;
// 判断密码是否经过url编码
const isURLEncodedPassword = function(pwd) {
if (!/%[0-9A-Fa-f]{2}/.test(pwd)) return false;
try {
const decoded = decodeURIComponent(pwd.replace(/\+/g, "%20"));
const reencoded = encodeURIComponent(decoded);
return reencoded === pwd;
} catch (e) {
return false;
}
}
if (isURLEncodedPassword(password)) {
password = decodeURIComponent(password); // 解码URL编码
} else {
password = password; // 保持原始值
}
// === 填充配置项 ===
var has_ss_type = (ss_type === "ss-rust") ? "ss-rust" : "ss-libev";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = ssu[0];
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.has_ss_type')[0].value = has_ss_type;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.has_ss_type')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = server;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = port;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = password || "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = method;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].dispatchEvent(event);
if (plugin && plugin !== "none") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].checked = true; // 设置 enable_plugin 为 true
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].dispatchEvent(event); // 触发事件
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].value = plugin;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].dispatchEvent(event);
if (plugin !== undefined) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin_opts')[0].value = pluginOpts || "";
}
} else {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].checked = false;
}
if (param != undefined) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURIComponent(param);
}
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
return false;
} else {
try {
const decoded = decodeURIComponent(pwd.replace(/\+/g, "%20"));
const reencoded = encodeURIComponent(decoded);
return reencoded === pwd;
} catch (e) {
// Xray SS 导入逻辑
// 拆分 @,判断是否是 base64 userinfo 的格式
var parts = url0.split("@");
if (parts.length > 1) {
// @ 前是 base64(method:password),后面是 server:port?params
var userinfo = b64decsafe(parts[0]);
var sepIndex = userinfo.indexOf(":");
if (sepIndex > -1) {
method = userinfo.slice(0, sepIndex);
password = userinfo.slice(sepIndex + 1); //一些链接用明文uuid做密码
}
}
var url = new URL("http://" + url0 + (param ? "#" + encodeURIComponent(param) : ""));
} catch(e) {
alert(e);
return false;
}
}
if (isURLEncodedPassword(password)) {
password = decodeURIComponent(password); // 解码URL编码
} else {
password = password; // 保持原始值
}
// === 填充配置项 ===
var has_ss_type = (ss_type === "ss-rust") ? "ss-rust" : "ss-libev";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = ssu[0];
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.has_ss_type')[0].value = has_ss_type;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.has_ss_type')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = server;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = port;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = password || "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = method;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].dispatchEvent(event);
if (plugin && plugin !== "none") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].checked = true; // 设置 enable_plugin 为 true
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].dispatchEvent(event); // 触发事件
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].value = plugin;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].dispatchEvent(event);
if (plugin !== undefined) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin_opts')[0].value = pluginOpts || "";
// Check if the elements exist before trying to modify them
function setElementValue(name, value) {
const element = document.getElementsByName(name)[0];
if (element) {
if (typeof value === 'boolean') {
element.checked = value;
} else {
element.value = value;
}
}
}
} else {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].checked = false;
}
function dispatchEventIfExists(name, event) {
const element = document.getElementsByName(name)[0];
if (element) {
element.dispatchEvent(event);
}
}
setElementValue('cbid.shadowsocksr.' + sid + '.alias', url.hash ? decodeURIComponent(url.hash.slice(1)) : "");
setElementValue('cbid.shadowsocksr.' + sid + '.type', "v2ray");
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.type', event);
setElementValue('cbid.shadowsocksr.' + sid + '.v2ray_protocol', "shadowsocks");
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.v2ray_protocol', event);
setElementValue('cbid.shadowsocksr.' + sid + '.server', url.hostname);
setElementValue('cbid.shadowsocksr.' + sid + '.server_port', url.port || "80");
setElementValue('cbid.shadowsocksr.' + sid + '.password', password || url.username);
setElementValue('cbid.shadowsocksr.' + sid + '.transport',
params.type === "http" ? "h2" :
(["xhttp", "splithttp"].includes(params.type) ? "xhttp" :
(["tcp", "raw"].includes(params.type) ? "raw" :
(params.type || "raw")))
);
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.transport', event);
setElementValue('cbid.shadowsocksr.' + sid + '.encrypt_method_ss', method || params.encryption || "none");
if ([ "tls", "xtls", "reality" ].includes(params.security)) {
setElementValue('cbid.shadowsocksr.' + sid + '.' + params.security, true);
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.' + params.security, event);
if (param != undefined) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURIComponent(param);
if (params.security === "tls") {
if (params.ech && params.ech.trim() !== "") {
setElementValue('cbid.shadowsocksr.' + sid + '.enable_ech', true); // 设置 enable_ech 为 true
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.enable_ech', event); // 触发事件
setElementValue('cbid.shadowsocksr.' + sid + '.ech_config', params.ech || "");
}
if (params.allowInsecure === "1") {
setElementValue('cbid.shadowsocksr.' + sid + '.insecure', true); // 设置 insecure 为 true
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.insecure', event); // 触发事件
}
}
if (params.security === "reality") {
setElementValue('cbid.shadowsocksr.' + sid + '.reality_publickey', params.pbk ? decodeURIComponent(params.pbk) : "");
setElementValue('cbid.shadowsocksr.' + sid + '.reality_shortid', params.sid || "");
setElementValue('cbid.shadowsocksr.' + sid + '.reality_spiderx', params.spx ? decodeURIComponent(params.spx) : "");
if (params.pqv && params.pqv.trim() !== "") {
setElementValue('cbid.shadowsocksr.' + sid + '.enable_mldsa65verify', true); // 设置 enable_mldsa65verify 为 true
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.enable_mldsa65verify', event); // 触发事件
setElementValue('cbid.shadowsocksr.' + sid + '.reality_mldsa65verify', params.pqv || "");
}
}
setElementValue('cbid.shadowsocksr.' + sid + '.tls_flow', params.flow || "none");
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.tls_flow', event);
setElementValue('cbid.shadowsocksr.' + sid + '.tls_alpn', params.alpn || "");
setElementValue('cbid.shadowsocksr.' + sid + '.fingerprint', params.fp || "");
setElementValue('cbid.shadowsocksr.' + sid + '.tls_host', params.sni || "");
}
switch (params.type) {
case "ws":
if (params.security !== "tls") {
setElementValue('cbid.shadowsocksr.' + sid + '.ws_host', params.host ? decodeURIComponent(params.host) : "");
}
setElementValue('cbid.shadowsocksr.' + sid + '.ws_path', params.path ? decodeURIComponent(params.path) : "/");
break;
case "httpupgrade":
if (params.security !== "tls") {
setElementValue('cbid.shadowsocksr.' + sid + '.httpupgrade_host', params.host ? decodeURIComponent(params.host) : "");
}
setElementValue('cbid.shadowsocksr.' + sid + '.httpupgrade_path', params.path ? decodeURIComponent(params.path) : "/");
break;
case "xhttp":
case "splithttp":
if (params.security !== "tls") {
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_host', params.host ? decodeURIComponent(params.host) : "");
}
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_mode', params.mode || "auto");
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_path', params.path ? decodeURIComponent(params.path) : "/");
if (params.extra && params.extra.trim() !== "") {
setElementValue('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra', true); // 设置 enable_xhttp_extra 为 true
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra', event); // 触发事件
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_extra', params.extra || "");
}
break;
case "kcp":
setElementValue('cbid.shadowsocksr.' + sid + '.kcp_guise', params.headerType || "none");
setElementValue('cbid.shadowsocksr.' + sid + '.seed', params.seed || "");
break;
case "http":
/* this is non-standard, bullshit */
case "h2":
setElementValue('cbid.shadowsocksr.' + sid + '.h2_host', params.host ? decodeURIComponent(params.host) : "");
setElementValue('cbid.shadowsocksr.' + sid + '.h2_path', params.path ? decodeURIComponent(params.path) : "");
break;
case "quic":
setElementValue('cbid.shadowsocksr.' + sid + '.quic_guise', params.headerType || "none");
setElementValue('cbid.shadowsocksr.' + sid + '.quic_security', params.quicSecurity || "none");
setElementValue('cbid.shadowsocksr.' + sid + '.quic_key', params.key || "");
break;
case "grpc":
setElementValue('cbid.shadowsocksr.' + sid + '.serviceName', params.serviceName || "");
setElementValue('cbid.shadowsocksr.' + sid + '.grpc_mode', params.mode || "gun");
break;
case "tcp":
case "raw":
setElementValue('cbid.shadowsocksr.' + sid + '.tcp_guise', params.headerType || "none");
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.tcp_guise', event);
if (params.headerType === "http") {
setElementValue('cbid.shadowsocksr.' + sid + '.http_host', params.host ? decodeURIComponent(params.host) : "");
setElementValue('cbid.shadowsocksr.' + sid + '.http_path', params.path ? decodeURIComponent(params.path) : "");
}
break;
}
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
return false;
}
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
return false;
case "ssr":
var sstr = b64decsafe((ssu[1] || "").replace(/#.*/, "").trim());
var ploc = sstr.indexOf("/?");
@@ -349,7 +482,7 @@ function import_ssr_url(btn, urlname, sid) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.protocol_param')[0].value = dictvalue(pdict, 'protoparam');
var rem = pdict['remarks'];
if (typeof (rem) != 'undefined' && rem != '' && rem.length > 0) document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = b64decutf8safe(rem);
s.innerHTML = "<font color='green'><%:Import configuration information successfully.%></font>";
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
return false;
case "trojan":
try {
@@ -360,93 +493,117 @@ function import_ssr_url(btn, urlname, sid) {
return false;
}
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = url.hash ? decodeURIComponent(url.hash.slice(1)) : "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "v2ray";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].value = "trojan";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = url.hostname;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = url.port || "80";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = decodeURIComponent(url.username);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = params.get("sni");
if (params.get("allowInsecure") === "1") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = true; // 设置 insecure 为 true
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].dispatchEvent(event); // 触发事件
}
if (params.get("ech") && params.get("ech").trim() !== "") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_ech')[0].checked = true; // 设置 enable_ech 为 true
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_ech')[0].dispatchEvent(event); // 触发事件
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ech_config')[0].value = params.get("ech");
}
document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].value =
params.get("type") == "http" ? "h2" :
(["xhttp", "splithttp"].includes(params.get("type")) ? "xhttp" :
(["tcp", "raw"].includes(params.get("type")) ? "raw" :
(params.get("type") || "raw")));
document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].dispatchEvent(event);
if (params.get("security") === "tls") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_alpn')[0].value = params.get("alpn") || "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.fingerprint')[0].value = params.get("fp") || "";
}
switch (params.get("type")) {
case "ws":
if (params.get("security") !== "tls") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ws_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
if (!params.get("type")) {
// 普通 Trojan 导入逻辑
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = url.hash ? decodeURIComponent(url.hash.slice(1)) : "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "trojan";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = url.hostname;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = url.port || "80";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = decodeURIComponent(url.username);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = params.get("peer") || params.get("sni");
if (params.get("allowInsecure") === "1") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = true; // 设置 insecure 为 true
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].dispatchEvent(event); // 触发事件
}
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ws_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
break;
case "httpupgrade":
if (params.get("security") !== "tls") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.httpupgrade_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
if (params.get("tfo") === "1") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.fast_open')[0].checked = true; // 设置 fast_open 为 true
document.getElementsByName('cbid.shadowsocksr.' + sid + '.fast_open')[0].dispatchEvent(event); // 触发事件
}
document.getElementsByName('cbid.shadowsocksr.' + sid + '.httpupgrade_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
break;
case "xhttp":
case "splithttp":
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_mode')[0].value = params.get("mode") || "auto";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
if (params.get("extra") && params.get("extra").trim() !== "") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra')[0].checked = true; // 设置 enable_xhttp_extra 为 true
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra')[0].dispatchEvent(event); // 触发事件
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_extra')[0].value = params.get("extra") || "";
}
break;
case "kcp":
document.getElementsByName('cbid.shadowsocksr.' + sid + '.kcp_guise')[0].value = params.get("headerType") || "none";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.seed')[0].value = params.get("seed") || "";
break;
case "http":
/* this is non-standard, bullshit */
case "h2":
document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
break;
case "quic":
document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_guise')[0].value = params.get("headerType") || "none";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_security')[0].value = params.get("quicSecurity") || "none";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_key')[0].value = params.get("key") || "";
break;
case "grpc":
document.getElementsByName('cbid.shadowsocksr.' + sid + '.serviceName')[0].value = params.get("serviceName") || "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.grpc_mode')[0].value = params.get("mode") || "gun";
break;
case "raw":
case "tcp":
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tcp_guise')[0].value = params.get("headerType") || "none";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tcp_guise')[0].dispatchEvent(event);
if (params.get("headerType") === "http") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
}
break;
}
s.innerHTML = "<font color='green'><%:Import configuration information successfully.%></font>";
return false;
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
return false;
} else {
// Xray Trojan 导入逻辑
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = url.hash ? decodeURIComponent(url.hash.slice(1)) : "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "v2ray";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].value = "trojan";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = url.hostname;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = url.port || "80";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = decodeURIComponent(url.username);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = params.get("sni");
if (params.get("allowInsecure") === "1") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = true; // 设置 insecure 为 true
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].dispatchEvent(event); // 触发事件
}
if (params.get("ech") && params.get("ech").trim() !== "") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_ech')[0].checked = true; // 设置 enable_ech 为 true
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_ech')[0].dispatchEvent(event); // 触发事件
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ech_config')[0].value = params.get("ech");
}
document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].value =
params.get("type") == "http" ? "h2" :
(["xhttp", "splithttp"].includes(params.get("type")) ? "xhttp" :
(["tcp", "raw"].includes(params.get("type")) ? "raw" :
(params.get("type") || "raw")));
document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].dispatchEvent(event);
if (params.get("security") === "tls") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_alpn')[0].value = params.get("alpn") || "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.fingerprint')[0].value = params.get("fp") || "";
}
switch (params.get("type")) {
case "ws":
if (params.get("security") !== "tls") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ws_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
}
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ws_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
break;
case "httpupgrade":
if (params.get("security") !== "tls") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.httpupgrade_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
}
document.getElementsByName('cbid.shadowsocksr.' + sid + '.httpupgrade_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
break;
case "xhttp":
case "splithttp":
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_mode')[0].value = params.get("mode") || "auto";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
if (params.get("extra") && params.get("extra").trim() !== "") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra')[0].checked = true; // 设置 enable_xhttp_extra 为 true
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra')[0].dispatchEvent(event); // 触发事件
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_extra')[0].value = params.get("extra") || "";
}
break;
case "kcp":
document.getElementsByName('cbid.shadowsocksr.' + sid + '.kcp_guise')[0].value = params.get("headerType") || "none";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.seed')[0].value = params.get("seed") || "";
break;
case "http":
/* this is non-standard, bullshit */
case "h2":
document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
break;
case "quic":
document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_guise')[0].value = params.get("headerType") || "none";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_security')[0].value = params.get("quicSecurity") || "none";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_key')[0].value = params.get("key") || "";
break;
case "grpc":
document.getElementsByName('cbid.shadowsocksr.' + sid + '.serviceName')[0].value = params.get("serviceName") || "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.grpc_mode')[0].value = params.get("mode") || "gun";
break;
case "raw":
case "tcp":
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tcp_guise')[0].value = params.get("headerType") || "none";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tcp_guise')[0].dispatchEvent(event);
if (params.get("headerType") === "http") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
}
break;
}
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
return false;
}
case "vmess":
var sstr = b64DecodeUnicode((ssu[1] || "").replace(/#.*/, "").trim());
var ploc = sstr.indexOf("/?");
@@ -532,7 +689,7 @@ function import_ssr_url(btn, urlname, sid) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.mux')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.mux')[0].dispatchEvent(event);
}
s.innerHTML = "<font color='green'><%:Import configuration information successfully.%></font>";
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
return false;
case "vless":
try {
@@ -664,153 +821,85 @@ function import_ssr_url(btn, urlname, sid) {
}
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
return false;
case "shadowsocks":
try {
// 处理完整 ss:// 链接
var urlinfo = ssu[1];
// 拆分 @,判断是否是 base64 userinfo 的格式
var parts = urlinfo.split("@");
if (parts.length > 1) {
// @ 前是 base64(method:password),后面是 server:port?params
var userinfo = b64decsafe(parts[0]);
var sepIndex = userinfo.indexOf(":");
if (sepIndex > -1) {
method = userinfo.slice(0, sepIndex);
password = userinfo.slice(sepIndex + 1); //一些链接用明文uuid做密码
}
}
var url = new URL("http://" + urlinfo);
case "tuic":
var url0 = (ssu[1] || "");
var param = "";
var params = url.searchParams;
// 先分离 #alias
var hashIndex = url0.indexOf("#");
if (hashIndex >= 0) {
param = url0.substring(hashIndex + 1);
url0 = url0.substring(0, hashIndex);
}
} catch(e) {
alert(e);
return false;
// 再分离 ? 或 /?(参数)
var queryIndex = (url0 = url0.replace('/?', '?')).indexOf("?");
var query = "";
if (queryIndex >= 0) {
query = url0.substring(queryIndex + 1);
url0 = url0.substring(0, queryIndex);
}
// Check if the elements exist before trying to modify them
function setElementValue(name, value) {
const element = document.getElementsByName(name)[0];
if (element) {
if (typeof value === 'boolean') {
element.checked = value;
} else {
element.value = value;
}
}
}
function dispatchEventIfExists(name, event) {
const element = document.getElementsByName(name)[0];
if (element) {
element.dispatchEvent(event);
}
}
setElementValue('cbid.shadowsocksr.' + sid + '.alias', url.hash ? decodeURIComponent(url.hash.slice(1)) : "");
setElementValue('cbid.shadowsocksr.' + sid + '.type', "v2ray");
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.type', event);
setElementValue('cbid.shadowsocksr.' + sid + '.v2ray_protocol', "shadowsocks");
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.v2ray_protocol', event);
setElementValue('cbid.shadowsocksr.' + sid + '.server', url.hostname);
setElementValue('cbid.shadowsocksr.' + sid + '.server_port', url.port || "80");
setElementValue('cbid.shadowsocksr.' + sid + '.password', password || url.username);
setElementValue('cbid.shadowsocksr.' + sid + '.transport',
params.get("type") === "http" ? "h2" :
(["xhttp", "splithttp"].includes(params.get("type")) ? "xhttp" :
(["tcp", "raw"].includes(params.get("type")) ? "raw" :
(params.get("type") || "raw")))
);
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.transport', event);
setElementValue('cbid.shadowsocksr.' + sid + '.encrypt_method_ss', method || params.get("encryption") || "none");
if ([ "tls", "xtls", "reality" ].includes(params.get("security"))) {
setElementValue('cbid.shadowsocksr.' + sid + '.' + params.get("security"), true);
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.' + params.get("security"), event);
if (params.get("security") === "tls") {
if (params.get("ech") && params.get("ech").trim() !== "") {
setElementValue('cbid.shadowsocksr.' + sid + '.enable_ech', true); // 设置 enable_ech 为 true
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.enable_ech', event); // 触发事件
setElementValue('cbid.shadowsocksr.' + sid + '.ech_config', params.get("ech") || "");
}
if (params.get("allowInsecure") === "1") {
setElementValue('cbid.shadowsocksr.' + sid + '.insecure', true); // 设置 insecure 为 true
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.insecure', event); // 触发事件
}
}
if (params.get("security") === "reality") {
setElementValue('cbid.shadowsocksr.' + sid + '.reality_publickey', params.get("pbk") ? decodeURIComponent(params.get("pbk")) : "");
setElementValue('cbid.shadowsocksr.' + sid + '.reality_shortid', params.get("sid") || "");
setElementValue('cbid.shadowsocksr.' + sid + '.reality_spiderx', params.get("spx") ? decodeURIComponent(params.get("spx")) : "");
if (params.get("pqv") && params.get("pqv").trim() !== "") {
setElementValue('cbid.shadowsocksr.' + sid + '.enable_mldsa65verify', true); // 设置 enable_mldsa65verify 为 true
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.enable_mldsa65verify', event); // 触发事件
setElementValue('cbid.shadowsocksr.' + sid + '.reality_mldsa65verify', params.get("pqv") || "");
}
}
setElementValue('cbid.shadowsocksr.' + sid + '.tls_flow', params.get("flow") || "none");
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.tls_flow', event);
var params = Object.fromEntries(new URLSearchParams(query));
setElementValue('cbid.shadowsocksr.' + sid + '.tls_alpn', params.get("alpn") || "");
setElementValue('cbid.shadowsocksr.' + sid + '.fingerprint', params.get("fp") || "");
setElementValue('cbid.shadowsocksr.' + sid + '.tls_host', params.get("sni") || "");
}
switch (params.get("type")) {
case "ws":
if (params.get("security") !== "tls") {
setElementValue('cbid.shadowsocksr.' + sid + '.ws_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
}
setElementValue('cbid.shadowsocksr.' + sid + '.ws_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
break;
case "httpupgrade":
if (params.get("security") !== "tls") {
setElementValue('cbid.shadowsocksr.' + sid + '.httpupgrade_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
}
setElementValue('cbid.shadowsocksr.' + sid + '.httpupgrade_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
break;
case "xhttp":
case "splithttp":
if (params.get("security") !== "tls") {
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
}
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_mode', params.get("mode") || "auto");
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
if (params.get("extra") && params.get("extra").trim() !== "") {
setElementValue('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra', true); // 设置 enable_xhttp_extra 为 true
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra', event); // 触发事件
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_extra', params.get("extra") || "");
}
break;
case "kcp":
setElementValue('cbid.shadowsocksr.' + sid + '.kcp_guise', params.get("headerType") || "none");
setElementValue('cbid.shadowsocksr.' + sid + '.seed', params.get("seed") || "");
break;
case "http":
/* this is non-standard, bullshit */
case "h2":
setElementValue('cbid.shadowsocksr.' + sid + '.h2_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
setElementValue('cbid.shadowsocksr.' + sid + '.h2_path', params.get("path") ? decodeURIComponent(params.get("path")) : "");
break;
case "quic":
setElementValue('cbid.shadowsocksr.' + sid + '.quic_guise', params.get("headerType") || "none");
setElementValue('cbid.shadowsocksr.' + sid + '.quic_security', params.get("quicSecurity") || "none");
setElementValue('cbid.shadowsocksr.' + sid + '.quic_key', params.get("key") || "");
break;
case "grpc":
setElementValue('cbid.shadowsocksr.' + sid + '.serviceName', params.get("serviceName") || "");
setElementValue('cbid.shadowsocksr.' + sid + '.grpc_mode', params.get("mode") || "gun");
break;
case "tcp":
case "raw":
setElementValue('cbid.shadowsocksr.' + sid + '.tcp_guise', params.get("headerType") || "none");
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.tcp_guise', event);
if (params.get("headerType") === "http") {
setElementValue('cbid.shadowsocksr.' + sid + '.http_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
setElementValue('cbid.shadowsocksr.' + sid + '.http_path', params.get("path") ? decodeURIComponent(params.get("path")) : "");
}
var sipIndex = url0.indexOf("@");
var userInfo = url0.substring(0, sipIndex); // 格式uuid:password
var hostPart = url0.substring(sipIndex + 1); // 格式hostname:port
var userInfoSplitIndex = userInfo.indexOf(":");
if(userInfoSplitIndex < 0) {
// 格式错误
s.innerHTML = "<font style='color:red'><%:Userinfo format error.%></font>";
break;
}
s.innerHTML = "<font color='green'><%:Import configuration information successfully.%></font>";
var method = userInfo.substring(0, userInfoSplitIndex);
var password = userInfo.substring(userInfoSplitIndex + 1);
var url = new URL("http://" + hostPart); // 用 URL 提取 host 与 port
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = ssu[0];
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = url.hostname;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = url.port;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_uuid')[0].value = method;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_ip')[0].value = params.ip || "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_passwd')[0].value = password;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.udp_relay_mode')[0].value = params.udp_relay_mode || "native";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.congestion_control')[0].value = params.congestion_control || "cubic";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_alpn')[0].value = params.alpn || "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.heartbeat')[0].value = params.heartbeat || "3";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.timeout')[0].value = params.timeout || "8";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.gc_interval')[0].value = params.gc_interval || "3";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.gc_lifetime')[0].value = params.gc_lifetime || "15";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.send_window')[0].value = params.send_window || "20971520";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.receive_window')[0].value = params.receive_window || "10485760";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_max_package_size')[0].value = params.max_packet_size || "1500";
if (params["disable_sni"] === "1" || params["disable_sni"] === "true") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.disable_sni')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.disable_sni')[0].dispatchEvent(event);
}
if (params["zero_rtt_handshake"] === "1" || params["zero_rtt_handshake"] === "true") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.zero_rtt_handshake')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.zero_rtt_handshake')[0].dispatchEvent(event);
}
if (params["dual_stack"] === "1" || params["dual_stack"] === "true") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_dual_stack')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_dual_stack')[0].dispatchEvent(event);
if (params.ipstack_prefer && params.ipstack_prefer.trim() !== "") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ipstack_prefer')[0].value = params.ipstack_prefer;
}
}
if (params["allowInsecure"] === "1" || params["allowInsecure"] === "true") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].dispatchEvent(event);
}
if (param != undefined) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURIComponent(param);
}
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
return false;
default:
s.innerHTML = "<font color='red'><%:Invalid format.%></font>";
s.innerHTML = "<font style=\'color:red\'><%:Invalid format.%></font>";
return false;
}
}