mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-05 09:54:06 +08:00
🐶 Sync 2026-10-03 11:32:07
This commit is contained in:
1 parent
a5bb91e6ed
commit
66e3d835c4
72 files changed
+5107
-1799
No files matched your search
@@ -34,6 +34,30 @@ const HTTP_PING_KEEPALIVE_HINT = _('The timeout (in seconds) that after performi
|
||||
TLS listener failed with nothing pointing at the path. */
|
||||
const HP_CERT_PATH_ROOTS = [ '/etc/homeproxy-pro/certs/', '/etc/acme/', '/etc/ssl/' ];
|
||||
|
||||
/* Rule-set source files: a `type: local` rule-set's `path` and a `type: remote`
|
||||
one's `initial_path`. This list mirrors RULE_PATH_ROOTS in
|
||||
/etc/homeproxy-pro/scripts/homeproxy-pro.uc, and tests/arch-guard.sh guard 50 fails
|
||||
when the two drift apart - the same lock guard 29 puts on the certificate
|
||||
list, for the same reason: the UI's check is only UX, UCI can be set from
|
||||
anywhere on the LAN, and a path the UI accepted but the backend dropped made
|
||||
the field vanish from the generated configuration with nothing pointing at
|
||||
the path.
|
||||
|
||||
It is deliberately a single root, and deliberately narrower than the
|
||||
general HP_DIR-shaped gate the backend also has: a rule-set belongs in the
|
||||
archive, which the package creates at install time
|
||||
(/etc/uci-defaults/luci-homeproxy-pro) and before every generation
|
||||
(runtime/service.sh's hp_prepare_ruleset_dir). */
|
||||
const HP_RULE_PATH_ROOTS = [ '/etc/homeproxy-pro/ruleset/' ];
|
||||
|
||||
/* The archive path offered as the datalist entry on the rule-set path fields,
|
||||
so the default the backend expects is one click away instead of something
|
||||
the user has to know. Kept as its own constant so the placeholder, the
|
||||
datalist and the validator's message all quote the same directory - a
|
||||
placeholder that named a path the validator then refused would be its own
|
||||
small version of the bug this list exists to prevent. */
|
||||
const HP_RULE_PATH_DEFAULT = '/etc/homeproxy-pro/ruleset/example.srs';
|
||||
|
||||
/* Methods whose failure has already been reported, so that a polled call
|
||||
cannot repeat the same notification every few seconds. */
|
||||
const rpc_warned = new Set();
|
||||
@@ -58,6 +82,80 @@ for (let i = 0; i < 64; i++)
|
||||
MD5_K[i] = Math.floor(Math.abs(Math.sin(i + 1)) * 4294967296);
|
||||
|
||||
return baseclass.extend({
|
||||
/* The archive path the rule-set form offers as its datalist entry and
|
||||
placeholder. Exported rather than left module-local so the view quotes
|
||||
this one string instead of repeating the path: a placeholder naming a
|
||||
directory the validator then refuses is its own small version of the
|
||||
drift guard 50 exists to catch, and the placeholder is exactly what a
|
||||
user copies. */
|
||||
rule_path_default: HP_RULE_PATH_DEFAULT,
|
||||
|
||||
/* Parse sing-box's rule-set download failures out of a log.
|
||||
*
|
||||
* With `ruleset_safe_start` on, a remote rule-set that cannot be
|
||||
* downloaded is no longer a failed start: sing-box reads the `initial_path`
|
||||
* fallback, comes up, and retries in the background, logging
|
||||
*
|
||||
* 2026-10-03 01:15:42 ERROR router: fetch rule-set geoip-cn: Get "https://…": dial tcp …
|
||||
*
|
||||
* That is a good trade, and it is also invisible: the instance is healthy,
|
||||
* the health gate passes, the LAN is proxied - and the rule-set that is
|
||||
* supposed to keep mainland traffic direct matches NOTHING, so all of it
|
||||
* goes to `final`. The status page is the only place a user looks without
|
||||
* ssh, so it has to show this.
|
||||
*
|
||||
* Two deliberate choices about the format:
|
||||
*
|
||||
* - the tag and the reason are matched on the stable part
|
||||
* (`fetch rule-set <tag>:`) and nothing assumes sing-box's timestamp
|
||||
* or level layout. A rule-set whose download failed long ago and whose
|
||||
* log line moves out of the file must not read as "no failures", so a
|
||||
* missing timestamp is omitted rather than faked.
|
||||
* - the last occurrence of a tag wins. The file is truncated at 50 KB by
|
||||
* clean_log.sh, so a tag that failed every 24 hours is in there
|
||||
* repeatedly, and the most recent reason is the one that is true now.
|
||||
*
|
||||
* The timestamp shape is the one thing that IS pinned, and it was pinned
|
||||
* from a real 1.14.2 line rather than guessed - the device writes
|
||||
*
|
||||
* +0800 2026-10-03 09:29:34 ERROR router: fetch rule-set geoip-cn: Get ...
|
||||
*
|
||||
* i.e. a UTC offset BEFORE the date. An earlier version of this anchored
|
||||
* the date at the start of the line and therefore returned no time for
|
||||
* every real line, which is the one shape the panel is supposed to show.
|
||||
* The offset is optional in the pattern so a build that omits it still
|
||||
* parses.
|
||||
*
|
||||
* Returns [{ tag, reason, at }], newest last. Never throws: this reads a
|
||||
* file that may be empty, half-written, or rotated mid-read. */
|
||||
parseRuleSetFetchFailures(text) {
|
||||
const out = [];
|
||||
if (!text)
|
||||
return out;
|
||||
|
||||
const seen = {};
|
||||
|
||||
for (const line of String(text).split('\n')) {
|
||||
const m = /fetch rule-set\s+([^\s:]+):\s*(.*)$/.exec(line);
|
||||
if (!m)
|
||||
continue;
|
||||
|
||||
const tag = m[1];
|
||||
const at = /^(?:[+-]\d{4}\s+)?(\d{4}-\d{2}-\d{2}[ T][0-9:.]+)/.exec(line);
|
||||
|
||||
if (seen[tag] !== undefined) {
|
||||
out[seen[tag]].reason = m[2].trim();
|
||||
out[seen[tag]].at = at ? at[1] : null;
|
||||
continue;
|
||||
}
|
||||
|
||||
seen[tag] = out.length;
|
||||
out.push({ tag: tag, reason: m[2].trim(), at: at ? at[1] : null });
|
||||
}
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
dns_strategy: {
|
||||
'': _('Default'),
|
||||
'prefer_ipv4': _('Prefer IPv4'),
|
||||
@@ -1108,6 +1206,23 @@ return baseclass.extend({
|
||||
return true;
|
||||
},
|
||||
|
||||
validateRuleSetPath(section_id, value) {
|
||||
if (section_id && value)
|
||||
/* HP_RULE_PATH_ROOTS is the same list the backend enforces
|
||||
(RULE_PATH_ROOTS, guard 50). The `..` rejection is explicit for
|
||||
the same reason as in validateCertificatePath: a prefix match
|
||||
alone accepts /etc/homeproxy-pro/ruleset/../../etc/shadow, and
|
||||
sing-box opens these files as root. The backend is the authority
|
||||
- this only saves a save that the generator would refuse a
|
||||
moment later with a message the user reads in a log file rather
|
||||
than on the page they are editing. */
|
||||
if (value.match(/(^|\/)\.\.(\/|$)/) ||
|
||||
!HP_RULE_PATH_ROOTS.some((root) => value.indexOf(root) === 0 && value.length > root.length))
|
||||
return _('Expecting: %s').format(_('/etc/homeproxy-pro/ruleset/...'));
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
validatePortRange(section_id, value) {
|
||||
if (section_id && value) {
|
||||
value = value.match(/^(\d+)?\:(\d+)?$/);
|
||||
|
||||
Reference in new issue
Block a user