2025-07-18 00:58:03 +08:00

1461 lines
44 KiB
HTML

<%+cbi/valueheader%>
<script type="text/javascript">
//<![CDATA[
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) {
var l;
str = str.replace(/-/g, "+").replace(/_/g, "/");
l = str.length;
l = (4 - l % 4) % 4;
if (l) str = padright(str, l, "=");
return atob(str);
}
function dictvalue(d, key) {
var v = d[key];
if (typeof (v) == 'undefined' || v == '') return '';
return b64decsafe(v);
}
function parseUrl(url) {
var m = url.match(/^(([^:\/?#]+:)?(?:\/\/((?:([^\/?#:]*)([^\/?#:]*)@)?([^\/?#:]*)(?::([^\/?#:]*))?)))?([^?#]*)(\?[^#]*)?(#.*)?$/);
if (!m) return null;
return {
hash: m[10] || "",
host: m[3] || "",
hostname: m[6] || "",
href: m[0] || "",
origin: m[1] || "",
pathname: m[8] || (m[1] ? "/" : ""),
port: m[7] || "",
protocol: m[2] || "",
search: m[9] || "",
username: m[4] || "",
password: m[5] || ""
};
}
function decodeFragment(fragment) {
if (!fragment) return '';
try {
var decoded = decodeURIComponent(fragment);
while (decoded !== fragment) {
fragment = decoded;
decoded = decodeURIComponent(fragment);
}
return fragment;
} catch (e) {
return fragment;
}
}
function parseQuery(search) {
var query = {};
if (search && search.length > 1) {
var params = search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var eqIndex = params[i].indexOf('=');
if (eqIndex !== -1) {
var key = params[i].substring(0, eqIndex);
var value = params[i].substring(eqIndex + 1);
try {
key = decodeURIComponent(key);
query[key] = value;
} catch (e) {
query[key] = value;
}
}
}
}
return query;
}
function setFormValue(sid, field, value) {
var element = document.getElementsByName('cbid.openclash.' + sid + '.' + field)[0];
if (element) {
element.value = value;
var event = document.createEvent("HTMLEvents");
event.initEvent("change", true, true);
element.dispatchEvent(event);
}
}
function export_url(btn, urlname, sid) {
var s = document.getElementById(urlname + '-status');
if (!s) return false;
var v_type = document.getElementsByName('cbid.openclash.' + sid + '.type')[0];
if (!v_type) return false;
var type = v_type.value.toLowerCase();
var url = null;
try {
switch (type) {
case "ss":
url = exportSS(sid);
break;
case "ssr":
url = exportSSR(sid);
break;
case "vmess":
url = exportVmess(sid);
break;
case "vless":
url = exportVless(sid);
break;
case "trojan":
url = exportTrojan(sid);
break;
case "hysteria":
url = exportHysteria(sid);
break;
case "hysteria2":
url = exportHysteria2(sid);
break;
case "tuic":
url = exportTuic(sid);
break;
case "socks5":
url = exportSocks(sid);
break;
case "http":
url = exportHttp(sid);
break;
case "anytls":
url = exportAnyTLS(sid);
break;
default:
s.innerHTML = "<font style=\"color:red\"><%:Unsupported protocol type%></font>";
return false;
}
if (url) {
var textarea = document.createElement("textarea");
textarea.textContent = url;
textarea.style.position = "fixed";
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand("copy");
s.innerHTML = "<font style=\"color:green\"><%:Copy%> " + type.toUpperCase() + " <%:to clipboard successfully%></font>";
} catch (ex) {
s.innerHTML = "<font style=\"color:red\"><%:Unable to copy%> " + type.toUpperCase() + " <%:to clipboard%></font>";
} finally {
document.body.removeChild(textarea);
}
} else {
s.innerHTML = "<font style=\"color:red\"><%:Export failed%></font>";
}
} catch (e) {
s.innerHTML = "<font style=\"color:red\"><%:Export error%></font>";
return false;
}
return false;
}
function getFormValue(sid, field) {
var element = document.getElementsByName('cbid.openclash.' + sid + '.' + field)[0];
return element ? element.value : '';
}
function exportSS(sid) {
var server = getFormValue(sid, 'server');
var port = getFormValue(sid, 'port');
var password = getFormValue(sid, 'password');
var cipher = getFormValue(sid, 'cipher');
var name = getFormValue(sid, 'name');
var obfs = getFormValue(sid, 'obfs');
var host = getFormValue(sid, 'host');
var path = getFormValue(sid, 'path');
var tls = getFormValue(sid, 'tls');
if (!server || !port || !password || !cipher) {
return null;
}
// SIP002 format
var userInfo = b64encsafe(cipher + ':' + password);
var url = userInfo + '@' + server + ':' + port + '/?';
var params = [];
if (obfs && obfs !== 'none') {
var plugin = '';
if (obfs === 'http' || obfs === 'tls') {
plugin = 'obfs-local;obfs=' + obfs;
if (host) {
plugin += ';obfs-host=' + host;
}
} else if (obfs === 'websocket') {
plugin = 'v2ray-plugin;mode=websocket';
if (host) {
plugin += ';host=' + host;
}
if (path) {
plugin += ';path=' + path;
}
if (tls === 'true') {
plugin += ';tls=true';
}
}
if (plugin) {
params.push('plugin=' + encodeURIComponent(plugin));
}
}
url += params.join('&');
if (name) {
url += '#' + encodeURIComponent(name);
}
return 'ss://' + url;
}
function exportSSR(sid) {
var server = getFormValue(sid, 'server');
var port = getFormValue(sid, 'port');
var protocol = getFormValue(sid, 'protocol');
var method = getFormValue(sid, 'cipher_ssr');
var obfs = getFormValue(sid, 'obfs_ssr');
var password = getFormValue(sid, 'password');
var obfs_param = getFormValue(sid, 'obfs_param');
var protocol_param = getFormValue(sid, 'protocol_param');
var name = getFormValue(sid, 'name');
if (!server || !port || !password || !method) {
return null;
}
var ssr_str = server + ":" + port + ":" + protocol + ":" + method + ":" + obfs + ":" +
b64encsafe(password) + "/?obfsparam=" + b64encsafe(obfs_param) +
"&protoparam=" + b64encsafe(protocol_param) + "&remarks=" + b64encutf8safe(name);
return "ssr://" + b64encsafe(ssr_str);
}
function exportVmess(sid) {
var server = getFormValue(sid, 'server');
var port = getFormValue(sid, 'port');
var uuid = getFormValue(sid, 'uuid');
var alterId = getFormValue(sid, 'alterId');
var security = getFormValue(sid, 'securitys');
var name = getFormValue(sid, 'name');
var obfs = getFormValue(sid, 'obfs_vmess');
var tls = getFormValue(sid, 'tls');
var servername = getFormValue(sid, 'servername');
if (!server || !port || !uuid) {
return null;
}
var info = {
"v": "2",
"ps": name || "",
"add": server,
"port": port,
"id": uuid,
"aid": alterId || "0",
"scy": security || "auto",
"net": "tcp",
"type": "none",
"host": "",
"path": "",
"tls": tls === 'true' ? "tls" : ""
};
if (tls === 'true' && servername) {
info.sni = servername;
}
// Handle network type
if (obfs === 'websocket') {
info.net = "ws";
info.path = getFormValue(sid, 'ws_opts_path') || '/';
var headers = getFormValue(sid, 'ws_opts_headers');
if (headers && headers.includes('Host:')) {
info.host = headers.split('Host:')[1].trim();
}
} else if (obfs === 'h2') {
info.net = "h2";
info.path = getFormValue(sid, 'h2_path') || '/';
info.host = getFormValue(sid, 'h2_host') || '';
} else if (obfs === 'grpc') {
info.net = "grpc";
info.path = getFormValue(sid, 'grpc_service_name') || '';
}
return "vmess://" + b64EncodeUnicode(JSON.stringify(info));
}
function exportVless(sid) {
var server = getFormValue(sid, 'server');
var port = getFormValue(sid, 'port');
var uuid = getFormValue(sid, 'uuid');
var name = getFormValue(sid, 'name');
var tls = getFormValue(sid, 'tls');
var servername = getFormValue(sid, 'servername');
var obfs = getFormValue(sid, 'obfs_vless');
var flow = getFormValue(sid, 'vless_flow');
if (!server || !port || !uuid) {
return null;
}
var url = uuid + '@' + server + ':' + port + '?';
var params = [];
params.push('encryption=none');
if (tls === 'true') {
if (flow && flow.includes('xtls')) {
params.push('security=xtls');
params.push('flow=' + flow);
} else {
params.push('security=tls');
}
if (servername) {
params.push('sni=' + encodeURIComponent(servername));
}
}
if (obfs === 'ws') {
params.push('type=ws');
var path = getFormValue(sid, 'ws_opts_path');
if (path) {
params.push('path=' + encodeURIComponent(path));
}
var headers = getFormValue(sid, 'ws_opts_headers');
if (headers && headers.includes('Host:')) {
var host = headers.split('Host:')[1].trim();
params.push('host=' + encodeURIComponent(host));
}
} else if (obfs === 'grpc') {
params.push('type=grpc');
var serviceName = getFormValue(sid, 'grpc_service_name');
if (serviceName) {
params.push('serviceName=' + encodeURIComponent(serviceName));
}
} else {
params.push('type=tcp');
}
url += params.join('&');
if (name) {
url += '#' + encodeURIComponent(name);
}
return 'vless://' + url;
}
function exportTrojan(sid) {
var server = getFormValue(sid, 'server');
var port = getFormValue(sid, 'port');
var password = getFormValue(sid, 'password');
var name = getFormValue(sid, 'name');
var sni = getFormValue(sid, 'sni');
var alpn = getFormValue(sid, 'alpn');
var skip_cert = getFormValue(sid, 'skip_cert_verify');
if (!server || !port || !password) {
return null;
}
var url = encodeURIComponent(password) + '@' + server + ':' + port + '/?';
var params = [];
if (sni) {
params.push('sni=' + encodeURIComponent(sni));
}
if (alpn) {
params.push('alpn=' + encodeURIComponent(alpn));
}
if (skip_cert === 'true') {
params.push('allowInsecure=1');
}
url += params.join('&');
if (name) {
url += '#' + encodeURIComponent(name);
}
return 'trojan://' + url;
}
function exportHysteria(sid) {
var server = getFormValue(sid, 'server');
var port = getFormValue(sid, 'port');
var auth = getFormValue(sid, 'hysteria_auth_str');
var name = getFormValue(sid, 'name');
var protocol = getFormValue(sid, 'hysteria_protocol');
var up = getFormValue(sid, 'hysteria_up');
var down = getFormValue(sid, 'hysteria_down');
var obfs = getFormValue(sid, 'hysteria_obfs');
var sni = getFormValue(sid, 'sni');
var alpn = getFormValue(sid, 'hysteria_alpn');
var skip_cert = getFormValue(sid, 'skip_cert_verify');
if (!server || !port) {
return null;
}
var url = server + ':' + port + '?';
var params = [];
if (auth) {
params.push('auth=' + encodeURIComponent(auth));
}
if (protocol) {
params.push('protocol=' + protocol);
}
if (up) {
params.push('up=' + up);
}
if (down) {
params.push('down=' + down);
}
if (obfs) {
params.push('obfsParam=' + encodeURIComponent(obfs));
}
if (sni) {
params.push('peer=' + encodeURIComponent(sni));
}
if (alpn) {
params.push('alpn=' + encodeURIComponent(alpn));
}
if (skip_cert === 'true') {
params.push('insecure=1');
}
url += params.join('&');
if (name) {
url += '#' + encodeURIComponent(name);
}
return 'hysteria://' + url;
}
function exportHysteria2(sid) {
var server = getFormValue(sid, 'server');
var port = getFormValue(sid, 'port');
var password = getFormValue(sid, 'password');
var name = getFormValue(sid, 'name');
var obfs = getFormValue(sid, 'hysteria_obfs');
var obfs_password = getFormValue(sid, 'hysteria_obfs_password');
var up = getFormValue(sid, 'hysteria_up');
var down = getFormValue(sid, 'hysteria_down');
var sni = getFormValue(sid, 'sni');
var alpn = getFormValue(sid, 'hysteria_alpn');
var skip_cert = getFormValue(sid, 'skip_cert_verify');
if (!server || !port) {
return null;
}
var url = '';
if (password) {
url += encodeURIComponent(password) + '@';
}
url += server + ':' + port + '?';
var params = [];
if (obfs) {
params.push('obfs=' + encodeURIComponent(obfs));
}
if (obfs_password) {
params.push('obfs-password=' + encodeURIComponent(obfs_password));
}
if (up) {
params.push('up=' + up);
}
if (down) {
params.push('down=' + down);
}
if (sni) {
params.push('sni=' + encodeURIComponent(sni));
}
if (alpn) {
params.push('alpn=' + encodeURIComponent(alpn));
}
if (skip_cert === 'true') {
params.push('insecure=1');
}
url += params.join('&');
if (name) {
url += '#' + encodeURIComponent(name);
}
return 'hysteria2://' + url;
}
function exportTuic(sid) {
var server = getFormValue(sid, 'server');
var port = getFormValue(sid, 'port');
var uuid = getFormValue(sid, 'uuid');
var password = getFormValue(sid, 'password');
var token = getFormValue(sid, 'tc_token');
var name = getFormValue(sid, 'name');
var cc = getFormValue(sid, 'congestion_controller');
var alpn = getFormValue(sid, 'tc_alpn');
var sni = getFormValue(sid, 'sni');
var disable_sni = getFormValue(sid, 'disable_sni');
var udp_relay = getFormValue(sid, 'udp_relay_mode');
if (!server || !port) {
return null;
}
var url = '';
if (password) {
// TUIC v5
url += encodeURIComponent(uuid) + ':' + encodeURIComponent(password) + '@';
} else if (token) {
// TUIC v4
url += encodeURIComponent(token) + '@';
}
url += server + ':' + port + '?';
var params = [];
if (cc) {
params.push('congestion_control=' + encodeURIComponent(cc));
}
if (alpn) {
params.push('alpn=' + encodeURIComponent(alpn));
}
if (sni) {
params.push('sni=' + encodeURIComponent(sni));
}
if (disable_sni === 'true') {
params.push('disable_sni=1');
}
if (udp_relay) {
params.push('udp_relay_mode=' + encodeURIComponent(udp_relay));
}
url += params.join('&');
if (name) {
url += '#' + encodeURIComponent(name);
}
return 'tuic://' + url;
}
function exportSocks(sid) {
var server = getFormValue(sid, 'server');
var port = getFormValue(sid, 'port');
var username = getFormValue(sid, 'auth_name');
var password = getFormValue(sid, 'auth_pass');
var name = getFormValue(sid, 'name');
if (!server || !port) {
return null;
}
var url = '';
if (username && password) {
url += encodeURIComponent(username) + ':' + encodeURIComponent(password) + '@';
}
url += server + ':' + port;
if (name) {
url += '#' + encodeURIComponent(name);
}
return 'socks5://' + url;
}
function exportHttp(sid) {
var server = getFormValue(sid, 'server');
var port = getFormValue(sid, 'port');
var username = getFormValue(sid, 'auth_name');
var password = getFormValue(sid, 'auth_pass');
var name = getFormValue(sid, 'name');
var tls = getFormValue(sid, 'tls');
if (!server || !port) {
return null;
}
var scheme = tls === 'true' ? 'https' : 'http';
var url = '';
if (username && password) {
url += encodeURIComponent(username) + ':' + encodeURIComponent(password) + '@';
}
url += server + ':' + port;
if (name) {
url += '#' + encodeURIComponent(name);
}
return scheme + '://' + url;
}
function exportAnyTLS(sid) {
var server = getFormValue(sid, 'server');
var port = getFormValue(sid, 'port');
var username = getFormValue(sid, 'auth_name');
var password = getFormValue(sid, 'password');
var name = getFormValue(sid, 'name');
var sni = getFormValue(sid, 'sni');
var fingerprint = getFormValue(sid, 'fingerprint');
var skip_cert = getFormValue(sid, 'skip_cert_verify');
if (!server || !port) {
return null;
}
var url = '';
if (username) {
url += encodeURIComponent(username);
if (password) {
url += ':' + encodeURIComponent(password);
}
url += '@';
}
url += server + ':' + port + '?';
var params = [];
if (sni) {
params.push('sni=' + encodeURIComponent(sni));
}
if (fingerprint) {
params.push('hpkp=' + encodeURIComponent(fingerprint));
}
if (skip_cert === 'true') {
params.push('insecure=1');
}
url += params.join('&');
if (name) {
url += '#' + encodeURIComponent(name);
}
return 'anytls://' + url;
}
function import_url(btn, urlname, sid) {
var s = document.getElementById(urlname + '-status');
if (!s) return false;
var ssrurl = prompt("<%:Paste sharing link here%>", "");
if (ssrurl == null || ssrurl == "") {
s.innerHTML = "<font style=\"color:red\"><%:User cancelled%></font>";
return false;
}
s.innerHTML = "";
var ssu = ssrurl.split('://');
if (ssu.length < 2) {
s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
return false;
}
var scheme = ssu[0].toLowerCase();
var event = document.createEvent("HTMLEvents");
event.initEvent("change", true, true);
try {
switch (scheme) {
case "ss":
if (parseSS(ssu[1], sid)) {
s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
} else {
s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
}
break;
case "ssr":
if (parseSSR(ssu[1], sid)) {
s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
} else {
s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
}
break;
case "vmess":
if (parseVmess(ssu[1], sid)) {
s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
} else {
s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
}
break;
case "vless":
if (parseVless(ssrurl, sid)) {
s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
} else {
s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
}
break;
case "trojan":
if (parseTrojan(ssrurl, sid)) {
s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
} else {
s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
}
break;
case "hysteria":
if (parseHysteria(ssrurl, sid)) {
s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
} else {
s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
}
break;
case "hysteria2":
case "hy2":
if (parseHysteria2(ssrurl, sid)) {
s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
} else {
s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
}
break;
case "tuic":
if (parseTuic(ssrurl, sid)) {
s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
} else {
s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
}
break;
case "socks":
case "socks5":
case "socks5h":
if (parseSocks(ssrurl, sid)) {
s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
} else {
s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
}
break;
case "http":
case "https":
if (parseHttp(ssrurl, sid)) {
s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
} else {
s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
}
break;
case "anytls":
if (parseAnyTLS(ssrurl, sid)) {
s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
} else {
s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
}
break;
default:
s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
return false;
}
} catch (e) {
s.innerHTML = "<font style=\"color:red\"><%:Parse error%></font>";
return false;
}
return false;
}
function parseSS(body, sid) {
var url0, param = "";
var sipIndex = body.indexOf("@");
var ploc = body.indexOf("#");
if (ploc > 0) {
url0 = body.substr(0, ploc);
param = body.substr(ploc + 1);
} else {
url0 = body;
}
setFormValue(sid, 'type', 'ss');
if (sipIndex !== -1) {
// SIP002 format
var userInfo = b64decsafe(url0.substr(0, sipIndex));
var temp = url0.substr(sipIndex + 1).split("/?");
var serverInfo = temp[0].split(":");
var server = serverInfo[0];
var port = serverInfo[1];
var method, password;
if (temp[1]) {
var query = parseQuery("?" + temp[1]);
if (query.plugin) {
var decodedPlugin = decodeURIComponent(query.plugin);
var pluginParts = decodedPlugin.split(';');
var pluginName = pluginParts[0];
// obfs-local
if (pluginName === 'obfs-local' || pluginName.includes('obfs')) {
var obfsMode = 'http';
var obfsHost = '';
for (var i = 1; i < pluginParts.length; i++) {
var opt = pluginParts[i];
var eqIndex = opt.indexOf('=');
if (eqIndex !== -1) {
var key = opt.substring(0, eqIndex).trim();
var value = opt.substring(eqIndex + 1).trim();
if (key === 'obfs') {
obfsMode = value;
} else if (key === 'obfs-host') {
obfsHost = value;
}
}
}
setFormValue(sid, 'obfs', obfsMode);
if (obfsHost) {
setFormValue(sid, 'host', obfsHost);
}
}
// v2ray-plugin
if (pluginName === 'v2ray-plugin') {
var v2rayMode = 'websocket';
var v2rayHost = '';
var v2rayPath = '/';
var v2rayTls = false;
for (var i = 1; i < pluginParts.length; i++) {
var opt = pluginParts[i];
var eqIndex = opt.indexOf('=');
if (eqIndex !== -1) {
var key = opt.substring(0, eqIndex).trim();
var value = opt.substring(eqIndex + 1).trim();
if (key === 'mode') {
v2rayMode = value;
} else if (key === 'host') {
v2rayHost = value;
} else if (key === 'path') {
v2rayPath = value;
} else if (key === 'tls') {
v2rayTls = value === 'true' || value === '1';
}
}
}
setFormValue(sid, 'obfs', 'websocket');
if (v2rayHost) {
setFormValue(sid, 'host', v2rayHost);
}
if (v2rayPath) {
setFormValue(sid, 'path', v2rayPath);
}
if (v2rayTls) {
setFormValue(sid, 'tls', 'true');
}
}
}
if (query['udp-over-tcp'] === 'true' || query['uot'] === '1') {
setFormValue(sid, 'udp_over_tcp', 'true');
}
}
var userInfoSplitIndex = userInfo.indexOf(":");
if (userInfoSplitIndex !== -1) {
method = userInfo.substr(0, userInfoSplitIndex);
password = userInfo.substr(userInfoSplitIndex + 1);
}
setFormValue(sid, 'server', server);
setFormValue(sid, 'port', port);
setFormValue(sid, 'password', password || "");
setFormValue(sid, 'cipher', method || "");
} else {
// Legacy format
var sstr = b64decsafe(url0);
var team = sstr.split('@');
var part1 = team[0].split(':');
var part2 = team[1].split(':');
setFormValue(sid, 'server', part2[0]);
setFormValue(sid, 'port', part2[1]);
setFormValue(sid, 'password', part1[1]);
setFormValue(sid, 'cipher', part1[0]);
}
if (param) {
setFormValue(sid, 'name', decodeURIComponent(param));
}
return true;
}
function parseSSR(body, sid) {
var dcBuf;
try {
dcBuf = b64decsafe(body);
} catch (e) {
return false;
}
setFormValue(sid, 'type', 'ssr');
// ssr://host:port:protocol:method:obfs:urlsafebase64pass/?obfsparam=...
var before, after;
var queryIndex = dcBuf.indexOf('/?');
if (queryIndex > 0) {
before = dcBuf.substr(0, queryIndex);
after = dcBuf.substr(queryIndex + 2);
} else {
before = dcBuf;
after = "";
}
var parts = before.split(':');
if (parts.length !== 6) {
return false;
}
var host = parts[0];
var port = parts[1];
var protocol = parts[2];
var method = parts[3];
var obfs = parts[4];
var password = b64decsafe(parts[5]);
setFormValue(sid, 'server', host);
setFormValue(sid, 'port', port);
setFormValue(sid, 'protocol', protocol);
setFormValue(sid, 'cipher_ssr', method);
setFormValue(sid, 'obfs_ssr', obfs);
setFormValue(sid, 'password', password);
if (after) {
var params = {};
var paramPairs = after.split('&');
for (var i = 0; i < paramPairs.length; i++) {
var pair = paramPairs[i].split('=');
if (pair.length === 2) {
var key = decodeURIComponent(pair[0]);
var value = pair[1];
params[key] = value;
}
}
if (params.obfsparam) {
setFormValue(sid, 'obfs_param', b64decsafe(params.obfsparam));
}
if (params.protoparam) {
setFormValue(sid, 'protocol_param', b64decsafe(params.protoparam));
}
if (params.remarks) {
setFormValue(sid, 'name', b64decutf8safe(params.remarks));
}
}
return true;
}
function parseVmess(body, sid) {
try {
// Try V2rayN format first
var sstr = b64DecodeUnicode(body);
var ssm = JSON.parse(sstr);
setFormValue(sid, 'type', 'vmess');
setFormValue(sid, 'name', ssm.ps || '');
setFormValue(sid, 'server', ssm.add);
setFormValue(sid, 'port', ssm.port);
setFormValue(sid, 'alterId', ssm.aid || 0);
setFormValue(sid, 'uuid', ssm.id);
if (ssm.scy) {
setFormValue(sid, 'securitys', ssm.scy);
}
if (ssm.tls === "tls") {
setFormValue(sid, 'tls', 'true');
if (ssm.sni) {
setFormValue(sid, 'servername', ssm.sni);
}
}
var network = (ssm.net || 'tcp').toLowerCase();
if (network === 'ws') {
setFormValue(sid, 'obfs_vmess', 'websocket');
setFormValue(sid, 'ws_opts_path', ssm.path || '/');
if (ssm.host) {
setFormValue(sid, 'ws_opts_headers', 'Host: ' + ssm.host);
}
} else if (network === 'h2') {
setFormValue(sid, 'obfs_vmess', 'h2');
setFormValue(sid, 'h2_path', ssm.path || '/');
if (ssm.host) {
setFormValue(sid, 'h2_host', ssm.host);
}
} else if (network === 'tcp') {
if (ssm.type === 'http') {
setFormValue(sid, 'obfs_vmess', 'http');
if (ssm.path) {
setFormValue(sid, 'http_path', ssm.path);
}
if (ssm.host) {
setFormValue(sid, 'http_host', ssm.host);
}
} else {
setFormValue(sid, 'obfs_vmess', 'none');
}
} else if (network === 'grpc') {
setFormValue(sid, 'obfs_vmess', 'grpc');
setFormValue(sid, 'grpc_service_name', ssm.path || '');
}
return true;
} catch (e) {
// Try Xray VMessAEAD format
try {
var parsed = parseUrl('vmess://' + body);
if (!parsed) return false;
var query = parseQuery(parsed.search);
setFormValue(sid, 'type', 'vmess');
setFormValue(sid, 'server', parsed.hostname);
setFormValue(sid, 'port', parsed.port || '443');
setFormValue(sid, 'uuid', parsed.username);
setFormValue(sid, 'alterId', 0);
setFormValue(sid, 'securitys', query.encryption || 'auto');
if (parsed.hash) {
setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
}
return true;
} catch (e2) {
return false;
}
}
}
function parseVless(url, sid) {
var parsed = parseUrl(url);
if (!parsed) return false;
var query = parseQuery(parsed.search);
setFormValue(sid, 'type', 'vless');
setFormValue(sid, 'server', parsed.hostname);
setFormValue(sid, 'port', parsed.port || '443');
setFormValue(sid, 'uuid', parsed.username);
if (query.security) {
if (query.security === 'tls' || query.security === 'xtls') {
setFormValue(sid, 'tls', 'true');
if (query.sni) {
setFormValue(sid, 'servername', decodeURIComponent(query.sni));
}
if (query.security === 'xtls') {
setFormValue(sid, 'vless_flow', query.flow || 'xtls-rprx-direct');
}
} else if (query.security === 'reality') {
setFormValue(sid, 'tls', 'true');
if (query.sni) {
setFormValue(sid, 'servername', decodeURIComponent(query.sni));
}
if (query.pbk || query['public-key']) {
setFormValue(sid, 'reality_public_key', query.pbk || query['public-key']);
}
if (query.sid || query['short-id']) {
setFormValue(sid, 'reality_short_id', query.sid || query['short-id']);
}
}
}
var network = (query.type || 'tcp').toLowerCase();
if (network === 'ws') {
setFormValue(sid, 'obfs_vless', 'ws');
setFormValue(sid, 'ws_opts_path', decodeURIComponent(query.path || '/'));
if (query.host) {
setFormValue(sid, 'ws_opts_headers', 'Host: ' + decodeURIComponent(query.host));
}
} else if (network === 'grpc') {
setFormValue(sid, 'obfs_vless', 'grpc');
setFormValue(sid, 'grpc_service_name', decodeURIComponent(query.serviceName || query.path || ''));
} else {
setFormValue(sid, 'obfs_vless', 'tcp');
}
if (parsed.hash) {
setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
}
return true;
}
function parseTrojan(url, sid) {
var parsed = parseUrl(url);
if (!parsed) return false;
var query = parseQuery(parsed.search);
setFormValue(sid, 'type', 'trojan');
setFormValue(sid, 'server', parsed.hostname);
setFormValue(sid, 'port', parsed.port || '443');
setFormValue(sid, 'password', parsed.username);
if (query.sni) {
setFormValue(sid, 'sni', decodeURIComponent(query.sni));
}
if (query.alpn) {
// Handle ALPN - multiple values support, decode properly
setFormValue(sid, 'alpn', decodeURIComponent(query.alpn));
}
var network = (query.type || '').toLowerCase();
if (network === 'ws') {
setFormValue(sid, 'obfs_trojan', 'ws');
setFormValue(sid, 'trojan_ws_path', decodeURIComponent(query.path || '/'));
if (query.host) {
setFormValue(sid, 'trojan_ws_headers', 'Host: ' + decodeURIComponent(query.host));
}
} else if (network === 'grpc') {
setFormValue(sid, 'obfs_trojan', 'grpc');
setFormValue(sid, 'grpc_service_name', decodeURIComponent(query.serviceName || ''));
}
if (query.allowInsecure === '1') {
setFormValue(sid, 'skip_cert_verify', 'true');
}
if (parsed.hash) {
setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
}
return true;
}
function parseHysteria(url, sid) {
var parsed = parseUrl(url);
if (!parsed) return false;
var query = parseQuery(parsed.search);
setFormValue(sid, 'type', 'hysteria');
setFormValue(sid, 'server', parsed.hostname);
setFormValue(sid, 'port', parsed.port || '443');
if (query.auth) {
setFormValue(sid, 'hysteria_auth_str', decodeURIComponent(query.auth));
}
if (query.protocol) {
setFormValue(sid, 'flag_transport', '1');
setFormValue(sid, 'hysteria_protocol', query.protocol);
}
if (query.up || query.upmbps) {
var upSpeed = decodeURIComponent(query.up || query.upmbps);
upSpeed = upSpeed.replace(/[^0-9]/g, '');
setFormValue(sid, 'hysteria_up', upSpeed);
}
if (query.down || query.downmbps) {
var downSpeed = decodeURIComponent(query.down || query.downmbps);
downSpeed = downSpeed.replace(/[^0-9]/g, '');
setFormValue(sid, 'hysteria_down', downSpeed);
}
if (query.obfs || query.obfsParam) {
setFormValue(sid, 'hysteria_obfs', decodeURIComponent(query.obfs || query.obfsParam));
}
if (query.peer) {
setFormValue(sid, 'sni', decodeURIComponent(query.peer));
}
if (query.alpn) {
setFormValue(sid, 'hysteria_alpn', decodeURIComponent(query.alpn));
}
if (query.insecure === '1') {
setFormValue(sid, 'skip_cert_verify', 'true');
}
if (parsed.hash) {
setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
}
return true;
}
function parseHysteria2(url, sid) {
var parsed = parseUrl(url);
if (!parsed) return false;
var query = parseQuery(parsed.search);
setFormValue(sid, 'type', 'hysteria2');
setFormValue(sid, 'server', parsed.hostname);
setFormValue(sid, 'port', parsed.port || '443');
if (parsed.username) {
setFormValue(sid, 'password', parsed.username);
}
if (query.obfs) {
setFormValue(sid, 'hysteria_obfs', decodeURIComponent(query.obfs));
}
if (query['obfs-password']) {
setFormValue(sid, 'hysteria_obfs_password', decodeURIComponent(query['obfs-password']));
}
if (query.up) {
setFormValue(sid, 'hysteria_up', decodeURIComponent(query.up));
}
if (query.down) {
setFormValue(sid, 'hysteria_down', decodeURIComponent(query.down));
}
if (query.sni) {
setFormValue(sid, 'sni', decodeURIComponent(query.sni));
}
if (query.alpn) {
setFormValue(sid, 'hysteria_alpn', decodeURIComponent(query.alpn));
}
if (query.insecure === '1') {
setFormValue(sid, 'skip_cert_verify', 'true');
}
if (parsed.hash) {
setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
}
return true;
}
function parseTuic(url, sid) {
var parsed = parseUrl(url);
if (!parsed) return false;
var query = parseQuery(parsed.search);
setFormValue(sid, 'type', 'tuic');
setFormValue(sid, 'server', parsed.hostname);
setFormValue(sid, 'port', parsed.port || '443');
// Check if it's v5 (has password) or v4 (token only)
if (parsed.password) {
setFormValue(sid, 'uuid', parsed.username);
setFormValue(sid, 'password', parsed.password);
} else {
setFormValue(sid, 'tc_token', parsed.username);
}
if (query.congestion_control) {
setFormValue(sid, 'congestion_controller', decodeURIComponent(query.congestion_control));
}
if (query.alpn) {
setFormValue(sid, 'tc_alpn', decodeURIComponent(query.alpn));
}
if (query.sni) {
setFormValue(sid, 'sni', decodeURIComponent(query.sni));
}
if (query.disable_sni === '1') {
setFormValue(sid, 'disable_sni', 'true');
}
if (query.udp_relay_mode) {
setFormValue(sid, 'udp_relay_mode', decodeURIComponent(query.udp_relay_mode));
}
if (parsed.hash) {
setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
}
return true;
}
function parseSocks(url, sid) {
var parsed = parseUrl(url);
if (!parsed) return false;
setFormValue(sid, 'type', 'socks5');
setFormValue(sid, 'server', parsed.hostname);
setFormValue(sid, 'port', parsed.port || '1080');
if (parsed.username) {
try {
var decoded = atob(parsed.username);
var parts = decoded.split(':');
setFormValue(sid, 'auth_name', parts[0] || '');
setFormValue(sid, 'auth_pass', parts[1] || '');
} catch (e) {
setFormValue(sid, 'auth_name', parsed.username);
if (parsed.password) {
setFormValue(sid, 'auth_pass', parsed.password);
}
}
}
if (parsed.hash) {
setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
} else {
setFormValue(sid, 'name', parsed.hostname + ':' + parsed.port);
}
return true;
}
function parseHttp(url, sid) {
var parsed = parseUrl(url);
if (!parsed) return false;
setFormValue(sid, 'type', 'http');
setFormValue(sid, 'server', parsed.hostname);
setFormValue(sid, 'port', parsed.port || (parsed.protocol === 'https:' ? '443' : '80'));
if (parsed.protocol === 'https:') {
setFormValue(sid, 'tls', 'true');
}
if (parsed.username) {
try {
var decoded = atob(parsed.username);
var parts = decoded.split(':');
setFormValue(sid, 'auth_name', parts[0] || '');
setFormValue(sid, 'auth_pass', parts[1] || '');
} catch (e) {
setFormValue(sid, 'auth_name', parsed.username);
if (parsed.password) {
setFormValue(sid, 'auth_pass', parsed.password);
}
}
}
if (parsed.hash) {
setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
} else {
setFormValue(sid, 'name', parsed.hostname + ':' + parsed.port);
}
return true;
}
function parseAnyTLS(url, sid) {
var parsed = parseUrl(url);
if (!parsed) return false;
var query = parseQuery(parsed.search);
setFormValue(sid, 'type', 'anytls');
setFormValue(sid, 'server', parsed.hostname);
setFormValue(sid, 'port', parsed.port || '443');
setFormValue(sid, 'auth_name', parsed.username);
setFormValue(sid, 'password', parsed.password || parsed.username);
if (query.sni) {
setFormValue(sid, 'sni', query.sni);
}
if (query.hpkp) {
setFormValue(sid, 'fingerprint', query.hpkp);
}
if (query.insecure === '1') {
setFormValue(sid, 'skip_cert_verify', 'true');
}
if (parsed.hash) {
setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
} else {
setFormValue(sid, 'name', parsed.hostname + ':' + parsed.port);
}
return true;
}
//]]>
</script>
<input type="button" class="btn cbi-button cbi-button-apply" value="<%:Import%>" onclick="return import_url(this, '<%=self.option%>', '<%=self.value%>')" />
<input type="button" class="btn cbi-button cbi-button-apply" value="<%:Export%>" onclick="return export_url(this, '<%=self.option%>', '<%=self.value%>')" />
<span id="<%=self.option%>-status"></span>
<%+cbi/valuefooter%>