package lienol: merge upstream source

This commit is contained in:
CN_SZTL 2019-12-21 19:32:02 +08:00
parent 83fa37a1b2
commit 8c6da18b51
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
171 changed files with 23023 additions and 324 deletions

View File

@ -1,4 +1,4 @@
# Copyright (C) 2018-2019 Lienol
# Copyright (C) 2018-2020 Lienol <lawlienol@gmail.com>
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=3.0
PKG_RELEASE:=127-20191214
PKG_RELEASE:=135-20191220
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PO2LMO:=./po2lmo
@ -67,11 +67,7 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_pdnsd
config PACKAGE_$(PKG_NAME)_INCLUDE_dns2socks
bool "Include dns2socks"
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_dns-forwarder
bool "Include dns-forwarder"
default n
default y
endmenu
endef
@ -95,8 +91,7 @@ define Package/$(PKG_NAME)
+PACKAGE_$(PKG_NAME)_INCLUDE_haproxy:haproxy \
+PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS:openwrt_chinadns \
+PACKAGE_$(PKG_NAME)_INCLUDE_pdnsd:pdnsd-alt \
+PACKAGE_$(PKG_NAME)_INCLUDE_dns2socks:dns2socks \
+PACKAGE_$(PKG_NAME)_INCLUDE_dns-forwarder:dns-forwarder
+PACKAGE_$(PKG_NAME)_INCLUDE_dns2socks:dns2socks
endef
define Build/Prepare

View File

@ -1 +0,0 @@
本人十分喜欢lean源码但本插件并非魔改版SSR Plus不喜欢勿用

View File

@ -1,4 +1,4 @@
-- Copyright 2018-2019 Lienol <lawlienol@gmail.com>
-- Copyright 2018-2020 Lienol <lawlienol@gmail.com>
module("luci.controller.passwall", package.seeall)
local appname = "passwall"
local http = require "luci.http"
@ -52,6 +52,8 @@ function index()
true
entry({"admin", "vpn", "passwall", "auto_ping_node"}, call("auto_ping_node")).leaf =
true
entry({"admin", "vpn", "passwall", "auto_ping_node_list"},
call("auto_ping_node_list")).leaf = true
entry({"admin", "vpn", "passwall", "ping_node"}, call("ping_node")).leaf =
true
entry({"admin", "vpn", "passwall", "set_node"}, call("set_node")).leaf =
@ -188,7 +190,7 @@ function auto_ping_node()
appname) == "1" and
luci.sys.exec("echo -n `command -v tcping`") ~= "" then
e.ping = luci.sys.exec(
"echo -n `tcping -q -c 1 -i 3 -p " .. port .. " " ..
"echo -n `tcping -q -c 1 -i 1 -p " .. port .. " " ..
address ..
" 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print$2}'`")
else
@ -200,6 +202,33 @@ function auto_ping_node()
luci.http.write_json(e)
end
function auto_ping_node_list()
local e = {}
local json_str = luci.http.formvalue("json")
local json = luci.jsonc.parse(json_str)
local index = json["index"]
local address = json["address"]
local port = json["port"]
local obj = {}
obj.index = index
if luci.sys.exec("echo -n `uci -q get %s.@global_other[0].use_tcping`" %
appname) == "1" and
luci.sys.exec("echo -n `command -v tcping`") ~= "" then
obj.ping = luci.sys.exec("echo -n `tcping -q -c 1 -i 1 -p " .. port ..
" " .. address ..
" 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print$2}'`")
else
obj.ping = luci.sys.exec(
"echo -n `ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print$2}'`" %
address)
end
e = obj
luci.http.prepare_content("application/json")
luci.http.write_json(e)
end
function ping_node()
local e = {}
local address = luci.http.formvalue("address")
@ -208,7 +237,7 @@ function ping_node()
appname) == "1" and
luci.sys.exec("echo -n `command -v tcping`") ~= "" then
e.ping = luci.sys.exec(
"echo -n `tcping -q -c 1 -i 3 -p " .. port .. " " ..
"echo -n `tcping -q -c 1 -i 1 -p " .. port .. " " ..
address ..
" 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print$2}'`")
else
@ -221,26 +250,14 @@ function ping_node()
end
function set_node()
local e = {}
local protocol = luci.http.formvalue("protocol")
local number = luci.http.formvalue("number")
local section = luci.http.formvalue("section")
if protocol == "tcp" then
luci.sys.call("uci set passwall.@global[0].tcp_node" .. number .. "=" ..
section ..
" && uci commit passwall && /etc/init.d/passwall restart")
elseif protocol == "udp" then
luci.sys.call("uci set passwall.@global[0].udp_node" .. number .. "=" ..
section ..
" && uci commit passwall && /etc/init.d/passwall restart")
elseif protocol == "socks5" then
luci.sys.call(
"uci set passwall.@global[0].socks5_node" .. number .. "=" ..
section ..
" && uci commit passwall && /etc/init.d/passwall restart")
end
luci.http.prepare_content("application/json")
luci.http.write_json(e)
luci.sys.call("uci set passwall.@global[0]." .. protocol .. "_node" ..
number .. "=" .. section ..
" && uci commit passwall && /etc/init.d/passwall restart > /dev/null 2>&1 &")
luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", "passwall",
"log"))
end
function copy_node()

View File

@ -90,8 +90,8 @@ for i = 1, socks5_node_num, 1 do
end
---- DNS Forward Mode
o = s:option(ListValue, "dns_mode", translate("DNS Forward Mode"),
translate("if you use no patterns are used, DNS of wan will be used by default as upstream of dnsmasq"))
o = s:option(ListValue, "dns_mode", translate("DNS Forward Mode"), translate(
"if you use no patterns are used, DNS of wan will be used by default as upstream of dnsmasq"))
o.rmempty = false
o:reset_values()
if is_installed("openwrt_chinadns") or is_finded("chinadns") then
@ -100,27 +100,26 @@ end
if is_installed("dns2socks") or is_finded("dns2socks") then
o:value("dns2socks", "dns2socks " .. translate("Need Socks5 server"))
end
if is_installed("pcap-dnsproxy") or is_finded("Pcap_DNSProxy") then
o:value("Pcap_DNSProxy", "Pcap_DNSProxy")
end
if is_installed("pdnsd") or is_installed("pdnsd-alt") or is_finded("pdnsd") then
o:value("pdnsd", "pdnsd")
end
o:value("local_7913", translate("Use local port 7913 as DNS"))
o:value("nonuse", translate("No patterns are used"))
o = s:option(Value, "dns2socks_forward", translate("DNS Forward Address"))
o.default = "8.8.4.4"
o:value("8.8.4.4", "8.8.4.4(Google DNS1)")
o:value("8.8.8.8", "8.8.8.8(Google DNS2)")
o:value("208.67.222.222", "208.67.222.222(OpenDNS DNS1)")
o:value("208.67.220.220", "208.67.220.220(OpenDNS DNS2)")
o:depends("dns_mode", "dns2socks")
---- upstreamm DNS Server for ChinaDNS
o = s:option(ListValue, "up_chinadns_mode",
translate("upstreamm DNS Server for ChinaDNS"), translate(
"Domestic DNS server 1 in advanced Settings is used as domestic DNS by default"))
o.default = "OpenDNS_1"
o:depends("dns_mode", "chinadns")
if is_installed("dnsproxy") or is_finded("dnsproxy") then
o:value("dnsproxy", "dnsproxy")
end
if is_installed("dns-forwarder") or is_finded("dns-forwarder") then
o:value("dns-forwarder", "dns-forwarder")
end
o:value("OpenDNS_1", "OpenDNS_1")
o:value("OpenDNS_2", "OpenDNS_2")
o:value("custom", translate("custom"))

View File

@ -19,7 +19,11 @@ o.default = 1
---- Auto Ping
o = s:option(Flag, "auto_ping", translate("Auto Ping"),
translate("This will automatically ping the node for latency"))
o.default = 0
o.default = 1
---- Concise display nodes
o = s:option(Flag, "compact_display_nodes", translate("Concise display nodes"))
o.default = 1
-- [[ Add the node via the link ]]--
s:append(Template("passwall/node_list/link_add_node"))
@ -27,7 +31,6 @@ s:append(Template("passwall/node_list/link_add_node"))
-- [[ Node List ]]--
s = m:section(TypedSection, "nodes")
s.anonymous = true
s.sortable = true
s.addremove = true
s.template = "cbi/tblsection"
s.extedit = d.build_url("admin", "vpn", "passwall", "node_config", "%s")
@ -43,32 +46,62 @@ function s.remove(t, a)
luci.http.redirect(d.build_url("admin", "vpn", "passwall", "node_list"))
end
---- Remarks
o = s:option(DummyValue, "remarks", translate("Remarks"))
---- Add Mode
o = s:option(DummyValue, "add_mode", translate("Add Mode"))
o.cfgvalue = function(t, n)
local v = Value.cfgvalue(t, n)
if v and v ~= '' then
return v
else
return '手动'
-- 简洁模式
if api.uci_get_type("global_other", "compact_display_nodes", "1") == "1" then
o = s:option(DummyValue, "group", translate("Group"))
o.width = "25%"
o.cfgvalue = function(t, n)
local group = api.uci_get_type_id(n, "group") or ""
return group ~= "" and group or ""
end
return str
end
---- Type
o = s:option(DummyValue, "type", translate("Type"))
o = s:option(DummyValue, "remarks", translate("Remarks"))
o.cfgvalue = function(t, n)
local str = ""
local is_sub = api.uci_get_type_id(n, "is_sub") or ""
local group = api.uci_get_type_id(n, "group") or ""
local remarks = api.uci_get_type_id(n, "remarks") or ""
local type = api.uci_get_type_id(n, "type") or ""
local address = api.uci_get_type_id(n, "address") or ""
local port = api.uci_get_type_id(n, "port") or ""
if is_sub == "" and group == "" then
str = str .. type .. ""
end
str = str .. remarks
if address ~= "" and port ~= "" then
local s = " " .. address .. ":" .. port .. ""
str = str .. s
end
return str
end
else
s.sortable = true
---- Remarks
o = s:option(DummyValue, "remarks", translate("Remarks"))
---- Address
o = s:option(DummyValue, "address", translate("Address"))
---- Add Mode
o = s:option(DummyValue, "add_mode", translate("Add Mode"))
o.cfgvalue = function(t, n)
local v = Value.cfgvalue(t, n)
if v and v ~= '' then
return v
else
return '手动'
end
return str
end
---- Port
o = s:option(DummyValue, "port", translate("Port"))
---- Type
o = s:option(DummyValue, "type", translate("Type"))
---- Encrypt Method
--[[ o = s:option(DummyValue, "encrypt_method", translate("Encrypt Method"))
---- Address
o = s:option(DummyValue, "address", translate("Address"))
---- Port
o = s:option(DummyValue, "port", translate("Port"))
---- Encrypt Method
--[[ o = s:option(DummyValue, "encrypt_method", translate("Encrypt Method"))
o.width = "15%"
o.cfgvalue = function(t, n)
local str = ""
@ -82,9 +115,11 @@ o.cfgvalue = function(t, n)
end
return str
end--]]
end
---- Ping
o = s:option(DummyValue, "ping", translate("Ping"))
o.width = "10%"
if api.uci_get_type("global_other", "auto_ping", "0") == "0" then
o.template = "passwall/node_list/ping"
else

View File

@ -51,19 +51,6 @@ s = m:section(TypedSection, "global_dns", translate("DNS Settings"))
s.anonymous = true
s.addremove = false
---- DNS Forward Address
o = s:option(Value, "dns_forward", translate("DNS Forward Address"))
o.rmempty = false
o.default = "8.8.4.4:53"
o:value("8.8.4.4:53", "8.8.4.4:53(Google DNS1)")
o:value("8.8.8.8:53", "8.8.8.8:53(Google DNS2)")
o:value("208.67.222.222:53", "208.67.222.222:53(OpenDNS DNS1_53)")
o:value("208.67.222.222:5353", "208.67.222.222:5353(OpenDNS DNS1_5353)")
o:value("208.67.222.222:443", "208.67.222.222:443(OpenDNS DNS1_443)")
o:value("208.67.220.220:53", "208.67.220.220:53(OpenDNS DNS2_53)")
o:value("208.67.220.220:5353", "208.67.220.220:5353(OpenDNS DNS2_5353)")
o:value("208.67.220.220:443", "208.67.220.220:443(OpenDNS DNS2_443)")
---- Mainland DNS Sever 1
o = s:option(Value, "dns_1", translate("Mainland DNS Sever 1"))
o.rmempty = false

View File

@ -28,36 +28,13 @@ o.default = 0
o:depends("auto_update", 1)
-- [[ Subscribe Settings ]]--
s = m:section(TypedSection, "global_subscribe", translate("Node Subscribe"))
s = m:section(TypedSection, "global_subscribe", translate("Node Subscribe"),
translate(
"Please input the subscription url first, save and submit before updating. If you subscribe to update, it is recommended to delete all subscriptions and then re-subscribe."))
s.anonymous = true
---- Subscribe URL
o = s:option(DynamicList, "subscribe_url", translate("Subscribe URL"),
translate(
"Please input the subscription url first, save and submit before updating. If you subscribe to update, it is recommended to delete all subscriptions and then re-subscribe."))
---- Subscribe Manually update
o = s:option(Button, "_update", translate("Manually update"))
o.inputstyle = "apply"
function o.write(e, e)
luci.sys
.call("nohup /usr/share/passwall/subscription.sh > /dev/null 2>&1 &")
luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", "passwall",
"log"))
end
---- Subscribe Delete All
o = s:option(Button, "_stop", translate("Delete All Subscribe Node"))
o.inputstyle = "remove"
function o.write(e, e)
luci.sys.call(
"nohup /usr/share/passwall/subscription.sh stop > /dev/null 2>&1 &")
luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", "passwall",
"log"))
end
---- Subscribe via proxy
o = s:option(Flag, "subscribe_by_ss", translate("Subscribe via proxy"))
o = s:option(Flag, "subscribe_proxy", translate("Subscribe via proxy"))
o.default = 0
o.rmempty = false
@ -81,6 +58,43 @@ for e = 0, 23 do o:value(e, e .. translate("oclock")) end
o.default = 0
o:depends("auto_update_subscribe", 1)
---- Subscribe Manually update
o = s:option(Button, "_update", translate("Manually update"))
o.inputstyle = "apply"
function o.write(e, e)
luci.sys
.call("nohup /usr/share/passwall/subscription.sh > /dev/null 2>&1 &")
luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", "passwall",
"log"))
end
---- Subscribe Delete All
o = s:option(Button, "_stop", translate("Delete All Subscribe Node"))
o.inputstyle = "remove"
function o.write(e, e)
luci.sys.call(
"nohup /usr/share/passwall/subscription.sh stop > /dev/null 2>&1 &")
luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", "passwall",
"log"))
end
s = m:section(TypedSection, "subscribe_list")
s.addremove = true
s.anonymous = true
s.sortable = true
s.template = "cbi/tblsection"
o = s:option(Flag, "enabled", translate("Enabled"))
o.rmempty = false
o = s:option(Value, "remark", translate("Subscribe Remark"))
o.width = "auto"
o.rmempty = false
o = s:option(Value, "url", translate("Subscribe URL"))
o.width = "auto"
o.rmempty = false
-- [[ App Settings ]]--
s = m:section(TypedSection, "global_app", translate("App Update"),
translate("Please confirm that your firmware supports FPU."))

View File

