luci-app-passwall: sync with upstream source
This commit is contained in:
parent
95923f589c
commit
45e68bf527
@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall
|
||||
PKG_VERSION:=3.9
|
||||
PKG_RELEASE:=18
|
||||
PKG_RELEASE:=19
|
||||
PKG_DATE:=20200717
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
@ -37,6 +37,9 @@ function index()
|
||||
entry({"admin", "vpn", "passwall", "server_user_status"}, call("server_user_status")).leaf = true
|
||||
entry({"admin", "vpn", "passwall", "server_get_log"}, call("server_get_log")).leaf = true
|
||||
entry({"admin", "vpn", "passwall", "server_clear_log"}, call("server_clear_log")).leaf = true
|
||||
entry({"admin", "vpn", "passwall", "link_append_temp"}, call("link_append_temp")).leaf = true
|
||||
entry({"admin", "vpn", "passwall", "link_load_temp"}, call("link_load_temp")).leaf = true
|
||||
entry({"admin", "vpn", "passwall", "link_clear_temp"}, call("link_clear_temp")).leaf = true
|
||||
entry({"admin", "vpn", "passwall", "link_add_node"}, call("link_add_node")).leaf = true
|
||||
entry({"admin", "vpn", "passwall", "get_log"}, call("get_log")).leaf = true
|
||||
entry({"admin", "vpn", "passwall", "clear_log"}, call("clear_log")).leaf = true
|
||||
@ -82,9 +85,38 @@ function hide_menu()
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin", "status", "overview"))
|
||||
end
|
||||
|
||||
function link_add_node()
|
||||
function link_append_temp()
|
||||
local link = luci.http.formvalue("link")
|
||||
luci.sys.call('rm -f /tmp/links.conf && echo "' .. link .. '" >> /tmp/links.conf')
|
||||
local lfile = "/tmp/links.conf"
|
||||
local ret, ldata="empty", {}
|
||||
luci.sys.call('touch ' .. lfile .. ' && echo \'' .. link .. '\' >> ' .. lfile)
|
||||
ret = luci.sys.exec([[awk -F'://' 'BEGIN{ all=0 } /.{2,9}:\/\/.{4,}$/ {gsub(/:\/\/.*$/,""); arr[$0]++; all++ } END { for(typ in arr) { printf("%s: %d, ", typ, arr[typ]) }; printf("\ntotal: %d", all) }' ]] .. lfile)
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({counter = ret})
|
||||
end
|
||||
|
||||
function link_load_temp()
|
||||
local lfile = "/tmp/links.conf"
|
||||
local ret, ldata="empty", {}
|
||||
ldata[#ldata+1] = nixio.fs.readfile(lfile) or "_nofile_"
|
||||
if ldata[1] == "" then
|
||||
ldata[1] = "_nodata_"
|
||||
else
|
||||
ret = luci.sys.exec([[awk -F'://' 'BEGIN{ all=0 } /.{2,9}:\/\/.{4,}$/ {gsub(/:\/\/.*$/,""); arr[$0]++; all++ } END { for(typ in arr) { printf("%s: %d, ", typ, arr[typ]) }; printf("\ntotal: %d", all) }' ]] .. lfile)
|
||||
end
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({counter = ret, data = ldata})
|
||||
end
|
||||
|
||||
function link_clear_temp()
|
||||
local lfile = "/tmp/links.conf"
|
||||
luci.sys.call('cat /dev/null > ' .. lfile)
|
||||
end
|
||||
|
||||
function link_add_node()
|
||||
local lfile = "/tmp/links.conf"
|
||||
local link = luci.http.formvalue("link")
|
||||
luci.sys.call('echo \'' .. link .. '\' >> ' .. lfile)
|
||||
luci.sys.call("lua /usr/share/passwall/subscribe.lua add log")
|
||||
end
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ local function gen_outbound(node, tag)
|
||||
concurrency = (node.mux_concurrency) and tonumber(node.mux_concurrency) or 8
|
||||
},
|
||||
-- 底层传输配置
|
||||
streamSettings = (node.protocol == "vmess") and {
|
||||
streamSettings = (node.protocol == "vmess" or node.protocol == "socks" or node.protocol == "shadowsocks") and {
|
||||
network = node.transport,
|
||||
security = node.stream_security,
|
||||
tlsSettings = (node.stream_security == "tls") and {
|
||||
@ -56,8 +56,7 @@ local function gen_outbound(node, tag)
|
||||
serverName = node.tls_serverName,
|
||||
allowInsecure = (node.tls_allowInsecure == "1") and true or false
|
||||
} or nil,
|
||||
tcpSettings = (node.transport == "tcp" and
|
||||
node.protocol ~= "socks") and {
|
||||
tcpSettings = (node.transport == "tcp" and node.protocol ~= "socks") and {
|
||||
header = {
|
||||
type = node.tcp_guise,
|
||||
request = {
|
||||
|
||||
@ -10,8 +10,7 @@ local function get_customed_path(e)
|
||||
end
|
||||
|
||||
local function is_finded(e)
|
||||
return luci.sys.exec("find /usr/*bin %s -iname %s -type f" %
|
||||
{get_customed_path(e), e}) ~= "" and true or false
|
||||
return luci.sys.exec("find /usr/*bin %s -iname %s -type f" % {get_customed_path(e), e}) ~= "" and true or false
|
||||
end
|
||||
|
||||
local function is_installed(e) return ipkg.installed(e) end
|
||||
@ -73,13 +72,17 @@ s = m:section(NamedSection, arg[1], "nodes", "")
|
||||
s.addremove = false
|
||||
s.dynamic = false
|
||||
|
||||
share = s:option(DummyValue, "share_url", translate("Share Current"))
|
||||
share.rawhtml = true
|
||||
share.template = "passwall/node_list/link_share_man"
|
||||
share.value = arg[1]
|
||||
|
||||
remarks = s:option(Value, "remarks", translate("Node Remarks"))
|
||||
remarks.default = translate("Remarks")
|
||||
remarks.rmempty = false
|
||||
|
||||
type = s:option(ListValue, "type", translate("Type"))
|
||||
if ((is_installed("redsocks2") or is_finded("redsocks2")) or
|
||||
(is_installed("ipt2socks") or is_finded("ipt2socks"))) then
|
||||
if is_installed("ipt2socks") or is_finded("ipt2socks") then
|
||||
type:value("Socks", translate("Socks"))
|
||||
end
|
||||
if is_finded("ss-redir") then
|
||||
@ -145,8 +148,7 @@ for k, v in pairs(nodes_table) do default_node:value(v.id, v.remarks) end
|
||||
default_node:depends("protocol", "_shunt")
|
||||
|
||||
-- Brook协议
|
||||
brook_protocol = s:option(ListValue, "brook_protocol",
|
||||
translate("Brook Protocol"))
|
||||
brook_protocol = s:option(ListValue, "brook_protocol", translate("Brook Protocol"))
|
||||
brook_protocol:value("client", translate("Brook"))
|
||||
brook_protocol:value("wsclient", translate("WebSocket"))
|
||||
brook_protocol:depends("type", "Brook")
|
||||
@ -213,28 +215,23 @@ password:depends("protocol", "http")
|
||||
password:depends("protocol", "socks")
|
||||
password:depends("protocol", "shadowsocks")
|
||||
|
||||
ss_encrypt_method = s:option(ListValue, "ss_encrypt_method",
|
||||
translate("Encrypt Method"))
|
||||
ss_encrypt_method = s:option(ListValue, "ss_encrypt_method", translate("Encrypt Method"))
|
||||
for a, t in ipairs(ss_encrypt_method_list) do ss_encrypt_method:value(t) end
|
||||
ss_encrypt_method:depends("type", "SS")
|
||||
|
||||
ssr_encrypt_method = s:option(ListValue, "ssr_encrypt_method",
|
||||
translate("Encrypt Method"))
|
||||
ssr_encrypt_method = s:option(ListValue, "ssr_encrypt_method", translate("Encrypt Method"))
|
||||
for a, t in ipairs(ssr_encrypt_method_list) do ssr_encrypt_method:value(t) end
|
||||
ssr_encrypt_method:depends("type", "SSR")
|
||||
|
||||
security = s:option(ListValue, "security",
|
||||
translate("Encrypt Method"))
|
||||
security = s:option(ListValue, "security", translate("Encrypt Method"))
|
||||
for a, t in ipairs(security_list) do security:value(t) end
|
||||
security:depends("protocol", "vmess")
|
||||
|
||||
v_ss_encrypt_method = s:option(ListValue, "v_ss_encrypt_method",
|
||||
translate("Encrypt Method"))
|
||||
v_ss_encrypt_method = s:option(ListValue, "v_ss_encrypt_method", translate("Encrypt Method"))
|
||||
for a, t in ipairs(v_ss_encrypt_method_list) do v_ss_encrypt_method:value(t) end
|
||||
v_ss_encrypt_method:depends("protocol", "shadowsocks")
|
||||
|
||||
ss_ota = s:option(Flag, "ss_ota", translate("OTA"), translate(
|
||||
"When OTA is enabled, V2Ray will reject connections that are not OTA enabled. This option is invalid when using AEAD encryption."))
|
||||
ss_ota = s:option(Flag, "ss_ota", translate("OTA"), translate("When OTA is enabled, V2Ray will reject connections that are not OTA enabled. This option is invalid when using AEAD encryption."))
|
||||
ss_ota.default = "0"
|
||||
ss_ota:depends("protocol", "shadowsocks")
|
||||
|
||||
@ -258,8 +255,7 @@ timeout.default = 300
|
||||
timeout:depends("type", "SS")
|
||||
timeout:depends("type", "SSR")
|
||||
|
||||
tcp_fast_open = s:option(ListValue, "tcp_fast_open", translate("TCP Fast Open"),
|
||||
translate("Need node support required"))
|
||||
tcp_fast_open = s:option(ListValue, "tcp_fast_open", translate("TCP Fast Open"), translate("Need node support required"))
|
||||
tcp_fast_open:value("false")
|
||||
tcp_fast_open:value("true")
|
||||
tcp_fast_open:depends("type", "SS")
|
||||
@ -278,9 +274,7 @@ ss_plugin_opts:depends("ss_plugin", "v2ray-plugin")
|
||||
ss_plugin_opts:depends("ss_plugin", "obfs-local")
|
||||
|
||||
use_kcp = s:option(Flag, "use_kcp", translate("Use Kcptun"),
|
||||
"<span style='color:red'>" .. translate(
|
||||
"Please confirm whether the Kcptun is installed. If not, please go to Rule Update download installation.") ..
|
||||
"</span>")
|
||||
"<span style='color:red'>" .. translate("Please confirm whether the Kcptun is installed. If not, please go to Rule Update download installation.") .. "</span>")
|
||||
use_kcp.default = 0
|
||||
use_kcp:depends("type", "SS")
|
||||
use_kcp:depends("type", "SSR")
|
||||
@ -294,34 +288,27 @@ kcp_port = s:option(Value, "kcp_port", translate("Kcptun Port"))
|
||||
kcp_port.datatype = "port"
|
||||
kcp_port:depends("use_kcp", "1")
|
||||
|
||||
kcp_opts = s:option(TextValue, "kcp_opts", translate("Kcptun Config"),
|
||||
translate(
|
||||
"--crypt aes192 --key abc123 --mtu 1350 --sndwnd 128 --rcvwnd 1024 --mode fast"))
|
||||
kcp_opts.placeholder =
|
||||
"--crypt aes192 --key abc123 --mtu 1350 --sndwnd 128 --rcvwnd 1024 --mode fast"
|
||||
kcp_opts = s:option(TextValue, "kcp_opts", translate("Kcptun Config"), translate("--crypt aes192 --key abc123 --mtu 1350 --sndwnd 128 --rcvwnd 1024 --mode fast"))
|
||||
kcp_opts.placeholder = "--crypt aes192 --key abc123 --mtu 1350 --sndwnd 128 --rcvwnd 1024 --mode fast"
|
||||
kcp_opts:depends("use_kcp", "1")
|
||||
|
||||
vmess_id = s:option(Value, "vmess_id", translate("ID"))
|
||||
vmess_id.password = true
|
||||
vmess_id:depends("protocol", "vmess")
|
||||
|
||||
alter_id = s:option(Value, "alter_id",
|
||||
translate("Alter ID"))
|
||||
alter_id = s:option(Value, "alter_id", translate("Alter ID"))
|
||||
alter_id:depends("protocol", "vmess")
|
||||
|
||||
vmess_level =
|
||||
s:option(Value, "vmess_level", translate("User Level"))
|
||||
vmess_level = s:option(Value, "vmess_level", translate("User Level"))
|
||||
vmess_level.default = 1
|
||||
vmess_level:depends("protocol", "vmess")
|
||||
|
||||
stream_security = s:option(ListValue, "stream_security",
|
||||
translate("Transport Layer Encryption"),
|
||||
translate(
|
||||
'Whether or not transport layer encryption is enabled, the supported options are "none" for unencrypted (default) and "TLS" for using TLS.'))
|
||||
stream_security = s:option(ListValue, "stream_security", translate("Transport Layer Encryption"), translate('Whether or not transport layer encryption is enabled, the supported options are "none" for unencrypted (default) and "TLS" for using TLS.'))
|
||||
stream_security:value("none", "none")
|
||||
stream_security:value("tls", "tls")
|
||||
stream_security.default = "tls"
|
||||
stream_security:depends("protocol", "vmess")
|
||||
stream_security:depends("protocol", "socks")
|
||||
stream_security:depends("protocol", "shadowsocks")
|
||||
stream_security:depends("type", "Trojan")
|
||||
stream_security:depends("type", "Trojan-Go")
|
||||
@ -333,13 +320,11 @@ stream_security.validate = function(self, value)
|
||||
end
|
||||
|
||||
-- [[ TLS部分 ]] --
|
||||
|
||||
tls_sessionTicket = s:option(Flag, "tls_sessionTicket", translate("Session Ticket"))
|
||||
tls_sessionTicket.default = "0"
|
||||
tls_sessionTicket:depends("stream_security", "tls")
|
||||
|
||||
-- [[ Trojan TLS ]]--
|
||||
|
||||
trojan_force_fp = s:option(ListValue, "fingerprint", translate("Finger Print"))
|
||||
for a, t in ipairs(force_fp) do trojan_force_fp:value(t) end
|
||||
trojan_force_fp.default = "firefox"
|
||||
@ -348,13 +333,11 @@ trojan_force_fp:depends({ type = "Trojan-Go", stream_security = "tls" })
|
||||
tls_serverName = s:option(Value, "tls_serverName", translate("Domain"))
|
||||
tls_serverName:depends("stream_security", "tls")
|
||||
|
||||
tls_allowInsecure = s:option(Flag, "tls_allowInsecure", translate("allowInsecure"), translate(
|
||||
"Whether unsafe connections are allowed. When checked, V2Ray does not check the validity of the TLS certificate provided by the remote host."))
|
||||
tls_allowInsecure = s:option(Flag, "tls_allowInsecure", translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, V2Ray does not check the validity of the TLS certificate provided by the remote host."))
|
||||
tls_allowInsecure.default = "0"
|
||||
tls_allowInsecure:depends("stream_security", "tls")
|
||||
|
||||
-- [[ Trojan Cert ]]--
|
||||
|
||||
trojan_cert_path = s:option(Value, "trojan_cert_path", translate("Trojan Cert Path"))
|
||||
trojan_cert_path.default = ""
|
||||
trojan_cert_path:depends({ stream_security = "tls", tls_allowInsecure = false })
|
||||
@ -397,12 +380,13 @@ transport:value("h2", "HTTP/2")
|
||||
transport:value("ds", "DomainSocket")
|
||||
transport:value("quic", "QUIC")
|
||||
transport:depends("protocol", "vmess")
|
||||
transport:depends("protocol", "socks")
|
||||
transport:depends("protocol", "shadowsocks")
|
||||
|
||||
--[[
|
||||
ss_transport = s:option(ListValue, "ss_transport", translate("Transport"))
|
||||
ss_transport:value("ws", "WebSocket")
|
||||
ss_transport:value("h2", "HTTP/2")
|
||||
ss_transport:value("ws", "WebSocket")
|
||||
ss_transport:value("h2+ws", "HTTP/2 & WebSocket")
|
||||
ss_transport:depends("protocol", "shadowsocks")
|
||||
]]--
|
||||
@ -410,27 +394,22 @@ ss_transport:depends("protocol", "shadowsocks")
|
||||
-- [[ TCP部分 ]]--
|
||||
|
||||
-- TCP伪装
|
||||
tcp_guise = s:option(ListValue, "tcp_guise",
|
||||
translate("Camouflage Type"))
|
||||
tcp_guise = s:option(ListValue, "tcp_guise", translate("Camouflage Type"))
|
||||
tcp_guise:value("none", "none")
|
||||
tcp_guise:value("http", "http")
|
||||
tcp_guise:depends("transport", "tcp")
|
||||
|
||||
-- HTTP域名
|
||||
tcp_guise_http_host = s:option(DynamicList, "tcp_guise_http_host",
|
||||
translate("HTTP Host"))
|
||||
tcp_guise_http_host = s:option(DynamicList, "tcp_guise_http_host", translate("HTTP Host"))
|
||||
tcp_guise_http_host:depends("tcp_guise", "http")
|
||||
|
||||
-- HTTP路径
|
||||
tcp_guise_http_path = s:option(DynamicList, "tcp_guise_http_path",
|
||||
translate("HTTP Path"))
|
||||
tcp_guise_http_path = s:option(DynamicList, "tcp_guise_http_path", translate("HTTP Path"))
|
||||
tcp_guise_http_path:depends("tcp_guise", "http")
|
||||
|
||||
-- [[ mKCP部分 ]]--
|
||||
|
||||
mkcp_guise = s:option(ListValue, "mkcp_guise",
|
||||
translate("Camouflage Type"), translate(
|
||||
'<br />none: default, no masquerade, data sent is packets with no characteristics.<br />srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).<br />utp: packets disguised as uTP will be recognized as bittorrent downloaded data.<br />wechat-video: packets disguised as WeChat video calls.<br />dtls: disguised as DTLS 1.2 packet.<br />wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)'))
|
||||
mkcp_guise = s:option(ListValue, "mkcp_guise", translate("Camouflage Type"), translate('<br />none: default, no masquerade, data sent is packets with no characteristics.<br />srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).<br />utp: packets disguised as uTP will be recognized as bittorrent downloaded data.<br />wechat-video: packets disguised as WeChat video calls.<br />dtls: disguised as DTLS 1.2 packet.<br />wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)'))
|
||||
for a, t in ipairs(header_type_list) do mkcp_guise:value(t) end
|
||||
mkcp_guise:depends("transport", "mkcp")
|
||||
|
||||
@ -440,28 +419,22 @@ mkcp_mtu:depends("transport", "mkcp")
|
||||
mkcp_tti = s:option(Value, "mkcp_tti", translate("KCP TTI"))
|
||||
mkcp_tti:depends("transport", "mkcp")
|
||||
|
||||
mkcp_uplinkCapacity = s:option(Value, "mkcp_uplinkCapacity",
|
||||
translate("KCP uplinkCapacity"))
|
||||
mkcp_uplinkCapacity = s:option(Value, "mkcp_uplinkCapacity", translate("KCP uplinkCapacity"))
|
||||
mkcp_uplinkCapacity:depends("transport", "mkcp")
|
||||
|
||||
mkcp_downlinkCapacity = s:option(Value, "mkcp_downlinkCapacity",
|
||||
translate("KCP downlinkCapacity"))
|
||||
mkcp_downlinkCapacity = s:option(Value, "mkcp_downlinkCapacity", translate("KCP downlinkCapacity"))
|
||||
mkcp_downlinkCapacity:depends("transport", "mkcp")
|
||||
|
||||
mkcp_congestion = s:option(Flag, "mkcp_congestion",
|
||||
translate("KCP Congestion"))
|
||||
mkcp_congestion = s:option(Flag, "mkcp_congestion", translate("KCP Congestion"))
|
||||
mkcp_congestion:depends("transport", "mkcp")
|
||||
|
||||
mkcp_readBufferSize = s:option(Value, "mkcp_readBufferSize",
|
||||
translate("KCP readBufferSize"))
|
||||
mkcp_readBufferSize = s:option(Value, "mkcp_readBufferSize", translate("KCP readBufferSize"))
|
||||
mkcp_readBufferSize:depends("transport", "mkcp")
|
||||
|
||||
mkcp_writeBufferSize = s:option(Value, "mkcp_writeBufferSize",
|
||||
translate("KCP writeBufferSize"))
|
||||
mkcp_writeBufferSize = s:option(Value, "mkcp_writeBufferSize", translate("KCP writeBufferSize"))
|
||||
mkcp_writeBufferSize:depends("transport", "mkcp")
|
||||
|
||||
-- [[ WebSocket部分 ]]--
|
||||
|
||||
ws_host = s:option(Value, "ws_host", translate("WebSocket Host"))
|
||||
ws_host:depends("transport", "ws")
|
||||
ws_host:depends("ss_transport", "ws")
|
||||
@ -475,7 +448,6 @@ ws_path:depends("trojan_transport", "h2+ws")
|
||||
ws_path:depends("trojan_transport", "ws")
|
||||
|
||||
-- [[ HTTP/2部分 ]]--
|
||||
|
||||
h2_host = s:option(Value, "h2_host", translate("HTTP/2 Host"))
|
||||
h2_host:depends("transport", "h2")
|
||||
h2_host:depends("ss_transport", "h2")
|
||||
@ -489,30 +461,24 @@ h2_path:depends("trojan_transport", "h2+ws")
|
||||
h2_path:depends("trojan_transport", "h2")
|
||||
|
||||
-- [[ DomainSocket部分 ]]--
|
||||
|
||||
ds_path = s:option(Value, "ds_path", "Path", translate(
|
||||
"A legal file path. This file must not exist before running V2Ray."))
|
||||
ds_path = s:option(Value, "ds_path", "Path", translate("A legal file path. This file must not exist before running V2Ray."))
|
||||
ds_path:depends("transport", "ds")
|
||||
|
||||
-- [[ QUIC部分 ]]--
|
||||
quic_security = s:option(ListValue, "quic_security",
|
||||
translate("Encrypt Method"))
|
||||
quic_security = s:option(ListValue, "quic_security", translate("Encrypt Method"))
|
||||
quic_security:value("none")
|
||||
quic_security:value("aes-128-gcm")
|
||||
quic_security:value("chacha20-poly1305")
|
||||
quic_security:depends("transport", "quic")
|
||||
|
||||
quic_key = s:option(Value, "quic_key",
|
||||
translate("Encrypt Method") .. translate("Key"))
|
||||
quic_key = s:option(Value, "quic_key", translate("Encrypt Method") .. translate("Key"))
|
||||
quic_key:depends("transport", "quic")
|
||||
|
||||
quic_guise = s:option(ListValue, "quic_guise",
|
||||
translate("Camouflage Type"))
|
||||
quic_guise = s:option(ListValue, "quic_guise", translate("Camouflage Type"))
|
||||
for a, t in ipairs(header_type_list) do quic_guise:value(t) end
|
||||
quic_guise:depends("transport", "quic")
|
||||
|
||||
-- [[ Trojan-Go Shadowsocks2 ]] --
|
||||
|
||||
ss_aead = s:option(Flag, "ss_aead", translate("Shadowsocks2"))
|
||||
ss_aead:depends("type", "Trojan-Go")
|
||||
ss_aead.default = "0"
|
||||
@ -540,33 +506,24 @@ mux_concurrency:depends("mux", "1")
|
||||
|
||||
-- [[ 当作为TCP节点时,是否同时开启socks代理 ]]--
|
||||
--[[
|
||||
tcp_socks = s:option(Flag, "tcp_socks", translate("TCP Open Socks"),
|
||||
translate(
|
||||
"When using this TCP node, whether to open the socks proxy at the same time"))
|
||||
tcp_socks = s:option(Flag, "tcp_socks", translate("TCP Open Socks"), translate("When using this TCP node, whether to open the socks proxy at the same time"))
|
||||
tcp_socks.default = 0
|
||||
tcp_socks:depends("type", "V2ray")
|
||||
|
||||
tcp_socks_port = s:option(Value, "tcp_socks_port",
|
||||
"Socks " .. translate("Port"),
|
||||
translate("Do not conflict with other ports"))
|
||||
tcp_socks_port = s:option(Value, "tcp_socks_port", "Socks " .. translate("Port"), translate("Do not conflict with other ports"))
|
||||
tcp_socks_port.datatype = "port"
|
||||
tcp_socks_port.default = 1080
|
||||
tcp_socks_port:depends("tcp_socks", "1")
|
||||
|
||||
tcp_socks_auth = s:option(ListValue, "tcp_socks_auth",
|
||||
translate("Socks for authentication"),
|
||||
translate(
|
||||
'Socks protocol authentication, support anonymous and password.'))
|
||||
tcp_socks_auth = s:option(ListValue, "tcp_socks_auth", translate("Socks for authentication"), translate('Socks protocol authentication, support anonymous and password.'))
|
||||
tcp_socks_auth:value("noauth", translate("anonymous"))
|
||||
tcp_socks_auth:value("password", translate("User Password"))
|
||||
tcp_socks_auth:depends("tcp_socks", "1")
|
||||
|
||||
tcp_socks_auth_username = s:option(Value, "tcp_socks_auth_username",
|
||||
"Socks " .. translate("Username"))
|
||||
tcp_socks_auth_username = s:option(Value, "tcp_socks_auth_username", "Socks " .. translate("Username"))
|
||||
tcp_socks_auth_username:depends("tcp_socks_auth", "password")
|
||||
|
||||
tcp_socks_auth_password = s:option(Value, "tcp_socks_auth_password",
|
||||
"Socks " .. translate("Password"))
|
||||
tcp_socks_auth_password = s:option(Value, "tcp_socks_auth_password", "Socks " .. translate("Password"))
|
||||
tcp_socks_auth_password:depends("tcp_socks_auth", "password")
|
||||
--]]
|
||||
|
||||
|
||||
@ -30,11 +30,6 @@ function gen_config(user)
|
||||
udp_timeout = 60,
|
||||
disable_http_check = true,
|
||||
tcp = {
|
||||
mux = (user.mux == "1") and {
|
||||
enabled = true,
|
||||
concurrency = tonumber(user.mux_concurrency),
|
||||
idle_timeout = 60,
|
||||
} or nil,
|
||||
transport_plugin = user.stream_security == "none" and user.trojan_transport == "original" and {
|
||||
enabled = user.plugin_type ~= nil,
|
||||
type = user.plugin_type or "plaintext",
|
||||
|
||||
@ -14,7 +14,7 @@ function gen_config(user)
|
||||
for i = 1, #user.vmess_id do
|
||||
clients[i] = {
|
||||
id = user.vmess_id[i],
|
||||
level = tonumber(user.vmess_level),
|
||||
level = tonumber(user.level),
|
||||
alterId = tonumber(user.alter_id)
|
||||
}
|
||||
end
|
||||
@ -42,12 +42,21 @@ function gen_config(user)
|
||||
}
|
||||
elseif user.protocol == "shadowsocks" then
|
||||
settings = {
|
||||
method = user.ss_encrypt_method,
|
||||
method = user.v_ss_encrypt_method,
|
||||
password = user.password,
|
||||
level = tonumber(user.vmess_level) or 1,
|
||||
level = tonumber(user.level) or 1,
|
||||
network = user.ss_network or "TCP,UDP",
|
||||
ota = (user.ss_ota == '1') and true or false
|
||||
}
|
||||
elseif user.protocol == "mtproto" then
|
||||
settings = {
|
||||
users = {
|
||||
{
|
||||
level = tonumber(user.level) or 1,
|
||||
secret = (user.password == nil) and "" or user.password
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
if user.accept_lan == nil or user.accept_lan == "0" then
|
||||
@ -74,7 +83,7 @@ function gen_config(user)
|
||||
concurrency = (node.mux_concurrency) and tonumber(node.mux_concurrency) or 8
|
||||
},
|
||||
-- 底层传输配置
|
||||
streamSettings = (node.protocol == "vmess") and {
|
||||
streamSettings = {
|
||||
network = node.transport,
|
||||
security = node.stream_security,
|
||||
tlsSettings = (node.stream_security == "tls") and {
|
||||
@ -122,7 +131,7 @@ function gen_config(user)
|
||||
key = node.quic_key,
|
||||
header = {type = node.quic_guise}
|
||||
} or nil
|
||||
} or nil,
|
||||
},
|
||||
settings = {
|
||||
vnext = (node.protocol == "vmess") and {
|
||||
{
|
||||
@ -132,7 +141,7 @@ function gen_config(user)
|
||||
{
|
||||
id = node.vmess_id,
|
||||
alterId = tonumber(node.alter_id),
|
||||
level = tonumber(node.vmess_level),
|
||||
level = tonumber(node.level),
|
||||
security = node.security
|
||||
}
|
||||
}
|
||||
@ -162,7 +171,7 @@ function gen_config(user)
|
||||
|
||||
local config = {
|
||||
log = {
|
||||
-- error = "/var/log/v2ray.log",
|
||||
-- error = "/var/etc/passwall_server/log/" .. user[".name"] .. ".log",
|
||||
loglevel = "warning"
|
||||
},
|
||||
-- 传入连接
|
||||
@ -171,14 +180,12 @@ function gen_config(user)
|
||||
listen = (user.bind_local == "1") and "127.0.0.1" or nil,
|
||||
port = tonumber(user.port),
|
||||
protocol = user.protocol,
|
||||
-- 底层传输配置
|
||||
settings = settings,
|
||||
streamSettings = (user.protocol == "vmess") and {
|
||||
streamSettings = {
|
||||
network = user.transport,
|
||||
security = (user.stream_security == 'tls') and "tls" or "none",
|
||||
tlsSettings = (user.stream_security == 'tls') and {
|
||||
disableSessionResumption = user.sessionTicket ~= "1" and true or false,
|
||||
-- serverName = (user.tls_serverName),
|
||||
allowInsecure = false,
|
||||
disableSystemRoot = false,
|
||||
certificates = {
|
||||
@ -209,22 +216,22 @@ function gen_config(user)
|
||||
writeBufferSize = tonumber(user.mkcp_writeBufferSize),
|
||||
header = {type = user.mkcp_guise}
|
||||
} or nil,
|
||||
wsSettings = (user.transport == "ws") and
|
||||
{
|
||||
headers = (user.ws_host) and {Host = user.ws_host} or
|
||||
nil,
|
||||
path = user.ws_path
|
||||
} or nil,
|
||||
httpSettings = (user.transport == "h2") and
|
||||
{path = user.h2_path, host = user.h2_host} or nil,
|
||||
dsSettings = (user.transport == "ds") and
|
||||
{path = user.ds_path} or nil,
|
||||
wsSettings = (user.transport == "ws") and {
|
||||
headers = (user.ws_host) and {Host = user.ws_host} or nil,
|
||||
path = user.ws_path
|
||||
} or nil,
|
||||
httpSettings = (user.transport == "h2") and {
|
||||
path = user.h2_path, host = user.h2_host
|
||||
} or nil,
|
||||
dsSettings = (user.transport == "ds") and {
|
||||
path = user.ds_path
|
||||
} or nil,
|
||||
quicSettings = (user.transport == "quic") and {
|
||||
security = user.quic_security,
|
||||
key = user.quic_key,
|
||||
header = {type = user.quic_guise}
|
||||
} or nil
|
||||
} or nil
|
||||
}
|
||||
}
|
||||
},
|
||||
-- 传出连接
|
||||
|
||||
@ -82,17 +82,17 @@ if is_installed("trojan-go") or is_finded("trojan-go") then
|
||||
end
|
||||
|
||||
protocol = s:option(ListValue, "protocol", translate("Protocol"))
|
||||
protocol:value("vmess", translate("Vmess"))
|
||||
protocol:value("http", translate("HTTP"))
|
||||
protocol:value("socks", translate("Socks"))
|
||||
protocol:value("shadowsocks", translate("Shadowsocks"))
|
||||
protocol:value("vmess", "Vmess")
|
||||
protocol:value("http", "HTTP")
|
||||
protocol:value("socks", "Socks")
|
||||
protocol:value("shadowsocks", "Shadowsocks")
|
||||
protocol:value("mtproto", "MTProto")
|
||||
protocol:depends("type", "V2ray")
|
||||
|
||||
-- Brook协议
|
||||
brook_protocol = s:option(ListValue, "brook_protocol",
|
||||
translate("Brook Protocol"))
|
||||
brook_protocol:value("server", translate("Brook"))
|
||||
brook_protocol:value("wsserver", translate("WebSocket"))
|
||||
brook_protocol = s:option(ListValue, "brook_protocol", translate("Brook Protocol"))
|
||||
brook_protocol:value("server", "Brook")
|
||||
brook_protocol:value("wsserver", "WebSocket")
|
||||
brook_protocol:depends("type", "Brook")
|
||||
|
||||
brook_tls = s:option(Flag, "brook_tls", translate("Use TLS"))
|
||||
@ -101,14 +101,6 @@ brook_tls:depends("brook_protocol", "wsserver")
|
||||
port = s:option(Value, "port", translate("Port"))
|
||||
port.datatype = "port"
|
||||
port.rmempty = false
|
||||
port:depends("type", "SSR")
|
||||
port:depends({ type = "V2ray", protocol = "vmess" })
|
||||
port:depends({ type = "V2ray", protocol = "http" })
|
||||
port:depends({ type = "V2ray", protocol = "socks" })
|
||||
port:depends({ type = "V2ray", protocol = "shadowsocks" })
|
||||
port:depends("type", "Brook")
|
||||
port:depends("type", "Trojan")
|
||||
port:depends("type", "Trojan-Go")
|
||||
|
||||
username = s:option(Value, "username", translate("Username"))
|
||||
username:depends("protocol", "http")
|
||||
@ -123,6 +115,7 @@ password:depends("type", "Trojan-Go")
|
||||
password:depends({ type = "V2ray", protocol = "http" })
|
||||
password:depends({ type = "V2ray", protocol = "socks" })
|
||||
password:depends({ type = "V2ray", protocol = "shadowsocks" })
|
||||
password:depends({ type = "V2ray", protocol = "mtproto" })
|
||||
|
||||
ssr_encrypt_method = s:option(ListValue, "ssr_encrypt_method", translate("Encrypt Method"))
|
||||
for a, t in ipairs(ssr_encrypt_method_list) do ssr_encrypt_method:value(t) end
|
||||
@ -185,21 +178,20 @@ alter_id = s:option(Value, "alter_id", translate("Alter ID"))
|
||||
alter_id.default = 16
|
||||
alter_id:depends({ type = "V2ray", protocol = "vmess" })
|
||||
|
||||
vmess_level = s:option(Value, "vmess_level", translate("User Level"))
|
||||
vmess_level.default = 1
|
||||
vmess_level:depends({ type = "V2ray", protocol = "vmess" })
|
||||
vmess_level:depends({ type = "V2ray", protocol = "shadowsocks" })
|
||||
level = s:option(Value, "level", translate("User Level"))
|
||||
level.default = 1
|
||||
level:depends({ type = "V2ray", protocol = "vmess" })
|
||||
level:depends({ type = "V2ray", protocol = "shadowsocks" })
|
||||
level:depends({ type = "V2ray", protocol = "mtproto" })
|
||||
|
||||
stream_security = s:option(ListValue, "stream_security",
|
||||
translate("Transport Layer Encryption"),
|
||||
translate(
|
||||
'Whether or not transport layer encryption is enabled, the supported options are "none" for unencrypted (default) and "TLS" for using TLS.'))
|
||||
stream_security = s:option(ListValue, "stream_security", translate("Transport Layer Encryption"), translate('Whether or not transport layer encryption is enabled, the supported options are "none" for unencrypted (default) and "TLS" for using TLS.'))
|
||||
stream_security:value("none", "none")
|
||||
stream_security:value("tls", "tls")
|
||||
stream_security.default = "tls"
|
||||
stream_security:depends({ type = "V2ray", protocol = "vmess", transport = "ws" })
|
||||
stream_security:depends({ type = "V2ray", protocol = "vmess", transport = "h2" })
|
||||
stream_security:depends("protocol", "shadowsocks")
|
||||
stream_security:depends({ type = "V2ray", protocol = "socks" })
|
||||
stream_security:depends({ type = "V2ray", protocol = "shadowsocks" })
|
||||
stream_security:depends("type", "Trojan-Go")
|
||||
|
||||
-- [[ TLS部分 ]] --
|
||||
@ -221,7 +213,9 @@ transport:value("ws", "WebSocket")
|
||||
transport:value("h2", "HTTP/2")
|
||||
transport:value("ds", "DomainSocket")
|
||||
transport:value("quic", "QUIC")
|
||||
transport:depends("protocol", "vmess")
|
||||
stream_security:depends({ type = "V2ray", protocol = "vmess" })
|
||||
stream_security:depends({ type = "V2ray", protocol = "socks" })
|
||||
stream_security:depends({ type = "V2ray", protocol = "shadowsocks" })
|
||||
|
||||
trojan_transport = s:option(ListValue, "trojan_transport", translate("Transport"))
|
||||
trojan_transport:value("original", "Original")
|
||||
@ -343,7 +337,7 @@ quic_guise = s:option(ListValue, "quic_guise", translate("Camouflage Type"))
|
||||
for a, t in ipairs(header_type_list) do quic_guise:value(t) end
|
||||
quic_guise:depends("transport", "quic")
|
||||
|
||||
remote_enable = s:option(Flag, "remote_enable", translate("Enable Remote"),translate("You can forward to Nginx/Caddy/V2ray WebSocket and more."))
|
||||
remote_enable = s:option(Flag, "remote_enable", translate("Enable Remote"), translate("You can forward to Nginx/Caddy/V2ray WebSocket and more."))
|
||||
remote_enable.default = "1"
|
||||
remote_enable.rmempty = false
|
||||
remote_enable:depends("type", "Trojan")
|
||||
@ -372,14 +366,6 @@ ss_aead_pwd.password = true
|
||||
ss_aead_pwd.rmempty = false
|
||||
ss_aead_pwd:depends("ss_aead", "1")
|
||||
|
||||
-- [[ Mux ]]--
|
||||
mux = s:option(Flag, "mux", translate("Mux"))
|
||||
|
||||
mux_concurrency = s:option(Value, "mux_concurrency",
|
||||
translate("Mux Concurrency"))
|
||||
mux_concurrency.default = 8
|
||||
mux_concurrency:depends("mux", "1")
|
||||
|
||||
local nodes_table = {}
|
||||
uci:foreach("passwall", "nodes", function(e)
|
||||
if e.type and e.type == "V2ray" and e.remarks and e.address and e.port then
|
||||
|
||||
@ -23,6 +23,41 @@ local dsp = require "luci.dispatcher"
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
function link_clear_temp() {
|
||||
if (confirm('<%:Are you sure to clear all cached links?%>') == true){
|
||||
XHR.get('<%=dsp.build_url("admin/vpn/passwall/link_clear_temp")%>', null,
|
||||
function(x, data) {
|
||||
if(x && x.status == 200) {
|
||||
window.location.href = '<%=dsp.build_url("admin/vpn/passwall/node_list")%>';
|
||||
}
|
||||
else {
|
||||
alert("<%:Error%>");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function link_load_temp() {
|
||||
var inputer = document.getElementById("nodes_link");
|
||||
XHR.get('<%=dsp.build_url("admin/vpn/passwall/link_load_temp")%>', null,
|
||||
function(x, data) {
|
||||
if(x.readyState === 4 && x.status === 200) {
|
||||
try {
|
||||
res = JSON.parse(x.responseText);
|
||||
}
|
||||
catch(e) {
|
||||
res = null;
|
||||
}
|
||||
if(res !== null && typeof(res) === "object") {
|
||||
alert(res.counter);
|
||||
if(res.data) inputer.value = res.data;
|
||||
}
|
||||
} else {
|
||||
alert("<%:Error%>");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function ajax_add_node(link) {
|
||||
if (link) {
|
||||
XHR.get('<%=dsp.build_url("admin/vpn/passwall/link_add_node")%>', {
|
||||
@ -51,7 +86,7 @@ local dsp = require "luci.dispatcher"
|
||||
function add_node() {
|
||||
var nodes_link = document.getElementById("nodes_link").value;
|
||||
if (nodes_link.trim() != "") {
|
||||
if (nodes_link.indexOf("ss://") == 0 || nodes_link.indexOf("ssr://") == 0 || nodes_link.indexOf("vmess://") == 0 || nodes_link.indexOf("trojan://") == 0) {
|
||||
if (nodes_link.indexOf("ss://") == 0 || nodes_link.indexOf("ssr://") == 0 || nodes_link.indexOf("vmess://") == 0 || nodes_link.indexOf("trojan://") == 0 || nodes_link.indexOf("trojan-go://") == 0) {
|
||||
ajax_add_node(nodes_link);
|
||||
}
|
||||
else {
|
||||
@ -88,9 +123,10 @@ local dsp = require "luci.dispatcher"
|
||||
</div>
|
||||
</div>
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"></label>
|
||||
<div class="cbi-value-field">
|
||||
<input class="cbi-button cbi-button-add" type="button" onclick="add_node()" value="<%:Add%>" />
|
||||
<input class="cbi-button cbi-button-apply" type="button" onclick="link_load_temp()" value="<%:Load %><%:Cached%>" />
|
||||
<input class="cbi-button cbi-button-refresh" type="button" onclick="link_clear_temp()" value="<%:Clear %><%:Cached%>" />
|
||||
<input class="cbi-button cbi-button-remove" type="button" onclick="close_add_link_div()" value="<%:Close%>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,604 @@
|
||||
<%+cbi/valueheader%>
|
||||
<%
|
||||
local dsp = require "luci.dispatcher"
|
||||
-%>
|
||||
<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 parseNodeUrl(url) {
|
||||
var m = url.match(/^(([^:\/?#]+:)?(?:\/\/((?:([^\/?#:]*)([^\/?#:]*)@)?([^\/?#:]*)(?::([^\/?#:]*))?)))?([^?#]*)(\?[^#]*)?(#.*)?$/),
|
||||
r = {
|
||||
hash: m[10] || "", // #asd
|
||||
host: m[3] || "", // localhost:257
|
||||
hostname: m[6] || "", // localhost
|
||||
href: m[0] || "", // http://username:password@localhost:257/deploy/?asd=asd#asd
|
||||
origin: m[1] || "", // http://username:password@localhost:257
|
||||
pathname: m[8] || (m[1] ? "/" : ""), // /deploy/
|
||||
port: m[7] || "", // 257
|
||||
protocol: m[2] || "", // http:
|
||||
search: m[9] || "", // ?asd=asd
|
||||
passwd: m[4] || "", // username
|
||||
removed: m[5] || "" // password
|
||||
};
|
||||
if (r.protocol.length === 2) {
|
||||
r.protocol = "file:///" + r.protocol.toUpperCase();
|
||||
r.origin = r.protocol + "//" + r.host;
|
||||
}
|
||||
r.href = r.origin + r.pathname + r.search + r.hash;
|
||||
return m && r;
|
||||
}
|
||||
|
||||
function link_append_temp(link) {
|
||||
XHR.get('<%=dsp.build_url("admin/vpn/passwall/link_append_temp")%>', {
|
||||
'link': link
|
||||
},
|
||||
function(x, data) {
|
||||
if(x.readyState === 4 && x.status === 200) {
|
||||
try {
|
||||
res = JSON.parse(x.responseText);
|
||||
}
|
||||
catch(e) {
|
||||
res = null;
|
||||
}
|
||||
if(res !== null && typeof(res) === "object") {
|
||||
alert(res.counter);
|
||||
}
|
||||
} else {
|
||||
alert("<%:Error%>");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function buildUrl(btn, urlname, sid) {
|
||||
var opt = {
|
||||
base: "cbid.passwall",
|
||||
fallback: "dummy",
|
||||
get: function(opt) {
|
||||
var id = this.base + "." + opt;
|
||||
var obj = document.getElementsByName(id) || document.getElementById(id);
|
||||
if (obj) {
|
||||
if (obj.length === 1) obj = obj[0];
|
||||
return obj;
|
||||
} else {
|
||||
alert("<%:Faltal on get option, please help in debug: %>" + opt);
|
||||
return document.getElementById(this.fallback);
|
||||
}
|
||||
},
|
||||
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, tval = "1", fval = "0") {
|
||||
var ret = "&" + param + "=";
|
||||
var obj = this.get(src);
|
||||
if (obj) {
|
||||
if (obj.type === "checkbox") {
|
||||
return ret + (obj.checked === true ? tval : fval);
|
||||
} else {
|
||||
return ret + encodeURIComponent(obj.value);
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
var s = document.getElementById(urlname + "-status");
|
||||
if (!s) {
|
||||
alert("Never");
|
||||
return false;
|
||||
}
|
||||
opt.base = "cbid.passwall." + sid;
|
||||
opt.fallback = urlname + "-dummy";
|
||||
var v_type = opt.get("type").value;
|
||||
var v_alias = opt.get("remarks");
|
||||
var url = null;
|
||||
if (v_type === "SSR") {
|
||||
var v_server = opt.get("address");
|
||||
var v_port = opt.get("port");
|
||||
var v_protocol = opt.get("ssr_protocol");
|
||||
var v_method = opt.get("ssr_encrypt_method");
|
||||
var v_obfs = opt.get("obfs");
|
||||
var v_password = opt.get("password");
|
||||
var v_obfs_param = opt.get("obfs_param");
|
||||
var v_protocol_param = opt.get("protocol_param");
|
||||
var ssr_str = v_server.value + ":" +
|
||||
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 === "Trojan" || v_type === "Trojan-Go") {
|
||||
var v_password = opt.get("password");
|
||||
var v_server = opt.get("address");
|
||||
var v_port = opt.get("port");
|
||||
url = encodeURIComponent(v_password.value) +
|
||||
"@" + v_server.value +
|
||||
":" + v_port.value + "/?";
|
||||
if (opt.get("stream_security").value === "tls") {
|
||||
url += "tls=1";
|
||||
url += opt.query("sni", "tls_serverName");
|
||||
url += opt.query("allowinsecure", "tls_allowInsecure");
|
||||
} else if (v_type === "Trojan-Go") {
|
||||
url += "tls=0";
|
||||
}
|
||||
if (v_type === "Trojan-Go") {
|
||||
if (opt.get("stream_security").value === "none" && opt.get("trojan_transport").value === "original") {
|
||||
var plugin = {};
|
||||
plugin.type = opt.get("plugin_type").value;
|
||||
if (plugin.type !== "plaintext") {
|
||||
plugin.command = opt.get("plugin_cmd").value;
|
||||
plugin.option = opt.get("plugin_option").value;
|
||||
plugin.arg = opt.getlist("plugin_arg");
|
||||
}
|
||||
url += "&plugin=" + encodeURIComponent(JSON.stringify(plugin));
|
||||
}
|
||||
url += opt.query("type", "trojan_transport");
|
||||
var ws = (opt.get("trojan_transport").value.indexOf("ws") !== -1);
|
||||
var h2 = (opt.get("trojan_transport").value.indexOf("h2") !== -1);
|
||||
if (ws) {
|
||||
url += opt.query("host", "ws_host");
|
||||
url += opt.query("path", "ws_path");
|
||||
} else if (h2) {
|
||||
url += opt.query("host", "h2_host");
|
||||
url += opt.query("path", "h2_path");
|
||||
}
|
||||
var enc = "none";
|
||||
if (opt.get("ss_aead").checked === true) {
|
||||
enc = "ss;" +
|
||||
opt.get("ss_aead_method").value +
|
||||
":" + opt.get("ss_aead_pwd").value;
|
||||
}
|
||||
url += "&encryption=" + encodeURIComponent(enc);
|
||||
url += opt.query("mux", "mux");
|
||||
}
|
||||
url += "#" + encodeURI(v_alias.value);
|
||||
}
|
||||
if (url) {
|
||||
url = v_type.toLowerCase() + "://" + url;
|
||||
link_append_temp(url);
|
||||
var textarea = document.createElement("textarea");
|
||||
textarea.textContent = url;
|
||||
textarea.style.position = "fixed";
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
try {
|
||||
document.execCommand("copy"); // Security exception may be thrown by some browsers.
|
||||
s.innerHTML = "<font color='green'><%:Share to clipboard successfully, copy to batch mode still: %></font>";
|
||||
} catch (ex) {
|
||||
s.innerHTML = "<font color='red'><%:Unable share to clipboard, copy to batch mode still: %></font>";
|
||||
} finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
} else {
|
||||
alert("<%:Not a supported scheme:%> " + v_type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function fromUrl(btn, urlname, sid) {
|
||||
var opt = {
|
||||
base: 'cbid.passwall',
|
||||
fallback: 'dummy',
|
||||
get: function(opt) {
|
||||
var obj;
|
||||
var id = this.base + '.' + opt;
|
||||
obj = document.getElementsByName(id)[0] || document.getElementById(id);
|
||||
if (obj) {
|
||||
return obj;
|
||||
} else {
|
||||
alert('<%:Faltal on get option, please help in debug: %>' + opt);
|
||||
return document.getElementById(this.fallback);
|
||||
}
|
||||
},
|
||||
set: function(opt, val) {
|
||||
var obj;
|
||||
obj = this.get(opt)
|
||||
if (obj) {
|
||||
if (obj.type === 'checkbox') {
|
||||
var event = document.createEvent("HTMLEvents");
|
||||
event.initEvent("change", true, true);
|
||||
obj.checked = val;
|
||||
obj.dispatchEvent(event);
|
||||
} else {
|
||||
obj.value = val;
|
||||
}
|
||||
} else {
|
||||
alert('<%:Faltal on set option, please help in debug: %>' + opt + ' = ' + val);
|
||||
}
|
||||
},
|
||||
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.passwall.' + sid
|
||||
opt.fallback = urlname + '-dummy';
|
||||
var ssrurl = prompt('<%:Paste Share URL Here%>', '');
|
||||
if (ssrurl === null || ssrurl === "") {
|
||||
s.innerHTML = "<font color='red'><%:User cancelled%></font>";
|
||||
return false;
|
||||
}
|
||||
s.innerHTML = "";
|
||||
var ssu = ssrurl.split('://');
|
||||
var event = document.createEvent("HTMLEvents");
|
||||
event.initEvent("change", true, true);
|
||||
if (ssu[0] === "ssr") {
|
||||
//var b64c = ssu[1].match(/([A-Za-z0-9_-]+)/);
|
||||
var sstr = b64decsafe(ssu[1]);
|
||||
var ploc = sstr.indexOf("/?");
|
||||
var url0 = "", param = "";
|
||||
if (ploc > 0) {
|
||||
url0 = sstr.substr(0, ploc);
|
||||
param = sstr.substr(ploc + 2);
|
||||
}
|
||||
console.log(param);
|
||||
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.get('type').dispatchEvent(event);
|
||||
opt.set('address', ssm[1]);
|
||||
opt.set('port', ssm[2]);
|
||||
opt.set('ssr_protocol', ssm[3]);
|
||||
opt.set('ssr_encrypt_method', ssm[4]);
|
||||
opt.set('obfs', ssm[5]);
|
||||
opt.set('password', b64decsafe(ssm[6]));
|
||||
opt.set('obfs_param', dictvalue(pdict, 'obfsparam'));
|
||||
opt.set('protocol_param', dictvalue(pdict, 'protoparam'));
|
||||
var rem = pdict['remarks'];
|
||||
if (typeof(rem) !== 'undefined' && rem !== '' && rem.length > 0)
|
||||
opt.set('remark', b64decutf8safe(rem));
|
||||
} else if (ssu[0] === "ss") {
|
||||
var url0 = "", param = "";
|
||||
var sipIndex = ssu[1].indexOf("@");
|
||||
var ploc = ssu[1].indexOf("#");
|
||||
if (ploc > 0) {
|
||||
url0 = ssu[1].substr(0, ploc);
|
||||
param = ssu[1].substr(ploc + 1);
|
||||
} else {
|
||||
url0 = ssu[1];
|
||||
}
|
||||
console.log(param);
|
||||
if (sipIndex !== -1) {
|
||||
// SIP002
|
||||
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, plugin, pluginOpts;
|
||||
if (temp[1]) {
|
||||
var pluginInfo = decodeURIComponent(temp[1]);
|
||||
var pluginIndex = pluginInfo.indexOf(";");
|
||||
var pluginNameInfo = pluginInfo.substr(0, pluginIndex);
|
||||
plugin = pluginNameInfo.substr(pluginNameInfo.indexOf("=") + 1)
|
||||
pluginOpts = pluginInfo.substr(pluginIndex + 1);
|
||||
}
|
||||
var userInfoSplitIndex = userInfo.indexOf(":");
|
||||
if (userInfoSplitIndex !== -1) {
|
||||
method = userInfo.substr(0, userInfoSplitIndex);
|
||||
password = userInfo.substr(userInfoSplitIndex + 1);
|
||||
}
|
||||
opt.set('type', "SS");
|
||||
opt.get('type').dispatchEvent(event);
|
||||
opt.set('address', server);
|
||||
opt.set('port', port);
|
||||
opt.set('password', password || "");
|
||||
opt.set('ss_encrypt_method', method || "");
|
||||
opt.set('ss_plugin', plugin || "");
|
||||
opt.set('ss_plugin_opts', pluginOpts || "");
|
||||
if (param !== undefined) {
|
||||
opt.set('remark', decodeURI(param));
|
||||
}
|
||||
} else {
|
||||
var sstr = b64decsafe(url0);
|
||||
var team = sstr.split('@');
|
||||
opt.set('type', "SS");
|
||||
opt.get('type').dispatchEvent(event);
|
||||
var part1 = team[0].split(':');
|
||||
var part2 = team[1].split(':');
|
||||
opt.set('address', part2[0]);
|
||||
opt.set('port', part2[1]);
|
||||
opt.set('password', part1[1]);
|
||||
opt.set('ss_encrypt_method', part1[0]);
|
||||
opt.set('ss_plugin', "");
|
||||
opt.set('ss_plugin_opts', "");
|
||||
if (param !== undefined) {
|
||||
opt.set('remark', decodeURI(param));
|
||||
}
|
||||
}
|
||||
} else if (ssu[0] === "trojan") {
|
||||
var stype = "Trojan";
|
||||
var m = parseNodeUrl(ssrurl);
|
||||
console.log(m.search);
|
||||
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.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] || '');
|
||||
}
|
||||
}
|
||||
if (queryParam.mux || queryParam.ws || queryParam.h2 || queryParam.ss || queryParam.plugin) {
|
||||
stype = "Trojan-Go";
|
||||
}
|
||||
opt.set('type', stype);
|
||||
opt.get('type').dispatchEvent(event);
|
||||
opt.set('address', m.hostname);
|
||||
opt.set('port', m.port || "443");
|
||||
opt.set('password', decodeURIComponent(password));
|
||||
var tls = true;
|
||||
if (stype === "Trojan-Go") {
|
||||
tls = queryParam.plugin === undefined;
|
||||
}
|
||||
if (tls === false) { alert("TODO: plugin params for trojan-go."); }
|
||||
opt.set('stream_security', tls ? "tls" : "none");
|
||||
opt.get('stream_security').dispatchEvent(event);
|
||||
if (tls) {
|
||||
opt.set('tls_serverName', queryParam.peer || queryParam.sni || '');
|
||||
opt.set('tls_allowInsecure', queryParam.allowinsecure === '1');
|
||||
}
|
||||
var tran = 'original';
|
||||
var ws = queryParam.type.indexOf('ws') !== -1;
|
||||
var h2 = queryParam.type.indexOf('h2') !== -1;
|
||||
if (ws && h2) {
|
||||
tran = 'h2+ws'
|
||||
} else {
|
||||
if (ws) tran = 'ws';
|
||||
if (h2) tran = 'h2';
|
||||
}
|
||||
opt.set('trojan_transport', 'tran');
|
||||
opt.get('trojan_transport').dispatchEvent(event);
|
||||
if (ws) {
|
||||
opt.set('ws_host', queryParam.wshost || '');
|
||||
opt.set('ws_path', queryParam.wspath || '/');
|
||||
}
|
||||
if (h2) {
|
||||
opt.set('h2_host', queryParam.h2host || '');
|
||||
opt.set('h2_path', queryParam.h2path || '/');
|
||||
}
|
||||
var ss = queryParam.ss === '1';
|
||||
opt.set('ss_aead', ss);
|
||||
if (ss) {
|
||||
opt.set('ss_aead_method', queryParam.ssmethod.toUpperCase() || '');
|
||||
opt.set('ss_aead_pwd', queryParam.sspasswd || '');
|
||||
}
|
||||
opt.set('mux', queryParam.mux === '1');
|
||||
if (m.hash) {
|
||||
opt.set('remark', decodeURI(m.hash.substr(1)));
|
||||
}
|
||||
} else if (ssu[0] === "trojan-go") {
|
||||
var m = parseNodeUrl(ssrurl);
|
||||
console.log(m.search);
|
||||
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.split('?');
|
||||
var queryParams = query[1];
|
||||
var queryArray = queryParams.split('&');
|
||||
for (i = 0; i < queryArray.length; i++) {
|
||||
var params = queryArray[i].split('=');
|
||||
queryParam[decodeURIComponent(params[0]).toLowerCase()] = decodeURIComponent(params[1] || '');
|
||||
}
|
||||
}
|
||||
opt.set('type', 'Trojan-Go');
|
||||
opt.get('type').dispatchEvent(event);
|
||||
opt.set('address', m.hostname);
|
||||
opt.set('port', m.port || "443");
|
||||
opt.set('password', decodeURIComponent(password));
|
||||
opt.set('stream_security', (queryParam.tls && queryParam.tls === '1') ? 'tls' : 'none');
|
||||
opt.get('stream_security').dispatchEvent(event);
|
||||
var plugin = queryParam.plugin !== undefined;
|
||||
if (plugin) {
|
||||
opt.set('trojan_transport', 'original');
|
||||
opt.get('trojan_transport').dispatchEvent(event);
|
||||
var plugin = JSON.parse(queryParam.plugin);
|
||||
if (plugin) {
|
||||
opt.set('plugin_type', plugin.type);
|
||||
opt.get('plugin_type').dispatchEvent(event);
|
||||
if (plugin.type !== "plaintext") {
|
||||
opt.set('plugin_cmd', plugin.command);
|
||||
opt.set('plugin_option', plugin.option);
|
||||
opt.setlist('plugin_arg', plugin.arg);
|
||||
}
|
||||
} else
|
||||
alert(queryParam.plugin);
|
||||
}
|
||||
var tls = !plugin && queryParam.tls === '1';
|
||||
opt.set('stream_security', tls ? "tls" : "none");
|
||||
opt.get('stream_security').dispatchEvent(event);
|
||||
if (tls) {
|
||||
opt.set('tls_serverName', queryParam.peer || queryParam.sni || '');
|
||||
opt.set('tls_allowInsecure', queryParam.allowinsecure === '1');
|
||||
}
|
||||
var tran = 'original';
|
||||
var or = queryParam.type === undefined || queryParam.type === 'original';
|
||||
var ws = queryParam.type.indexOf('ws') !== -1;
|
||||
var h2 = queryParam.type.indexOf('h2') !== -1;
|
||||
if (ws && h2) {
|
||||
tran = 'h2+ws'
|
||||
} else {
|
||||
if (ws) tran = 'ws';
|
||||
if (h2) tran = 'h2';
|
||||
}
|
||||
opt.set('trojan_transport', tran);
|
||||
opt.get('trojan_transport').dispatchEvent(event);
|
||||
if (ws) {
|
||||
opt.set('ws_host', queryParam.host || '');
|
||||
opt.set('ws_path', queryParam.path || '/');
|
||||
}
|
||||
if (h2){
|
||||
opt.set('h2_host', queryParam.host || '');
|
||||
opt.set('h2_path', queryParam.path || '/');
|
||||
}
|
||||
var enc = {};
|
||||
var ss = false;
|
||||
if (queryParam.encryption) {
|
||||
var r = queryParam.encryption.match(/^(ss);([^;:]*)[;:](.*)$/),
|
||||
enc = {type: r[1], method: r[2], password: r[3]};
|
||||
}
|
||||
ss = enc.type === 'ss';
|
||||
opt.set('ss_aead', ss);
|
||||
if (ss) {
|
||||
opt.set('ss_aead_method', enc.method.toUpperCase() || '');
|
||||
opt.set('ss_aead_pwd', enc.password || '');
|
||||
}
|
||||
opt.set('mux', queryParam.mux === '1');
|
||||
if (m.hash) {
|
||||
opt.set('remark', decodeURI(m.hash));
|
||||
}
|
||||
} else if (ssu[0] === "vmess") {
|
||||
var sstr = b64DecodeUnicode(ssu[1]);
|
||||
var ploc = sstr.indexOf("/?");
|
||||
opt.set('type', "V2ray");
|
||||
opt.get('type').dispatchEvent(event);
|
||||
var url0, param = "";
|
||||
if (ploc > 0) {
|
||||
url0 = sstr.substr(0, ploc);
|
||||
param = sstr.substr(ploc + 2);
|
||||
}
|
||||
var ssm = JSON.parse(sstr);
|
||||
opt.set('remark', ssm.ps);
|
||||
opt.set('address', ssm.add);
|
||||
opt.set('port', ssm.port);
|
||||
opt.set('alter_id', ssm.aid);
|
||||
opt.set('vmess_id', ssm.id);
|
||||
opt.set('stream_security', ssm.tls === "tls" ? "tls" : "none");
|
||||
opt.get('stream_security').dispatchEvent(event);
|
||||
if (ssm.tls === "tls") {
|
||||
opt.set('tls_serverName', ssm.host);
|
||||
}
|
||||
opt.set('transport', ssm.net);
|
||||
opt.get('transport').dispatchEvent(event);
|
||||
if (ssm.net === "tcp") {
|
||||
opt.set('tcp_guise', (ssm.host && ssm.path) ? "http" : "none");
|
||||
opt.get('tcp_guise').dispatchEvent(event);
|
||||
if (ssm.host && ssm.path) {
|
||||
opt.set('tcp_guise_http_host', ssm.host);
|
||||
opt.set('tcp_guise_http_path', ssm.path);
|
||||
}
|
||||
} else if (ssm.net === "ws") {
|
||||
opt.set('ws_host', ssm.host);
|
||||
opt.set('ws_path', ssm.path);
|
||||
} else if (ssm.net === "h2") {
|
||||
opt.set('h2_host', ssm.host);
|
||||
opt.set('h2_path', ssm.path);
|
||||
} else if (ssm.net === "quic") {
|
||||
opt.set('quic_security', ssm.securty);
|
||||
opt.set('quic_key', ssm.key);
|
||||
} else if (ssm.net === "kcp") {
|
||||
opt.set('mkcp_guise', ssm.type);
|
||||
opt.get('mkcp_guise').dispatchEvent(event);
|
||||
}
|
||||
} else {
|
||||
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>: " + ssu[0];
|
||||
return false;
|
||||
}
|
||||
s.innerHTML = "<font color='green'><%:Import Finished %></font>";
|
||||
return false;
|
||||
}
|
||||
|
||||
//]]></script>
|
||||
<input type="test" class="hidden" id='<%=self.option%>-dummy' value="-dummy-" />
|
||||
<input type="button" class="cbi-button cbi-button-apply" value='<%:From Share URL%>' onclick="return fromUrl(this, '<%=self.option%>', '<%=self.value%>')" />
|
||||
<input type="button" class="cbi-button cbi-button-apply" value='<%:Build Share URL%>' onclick="return buildUrl(this, '<%=self.option%>', '<%=self.value%>')" />
|
||||
<span id="<%=self.option%>-status"></span>
|
||||
<%+cbi/valuefooter%>
|
||||
@ -370,6 +370,42 @@ msgstr "负载均衡节点列表"
|
||||
msgid "Load balancing node list, <a target='_blank' href='https://toutyrater.github.io/routing/balance2.html'>document</a>"
|
||||
msgstr "负载均衡节点列表,<a target='_blank' href='https://toutyrater.github.io/routing/balance2.html'>文档原理</a>"
|
||||
|
||||
msgid "Share Current"
|
||||
msgstr "所见即所得"
|
||||
|
||||
msgid "From Share URL"
|
||||
msgstr "导入配置信息"
|
||||
|
||||
msgid "Build Share URL"
|
||||
msgstr "导出配置信息"
|
||||
|
||||
msgid "Import Finished"
|
||||
msgstr "导入完成:"
|
||||
|
||||
msgid "Not a supported scheme:"
|
||||
msgstr "不支持这种样式的:"
|
||||
|
||||
msgid "Invalid Share URL Format"
|
||||
msgstr "无效的分享信息"
|
||||
|
||||
msgid "User cancelled"
|
||||
msgstr "用户已取消"
|
||||
|
||||
msgid "Paste Share URL Here"
|
||||
msgstr "在此处粘贴分享信息"
|
||||
|
||||
msgid "Unable share to clipboard, copy to batch mode still:"
|
||||
msgstr "无法分享网址到剪贴板,复制到批量导入临时输入:"
|
||||
|
||||
msgid "Share to clipboard successfully, copy to batch mode still:"
|
||||
msgstr "成功复制分享网址到剪贴板和批量导入临时输入:"
|
||||
|
||||
msgid "Faltal on get option, please help in debug:"
|
||||
msgstr "代码错误,请协助捉虫:"
|
||||
|
||||
msgid "Faltal on set option, please help in debug:"
|
||||
msgstr "代码错误,请协助捉虫:"
|
||||
|
||||
msgid "Address"
|
||||
msgstr "地址"
|
||||
|
||||
@ -386,7 +422,7 @@ msgid "Finger Print"
|
||||
msgstr "指纹伪造"
|
||||
|
||||
msgid "Shadowsocks2"
|
||||
msgstr "双重加密"
|
||||
msgstr "二次加密"
|
||||
|
||||
msgid "Encrypt Method"
|
||||
msgstr "加密"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user