op-packages/luci-app-passwall/luasrc/view/passwall/node_config/link_share_man.htm
github-actions[bot] ddc3d78236 🦄 Sync 2026-07-16 04:24:09
2026-07-16 04:24:09 +08:00

1901 lines
74 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<%+cbi/valueheader%>
<%
local api = require "luci.passwall.api"
local appname = api.appname
local map = self.map
local has_ss_rust = api.is_finded("sslocal")
local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray")
local has_hysteria2 = api.finded_com("hysteria")
local ss_type = api.get_core("ss_type", {{has_ss_rust,"shadowsocks-rust"},{has_singbox,"sing-box"},{has_xray,"xray"}})
local trojan_type = api.get_core("trojan_type", {{has_singbox,"sing-box"},{has_xray,"xray"}})
local vmess_type = api.get_core("vmess_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
local vless_type = api.get_core("vless_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
local hysteria2_type = api.get_core("hysteria2_type", {{has_hysteria2,"hysteria2"},{has_singbox,"sing-box"}, {has_xray,"xray"}})
local current_node = map:get(section)
-%>
<script src="<%=resource%>/view/<%=appname%>/qrcode.min.js"></script>
<script type="text/javascript">//<![CDATA[
let has_singbox = "<%=has_singbox%>"
let has_xray = "<%=has_xray%>"
let has_hysteria2 = "<%=has_hysteria2%>"
let ss_type = "<%=ss_type%>"
let trojan_type = "<%=trojan_type%>"
let vmess_type = "<%=vmess_type%>"
let vless_type = "<%=vless_type%>"
let hysteria2_type = "<%=hysteria2_type%>"
function padright(str, cnt, pad) {
return str + Array(cnt + 1).join(pad);
}
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
function b64encutf8safe(str) {
return b64EncodeUnicode(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, '');
}
function b64DecodeUnicode(str) {
return decodeURIComponent(Array.prototype.map.call(atob(str), function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
function b64decutf8safe(str) {
var l;
str = str.replace(/-/g, "+").replace(/_/g, "/");
l = str.length;
l = (4 - l % 4) % 4;
if (l)
str = padright(str, l, "=");
return b64DecodeUnicode(str);
}
function b64encsafe(str) {
return btoa(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, '')
}
function b64decsafe(str) {
const orig = str;
try {
str = str.replace(/-/g, "+").replace(/_/g, "/");
const pad = (4 - str.length % 4) % 4;
if (pad) str += "=".repeat(pad);
return atob(str);
} catch (e) {
return orig;
}
}
function dictvalue(d, key) {
var v = d[key];
if (typeof (v) === 'undefined' || v === '')
return '';
return b64decsafe(v);
}
function parseNodeUrl(url) {
let protocol = url.substring(0, url.indexOf("://")) + ":"
let str = "http" + url.substring(url.indexOf("://"))
const parsedUrl = new URL(str);
var r = {
hash: parsedUrl.hash, // #asd
host: parsedUrl.host, // localhost:257
hostname: parsedUrl.hostname, // localhost
port: parsedUrl.port, // 257
search: parsedUrl.search, // ?asd=asd
passwd: parsedUrl.username || parsedUrl.password // username
};
return r;
}
function genQrcode(btn, urlname, sid) {
var qrcode_div = document.getElementById("qrcode_div");
qrcode_div.style.display = null;
document.getElementById("qrcode").innerHTML = "";
var url = buildUrl(btn, urlname, sid);
if (url) {
var qrcode = new QRCode(document.getElementById("qrcode"), {
width: 150,
height: 150
});
qrcode.makeCode(url);
}
}
function buildUrl(btn, urlname, sid) {
var opt = {
base: "cbid.<%=appname%>",
client: true,
get: function (opt) {
var id = this.base + "." + opt;
var obj = document.getElementsByName(id)[0] || document.getElementsByClassName(id)[0] || document.getElementById(id)
if (obj) {
return obj;
} else {
return null;
}
},
getlist: function (opt) {
var id = this.base + "." + opt;
var objs = document.getElementsByName(id) || document.getElementsByClassName(id);
var ret = [];
if (objs) {
for (var i = 0; i < objs.length; i++) {
ret[i] = objs[i].value;
}
} else {
alert("<%:Faltal on get option, please help in debug: %>" + opt);
}
return ret;
},
query: function (param, src, default_value) {
var obj = this.get(src);
if (obj) {
var ret = "&" + param + "=";
if (obj.type === "checkbox") {
return ret + (obj.checked === true ? "1" : "0");
} else {
var result = encodeURIComponent(obj.value);
if (result == null || result.trim() == "") {
if (default_value) {
return ret + default_value;
}
return "";
} else {
return ret + result;
}
}
}
return "";
}
}
opt.base = "cbid." + urlname + "." + sid;
opt.client = urlname.indexOf("server") === -1;
var v_type = opt.get("type").value;
var v_alias = opt.get("remarks");
var dom_prefix = null
var protocol = ""
if (v_type === "SS-Rust") {
dom_prefix = "ssrust_"
protocol = "ss"
} else if (v_type === "SSR") {
dom_prefix = "ssr_"
protocol = "ssr"
} else if (v_type === "Hysteria2") {
dom_prefix = "hysteria2_"
protocol = "hysteria2"
} else if (v_type === "Xray") {
dom_prefix = "xray_"
} else if (v_type === "sing-box") {
dom_prefix = "singbox_"
}
var _address = ""
if (dom_prefix && dom_prefix != null) {
try {
var v_server = opt.get(dom_prefix + "address");
const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
if (ipv6Regex.test(v_server.value)) {
_address = "[" + v_server.value + "]"
} else {
_address = v_server.value
}
} catch (e) {
}
}
var url = null;
if (v_type === "SS-Rust" || ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "shadowsocks")) {
protocol = "ss"
var v_port = opt.get(dom_prefix + "port");
var v_method = opt.get(dom_prefix + "method") || opt.get(dom_prefix + "ss_method");
var v_password = opt.get(dom_prefix + "password");
url = b64encsafe(v_method.value + ":" + v_password.value) + "@" +
_address + ":" +
v_port.value + "/?";
var shadow_tls;
//生成SS Shadow-TLS 插件参数
const generateShadowTLSBase64 = function(paramStr) {
try {
let obj = {};
let list = paramStr.split(";");
for (let i = 0; i < list.length; i++) {
let kv = list[i].split("=");
if (kv.length === 2) {
let k = kv[0].trim(), v = kv[1].trim();
let m = k.match(/^v(\d+)$/);
if (m && v === "1") obj.version = m[1];
else if (k === "passwd") obj.password = v;
else obj[k] = v;
}
}
return b64encsafe(JSON.stringify(obj));
} catch (e) {
return "";
}
}
var params = "";
opt.get(dom_prefix + "tcp_fast_open")?.checked && (params += "&tfo=1");
var v_plugin_dom = opt.get(dom_prefix + "plugin");
if (v_plugin_dom) {
var v_plugin = v_plugin_dom.value;
if (v_plugin && v_plugin != "none") {
if (v_plugin == "simple-obfs" || v_plugin == "obfs-local") {
v_plugin = "obfs-local";
}
var v_plugin_opts = opt.get(dom_prefix + "plugin_opts").value;
if (v_plugin_opts && v_plugin_opts != "") {
v_plugin += ";" + v_plugin_opts;
}
params += "&plugin=" + encodeURIComponent(v_plugin);
if (v_plugin_dom.value == "shadow-tls" && v_plugin_opts && v_plugin_opts != "") {
params = "shadow-tls=" + generateShadowTLSBase64(v_plugin_opts);
shadow_tls = 1;
}
}
} else if (v_type === "sing-box" || v_type === "Xray") {
var v_transport = opt.get(dom_prefix + "transport").value;
if (v_transport === "ws") {
params += opt.query("host", dom_prefix + "ws_host");
params += opt.query("path", dom_prefix + "ws_path");
if (v_type == "sing-box" && opt.get(dom_prefix + "ws_enableEarlyData").checked) {
var ws_maxEarlyData = opt.get(dom_prefix + "ws_maxEarlyData").value;
params += "?ed=" + ws_maxEarlyData;
}
} else if (v_transport === "http") {
params += opt.query("host", dom_prefix + "http_host");
params += opt.query("path", dom_prefix + "http_path");
} else if (v_transport === "raw" || v_transport === "tcp") {
v_transport = "tcp";
params += opt.query("headerType", dom_prefix + "tcp_guise");
params += opt.query("host", dom_prefix + "tcp_guise_http_host");
params += opt.query("path", dom_prefix + "tcp_guise_http_path");
} else if (v_transport === "mkcp") {
v_transport = "kcp";
params += opt.query("headerType", dom_prefix + "mkcp_guise");
params += opt.query("seed", dom_prefix + "mkcp_seed");
} else if (v_transport === "quic") {
params += opt.query("headerType", dom_prefix + "quic_guise");
params += opt.query("key", dom_prefix + "quic_key");
params += opt.query("quicSecurity", dom_prefix + "quic_security");
} else if (v_transport === "grpc") {
params += opt.query("path", dom_prefix + "grpc_serviceName");
params += opt.query("serviceName", dom_prefix + "grpc_serviceName");
params += opt.query("mode", dom_prefix + "grpc_mode");
} else if (v_transport === "xhttp") {
params += opt.query("host", dom_prefix + "xhttp_host");
params += opt.query("path", dom_prefix + "xhttp_path");
params += opt.query("mode", dom_prefix + "xhttp_mode");
if (opt.get(dom_prefix + "use_xhttp_extra").checked) {
params += opt.query("extra", dom_prefix + "xhttp_extra");
}
}
params += "&type=" + v_transport;
if (opt.get(dom_prefix + "tls").checked) {
var v_security = "tls";
if (opt.get(dom_prefix + "fingerprint") && opt.get(dom_prefix + "fingerprint").value != "") {
let v_fp = opt.get(dom_prefix + "fingerprint").value;
params += "&fp=" + v_fp;
}
if (opt.get(dom_prefix + "reality") && opt.get(dom_prefix + "reality").checked) {
v_security = "reality";
params += opt.query("pbk", dom_prefix + "reality_publicKey");
params += opt.query("sid", dom_prefix + "reality_shortId");
params += opt.query("spx", dom_prefix + "reality_spiderX");
params += opt.query("pqv", dom_prefix + "reality_mldsa65Verify");
}
params += "&security=" + v_security;
params += opt.query("alpn", dom_prefix + "alpn");
params += opt.query("sni", dom_prefix + "tls_serverName");
params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
params += opt.query("pcs", dom_prefix + "tls_pinSHA256");
params += opt.query("vcn", dom_prefix + "tls_CertByName");
params += opt.query("ech", dom_prefix + "ech_config");
}
opt.get(dom_prefix + "uot")?.checked && (params += "&udp=1");
if (opt.get(dom_prefix + "use_finalmask")?.checked) {
params += opt.query("fm", dom_prefix + "finalmask");
}
if (opt.get(dom_prefix + "shadowtls")?.checked) {
let st_plugin_str = "";
let st_version = opt.get(dom_prefix + "shadowtls_version")?.value;
if (st_version) st_plugin_str += "v" + st_version + "=1;";
let st_password = opt.get(dom_prefix + "shadowtls_password")?.value;
if (st_password) st_plugin_str += "passwd=" + st_password +";";
let st_host = opt.get(dom_prefix + "shadowtls_serverName")?.value;
if (st_host) st_plugin_str += "host=" + st_host +";";
if (opt.get(dom_prefix + "shadowtls_utls").checked) {
let st_fingerprint = opt.get(dom_prefix + "shadowtls_fingerprint")?.value;
if (st_fingerprint) st_plugin_str += "fingerprint=" + st_fingerprint;
}
params = "shadow-tls=" + generateShadowTLSBase64(st_plugin_str);
shadow_tls = 1;
}
}
if (shadow_tls) {
url = b64encsafe(v_method.value + ":" + v_password.value + "@" +
_address + ":" +
v_port.value) + "?";
} else {
params += "&group="
}
params += "#" + encodeURIComponent(v_alias.value);
if (params[0] == "&") {
params = params.substring(1);
}
url += params;
} else if (v_type === "SSR") {
var v_port = opt.get(dom_prefix + "port");
var v_protocol = opt.get(dom_prefix + "protocol");
var v_method = opt.get(dom_prefix + "method");
var v_obfs = opt.get(dom_prefix + "obfs");
var v_password = opt.get(dom_prefix + "password");
var v_obfs_param = opt.get(dom_prefix + "obfs_param");
var v_protocol_param = opt.get(dom_prefix + "protocol_param");
var ssr_str = _address + ":" +
v_port.value + ":" +
v_protocol.value + ":" +
v_method.value + ":" +
v_obfs.value + ":" +
b64encsafe(v_password.value) +
"/?obfsparam=" + b64encsafe(v_obfs_param.value) +
"&protoparam=" + b64encsafe(v_protocol_param.value) +
"&remarks=" + b64encutf8safe(v_alias.value);
url = b64encsafe(ssr_str);
} else if ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "vmess") {
protocol = "vmess";
var info = {};
info.v = "2";
info.ps = v_alias.value;
info.add = opt.get(dom_prefix + "address").value;
//info.add = _address;
info.port = opt.get(dom_prefix + "port").value;
info.id = opt.get(dom_prefix + "uuid").value;
var v_transport = opt.get(dom_prefix + "transport").value;
if (v_transport === "ws") {
info.host = opt.get(dom_prefix + "ws_host").value;
info.path = opt.get(dom_prefix + "ws_path").value;
if (v_type == "sing-box" && opt.get(dom_prefix + "ws_enableEarlyData").checked) {
var ws_maxEarlyData = opt.get(dom_prefix + "ws_maxEarlyData").value;
info.path = info.path + "?ed=" + ws_maxEarlyData;
}
} else if (v_transport === "http") {
info.host = opt.get(dom_prefix + "http_host").value;
info.path = opt.get(dom_prefix + "http_path").value;
} else if (v_transport === "raw" || v_transport === "tcp") {
v_transport = "tcp";
info.type = opt.get(dom_prefix + "tcp_guise").value;
if (info.type === "http") {
info.host = opt.get(dom_prefix + "tcp_guise_http_host").value;
info.path = opt.get(dom_prefix + "tcp_guise_http_path").value;
}
} else if (v_transport === "mkcp") {
v_transport = "kcp";
info.type = opt.get(dom_prefix + "mkcp_guise").value;
info.seed = opt.get(dom_prefix + "mkcp_seed").value;
} else if (v_transport === "quic") {
info.type = opt.get(dom_prefix + "quic_guise")?.value;
info.key = opt.get(dom_prefix + "quic_key")?.value;
info.securty = opt.get(dom_prefix + "quic_security")?.value;
} else if (v_transport === "grpc") {
info.path = opt.get(dom_prefix + "grpc_serviceName").value;
}
info.net = v_transport;
info.security = opt.get(dom_prefix + "security").value || "auto";
info.scy = info.security;
if (opt.get(dom_prefix + "tls").checked) {
var v_security = "tls";
info.tls = "tls";
info.sni = opt.get(dom_prefix + "tls_serverName").value;
info.alpn = opt.get(dom_prefix + "alpn")?.value;
if (info.alpn === "default") info.alpn = undefined;
info.fp = opt.get(dom_prefix + "fingerprint")?.value;
info.pcs = opt.get(dom_prefix + "tls_pinSHA256")?.value;
opt.get(dom_prefix + "tls_allowInsecure")?.checked && (info.insecure = "1");
}
opt.get(dom_prefix + "tcp_fast_open")?.checked && (info.tfo = "1");
if (opt.get(dom_prefix + "use_finalmask")?.checked) {
info.fm = opt.get(dom_prefix + "finalmask").value;
if (info.fm) info.fm = encodeURI(info.fm);
}
url = b64EncodeUnicode(JSON.stringify(info));
} else if ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "vless") {
protocol = "vless";
var v_password = opt.get(dom_prefix + "uuid");
var v_port = opt.get(dom_prefix + "port");
url = encodeURIComponent(v_password.value) +
"@" + _address +
":" + v_port.value + "?";
var params = "";
var v_transport = opt.get(dom_prefix + "transport").value;
if (v_transport === "ws") {
params += opt.query("host", dom_prefix + "ws_host");
params += opt.query("path", dom_prefix + "ws_path");
if (v_type == "sing-box" && opt.get(dom_prefix + "ws_enableEarlyData").checked) {
var ws_maxEarlyData = opt.get(dom_prefix + "ws_maxEarlyData").value;
params += encodeURIComponent("?ed=" + ws_maxEarlyData);
}
} else if (v_transport === "http") {
params += opt.query("host", dom_prefix + "http_host");
params += opt.query("path", dom_prefix + "http_path");
} else if (v_transport === "raw" || v_transport === "tcp") {
v_transport = "tcp";
params += opt.query("headerType", dom_prefix + "tcp_guise");
params += opt.query("host", dom_prefix + "tcp_guise_http_host");
params += opt.query("path", dom_prefix + "tcp_guise_http_path");
} else if (v_transport === "mkcp") {
v_transport = "kcp";
params += opt.query("headerType", dom_prefix + "mkcp_guise");
params += opt.query("seed", dom_prefix + "mkcp_seed");
} else if (v_transport === "quic") {
params += opt.query("headerType", dom_prefix + "quic_guise");
params += opt.query("key", dom_prefix + "quic_key");
params += opt.query("quicSecurity", dom_prefix + "quic_security");
} else if (v_transport === "grpc") {
params += opt.query("path", dom_prefix + "grpc_serviceName");
params += opt.query("serviceName", dom_prefix + "grpc_serviceName");
params += opt.query("mode", dom_prefix + "grpc_mode");
} else if (v_transport === "xhttp") {
params += opt.query("host", dom_prefix + "xhttp_host");
params += opt.query("path", dom_prefix + "xhttp_path");
params += opt.query("mode", dom_prefix + "xhttp_mode");
if (opt.get(dom_prefix + "use_xhttp_extra").checked) {
params += opt.query("extra", dom_prefix + "xhttp_extra");
}
} else if (v_transport === "httpupgrade") {
v_transport = "httpupgrade";
params += opt.query("host", dom_prefix + "httpupgrade_host");
params += opt.query("path", dom_prefix + "httpupgrade_path");
}
params += "&type=" + v_transport;
if (v_type === "sing-box") {
params += "&encryption=none";
} else {
params += opt.query("encryption", dom_prefix + "encryption");
}
if (opt.get(dom_prefix + "tls").checked) {
var v_security = "tls";
if (opt.get(dom_prefix + "fingerprint") && opt.get(dom_prefix + "fingerprint").value != "") {
let v_fp = opt.get(dom_prefix + "fingerprint").value;
params += "&fp=" + v_fp;
}
if (opt.get(dom_prefix + "reality") && opt.get(dom_prefix + "reality").checked) {
v_security = "reality";
params += opt.query("pbk", dom_prefix + "reality_publicKey");
params += opt.query("sid", dom_prefix + "reality_shortId");
params += opt.query("spx", dom_prefix + "reality_spiderX");
params += opt.query("pqv", dom_prefix + "reality_mldsa65Verify");
}
if (opt.get(dom_prefix + "flow") && opt.get(dom_prefix + "flow").value) {
let v_flow = opt.get(dom_prefix + "flow").value;
params += "&flow=" + v_flow;
}
params += "&security=" + v_security;
params += opt.query("alpn", dom_prefix + "alpn");
params += opt.query("sni", dom_prefix + "tls_serverName");
params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
params += opt.query("pcs", dom_prefix + "tls_pinSHA256");
params += opt.query("vcn", dom_prefix + "tls_CertByName");
params += opt.query("ech", dom_prefix + "ech_config");
}
opt.get(dom_prefix + "tcp_fast_open")?.checked && (params += "&tfo=1");
if (opt.get(dom_prefix + "use_finalmask")?.checked) {
params += opt.query("fm", dom_prefix + "finalmask");
}
params += "#" + encodeURI(v_alias.value);
if (params[0] == "&") {
params = params.substring(1);
}
url += params;
} else if ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "trojan") {
protocol = "trojan"
var v_password = opt.get(dom_prefix + "password");
var v_port = opt.get(dom_prefix + "port");
url = encodeURIComponent(v_password.value) +
"@" + _address +
":" + v_port.value + "/?";
var params = "";
var v_transport = opt.get(dom_prefix + "transport").value;
if (v_transport === "ws") {
params += opt.query("host", dom_prefix + "ws_host");
params += opt.query("path", dom_prefix + "ws_path");
if (v_type == "sing-box" && opt.get(dom_prefix + "ws_enableEarlyData").checked) {
var ws_maxEarlyData = opt.get(dom_prefix + "ws_maxEarlyData").value;
params += "?ed=" + ws_maxEarlyData;
}
} else if (v_transport === "http") {
params += opt.query("host", dom_prefix + "http_host");
params += opt.query("path", dom_prefix + "http_path");
} else if (v_transport === "raw" || v_transport === "tcp") {
v_transport = "tcp";
params += opt.query("headerType", dom_prefix + "tcp_guise");
params += opt.query("host", dom_prefix + "tcp_guise_http_host");
params += opt.query("path", dom_prefix + "tcp_guise_http_path");
} else if (v_transport === "mkcp") {
v_transport = "kcp";
params += opt.query("headerType", dom_prefix + "mkcp_guise");
params += opt.query("seed", dom_prefix + "mkcp_seed");
} else if (v_transport === "quic") {
params += opt.query("headerType", dom_prefix + "quic_guise");
params += opt.query("key", dom_prefix + "quic_key");
params += opt.query("quicSecurity", dom_prefix + "quic_security");
} else if (v_transport === "grpc") {
params += opt.query("path", dom_prefix + "grpc_serviceName");
params += opt.query("serviceName", dom_prefix + "grpc_serviceName");
params += opt.query("mode", dom_prefix + "grpc_mode");
}
params += "&type=" + v_transport;
var v_security = "none";
if (opt.get(dom_prefix + "tls").checked) {
v_security = "tls";
if (opt.get(dom_prefix + "fingerprint") && opt.get(dom_prefix + "fingerprint").value != "") {
let v_fp = opt.get(dom_prefix + "fingerprint").value;
params += "&fp=" + v_fp;
}
if (opt.get(dom_prefix + "reality") && opt.get(dom_prefix + "reality").checked) {
v_security = "reality";
params += opt.query("pbk", dom_prefix + "reality_publicKey");
params += opt.query("sid", dom_prefix + "reality_shortId");
params += opt.query("spx", dom_prefix + "reality_spiderX");
params += opt.query("pqv", dom_prefix + "reality_mldsa65Verify");
}
params += opt.query("alpn", dom_prefix + "alpn");
params += opt.query("sni", dom_prefix + "tls_serverName");
params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
params += opt.query("pcs", dom_prefix + "tls_pinSHA256");
params += opt.query("vcn", dom_prefix + "tls_CertByName");
params += opt.query("ech", dom_prefix + "ech_config");
}
params += "&security=" + v_security;
opt.get(dom_prefix + "tcp_fast_open")?.checked && (params += "&tfo=1");
if (opt.get(dom_prefix + "use_finalmask")?.checked) {
params += opt.query("fm", dom_prefix + "finalmask");
}
params += "#" + encodeURI(v_alias.value);
if (params[0] == "&") {
params = params.substring(1);
}
url += params;
} else if ((v_type === "Hysteria2") || ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "hysteria2")) {
protocol = "hysteria2"
var v_port = opt.get(dom_prefix + "port");
var params = "";
params += opt.query("sni", dom_prefix + "tls_serverName");
params += opt.query("insecure", dom_prefix + "tls_allowInsecure");
params += opt.query("pinSHA256", dom_prefix + "tls_pinSHA256");
params += opt.query("pcs", dom_prefix + "tls_pinSHA256");
params += opt.query("vcn", dom_prefix + "tls_CertByName");
var v_password = null;
if (v_type === "Hysteria2") {
v_password = opt.get("hysteria2_auth_password");
var dom_obfs_type = opt.get("hysteria2_obfs_type");
if (dom_obfs_type && dom_obfs_type.value != "") {
params += opt.query("obfs", "hysteria2_obfs_type");
params += opt.query("obfs-password", "hysteria2_obfs_password");
if (dom_obfs_type.value === "gecko") {
params += opt.query("minPacketSize", "hysteria2_obfs_MinPacketSize");
params += opt.query("maxPacketSize", "hysteria2_obfs_MaxPacketSize");
}
}
params += opt.query("mport", "hysteria2_hop");
} else {
v_password = opt.get(dom_prefix + "hysteria2_auth_password");
var dom_obfs_type = opt.get(dom_prefix + "hysteria2_obfs_type");
if (dom_obfs_type && dom_obfs_type.value != "") {
params += opt.query("obfs", dom_prefix + "hysteria2_obfs_type");
params += opt.query("obfs-password", dom_prefix + "hysteria2_obfs_password");
if (dom_obfs_type.value === "gecko") {
params += opt.query("minPacketSize", dom_prefix + "hysteria2_obfs_MinPacketSize");
params += opt.query("maxPacketSize", dom_prefix + "hysteria2_obfs_MaxPacketSize");
}
}
params += opt.query("mport", dom_prefix + "hysteria2_hop");
if (opt.get(dom_prefix + "use_finalmask")?.checked) {
params += opt.query("fm", dom_prefix + "finalmask");
}
}
params = params.replace(/^&/, "");
url =
_address + ":" +
v_port.value + "?" +
params +
"#" + encodeURI(v_alias.value);
if (v_password) {
url = encodeURIComponent(v_password.value) + "@" + url
}
} else if (v_type === "sing-box" && opt.get(dom_prefix + "protocol").value === "tuic") {
protocol = "tuic";
var v_username = opt.get(dom_prefix + "uuid");
var v_password = opt.get(dom_prefix + "password");
var v_port = opt.get(dom_prefix + "port");
url = encodeURIComponent(v_username.value) +
":" + encodeURIComponent(v_password.value) +
"@" + _address +
":" + v_port.value + "?";
var params = "";
params += opt.query("sni", dom_prefix + "tls_serverName");
params += opt.query("disable_sni", dom_prefix + "tls_disable_sni");
params += opt.query("alpn", dom_prefix + "tuic_alpn");
params += opt.query("congestion_control", dom_prefix + "tuic_congestion_control");
params += opt.query("udp_relay_mode", dom_prefix + "tuic_udp_relay_mode");
params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
params += "#" + encodeURI(v_alias.value);
if (params[0] == "&") {
params = params.substring(1);
}
url += params;
} else if (v_type === "sing-box" && opt.get(dom_prefix + "protocol").value === "anytls") {
protocol = "anytls";
var v_password = opt.get(dom_prefix + "password");
var v_port = opt.get(dom_prefix + "port");
url = encodeURIComponent(v_password.value) +
"@" + _address +
":" + v_port.value + "?";
var params = "";
if (opt.get(dom_prefix + "tls").checked) {
var v_security = "tls";
if (opt.get(dom_prefix + "fingerprint") && opt.get(dom_prefix + "fingerprint").value != "") {
let v_fp = opt.get(dom_prefix + "fingerprint").value;
params += "&fp=" + v_fp;
}
if (opt.get(dom_prefix + "reality") && opt.get(dom_prefix + "reality").checked) {
v_security = "reality";
params += opt.query("pbk", dom_prefix + "reality_publicKey");
params += opt.query("sid", dom_prefix + "reality_shortId");
}
params += "&security=" + v_security;
params += opt.query("alpn", dom_prefix + "alpn");
params += opt.query("sni", dom_prefix + "tls_serverName");
params += opt.query("insecure", dom_prefix + "tls_allowInsecure");
}
params += "#" + encodeURI(v_alias.value);
if (params[0] == "&") {
params = params.substring(1);
}
url += params;
} else if (v_type === "sing-box" && opt.get(dom_prefix + "protocol").value === "naive") {
protocol = "naive+https";
var v_username = opt.get(dom_prefix + "username");
var v_password = opt.get(dom_prefix + "password");
var v_port = opt.get(dom_prefix + "port");
url = encodeURIComponent(v_username.value) +
":" + encodeURIComponent(v_password.value) +
"@" + _address +
":" + v_port.value + "?";
var params = "security=tls";
params += opt.query("sni", dom_prefix + "tls_serverName");
params += opt.query("insecure-concurrency", dom_prefix + "naive_insecure_concurrency");
params += opt.query("ech", dom_prefix + "ech_config");
params += opt.query("uot", dom_prefix + "uot");
if (opt.get(dom_prefix + "naive_quic")?.checked) {
protocol = "naive+quic";
params += opt.query("congestion_control", dom_prefix + "naive_congestion_control");
}
params += "#" + encodeURI(v_alias.value);
if (params[0] == "&") {
params = params.substring(1);
}
url += params;
}
if (url) {
url = protocol.toLowerCase() + "://" + url;
return url;
} else {
alert("<%:Not a supported scheme:%> " + v_type);
}
return false;
}
function exportUrl(btn, urlname, sid) {
var url = buildUrl(btn, urlname, sid);
if (url) {
var textarea = document.createElement("textarea");
textarea.textContent = url;
textarea.style.position = "fixed";
document.body.appendChild(textarea);
textarea.select();
try {
var s = document.getElementById(urlname + "-status");
if (!s) {
alert("Never");
return false;
}
document.execCommand("copy"); // Security exception may be thrown by some browsers.
s.innerHTML = "<font color='green'><%:Share URL to clipboard successfully.%></font>";
} catch (ex) {
s.innerHTML = "<font color='red'><%:Share URL to clipboard unable.%></font>";
} finally {
document.body.removeChild(textarea);
}
}
}
function unbracketIP(server) {
if (!server) return '';
return server.replace(/^\[/, '').replace(/\]$/, '');
}
function fromUrl(btn, urlname, sid, cacheData) {
var opt = {
base: 'cbid.<%=appname%>',
client: true,
get: function (opt) {
var obj;
var id = this.base + '.' + opt;
obj = document.getElementsByName(id)[0] || document.getElementById(id);
if (obj) {
var combobox = document.getElementById('cbi.combobox.' + id);
if (combobox) {
obj.combobox = combobox;
}
var div = document.getElementById(id);
if (div && div.getElementsByTagName("li").length > 0) {
obj = div;
}
return obj;
} else {
return null;
}
},
set: function (opt, val) {
var obj;
obj = this.get(opt);
if (obj) {
var event = document.createEvent("HTMLEvents");
event.initEvent("change", true, true);
if (obj.type === 'checkbox') {
obj.checked = val;
} else {
obj.value = val;
if (obj.combobox) {
obj.combobox.value = val;
}
var list = obj.getElementsByTagName("li");
if (list.length > 0) {
for (var i = 0; i < list.length; i++) {
var li = list[i];
var data = li.getAttribute("data-value");
li.removeAttribute("selected");
li.removeAttribute("display");
if (data && data == val) {
li.setAttribute("selected", true);
li.setAttribute("display", "0");
}
}
var input = document.getElementsByName(obj.id)[0];
if (input) {
input.value = val;
} else {
var input = document.createElement("input");
input.setAttribute("type", "hidden");
input.setAttribute("name", obj.id);
input.setAttribute("value", val);
obj.appendChild(input);
}
}
}
try {
obj.dispatchEvent(event);
} catch (err) {}
} else {
//alert('<%:Faltal on set option, please help in debug: %>' + opt + ' = ' + val);
// 处理 DynamicList
var fullName = this.base + '.' + opt;
var lists = document.querySelectorAll('.cbi-dynlist');
for (var i = 0; i < lists.length; i++) {
var parent = lists[i].closest('.cbi-value');
if (!parent) continue;
// 尝试从 label 的 for 属性中提取 fullName
var label = parent.querySelector('label.cbi-value-title');
var labelFor = label?.getAttribute('for');
if (labelFor === fullName) {
var input = lists[i].querySelector('input[type="text"]');
var addBtn = lists[i].querySelector('.cbi-button-add');
if (input && addBtn) {
input.value = val;
addBtn.click();
}
break;
}
}
}
},
setlist: function (opt, vlist) {
var id = this.base + "." + opt;
var objs = document.getElementsByName(id) || document.getElementsByClassName(id);
if (objs) {
var values = "";
for (var i = 0; i < vlist.length; i++) {
values += vlist[i] + ", ";
}
alert("Manually input the option:\n" + opt + "s:\n[" + values + "]");
} else {
//alert("<%:Faltal on set option, please help in debug: %>" + opt);
}
}
}
var s = document.getElementById(urlname + '-status');
if (!s) {
alert("Never");
return false;
}
opt.base = "cbid." + urlname + "." + sid;
opt.client = urlname.indexOf("server") === -1;
var ssrurl = null;
if (cacheData) {
ssrurl = cacheData.ssrurl
} else {
ssrurl = prompt('<%:Paste Share URL Here%>', '');
if (ssrurl === null || ssrurl === "") {
return false;
}
sessionStorage.setItem("fromUrl", JSON.stringify({
timestamp: Date.now(),
savetime: 60 * 1000,
urlname: urlname,
sid: sid,
ssrurl: ssrurl
}));
}
ssrurl = ssrurl.replace(/&amp;/gi, '&').replace(/\s*#\s*/, '#').trim(); //一些奇葩的链接用"&amp;"当做"&""#"前后带空格
s.innerHTML = "";
var ssu = ssrurl.split('://');
var event = document.createEvent("HTMLEvents");
event.initEvent("change", true, true);
var dom_prefix = null
if (ssu[0] === "ssr") {
dom_prefix = "ssr_"
//var b64c = ssu[1].match(/([A-Za-z0-9_-]+)/);
var sstr = b64decsafe((ssu[1] || "").replace(/#.*/, "").trim());
var ploc = sstr.indexOf("/?");
var url0 = "", param = "";
if (ploc > 0) {
url0 = sstr.substr(0, ploc);
param = sstr.substr(ploc + 2);
} else {
var url0 = sstr;
}
var ssm = url0.match(/^(.+):([^:]+):([^:]*):([^:]+):([^:]*):([^:]+)/);
if (!ssm || ssm.length < 7) {
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
return false;
}
var pdict = {};
if (param.length > 2) {
var a = param.split('&');
for (var i = 0; i < a.length; i++) {
var b = a[i].split('=');
pdict[decodeURIComponent(b[0])] = decodeURIComponent(b[1] || '');
}
}
opt.set('type', "SSR");
opt.set(dom_prefix + 'address', unbracketIP(ssm[1]));
opt.set(dom_prefix + 'port', ssm[2]);
opt.set(dom_prefix + 'protocol', ssm[3]);
opt.set(dom_prefix + 'method', ssm[4]);
opt.set(dom_prefix + 'obfs', ssm[5]);
opt.set(dom_prefix + 'password', b64decsafe(ssm[6]));
opt.set(dom_prefix + 'obfs_param', dictvalue(pdict, 'obfsparam'));
opt.set(dom_prefix + 'protocol_param', dictvalue(pdict, 'protoparam'));
var rem = pdict['remarks'];
if (typeof (rem) !== 'undefined' && rem !== '' && rem.length > 0)
opt.set('remarks', b64decutf8safe(rem));
}
if (ssu[0] === "ss") {
var url0 = ssu[1] || "";
param = "";
var ploc = url0.indexOf("#");
if (ploc >= 0) {
param = url0.substr(ploc + 1);
url0 = url0.substr(0, ploc);
}
var queryIndex = (url0 = url0.replace('/?', '?')).indexOf("?");
var queryStr = "";
if (queryIndex >= 0) {
queryStr = url0.substr(queryIndex + 1);
url0 = url0.substr(0, queryIndex);
}
var queryParam = {};
queryParam = Object.fromEntries(new URLSearchParams(queryStr));
var server, port, method, password, plugin, pluginOpts;
var sipIndex = url0.indexOf("@");
if (sipIndex !== -1) {
// SIP002 base64(method:pass)@host:port
var userInfo = b64decsafe(decodeURIComponent(url0.substr(0, sipIndex)));
var temp = url0.substr(sipIndex + 1);
var serverInfo = temp.split(":");
server = serverInfo[0];
port = serverInfo[1];
var userInfoSplitIndex = userInfo.indexOf(":");
if (userInfoSplitIndex !== -1) {
method = userInfo.substr(0, userInfoSplitIndex);
password = userInfo.substr(userInfoSplitIndex + 1);
} else {
password = url0.substr(0, sipIndex); //一些链接用明文uuid做密码
}
} else {
// base64(method:pass@host:port)
var sstr = b64decsafe(decodeURIComponent(url0));
var m2022 = sstr.match(/^([^:]+):([^:]+):([^@]+)@([^:]+):(\d+)$/);
var mNormal = sstr.match(/^([^:]+):([^@]+)@([^:]+):(\d+)$/);
if (m2022) {
method = m2022[1];
password = m2022[2] + ":" + m2022[3];
server = m2022[4];
port = m2022[5];
} else if (mNormal) {
method = mNormal[1];
password = mNormal[2];
server = mNormal[3];
port = mNormal[4];
}
}
// 判断密码是否经过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;
}
}
password = isURLEncodedPassword(password) ? decodeURIComponent(password) : password;
if (queryParam.plugin) {
var pluginParams = decodeURIComponent(queryParam.plugin).split(";");
plugin = pluginParams.shift();
pluginOpts = pluginParams.join(";");
}
const needUpgrade = ss_type !== "Xray" && ss_type !== "sing-box" &&
queryParam.type && queryParam.type !== "tcp" &&
queryParam.headerType && queryParam.headerType !== "none";
if (has_xray && (ss_type == "xray" || needUpgrade || queryParam.type === "xhttp")) {
dom_prefix = "xray_"
opt.set('type', "Xray");
opt.set(dom_prefix + 'protocol', "shadowsocks");
} else if (has_singbox && (ss_type == "sing-box" || needUpgrade)) {
dom_prefix = "singbox_"
opt.set('type', "sing-box");
opt.set(dom_prefix + 'protocol', "shadowsocks");
} else {
dom_prefix = "ssrust_"
opt.set('type', "SS-Rust");
}
const _method = (method || "none").toLowerCase();
const mapping = {
"chacha20-poly1305": "chacha20-ietf-poly1305",
"xchacha20-poly1305": "xchacha20-ietf-poly1305",
};
method = mapping[_method] || _method;
opt.set(dom_prefix + 'address', unbracketIP(server));
opt.set(dom_prefix + 'port', port);
opt.set(dom_prefix + 'password', password || "");
opt.set(dom_prefix + 'method', method || "");
opt.set(dom_prefix + 'ss_method', method || "");
opt.set(dom_prefix + 'tcp_fast_open', queryParam.tfo);
if (plugin && plugin != "none") {
plugin = (plugin === "simple-obfs") ? "obfs-local" : plugin;
opt.set(dom_prefix + 'plugin_enabled', true);
opt.set(dom_prefix + 'plugin', plugin || "none");
opt.set(dom_prefix + 'plugin_opts', pluginOpts || "");
//obfs-local插件转换成xray支持的格式
if (plugin == "obfs-local" && dom_prefix == "xray_") {
var obfs = pluginOpts.match(/obfs=([^;]+)/);
var obfs_host = pluginOpts.match(/obfs-host=([^;]+)/);
obfs = obfs ? obfs[1] : "";
obfs_host = obfs_host ? obfs_host[1] : "";
if (obfs === "http") {
opt.set(dom_prefix + 'transport', "raw");
opt.set(dom_prefix + 'tcp_guise', "http");
opt.set(dom_prefix + 'tcp_guise_http_host', obfs_host || '');
opt.set(dom_prefix + 'tcp_guise_http_path', '/');
} else if (obfs === "tls") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'tls_serverName', obfs_host || '');
opt.set(dom_prefix + 'tls_allowInsecure', true);
}
}
} else {
opt.set(dom_prefix + 'plugin', "none");
}
if (param !== undefined) {
opt.set('remarks', decodeURIComponent(param));
}
if (Object.keys(queryParam).length > 0 && !queryParam.plugin) {
if (queryParam.security) {
if (queryParam.security == "tls") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'reality', false);
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
opt.set(
dom_prefix + 'tls_allowInsecure',
!((queryParam.allowinsecure ?? '0') === '0' && (queryParam.allowInsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0')
);
if (queryParam.fp && queryParam.fp.trim() != "") {
opt.set(dom_prefix + 'utls', true);
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
}
opt.set(dom_prefix + 'ech', !!queryParam.ech);
opt.set(dom_prefix + 'ech_config', queryParam.ech || '');
opt.set(dom_prefix + 'tls_pinSHA256', queryParam.pcs || '');
opt.set(dom_prefix + 'tls_CertByName', queryParam.vcn || '');
}
if (queryParam.security == "reality") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'reality', true);
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
if (queryParam.fp && queryParam.fp.trim() != "") {
opt.set(dom_prefix + 'utls', true);
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
}
opt.set(dom_prefix + 'reality_publicKey', queryParam.pbk || '');
opt.set(dom_prefix + 'reality_shortId', queryParam.sid || '');
opt.set(dom_prefix + 'reality_spiderX', queryParam.spx || '');
opt.set(dom_prefix + 'use_mldsa65Verify', !!queryParam.pqv);
opt.set(dom_prefix + 'reality_mldsa65Verify', queryParam.pqv || '');
}
}
queryParam.type = queryParam.type?.toLowerCase();
if (queryParam.type === "kcp") {
queryParam.type = "mkcp";
}
if (queryParam.type === "h2") {
queryParam.type = "http";
}
if (dom_prefix == "singbox_" && queryParam.type === "raw") {
queryParam.type = "tcp";
} else if (dom_prefix == "xray_" && queryParam.type === "tcp") {
queryParam.type = "raw";
}
if (dom_prefix == "xray_" && queryParam.type === "http") {
opt.set(dom_prefix + 'transport', "xhttp");
} else {
opt.set(dom_prefix + 'transport', queryParam.type);
}
if (queryParam.type === "raw" || queryParam.type === "tcp") {
opt.set(dom_prefix + 'tcp_guise', queryParam.headerType || "none");
if (queryParam.headerType && queryParam.headerType != "none") {
opt.set(dom_prefix + 'tcp_guise_http_host', queryParam.host || "");
opt.set(dom_prefix + 'tcp_guise_http_path', queryParam.path || "");
}
} else if (queryParam.type === "ws") {
opt.set(dom_prefix + 'ws_host', queryParam.host || "");
opt.set(dom_prefix + 'ws_path', queryParam.path || "");
if (dom_prefix == "singbox_" && queryParam.path && queryParam.path.length > 1) {
var ws_path_params = {};
var ws_path_dat = queryParam.path.split('?');
var ws_path = ws_path_dat[0];
var ws_path_params = {};
var ws_path_params_array = (ws_path_dat[1] || '').split('&');
for (i = 0; i < ws_path_params_array.length; i++) {
var kv = ws_path_params_array[i].split('=');
ws_path_params[decodeURIComponent(kv[0]).toLowerCase()] = decodeURIComponent(kv[1] || '');
}
if (ws_path_params.ed) {
opt.set(dom_prefix + 'ws_path', ws_path);
opt.set(dom_prefix + 'ws_enableEarlyData', true);
opt.set(dom_prefix + 'ws_maxEarlyData', ws_path_params.ed);
opt.set(dom_prefix + 'ws_earlyDataHeaderName', 'Sec-WebSocket-Protocol');
}
}
} else if (queryParam.type === "http") {
if (dom_prefix == "xray_") {
opt.set(dom_prefix + 'xhttp_mode', "stream-one");
opt.set(dom_prefix + 'xhttp_host', queryParam.host || "");
opt.set(dom_prefix + 'xhttp_path', queryParam.path || "");
} else {
opt.set(dom_prefix + 'http_host', queryParam.host || "");
opt.set(dom_prefix + 'http_path', queryParam.path || "");
}
} else if (queryParam.type === "quic") {
opt.set(dom_prefix + 'quic_guise', queryParam.headerType || "none");
opt.set(dom_prefix + 'quic_security', queryParam.quicSecurity);
opt.set(dom_prefix + 'quic_key', queryParam.key);
} else if (queryParam.type === "mkcp") {
opt.set(dom_prefix + 'mkcp_guise', queryParam.headerType || "none");
opt.set(dom_prefix + 'mkcp_seed', queryParam.seed || "");
} else if (queryParam.type === "grpc") {
opt.set(dom_prefix + 'grpc_serviceName', (queryParam.serviceName || queryParam.path) || "");
opt.set(dom_prefix + 'grpc_mode', queryParam.mode || "gun");
} else if (queryParam.type === "xhttp") {
opt.set(dom_prefix + 'xhttp_host', queryParam.host || "");
opt.set(dom_prefix + 'xhttp_path', queryParam.path || "");
opt.set(dom_prefix + 'xhttp_mode', queryParam.mode || "auto");
opt.set(dom_prefix + 'use_xhttp_extra', !!queryParam.extra);
opt.set(dom_prefix + 'xhttp_extra', queryParam.extra || "");
}
opt.set(dom_prefix + 'uot', queryParam.udp);
opt.set(dom_prefix + 'use_finalmask', !!queryParam.fm);
opt.set(dom_prefix + 'finalmask', queryParam.fm || "");
if (queryParam["shadow-tls"]) {
//解析SS Shadow-TLS 插件参数
const parseShadowTLSParams = function(base64Str, outObj) {
try {
let obj = JSON.parse(b64decsafe(base64Str));
if (outObj && typeof outObj === "object") {
for (let k in obj) outObj[k] = obj[k];
}
let out = [];
if (obj.version) out.push("v" + obj.version + "=1");
if (obj.password) out.push("passwd=" + obj.password);
for (let k in obj)
if (k !== "version" && k !== "password")
out.push(k + "=" + obj[k]);
return out.join(";");
} catch (e) {
return "";
}
}
if (dom_prefix === "ssrust_") {
opt.set(dom_prefix + 'plugin_enabled', true);
opt.set(dom_prefix + 'plugin', "shadow-tls");
let shadowtlsOpt = parseShadowTLSParams(queryParam["shadow-tls"]);
opt.set(dom_prefix + 'plugin_opts', shadowtlsOpt || "");
} else if (dom_prefix === "singbox_") {
let shadowtlsOpt = {};
parseShadowTLSParams(queryParam["shadow-tls"], shadowtlsOpt);
if (Object.keys(shadowtlsOpt).length > 0) {
opt.set(dom_prefix + 'shadowtls', true);
opt.set(dom_prefix + 'shadowtls_version', shadowtlsOpt.version || "1");
opt.set(dom_prefix + 'shadowtls_password', shadowtlsOpt.password || "");
opt.set(dom_prefix + 'shadowtls_serverName', shadowtlsOpt.host || "");
if (shadowtlsOpt.fingerprint) {
opt.set(dom_prefix + 'shadowtls_utls', true);
opt.set(dom_prefix + 'shadowtls_fingerprint', shadowtlsOpt.fingerprint || "chrome");
}
}
}
}
}
}
if (ssu[0] === "trojan") {
if (trojan_type == "sing-box" && has_singbox) {
dom_prefix = "singbox_"
opt.set('type', "sing-box");
opt.set(dom_prefix + 'protocol', "trojan");
} else if (trojan_type == "xray" && has_xray) {
dom_prefix = "xray_"
opt.set('type', "Xray");
opt.set(dom_prefix + 'protocol', "trojan");
}
var m = parseNodeUrl(ssrurl);
var password = m.passwd;
if (password === "") {
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
return false;
}
var queryParam = {};
if (m.search.length > 1) {
var query = m.search.replace('/?', '?').split('?');
var queryParams = query[1];
var queryArray = queryParams.split('&');
var params;
for (var i = 0; i < queryArray.length; i++) {
params = queryArray[i].split('=');
queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
}
}
opt.set(dom_prefix + 'address', unbracketIP(m.hostname));
opt.set(dom_prefix + 'port', m.port || "443");
opt.set(dom_prefix + 'password', decodeURIComponent(password));
queryParam.type = queryParam.type ? queryParam.type.toLowerCase() : "tcp";
if (queryParam.type === "kcp") {
queryParam.type = "mkcp";
}
if (queryParam.type === "h2") {
queryParam.type = "http";
}
if (dom_prefix == "singbox_" && queryParam.type === "raw") {
queryParam.type = "tcp";
} else if (dom_prefix == "xray_" && queryParam.type === "tcp") {
queryParam.type = "raw";
}
if (dom_prefix == "xray_" && queryParam.type === "http") {
opt.set(dom_prefix + 'transport', "xhttp");
} else {
opt.set(dom_prefix + 'transport', queryParam.type);
}
if (queryParam.type === "raw" || queryParam.type === "tcp") {
opt.set(dom_prefix + 'tcp_guise', queryParam.headerType || "none");
if (queryParam.headerType && queryParam.headerType != "none") {
opt.set(dom_prefix + 'tcp_guise_http_host', queryParam.host || "");
opt.set(dom_prefix + 'tcp_guise_http_path', queryParam.path || "");
}
} else if (queryParam.type === "ws") {
opt.set(dom_prefix + 'ws_host', queryParam.host || "");
opt.set(dom_prefix + 'ws_path', queryParam.path || "");
if (dom_prefix == "singbox_" && queryParam.path && queryParam.path.length > 1) {
var ws_path_params = {};
var ws_path_dat = queryParam.path.split('?');
var ws_path = ws_path_dat[0];
var ws_path_params = {};
var ws_path_params_array = (ws_path_dat[1] || '').split('&');
for (i = 0; i < ws_path_params_array.length; i++) {
var kv = ws_path_params_array[i].split('=');
ws_path_params[decodeURIComponent(kv[0]).toLowerCase()] = decodeURIComponent(kv[1] || '');
}
if (ws_path_params.ed) {
opt.set(dom_prefix + 'ws_path', ws_path);
opt.set(dom_prefix + 'ws_enableEarlyData', true);
opt.set(dom_prefix + 'ws_maxEarlyData', ws_path_params.ed);
opt.set(dom_prefix + 'ws_earlyDataHeaderName', 'Sec-WebSocket-Protocol');
}
}
} else if (queryParam.type === "http") {
if (dom_prefix == "xray_") {
opt.set(dom_prefix + 'xhttp_mode', "stream-one");
opt.set(dom_prefix + 'xhttp_host', queryParam.host || "");
opt.set(dom_prefix + 'xhttp_path', queryParam.path || "");
} else {
opt.set(dom_prefix + 'http_host', queryParam.host || "");
opt.set(dom_prefix + 'http_path', queryParam.path || "");
}
} else if (queryParam.type === "quic") {
opt.set(dom_prefix + 'quic_guise', queryParam.headerType || "none");
opt.set(dom_prefix + 'quic_security', queryParam.quicSecurity);
opt.set(dom_prefix + 'quic_key', queryParam.key);
} else if (queryParam.type === "mkcp") {
opt.set(dom_prefix + 'mkcp_guise', queryParam.headerType || "none");
opt.set(dom_prefix + 'mkcp_seed', queryParam.seed || "");
} else if (queryParam.type === "grpc") {
opt.set(dom_prefix + 'grpc_serviceName', (queryParam.serviceName || queryParam.path) || "");
opt.set(dom_prefix + 'grpc_mode', queryParam.mode || "gun");
}
queryParam.security = queryParam.security || "tls";
if (queryParam.security == "tls" || queryParam.security == "reality") {
if (queryParam.security == "tls") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'reality', false);
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.peer || queryParam.sni || "");
if (queryParam.fp && queryParam.fp.trim() != "") {
opt.set(dom_prefix + 'utls', true);
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
}
opt.set(dom_prefix + 'ech', !!queryParam.ech);
opt.set(dom_prefix + 'ech_config', queryParam.ech || '');
opt.set(dom_prefix + 'tls_pinSHA256', queryParam.pcs || '');
opt.set(dom_prefix + 'tls_CertByName', queryParam.vcn || '');
opt.set(
dom_prefix + 'tls_allowInsecure',
!((queryParam.allowinsecure ?? '0') === '0' && (queryParam.allowInsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0')
);
}
if (queryParam.security == "reality") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'reality', true);
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.peer || queryParam.sni || "");
if (queryParam.fp && queryParam.fp.trim() != "") {
opt.set(dom_prefix + 'utls', true);
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
}
opt.set(dom_prefix + 'reality_publicKey', queryParam.pbk || '');
opt.set(dom_prefix + 'reality_shortId', queryParam.sid || '');
}
}
opt.set(dom_prefix + 'tcp_fast_open', queryParam.tfo);
opt.set(dom_prefix + 'use_finalmask', !!queryParam.fm);
opt.set(dom_prefix + 'finalmask', queryParam.fm || "");
if (m.hash) {
opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
}
}
if (ssu[0] === "vmess") {
var sstr = b64DecodeUnicode((ssu[1] || "").replace(/#.*/, "").trim());
var ploc = sstr.indexOf("/?");
if (vmess_type == "sing-box" && has_singbox) {
dom_prefix = "singbox_"
opt.set('type', "sing-box");
} else if (has_xray) {
dom_prefix = "xray_"
opt.set('type', "Xray");
}
opt.set(dom_prefix + 'protocol', "vmess");
var url0, param = "";
if (ploc > 0) {
url0 = sstr.substr(0, ploc);
param = sstr.substr(ploc + 2);
}
var ssm = JSON.parse(sstr);
opt.set('remarks', ssm.ps);
opt.set(dom_prefix + 'address', unbracketIP(ssm.add));
opt.set(dom_prefix + 'port', ssm.port);
opt.set(dom_prefix + 'uuid', ssm.id);
opt.set(dom_prefix + 'security', ssm.security || ssm.scy || "auto");
opt.set(dom_prefix + 'tls', ssm.tls === "tls");
if (ssm.tls === "tls") {
opt.set(dom_prefix + 'tls_serverName', ssm.sni || ssm.host);
opt.set(dom_prefix + 'alpn', ssm.alpn || "default");
if (ssm.fp && ssm.fp !== "") {
opt.set(dom_prefix + 'utls', true);
opt.set(dom_prefix + 'fingerprint', ssm.fp);
}
opt.set(dom_prefix + 'tls_pinSHA256', ssm.pcs || "");
opt.set(
dom_prefix + 'tls_allowInsecure',
!((ssm.allowinsecure ?? '0') === '0' && (ssm.allowInsecure ?? '0') === '0' && (ssm.insecure ?? '0') === '0')
);
}
ssm.net = ssm.net.toLowerCase();
if (ssm.net === "kcp" || ssm.net === "mkcp")
ssm.net = "mkcp"
if (dom_prefix == "singbox_" && ssm.net === "raw") {
ssm.net = "tcp";
} else if (dom_prefix == "xray_" && ssm.net === "tcp") {
ssm.net = "raw";
}
if (ssm.net === "h2" || ssm.net === "http") {
ssm.net = "http";
}
if (dom_prefix == "xray_" && ssm.net === "http") {
opt.set(dom_prefix + 'transport', "xhttp");
} else {
opt.set(dom_prefix + 'transport', ssm.net);
}
if (ssm.net === "raw" || ssm.net === "tcp") {
opt.set(dom_prefix + 'tcp_guise', (ssm.host && ssm.host != "") ? "http" : "none");
if (ssm.host && ssm.host != "") {
opt.set(dom_prefix + 'tcp_guise_http_host', ssm.host);
opt.set(dom_prefix + 'tcp_guise_http_path', ssm.path || "");
}
} else if (ssm.net === "ws") {
opt.set(dom_prefix + 'ws_host', ssm.host);
opt.set(dom_prefix + 'ws_path', ssm.path);
if (dom_prefix == "singbox_" && ssm.path && ssm.path.length > 1) {
var ws_path_params = {};
var ws_path_dat = ssm.path.split('?');
var ws_path = ws_path_dat[0];
var ws_path_params = {};
var ws_path_params_array = (ws_path_dat[1] || '').split('&');
for (i = 0; i < ws_path_params_array.length; i++) {
var kv = ws_path_params_array[i].split('=');
ws_path_params[decodeURIComponent(kv[0]).toLowerCase()] = decodeURIComponent(kv[1] || '');
}
if (ws_path_params.ed) {
opt.set(dom_prefix + 'ws_path', ws_path);
opt.set(dom_prefix + 'ws_enableEarlyData', true);
opt.set(dom_prefix + 'ws_maxEarlyData', ws_path_params.ed);
opt.set(dom_prefix + 'ws_earlyDataHeaderName', 'Sec-WebSocket-Protocol');
}
}
} else if (ssm.net === "http") {
if (dom_prefix == "xray_") {
opt.set(dom_prefix + 'xhttp_mode', "stream-one");
opt.set(dom_prefix + 'xhttp_host', ssm.host || "");
opt.set(dom_prefix + 'xhttp_path', ssm.path || "");
} else {
opt.set(dom_prefix + 'http_host', ssm.host || "");
opt.set(dom_prefix + 'http_path', ssm.path || "");
}
} else if (ssm.net === "quic") {
opt.set(dom_prefix + 'quic_security', ssm.securty);
opt.set(dom_prefix + 'quic_key', ssm.key);
} else if (ssm.net === "kcp" || ssm.net === "mkcp") {
opt.set(dom_prefix + 'mkcp_guise', ssm.type || "none");
opt.set(dom_prefix + 'mkcp_seed', ssm.seed || "");
} else if (ssm.net === "grpc") {
opt.set(dom_prefix + 'grpc_serviceName', ssm.path);
}
opt.set(dom_prefix + 'tcp_fast_open', ssm.tfo);
opt.set(dom_prefix + 'use_finalmask', !!ssm.fm);
opt.set(dom_prefix + 'finalmask', ssm.fm || "");
}
if (ssu[0] === "vless") {
if (vless_type == "sing-box" && has_singbox) {
dom_prefix = "singbox_";
} else if (has_xray) {
dom_prefix = "xray_";
}
var m = parseNodeUrl(ssrurl);
var password = m.passwd;
if (password === "") {
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
return false;
}
var queryParam = {};
if (m.search.length > 1) {
var query = m.search.replace('/?', '?').split('?')
var queryParams = query[1];
var queryArray = queryParams.split('&');
var params;
for (i = 0; i < queryArray.length; i++) {
params = queryArray[i].split('=');
queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
}
}
queryParam.type = queryParam.type.toLowerCase();
if (["xhttp", "kcp", "mkcp"].includes(queryParam.type) && vless_type !== "xray" && has_xray) {
dom_prefix = "xray_";
}
opt.set("type", dom_prefix === "singbox_" ? "sing-box" : "Xray");
opt.set(dom_prefix + 'protocol', "vless");
opt.set(dom_prefix + 'uuid', password);
opt.set(dom_prefix + 'address', unbracketIP(m.hostname));
opt.set(dom_prefix + 'port', m.port || "443");
opt.set(dom_prefix + 'encryption', queryParam.encryption || "none");
queryParam.security = (!queryParam.security && queryParam.flow) ? "tls" : queryParam.security;
if (queryParam.security) {
if (queryParam.security == "tls") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'reality', false);
opt.set(dom_prefix + 'flow', queryParam.flow || '');
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
opt.set(
dom_prefix + 'tls_allowInsecure',
!((queryParam.allowinsecure ?? '0') === '0' && (queryParam.allowInsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0')
);
if (queryParam.fp && queryParam.fp.trim() != "") {
opt.set(dom_prefix + 'utls', true);
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
}
opt.set(dom_prefix + 'ech', !!queryParam.ech);
opt.set(dom_prefix + 'ech_config', queryParam.ech || '');
opt.set(dom_prefix + 'tls_pinSHA256', queryParam.pcs || '');
opt.set(dom_prefix + 'tls_CertByName', queryParam.vcn || '');
}
if (queryParam.security == "reality") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'reality', true);
opt.set(dom_prefix + 'flow', queryParam.flow || '');
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
if (queryParam.fp && queryParam.fp.trim() != "") {
opt.set(dom_prefix + 'utls', true);
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
}
opt.set(dom_prefix + 'reality_publicKey', queryParam.pbk || '');
opt.set(dom_prefix + 'reality_shortId', queryParam.sid || '');
opt.set(dom_prefix + 'reality_spiderX', queryParam.spx || '');
opt.set(dom_prefix + 'use_mldsa65Verify', !!queryParam.pqv);
opt.set(dom_prefix + 'reality_mldsa65Verify', queryParam.pqv || '');
}
}
if (queryParam.type === "kcp") {
queryParam.type = "mkcp";
}
if (queryParam.type === "h2") {
queryParam.type = "http";
}
if (dom_prefix == "singbox_" && queryParam.type === "raw") {
queryParam.type = "tcp";
} else if (dom_prefix == "xray_" && queryParam.type === "tcp") {
queryParam.type = "raw";
}
if (dom_prefix == "xray_" && queryParam.type === "http") {
opt.set(dom_prefix + 'transport', "xhttp");
} else {
opt.set(dom_prefix + 'transport', queryParam.type);
}
if (queryParam.type === "raw" || queryParam.type === "tcp") {
opt.set(dom_prefix + 'tcp_guise', queryParam.headerType || "none");
if (queryParam.headerType && queryParam.headerType != "none") {
opt.set(dom_prefix + 'tcp_guise_http_host', queryParam.host || "");
opt.set(dom_prefix + 'tcp_guise_http_path', queryParam.path || "");
}
} else if (queryParam.type === "ws") {
opt.set(dom_prefix + 'ws_host', queryParam.host || "");
opt.set(dom_prefix + 'ws_path', queryParam.path || "");
if (dom_prefix == "singbox_" && queryParam.path && queryParam.path.length > 1) {
var ws_path_params = {};
var ws_path_dat = queryParam.path.split('?');
var ws_path = ws_path_dat[0];
var ws_path_params = {};
var ws_path_params_array = (ws_path_dat[1] || '').split('&');
for (i = 0; i < ws_path_params_array.length; i++) {
var kv = ws_path_params_array[i].split('=');
ws_path_params[decodeURIComponent(kv[0]).toLowerCase()] = decodeURIComponent(kv[1] || '');
}
if (ws_path_params.ed) {
opt.set(dom_prefix + 'ws_path', ws_path);
opt.set(dom_prefix + 'ws_enableEarlyData', true);
opt.set(dom_prefix + 'ws_maxEarlyData', ws_path_params.ed);
opt.set(dom_prefix + 'ws_earlyDataHeaderName', 'Sec-WebSocket-Protocol');
}
}
} else if (queryParam.type === "h2" || queryParam.type === "http") {
if (dom_prefix == "xray_") {
opt.set(dom_prefix + 'xhttp_mode', "stream-one");
opt.set(dom_prefix + 'xhttp_host', queryParam.host || "");
opt.set(dom_prefix + 'xhttp_path', queryParam.path || "");
} else {
opt.set(dom_prefix + 'http_host', queryParam.host || "");
opt.set(dom_prefix + 'http_path', queryParam.path || "");
}
} else if (queryParam.type === "quic") {
opt.set(dom_prefix + 'quic_guise', queryParam.headerType || "none");
opt.set(dom_prefix + 'quic_security', queryParam.quicSecurity);
opt.set(dom_prefix + 'quic_key', queryParam.key);
} else if (queryParam.type === "kcp" || queryParam.type === "mkcp") {
opt.set(dom_prefix + 'mkcp_guise', queryParam.headerType || "none");
opt.set(dom_prefix + 'mkcp_seed', queryParam.seed || "");
} else if (queryParam.type === "grpc") {
opt.set(dom_prefix + 'grpc_serviceName', (queryParam.serviceName || queryParam.path) || "");
opt.set(dom_prefix + 'grpc_mode', queryParam.mode || "gun");
} else if (queryParam.type === "xhttp") {
opt.set(dom_prefix + 'xhttp_host', queryParam.host || "");
opt.set(dom_prefix + 'xhttp_path', queryParam.path || "");
opt.set(dom_prefix + 'xhttp_mode', queryParam.mode || "auto");
opt.set(dom_prefix + 'use_xhttp_extra', !!queryParam.extra);
opt.set(dom_prefix + 'xhttp_extra', queryParam.extra || "");
} else if (queryParam.type === "httpupgrade") {
opt.set(dom_prefix + 'httpupgrade_host', queryParam.host || "");
opt.set(dom_prefix + 'httpupgrade_path', queryParam.path || "");
}
opt.set(dom_prefix + 'tcp_fast_open', queryParam.tfo);
opt.set(dom_prefix + 'use_finalmask', !!queryParam.fm);
opt.set(dom_prefix + 'finalmask', queryParam.fm || "");
if (m.hash) {
opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
}
}
if (ssu[0] === "hysteria2" || ssu[0] === "hy2") {
var m = parseNodeUrl(ssrurl);
var password = m.passwd;
if (password === "") {
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
return false;
}
var queryParam = {};
if (m.search.length > 1) {
var query = m.search.replace('/?', '?').split('?')
var queryParams = query[1];
var queryArray = queryParams.split('&');
var params;
for (i = 0; i < queryArray.length; i++) {
params = queryArray[i].split('=');
queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
}
}
if ((hysteria2_type == "sing-box" && has_singbox) || (hysteria2_type == "xray" && has_xray)) {
var is_singbox = hysteria2_type == "sing-box" && has_singbox;
opt.set('type', is_singbox ? "sing-box" : "Xray");
dom_prefix = is_singbox ? "singbox_" : "xray_";
opt.set(dom_prefix + 'protocol', "hysteria2");
opt.set(dom_prefix + 'hysteria2_auth_password', decodeURIComponent(password));
if (queryParam["obfs-password"] || queryParam["obfs_password"]) {
opt.set(dom_prefix + 'hysteria2_obfs_type', queryParam.obfs || "salamander");
opt.set(dom_prefix + 'hysteria2_obfs_password', queryParam["obfs-password"] || queryParam["obfs_password"]);
}
if (queryParam.obfs === "gecko") {
opt.set(dom_prefix + 'hysteria2_obfs_MinPacketSize', queryParam.minPacketSize || "512");
opt.set(dom_prefix + 'hysteria2_obfs_MaxPacketSize', queryParam.maxPacketSize || "1200");
}
opt.set(dom_prefix + 'hysteria2_hop', queryParam.mport || "");
opt.set(dom_prefix + 'use_finalmask', !!queryParam.fm);
opt.set(dom_prefix + 'finalmask', queryParam.fm || "");
} else if (has_hysteria2) {
opt.set('type', "Hysteria2");
dom_prefix = "hysteria2_"
opt.set(dom_prefix + 'auth_password', decodeURIComponent(password));
if (queryParam["obfs-password"] || queryParam["obfs_password"]) {
opt.set(dom_prefix + 'obfs_type', queryParam.obfs || "salamander");
opt.set(dom_prefix + 'obfs_password', queryParam["obfs-password"] || queryParam["obfs_password"]);
}
if (queryParam.obfs === "gecko") {
opt.set(dom_prefix + 'obfs_MinPacketSize', queryParam.minPacketSize || "512");
opt.set(dom_prefix + 'obfs_MaxPacketSize', queryParam.maxPacketSize || "1200");
}
opt.set(dom_prefix + 'hop', queryParam.mport || "");
}
opt.set(dom_prefix + 'address', unbracketIP(m.hostname));
opt.set(dom_prefix + 'port', m.port || "443");
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || "");
opt.set(
dom_prefix + 'tls_allowInsecure',
!((queryParam.allowinsecure ?? '0') === '0' && (queryParam.allowInsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0')
);
opt.set(dom_prefix + 'tls_pinSHA256', queryParam.pcs || queryParam.pinSHA256 || '');
opt.set(dom_prefix + 'tls_CertByName', queryParam.vcn || '');
if (m.hash) {
opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
}
}
if (ssu[0] === "tuic") {
if (has_singbox) {
dom_prefix = "singbox_"
opt.set('type', "sing-box");
}
opt.set(dom_prefix + 'protocol', "tuic");
var _parsedUrl = new URL("http://" + ssu[1]);
var username = _parsedUrl.username;
var password = _parsedUrl.password;
var hostname = _parsedUrl.hostname;
var port = _parsedUrl.port;
var search = _parsedUrl.search;
var hash = _parsedUrl.hash;
if (!username || !password) { //修正某些链接会把uuid和password之间的:进行编码
const decoded = decodeURIComponent(username || password || "");
const i = decoded.indexOf(":");
if (i > -1) {
username = decoded.slice(0, i);
password = decoded.slice(i + 1);
}
}
opt.set(dom_prefix + 'uuid', decodeURIComponent(username));
opt.set(dom_prefix + 'password', decodeURIComponent(password));
opt.set(dom_prefix + 'address', unbracketIP(hostname));
opt.set(dom_prefix + 'port', port || "443");
var queryParam = {};
if (search.length > 1) {
var query = search.split('?')
var queryParams = query[1];
var queryArray = queryParams.split('&');
var params;
for (i = 0; i < queryArray.length; i++) {
params = queryArray[i].split('=');
queryParam[decodeURIComponent(params[0]).toLowerCase()] = decodeURIComponent(params[1] || '');
}
}
opt.set(dom_prefix + 'tuic_congestion_control', queryParam.congestion_control || 'cubic');
opt.set(dom_prefix + 'tuic_udp_relay_mode', queryParam.udp_relay_mode || 'native');
opt.set(dom_prefix + 'tuic_alpn', queryParam.alpn || 'h3');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
opt.set(dom_prefix + 'tls_disable_sni', queryParam.disable_sni === "1");
opt.set(
dom_prefix + 'tls_allowInsecure',
!((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0' && (queryParam.allow_insecure ?? '0') === '0')
);
if (hash) {
opt.set('remarks', decodeURIComponent(hash.substr(1)));
}
}
if (ssu[0] === "anytls") {
if (has_singbox) {
dom_prefix = "singbox_"
opt.set('type', "sing-box");
}
opt.set(dom_prefix + 'protocol', "anytls");
var m = parseNodeUrl(ssrurl);
var password = m.passwd;
if (password === "") {
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
return false;
}
opt.set(dom_prefix + 'password', password);
opt.set(dom_prefix + 'address', unbracketIP(m.hostname));
opt.set(dom_prefix + 'port', m.port || "443");
var queryParam = {};
if (m.search.length > 1) {
var query = m.search.replace('/?', '?').split('?')
var queryParams = query[1];
var queryArray = queryParams.split('&');
var params;
for (i = 0; i < queryArray.length; i++) {
params = queryArray[i].split('=');
queryParam[decodeURIComponent(params[0]).toLowerCase()] = decodeURIComponent(params[1] || '');
}
}
queryParam.security = queryParam.security || "tls";
if (queryParam.security) {
if (queryParam.security == "tls") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'reality', false);
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
opt.set(dom_prefix + 'tls_allowInsecure', !((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0'));
if (queryParam.fp && queryParam.fp.trim() != "") {
opt.set(dom_prefix + 'utls', true);
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
}
}
if (queryParam.security == "reality") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'reality', true);
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
if (queryParam.fp && queryParam.fp.trim() != "") {
opt.set(dom_prefix + 'utls', true);
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
}
opt.set(dom_prefix + 'reality_publicKey', queryParam.pbk || '');
opt.set(dom_prefix + 'reality_shortId', queryParam.sid || '');
}
}
if (m.hash) {
opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
}
}
if (ssu[0] === "naive+https" || ssu[0] === "naive+quic") {
if (has_singbox) {
dom_prefix = "singbox_"
opt.set('type', "sing-box");
}
opt.set(dom_prefix + 'protocol', "naive");
var _parsedUrl = new URL("http://" + ssu[1]);
var username = _parsedUrl.username;
var password = _parsedUrl.password;
var hostname = _parsedUrl.hostname;
var port = _parsedUrl.port;
var search = _parsedUrl.search;
var hash = _parsedUrl.hash;
if (!username || !password) { //某些链接会把username和password之间的:进行编码
const decoded = decodeURIComponent(username || password || "");
const i = decoded.indexOf(":");
if (i > -1) {
username = decoded.slice(0, i);
password = decoded.slice(i + 1);
}
}
opt.set(dom_prefix + 'username', decodeURIComponent(username));
opt.set(dom_prefix + 'password', decodeURIComponent(password));
opt.set(dom_prefix + 'address', unbracketIP(hostname));
opt.set(dom_prefix + 'port', port || "443");
var queryParam = {};
if (search.length > 1) {
var query = search.split('?')
var queryParams = query[1];
var queryArray = queryParams.split('&');
var params;
for (i = 0; i < queryArray.length; i++) {
params = queryArray[i].split('=');
queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
}
}
opt.set(dom_prefix + 'naive_insecure_concurrency', queryParam['insecure-concurrency'] || '0');
opt.set(dom_prefix + 'uot', (queryParam.uot ?? '0') === '1');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
opt.set(dom_prefix + 'ech', !!queryParam.ech);
opt.set(dom_prefix + 'ech_config', queryParam.ech || '');
if (ssu[0] === "naive+quic") {
opt.set(dom_prefix + 'naive_quic', true);
opt.set(dom_prefix + 'naive_congestion_control', queryParam.congestion_control || 'bbr');
}
if (hash) {
opt.set('remarks', decodeURIComponent(hash.substr(1)));
}
}
if (dom_prefix && dom_prefix != null) {
if (opt.get(dom_prefix + 'port').value) {
opt.get(dom_prefix + 'port').focus();
opt.get(dom_prefix + 'port').blur();
}
} else {
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
sessionStorage.removeItem("fromUrl");
return false;
}
s.innerHTML = "<font color='green'><%:Import Finished %></font>";
sessionStorage.removeItem("fromUrl");
return true;
}
function exportConfigFile(btn, sid) {
window.open('<%=api.url("gen_client_config")%>?id=' + sid, "_blank")
}
document.addEventListener("DOMContentLoaded", function () {
setTimeout(function () {
const fromUrlCache = JSON.parse(sessionStorage.getItem("fromUrl"));
if (fromUrlCache && fromUrlCache.savetime && (Date.now() - fromUrlCache.timestamp) < fromUrlCache.savetime) {
fromUrl(null, fromUrlCache.urlname, fromUrlCache.sid, fromUrlCache)
} else {
sessionStorage.removeItem("fromUrl");
}
}, 500);
})
//]]></script>
<style>
.share-toolbar {
display: inline-block;
text-align: center;
padding: 5px 0 5px;
white-space: nowrap;
}
@media screen and (max-width: 500px) {
.share-toolbar {
white-space: normal;
}
}
.toolbar-buttons .cbi-button {
margin-right: 2px;
margin-bottom: 2px;
}
.toolbar-buttons .cbi-button:last-child {
margin-right: 0;
}
.status-text {
display: none;
}
.status-text:not(:empty) {
display: inline-block;
line-height: 1;
padding: 5px 0;
}
</style>
<div class="share-toolbar">
<div class="toolbar-buttons">
<% if not current_node.protocol or not current_node.protocol:find("^_") then -%>
<input id="fromUrlBtn" type="button" class="btn cbi-button cbi-button-apply" value='<%:From Share URL%>' onclick="return fromUrl(this, '<%=self.option%>', '<%=self.value%>')" />
<input id="exportUrlBtn" type="button" class="btn cbi-button cbi-button-apply" value='<%:Build Share URL%>' onclick="return exportUrl(this, '<%=self.option%>', '<%=self.value%>')" />
<input id="genQrcodeBtn" type="button" class="btn cbi-button cbi-button-apply" value='<%:Generate QRCode%>' onclick="return genQrcode(this, '<%=self.option%>', '<%=self.value%>')" />
<% end -%>
<input id="exportConfigFileBtn" type="button" class="btn cbi-button cbi-button-apply" value='<%:Export Config File%>' onclick="return exportConfigFile(this, '<%=self.value%>')" />
</div>
<div id="qrcode_div" style="padding:5px 0;display:none">
<div id="qrcode" style="display:flex;justify-content:center;"></div>
</div>
<div style="text-align:center;padding:0;min-height:0;line-height:1;">
<span id="<%=self.option%>-status" class="status-text"></span>
</div>
</div>
<%+cbi/valuefooter%>