Add proxy parameter filters for URLTest and Priority
This commit is contained in:
+567
-447
File diff suppressed because it is too large
Load Diff
+518
-446
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: FORKOP\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-12 00:20+0300\n"
|
||||
"PO-Revision-Date: 2026-07-12 00:20+0300\n"
|
||||
"POT-Creation-Date: 2026-07-13 03:22+0300\n"
|
||||
"PO-Revision-Date: 2026-07-13 03:22+0300\n"
|
||||
"Last-Translator: ushan0v\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: ru\n"
|
||||
@@ -80,6 +80,12 @@ msgstr "Добавьте URL или локальные пути к списка
|
||||
msgid "Additional marking rules found"
|
||||
msgstr "Найдены дополнительные правила маркировки"
|
||||
|
||||
msgid "Additionally exclude servers by protocol, transport, and security. Exclude only servers matching the specified parameters."
|
||||
msgstr "Дополнительно исключать серверы по протоколу, транспорту и защите. Исключать только серверы, совпавшие по указанным параметрам."
|
||||
|
||||
msgid "Additionally filter servers by protocol, transport, and security. Add only servers matching the specified parameters."
|
||||
msgstr "Дополнительно отбирать серверы по протоколу, транспорту и защите. Добавлять только серверы, совпавшие по указанным параметрам."
|
||||
|
||||
msgid "Address"
|
||||
msgstr "Адрес"
|
||||
|
||||
@@ -482,6 +488,15 @@ msgstr "Не тестировать серверы из этих стран."
|
||||
msgid "Do not test servers whose names match the expression."
|
||||
msgstr "Не тестировать серверы, имена которых совпадают с выражением."
|
||||
|
||||
msgid "Do not test servers with one of the selected protocols."
|
||||
msgstr "Не тестировать серверы с одним из выбранных протоколов."
|
||||
|
||||
msgid "Do not test servers with one of the selected security types."
|
||||
msgstr "Не тестировать серверы с одним из выбранных типов защиты."
|
||||
|
||||
msgid "Do not test servers with one of the selected transports."
|
||||
msgstr "Не тестировать серверы с одним из выбранных транспортов."
|
||||
|
||||
msgid "Do not test specified servers."
|
||||
msgstr "Не тестировать указанные серверы."
|
||||
|
||||
@@ -605,6 +620,9 @@ msgstr "HWID, который будет отправляться при запр
|
||||
msgid "Enter the subscription URL"
|
||||
msgstr "Введите URL подписки"
|
||||
|
||||
msgid "Exclude by proxy parameters"
|
||||
msgstr "Исключить по параметрам прокси"
|
||||
|
||||
msgid "Exclude by regular expression"
|
||||
msgstr "Исключить по регулярному выражению"
|
||||
|
||||
@@ -620,6 +638,15 @@ msgstr "Исключите трафик протокола NTP из туннел
|
||||
msgid "Exclude servers"
|
||||
msgstr "Исключить серверы"
|
||||
|
||||
msgid "Exclude servers with one of the selected protocols from this level."
|
||||
msgstr "Исключить из этого уровня серверы с одним из выбранных протоколов."
|
||||
|
||||
msgid "Exclude servers with one of the selected security types from this level."
|
||||
msgstr "Исключить из этого уровня серверы с одним из выбранных типов защиты."
|
||||
|
||||
msgid "Exclude servers with one of the selected transports from this level."
|
||||
msgstr "Исключить из этого уровня серверы с одним из выбранных транспортов."
|
||||
|
||||
msgid "Expecting: %s"
|
||||
msgstr "Ожидается: %s"
|
||||
|
||||
@@ -839,6 +866,9 @@ msgstr "Inbound JSON не может быть пустым"
|
||||
msgid "Inbound JSON must be an object with a type field"
|
||||
msgstr "Inbound JSON должен быть объектом с полем type"
|
||||
|
||||
msgid "Include by proxy parameters"
|
||||
msgstr "Включить по параметрам прокси"
|
||||
|
||||
msgid "Include by regular expression"
|
||||
msgstr "Включить по регулярному выражению"
|
||||
|
||||
@@ -1316,6 +1346,15 @@ msgstr "Только выбранные, кроме исключений"
|
||||
msgid "Only servers whose names match the expression."
|
||||
msgstr "Только серверы, имена которых соответствуют выражению."
|
||||
|
||||
msgid "Only servers with one of the selected protocols."
|
||||
msgstr "Только серверы с одним из выбранных протоколов."
|
||||
|
||||
msgid "Only servers with one of the selected security types."
|
||||
msgstr "Только серверы с одним из выбранных типов защиты."
|
||||
|
||||
msgid "Only servers with one of the selected transports."
|
||||
msgstr "Только серверы с одним из выбранных транспортов."
|
||||
|
||||
msgid "Only the specified servers."
|
||||
msgstr "Только указанные серверы."
|
||||
|
||||
@@ -1841,6 +1880,15 @@ msgstr "Тестирование задержки"
|
||||
msgid "Test only selected servers."
|
||||
msgstr "Тестировать только выбранные серверы."
|
||||
|
||||
msgid "Test only servers with one of the selected protocols."
|
||||
msgstr "Тестировать только серверы с одним из выбранных протоколов."
|
||||
|
||||
msgid "Test only servers with one of the selected security types."
|
||||
msgstr "Тестировать только серверы с одним из выбранных типов защиты."
|
||||
|
||||
msgid "Test only servers with one of the selected transports."
|
||||
msgstr "Тестировать только серверы с одним из выбранных транспортов."
|
||||
|
||||
msgid "Test servers only from the specified countries."
|
||||
msgstr "Тестировать серверы только из указанных стран."
|
||||
|
||||
|
||||
@@ -715,6 +715,26 @@ function urltest_include_regex(section, value) {
|
||||
list_value(section, "urltest_include_regex"));
|
||||
}
|
||||
|
||||
function urltest_include_proxy_parameters(section, value) {
|
||||
let child = urltest_child(section, value);
|
||||
return child != null ? child_bool(child, "include_proxy_parameters", false) : false;
|
||||
}
|
||||
|
||||
function urltest_include_protocols(section, value) {
|
||||
let child = urltest_child(section, value);
|
||||
return child != null ? child_list(child, "include_protocols", []) : [];
|
||||
}
|
||||
|
||||
function urltest_include_transports(section, value) {
|
||||
let child = urltest_child(section, value);
|
||||
return child != null ? child_list(child, "include_transports", []) : [];
|
||||
}
|
||||
|
||||
function urltest_include_securities(section, value) {
|
||||
let child = urltest_child(section, value);
|
||||
return child != null ? child_list(child, "include_securities", []) : [];
|
||||
}
|
||||
|
||||
function urltest_exclude_countries(section, value) {
|
||||
let child = urltest_child(section, value);
|
||||
if (child != null)
|
||||
@@ -739,6 +759,26 @@ function urltest_exclude_regex(section, value) {
|
||||
list_value(section, "urltest_exclude_regex"));
|
||||
}
|
||||
|
||||
function urltest_exclude_proxy_parameters(section, value) {
|
||||
let child = urltest_child(section, value);
|
||||
return child != null ? child_bool(child, "exclude_proxy_parameters", false) : false;
|
||||
}
|
||||
|
||||
function urltest_exclude_protocols(section, value) {
|
||||
let child = urltest_child(section, value);
|
||||
return child != null ? child_list(child, "exclude_protocols", []) : [];
|
||||
}
|
||||
|
||||
function urltest_exclude_transports(section, value) {
|
||||
let child = urltest_child(section, value);
|
||||
return child != null ? child_list(child, "exclude_transports", []) : [];
|
||||
}
|
||||
|
||||
function urltest_exclude_securities(section, value) {
|
||||
let child = urltest_child(section, value);
|
||||
return child != null ? child_list(child, "exclude_securities", []) : [];
|
||||
}
|
||||
|
||||
function priority_group_display_name(section, value) {
|
||||
let child = priority_group_child(section, value);
|
||||
return child != null ? child_option(child, "name", as_string(value)) : as_string(value);
|
||||
@@ -829,6 +869,26 @@ function priority_level_include_regex(group_id, value) {
|
||||
return child != null ? child_list_alias(child, [ "include_regex", "regex" ], []) : [];
|
||||
}
|
||||
|
||||
function priority_level_include_proxy_parameters(group_id, value) {
|
||||
let child = priority_level_child(group_id, value);
|
||||
return child != null ? child_bool(child, "include_proxy_parameters", false) : false;
|
||||
}
|
||||
|
||||
function priority_level_include_protocols(group_id, value) {
|
||||
let child = priority_level_child(group_id, value);
|
||||
return child != null ? child_list(child, "include_protocols", []) : [];
|
||||
}
|
||||
|
||||
function priority_level_include_transports(group_id, value) {
|
||||
let child = priority_level_child(group_id, value);
|
||||
return child != null ? child_list(child, "include_transports", []) : [];
|
||||
}
|
||||
|
||||
function priority_level_include_securities(group_id, value) {
|
||||
let child = priority_level_child(group_id, value);
|
||||
return child != null ? child_list(child, "include_securities", []) : [];
|
||||
}
|
||||
|
||||
function priority_level_exclude_countries(group_id, value) {
|
||||
let child = priority_level_child(group_id, value);
|
||||
return child != null ? child_list(child, "exclude_countries", []) : [];
|
||||
@@ -844,6 +904,26 @@ function priority_level_exclude_regex(group_id, value) {
|
||||
return child != null ? child_list(child, "exclude_regex", []) : [];
|
||||
}
|
||||
|
||||
function priority_level_exclude_proxy_parameters(group_id, value) {
|
||||
let child = priority_level_child(group_id, value);
|
||||
return child != null ? child_bool(child, "exclude_proxy_parameters", false) : false;
|
||||
}
|
||||
|
||||
function priority_level_exclude_protocols(group_id, value) {
|
||||
let child = priority_level_child(group_id, value);
|
||||
return child != null ? child_list(child, "exclude_protocols", []) : [];
|
||||
}
|
||||
|
||||
function priority_level_exclude_transports(group_id, value) {
|
||||
let child = priority_level_child(group_id, value);
|
||||
return child != null ? child_list(child, "exclude_transports", []) : [];
|
||||
}
|
||||
|
||||
function priority_level_exclude_securities(group_id, value) {
|
||||
let child = priority_level_child(group_id, value);
|
||||
return child != null ? child_list(child, "exclude_securities", []) : [];
|
||||
}
|
||||
|
||||
function priority_level_countries(group_id, value) {
|
||||
return priority_level_include_countries(group_id, value);
|
||||
}
|
||||
@@ -958,9 +1038,17 @@ return {
|
||||
urltest_include_countries,
|
||||
urltest_include_outbounds,
|
||||
urltest_include_regex,
|
||||
urltest_include_proxy_parameters,
|
||||
urltest_include_protocols,
|
||||
urltest_include_transports,
|
||||
urltest_include_securities,
|
||||
urltest_exclude_countries,
|
||||
urltest_exclude_outbounds,
|
||||
urltest_exclude_regex,
|
||||
urltest_exclude_proxy_parameters,
|
||||
urltest_exclude_protocols,
|
||||
urltest_exclude_transports,
|
||||
urltest_exclude_securities,
|
||||
priority_groups,
|
||||
priority_group_settings,
|
||||
priority_levels,
|
||||
@@ -982,9 +1070,17 @@ return {
|
||||
priority_level_include_countries,
|
||||
priority_level_include_outbounds,
|
||||
priority_level_include_regex,
|
||||
priority_level_include_proxy_parameters,
|
||||
priority_level_include_protocols,
|
||||
priority_level_include_transports,
|
||||
priority_level_include_securities,
|
||||
priority_level_exclude_countries,
|
||||
priority_level_exclude_outbounds,
|
||||
priority_level_exclude_regex,
|
||||
priority_level_exclude_proxy_parameters,
|
||||
priority_level_exclude_protocols,
|
||||
priority_level_exclude_transports,
|
||||
priority_level_exclude_securities,
|
||||
priority_level_countries,
|
||||
priority_level_outbounds,
|
||||
priority_level_regex,
|
||||
|
||||
@@ -1047,6 +1047,27 @@ function validate_detect_server_country_value(value, section) {
|
||||
fail_validation("Invalid server country detection mode '" + value + "' in rule '" + section + "'. Aborted.");
|
||||
}
|
||||
|
||||
function validate_proxy_parameter_value(value, allowed, parameter, section) {
|
||||
value = lc(as_string(value));
|
||||
if (value == "" || contains(allowed, value))
|
||||
return;
|
||||
|
||||
fail_validation("Invalid proxy " + parameter + " '" + value + "' in rule '" + section + "'. Aborted.");
|
||||
}
|
||||
|
||||
function validate_proxy_parameter_filters(protocols, transports, securities, section) {
|
||||
for (let value in protocols)
|
||||
validate_proxy_parameter_value(value,
|
||||
[ "direct", "http", "hysteria2", "shadowsocks", "socks", "trojan", "vless", "vmess" ],
|
||||
"protocol", section);
|
||||
for (let value in transports)
|
||||
validate_proxy_parameter_value(value,
|
||||
[ "tcp", "ws", "grpc", "http", "httpupgrade", "xhttp" ],
|
||||
"transport", section);
|
||||
for (let value in securities)
|
||||
validate_proxy_parameter_value(value, [ "none", "tls", "reality" ], "security", section);
|
||||
}
|
||||
|
||||
function validate_urltest_regex_value(value, section) {
|
||||
if (as_string(value) == "" || regex_valid(value))
|
||||
return;
|
||||
@@ -1121,12 +1142,26 @@ function validate_priority_group(section, group_id) {
|
||||
validate_country_code_value(value, name);
|
||||
for (let value in connections.priority_level_include_regex(group_id, level_id))
|
||||
validate_urltest_regex_value(value, name);
|
||||
if (connections.priority_level_include_proxy_parameters(group_id, level_id))
|
||||
validate_proxy_parameter_filters(
|
||||
connections.priority_level_include_protocols(group_id, level_id),
|
||||
connections.priority_level_include_transports(group_id, level_id),
|
||||
connections.priority_level_include_securities(group_id, level_id),
|
||||
name
|
||||
);
|
||||
}
|
||||
if (filter_mode == "exclude" || filter_mode == "mixed") {
|
||||
for (let value in connections.priority_level_exclude_countries(group_id, level_id))
|
||||
validate_country_code_value(value, name);
|
||||
for (let value in connections.priority_level_exclude_regex(group_id, level_id))
|
||||
validate_urltest_regex_value(value, name);
|
||||
if (connections.priority_level_exclude_proxy_parameters(group_id, level_id))
|
||||
validate_proxy_parameter_filters(
|
||||
connections.priority_level_exclude_protocols(group_id, level_id),
|
||||
connections.priority_level_exclude_transports(group_id, level_id),
|
||||
connections.priority_level_exclude_securities(group_id, level_id),
|
||||
name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1382,12 +1417,26 @@ function validate_rule(section, sections, context) {
|
||||
validate_urltest_regex_value(value, name);
|
||||
for (let value in connections.urltest_include_countries(section, urltest_id))
|
||||
validate_country_code_value(value, name);
|
||||
if (connections.urltest_include_proxy_parameters(section, urltest_id))
|
||||
validate_proxy_parameter_filters(
|
||||
connections.urltest_include_protocols(section, urltest_id),
|
||||
connections.urltest_include_transports(section, urltest_id),
|
||||
connections.urltest_include_securities(section, urltest_id),
|
||||
name
|
||||
);
|
||||
}
|
||||
if (contains([ "exclude", "mixed" ], urltest_filter_mode)) {
|
||||
for (let value in connections.urltest_exclude_countries(section, urltest_id))
|
||||
validate_country_code_value(value, name);
|
||||
for (let value in connections.urltest_exclude_regex(section, urltest_id))
|
||||
validate_urltest_regex_value(value, name);
|
||||
if (connections.urltest_exclude_proxy_parameters(section, urltest_id))
|
||||
validate_proxy_parameter_filters(
|
||||
connections.urltest_exclude_protocols(section, urltest_id),
|
||||
connections.urltest_exclude_transports(section, urltest_id),
|
||||
connections.urltest_exclude_securities(section, urltest_id),
|
||||
name
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -986,21 +986,75 @@ function tag_country_filter_matches(tag, countries, country_filter) {
|
||||
return country != "" && array_contains(country_filter, country);
|
||||
}
|
||||
|
||||
function tag_attribute_filter_matches(tag, metadata, selected_values) {
|
||||
selected_values = array_or_empty(selected_values);
|
||||
if (length(selected_values) == 0)
|
||||
return true;
|
||||
|
||||
let value = lc(as_string(object_or_empty(metadata)[tag] || ""));
|
||||
if (value == "")
|
||||
return false;
|
||||
for (let selected in selected_values)
|
||||
if (lc(as_string(selected)) == value)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function proxy_parameter_filter_matches_all(tag, metadata, protocols, transports, securities) {
|
||||
metadata = object_or_empty(metadata);
|
||||
return tag_attribute_filter_matches(tag, metadata.protocols, protocols) &&
|
||||
tag_attribute_filter_matches(tag, metadata.transports, transports) &&
|
||||
tag_attribute_filter_matches(tag, metadata.securities, securities);
|
||||
}
|
||||
|
||||
function proxy_parameter_filter_matches_any(tag, metadata, protocols, transports, securities) {
|
||||
metadata = object_or_empty(metadata);
|
||||
return (length(array_or_empty(protocols)) > 0 &&
|
||||
tag_attribute_filter_matches(tag, metadata.protocols, protocols)) ||
|
||||
(length(array_or_empty(transports)) > 0 &&
|
||||
tag_attribute_filter_matches(tag, metadata.transports, transports)) ||
|
||||
(length(array_or_empty(securities)) > 0 &&
|
||||
tag_attribute_filter_matches(tag, metadata.securities, securities));
|
||||
}
|
||||
|
||||
function name_or_country_filter_configured(name_filter, regexes, country_filter) {
|
||||
return length(array_or_empty(name_filter)) > 0 ||
|
||||
length(array_or_empty(regexes)) > 0 ||
|
||||
length(array_or_empty(country_filter)) > 0;
|
||||
}
|
||||
|
||||
function urltest_all_candidate_outbounds(urltest_candidate_tags) {
|
||||
return unique_string_array(urltest_candidate_tags);
|
||||
}
|
||||
|
||||
function urltest_matching_candidate_outbounds(urltest_candidate_tags, names, countries, name_filter, regexes, country_filter) {
|
||||
function urltest_matching_candidate_outbounds(urltest_candidate_tags, names, countries, name_filter, regexes, country_filter,
|
||||
metadata, proxy_parameters_enabled, proxy_parameters_operator, protocols, transports, securities) {
|
||||
names = object_or_empty(names);
|
||||
countries = object_or_empty(countries);
|
||||
country_filter = runtime_urltest.normalized_country_list(country_filter);
|
||||
|
||||
let regex_set = regex_match_set(urltest_candidate_tags, names, regexes);
|
||||
let base_filter_configured = name_or_country_filter_configured(name_filter, regexes, country_filter);
|
||||
let result = [];
|
||||
|
||||
for (let tag in array_or_empty(urltest_candidate_tags)) {
|
||||
if (tag_name_filter_matches(tag, names, name_filter, regex_set) ||
|
||||
tag_country_filter_matches(tag, countries, country_filter))
|
||||
let base_matches = tag_name_filter_matches(tag, names, name_filter, regex_set) ||
|
||||
tag_country_filter_matches(tag, countries, country_filter);
|
||||
let matches = base_matches;
|
||||
if (proxy_parameters_enabled && proxy_parameters_operator == "or") {
|
||||
matches = base_matches || proxy_parameter_filter_matches_any(
|
||||
tag, metadata, protocols, transports, securities
|
||||
);
|
||||
}
|
||||
else if (proxy_parameters_enabled) {
|
||||
if (!base_filter_configured)
|
||||
base_matches = true;
|
||||
matches = base_matches && proxy_parameter_filter_matches_all(
|
||||
tag, metadata, protocols, transports, securities
|
||||
);
|
||||
}
|
||||
|
||||
if (matches)
|
||||
push(result, tag);
|
||||
}
|
||||
|
||||
@@ -1017,8 +1071,11 @@ function urltest_exclude_outbounds(all_outbounds, excluded_outbounds) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function filter_candidate_outbounds(filter_mode, urltest_candidate_tags, names, countries,
|
||||
include_names, include_regex, include_countries, exclude_names, exclude_regex, exclude_countries) {
|
||||
function filter_candidate_outbounds(filter_mode, urltest_candidate_tags, names, countries, metadata,
|
||||
include_names, include_regex, include_countries,
|
||||
include_proxy_parameters, include_protocols, include_transports, include_securities,
|
||||
exclude_names, exclude_regex, exclude_countries,
|
||||
exclude_proxy_parameters, exclude_protocols, exclude_transports, exclude_securities) {
|
||||
let all_outbounds = urltest_all_candidate_outbounds(urltest_candidate_tags);
|
||||
if (filter_mode == "" || filter_mode == "disabled")
|
||||
return all_outbounds;
|
||||
@@ -1031,7 +1088,13 @@ function filter_candidate_outbounds(filter_mode, urltest_candidate_tags, names,
|
||||
countries,
|
||||
include_names,
|
||||
include_regex,
|
||||
include_countries
|
||||
include_countries,
|
||||
metadata,
|
||||
include_proxy_parameters,
|
||||
"and",
|
||||
include_protocols,
|
||||
include_transports,
|
||||
include_securities
|
||||
);
|
||||
let exclude_outbounds = urltest_matching_candidate_outbounds(
|
||||
urltest_candidate_tags,
|
||||
@@ -1039,7 +1102,13 @@ function filter_candidate_outbounds(filter_mode, urltest_candidate_tags, names,
|
||||
countries,
|
||||
exclude_names,
|
||||
exclude_regex,
|
||||
exclude_countries
|
||||
exclude_countries,
|
||||
metadata,
|
||||
exclude_proxy_parameters,
|
||||
"or",
|
||||
exclude_protocols,
|
||||
exclude_transports,
|
||||
exclude_securities
|
||||
);
|
||||
|
||||
if (filter_mode == "include")
|
||||
@@ -1057,12 +1126,21 @@ function urltest_filtered_outbounds(section, urltest_id, urltest_candidate_tags,
|
||||
urltest_candidate_tags,
|
||||
object_or_empty(object_or_empty(state.outboundMetadata).names),
|
||||
urltest_country_metadata(section, urltest_id, state),
|
||||
object_or_empty(state.outboundMetadata),
|
||||
connections.urltest_include_outbounds(section, urltest_id),
|
||||
connections.urltest_include_regex(section, urltest_id),
|
||||
connections.urltest_include_countries(section, urltest_id),
|
||||
connections.urltest_include_proxy_parameters(section, urltest_id),
|
||||
connections.urltest_include_protocols(section, urltest_id),
|
||||
connections.urltest_include_transports(section, urltest_id),
|
||||
connections.urltest_include_securities(section, urltest_id),
|
||||
connections.urltest_exclude_outbounds(section, urltest_id),
|
||||
connections.urltest_exclude_regex(section, urltest_id),
|
||||
connections.urltest_exclude_countries(section, urltest_id)
|
||||
connections.urltest_exclude_countries(section, urltest_id),
|
||||
connections.urltest_exclude_proxy_parameters(section, urltest_id),
|
||||
connections.urltest_exclude_protocols(section, urltest_id),
|
||||
connections.urltest_exclude_transports(section, urltest_id),
|
||||
connections.urltest_exclude_securities(section, urltest_id)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1083,12 +1161,21 @@ function priority_level_filtered_outbounds(group_id, level_id, urltest_candidate
|
||||
urltest_candidate_tags,
|
||||
object_or_empty(object_or_empty(state.outboundMetadata).names),
|
||||
priority_level_country_metadata(group_id, level_id, state),
|
||||
object_or_empty(state.outboundMetadata),
|
||||
connections.priority_level_include_outbounds(group_id, level_id),
|
||||
connections.priority_level_include_regex(group_id, level_id),
|
||||
connections.priority_level_include_countries(group_id, level_id),
|
||||
connections.priority_level_include_proxy_parameters(group_id, level_id),
|
||||
connections.priority_level_include_protocols(group_id, level_id),
|
||||
connections.priority_level_include_transports(group_id, level_id),
|
||||
connections.priority_level_include_securities(group_id, level_id),
|
||||
connections.priority_level_exclude_outbounds(group_id, level_id),
|
||||
connections.priority_level_exclude_regex(group_id, level_id),
|
||||
connections.priority_level_exclude_countries(group_id, level_id)
|
||||
connections.priority_level_exclude_countries(group_id, level_id),
|
||||
connections.priority_level_exclude_proxy_parameters(group_id, level_id),
|
||||
connections.priority_level_exclude_protocols(group_id, level_id),
|
||||
connections.priority_level_exclude_transports(group_id, level_id),
|
||||
connections.priority_level_exclude_securities(group_id, level_id)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1911,9 +1998,7 @@ function add_manual_proxy_link(config, state, section_name, manual_index, link,
|
||||
push(urltest_candidate_tags, tag_name);
|
||||
|
||||
state.links[tag_name] = as_string(link);
|
||||
state.outboundMetadata.names[tag_name] = display_name;
|
||||
if (as_string(outbound.server || "") != "")
|
||||
state.servers[tag_name] = as_string(outbound.server);
|
||||
runtime_subscription.remember_outbound_metadata(state, tag_name, display_name, outbound);
|
||||
return tag_name;
|
||||
}
|
||||
|
||||
|
||||
@@ -199,6 +199,25 @@ function remember_outbound_metadata(state, tag_name, display_name, outbound) {
|
||||
if (type(state) != "object")
|
||||
return;
|
||||
state.outboundMetadata.names[tag_name] = display_name;
|
||||
let protocol = lc(as_string(outbound.type || ""));
|
||||
if (protocol != "")
|
||||
state.outboundMetadata.protocols[tag_name] = protocol;
|
||||
|
||||
let transport = lc(as_string(object_or_empty(outbound.transport).type || ""));
|
||||
if (transport == "" || transport == "raw")
|
||||
transport = "tcp";
|
||||
else if (transport == "h2")
|
||||
transport = "http";
|
||||
state.outboundMetadata.transports[tag_name] = transport;
|
||||
|
||||
let tls = type(outbound.tls) == "object" ? outbound.tls : null;
|
||||
let security = "none";
|
||||
if (tls != null && tls.enabled !== false) {
|
||||
let reality = type(tls.reality) == "object" ? tls.reality : null;
|
||||
security = reality != null && reality.enabled !== false ? "reality" : "tls";
|
||||
}
|
||||
state.outboundMetadata.securities[tag_name] = security;
|
||||
|
||||
let server = as_string(outbound.server || "");
|
||||
if (server != "")
|
||||
state.servers[tag_name] = server;
|
||||
@@ -337,7 +356,10 @@ function new_section_state(section_name) {
|
||||
linkRefs: {},
|
||||
outboundMetadata: {
|
||||
names: {},
|
||||
countries: {}
|
||||
countries: {},
|
||||
protocols: {},
|
||||
transports: {},
|
||||
securities: {}
|
||||
},
|
||||
servers: {},
|
||||
urltestCandidateTags: [],
|
||||
|
||||
@@ -1708,6 +1708,91 @@ function serverCountryDetectionChoices() {
|
||||
];
|
||||
}
|
||||
|
||||
function proxyProtocolChoices() {
|
||||
return [
|
||||
["vless", "VLESS"],
|
||||
["vmess", "VMess"],
|
||||
["trojan", "Trojan"],
|
||||
["shadowsocks", "Shadowsocks"],
|
||||
["socks", "SOCKS"],
|
||||
["http", "HTTP"],
|
||||
["hysteria2", "Hysteria2"],
|
||||
["direct", "Direct"],
|
||||
];
|
||||
}
|
||||
|
||||
function proxyTransportChoices() {
|
||||
return [
|
||||
["tcp", "TCP"],
|
||||
["ws", "WebSocket"],
|
||||
["grpc", "gRPC"],
|
||||
["http", "HTTP"],
|
||||
["httpupgrade", "HTTPUpgrade"],
|
||||
["xhttp", "XHTTP"],
|
||||
];
|
||||
}
|
||||
|
||||
function proxySecurityChoices() {
|
||||
return [
|
||||
["none", "None"],
|
||||
["tls", "TLS"],
|
||||
["reality", "Reality"],
|
||||
];
|
||||
}
|
||||
|
||||
function addProxyParameterFilterOptions(itemSection, options) {
|
||||
const prefix = options.prefix;
|
||||
const dependencies = options.dependencies;
|
||||
|
||||
let o = itemSection.option(
|
||||
form.Flag,
|
||||
`${prefix}_proxy_parameters`,
|
||||
options.toggleLabel,
|
||||
options.toggleDescription,
|
||||
);
|
||||
dependencies.forEach((dependency) => o.depends(dependency));
|
||||
o.default = "0";
|
||||
o.rmempty = false;
|
||||
|
||||
[
|
||||
[
|
||||
"protocols",
|
||||
_("Protocol"),
|
||||
options.protocolDescription,
|
||||
proxyProtocolChoices(),
|
||||
],
|
||||
[
|
||||
"transports",
|
||||
_("Transport"),
|
||||
options.transportDescription,
|
||||
proxyTransportChoices(),
|
||||
],
|
||||
[
|
||||
"securities",
|
||||
_("Security"),
|
||||
options.securityDescription,
|
||||
proxySecurityChoices(),
|
||||
],
|
||||
].forEach(([suffix, label, description, choices]) => {
|
||||
const list = itemSection.option(
|
||||
form.DynamicList,
|
||||
`${prefix}_${suffix}`,
|
||||
label,
|
||||
description,
|
||||
);
|
||||
dependencies.forEach((dependency) =>
|
||||
list.depends(
|
||||
Object.assign({}, dependency, {
|
||||
[`${prefix}_proxy_parameters`]: "1",
|
||||
}),
|
||||
),
|
||||
);
|
||||
list.rmempty = true;
|
||||
choices.forEach(([value, choiceLabel]) => list.value(value, choiceLabel));
|
||||
list.placeholder = _("-- Select --");
|
||||
});
|
||||
}
|
||||
|
||||
function urlTestUrlChoices() {
|
||||
return Array.isArray(main.LATENCY_TEST_URL_OPTIONS)
|
||||
? main.LATENCY_TEST_URL_OPTIONS
|
||||
@@ -1837,9 +1922,17 @@ function urlTestSettingsKeys() {
|
||||
"include_countries",
|
||||
"include_outbounds",
|
||||
"include_regex",
|
||||
"include_proxy_parameters",
|
||||
"include_protocols",
|
||||
"include_transports",
|
||||
"include_securities",
|
||||
"exclude_countries",
|
||||
"exclude_outbounds",
|
||||
"exclude_regex",
|
||||
"exclude_proxy_parameters",
|
||||
"exclude_protocols",
|
||||
"exclude_transports",
|
||||
"exclude_securities",
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1929,9 +2022,17 @@ function priorityLevelSettingsKeys() {
|
||||
"country",
|
||||
"server_name",
|
||||
"regex",
|
||||
"include_proxy_parameters",
|
||||
"include_protocols",
|
||||
"include_transports",
|
||||
"include_securities",
|
||||
"exclude_countries",
|
||||
"exclude_outbounds",
|
||||
"exclude_regex",
|
||||
"exclude_proxy_parameters",
|
||||
"exclude_protocols",
|
||||
"exclude_transports",
|
||||
"exclude_securities",
|
||||
];
|
||||
}
|
||||
|
||||
@@ -2300,6 +2401,41 @@ function addUrlTestItemOptions(itemSection, options = {}) {
|
||||
);
|
||||
o.default = "flag_emoji";
|
||||
|
||||
const includeProxyParameterOptions = {
|
||||
prefix: "include",
|
||||
toggleLabel: _("Include by proxy parameters"),
|
||||
toggleDescription: _(
|
||||
"Additionally filter servers by protocol, transport, and security. Add only servers matching the specified parameters.",
|
||||
),
|
||||
dependencies: [{ filter_mode: "include" }, { filter_mode: "mixed" }],
|
||||
protocolDescription: _(
|
||||
"Test only servers with one of the selected protocols.",
|
||||
),
|
||||
transportDescription: _(
|
||||
"Test only servers with one of the selected transports.",
|
||||
),
|
||||
securityDescription: _(
|
||||
"Test only servers with one of the selected security types.",
|
||||
),
|
||||
};
|
||||
const excludeProxyParameterOptions = {
|
||||
prefix: "exclude",
|
||||
toggleLabel: _("Exclude by proxy parameters"),
|
||||
toggleDescription: _(
|
||||
"Additionally exclude servers by protocol, transport, and security. Exclude only servers matching the specified parameters.",
|
||||
),
|
||||
dependencies: [{ filter_mode: "exclude" }, { filter_mode: "mixed" }],
|
||||
protocolDescription: _(
|
||||
"Do not test servers with one of the selected protocols.",
|
||||
),
|
||||
transportDescription: _(
|
||||
"Do not test servers with one of the selected transports.",
|
||||
),
|
||||
securityDescription: _(
|
||||
"Do not test servers with one of the selected security types.",
|
||||
),
|
||||
};
|
||||
|
||||
[
|
||||
[
|
||||
"include_countries",
|
||||
@@ -2377,6 +2513,11 @@ function addUrlTestItemOptions(itemSection, options = {}) {
|
||||
return validator(null, value);
|
||||
};
|
||||
}
|
||||
if (key === "include_regex") {
|
||||
addProxyParameterFilterOptions(itemSection, includeProxyParameterOptions);
|
||||
} else if (key === "exclude_regex") {
|
||||
addProxyParameterFilterOptions(itemSection, excludeProxyParameterOptions);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2466,6 +2607,45 @@ function addPriorityLevelItemOptions(itemSection, options = {}) {
|
||||
);
|
||||
o.default = "flag_emoji";
|
||||
|
||||
const includeProxyParameterOptions = {
|
||||
prefix: "include",
|
||||
toggleLabel: _("Include by proxy parameters"),
|
||||
toggleDescription: _(
|
||||
"Additionally filter servers by protocol, transport, and security. Add only servers matching the specified parameters.",
|
||||
),
|
||||
dependencies: [
|
||||
{ direct: "0", filter_mode: "include" },
|
||||
{ direct: "0", filter_mode: "mixed" },
|
||||
],
|
||||
protocolDescription: _("Only servers with one of the selected protocols."),
|
||||
transportDescription: _(
|
||||
"Only servers with one of the selected transports.",
|
||||
),
|
||||
securityDescription: _(
|
||||
"Only servers with one of the selected security types.",
|
||||
),
|
||||
};
|
||||
const excludeProxyParameterOptions = {
|
||||
prefix: "exclude",
|
||||
toggleLabel: _("Exclude by proxy parameters"),
|
||||
toggleDescription: _(
|
||||
"Additionally exclude servers by protocol, transport, and security. Exclude only servers matching the specified parameters.",
|
||||
),
|
||||
dependencies: [
|
||||
{ direct: "0", filter_mode: "exclude" },
|
||||
{ direct: "0", filter_mode: "mixed" },
|
||||
],
|
||||
protocolDescription: _(
|
||||
"Exclude servers with one of the selected protocols from this level.",
|
||||
),
|
||||
transportDescription: _(
|
||||
"Exclude servers with one of the selected transports from this level.",
|
||||
),
|
||||
securityDescription: _(
|
||||
"Exclude servers with one of the selected security types from this level.",
|
||||
),
|
||||
};
|
||||
|
||||
[
|
||||
[
|
||||
"country",
|
||||
@@ -2543,6 +2723,11 @@ function addPriorityLevelItemOptions(itemSection, options = {}) {
|
||||
return validator(null, value);
|
||||
};
|
||||
}
|
||||
if (key === "regex") {
|
||||
addProxyParameterFilterOptions(itemSection, includeProxyParameterOptions);
|
||||
} else if (key === "exclude_regex") {
|
||||
addProxyParameterFilterOptions(itemSection, excludeProxyParameterOptions);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: FORKOP\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-12 00:20+0300\n"
|
||||
"PO-Revision-Date: 2026-07-12 00:20+0300\n"
|
||||
"POT-Creation-Date: 2026-07-13 03:22+0300\n"
|
||||
"PO-Revision-Date: 2026-07-13 03:22+0300\n"
|
||||
"Last-Translator: ushan0v\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: ru\n"
|
||||
@@ -80,6 +80,12 @@ msgstr "Добавьте URL или локальные пути к списка
|
||||
msgid "Additional marking rules found"
|
||||
msgstr "Найдены дополнительные правила маркировки"
|
||||
|
||||
msgid "Additionally exclude servers by protocol, transport, and security. Exclude only servers matching the specified parameters."
|
||||
msgstr "Дополнительно исключать серверы по протоколу, транспорту и защите. Исключать только серверы, совпавшие по указанным параметрам."
|
||||
|
||||
msgid "Additionally filter servers by protocol, transport, and security. Add only servers matching the specified parameters."
|
||||
msgstr "Дополнительно отбирать серверы по протоколу, транспорту и защите. Добавлять только серверы, совпавшие по указанным параметрам."
|
||||
|
||||
msgid "Address"
|
||||
msgstr "Адрес"
|
||||
|
||||
@@ -482,6 +488,15 @@ msgstr "Не тестировать серверы из этих стран."
|
||||
msgid "Do not test servers whose names match the expression."
|
||||
msgstr "Не тестировать серверы, имена которых совпадают с выражением."
|
||||
|
||||
msgid "Do not test servers with one of the selected protocols."
|
||||
msgstr "Не тестировать серверы с одним из выбранных протоколов."
|
||||
|
||||
msgid "Do not test servers with one of the selected security types."
|
||||
msgstr "Не тестировать серверы с одним из выбранных типов защиты."
|
||||
|
||||
msgid "Do not test servers with one of the selected transports."
|
||||
msgstr "Не тестировать серверы с одним из выбранных транспортов."
|
||||
|
||||
msgid "Do not test specified servers."
|
||||
msgstr "Не тестировать указанные серверы."
|
||||
|
||||
@@ -605,6 +620,9 @@ msgstr "HWID, который будет отправляться при запр
|
||||
msgid "Enter the subscription URL"
|
||||
msgstr "Введите URL подписки"
|
||||
|
||||
msgid "Exclude by proxy parameters"
|
||||
msgstr "Исключить по параметрам прокси"
|
||||
|
||||
msgid "Exclude by regular expression"
|
||||
msgstr "Исключить по регулярному выражению"
|
||||
|
||||
@@ -620,6 +638,15 @@ msgstr "Исключите трафик протокола NTP из туннел
|
||||
msgid "Exclude servers"
|
||||
msgstr "Исключить серверы"
|
||||
|
||||
msgid "Exclude servers with one of the selected protocols from this level."
|
||||
msgstr "Исключить из этого уровня серверы с одним из выбранных протоколов."
|
||||
|
||||
msgid "Exclude servers with one of the selected security types from this level."
|
||||
msgstr "Исключить из этого уровня серверы с одним из выбранных типов защиты."
|
||||
|
||||
msgid "Exclude servers with one of the selected transports from this level."
|
||||
msgstr "Исключить из этого уровня серверы с одним из выбранных транспортов."
|
||||
|
||||
msgid "Expecting: %s"
|
||||
msgstr "Ожидается: %s"
|
||||
|
||||
@@ -839,6 +866,9 @@ msgstr "Inbound JSON не может быть пустым"
|
||||
msgid "Inbound JSON must be an object with a type field"
|
||||
msgstr "Inbound JSON должен быть объектом с полем type"
|
||||
|
||||
msgid "Include by proxy parameters"
|
||||
msgstr "Включить по параметрам прокси"
|
||||
|
||||
msgid "Include by regular expression"
|
||||
msgstr "Включить по регулярному выражению"
|
||||
|
||||
@@ -1316,6 +1346,15 @@ msgstr "Только выбранные, кроме исключений"
|
||||
msgid "Only servers whose names match the expression."
|
||||
msgstr "Только серверы, имена которых соответствуют выражению."
|
||||
|
||||
msgid "Only servers with one of the selected protocols."
|
||||
msgstr "Только серверы с одним из выбранных протоколов."
|
||||
|
||||
msgid "Only servers with one of the selected security types."
|
||||
msgstr "Только серверы с одним из выбранных типов защиты."
|
||||
|
||||
msgid "Only servers with one of the selected transports."
|
||||
msgstr "Только серверы с одним из выбранных транспортов."
|
||||
|
||||
msgid "Only the specified servers."
|
||||
msgstr "Только указанные серверы."
|
||||
|
||||
@@ -1841,6 +1880,15 @@ msgstr "Тестирование задержки"
|
||||
msgid "Test only selected servers."
|
||||
msgstr "Тестировать только выбранные серверы."
|
||||
|
||||
msgid "Test only servers with one of the selected protocols."
|
||||
msgstr "Тестировать только серверы с одним из выбранных протоколов."
|
||||
|
||||
msgid "Test only servers with one of the selected security types."
|
||||
msgstr "Тестировать только серверы с одним из выбранных типов защиты."
|
||||
|
||||
msgid "Test only servers with one of the selected transports."
|
||||
msgstr "Тестировать только серверы с одним из выбранных транспортов."
|
||||
|
||||
msgid "Test servers only from the specified countries."
|
||||
msgstr "Тестировать серверы только из указанных стран."
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,8 @@ fail() {
|
||||
|
||||
wrapper_styles="$(sed -n '/^\.fkp-button-add-dynlist > \.add-item {$/,/^}$/p' "$SECTION_JS")"
|
||||
button_styles="$(sed -n '/^\.fkp-button-add-dynlist > \.add-item > \.cbi-button-add {$/,/^}$/p' "$SECTION_JS")"
|
||||
urltest_options="$(sed -n '/^function addUrlTestItemOptions(/,/^function priorityLevelSettingsForValidation(/p' "$SECTION_JS")"
|
||||
priority_options="$(sed -n '/^function addPriorityLevelItemOptions(/,/^function addPriorityGroupItemOptions(/p' "$SECTION_JS")"
|
||||
|
||||
grep -Fq 'display: flex;' <<<"$wrapper_styles" ||
|
||||
fail "button-only DynamicList add rows must use a content-sized flex wrapper"
|
||||
@@ -30,4 +32,22 @@ grep -Fq 'max-width: 100% !important;' <<<"$button_styles" ||
|
||||
grep -Fq 'text-overflow: ellipsis !important;' <<<"$button_styles" ||
|
||||
fail "button-only DynamicList labels must truncate instead of overflowing"
|
||||
|
||||
grep -Fq 'if (key === "include_regex") {' <<<"$urltest_options" ||
|
||||
fail "URLTest include proxy parameters must follow the include regex option"
|
||||
grep -Fq 'else if (key === "exclude_regex") {' <<<"$urltest_options" ||
|
||||
fail "URLTest exclude proxy parameters must follow the exclude regex option"
|
||||
grep -Fq 'if (key === "regex") {' <<<"$priority_options" ||
|
||||
fail "Priority include proxy parameters must follow the include regex option"
|
||||
grep -Fq 'else if (key === "exclude_regex") {' <<<"$priority_options" ||
|
||||
fail "Priority exclude proxy parameters must follow the exclude regex option"
|
||||
grep -Fq '["direct", "Direct"]' "$SECTION_JS" ||
|
||||
fail "proxy protocol choices must keep Direct untranslated"
|
||||
grep -Fq '["none", "None"]' "$SECTION_JS" ||
|
||||
fail "proxy security choices must keep None untranslated"
|
||||
grep -Fq '_("Security")' "$SECTION_JS" ||
|
||||
fail "proxy parameter filters must use the short Security label"
|
||||
if grep -Fq 'Connection security' "$SECTION_JS"; then
|
||||
fail "proxy parameter filter copy must not mention connection security"
|
||||
fi
|
||||
|
||||
printf 'LuCI DynamicList layout checks passed\n'
|
||||
|
||||
Executable
+194
@@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
FORKOP_LIB="$ROOT_DIR/forkop/files/usr/lib"
|
||||
GENERATOR_UC="$FORKOP_LIB/singbox/generator.uc"
|
||||
VALIDATOR_UC="$FORKOP_LIB/config/validator.uc"
|
||||
WORK_DIR="$(mktemp -d)"
|
||||
|
||||
cleanup() {
|
||||
rm -rf "$WORK_DIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
fail() {
|
||||
printf 'FAIL: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
generate_config() {
|
||||
local fixture="$1"
|
||||
local output="$2"
|
||||
mkdir -p "${output}.section-cache"
|
||||
ucode -L "$FORKOP_LIB" "$GENERATOR_UC" generate-config-fixture \
|
||||
"$fixture" "$output" "127.0.0.1"
|
||||
}
|
||||
|
||||
validate_fixture() {
|
||||
local fixture="$1"
|
||||
FORKOP_LIB="$FORKOP_LIB" ucode -L "$FORKOP_LIB" "$VALIDATOR_UC" \
|
||||
validate-runtime-fixture "$fixture" "{}"
|
||||
}
|
||||
|
||||
cat >"$WORK_DIR/fixture.json" <<'JSON'
|
||||
{
|
||||
"settings": {
|
||||
".name": "settings",
|
||||
".type": "settings",
|
||||
"dns_server": [ "77.88.8.8" ],
|
||||
"bootstrap_dns_server": [ "77.88.8.8" ]
|
||||
},
|
||||
"section": [
|
||||
{
|
||||
".name": "proxy",
|
||||
".type": "section",
|
||||
"enabled": "1",
|
||||
"action": "proxy",
|
||||
"outbound_jsons": [
|
||||
"{\"type\":\"vless\",\"tag\":\"Alpha\",\"server\":\"alpha.example\",\"server_port\":443,\"uuid\":\"00000000-0000-4000-8000-000000000001\",\"tls\":{\"enabled\":true}}",
|
||||
"{\"type\":\"vless\",\"tag\":\"Beta\",\"server\":\"beta.example\",\"server_port\":443,\"uuid\":\"00000000-0000-4000-8000-000000000002\",\"transport\":{\"type\":\"ws\"},\"tls\":{\"enabled\":true,\"reality\":{\"enabled\":true}}}",
|
||||
"{\"type\":\"vmess\",\"tag\":\"Gamma\",\"server\":\"gamma.example\",\"server_port\":443,\"uuid\":\"00000000-0000-4000-8000-000000000003\",\"transport\":{\"type\":\"grpc\"}}",
|
||||
"{\"type\":\"trojan\",\"tag\":\"Delta\",\"server\":\"delta.example\",\"server_port\":443,\"password\":\"secret\",\"transport\":{\"type\":\"xhttp\"},\"tls\":{\"enabled\":true}}",
|
||||
"{\"type\":\"http\",\"tag\":\"Echo\",\"server\":\"echo.example\",\"server_port\":8080}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"urltest": [
|
||||
{
|
||||
".name": "and_filter",
|
||||
".type": "urltest",
|
||||
"section": "proxy",
|
||||
"name": "AND filter",
|
||||
"filter_mode": "mixed",
|
||||
"include_regex": [ "Alpha|Beta|Gamma|Delta" ],
|
||||
"include_proxy_parameters": "1",
|
||||
"include_protocols": [ "vless", "vmess" ],
|
||||
"include_transports": [ "tcp", "ws", "grpc" ],
|
||||
"include_securities": [ "tls", "reality", "none" ],
|
||||
"exclude_regex": [ "Alpha" ],
|
||||
"exclude_proxy_parameters": "1",
|
||||
"exclude_securities": [ "reality" ]
|
||||
},
|
||||
{
|
||||
".name": "parameters_only",
|
||||
".type": "urltest",
|
||||
"section": "proxy",
|
||||
"name": "Parameters only",
|
||||
"filter_mode": "include",
|
||||
"include_proxy_parameters": "1",
|
||||
"include_protocols": [ "http" ],
|
||||
"include_transports": [ "tcp" ],
|
||||
"include_securities": [ "none" ]
|
||||
}
|
||||
],
|
||||
"priority_group": [
|
||||
{
|
||||
".name": "pg_parameters",
|
||||
".type": "priority_group",
|
||||
"section": "proxy",
|
||||
"name": "Parameter priority"
|
||||
}
|
||||
],
|
||||
"priority_level": [
|
||||
{
|
||||
".name": "pl_grpc",
|
||||
".type": "priority_level",
|
||||
"group": "pg_parameters",
|
||||
"name": "gRPC VMess",
|
||||
"order": "0",
|
||||
"filter_mode": "include",
|
||||
"include_proxy_parameters": "1",
|
||||
"include_protocols": [ "vmess" ],
|
||||
"include_transports": [ "grpc" ],
|
||||
"include_securities": [ "none" ]
|
||||
},
|
||||
{
|
||||
".name": "pl_mixed",
|
||||
".type": "priority_level",
|
||||
"group": "pg_parameters",
|
||||
"name": "Mixed VLESS",
|
||||
"order": "1",
|
||||
"filter_mode": "mixed",
|
||||
"regex": [ "Alpha|Beta" ],
|
||||
"include_proxy_parameters": "1",
|
||||
"include_protocols": [ "vless" ],
|
||||
"exclude_regex": [ "Alpha" ],
|
||||
"exclude_proxy_parameters": "1",
|
||||
"exclude_securities": [ "reality" ]
|
||||
},
|
||||
{
|
||||
".name": "pl_xhttp",
|
||||
".type": "priority_level",
|
||||
"group": "pg_parameters",
|
||||
"name": "XHTTP Trojan",
|
||||
"order": "2",
|
||||
"filter_mode": "include",
|
||||
"include_proxy_parameters": "1",
|
||||
"include_protocols": [ "trojan" ],
|
||||
"include_transports": [ "xhttp" ],
|
||||
"include_securities": [ "tls" ]
|
||||
},
|
||||
{
|
||||
".name": "pl_remaining",
|
||||
".type": "priority_level",
|
||||
"group": "pg_parameters",
|
||||
"name": "Remaining",
|
||||
"order": "3",
|
||||
"filter_mode": "disabled"
|
||||
}
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
validate_fixture "$WORK_DIR/fixture.json" >/dev/null || fail "valid proxy parameter filters"
|
||||
generate_config "$WORK_DIR/fixture.json" "$WORK_DIR/config.json"
|
||||
|
||||
ucode -e '
|
||||
let fs = require("fs");
|
||||
function fail(message) { die(message + "\n"); }
|
||||
function outbound_by_tag(config, tag) {
|
||||
for (let outbound in config.outbounds || [])
|
||||
if (outbound && outbound.tag == tag)
|
||||
return outbound;
|
||||
return null;
|
||||
}
|
||||
function assert_array(value, expected, label) {
|
||||
value = value || [];
|
||||
if (length(value) != length(expected))
|
||||
fail(label + " length mismatch: " + sprintf("%J", value));
|
||||
for (let i = 0; i < length(expected); i++)
|
||||
if (value[i] != expected[i])
|
||||
fail(label + " mismatch: " + sprintf("%J", value));
|
||||
}
|
||||
let config = json(fs.readfile(ARGV[0]));
|
||||
let cache = json(fs.readfile(ARGV[1]));
|
||||
assert_array(outbound_by_tag(config, "proxy-urltest-and_filter-out").outbounds, [ "Gamma" ], "URLTest AND/OR filter");
|
||||
assert_array(outbound_by_tag(config, "proxy-urltest-parameters_only-out").outbounds, [ "Echo" ], "URLTest parameter-only filter");
|
||||
assert_array(outbound_by_tag(config, "proxy-priority-pg_parameters-out").outbounds,
|
||||
[ "Gamma", "Delta", "Alpha", "Beta", "Echo" ], "Priority parameter filters");
|
||||
let priority_levels = ((cache.priorityGroups || {})["proxy-priority-pg_parameters-out"] || {}).levels || [];
|
||||
assert_array(priority_levels[1].outbounds, [], "Priority exclusion OR filter");
|
||||
|
||||
let metadata = cache.outboundMetadata || {};
|
||||
if (metadata.protocols.Alpha != "vless" || metadata.protocols.Echo != "http")
|
||||
fail("protocol metadata was not normalized");
|
||||
if (metadata.transports.Alpha != "tcp" || metadata.transports.Beta != "ws" || metadata.transports.Delta != "xhttp")
|
||||
fail("transport metadata was not normalized");
|
||||
if (metadata.securities.Alpha != "tls" || metadata.securities.Beta != "reality" || metadata.securities.Gamma != "none")
|
||||
fail("security metadata was not normalized");
|
||||
' "$WORK_DIR/config.json" "$WORK_DIR/config.json.section-cache/proxy.json" ||
|
||||
fail "URLTest and Priority proxy parameter filtering"
|
||||
|
||||
node - "$WORK_DIR/fixture.json" "$WORK_DIR/invalid.json" <<'JS'
|
||||
const fs = require('fs');
|
||||
const fixture = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
||||
fixture.urltest[0].include_protocols = ['invalid'];
|
||||
fs.writeFileSync(process.argv[3], JSON.stringify(fixture));
|
||||
JS
|
||||
|
||||
if validate_fixture "$WORK_DIR/invalid.json" >/dev/null 2>&1; then
|
||||
fail "invalid proxy protocol should be rejected"
|
||||
fi
|
||||
|
||||
printf 'proxy parameter filter regression tests passed\n'
|
||||
Reference in New Issue
Block a user