mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-02 18:03:56 +08:00
⛅ Sync 2026-08-09 20:41:06
This commit is contained in:
1 parent
80095dfd81
commit
dcd5055a31
14 files changed
+196
-88
No files matched your search
+1
-1
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=gecoosac
|
PKG_NAME:=gecoosac
|
||||||
PKG_VERSION:=2.2.20251015
|
PKG_VERSION:=2.2.20251015
|
||||||
PKG_RELEASE:=18
|
PKG_RELEASE:=19
|
||||||
|
|
||||||
PKG_MAINTAINER:=Roc Lai <laipeng668@qq.com>
|
PKG_MAINTAINER:=Roc Lai <laipeng668@qq.com>
|
||||||
PKG_LICENSE:=AGPL-3.0-only
|
PKG_LICENSE:=AGPL-3.0-only
|
||||||
|
|||||||
@@ -86,6 +86,29 @@ normalize_path() {
|
|||||||
printf '%s\n' "$normalized"
|
printf '%s\n' "$normalized"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
path_uses_clear_stage() {
|
||||||
|
local path="$1" resolved
|
||||||
|
|
||||||
|
path="$(normalize_path "$path")" || return 1
|
||||||
|
case "$path" in
|
||||||
|
/.gecoosac-clear.*|/.gecoosac-clear.*/*|*/.gecoosac-clear.*|*/.gecoosac-clear.*/*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -e "$1" ] || [ -L "$1" ]; then
|
||||||
|
resolved="$(readlink -f "$1" 2>/dev/null)" || return 1
|
||||||
|
resolved="$(normalize_path "$resolved")" || return 1
|
||||||
|
case "$resolved" in
|
||||||
|
/.gecoosac-clear.*|/.gecoosac-clear.*/*|*/.gecoosac-clear.*|*/.gecoosac-clear.*/*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
is_safe_upload_dir() {
|
is_safe_upload_dir() {
|
||||||
local path physical
|
local path physical
|
||||||
|
|
||||||
@@ -468,12 +491,20 @@ normalize_conf() {
|
|||||||
logger -t gecoosac "refusing unsupported upload directory: $upload_dir"
|
logger -t gecoosac "refusing unsupported upload directory: $upload_dir"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
if path_uses_clear_stage "$upload_dir"; then
|
||||||
|
logger -t gecoosac "refusing reserved upload cleanup stage path: $upload_dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
if is_safe_db_dir "$db_dir" "$upload_dir"; then
|
if is_safe_db_dir "$db_dir" "$upload_dir"; then
|
||||||
db_dir="$(normalize_path "$db_dir")"
|
db_dir="$(normalize_path "$db_dir")"
|
||||||
else
|
else
|
||||||
logger -t gecoosac "refusing unsupported database directory: $db_dir"
|
logger -t gecoosac "refusing unsupported database directory: $db_dir"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
if path_uses_clear_stage "$db_dir"; then
|
||||||
|
logger -t gecoosac "refusing reserved upload cleanup stage path: $db_dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
if [ "$isonlyoneprot" = "0" ] && [ "$https" = "1" ]; then
|
if [ "$isonlyoneprot" = "0" ] && [ "$https" = "1" ]; then
|
||||||
is_abs_path "$crt_file" || {
|
is_abs_path "$crt_file" || {
|
||||||
logger -t gecoosac "refusing non-absolute certificate path: $crt_file"
|
logger -t gecoosac "refusing non-absolute certificate path: $crt_file"
|
||||||
@@ -483,6 +514,10 @@ normalize_conf() {
|
|||||||
logger -t gecoosac "refusing non-absolute key path: $key_file"
|
logger -t gecoosac "refusing non-absolute key path: $key_file"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
if path_uses_clear_stage "$crt_file" || path_uses_clear_stage "$key_file"; then
|
||||||
|
logger -t gecoosac "refusing reserved upload cleanup stage certificate path"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
if is_safe_pid_dir "$piddir" "$upload_dir"; then
|
if is_safe_pid_dir "$piddir" "$upload_dir"; then
|
||||||
piddir="$(normalize_path "$piddir")"
|
piddir="$(normalize_path "$piddir")"
|
||||||
@@ -490,6 +525,10 @@ normalize_conf() {
|
|||||||
logger -t gecoosac "refusing unsupported PID directory: $piddir"
|
logger -t gecoosac "refusing unsupported PID directory: $piddir"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
if path_uses_clear_stage "$piddir"; then
|
||||||
|
logger -t gecoosac "refusing reserved upload cleanup stage path: $piddir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
is_port "$port" || {
|
is_port "$port" || {
|
||||||
logger -t gecoosac "refusing invalid interface port: $port"
|
logger -t gecoosac "refusing invalid interface port: $port"
|
||||||
return 1
|
return 1
|
||||||
@@ -659,8 +698,16 @@ start_prepared_service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
start_service() {
|
start_service() {
|
||||||
prepare_service || exit 1
|
service_prepare_failed=0
|
||||||
start_prepared_service
|
if ! prepare_service; then
|
||||||
|
service_prepare_failed=1
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
start_prepared_service || service_prepare_failed=1
|
||||||
|
}
|
||||||
|
|
||||||
|
service_started() {
|
||||||
|
[ "${service_prepare_failed:-0}" = "0" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
service_running_state() {
|
service_running_state() {
|
||||||
@@ -709,7 +756,7 @@ wait_service_stopped() {
|
|||||||
state="$?"
|
state="$?"
|
||||||
case "$state" in
|
case "$state" in
|
||||||
0) return 0 ;;
|
0) return 0 ;;
|
||||||
1)
|
1|2)
|
||||||
[ "$i" -ge 5 ] && return 1
|
[ "$i" -ge 5 ] && return 1
|
||||||
sleep 1
|
sleep 1
|
||||||
i=$((i + 1))
|
i=$((i + 1))
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=luci-app-gecoosac
|
PKG_NAME:=luci-app-gecoosac
|
||||||
PKG_VERSION:=2.2
|
PKG_VERSION:=2.2
|
||||||
PKG_RELEASE:=18
|
PKG_RELEASE:=19
|
||||||
|
|
||||||
LUCI_TITLE:=LuCI Support for gecoosac
|
LUCI_TITLE:=LuCI Support for gecoosac
|
||||||
LUCI_DEPENDS:=+luci-base +gecoosac +gecoosac-files
|
LUCI_DEPENDS:=+luci-base +gecoosac +gecoosac-files
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ const DEFAULT_PID_DIR = '/var/run';
|
|||||||
const CONFIG_BACKUP_DIR = '/etc/gecoosac';
|
const CONFIG_BACKUP_DIR = '/etc/gecoosac';
|
||||||
const DB_DIR_PREFIXES = [ '/etc/gecoosac', '/tmp/gecoosac', '/var/lib/gecoosac' ];
|
const DB_DIR_PREFIXES = [ '/etc/gecoosac', '/tmp/gecoosac', '/var/lib/gecoosac' ];
|
||||||
const PID_DIR_PREFIXES = [ '/var/run', '/tmp/gecoosac' ];
|
const PID_DIR_PREFIXES = [ '/var/run', '/tmp/gecoosac' ];
|
||||||
|
const CLEAR_STAGE_PATH_ERROR = _('Paths under .gecoosac-clear.* are reserved for upload cleanup.');
|
||||||
|
|
||||||
let statusPollRegistered = false;
|
let statusPollRegistered = false;
|
||||||
|
|
||||||
@@ -92,7 +93,12 @@ function validateCertificatePath(section_id, value, singlePortOption, httpsOptio
|
|||||||
if (singlePortOption.formvalue(section_id) !== '0' || httpsOption.formvalue(section_id) !== '1' || !value)
|
if (singlePortOption.formvalue(section_id) !== '0' || httpsOption.formvalue(section_id) !== '1' || !value)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return String(value).charAt(0) === '/' ? true : _('Expecting an absolute path');
|
if (String(value).charAt(0) !== '/')
|
||||||
|
return _('Expecting an absolute path');
|
||||||
|
|
||||||
|
return usesClearStagePath(value)
|
||||||
|
? CLEAR_STAGE_PATH_ERROR
|
||||||
|
: true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function triggerActiveValidation(section_id, options) {
|
function triggerActiveValidation(section_id, options) {
|
||||||
@@ -134,6 +140,17 @@ function normalizePath(value) {
|
|||||||
return '/' + parts.join('/');
|
return '/' + parts.join('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function usesClearStagePath(value) {
|
||||||
|
const path = normalizePath(value);
|
||||||
|
const segments = path === null ? [] : path.split('/');
|
||||||
|
|
||||||
|
for (const segment of segments)
|
||||||
|
if (segment.indexOf('.gecoosac-clear.') === 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function managedPath(value, policy) {
|
function managedPath(value, policy) {
|
||||||
const path = normalizePath(value);
|
const path = normalizePath(value);
|
||||||
|
|
||||||
@@ -247,14 +264,14 @@ function clientHost() {
|
|||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clientUrl() {
|
function clientUrl(status) {
|
||||||
const singlePort = uci.get('gecoosac', 'config', 'isonlyoneprot') !== '0';
|
const protocol = status && status.protocol;
|
||||||
const https = uci.get('gecoosac', 'config', 'https') === '1';
|
const port = validPort(status && status.port, null);
|
||||||
const port = singlePort
|
|
||||||
? validPort(uci.get('gecoosac', 'config', 'port'), '60650')
|
|
||||||
: validPort(uci.get('gecoosac', 'config', 'm_port'), '8080');
|
|
||||||
|
|
||||||
return (singlePort || !https ? 'http://' : 'https://') + clientHost() + ':' + port;
|
if ((protocol === 'http' || protocol === 'https') && port !== null)
|
||||||
|
return protocol + '://' + clientHost() + ':' + port;
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderStatusContent(status) {
|
function renderStatusContent(status) {
|
||||||
@@ -263,12 +280,13 @@ function renderStatusContent(status) {
|
|||||||
(RPC_ERROR_MESSAGES[status.error] || _('Unable to query service status')));
|
(RPC_ERROR_MESSAGES[status.error] || _('Unable to query service status')));
|
||||||
|
|
||||||
const running = serviceRunning(status);
|
const running = serviceRunning(status);
|
||||||
|
const url = running ? clientUrl(status) : null;
|
||||||
const text = running
|
const text = running
|
||||||
? _('The GecoosAC service is running.')
|
? _('The GecoosAC service is running.')
|
||||||
: _('The GecoosAC service is not running.');
|
: _('The GecoosAC service is not running.');
|
||||||
const state = E('span', { 'class': running ? 'gecoosac-running' : 'gecoosac-stopped' }, text);
|
const state = E('span', { 'class': running ? 'gecoosac-running' : 'gecoosac-stopped' }, text);
|
||||||
|
|
||||||
if (!running)
|
if (!running || !url)
|
||||||
return E('p', {}, state);
|
return E('p', {}, state);
|
||||||
|
|
||||||
return E('p', {}, [
|
return E('p', {}, [
|
||||||
@@ -276,7 +294,7 @@ function renderStatusContent(status) {
|
|||||||
E('button', {
|
E('button', {
|
||||||
'class': 'cbi-button cbi-button-reload',
|
'class': 'cbi-button cbi-button-reload',
|
||||||
'click': function() {
|
'click': function() {
|
||||||
const client = window.open(clientUrl(), '_blank', 'noopener');
|
const client = window.open(url, '_blank', 'noopener');
|
||||||
if (client)
|
if (client)
|
||||||
client.opener = null;
|
client.opener = null;
|
||||||
}
|
}
|
||||||
@@ -442,6 +460,8 @@ return view.extend({
|
|||||||
o.validate = function(section_id, value) {
|
o.validate = function(section_id, value) {
|
||||||
if (usesManagedPath(value) && !pathPolicy)
|
if (usesManagedPath(value) && !pathPolicy)
|
||||||
return _('Unable to validate /var paths on this system.');
|
return _('Unable to validate /var paths on this system.');
|
||||||
|
if (usesClearStagePath(value))
|
||||||
|
return CLEAR_STAGE_PATH_ERROR;
|
||||||
|
|
||||||
return validUploadDir(value, pathPolicy)
|
return validUploadDir(value, pathPolicy)
|
||||||
? true
|
? true
|
||||||
@@ -458,6 +478,8 @@ return view.extend({
|
|||||||
const uploadDir = uploadDirOption.formvalue(section_id) || DEFAULT_UPLOAD_DIR;
|
const uploadDir = uploadDirOption.formvalue(section_id) || DEFAULT_UPLOAD_DIR;
|
||||||
if ((usesManagedPath(value) || usesManagedPath(uploadDir)) && !pathPolicy)
|
if ((usesManagedPath(value) || usesManagedPath(uploadDir)) && !pathPolicy)
|
||||||
return _('Unable to validate /var paths on this system.');
|
return _('Unable to validate /var paths on this system.');
|
||||||
|
if (usesClearStagePath(value))
|
||||||
|
return CLEAR_STAGE_PATH_ERROR;
|
||||||
|
|
||||||
if (!validPathPrefix(value, DB_DIR_PREFIXES))
|
if (!validPathPrefix(value, DB_DIR_PREFIXES))
|
||||||
return _('Database directory must be under /etc/gecoosac, /tmp/gecoosac, or /var/lib/gecoosac.');
|
return _('Database directory must be under /etc/gecoosac, /tmp/gecoosac, or /var/lib/gecoosac.');
|
||||||
@@ -477,6 +499,8 @@ return view.extend({
|
|||||||
const uploadDir = uploadDirOption.formvalue(section_id) || DEFAULT_UPLOAD_DIR;
|
const uploadDir = uploadDirOption.formvalue(section_id) || DEFAULT_UPLOAD_DIR;
|
||||||
if ((usesManagedPath(value) || usesManagedPath(uploadDir)) && !pathPolicy)
|
if ((usesManagedPath(value) || usesManagedPath(uploadDir)) && !pathPolicy)
|
||||||
return _('Unable to validate /var paths on this system.');
|
return _('Unable to validate /var paths on this system.');
|
||||||
|
if (usesClearStagePath(value))
|
||||||
|
return CLEAR_STAGE_PATH_ERROR;
|
||||||
|
|
||||||
if (!validPathPrefix(value, PID_DIR_PREFIXES))
|
if (!validPathPrefix(value, PID_DIR_PREFIXES))
|
||||||
return _('PID directory must be under /var/run or /tmp/gecoosac.');
|
return _('PID directory must be under /var/run or /tmp/gecoosac.');
|
||||||
|
|||||||
@@ -193,6 +193,9 @@ msgstr "无法验证上传目录清理暂存区"
|
|||||||
msgid "Upload cleanup stage contains a configured protected path"
|
msgid "Upload cleanup stage contains a configured protected path"
|
||||||
msgstr "上传目录清理暂存区包含已配置的受保护路径"
|
msgstr "上传目录清理暂存区包含已配置的受保护路径"
|
||||||
|
|
||||||
|
msgid "Paths under .gecoosac-clear.* are reserved for upload cleanup."
|
||||||
|
msgstr ".gecoosac-clear.* 下的路径保留用于上传目录清理。"
|
||||||
|
|
||||||
msgid "Unable to recreate upload directory"
|
msgid "Unable to recreate upload directory"
|
||||||
msgstr "无法重新创建上传目录"
|
msgstr "无法重新创建上传目录"
|
||||||
|
|
||||||
|
|||||||
@@ -193,6 +193,9 @@ msgstr "無法驗證上傳目錄清理暫存區"
|
|||||||
msgid "Upload cleanup stage contains a configured protected path"
|
msgid "Upload cleanup stage contains a configured protected path"
|
||||||
msgstr "上傳目錄清理暫存區包含已設定的受保護路徑"
|
msgstr "上傳目錄清理暫存區包含已設定的受保護路徑"
|
||||||
|
|
||||||
|
msgid "Paths under .gecoosac-clear.* are reserved for upload cleanup."
|
||||||
|
msgstr ".gecoosac-clear.* 下的路徑保留供上傳目錄清理使用。"
|
||||||
|
|
||||||
msgid "Unable to recreate upload directory"
|
msgid "Unable to recreate upload directory"
|
||||||
msgstr "無法重新建立上傳目錄"
|
msgstr "無法重新建立上傳目錄"
|
||||||
|
|
||||||
|
|||||||
@@ -243,20 +243,78 @@ configured_path_in_upload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
status_result() {
|
status_result() {
|
||||||
local ok="$1" running="$2" message="$3"
|
local ok="$1" running="$2" message="$3" protocol="$4" port="$5"
|
||||||
|
|
||||||
json_init
|
json_init
|
||||||
json_add_boolean ok "$ok"
|
json_add_boolean ok "$ok"
|
||||||
json_add_boolean running "$running"
|
json_add_boolean running "$running"
|
||||||
[ -n "$message" ] && json_add_string error "$message"
|
[ -n "$message" ] && json_add_string error "$message"
|
||||||
|
[ -n "$protocol" ] && json_add_string protocol "$protocol"
|
||||||
|
[ -n "$port" ] && json_add_string port "$port"
|
||||||
json_dump
|
json_dump
|
||||||
json_cleanup
|
json_cleanup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runtime_endpoint() {
|
||||||
|
local keys key argument pending interface_port management_port
|
||||||
|
local single_port https_enabled
|
||||||
|
|
||||||
|
status_protocol=http
|
||||||
|
status_port=
|
||||||
|
pending=
|
||||||
|
interface_port=
|
||||||
|
management_port=
|
||||||
|
single_port=1
|
||||||
|
https_enabled=0
|
||||||
|
|
||||||
|
json_select command 2>/dev/null || return 1
|
||||||
|
json_get_keys keys
|
||||||
|
for key in $keys; do
|
||||||
|
json_get_var argument "$key"
|
||||||
|
if [ -n "$pending" ]; then
|
||||||
|
case "$pending" in
|
||||||
|
interface) interface_port="$argument" ;;
|
||||||
|
management) management_port="$argument" ;;
|
||||||
|
single) single_port="$argument" ;;
|
||||||
|
https) https_enabled="$argument" ;;
|
||||||
|
esac
|
||||||
|
pending=
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$argument" in
|
||||||
|
-p) pending=interface ;;
|
||||||
|
-mp) pending=management ;;
|
||||||
|
-isonlyoneprot) pending=single ;;
|
||||||
|
-https) pending=https ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
json_select ..
|
||||||
|
|
||||||
|
case "$single_port" in
|
||||||
|
0)
|
||||||
|
[ -n "$management_port" ] || return 1
|
||||||
|
status_port="$management_port"
|
||||||
|
[ "$https_enabled" = "1" ] && status_protocol=https
|
||||||
|
;;
|
||||||
|
1)
|
||||||
|
status_port="$interface_port"
|
||||||
|
;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$status_port" in
|
||||||
|
""|*[!0-9]*) return 1 ;;
|
||||||
|
esac
|
||||||
|
[ "$status_port" -ge 1 ] 2>/dev/null && [ "$status_port" -le 65535 ]
|
||||||
|
}
|
||||||
|
|
||||||
service_status() {
|
service_status() {
|
||||||
local data instances instance running state
|
local data instances instance running state status_protocol status_port
|
||||||
|
|
||||||
running=0
|
running=0
|
||||||
|
status_protocol=
|
||||||
|
status_port=
|
||||||
data="$(ubus call service list '{"name":"gecoosac"}' 2>/dev/null)" || {
|
data="$(ubus call service list '{"name":"gecoosac"}' 2>/dev/null)" || {
|
||||||
status_result 0 0 "Unable to query service status"
|
status_result 0 0 "Unable to query service status"
|
||||||
return
|
return
|
||||||
@@ -272,17 +330,18 @@ service_status() {
|
|||||||
for instance in $instances; do
|
for instance in $instances; do
|
||||||
json_select "$instance" 2>/dev/null || continue
|
json_select "$instance" 2>/dev/null || continue
|
||||||
json_get_var state running
|
json_get_var state running
|
||||||
json_select ..
|
|
||||||
if [ "$state" = "1" ]; then
|
if [ "$state" = "1" ]; then
|
||||||
running=1
|
running=1
|
||||||
|
runtime_endpoint
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
|
json_select ..
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
json_cleanup
|
json_cleanup
|
||||||
status_result 1 "$running"
|
status_result 1 "$running" "" "$status_protocol" "$status_port"
|
||||||
}
|
}
|
||||||
|
|
||||||
path_policy() {
|
path_policy() {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=luci-app-passwall2
|
PKG_NAME:=luci-app-passwall2
|
||||||
PKG_VERSION:=26.8.7
|
PKG_VERSION:=26.8.7
|
||||||
PKG_RELEASE:=73
|
PKG_RELEASE:=74
|
||||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||||
|
|
||||||
PKG_CONFIG_DEPENDS:= \
|
PKG_CONFIG_DEPENDS:= \
|
||||||
|
|||||||
@@ -24,24 +24,16 @@ for k, e in ipairs(api.get_valid_nodes()) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
local dynamicList_write = function(self, section, value)
|
local dynamicList_write = function(self, section, value)
|
||||||
local t = {}
|
local new_t = {}
|
||||||
local t2 = {}
|
|
||||||
if type(value) == "table" then
|
if type(value) == "table" then
|
||||||
local x
|
new_t = api.table_remove_duplicates(value)
|
||||||
for _, x in ipairs(value) do
|
|
||||||
if x and #x > 0 then
|
|
||||||
if not t2[x] then
|
|
||||||
t2[x] = x
|
|
||||||
t[#t+1] = x
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
t = { value }
|
new_t = { value }
|
||||||
end
|
end
|
||||||
t = table.concat(t, " ")
|
local new_val = table.concat(new_t, " ")
|
||||||
return DynamicList.write(self, section, t)
|
return DynamicList.write(self, section, new_val)
|
||||||
end
|
end
|
||||||
|
|
||||||
local doh_validate = function(self, value, t)
|
local doh_validate = function(self, value, t)
|
||||||
if value ~= "" then
|
if value ~= "" then
|
||||||
local flag = 0
|
local flag = 0
|
||||||
|
|||||||
@@ -168,23 +168,14 @@ source.validate = function(self, value, t)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local dynamicList_write = function(self, section, value)
|
local dynamicList_write = function(self, section, value)
|
||||||
local t = {}
|
local new_t = {}
|
||||||
local t2 = {}
|
|
||||||
if type(value) == "table" then
|
if type(value) == "table" then
|
||||||
local x
|
new_t = api.table_remove_duplicates(value)
|
||||||
for _, x in ipairs(value) do
|
|
||||||
if x and #x > 0 then
|
|
||||||
if not t2[x] then
|
|
||||||
t2[x] = x
|
|
||||||
t[#t+1] = x
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
t = { value }
|
new_t = { value }
|
||||||
end
|
end
|
||||||
t = table.concat(t, " ")
|
local new_val = table.concat(new_t, " ")
|
||||||
return DynamicList.write(self, section, t)
|
return DynamicList.write(self, section, new_val)
|
||||||
end
|
end
|
||||||
|
|
||||||
source.write = dynamicList_write
|
source.write = dynamicList_write
|
||||||
|
|||||||
@@ -534,22 +534,13 @@ o:value("TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256")
|
|||||||
o:value("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")
|
o:value("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")
|
||||||
o:depends({ [_n("tls")] = true, [_n("reality")] = false })
|
o:depends({ [_n("tls")] = true, [_n("reality")] = false })
|
||||||
function o.custom_write(self, section, value)
|
function o.custom_write(self, section, value)
|
||||||
local t = {}
|
local new_t
|
||||||
local t2 = {}
|
|
||||||
if type(value) == "table" then
|
if type(value) == "table" then
|
||||||
local x
|
new_t = api.table_remove_duplicates(value)
|
||||||
for _, x in ipairs(value) do
|
|
||||||
if x and #x > 0 then
|
|
||||||
if not t2[x] then
|
|
||||||
t2[x] = x
|
|
||||||
t[#t+1] = x
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
t = { value }
|
new_t = { value }
|
||||||
end
|
end
|
||||||
m:set(section, self.option:sub(1 + #option_prefix), t)
|
m:set(section, self.option:sub(1 + #option_prefix), new_t)
|
||||||
end
|
end
|
||||||
|
|
||||||
o = s:option(TextValue, _n("reality_mldsa65Verify"), "ML-DSA-65 " .. translate("Public key"))
|
o = s:option(TextValue, _n("reality_mldsa65Verify"), "ML-DSA-65 " .. translate("Public key"))
|
||||||
|
|||||||
@@ -590,22 +590,13 @@ o:value("TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256")
|
|||||||
o:value("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")
|
o:value("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")
|
||||||
o:depends({ [_n("tls")] = true })
|
o:depends({ [_n("tls")] = true })
|
||||||
function o.custom_write(self, section, value)
|
function o.custom_write(self, section, value)
|
||||||
local t = {}
|
local new_t
|
||||||
local t2 = {}
|
|
||||||
if type(value) == "table" then
|
if type(value) == "table" then
|
||||||
local x
|
new_t = api.table_remove_duplicates(value)
|
||||||
for _, x in ipairs(value) do
|
|
||||||
if x and #x > 0 then
|
|
||||||
if not t2[x] then
|
|
||||||
t2[x] = x
|
|
||||||
t[#t+1] = x
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
t = { value }
|
new_t = { value }
|
||||||
end
|
end
|
||||||
m:set(section, self.option:sub(1 + #option_prefix), t)
|
m:set(section, self.option:sub(1 + #option_prefix), new_t)
|
||||||
end
|
end
|
||||||
|
|
||||||
o = s:option(Flag, _n("ech"), translate("ECH"))
|
o = s:option(Flag, _n("ech"), translate("ECH"))
|
||||||
|
|||||||
@@ -218,23 +218,14 @@ o:depends({ [_n("reality")] = true })
|
|||||||
|
|
||||||
o = s:option(DynamicList, _n("reality_serverNames"), translate("serverNames"))
|
o = s:option(DynamicList, _n("reality_serverNames"), translate("serverNames"))
|
||||||
o:depends({ [_n("reality")] = true })
|
o:depends({ [_n("reality")] = true })
|
||||||
function o.write(self, section, value)
|
function o.custom_write(self, section, value)
|
||||||
local t = {}
|
local new_t = {}
|
||||||
local t2 = {}
|
|
||||||
if type(value) == "table" then
|
if type(value) == "table" then
|
||||||
local x
|
new_t = api.table_remove_duplicates(value)
|
||||||
for _, x in ipairs(value) do
|
|
||||||
if x and #x > 0 then
|
|
||||||
if not t2[x] then
|
|
||||||
t2[x] = x
|
|
||||||
t[#t+1] = x
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
t = { value }
|
new_t = { value }
|
||||||
end
|
end
|
||||||
return DynamicList.write(self, section, t)
|
m:set(section, self.option:sub(1 + #option_prefix), new_t)
|
||||||
end
|
end
|
||||||
|
|
||||||
o = s:option(ListValue, _n("alpn"), translate("alpn"))
|
o = s:option(ListValue, _n("alpn"), translate("alpn"))
|
||||||
|
|||||||
@@ -1863,3 +1863,19 @@ function get_network_devices()
|
|||||||
table.sort(_devices, function(a, b) return a.sort < b.sort end)
|
table.sort(_devices, function(a, b) return a.sort < b.sort end)
|
||||||
return _devices
|
return _devices
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function table_remove_duplicates(t)
|
||||||
|
if not t or #t == 0 then return nil end
|
||||||
|
local t_lookup = {}
|
||||||
|
local new_t = {}
|
||||||
|
local x
|
||||||
|
for _, x in ipairs(t) do
|
||||||
|
if x and #x > 0 then
|
||||||
|
if not t_lookup[x] then
|
||||||
|
t_lookup[x] = x
|
||||||
|
new_t[#new_t+1] = x
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return new_t
|
||||||
|
end
|
||||||
Reference in new issue
Block a user