@ -362,22 +362,21 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
},
function(x, rv) {
if (rv.status) {
var receiveDate = (new Date()).getTime();
var responseTimeMs = receiveDate - sendDate;
var time = ((new Date()).getTime() - sendDate) / 1000;
var speed = "";
if (responseTimeMs < 300) {
if (time < 0.5) {
s.className="green";
speed = "<%:very good%>";
} else if (responseTimeMs < 600) {
} else if (time < 0.8) {
s.className="green";
speed = "<%:good%>";
} else if (responseTimeMs < 2000) {
} else if (time < 1.5) {
s.className="yellow";
speed = "<%:general%>";
} else if (responseTimeMs < 5000) {
} else if (time < 3) {
s.className="red";
speed = "<%:bad%>";
} else if (responseTimeMs >= 5000) {
} else if (time >= 3) {
s.className="red";
speed = "<%:very bad%>";
}

View File

@ -216,23 +216,22 @@ local socks5_node_num = api.uci_get_type("global_other", "socks5_node_num", 1)
var s = document.getElementById('_' + type + '_status');
if(s) {
if(rv.status) {
var receiveDate = (new Date()).getTime();
var responseTimeMs = receiveDate - sendDate;
var time = ((new Date()).getTime() - sendDate) / 1000;
var speed = "";
var color="red";
if (responseTimeMs < 300) {
if (time < 0.5) {
color = "green";
speed = "<%:very good%>";
} else if (responseTimeMs < 600) {
} else if (time < 0.8) {
color = "green";
speed = "<%:good%>";
} else if (responseTimeMs < 2000) {
} else if (time < 1.5) {
color = "#b9b90b";
speed = "<%:general%>";
} else if (responseTimeMs < 5000) {
} else if (time < 3) {
color = "red";
speed = "<%:bad%>";
} else if (responseTimeMs >= 5000) {
} else if (time >= 3) {
color = "red";
speed = "<%:very bad%>";
}

View File

@ -5,6 +5,7 @@
local tcp_node_num = api.uci_get_type("global_other", "tcp_node_num", 1)
local udp_node_num = api.uci_get_type("global_other", "udp_node_num", 1)
local socks5_node_num = api.uci_get_type("global_other", "socks5_node_num", 1)
local compact_display_nodes = api.uci_get_type("global_other", "compact_display_nodes", 1)
-%>
<style>
@ -33,6 +34,52 @@ table td, .table .td {
<script type="text/javascript">
//<![CDATA[
var ajax = {
post: function(url, data, fn_success, fn_timeout) {
var xhr = new XMLHttpRequest();
var code = ajax.encode(data);
xhr.open("POST", url, true);
xhr.timeout = 2000;
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.ontimeout = function() {
fn_timeout(xhr);
}
xhr.onreadystatechange = function() {
if(xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) {
var json = null;
if (xhr.getResponseHeader("Content-Type") == "application/json") {
try {
json = eval('(' + xhr.responseText + ')');
}
catch(e) {
json = null;
}
}
fn_success(xhr, json);
}
};
xhr.send(code);
},
encode: function(obj) {
obj = obj ? obj : { };
obj['_'] = Math.random();
if (typeof obj == 'object')
{
var code = '';
var self = this;
for (var k in obj)
code += (code ? '&' : '') +
k + '=' + encodeURIComponent(obj[k]);
return code;
}
return obj;
}
}
var section = "";
function open_set_node_div(cbi_id) {
section = cbi_id;
@ -46,58 +93,93 @@ table td, .table .td {
document.getElementById("set_node_name").innerHTML = "";
}
var auto_ping_value = document.getElementsByClassName('auto_ping_value');
for(var i = 0; i < auto_ping_value.length; i++) {
var cbi_id = auto_ping_value[i].getAttribute("cbiid");
var address = document.getElementById("cbid.passwall." + cbi_id + ".address").value;
var port = document.getElementById("cbid.passwall." + cbi_id + ".port").value;
XHR.get('<%=dsp.build_url("admin/vpn/passwall/auto_ping_node")%>', {
index: i,
address: address,
port: port
},
function(x, result) {
auto_ping_value[result.index].innerHTML = (result.ping ? result.ping : "--") + " ms";
}
);
}
function set_node(protocol,number) {
if (confirm('<%:Are you sure set to%> ' + protocol.toUpperCase() + "_" + number + '<%:the server?%>')==true){
XHR.get('<%=dsp.build_url("admin/vpn/passwall/set_node")%>', { "protocol" : protocol , "number" : number , "section" : section },
function(x, result) {
if(x && x.status == 200) {
//window.location.href = '<%=dsp.build_url("admin/vpn/passwall/log")%>'
}
}
);
window.location.href = '<%=dsp.build_url("admin/vpn/passwall/log")%>'
window.location.href = '<%=dsp.build_url("admin/vpn/passwall/set_node")%>?protocol=' + protocol + '&number=' + number + '&section=' + section;
}
}
function ping_node(cbi_id,dom) {
var address = document.getElementById("cbid.passwall." + cbi_id + ".address").value;
var port = document.getElementById("cbid.passwall." + cbi_id + ".port").value;
XHR.get('<%=dsp.build_url("admin/vpn/passwall/ping_node")%>', {
<% if compact_display_nodes and tonumber(compact_display_nodes) == 1 then %>
var remarks = document.getElementById("cbid.passwall." + cbi_id + ".remarks").value;
var address_full = remarks.substring(remarks.lastIndexOf("") + 1, remarks.lastIndexOf(""));
var address = address_full.substring(0, address_full.lastIndexOf(":"));
var port = address_full.substring(address_full.lastIndexOf(":") + 1);
<% else %>
var address = document.getElementById("cbid.passwall." + cbi_id + ".address").value;
var port = document.getElementById("cbid.passwall." + cbi_id + ".port").value;
<% end %>
if ((address != null && address != "") && (port != null && port != "")) {
XHR.get('<%=dsp.build_url("admin/vpn/passwall/ping_node")%>', {
address: address,
port: port
},
function(x, result) {
if(x && x.status == 200) {
if (result.ping != null && result.ping != "")
dom.outerHTML = result.ping + " ms";
else
dom.outerHTML = "--";
}
}
);
}
}
/* 自动Ping */
var node_list = [];
var auto_ping_value = document.getElementsByClassName('auto_ping_value');
for(var i = 0; i < auto_ping_value.length; i++) {
var cbi_id = auto_ping_value[i].getAttribute("cbiid");
<% if compact_display_nodes and tonumber(compact_display_nodes) == 1 then %>
var remarks = document.getElementById("cbid.passwall." + cbi_id + ".remarks").value;
var address_full = remarks.substring(remarks.lastIndexOf("") + 1, remarks.lastIndexOf(""));
var address = address_full.substring(0, address_full.lastIndexOf(":"));
var port = address_full.substring(address_full.lastIndexOf(":") + 1);
<% else %>
var address = document.getElementById("cbid.passwall." + cbi_id + ".address").value;
var port = document.getElementById("cbid.passwall." + cbi_id + ".port").value;
<% end %>
if ((address != null && address != "") && (port != null && port != "")) {
var data = {
index: i,
address: address,
port: port
};
node_list.push(data);
}
}
var index = 0;
function auto_ping() {
if (index >= node_list.length){
return;
}
var json = JSON.stringify(node_list[index]);
ajax.post('<%=dsp.build_url("admin/vpn/passwall/auto_ping_node_list")%>', {
json: json
},
function(x, result) {
if(x && x.status == 200) {
if (result.ping != null && result.ping != "")
dom.outerHTML = result.ping + " ms";
else
dom.outerHTML = "--";
auto_ping_value[result.index].innerHTML = (result.ping ? result.ping : "--") + " ms";
}
}
index++;
auto_ping();
},
function(x) {
index++;
auto_ping();
},
);
}
auto_ping();
//]]>
</script>
<div id="set_node_div">
<div class="cbi-value">您选择的服务器是:<span id="set_node_name"></span></div>
<div class="cbi-value"><%:You choose node is:%><span id="set_node_name"></span></div>
<div class="cbi-value">
<% if tcp_node_num and tonumber(tcp_node_num) >= 1 then %>
<% for i = 1, tcp_node_num, 1 do %>

View File

@ -232,6 +232,9 @@ msgstr "你确定要设为"
msgid "the server?"
msgstr "服务器吗?"
msgid "You choose node is:"
msgstr "你选择的节点是:"
msgid "The server client can also use this rule to scientifically surf the Internet"
msgstr "本机服务器的客户端也可以使用这个代理模式上网"
@ -268,6 +271,9 @@ msgstr "Ping延迟"
msgid "Ping Value"
msgstr "Ping值"
msgid "Group"
msgstr "组"
msgid "Use TCPing"
msgstr "使用TCPing"
@ -280,6 +286,9 @@ msgstr "自动Ping"
msgid "This will automatically ping the node for latency"
msgstr "选中后保存应用后即自动Ping节点"
msgid "Concise display nodes"
msgstr "简洁显示节点"
msgid "Apply"
msgstr "应用"
@ -547,6 +556,9 @@ msgstr "如果你希望从内存中运行,请更改路径,例如/tmp/brook
msgid "Node Subscribe"
msgstr "节点订阅"
msgid "Subscribe Remark"
msgstr "订阅备注(机场)"
msgid "Subscribe URL"
msgstr "订阅网址"

0
package/lienol/luci-app-passwall/po2lmo Normal file → Executable file
View File

View File

@ -3,10 +3,10 @@ config global
option tcp_node1 'nil'
option udp_node1 'nil'
option socks5_node1 'nil'
option dns_mode 'chinadns'
option up_chinadns_mode 'OpenDNS_1'
option dns_mode 'pdnsd'
option dns2socks_forward '8.8.4.4'
option proxy_mode 'chnroute'
option localhost_proxy_mode 'default'
option localhost_proxy_mode 'gfwlist'
config global_haproxy
option balancing_enable '0'
@ -20,7 +20,6 @@ config global_dns
option dns_port '0'
option wan_port '0'
option dns_53 '1'
option dns_forward '8.8.4.4:53'
option dns_1 '114.114.114.114'
option dns_2 '119.29.29.29'
@ -38,11 +37,12 @@ config global_proxy
config global_other
option use_tcping '1'
option auto_ping '0'
option auto_ping '1'
option tcp_node_num '1'
option udp_node_num '1'
option socks5_node_num '1'
option status_use_big_icon '1'
option compact_display_nodes '1'
config global_rules
option auto_update '0'
@ -57,7 +57,7 @@ config global_app
option brook_file '/usr/bin/brook'
config global_subscribe
option subscribe_by_ss '0'
option subscribe_proxy '0'
option auto_update_subscribe '0'
config auto_switch

View File

View File

@ -1,5 +1,5 @@
#!/bin/sh
# Copyright (C) 2018-2019 Lienol <lawlienol@gmail.com>
# Copyright (C) 2018-2020 Lienol <lawlienol@gmail.com>
. $IPKG_INSTROOT/lib/functions.sh
. $IPKG_INSTROOT/lib/functions/service.sh
@ -14,7 +14,7 @@ REDSOCKS_CONFIG_UDP_FILE=$CONFIG_PATH/redsocks_UDP.conf
CONFIG_TCP_FILE=$CONFIG_PATH/TCP.json
CONFIG_UDP_FILE=$CONFIG_PATH/UDP.json
CONFIG_SOCKS5_FILE=$CONFIG_PATH/SOCKS5.json
LOCK_FILE=$CONFIG_PATH/$CONFIG.lock
LOCK_FILE=/var/lock/$CONFIG.lock
LOG_FILE=/var/log/$CONFIG.log
RULE_PATH=/etc/config/${CONFIG}_rule
APP_PATH=/usr/share/$CONFIG
@ -117,6 +117,24 @@ get_not_exists_port_after() {
fi
}
set_subscribe_proxy() {
local enabled
local url
config_get enabled $1 enabled
config_get url $1 url
[ "$enabled" == "1" ] && {
[ -n "$url" -a "$url" != "" ] && {
if [ -n "$(echo -n "$url" | grep "//")" ]; then
echo -n "$url" | awk -F'/' '{print $3}' | sed "s/^/server=&\/./g" | sed "s/$/\/127.0.0.1#$DNS_PORT/g" >>$TMP_DNSMASQ_PATH/subscribe.conf
echo -n "$url" | awk -F'/' '{print $3}' | sed "s/^/ipset=&\/./g" | sed "s/$/\/router/g" >>$TMP_DNSMASQ_PATH/subscribe.conf
else
echo -n "$url" | awk -F'/' '{print $1}' | sed "s/^/server=&\/./g" | sed "s/$/\/127.0.0.1#$DNS_PORT/g" >>$TMP_DNSMASQ_PATH/subscribe.conf
echo -n "$url" | awk -F'/' '{print $1}' | sed "s/^/ipset=&\/./g" | sed "s/$/\/router/g" >>$TMP_DNSMASQ_PATH/subscribe.conf
fi
}
}
}
TCP_NODE_NUM=$(config_t_get global_other tcp_node_num 1)
for i in $(seq 1 $TCP_NODE_NUM); do
eval TCP_NODE$i=$(config_t_get global tcp_node$i nil)
@ -170,9 +188,6 @@ load_config() {
process=$(config_t_get global_forwarding process)
fi
LOCALHOST_PROXY_MODE=$(config_t_get global localhost_proxy_mode default)
DNS_FORWARD=$(config_t_get global_dns dns_forward 208.67.222.222:443)
DNS_FORWARD_IP=$(echo "$DNS_FORWARD" | awk -F':' '{print $1}')
DNS_FORWARD_PORT=$(echo "$DNS_FORWARD" | awk -F':' '{print $2}')
DNS1=$(config_t_get global_dns dns_1)
DNS2=$(config_t_get global_dns dns_2)
TCP_REDIR_PORT1=$(config_t_get global_proxy tcp_redir_port 1041)
@ -622,24 +637,21 @@ start_dns() {
nonuse)
echolog "不使用任何DNS转发模式将会直接将WAN口DNS给dnsmasq上游"
;;
local_7913)
echolog "运行DNS转发模式使用本机7913端口DNS服务器解析域名..."
;;
dns2socks)
if [ -n "$SOCKS5_NODE1" -a "$SOCKS5_NODE1" != "nil" ]; then
dns2socks_bin=$(find_bin dns2socks)
[ -n "$dns2socks_bin" ] && {
nohup $dns2socks_bin 127.0.0.1:$SOCKS5_PROXY_PORT1 $DNS_FORWARD 127.0.0.1:$DNS_PORT >/dev/null 2>&1 &
local dns=$(config_t_get global dns2socks_forward 8.8.4.4)
nohup $dns2socks_bin 127.0.0.1:$SOCKS5_PROXY_PORT1 ${dns}:53 127.0.0.1:$DNS_PORT >/dev/null 2>&1 &
echolog "运行DNS转发模式dns2socks..."
}
else
echolog "dns2socks模式需要使用Socks5代理节点请开启"
fi
;;
Pcap_DNSProxy)
Pcap_DNSProxy_bin=$(find_bin Pcap_DNSProxy)
[ -n "$Pcap_DNSProxy_bin" ] && {
nohup $Pcap_DNSProxy_bin -c /etc/pcap-dnsproxy >/dev/null 2>&1 &
echolog "运行DNS转发模式Pcap_DNSProxy..."
}
;;
pdnsd)
pdnsd_bin=$(find_bin pdnsd)
[ -n "$pdnsd_bin" ] && {
@ -648,16 +660,14 @@ start_dns() {
echolog "运行DNS转发模式Pdnsd..."
}
;;
local_7913)
echolog "运行DNS转发模式使用本机7913端口DNS服务器解析域名..."
;;
chinadns)
chinadns_bin=$(find_bin ChinaDNS)
[ -n "$chinadns_bin" ] && {
other=1
other_port=$(expr $DNS_PORT + 1)
echolog "运行DNS转发模式ChinaDNS..."
dns1=$(config_t_get global_dns dns_1)
[ "$dns1" = "dnsbyisp" ] && dns1=$(cat /tmp/resolv.conf.auto 2>/dev/null | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | sort -u | grep -v 0.0.0.0 | grep -v 127.0.0.1 | sed -n '2P')
local dns1=$DNS1
[ "$DNS1" = "dnsbyisp" ] && dns1=$(cat /tmp/resolv.conf.auto 2>/dev/null | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | grep -v 0.0.0.0 | grep -v 127.0.0.1 | sed -n '1P')
case "$UP_CHINADNS_MODE" in
OpenDNS_1)
other=0
@ -675,23 +685,9 @@ start_dns() {
nohup $chinadns_bin -p $DNS_PORT -c $RULE_PATH/chnroute -m -d -s $UP_CHINADNS_CUSTOM >/dev/null 2>&1 &
echolog "运行ChinaDNS上游转发模式$UP_CHINADNS_CUSTOM..."
;;
dnsproxy)
dnsproxy_bin=$(find_bin dnsproxy)
[ -n "$dnsproxy_bin" ] && {
nohup $dnsproxy_bin -d -T -p $DNS_PORT -R $DNS_FORWARD_IP -P $DNS_FORWARD_PORT >/dev/null 2>&1 &
echolog "运行ChinaDNS上游转发模式dnsproxy..."
}
;;
dns-forwarder)
dnsforwarder_bin=$(find_bin dns-forwarder)
[ -n "$dnsforwarder_bin" ] && {
nohup $dnsforwarder_bin -p $DNS_PORT -s $DNS_FORWARD >/dev/null 2>&1 &
echolog "运行ChinaDNS上游转发模式dns-forwarder..."
}
;;
esac
if [ "$other" = "1" ]; then
nohup $chinadns_bin -p 7923 -c $RULE_PATH/chnroute -m -d -s $dns1,127.0.0.1:$DNS_PORT >/dev/null 2>&1 &
nohup $chinadns_bin -p $DNS_PORT -c $RULE_PATH/chnroute -m -d -s $dns1,127.0.0.1:$other_port >/dev/null 2>&1 &
fi
}
;;
@ -717,7 +713,6 @@ EOF
echolog "生成Dnsmasq配置文件。"
if [ "$dnsport" != "0" ]; then
isp_dns=$(cat /tmp/resolv.conf.auto 2>/dev/null | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | sort -u | grep -v 0.0.0.0 | grep -v 127.0.0.1)
failcount=0
while [ "$failcount" -lt "10" ]; do
interface=$(ifconfig | grep "$dnsport" | awk '{print $1}')
@ -727,13 +722,6 @@ EOF
[ "$failcount" -ge 10 ] && exit 0
sleep 1m
else
[ -n "$isp_dns" ] && {
for isp_ip in $isp_dns; do
echo server=$isp_ip >>/etc/dnsmasq.conf
route add -host ${isp_ip} dev ${dnsport}
echolog "添加运营商DNS出口路由表$dnsport"
done
}
[ "$DNS1" != "dnsbyisp" ] && {
route add -host ${DNS1} dev ${dnsport}
echolog "添加DNS1出口路由表$dnsport"
@ -748,10 +736,10 @@ EOF
fi
done
else
isp_dns=$(cat /tmp/resolv.conf.auto 2>/dev/null | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | sort -u | grep -v 0.0.0.0 | grep -v 127.0.0.1)
[ -n "$isp_dns" ] && {
for isp_ip in $isp_dns; do
echo server=$isp_ip >>/etc/dnsmasq.conf
isp_dnss=$(cat /tmp/resolv.conf.auto 2>/dev/null | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | sort -u | grep -v 0.0.0.0 | grep -v 127.0.0.1)
[ -n "$isp_dnss" ] && {
for isp_dns in $isp_dnss; do
echo server=$isp_dns >>/etc/dnsmasq.conf
done
}
[ "$DNS1" != "dnsbyisp" ] && {
@ -805,22 +793,10 @@ EOF
# done
# fi
subscribe_by_ss=$(config_t_get global_subscribe subscribe_by_ss)
[ -z "$subscribe_by_ss" ] && subscribe_by_ss=0
[ "$subscribe_by_ss" -eq 1 ] && {
subscribe_url=$(config_t_get global_subscribe subscribe_url)
[ -n "$subscribe_url" ] && {
for url in $subscribe_url; do
if [ -n "$(echo -n "$url" | grep "//")" ]; then
echo -n "$url" | awk -F'/' '{print $3}' | sed "s/^/server=&\/./g" | sed "s/$/\/127.0.0.1#$DNS_PORT/g" >>$TMP_DNSMASQ_PATH/subscribe.conf
echo -n "$url" | awk -F'/' '{print $3}' | sed "s/^/ipset=&\/./g" | sed "s/$/\/router/g" >>$TMP_DNSMASQ_PATH/subscribe.conf
else
echo -n "$url" | awk -F'/' '{print $1}' | sed "s/^/server=&\/./g" | sed "s/$/\/127.0.0.1#$DNS_PORT/g" >>$TMP_DNSMASQ_PATH/subscribe.conf
echo -n "$url" | awk -F'/' '{print $1}' | sed "s/^/ipset=&\/./g" | sed "s/$/\/router/g" >>$TMP_DNSMASQ_PATH/subscribe.conf
fi
done
restdns=1
}
subscribe_proxy=$(config_t_get global_subscribe subscribe_proxy 0)
[ "$subscribe_proxy" -eq 1 ] && {
config_foreach set_subscribe_proxy "subscribe_list"
restdns=1
}
if [ ! -f "$TMP_DNSMASQ_PATH/gfwlist.conf" -a "$DNS_MODE" != "nonuse" ]; then
@ -977,13 +953,10 @@ gen_pdnsd_config() {
}
stop_dnsmasq() {
if [ "$TCP_NODE1" == "nil" ]; then
rm -rf /var/dnsmasq.d/dnsmasq-$CONFIG.conf
rm -rf $DNSMASQ_PATH/dnsmasq-$CONFIG.conf
rm -rf $TMP_DNSMASQ_PATH
/etc/init.d/dnsmasq restart 2>/dev/null
echolog "没有选择节点!"
fi
rm -rf /var/dnsmasq.d/dnsmasq-$CONFIG.conf
rm -rf $DNSMASQ_PATH/dnsmasq-$CONFIG.conf
rm -rf $TMP_DNSMASQ_PATH
/etc/init.d/dnsmasq restart 2>/dev/null
}
start_haproxy() {
@ -1136,11 +1109,9 @@ boot() {
}
start() {
#防止并发启动
! load_config && return 1
[ -f "$LOCK_FILE" ] && return 3
touch "$LOCK_FILE"
echolog "开始运行脚本!"
! load_config && return 1
add_vps_port
start_haproxy
start_socks5_proxy
@ -1164,7 +1135,7 @@ stop() {
clean_log
source $APP_PATH/iptables.sh stop
del_vps_port
kill_all pdnsd Pcap_DNSProxy brook dns2socks haproxy dns-forwarder chinadns dnsproxy ipt2socks
kill_all pdnsd brook dns2socks haproxy chinadns ipt2socks
ps -w | grep -E "$CONFIG_TCP_FILE|$CONFIG_UDP_FILE|$CONFIG_SOCKS5_FILE" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &
ps -w | grep -E "$CONFIG_PATH" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &
ps -w | grep "kcptun_client" | grep "$KCPTUN_REDIR_PORT" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &

View File

View File

View File

@ -1,5 +1,6 @@
#!/bin/bash
. $IPKG_INSTROOT/lib/functions.sh
. /usr/share/libubox/jshn.sh
CONFIG=passwall
@ -31,6 +32,76 @@ decode_url_link() {
fi
}
start_subscribe() {
local enabled
local url
config_get enabled $1 enabled
config_get url $1 url
[ "$enabled" == "1" ] && {
[ -n "$url" -a "$url" != "" ] && {
local addnum_ss=0
local updatenum_ss=0
local delnum_ss=0
local addnum_ssr=0
local updatenum_ssr=0
local delnum_ssr=0
local addnum_v2ray=0
local updatenum_v2ray=0
local delnum_v2ray=0
local addnum_trojan=0
local updatenum_trojan=0
local delnum_trojan=0
config_get subscrib_remark $1 remark
let index+=1
echo "$Date: 正在订阅:$url" >> $LOG_FILE
result=$(/usr/bin/curl --connect-timeout 10 -sL $url)
[ "$?" != 0 ] || [ -z "$result" ] && {
result=$(/usr/bin/wget --no-check-certificate --timeout=8 -t 1 -O- $url)
[ "$?" != 0 ] || [ -z "$result" ] && echo "$Date: 订阅失败:$url,请检测订阅链接是否正常或使用代理尝试!" >> $LOG_FILE && continue
}
file="/var/${CONFIG}_sub/$index"
echo "$result" > $file
get_local_nodes
[ -z "$(du -sh $file 2> /dev/null)" ] && echo "$Date: 订阅失败:$url,解密失败!" >> $LOG_FILE && continue
decode_link=$(cat "$file" | base64 -d 2> /dev/null)
maxnum=$(echo -n "$decode_link" | grep "MAX=" | awk -F"=" '{print $2}')
if [ -n "$maxnum" ]; then
decode_link=$(echo -n "$decode_link" | sed '/MAX=/d' | shuf -n${maxnum})
else
decode_link=$(echo -n "$decode_link")
fi
[ -z "$decode_link" ] && continue
for link in $decode_link
do
if expr "$link" : "ss://";then
link_type="ss"
new_link=$(echo -n "$link" | sed 's/ss:\/\///g')
elif expr "$link" : "ssr://";then
link_type="ssr"
new_link=$(echo -n "$link" | sed 's/ssr:\/\///g')
elif expr "$link" : "vmess://";then
link_type="v2ray"
new_link=$(echo -n "$link" | sed 's/vmess:\/\///g')
elif expr "$link" : "trojan://";then
link_type="trojan"
new_link=$(echo -n "$link" | sed 's/trojan:\/\///g')
fi
[ -z "$link_type" ] && continue
get_remote_config "$link_type" "$new_link"
update_config
done
[ "$addnum_ss" -gt 0 ] || [ "$updatenum_ss" -gt 0 ] || [ "$delnum_ss" -gt 0 ] && echo "$Date: $subscrib_remark SS节点新增 $addnum_ss 个,修改 $updatenum_ss 个,删除 $delnum_ss 个。" >> $LOG_FILE
[ "$addnum_ssr" -gt 0 ] || [ "$updatenum_ssr" -gt 0 ] || [ "$delnum_ssr" -gt 0 ] && echo "$Date: $subscrib_remark SSR节点新增 $addnum_ssr 个,修改 $updatenum_ssr 个,删除 $delnum_ssr 个。" >> $LOG_FILE
[ "$addnum_v2ray" -gt 0 ] || [ "$updatenum_v2ray" -gt 0 ] || [ "$delnum_v2ray" -gt 0 ] && echo "$Date: $subscrib_remark V2ray节点新增 $addnum_v2ray 个,修改 $updatenum_v2ray 个,删除 $delnum_v2ray 个。" >> $LOG_FILE
[ "$addnum_trojan" -gt 0 ] || [ "$updatenum_trojan" -gt 0 ] || [ "$delnum_trojan" -gt 0 ] && echo "$Date: $subscrib_remark Trojan节点新增 $addnum_trojan 个,修改 $updatenum_trojan 个,删除 $delnum_trojan 个。" >> $LOG_FILE
}
}
}
ss_decode() {
temp_link=$1
if [[ "$(echo $temp_link | grep "@")" != "" ]]; then
@ -54,11 +125,11 @@ get_node_index(){
}
get_local_nodes(){
[ -f "/etc/config/$CONFIG" ] && [ "`uci show $CONFIG | grep -c 'sub_node'`" -gt 0 ] && {
[ -f "/etc/config/$CONFIG" ] && [ "`uci show $CONFIG | grep -c 'is_sub'`" -gt 0 ] && {
get_node_index
for i in `seq $nodes_index -1 1`
do
[ "$(uci show $CONFIG.@nodes[$(($i-1))]|grep -c "sub_node")" -eq 1 ] && {
[ "$(uci show $CONFIG.@nodes[$(($i-1))]|grep -c "is_sub")" -eq 1 ] && {
if [ ! -f "/usr/share/${CONFIG}/sub/all_localnodes" ]; then
echo $(config_t_get nodes address $(($i-1))) > /usr/share/${CONFIG}/sub/all_localnodes
else
@ -71,9 +142,8 @@ get_local_nodes(){
get_remote_config(){
isAdd=1
add_mode="订阅"
add_mode="$subscrib_remark"
[ -n "$3" ] && add_mode="导入"
group="sub_node"
if [ "$1" == "ss" ]; then
decode_link="$2"
decode_link=$(ss_decode $decode_link)
@ -86,8 +156,6 @@ get_remote_config(){
decode_link="$2"
decode_link=$(decode_url_link $decode_link 1)
node_address=$(echo "$decode_link" | awk -F ':' '{print $1}')
node_address=$(echo $node_address |awk '{print gensub(/[^!-~]/,"","g",$0)}')
[ -z "$node_address" -o "$node_address" == "" ] && isAdd=0
node_port=$(echo "$decode_link" | awk -F ':' '{print $2}')
protocol=$(echo "$decode_link" | awk -F ':' '{print $3}')
ssr_encrypt_method=$(echo "$decode_link" | awk -F ':' '{print $4}')
@ -101,6 +169,7 @@ get_remote_config(){
remarks_temp=$(echo "$decode_link" |grep -Eo "remarks.+" |sed 's/remarks=//g'|awk -F'&' '{print $1}')
[ -n "$remarks_temp" ] && remarks="$(decode_url_link $remarks_temp 0)"
group_temp=$(echo "$decode_link" |grep -Eo "group.+" |sed 's/group=//g'|awk -F'&' '{print $1}')
[ -n "$group_temp" ] && group="$(decode_url_link $group_temp 0)"
elif [ "$1" == "v2ray" ]; then
decode_link=$(decode_url_link $2 1)
json_load "$decode_link"
@ -134,6 +203,9 @@ get_remote_config(){
remarks="${node_address}:${node_port}"
fi
node_address=$(echo $node_address |awk '{print gensub(/[^!-~]/,"","g",$0)}')
#[ -z "$node_address" -o "$node_address" == "" ] && isAdd=0
# 把全部节点节点写入文件 /usr/share/${CONFIG}/sub/all_onlinenodes
if [ ! -f "/usr/share/${CONFIG}/sub/all_onlinenodes" ]; then
echo $node_address > /usr/share/${CONFIG}/sub/all_onlinenodes
@ -147,7 +219,7 @@ add_nodes(){
get_node_index
uci_set="uci set $CONFIG.@nodes[$nodes_index]."
uci add $CONFIG nodes > /dev/null
[ -z "$3" ] && ${uci_set}group="$group"
[ -z "$3" ] && ${uci_set}is_sub="is_sub"
if [ "$2" == "ss" ]; then
${uci_set}add_mode="$add_mode"
${uci_set}remarks="$remarks"
@ -181,6 +253,7 @@ add_nodes(){
${uci_set}obfs_param="$obfsparam"
${uci_set}timeout=300
${uci_set}tcp_fast_open=false
${uci_set}group="$group"
if [ "$1" == "add" ]; then
let addnum_ssr+=1
@ -234,14 +307,11 @@ add_nodes(){
update_config(){
[ "$isAdd" == 1 ] && {
isadded_address=$(uci show $CONFIG | grep -c "remarks='$remarks'")
if [ "$isadded_address" -eq 0 ]; then
isadded_remarks=$(uci show $CONFIG | grep -c "remarks='$remarks'")
if [ "$isadded_remarks" -eq 0 ]; then
add_nodes add "$link_type"
else
index=$(uci show $CONFIG | grep -w "remarks='$remarks'" | cut -d '[' -f2|cut -d ']' -f1)
local_port=$(config_t_get nodes port $index)
local_vmess_id=$(config_t_get nodes v2ray_VMess_id $index)
uci delete $CONFIG.@nodes[$index]
add_nodes update "$link_type"
fi
@ -275,7 +345,7 @@ del_config(){
del_all_config(){
get_node_index
[ "`uci show $CONFIG | grep -c 'sub_node'`" -eq 0 ] && exit 0
[ "`uci show $CONFIG | grep -c 'is_sub'`" -eq 0 ] && exit 0
TCP_NODE_NUM=$(uci get $CONFIG.@global_other[0].tcp_node_num)
for i in $(seq 1 $TCP_NODE_NUM); do
eval TCP_NODE$i=$(config_t_get global tcp_node$i)
@ -293,11 +363,14 @@ del_all_config(){
[ "$UDP_NODE1" == "default" ] && UDP_NODE1=$TCP_NODE1
is_stop=0
for i in $(seq 1 $TCP_NODE_NUM); do
eval node=\$TCP_NODE$i
[ -n "$node" -a "$node" != "nil" ] && {
is_sub_node=`uci -q get $CONFIG.$node.group`
is_sub_node=`uci -q get $CONFIG.$node.is_sub`
[ -n "$is_sub_node" ] && {
is_stop=1
uci set $CONFIG.@global[0].tcp_node$i="nil" && uci commit $CONFIG
}
}
@ -306,8 +379,9 @@ del_all_config(){
for i in $(seq 1 $UDP_NODE_NUM); do
eval node=\$UDP_NODE$i
[ "$node" != "nil" ] && {
is_sub_node=`uci -q get $CONFIG.$node.group`
is_sub_node=`uci -q get $CONFIG.$node.is_sub`
[ -n "$is_sub_node" ] && {
is_stop=1
uci set $CONFIG.@global[0].udp_node$i="nil" && uci commit $CONFIG
}
}
@ -316,8 +390,9 @@ del_all_config(){
for i in $(seq 1 $SOCKS5_NODE_NUM); do
eval node=\$SOCKS5_NODE$i
[ "$node" != "nil" ] && {
is_sub_node=`uci -q get $CONFIG.$node.group`
is_sub_node=`uci -q get $CONFIG.$node.is_sub`
[ -n "$is_sub_node" ] && {
is_stop=1
uci set $CONFIG.@global[0].socks5_node$i="nil" && uci commit $CONFIG
}
}
@ -325,10 +400,10 @@ del_all_config(){
for i in `seq $nodes_index -1 1`
do
[ "$(uci show $CONFIG.@nodes[$(($i-1))] | grep -c 'sub_node')" -eq 1 ] && uci delete $CONFIG.@nodes[$(($i-1))] && uci commit $CONFIG
[ "$(uci show $CONFIG.@nodes[$(($i-1))] | grep -c 'is_sub')" -eq 1 ] && uci delete $CONFIG.@nodes[$(($i-1))] && uci commit $CONFIG
done
/etc/init.d/$CONFIG stop
[ "$is_stop" == 1 ] && /etc/init.d/$CONFIG restart
}
add() {
@ -371,82 +446,24 @@ start() {
touch "$LOCK_FILE"
base64=$(command -v base64)
[ -z "$base64" ] && echo "$Date: 找不到Base64程序请安装后重试" >> $LOG_FILE && rm -f "$LOCK_FILE" && exit 0
addnum_ss=0
updatenum_ss=0
delnum_ss=0
addnum_ssr=0
updatenum_ssr=0
delnum_ssr=0
addnum_v2ray=0
updatenum_v2ray=0
delnum_v2ray=0
addnum_trojan=0
updatenum_trojan=0
delnum_trojan=0
subscribe_url=$(uci get $CONFIG.@global_subscribe[0].subscribe_url) # 订阅地址
[ -z "$subscribe_url" ] && echo "$Date: 订阅地址为空,订阅失败!" >> $LOG_FILE && rm -f "$LOCK_FILE" && exit 0
has_subscribe=$(uci show $CONFIG | grep @subscribe_list | grep enabled=\'1\')
[ -z "$has_subscribe" -o "$has_subscribe" = "" ] && echo "$Date: 没有订阅地址或没启用!" >> $LOG_FILE && rm -f "$LOCK_FILE" && exit 0
echo "$Date: 开始订阅..." >> $LOG_FILE
mkdir -p /var/${CONFIG}_sub && rm -f /var/${CONFIG}_sub/*
index=0
for url in $subscribe_url
do
let index+=1
echo "$Date: 正在订阅:$url" >> $LOG_FILE
result=$(/usr/bin/curl --connect-timeout 10 -sL $url)
[ "$?" != 0 ] || [ -z "$result" ] && {
result=$(/usr/bin/wget --no-check-certificate --timeout=8 -t 1 -O- $url)
[ "$?" != 0 ] || [ -z "$result" ] && echo "$Date: 订阅失败:$url,请检测订阅链接是否正常或使用代理尝试!" >> $LOG_FILE && continue
}
echo "$result" > /var/${CONFIG}_sub/$index
done
[ ! -d "/var/${CONFIG}_sub" ] || [ "$(ls /var/${CONFIG}_sub | wc -l)" -eq 0 ] && echo "$Date: 订阅失败" >> $LOG_FILE && rm -f "$LOCK_FILE" && exit 0
mkdir -p /usr/share/${CONFIG}/sub && rm -f /usr/share/${CONFIG}/sub/*
get_local_nodes
for file in /var/${CONFIG}_sub/*
do
[ -z "$(du -sh $file 2> /dev/null)" ] && echo "$Date: 订阅失败:$url,解密失败!" >> $LOG_FILE && continue
decode_link=$(cat "$file" | base64 -d 2> /dev/null)
maxnum=$(echo -n "$decode_link" | grep "MAX=" | awk -F"=" '{print $2}')
if [ -n "$maxnum" ]; then
decode_link=$(echo -n "$decode_link" | sed '/MAX=/d' | shuf -n${maxnum})
else
decode_link=$(echo -n "$decode_link")
fi
[ -z "$decode_link" ] && continue
for link in $decode_link
do
if expr "$link" : "ss://";then
link_type="ss"
new_link=$(echo -n "$link" | sed 's/ss:\/\///g')
elif expr "$link" : "ssr://";then
link_type="ssr"
new_link=$(echo -n "$link" | sed 's/ssr:\/\///g')
elif expr "$link" : "vmess://";then
link_type="v2ray"
new_link=$(echo -n "$link" | sed 's/vmess:\/\///g')
elif expr "$link" : "trojan://";then
link_type="trojan"
new_link=$(echo -n "$link" | sed 's/trojan:\/\///g')
fi
[ -z "$link_type" ] && continue
get_remote_config "$link_type" "$new_link"
update_config
done
done
index=0
config_load $CONFIG
config_foreach start_subscribe "subscribe_list"
[ -f "/usr/share/${CONFIG}/sub/all_localnodes" ] && del_config
echo "$Date: 本次更新SS节点新增 $addnum_ss 个,修改 $updatenum_ss 个,删除 $delnum_ss 个。" >> $LOG_FILE
echo "$Date: 本次更新SSR节点新增 $addnum_ssr 个,修改 $updatenum_ssr 个,删除 $delnum_ssr 个。" >> $LOG_FILE
echo "$Date: 本次更新V2ray节点新增 $addnum_v2ray 个,修改 $updatenum_v2ray 个,删除 $delnum_v2ray 个。" >> $LOG_FILE
echo "$Date: 本次更新Trojan节点新增 $addnum_trojan 个,修改 $updatenum_trojan 个,删除 $delnum_trojan 个。" >> $LOG_FILE
echo "$Date: 订阅完毕..." >> $LOG_FILE
rm -f "$LOCK_FILE"
exit 0
}
stop() {
[ "`uci show $CONFIG | grep -c 'sub_node'`" -gt 0 ] && {
[ "`uci show $CONFIG | grep -c 'is_sub'`" -gt 0 ] && {
del_all_config
echo "$Date: 在线订阅节点已全部删除" >> $LOG_FILE
}

View File

@ -11,6 +11,7 @@ test_url() {
status=$(/usr/bin/curl -I -o /dev/null -s --connect-timeout 3 -w %{http_code} "$1" | grep 200)
[ "$?" != 0 ] && {
status=$(/usr/bin/wget --no-check-certificate --spider --timeout=3 "$1")
[ "$?" == 0 ] && status=200
}
echo $status
}

View File

@ -1,4 +1,4 @@
# Copyright (C) 2019 Lienol
# Copyright (C) 2019-2020 Lienol
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
@ -10,9 +10,9 @@ LUCI_TITLE:=LuCI support for Trojan Server
LUCI_DEPENDS:=+luci-lib-jsonc +trojan
LUCI_PKGARCH:=all
PKG_VERSION:=1.0
PKG_RELEASE:=2-20191207
PKG_RELEASE:=3-20191220
include $(TOPDIR)/feeds/luci/luci.mk
include ../luci_my.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -1,5 +1,5 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2019 Lienol <lawlienol@gmail.com>
# Copyright (C) 2019-2020 Lienol <lawlienol@gmail.com>
START=99
@ -20,13 +20,6 @@ gen_trojan_config_file() {
lua /usr/lib/lua/luci/model/cbi/trojan_server/api/gen_trojan_config_file.lua $1 > $CONFIG_PATH/$1.json
echolog "$remarks $port 生成并运行 Trojan 配置文件 - $CONFIG_PATH/$1.json"
trojan -c $CONFIG_PATH/$1.json >/dev/null 2>&1 &
is_run=`ps -w| grep -v grep | grep "$CONFIG_PATH/$1.json"`
if [ -z "$is_run" ];then
echolog "$remarks $port Trojan 运行失败"
else
echolog "$remarks $port Trojan 运行成功"
fi
}
start_trojan_server() {

View File

@ -0,0 +1,19 @@
# Copyright (C) 2018-2020 Lienol
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-v2ray-server
LUCI_TITLE:=LuCI support for V2ray Server
LUCI_DEPENDS:=+libsodium +luci-lib-jsonc +unzip +v2ray
LUCI_PKGARCH:=all
PKG_VERSION:=1.0
PKG_RELEASE:=29-20191220
include ../luci_my.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,66 @@
-- Copyright 2018-2019 Lienol <lawlienol@gmail.com>
module("luci.controller.v2ray_server", package.seeall)
local http = require "luci.http"
local v2ray = require "luci.model.cbi.v2ray_server.api.v2ray"
function index()
if not nixio.fs.access("/etc/config/v2ray_server") then return end
entry({"admin", "vpn"}, firstchild(), "VPN", 45).dependent = false
entry({"admin", "vpn", "v2ray_server"}, cbi("v2ray_server/index"),
_("V2ray Server"), 3).dependent = true
entry({"admin", "vpn", "v2ray_server", "config"}, cbi("v2ray_server/config")).leaf =
true
entry({"admin", "vpn", "v2ray_server", "users_status"},
call("v2ray_users_status")).leaf = true
entry({"admin", "vpn", "v2ray_server", "check"}, call("v2ray_check")).leaf =
true
entry({"admin", "vpn", "v2ray_server", "update"}, call("v2ray_update")).leaf =
true
entry({"admin", "vpn", "v2ray_server", "get_log"}, call("get_log")).leaf =
true
entry({"admin", "vpn", "v2ray_server", "clear_log"}, call("clear_log")).leaf =
true
end
local function http_write_json(content)
http.prepare_content("application/json")
http.write_json(content or {code = 1})
end
function v2ray_users_status()
local e = {}
e.index = luci.http.formvalue("index")
e.status = luci.sys.call(
"ps -w| grep -v grep | grep '/var/etc/v2ray_server/" ..
luci.http.formvalue("id") .. "' >/dev/null") == 0
http_write_json(e)
end
function v2ray_check()
local json = v2ray.to_check("")
http_write_json(json)
end
function v2ray_update()
local json = nil
local task = http.formvalue("task")
if task == "extract" then
json =
v2ray.to_extract(http.formvalue("file"), http.formvalue("subfix"))
elseif task == "move" then
json = v2ray.to_move(http.formvalue("file"))
else
json = v2ray.to_download(http.formvalue("url"))
end
http_write_json(json)
end
function get_log()
luci.http.write(luci.sys.exec(
"[ -f '/var/log/v2ray_server/app.log' ] && cat /var/log/v2ray_server/app.log"))
end
function clear_log() luci.sys.call("echo '' > /var/log/v2ray_server/app.log") end

View File

@ -0,0 +1,91 @@
local ucursor = require"luci.model.uci".cursor()
local json = require "luci.jsonc"
local server_section = arg[1]
local server = ucursor:get_all("v2ray_server", server_section)
local settings = nil
if server.protocol == "vmess" then
if server.VMess_id then
local clients = {}
for i = 1, #server.VMess_id do
clients[i] = {
id = server.VMess_id[i],
level = tonumber(server.VMess_level),
alterId = tonumber(server.VMess_alterId)
}
end
settings = {clients = clients}
end
elseif server.protocol == "socks" then
settings = {
auth = "password",
accounts = {
{user = server.socks_username, pass = server.socks_password}
}
}
elseif server.protocol == "shadowsocks" then
settings = {
method = server.ss_method,
password = server.ss_password,
level = tonumber(server.ss_level),
network = server.ss_network,
ota = (server.ss_ota == '1') and true or false
}
end
local v2ray = {
log = {
-- error = "/var/log/v2ray.log",
loglevel = "warning"
},
-- 传入连接
inbound = {
listen = (server.bind_local == "1") and "127.0.0.1" or nil,
port = tonumber(server.port),
protocol = server.protocol,
-- 底层传输配置
settings = settings,
streamSettings = (server.protocol == "vmess") and {
network = server.transport,
security = (server.tls_enable == '1') and "tls" or "none",
tlsSettings = (server.tls_enable == '1') and {
-- serverName = (server.tls_serverName),
allowInsecure = false,
disableSystemRoot = false,
certificates = {
{
certificateFile = server.tls_certificateFile,
keyFile = server.tls_keyFile
}
}
} or nil,
kcpSettings = (server.transport == "mkcp") and {
mtu = tonumber(server.mkcp_mtu),
tti = tonumber(server.mkcp_tti),
uplinkCapacity = tonumber(server.mkcp_uplinkCapacity),
downlinkCapacity = tonumber(server.mkcp_downlinkCapacity),
congestion = (server.mkcp_congestion == "1") and true or false,
readBufferSize = tonumber(server.mkcp_readBufferSize),
writeBufferSize = tonumber(server.mkcp_writeBufferSize),
header = {type = server.mkcp_guise}
} or nil,
wsSettings = (server.transport == "ws") and {
headers = (server.ws_host) and {Host = server.ws_host} or nil,
path = server.ws_path
} or nil,
httpSettings = (server.transport == "h2") and
{path = server.h2_path, host = server.h2_host} or nil,
quicSettings = (server.transport == "quic") and {
security = server.quic_security,
key = server.quic_key,
header = {type = server.quic_guise}
} or nil
} or nil
},
-- 传出连接
outbound = {protocol = "freedom"},
-- 额外传出连接
outboundDetour = {{protocol = "blackhole", tag = "blocked"}}
}
print(json.stringify(v2ray, 1))

View File

@ -0,0 +1,326 @@
module("luci.model.cbi.v2ray_server.api.v2ray", package.seeall)
local fs = require "nixio.fs"
local sys = require "luci.sys"
local uci = require"luci.model.uci".cursor()
local util = require "luci.util"
local i18n = require "luci.i18n"
local ipkg = require "luci.model.ipkg"
local v2ray_api =
"https://api.github.com/repos/v2ray/v2ray-core/releases/latest"
local wget = "/usr/bin/wget"
local wget_args = {
"--no-check-certificate", "--quiet", "--timeout=100", "--tries=3"
}
local curl = "/usr/bin/curl"
local command_timeout = 300
local LEDE_BOARD = nil
local DISTRIB_TARGET = nil
local is_armv7 = false
local function _unpack(t, i)
i = i or 1
if t[i] ~= nil then return t[i], _unpack(t, i + 1) end
end
local function exec(cmd, args, writer, timeout)
local os = require "os"
local nixio = require "nixio"
local fdi, fdo = nixio.pipe()
local pid = nixio.fork()
if pid > 0 then
fdo:close()
if writer or timeout then
local starttime = os.time()
while true do
if timeout and os.difftime(os.time(), starttime) >= timeout then
nixio.kill(pid, nixio.const.SIGTERM)
return 1
end
if writer then
local buffer = fdi:read(2048)
if buffer and #buffer > 0 then
writer(buffer)
end
end
local wpid, stat, code = nixio.waitpid(pid, "nohang")
if wpid and stat == "exited" then return code end
if not writer and timeout then nixio.nanosleep(1) end
end
else
local wpid, stat, code = nixio.waitpid(pid)
return wpid and stat == "exited" and code
end
elseif pid == 0 then
nixio.dup(fdo, nixio.stdout)
fdi:close()
fdo:close()
nixio.exece(cmd, args, nil)
nixio.stdout:close()
os.exit(1)
end
end
local function compare_versions(ver1, comp, ver2)
local table = table
local av1 = util.split(ver1, "[%.%-]", nil, true)
local av2 = util.split(ver2, "[%.%-]", nil, true)
local max = table.getn(av1)
local n2 = table.getn(av2)
if (max < n2) then max = n2 end
for i = 1, max, 1 do
local s1 = av1[i] or ""
local s2 = av2[i] or ""
if comp == "~=" and (s1 ~= s2) then return true end
if (comp == "<" or comp == "<=") and (s1 < s2) then return true end
if (comp == ">" or comp == ">=") and (s1 > s2) then return true end
if (s1 ~= s2) then return false end
end
return not (comp == "<" or comp == ">")
end
local function auto_get_arch()
local arch = nixio.uname().machine or ""
if fs.access("/usr/lib/os-release") then
LEDE_BOARD = sys.exec(
"echo -n `grep 'LEDE_BOARD' /usr/lib/os-release | awk -F '[\\042\\047]' '{print $2}'`")
end
if fs.access("/etc/openwrt_release") then
DISTRIB_TARGET = sys.exec(
"echo -n `grep 'DISTRIB_TARGET' /etc/openwrt_release | awk -F '[\\042\\047]' '{print $2}'`")
end
if arch == "mips" then
if LEDE_BOARD and LEDE_BOARD ~= "" then
if string.match(LEDE_BOARD, "ramips") == "ramips" then
arch = "ramips"
else
arch = sys.exec("echo '" .. LEDE_BOARD ..
"' | grep -oE 'ramips|ar71xx'")
end
elseif DISTRIB_TARGET and DISTRIB_TARGET ~= "" then
if string.match(DISTRIB_TARGET, "ramips") == "ramips" then
arch = "ramips"
else
arch = sys.exec("echo '" .. DISTRIB_TARGET ..
"' | grep -oE 'ramips|ar71xx'")
end
end
end
return util.trim(arch)
end
local function get_file_info(arch)
local file_tree = ""
local sub_version = ""
if arch == "x86_64" then
file_tree = "64"
elseif arch == "aarch64" then
file_tree = "arm64"
elseif arch == "ramips" then
file_tree = "mipsle"
elseif arch == "ar71xx" then
file_tree = "mips"
elseif arch:match("^i[%d]86$") then
file_tree = "32"
elseif arch:match("^armv[5-8]") then
file_tree = "arm"
sub_version = arch:match("[5-8]")
if LEDE_BOARD and string.match(LEDE_BOARD, "bcm53xx") == "bcm53xx" then
sub_version = "5"
elseif DISTRIB_TARGET and string.match(DISTRIB_TARGET, "bcm53xx") ==
"bcm53xx" then
sub_version = "5"
end
sub_version = "5"
if sub_version == "7" then is_armv7 = true end
end
return file_tree, sub_version
end
local function get_api_json(url)
local jsonc = require "luci.jsonc"
local output = {}
-- exec(wget, { "-O-", url, _unpack(wget_args) },
-- function(chunk) output[#output + 1] = chunk end)
-- local json_content = util.trim(table.concat(output))
local json_content = luci.sys.exec(curl .. " -sL " .. url)
if json_content == "" then return {} end
return jsonc.parse(json_content) or {}
end
function get_v2ray_file_path() return "/usr/bin/v2ray" end
function get_v2ray_version()
if get_v2ray_file_path() and get_v2ray_file_path() ~= "" then
if fs.access(get_v2ray_file_path() .. "/v2ray") then
return luci.sys.exec("echo -n `" .. get_v2ray_file_path() ..
"/v2ray -version | awk '{print $2}' | sed -n 1P" ..
"`")
end
end
return ""
end
function to_check(arch)
if not arch or arch == "" then arch = auto_get_arch() end
local file_tree, sub_version = get_file_info(arch)
if file_tree == "" then
return {
code = 1,
error = i18n.translate(
"Can't determine ARCH, or ARCH not supported.")
}
end
local json = get_api_json(v2ray_api)
if json.tag_name == nil then
return {
code = 1,
error = i18n.translate("Get remote version info failed.")
}
end
local remote_version = json.tag_name:match("[^v]+")
local needs_update = compare_versions(get_v2ray_version(), "<",
remote_version)
local html_url, download_url
if needs_update then
html_url = json.html_url
for _, v in ipairs(json.assets) do
if v.name and v.name:match("linux%-" .. file_tree) then
download_url = v.browser_download_url
break
end
end
end
if needs_update and not download_url then
return {
code = 1,
now_version = get_v2ray_version(),
version = remote_version,
html_url = html_url,
error = i18n.translate(
"New version found, but failed to get new version download url.")
}
end
return {
code = 0,
update = needs_update,
now_version = get_v2ray_version(),
version = remote_version,
url = {html = html_url, download = download_url}
}
end
function to_download(url)
if not url or url == "" then
return {code = 1, error = i18n.translate("Download url is required.")}
end
sys.call("/bin/rm -f /tmp/v2ray_download.*")
local tmp_file = util.trim(util.exec("mktemp -u -t v2ray_download.XXXXXX"))
local result = exec(wget, {"-O", tmp_file, url, _unpack(wget_args)}, nil,
command_timeout) == 0
if not result then
exec("/bin/rm", {"-f", tmp_file})
return {
code = 1,
error = i18n.translatef("File download failed or timed out: %s", url)
}
end
return {code = 0, file = tmp_file}
end
function to_extract(file, subfix)
local isinstall_unzip = ipkg.installed("unzip")
if isinstall_unzip == nil then
ipkg.update()
ipkg.install("unzip")
end
if not file or file == "" or not fs.access(file) then
return {code = 1, error = i18n.translate("File path required.")}
end
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
local tmp_dir = util.trim(util.exec("mktemp -d -t v2ray_extract.XXXXXX"))
local output = {}
exec("/usr/bin/unzip", {"-o", file, "-d", tmp_dir},
function(chunk) output[#output + 1] = chunk end)
local files = util.split(table.concat(output))
exec("/bin/rm", {"-f", file})
return {code = 0, file = tmp_dir}
end
function to_move(file)
if not file or file == "" then
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
return {code = 1, error = i18n.translate("Client file is required.")}
end
local client_file = get_v2ray_file_path()
sys.call("mkdir -p " .. client_file)
if not arch or arch == "" then arch = auto_get_arch() end
local file_tree, sub_version = get_file_info(arch)
local result = nil
if is_armv7 and is_armv7 == true then
result = exec("/bin/mv", {
"-f", file .. "/v2ray_armv7", file .. "/v2ctl_armv7", client_file
}, nil, command_timeout) == 0
else
result = exec("/bin/mv",
{"-f", file .. "/v2ray", file .. "/v2ctl", client_file},
nil, command_timeout) == 0
end
if not result or not fs.access(client_file) then
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
return {
code = 1,
error = i18n.translatef("Can't move new file to path: %s",
client_file)
}
end
exec("/bin/chmod", {"-R", "755", client_file})
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
return {code = 0}
end

View File

@ -0,0 +1,220 @@
local app_name = "v2ray_server"
local d = require "luci.dispatcher"
local header_type = {"none", "srtp", "utp", "wechat-video", "dtls", "wireguard"}
map = Map(app_name, "V2ray " .. translate("Server Config"))
map.redirect = d.build_url("admin", "vpn", "v2ray_server")
t = map:section(NamedSection, arg[1], "user", "")
t.addremove = false
t.dynamic = false
enable = t:option(Flag, "enable", translate("Enable"))
enable.default = "1"
enable.rmempty = false
remarks = t:option(Value, "remarks", translate("Remarks"))
remarks.default = translate("Remarks")
remarks.rmempty = false
bind_local = t:option(Flag, "bind_local", translate("Bind Local"), translate(
"When selected, it can only be accessed locally,It is recommended to turn on when using reverse proxies."))
bind_local.default = "0"
bind_local.rmempty = false
port = t:option(Value, "port", translate("Port"))
port.datatype = "port"
port.rmempty = false
protocol = t:option(ListValue, "protocol", translate("Protocol"))
protocol:value("vmess", translate("Vmess"))
protocol:value("socks", translate("Socks"))
protocol:value("shadowsocks", translate("Shadowsocks"))
socks_username = t:option(Value, "socks_username", translate("User name"))
socks_username:depends("protocol", "socks")
socks_password = t:option(Value, "socks_password", translate("Password"))
socks_password.password = true
socks_password:depends("protocol", "socks")
ss_method = t:option(ListValue, "ss_method", translate("Encrypt Method"))
ss_method:value("aes-128-cfb")
ss_method:value("aes-256-cfb")
ss_method:value("aes-128-gcm")
ss_method:value("aes-256-gcm")
ss_method:value("chacha20")
ss_method:value("chacha20-ietf")
ss_method:value("chacha20-poly1305")
ss_method:value("chacha20-ietf-poly1305")
ss_method:depends("protocol", "shadowsocks")
ss_password = t:option(Value, "ss_password", translate("Password"))
ss_password:depends("protocol", "shadowsocks")
ss_level = t:option(Value, "ss_level", translate("User Level"))
ss_level.default = 1
ss_level:depends("protocol", "shadowsocks")
ss_network = t:option(ListValue, "ss_network", translate("Transport"))
ss_network.default = "tcp,udp"
ss_network:value("tcp", "TCP")
ss_network:value("udp", "UDP")
ss_network:value("tcp,udp", "TCP,UDP")
ss_network:depends("protocol", "shadowsocks")
ss_ota = t: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")
VMess_id = t:option(DynamicList, "VMess_id", translate("ID"))
for i = 1, 3 do
local uuid = luci.sys.exec("cat /proc/sys/kernel/random/uuid")
VMess_id:value(uuid)
end
VMess_id:depends("protocol", "vmess")
VMess_alterId = t:option(Value, "VMess_alterId", translate("Alter ID"))
VMess_alterId.default = 16
VMess_alterId:depends("protocol", "vmess")
VMess_level = t:option(Value, "VMess_level", translate("User Level"))
VMess_level.default = 1
VMess_level:depends("protocol", "vmess")
transport = t:option(ListValue, "transport", translate("Transport"))
transport:value("tcp", "TCP")
transport:value("mkcp", "mKCP")
transport:value("ws", "WebSocket")
transport:value("h2", "HTTP/2")
transport:value("quic", "QUIC")
transport:depends("protocol", "vmess")
-- [[ TCP部分 ]]--
-- TCP伪装
tcp_guise = t:option(ListValue, "tcp_guise", translate("Camouflage Type"))
tcp_guise:depends("transport", "tcp")
tcp_guise:value("none", "none")
tcp_guise:value("http", "http")
-- HTTP域名
tcp_guise_http_host = t:option(DynamicList, "tcp_guise_http_host",
translate("HTTP Host"))
tcp_guise_http_host:depends("tcp_guise", "http")
-- HTTP路径
tcp_guise_http_path = t:option(DynamicList, "tcp_guise_http_path",
translate("HTTP Path"))
tcp_guise_http_path:depends("tcp_guise", "http")
-- [[ mKCP部分 ]]--
mkcp_guise = t: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) do mkcp_guise:value(t) end
mkcp_guise:depends("transport", "mkcp")
mkcp_mtu = t:option(Value, "mkcp_mtu", translate("KCP MTU"))
mkcp_mtu:depends("transport", "mkcp")
mkcp_tti = t:option(Value, "mkcp_tti", translate("KCP TTI"))
mkcp_tti:depends("transport", "mkcp")
mkcp_uplinkCapacity = t:option(Value, "mkcp_uplinkCapacity",
translate("KCP uplinkCapacity"))
mkcp_uplinkCapacity:depends("transport", "mkcp")
mkcp_downlinkCapacity = t:option(Value, "mkcp_downlinkCapacity",
translate("KCP downlinkCapacity"))
mkcp_downlinkCapacity:depends("transport", "mkcp")
mkcp_congestion = t:option(Flag, "mkcp_congestion", translate("KCP Congestion"))
mkcp_congestion:depends("transport", "mkcp")
mkcp_readBufferSize = t:option(Value, "mkcp_readBufferSize",
translate("KCP readBufferSize"))
mkcp_readBufferSize:depends("transport", "mkcp")
mkcp_writeBufferSize = t:option(Value, "mkcp_writeBufferSize",
translate("KCP writeBufferSize"))
mkcp_writeBufferSize:depends("transport", "mkcp")
-- [[ WebSocket部分 ]]--
ws_path = t:option(Value, "ws_path", translate("WebSocket Path"))
ws_path:depends("transport", "ws")
ws_host = t:option(Value, "ws_host", translate("WebSocket Host"))
ws_host:depends("transport", "ws")
-- [[ HTTP/2部分 ]]--
h2_path = t:option(Value, "h2_path", translate("HTTP/2 Path"))
h2_path:depends("transport", "h2")
h2_host = t:option(DynamicList, "h2_host", translate("HTTP/2 Host"),
translate("Camouflage Domain,you can not fill in"))
h2_host:depends("transport", "h2")
-- [[ QUIC部分 ]]--
quic_security =
t: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 = t:option(Value, "quic_key",
translate("Encrypt Method") .. translate("Key"))
quic_key:depends("transport", "quic")
quic_guise = t:option(ListValue, "quic_guise", translate("Camouflage Type"))
for a, t in ipairs(header_type) do quic_guise:value(t) end
quic_guise:depends("transport", "quic")
-- [[ TLS部分 ]] --
tls_enable = t:option(Flag, "tls_enable", translate("Use HTTPS"))
tls_enable:depends("transport", "ws")
tls_enable:depends("transport", "h2")
tls_enable.default = "1"
tls_enable.rmempty = false
-- tls_serverName = t:option(Value, "tls_serverName", translate("Domain"))
-- tls_serverName:depends("transport", "ws")
-- tls_serverName:depends("transport", "h2")
tls_certificateFile = t:option(Value, "tls_certificateFile",
translate("Public key absolute path"),
translate("as:") .. "/etc/ssl/fullchain.pem")
tls_certificateFile:depends("tls_enable", 1)
tls_keyFile = t:option(Value, "tls_keyFile",
translate("Private key absolute path"),
translate("as:") .. "/etc/ssl/private.key")
tls_keyFile:depends("tls_enable", 1)
function rmempty_restore()
VMess_id.rmempty = true
VMess_alterId.rmempty = true
socks_username.rmempty = true
socks_password.rmempty = true
ss_password.rmempty = true
ss_ota.rmempty = true
end
protocol.validate = function(self, value)
rmempty_restore()
if value == "vmess" then
VMess_id.rmempty = false
VMess_alterId.rmempty = false
elseif value == "socks" then
socks_username.rmempty = true
socks_password.rmempty = true
elseif value == "shadowsocks" then
ss_password.rmempty = false
ss_ota.rmempty = false
end
return value
end
return map

View File

@ -0,0 +1,105 @@
local i = require "luci.dispatcher"
local e = require "nixio.fs"
local e = require "luci.sys"
local e = luci.model.uci.cursor()
local o = "v2ray_server"
m = Map(o, translate("V2ray Server"))
t = m:section(TypedSection, "global", translate("Global Settings"))
t.anonymous = true
t.addremove = false
e = t:option(Flag, "enable", translate("Enable"))
e.rmempty = false
t:append(Template("v2ray_server/v2ray"))
t = m:section(TypedSection, "user", translate("Users Manager"))
t.anonymous = true
t.addremove = true
t.template = "cbi/tblsection"
t.extedit = i.build_url("admin", "vpn", o, "config", "%s")
function t.create(t, e)
local e = TypedSection.create(t, e)
luci.http.redirect(i.build_url("admin", "vpn", o, "config", e))
end
function t.remove(t, a)
t.map.proceed = true
t.map:del(a)
luci.http.redirect(i.build_url("admin", "vpn", o))
end
e = t:option(Flag, "enable", translate("Enable"))
e.width = "5%"
e.rmempty = false
e = t:option(DummyValue, "status", translate("Status"))
e.template = "v2ray_server/users_status"
e.value = translate("Collecting data...")
e = t:option(DummyValue, "remarks", translate("Remarks"))
e.width = "15%"
e = t:option(DummyValue, "port", translate("Port"))
e.width = "10%"
e = t:option(DummyValue, "protocol", translate("Protocol"))
e.width = "15%"
e.cfgvalue = function(self, section)
local str = "未知"
local protocol = m:get(section, "protocol") or ""
if protocol ~= "" then str = (protocol:gsub("^%l", string.upper)) end
return str
end
e = t:option(DummyValue, "transport", translate("Transport"))
e.width = "10%"
e.cfgvalue = function(self, section)
local t = "未知"
local b = ""
local protocol = m:get(section, "protocol") or ""
if protocol == "vmess" then
b = "transport"
elseif protocol == "shadowsocks" then
b = "ss_network"
end
local a = m:get(section, b) or ""
if a == "tcp" then
t = "TCP"
elseif a == "udp" then
t = "UDP"
elseif a == "tcp,udp" then
t = "TCP,UDP"
elseif a == "mkcp" then
t = "mKCP"
elseif a == "ws" then
t = "WebSocket"
elseif a == "h2" then
t = "HTTP/2"
elseif a == "quic" then
t = "QUIC"
else
t = "TCP,UDP"
end
return t
end
e = t:option(DummyValue, "password", translate("Password"))
e.width = "30%"
e.cfgvalue = function(self, section)
local e = ""
local protocol = m:get(section, "protocol") or ""
if protocol == "vmess" then
e = "VMess_id"
elseif protocol == "shadowsocks" then
e = "ss_password"
elseif protocol == "socks" then
e = "socks_password"
end
local e = m:get(section, e) or ""
local t = ""
if type(e) == "table" then
for a = 1, #e do t = t .. e[a] end
else
t = e
end
return t
end
m:append(Template("v2ray_server/log"))
m:append(Template("v2ray_server/users_list_status"))
return m

View File

@ -0,0 +1,31 @@
<script type="text/javascript">
//<![CDATA[
function clear_log(btn) {
XHR.get('<%=url([[admin]], [[vpn]], [[v2ray_server]], [[clear_log]])%>', null,
function(x, data) {
if(x && x.status == 200) {
var log_textarea = document.getElementById('log_textarea');
log_textarea.innerHTML = "";
log_textarea.scrollTop = log_textarea.scrollHeight;
}
}
);
}
XHR.poll(3, '<%=url([[admin]], [[vpn]], [[v2ray_server]], [[get_log]])%>', null,
function(x, data) {
if(x && x.status == 200) {
var log_textarea = document.getElementById('log_textarea');
log_textarea.innerHTML = x.responseText;
log_textarea.scrollTop = log_textarea.scrollHeight;
}
}
);
//]]>
</script>
<fieldset class="cbi-section" id="_log_fieldset">
<legend>
<%:Logs%>
</legend>
<input class="cbi-button cbi-input-remove" type="button" onclick="clear_log()" value="<%:Clear logs%>">
<textarea id="log_textarea" class="cbi-input-textarea" style="width: 100%;margin-top: 10px;" data-update="change" rows="20" wrap="off" readonly="readonly"></textarea>
</fieldset>

View File

@ -0,0 +1,23 @@
<%
local dsp = require "luci.dispatcher"
-%>
<script type="text/javascript">
//<![CDATA[
var v2ray_users_status = document.getElementsByClassName('v2ray_users_status');
for(var i = 0; i < v2ray_users_status.length; i++) {
var id = v2ray_users_status[i].parentElement.parentElement.parentElement.id;
id = id.substr(id.lastIndexOf("-") + 1);
XHR.poll(1,'<%=dsp.build_url("admin/vpn/v2ray_server/users_status")%>', {
index: i,
id: id
},
function(x, result) {
v2ray_users_status[result.index].setAttribute("style","font-weight:bold;");
v2ray_users_status[result.index].setAttribute("color",result.status ? "green":"red");
v2ray_users_status[result.index].innerHTML = (result.status ? '✓' : 'X');
}
);
}
//]]>
</script>

View File

@ -0,0 +1,3 @@
<%+cbi/valueheader%>
<font class="v2ray_users_status" hint="<%=self:cfgvalue(section)%>">--</font>
<%+cbi/valuefooter%>

View File

@ -0,0 +1,182 @@
<%
local v2ray_version=luci.sys.exec("/usr/bin/v2ray/v2ray -version | awk '{print $2}' | sed -n 1P")
local dsp = require "luci.dispatcher"
-%>
<script type="text/javascript">
//<![CDATA[
var v2rayInfo;
var tokenStr = '<%=token%>';
var noUpdateText = '<%:已是最新版本%>';
var updateSuccessText = '<%:更新成功.%>';
var clickToUpdateText = '<%:点击更新%>';
var inProgressText = '<%:正在更新...%>';
var unexpectedErrorText = '<%:意外错误.%>';
var updateInProgressNotice = '<%:正在更新,你确认要关闭吗?%>';
window.onload = function() {
var v2rayCheckBtn = document.getElementById('_v2ray-check_btn');
var v2rayDetailElm = document.getElementById('_v2ray-check_btn-detail');
};
function addPageNotice_v2ray() {
window.onbeforeunload = function(e) {
e.returnValue = updateInProgressNotice;
return updateInProgressNotice;
};
}
function removePageNotice_v2ray() {
window.onbeforeunload = undefined;
}
function onUpdateSuccess_v2ray(btn) {
alert(updateSuccessText);
if(btn) {
btn.value = updateSuccessText;
btn.placeholder = updateSuccessText;
btn.disabled = true;
}
window.setTimeout(function() {
window.location.reload();
}, 1000);
}
function onRequestError_v2ray(btn, errorMessage) {
btn.disabled = false;
btn.value = btn.placeholder;
if(errorMessage) {
alert(errorMessage);
}
}
function doAjaxGet(url, data, onResult) {
new XHR().get(url, data, function(_, json) {
var resultJson = json || {
'code': 1,
'error': unexpectedErrorText
};
if(typeof onResult === 'function') {
onResult(resultJson);
}
})
}
function onBtnClick_v2ray(btn) {
if(v2rayInfo === undefined) {
checkUpdate_v2ray(btn);
} else {
doUpdate_v2ray(btn);
}
}
function checkUpdate_v2ray(btn) {
btn.disabled = true;
btn.value = inProgressText;
addPageNotice_v2ray();
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
doAjaxGet('<%=dsp.build_url("admin/vpn/v2ray_server/check")%>', {
token: tokenStr,
arch: ''
}, function(json) {
removePageNotice_v2ray();
if(json.code) {
v2rayInfo = undefined;
onRequestError_v2ray(btn, json.error);
} else {
if(json.update) {
v2rayInfo = json;
btn.disabled = false;
btn.value = clickToUpdateText;
btn.placeholder = clickToUpdateText;
if(ckeckDetailElm) {
var urlNode = '';
if(json.version) {
urlNode = '<em style="color:red;">最新版本号:' + json.version + '</em>';
if(json.url && json.url.html) {
urlNode = '<a href="' + json.url.html + '" target="_blank">' + urlNode + '</a>';
}
}
ckeckDetailElm.innerHTML = urlNode;
}
} else {
btn.disabled = true;
btn.value = noUpdateText;
}
}
});
}
function doUpdate_v2ray(btn) {
btn.disabled = true;
btn.value = '<%:下载中...%>';
addPageNotice_v2ray();
var v2rayUpdateUrl = '<%=dsp.build_url("admin/vpn/v2ray_server/update")%>';
// Download file
doAjaxGet(v2rayUpdateUrl, {
token: tokenStr,
url: v2rayInfo ? v2rayInfo.url.download : ''
}, function(json) {
if(json.code) {
removePageNotice_v2ray();
onRequestError_v2ray(btn, json.error);
} else {
btn.value = '<%:解压中...%>';
// Extract file
doAjaxGet(v2rayUpdateUrl, {
token: tokenStr,
task: 'extract',
file: json.file,
subfix: v2rayInfo ? v2rayInfo.type : ''
}, function(json) {
if(json.code) {
removePageNotice_v2ray();
onRequestError_v2ray(btn, json.error);
} else {
btn.value = '<%:移动中...%>';
// Move file to target dir
doAjaxGet(v2rayUpdateUrl, {
token: tokenStr,
task: 'move',
file: json.file
}, function(json) {
removePageNotice_v2ray();
if(json.code) {
onRequestError_v2ray(btn, json.error);
} else {
onUpdateSuccess_v2ray(btn);
}
})
}
})
}
})
}
//]]>
</script>
<div class="cbi-value">
<label class="cbi-value-title">V2ray
<%:Version%>
</label>
<div class="cbi-value-field">
<div class="cbi-value-description">
<span><%=v2ray_version%>】</span>
<input class="cbi-button cbi-input-apply" type="submit" id="_v2ray-check_btn" onclick="onBtnClick_v2ray(this);" value="<%:Manually update%>">
<span id="_v2ray-check_btn-detail"></span>
</div>
</div>
</div>

View File

@ -0,0 +1,137 @@
msgid "V2ray Server"
msgstr "V2ray 服务器"
msgid "Global Settings"
msgstr "全局设置"
msgid "Caddy path"
msgstr "Caddy 路径"
msgid "if you want to run from memory, change the path, such as /tmp/caddy, Then save the application and update it manually."
msgstr "如果你希望从内存中运行,请更改路径,例如/tmp/caddy然后保存应用后再手动更新。"
msgid "Server Config"
msgstr "服务器配置"
msgid "Users Manager"
msgstr "用户管理"
msgid "Remarks"
msgstr "备注"
msgid "Bind Local"
msgstr "本机监听"
msgid "When selected, it can only be accessed locally,It is recommended to turn on when using reverse proxies."
msgstr "当勾选时,只能由本机访问此端口,当开启反向代理时建议勾选此项。"
msgid "Port"
msgstr "端口"
msgid "Password"
msgstr "密码"
msgid "Protocol"
msgstr "协议"
msgid "Null"
msgstr "无"
msgid "Alter ID"
msgstr "额外ID(AlterID)"
msgid "User Level"
msgstr "用户等级(Level)"
msgid "When OTA is enabled, V2Ray will reject connections that are not OTA enabled. This option is invalid when using AEAD encryption."
msgstr "开启 OTA 后V2Ray 会拒绝未启用 OTA 的连接。当使用 AEAD 加密时,该选项无效。"
msgid "Transport"
msgstr "传输方式"
msgid "Camouflage Type"
msgstr "伪装类型"
msgid "Camouflage Domain,you can not fill in"
msgstr "伪装域名,也可以不填写"
msgid "Reverse Proxy"
msgstr "反向代理"
msgid "Reverse Proxy Type"
msgstr "反向代理类型"
msgid "can not has conflict"
msgstr "请不要冲突"
msgid "Use HTTPS"
msgstr "使用HTTPS"
msgid "TLS Settings"
msgstr "TLS配置"
msgid "Nginx does not support HTTP/2 reverse proxies"
msgstr "Nginx 不支持HTTP/2反向代理"
msgid "as:"
msgstr "如:"
msgid "Public key absolute path"
msgstr "公钥文件绝对路径"
msgid "Private key absolute path"
msgstr "私钥文件绝对路径"
msgid "<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)"
msgstr "<br>none默认值不进行伪装发送的数据是没有特征的数据包。<br>srtp伪装成 SRTP 数据包,会被识别为视频通话数据(如 FaceTime。<br>utp伪装成 uTP 数据包,会被识别为 BT 下载数据。<br>wechat-video伪装成微信视频通话的数据包。<br>dtls伪装成 DTLS 1.2 数据包。<br>wireguard伪装成 WireGuard 数据包。(并不是真正的 WireGuard 协议)"
msgid "Logs"
msgstr "日志"
msgid "Clear logs"
msgstr "清空日志"
msgid "Can't determine ARCH, or ARCH not supported."
msgstr "无法确认ARCH架构或是不支持。"
msgid "Get remote version info failed."
msgstr "获取远程版本信息失败。"
msgid "New version found, but failed to get new version download url."
msgstr "发现新版本,但未能获得新版本的下载地址。"
msgid "Download url is required."
msgstr "请指定下载地址。"
msgid "File download failed or timed out: %s"
msgstr "文件下载失败或超时:%s"
msgid "File path required."
msgstr "请指定文件路径。"
msgid "Can't find client in file: %s"
msgstr "无法在文件中找到客户端:%s"
msgid "Client file is required."
msgstr "请指定客户端文件。"
msgid "The client file is not suitable for current device."
msgstr "客户端文件不适合当前设备。"
msgid "Can't move new file to path: %s"
msgstr "无法移动新文件到:%s"
msgid "Enabled"
msgstr "启用"
msgid "Status"
msgstr "状态"
msgid "Current Condition"
msgstr "当前状态"
msgid "NOT RUNNING"
msgstr "未运行"
msgid "RUNNING"
msgstr "运行中"

View File

@ -0,0 +1,45 @@
config global
option enable '0'
config user
option enable '1'
option remarks '备注222'
option bind_local '0'
option protocol 'vmess'
list VMess_id 'fd00927a-b0c2-4629-aef7-d9ff15a9d722'
option VMess_alterId '16'
option VMess_level '1'
option transport 'tcp'
option tcp_guise 'none'
option port '12366'
config user
option enable '1'
option remarks 'WebsocketDemo'
option bind_local '0'
option protocol 'vmess'
option VMess_alterId '16'
option VMess_level '1'
list VMess_id 'fd00927a-b0c2-4629-aef7-d9ff15a9d722'
option transport 'ws'
option ws_path '/websocket'
option tls_enable '1'
option tls_certificateFile '/etc/config/ssl/fullchain.pem'
option tls_keyFile '/etc/config/ssl/private.key'
option port '30010'
config user
option enable '1'
option remarks 'H2Demo'
option bind_local '0'
option protocol 'vmess'
option VMess_alterId '16'
option VMess_level '1'
list VMess_id 'fd00927a-b0c2-4629-aef7-d9ff15a9d722'
option tls_enable '1'
option tls_certificateFile '/etc/config/ssl/fullchain.pem'
option tls_keyFile '/etc/config/ssl/private.key'
option transport 'h2'
option h2_path '/h2'
option port '30011'

View File

@ -0,0 +1,59 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2018-2020 Lienol <lawlienol@gmail.com>
START=99
CONFIG=v2ray_server
CONFIG_PATH=/var/etc/$CONFIG
LOG_PATH=/var/log/$CONFIG
LOG_APP_FILE=$LOG_PATH/app.log
echolog() {
echo -e "$(date "+%Y-%m-%d %H:%M:%S"): $1" >> $LOG_APP_FILE
}
gen_v2ray_config_file() {
config_get enable $1 enable
[ "$enable" = "0" ] && return 0
config_get remarks $1 remarks
config_get port $1 port
config_get transport $1 transport
lua /usr/lib/lua/luci/model/cbi/v2ray_server/api/genv2rayconfig.lua $1 > $CONFIG_PATH/$1.json
echolog "$remarks $port 生成并运行 V2ray 配置文件 - $CONFIG_PATH/$1.json"
/usr/bin/v2ray/v2ray -config $CONFIG_PATH/$1.json >/dev/null 2>&1 &
}
start_v2ray_server() {
mkdir -p $CONFIG_PATH $LOG_PATH
touch $LOG_APP_FILE
caddy_file=$(uci get $CONFIG.@global[0].caddy_file)
config_foreach gen_v2ray_config_file "user"
fw3 reload >/dev/null 2>&1 &
}
stop_v2ray_server() {
fw3 reload >/dev/null 2>&1 &
ps -w | grep "$CONFIG_PATH/" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &
rm -rf $CONFIG_PATH
rm -rf $LOG_PATH
}
start() {
config_load $CONFIG
enable=$(uci get $CONFIG.@global[0].enable)
if [ "$enable" = "0" ];then
stop_v2ray_server
else
start_v2ray_server
fi
}
stop() {
stop_v2ray_server
}
restart() {
stop
sleep 1
start
}

View File

@ -0,0 +1,21 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete firewall.v2ray_server
set firewall.v2ray_server=include
set firewall.v2ray_server.type=script
set firewall.v2ray_server.path=/usr/share/v2ray_server/firewall.include
set firewall.v2ray_server.reload=1
EOF
uci -q batch <<-EOF >/dev/null
delete ucitrack.@v2ray_server[-1]
add ucitrack v2ray_server
set ucitrack.@v2ray_server[-1].init=v2ray_server
commit ucitrack
EOF
chmod a+x /usr/share/v2ray_server/* >/dev/null 2>&1
rm -f /tmp/luci-indexcache
exit 0

View File

@ -0,0 +1,29 @@
#!/bin/sh
. $IPKG_INSTROOT/lib/functions.sh
. $IPKG_INSTROOT/lib/functions/service.sh
gen_user_iptables() {
config_get enable $1 enable
[ "$enable" = "0" ] && return 0
config_get remarks $1 remarks
config_get bind_local $1 bind_local
config_get port $1 port
dport=$port
[ "$bind_local" != "1" ] && {
iptables -A V2RAY-SERVER -p tcp --dport $dport -m comment --comment "$remarks" -j ACCEPT
iptables -A V2RAY-SERVER -p udp --dport $dport -m comment --comment "$remarks" -j ACCEPT
}
}
iptables -F V2RAY-SERVER 2>/dev/null
iptables -D INPUT -j V2RAY-SERVER 2>/dev/null
iptables -X V2RAY-SERVER 2>/dev/null
enable=$(uci get v2ray_server.@global[0].enable)
if [ $enable -eq 1 ]; then
iptables -N V2RAY-SERVER
iptables -I INPUT -j V2RAY-SERVER
config_load v2ray_server
config_foreach gen_user_iptables "user"
fi

View File

@ -0,0 +1,16 @@
# Copyright (C) 2008-2019 Jerrykuku
# Copyright (C) 2019 Lienol
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
LUCI_TITLE:=Argon Mod Theme
LUCI_DEPENDS:=
PKG_VERSION:=1.5
PKG_RELEASE:=08-20191221
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="icomoon" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe20a;" glyph-name="expand_less" d="M512 596.667l256-256-60-60-196 196-196-196-60 60z" />
<glyph unicode="&#xe20b;" glyph-name="expand_more" d="M708 572.667l60-60-256-256-256 256 60 60 196-196z" />
<glyph unicode="&#xe20e;" glyph-name="menu" d="M128 682.667h768v-86h-768v86zM128 384.667v84h768v-84h-768zM128 170.667v86h768v-86h-768z" />
<glyph unicode="&#xe291;" glyph-name="favorite" d="M512 28.667l-62 56q-106 96-154 142t-107 114-81 123-22 113q0 98 67 166t167 68q116 0 192-90 76 90 192 90 100 0 167-68t67-166q0-78-52-162t-113-146-199-186z" />
<glyph unicode="&#xe603;" glyph-name="spinner9" d="M512 960c-278.748 0-505.458-222.762-511.848-499.974 5.92 241.864 189.832 435.974 415.848 435.974 229.75 0 416-200.576 416-448 0-53.020 42.98-96 96-96s96 42.98 96 96c0 282.77-229.23 512-512 512zM512-64c278.748 0 505.458 222.762 511.848 499.974-5.92-241.864-189.832-435.974-415.848-435.974-229.75 0-416 200.576-416 448 0 53.020-42.98 96-96 96s-96-42.98-96-96c0-282.77 229.23-512 512-512z" />
<glyph unicode="&#xf059;" glyph-name="question-circle" horiz-adv-x="878" d="M512 164.571v109.714q0 8-5.143 13.143t-13.143 5.143h-109.714q-8 0-13.143-5.143t-5.143-13.143v-109.714q0-8 5.143-13.143t13.143-5.143h109.714q8 0 13.143 5.143t5.143 13.143zM658.286 548.571q0 50.286-31.714 93.143t-79.143 66.286-97.143 23.429q-138.857 0-212-121.714-8.571-13.714 4.571-24l75.429-57.143q4-3.429 10.857-3.429 9.143 0 14.286 6.857 30.286 38.857 49.143 52.571 19.429 13.714 49.143 13.714 27.429 0 48.857-14.857t21.429-33.714q0-21.714-11.429-34.857t-38.857-25.714q-36-16-66-49.429t-30-71.714v-20.571q0-8 5.143-13.143t13.143-5.143h109.714q8 0 13.143 5.143t5.143 13.143q0 10.857 12.286 28.286t31.143 28.286q18.286 10.286 28 16.286t26.286 20 25.429 27.429 16 34.571 7.143 46.286zM877.714 438.857q0-119.429-58.857-220.286t-159.714-159.714-220.286-58.857-220.286 58.857-159.714 159.714-58.857 220.286 58.857 220.286 159.714 159.714 220.286 58.857 220.286-58.857 159.714-159.714 58.857-220.286z" />
</font></defs></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 24 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,251 @@
/**
* Material is a clean HTML5 theme for LuCI. It is based on luci-theme-bootstrap and MUI
*
* luci-theme-material
* Copyright 2015 Lutty Yang <lutty@wcan.in>
*
* Have a bug? Please create an issue here on GitHub!
* https://github.com/LuttyYang/luci-theme-material/issues
*
* luci-theme-bootstrap:
* Copyright 2008 Steven Barth <steven@midlink.org>
* Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
* Copyright 2012 David Menting <david@nut-bolt.nl>
*
* MUI:
* https://github.com/muicss/mui
*
* Licensed to the public under the Apache License 2.0
*/
(function ($) {
$(".main > .loading").fadeOut();
/**
* trim text, Remove spaces, wrap
* @param text
* @returns {string}
*/
function trimText(text) {
return text.replace(/[ \t\n\r]+/g, " ");
}
var lastNode = undefined;
var mainNodeName = undefined;
var nodeUrl = "";
(function(node){
if (node[0] == "admin"){
luciLocation = [node[1], node[2]];
}else{
luciLocation = node;
}
for(var i in luciLocation){
nodeUrl += luciLocation[i];
if (i != luciLocation.length - 1){
nodeUrl += "/";
}
}
})(luciLocation);
/**
* get the current node by Burl (primary)
* @returns {boolean} success?
*/
function getCurrentNodeByUrl() {
var ret = false;
if (!$('body').hasClass('logged-in')) {
luciLocation = ["Main", "Login"];
return true;
}
$(".main > .main-left > .nav > .slide > .menu").each(function () {
var ulNode = $(this);
ulNode.next().find("a").each(function () {
var that = $(this);
var href = that.attr("href");
if (href.indexOf(nodeUrl) != -1) {
ulNode.click();
ulNode.next(".slide-menu").stop(true, true);
lastNode = that.parent();
lastNode.addClass("active");
ret = true;
return true;
}
});
});
return ret;
}
/**
* menu click
*/
$(".main > .main-left > .nav > .slide > .menu").click(function () {
var ul = $(this).next(".slide-menu");
var menu = $(this);
if (!ul.is(":visible")) {
menu.addClass("active");
ul.addClass("active");
ul.stop(true).slideDown("fast");
} else {
ul.stop(true).slideUp("fast", function () {
menu.removeClass("active");
ul.removeClass("active");
});
}
return false;
});
/**
* hook menu click and add the hash
*/
$(".main > .main-left > .nav > .slide > .slide-menu > li > a").click(function () {
if (lastNode != undefined) lastNode.removeClass("active");
$(this).parent().addClass("active");
$(".main > .loading").fadeIn("fast");
return true;
});
/**
* fix menu click
*/
$(".main > .main-left > .nav > .slide > .slide-menu > li").click(function () {
if (lastNode != undefined) lastNode.removeClass("active");
$(this).addClass("active");
$(".main > .loading").fadeIn("fast");
window.location = $($(this).find("a")[0]).attr("href");
return false;
});
/**
* fix submenu click
*/
$("#maincontent > .container > .tabs > li").click(function () {
console.log("sub");
$(".main > .loading").fadeIn("fast");
window.location = $($(this).find("a")[0]).attr("href");
return false;
});
/**
* get current node and open it
*/
if (getCurrentNodeByUrl()) {
mainNodeName = "node-" + luciLocation[0] + "-" + luciLocation[1];
mainNodeName = mainNodeName.replace(/[ \t\n\r\/]+/g, "_").toLowerCase();
$("body").addClass(mainNodeName);
}
$(".cbi-button-up").val("");
$(".cbi-button-down").val("");
/**
* hook other "A Label" and add hash to it.
*/
$("#maincontent > .container").find("a").each(function () {
var that = $(this);
var href = that.attr("href");
if (href != undefined && href.indexOf("javascript") != -1) {
return true;
}
var onclick = that.attr("onclick");
if (onclick == undefined || onclick == "") {
that.click(function () {
var href = that.attr("href");
if (href.indexOf("#") == -1) {
$(".main > .loading").fadeIn("fast");
return true;
}
});
}
});
/**
* Sidebar expand
*/
var showSide = false;
$(".showSide").click(function () {
if (showSide) {
$(".darkMask").stop(true).fadeOut("fast");
$(".main-left").stop(true).animate({
width: "0"
}, "fast");
$(".main-right").css("overflow-y", "auto");
showSide = false;
} else {
$(".darkMask").stop(true).fadeIn("fast");
$(".main-left").stop(true).animate({
width: "15rem"
}, "fast");
$(".main-right").css("overflow-y", "hidden");
showSide = true;
}
});
$(".darkMask").click(function () {
if (showSide) {
showSide = false;
$(".darkMask").stop(true).fadeOut("fast");
$(".main-left").stop(true).animate({
width: "0"
}, "fast");
$(".main-right").css("overflow-y", "auto");
}
});
$(window).resize(function () {
if ($(window).width() > 921) {
$(".main-left").css("width", "");
$(".darkMask").stop(true);
$(".darkMask").css("display", "none");
showSide = false;
}
});
/**
* fix legend position
*/
$("legend").each(function () {
var that = $(this);
that.after("<span class='panel-title'>" + that.text() + "</span>");
});
/* $(".cbi-section-table-titles, .cbi-section-table-descr, .cbi-section-descr").each(function () {
var that = $(this);
if (that.text().trim() == ""){
that.css("display", "none");
}
}); */
$(".main-right").focus();
$(".main-right").blur();
$("input").attr("size", "0");
if (mainNodeName != undefined) {
console.log(mainNodeName);
switch (mainNodeName) {
case "node-status-system_log":
case "node-status-kernel_log":
$("#syslog").focus(function () {
$("#syslog").blur();
$(".main-right").focus();
$(".main-right").blur();
});
break;
case "node-status-firewall":
var button = $(".node-status-firewall > .main fieldset li > a");
button.addClass("cbi-button cbi-button-reset a-to-btn");
break;
case "node-system-reboot":
var button = $(".node-system-reboot > .main > .main-right p > a");
button.addClass("cbi-button cbi-input-reset a-to-btn");
break;
}
}
})(jQuery);

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="icomoon" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe20a;" glyph-name="expand_less" d="M512 596.667l256-256-60-60-196 196-196-196-60 60z" />
<glyph unicode="&#xe20b;" glyph-name="expand_more" d="M708 572.667l60-60-256-256-256 256 60 60 196-196z" />
<glyph unicode="&#xe20e;" glyph-name="menu" d="M128 682.667h768v-86h-768v86zM128 384.667v84h768v-84h-768zM128 170.667v86h768v-86h-768z" />
<glyph unicode="&#xe291;" glyph-name="favorite" d="M512 28.667l-62 56q-106 96-154 142t-107 114-81 123-22 113q0 98 67 166t167 68q116 0 192-90 76 90 192 90 100 0 167-68t67-166q0-78-52-162t-113-146-199-186z" />
<glyph unicode="&#xe603;" glyph-name="spinner9" d="M512 960c-278.748 0-505.458-222.762-511.848-499.974 5.92 241.864 189.832 435.974 415.848 435.974 229.75 0 416-200.576 416-448 0-53.020 42.98-96 96-96s96 42.98 96 96c0 282.77-229.23 512-512 512zM512-64c278.748 0 505.458 222.762 511.848 499.974-5.92-241.864-189.832-435.974-415.848-435.974-229.75 0-416 200.576-416 448 0 53.020-42.98 96-96 96s-96-42.98-96-96c0-282.77 229.23-512 512-512z" />
<glyph unicode="&#xf059;" glyph-name="question-circle" horiz-adv-x="878" d="M512 164.571v109.714q0 8-5.143 13.143t-13.143 5.143h-109.714q-8 0-13.143-5.143t-5.143-13.143v-109.714q0-8 5.143-13.143t13.143-5.143h109.714q8 0 13.143 5.143t5.143 13.143zM658.286 548.571q0 50.286-31.714 93.143t-79.143 66.286-97.143 23.429q-138.857 0-212-121.714-8.571-13.714 4.571-24l75.429-57.143q4-3.429 10.857-3.429 9.143 0 14.286 6.857 30.286 38.857 49.143 52.571 19.429 13.714 49.143 13.714 27.429 0 48.857-14.857t21.429-33.714q0-21.714-11.429-34.857t-38.857-25.714q-36-16-66-49.429t-30-71.714v-20.571q0-8 5.143-13.143t13.143-5.143h109.714q8 0 13.143 5.143t5.143 13.143q0 10.857 12.286 28.286t31.143 28.286q18.286 10.286 28 16.286t26.286 20 25.429 27.429 16 34.571 7.143 46.286zM877.714 438.857q0-119.429-58.857-220.286t-159.714-159.714-220.286-58.857-220.286 58.857-159.714 159.714-58.857 220.286 58.857 220.286 159.714 159.714 220.286 58.857 220.286-58.857 159.714-159.714 58.857-220.286z" />
</font></defs></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 24 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,251 @@
/**
* Material is a clean HTML5 theme for LuCI. It is based on luci-theme-bootstrap and MUI
*
* luci-theme-material
* Copyright 2015 Lutty Yang <lutty@wcan.in>
*
* Have a bug? Please create an issue here on GitHub!
* https://github.com/LuttyYang/luci-theme-material/issues
*
* luci-theme-bootstrap:
* Copyright 2008 Steven Barth <steven@midlink.org>
* Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
* Copyright 2012 David Menting <david@nut-bolt.nl>
*
* MUI:
* https://github.com/muicss/mui
*
* Licensed to the public under the Apache License 2.0
*/
(function ($) {
$(".main > .loading").fadeOut();
/**
* trim text, Remove spaces, wrap
* @param text
* @returns {string}
*/
function trimText(text) {
return text.replace(/[ \t\n\r]+/g, " ");
}
var lastNode = undefined;
var mainNodeName = undefined;
var nodeUrl = "";
(function(node){
if (node[0] == "admin"){
luciLocation = [node[1], node[2]];
}else{
luciLocation = node;
}
for(var i in luciLocation){
nodeUrl += luciLocation[i];
if (i != luciLocation.length - 1){
nodeUrl += "/";
}
}
})(luciLocation);
/**
* get the current node by Burl (primary)
* @returns {boolean} success?
*/
function getCurrentNodeByUrl() {
var ret = false;
if (!$('body').hasClass('logged-in')) {
luciLocation = ["Main", "Login"];
return true;
}
$(".main > .main-left > .nav > .slide > .menu").each(function () {
var ulNode = $(this);
ulNode.next().find("a").each(function () {
var that = $(this);
var href = that.attr("href");
if (href.indexOf(nodeUrl) != -1) {
ulNode.click();
ulNode.next(".slide-menu").stop(true, true);
lastNode = that.parent();
lastNode.addClass("active");
ret = true;
return true;
}
});
});
return ret;
}
/**
* menu click
*/
$(".main > .main-left > .nav > .slide > .menu").click(function () {
var ul = $(this).next(".slide-menu");
var menu = $(this);
if (!ul.is(":visible")) {
menu.addClass("active");
ul.addClass("active");
ul.stop(true).slideDown("fast");
} else {
ul.stop(true).slideUp("fast", function () {
menu.removeClass("active");
ul.removeClass("active");
});
}
return false;
});
/**
* hook menu click and add the hash
*/
$(".main > .main-left > .nav > .slide > .slide-menu > li > a").click(function () {
if (lastNode != undefined) lastNode.removeClass("active");
$(this).parent().addClass("active");
$(".main > .loading").fadeIn("fast");
return true;
});
/**
* fix menu click
*/
$(".main > .main-left > .nav > .slide > .slide-menu > li").click(function () {
if (lastNode != undefined) lastNode.removeClass("active");
$(this).addClass("active");
$(".main > .loading").fadeIn("fast");
window.location = $($(this).find("a")[0]).attr("href");
return false;
});
/**
* fix submenu click
*/
$("#maincontent > .container > .tabs > li").click(function () {
console.log("sub");
$(".main > .loading").fadeIn("fast");
window.location = $($(this).find("a")[0]).attr("href");
return false;
});
/**
* get current node and open it
*/
if (getCurrentNodeByUrl()) {
mainNodeName = "node-" + luciLocation[0] + "-" + luciLocation[1];
mainNodeName = mainNodeName.replace(/[ \t\n\r\/]+/g, "_").toLowerCase();
$("body").addClass(mainNodeName);
}
$(".cbi-button-up").val("");
$(".cbi-button-down").val("");
/**
* hook other "A Label" and add hash to it.
*/
$("#maincontent > .container").find("a").each(function () {
var that = $(this);
var href = that.attr("href");
if (href != undefined && href.indexOf("javascript") != -1) {
return true;
}
var onclick = that.attr("onclick");
if (onclick == undefined || onclick == "") {
that.click(function () {
var href = that.attr("href");
if (href.indexOf("#") == -1) {
$(".main > .loading").fadeIn("fast");
return true;
}
});
}
});
/**
* Sidebar expand
*/
var showSide = false;
$(".showSide").click(function () {
if (showSide) {
$(".darkMask").stop(true).fadeOut("fast");
$(".main-left").stop(true).animate({
width: "0"
}, "fast");
$(".main-right").css("overflow-y", "auto");
showSide = false;
} else {
$(".darkMask").stop(true).fadeIn("fast");
$(".main-left").stop(true).animate({
width: "15rem"
}, "fast");
$(".main-right").css("overflow-y", "hidden");
showSide = true;
}
});
$(".darkMask").click(function () {
if (showSide) {
showSide = false;
$(".darkMask").stop(true).fadeOut("fast");
$(".main-left").stop(true).animate({
width: "0"
}, "fast");
$(".main-right").css("overflow-y", "auto");
}
});
$(window).resize(function () {
if ($(window).width() > 921) {
$(".main-left").css("width", "");
$(".darkMask").stop(true);
$(".darkMask").css("display", "none");
showSide = false;
}
});
/**
* fix legend position
*/
$("legend").each(function () {
var that = $(this);
that.after("<span class='panel-title'>" + that.text() + "</span>");
});
/* $(".cbi-section-table-titles, .cbi-section-table-descr, .cbi-section-descr").each(function () {
var that = $(this);
if (that.text().trim() == ""){
that.css("display", "none");
}
}); */
$(".main-right").focus();
$(".main-right").blur();
$("input").attr("size", "0");
if (mainNodeName != undefined) {
console.log(mainNodeName);
switch (mainNodeName) {
case "node-status-system_log":
case "node-status-kernel_log":
$("#syslog").focus(function () {
$("#syslog").blur();
$(".main-right").focus();
$(".main-right").blur();
});
break;
case "node-status-firewall":
var button = $(".node-status-firewall > .main fieldset li > a");
button.addClass("cbi-button cbi-button-reset a-to-btn");
break;
case "node-system-reboot":
var button = $(".node-system-reboot > .main > .main-right p > a");
button.addClass("cbi-button cbi-input-reset a-to-btn");
break;
}
}
})(jQuery);

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@ -0,0 +1,7 @@
/*!
Pure v1.0.1
Copyright 2013 Yahoo!
Licensed under the BSD License.
https://github.com/pure-css/pure/blob/master/LICENSE.md
*/
.pure-g{letter-spacing:-.31em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-flow:row wrap;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-align-content:flex-start;-ms-flex-line-pack:start;align-content:flex-start}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){table .pure-g{display:block}}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u,.pure-u-1,.pure-u-1-1,.pure-u-1-12,.pure-u-1-2,.pure-u-1-24,.pure-u-1-3,.pure-u-1-4,.pure-u-1-5,.pure-u-1-6,.pure-u-1-8,.pure-u-10-24,.pure-u-11-12,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-2-24,.pure-u-2-3,.pure-u-2-5,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24,.pure-u-3-24,.pure-u-3-4,.pure-u-3-5,.pure-u-3-8,.pure-u-4-24,.pure-u-4-5,.pure-u-5-12,.pure-u-5-24,.pure-u-5-5,.pure-u-5-6,.pure-u-5-8,.pure-u-6-24,.pure-u-7-12,.pure-u-7-24,.pure-u-7-8,.pure-u-8-24,.pure-u-9-24{display:inline-block;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class*=pure-u]{font-family:sans-serif}.pure-u-1-24{width:4.1667%}.pure-u-1-12,.pure-u-2-24{width:8.3333%}.pure-u-1-8,.pure-u-3-24{width:12.5%}.pure-u-1-6,.pure-u-4-24{width:16.6667%}.pure-u-1-5{width:20%}.pure-u-5-24{width:20.8333%}.pure-u-1-4,.pure-u-6-24{width:25%}.pure-u-7-24{width:29.1667%}.pure-u-1-3,.pure-u-8-24{width:33.3333%}.pure-u-3-8,.pure-u-9-24{width:37.5%}.pure-u-2-5{width:40%}.pure-u-10-24,.pure-u-5-12{width:41.6667%}.pure-u-11-24{width:45.8333%}.pure-u-1-2,.pure-u-12-24{width:50%}.pure-u-13-24{width:54.1667%}.pure-u-14-24,.pure-u-7-12{width:58.3333%}.pure-u-3-5{width:60%}.pure-u-15-24,.pure-u-5-8{width:62.5%}.pure-u-16-24,.pure-u-2-3{width:66.6667%}.pure-u-17-24{width:70.8333%}.pure-u-18-24,.pure-u-3-4{width:75%}.pure-u-19-24{width:79.1667%}.pure-u-4-5{width:80%}.pure-u-20-24,.pure-u-5-6{width:83.3333%}.pure-u-21-24,.pure-u-7-8{width:87.5%}.pure-u-11-12,.pure-u-22-24{width:91.6667%}.pure-u-23-24{width:95.8333%}.pure-u-1,.pure-u-1-1,.pure-u-24-24,.pure-u-5-5{width:100%}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="icomoon" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe20a;" glyph-name="expand_less" d="M512 596.667l256-256-60-60-196 196-196-196-60 60z" />
<glyph unicode="&#xe20b;" glyph-name="expand_more" d="M708 572.667l60-60-256-256-256 256 60 60 196-196z" />
<glyph unicode="&#xe20e;" glyph-name="menu" d="M128 682.667h768v-86h-768v86zM128 384.667v84h768v-84h-768zM128 170.667v86h768v-86h-768z" />
<glyph unicode="&#xe291;" glyph-name="favorite" d="M512 28.667l-62 56q-106 96-154 142t-107 114-81 123-22 113q0 98 67 166t167 68q116 0 192-90 76 90 192 90 100 0 167-68t67-166q0-78-52-162t-113-146-199-186z" />
<glyph unicode="&#xe603;" glyph-name="spinner9" d="M512 960c-278.748 0-505.458-222.762-511.848-499.974 5.92 241.864 189.832 435.974 415.848 435.974 229.75 0 416-200.576 416-448 0-53.020 42.98-96 96-96s96 42.98 96 96c0 282.77-229.23 512-512 512zM512-64c278.748 0 505.458 222.762 511.848 499.974-5.92-241.864-189.832-435.974-415.848-435.974-229.75 0-416 200.576-416 448 0 53.020-42.98 96-96 96s-96-42.98-96-96c0-282.77 229.23-512 512-512z" />
<glyph unicode="&#xf059;" glyph-name="question-circle" horiz-adv-x="878" d="M512 164.571v109.714q0 8-5.143 13.143t-13.143 5.143h-109.714q-8 0-13.143-5.143t-5.143-13.143v-109.714q0-8 5.143-13.143t13.143-5.143h109.714q8 0 13.143 5.143t5.143 13.143zM658.286 548.571q0 50.286-31.714 93.143t-79.143 66.286-97.143 23.429q-138.857 0-212-121.714-8.571-13.714 4.571-24l75.429-57.143q4-3.429 10.857-3.429 9.143 0 14.286 6.857 30.286 38.857 49.143 52.571 19.429 13.714 49.143 13.714 27.429 0 48.857-14.857t21.429-33.714q0-21.714-11.429-34.857t-38.857-25.714q-36-16-66-49.429t-30-71.714v-20.571q0-8 5.143-13.143t13.143-5.143h109.714q8 0 13.143 5.143t5.143 13.143q0 10.857 12.286 28.286t31.143 28.286q18.286 10.286 28 16.286t26.286 20 25.429 27.429 16 34.571 7.143 46.286zM877.714 438.857q0-119.429-58.857-220.286t-159.714-159.714-220.286-58.857-220.286 58.857-159.714 159.714-58.857 220.286 58.857 220.286 159.714 159.714 220.286 58.857 220.286-58.857 159.714-159.714 58.857-220.286z" />
</font></defs></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="icomoon" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe900;" glyph-name="angle-right" d="M704.6 414l-272-272c-18.8-18.8-49.2-18.8-67.8 0l-45.2 45.2c-18.8 18.8-18.8 49.2 0 67.8l192.8 192.8-192.8 192.8c-18.8 18.8-18.8 49.2 0 67.8l45 45.6c18.8 18.8 49.2 18.8 67.8 0l272-272c19-18.8 19-49.2 0.2-68z" />
<glyph unicode="&#xe901;" glyph-name="password_unlock" d="M196.923 603.569v0zM827.077 507.077h-512v92.554c0 104.369 78.769 196.923 183.138 202.831 96.492 5.908 177.231-55.138 202.831-141.785 1.969-7.877 9.846-15.754 19.692-15.754h80.738c11.815 0 21.662 11.815 19.692 23.631-31.508 149.662-165.415 259.938-324.923 252.062-167.385-7.877-295.385-151.631-299.323-317.046v-96.492c-43.323 0-78.769-35.446-78.769-78.769v-374.154c0-43.323 35.446-78.769 78.769-78.769h630.154c43.323 0 78.769 35.446 78.769 78.769v374.154c0 43.323-35.446 78.769-78.769 78.769zM602.585 119.138c3.938-11.815-5.908-25.6-19.692-25.6h-143.754c-13.785 0-23.631 11.815-19.692 25.6l35.446 118.154c-29.538 19.692-47.262 55.138-39.385 94.523 7.877 37.415 37.415 66.954 76.8 74.831 63.015 11.815 118.154-33.477 118.154-92.554 0-31.508-15.754-61.046-41.354-76.8l33.477-118.154z" />
</font></defs></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,288 @@
/**
* Argon is a clean HTML5 theme for LuCI. It is based on luci-theme-material and Argon Template
*
* luci-theme-argon
* Copyright 2019 Jerrykuku <jerrykuku@qq.com>
*
* Have a bug? Please create an issue here on GitHub!
* https://github.com/jerrykuku/luci-theme-argon/issues
*
* luci-theme-bootstrap:
* Copyright 2008 Steven Barth <steven@midlink.org>
* Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
* Copyright 2012 David Menting <david@nut-bolt.nl>
*
* MUI:
* https://github.com/muicss/mui
*
* luci-theme-material:
* https://github.com/LuttyYang/luci-theme-material/
*
* Agron Theme
* https://demos.creative-tim.com/argon-dashboard/index.html
*
* Login background
* https://unsplash.com/
*
* Licensed to the public under the Apache License 2.0
*/
/*
* Font generate by Icomoon<icomoon.io>
*/
(function ($) {
$(".main > .loading").hide();
$(".main > .loading").fadeOut();
/**
* trim text, Remove spaces, wrap
* @param text
* @returns {string}
*/
function trimText(text) {
return text.replace(/[ \t\n\r]+/g, " ");
}
var lastNode = undefined;
var mainNodeName = undefined;
var nodeUrl = "";
(function (node) {
if (node[0] == "admin") {
luciLocation = [node[1], node[2]];
} else {
luciLocation = node;
}
for (var i in luciLocation) {
nodeUrl += luciLocation[i];
if (i != luciLocation.length - 1) {
nodeUrl += "/";
}
}
})(luciLocation);
/**
* get the current node by Burl (primary)
* @returns {boolean} success?
*/
function getCurrentNodeByUrl() {
var ret = false;
if (!$('body').hasClass('logged-in')) {
luciLocation = ["Main", "Login"];
return true;
}
$(".main > .main-left > .nav > .slide > .active").next(".slide-menu").stop(true).slideUp("fast");
$(".main > .main-left > .nav > .slide > .menu").removeClass("active");
$(".main > .main-left > .nav > .slide > .menu").each(function () {
var ulNode = $(this);
ulNode.next().find("a").each(function () {
var that = $(this);
var href = that.attr("href");
if (href.indexOf(nodeUrl) != -1) {
ulNode.click();
ulNode.next(".slide-menu").stop(true, true);
lastNode = that.parent();
lastNode.addClass("active");
ret = true;
return true;
}
});
});
return ret;
}
/**
* menu click
*/
$(".main > .main-left > .nav > .slide > .menu").click(function () {
var ul = $(this).next(".slide-menu");
var menu = $(this);
if (!menu.hasClass("exit")) {
$(".main > .main-left > .nav > .slide > .active").next(".slide-menu").stop(true).slideUp("fast");
$(".main > .main-left > .nav > .slide > .menu").removeClass("active");
if (!ul.is(":visible")) {
menu.addClass("active");
ul.addClass("active");
ul.stop(true).slideDown("fast");
} else {
ul.stop(true).slideUp("fast", function () {
menu.removeClass("active");
ul.removeClass("active");
});
}
return false;
}
});
// define what element should be observed by the observer
// and what types of mutations trigger the callback
if ($("#cbi-dhcp-lan-ignore").length > 0) {
observer.observe(document.getElementById("cbi-dhcp-lan-ignore"), {
subtree: true,
attributes: true
});
}
/**
* hook menu click and add the hash
*/
$(".main > .main-left > .nav > .slide > .slide-menu > li > a").click(function () {
if (lastNode != undefined)
lastNode.removeClass("active");
$(this).parent().addClass("active");
$(".main > .loading").fadeIn("fast");
return true;
});
/**
* fix menu click
*/
$(".main > .main-left > .nav > .slide > .slide-menu > li").click(function () {
if (lastNode != undefined)
lastNode.removeClass("active");
$(this).addClass("active");
$(".main > .loading").fadeIn("fast");
window.location = $($(this).find("a")[0]).attr("href");
return false;
});
/**
* fix submenu click
*/
$("#maincontent > .container > .tabs > li").click(function () {
$(".main > .loading").fadeIn("fast");
window.location = $($(this).find("a")[0]).attr("href");
return false;
});
/**
* get current node and open it
*/
if (getCurrentNodeByUrl()) {
mainNodeName = "node-" + luciLocation[0] + "-" + luciLocation[1];
mainNodeName = mainNodeName.replace(/[ \t\n\r\/]+/g, "_").toLowerCase();
$("body").addClass(mainNodeName);
}
$(".cbi-button-up").val("");
$(".cbi-button-down").val("");
/**
* hook other "A Label" and add hash to it.
*/
$("#maincontent > .container").find("a").each(function () {
var that = $(this);
var onclick = that.attr("onclick");
if (onclick == undefined || onclick == "") {
that.click(function () {
var href = that.attr("href");
if (href.indexOf("#") == -1) {
$(".main > .loading").fadeIn("fast");
return true;
}
});
}
});
/**
* Sidebar expand
*/
var showSide = false;
$(".showSide").click(function () {
if (showSide) {
$(".darkMask").stop(true).fadeOut("fast");
$(".main-left").stop(true).animate({
width: "0"
}, "fast");
$(".main-right").css("overflow-y", "auto");
showSide = false;
} else {
$(".darkMask").stop(true).fadeIn("fast");
$(".main-left").stop(true).animate({
width: "15rem"
}, "fast");
$(".main-right").css("overflow-y", "hidden");
showSide = true;
}
});
$(".darkMask").click(function () {
if (showSide) {
showSide = false;
$(".darkMask").stop(true).fadeOut("fast");
$(".main-left").stop(true).animate({
width: "0"
}, "fast");
$(".main-right").css("overflow-y", "auto");
}
});
$(window).resize(function () {
if ($(window).width() > 921) {
$(".main-left").css("width", "");
$(".darkMask").stop(true);
$(".darkMask").css("display", "none");
showSide = false;
}
});
/**
* fix legend position
*/
$("legend").each(function () {
var that = $(this);
that.after("<span class='panel-title'>" + that.text() + "</span>");
});
$(".cbi-section-table-titles, .cbi-section-table-descr, .cbi-section-descr").each(function () {
var that = $(this);
if (that.text().trim() == "") {
that.css("display", "none");
}
});
$(".node-main-login > .main .cbi-value.cbi-value-last .cbi-input-text").focus(function () {
//$(".node-main-login > .main > .main-right > .login-bg").addClass("blur");
});
$(".node-main-login > .main .cbi-value.cbi-value-last .cbi-input-text").blur(function () {
//$(".node-main-login > .main > .main-right > .login-bg").removeClass("blur");
});
$(".main-right").focus();
$(".main-right").blur();
$("input").attr("size", "0");
if (mainNodeName != undefined) {
console.log(mainNodeName);
switch (mainNodeName) {
case "node-status-system_log":
case "node-status-kernel_log":
$("#syslog").focus(function () {
$("#syslog").blur();
$(".main-right").focus();
$(".main-right").blur();
});
break;
case "node-status-firewall":
var button = $(".node-status-firewall > .main fieldset li > a");
button.addClass("cbi-button cbi-button-reset a-to-btn");
break;
case "node-system-reboot":
var button = $(".node-system-reboot > .main > .main-right p > a");
button.addClass("cbi-button cbi-input-reset a-to-btn");
break;
}
}
})(jQuery);

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Some files were not shown because too many files have changed in this diff Show More