luci-app-wg-obfuscator: add LuCI support for wg-obfuscator - #9001
luci-app-wg-obfuscator: add LuCI support for wg-obfuscator#9001ClusterM wants to merge 1 commit into
Conversation
| "description": "Grant access to WireGuard Obfuscator configuration", | ||
| "read": { | ||
| "file": { | ||
| "/var/etc/wg-obfuscator.conf": [ "read" ] |
There was a problem hiding this comment.
fs.stat() maps to ubus file.stat, which rpcd gates on the list permission, not read — see rpc_check_path(msg, R, "list", ...) in rpc_file_stat, file.c:734. Non-root sessions will therefore get access denied on the getConfigPresent() call, and since it is wrapped in L.resolveDefault(..., null) the status line silently shows "Not found" forever. The view never reads the file content, so list alone is enough.
| "/var/etc/wg-obfuscator.conf": [ "read" ] | |
| "/var/etc/wg-obfuscator.conf": [ "list" ] |
Generated by Claude Code
There was a problem hiding this comment.
read -> list is fixed, thanks. Left a follow-up on the new line about the /var -> /tmp symlink, which is a separate matter.
Generated by Claude Code
| s = m.section(form.TypedSection); | ||
| s.anonymous = true; | ||
| s.render = function () { | ||
| poll.add(() => Promise.all([ |
There was a problem hiding this comment.
Registering the poller inside the section's render() leaks one poller per re-render: Map.save() ends in renderContents() (form.js:639), which calls this render() again, and poll.add() only dedupes on identical function identity (luci.js:1091) — a fresh arrow function each time. After N "Save & Apply" cycles the page fires N service list + file stat round trips per interval. Register the poll once from the view's render() (or keep a module-level reference and re-add the same function).
Generated by Claude Code
There was a problem hiding this comment.
| o.password = true; | ||
| o.default = 'test'; | ||
| o.rmempty = false; |
There was a problem hiding this comment.
Defaulting the shared obfuscation secret to test means a user who adds an instance and hits Save gets a publicly known key written to UCI. Leave it unset so the required-field check forces a real value.
| o.password = true; | |
| o.default = 'test'; | |
| o.rmempty = false; | |
| o.password = true; | |
| o.rmempty = false; |
Generated by Claude Code
There was a problem hiding this comment.
| "Project-Id-Version: wg-obfuscator 1.6\n" | ||
| "POT-Creation-Date: 2026-09-03 00:00+0000\n" | ||
| "PO-Revision-Date: 2026-09-03 00:00+0000\n" | ||
| "Last-Translator: AI Assistant\n" |
There was a problem hiding this comment.
CONTRIBUTING.md asks contributors to use Weblate rather than editing *.po directly; these eight catalogs are machine-generated and will be clobbered on the next Weblate sync. Please drop po/{de,es,fr,pt_BR,ru,tr,uk,zh_Hans}/ and ship only po/templates/wg-obfuscator.pot, letting Weblate pick the app up.
Generated by Claude Code
| o.placeholder = 'example.com:13255'; | ||
| o.default = '10.13.1.100:13255'; |
There was a problem hiding this comment.
nit: setting both placeholder and default makes the placeholder dead — the field is prefilled with the hardcoded RFC1918 address instead. Same pair on lines 153-154 for source_if.
| o.placeholder = 'example.com:13255'; | |
| o.default = '10.13.1.100:13255'; | |
| o.placeholder = 'example.com:13255'; |
Generated by Claude Code
There was a problem hiding this comment.
703e2ad to
2224627
Compare
|
Thanks for the review. Four of the five points are fixed in the amended commit; the translation one needs a maintainer decision.
So the status line really did read "Not found" forever for every non-root session. Changed to Poller leaking on re-render — fixed. The callback is now a module-level Default obfuscation key — dropped here and in the daemon's shipped UCI config. The config generator in the packages PR no longer defaults it either, so a missing key is now a reported error rather than a known secret. Dead placeholders — removed the The |
Configures wg-obfuscator, the WireGuard traffic obfuscator, from the web interface. The view maps every UCI option that the daemon's config generator reads: listen address and port, target, obfuscation key, protocol masking, dummy padding, the three timeouts, firewall mark, logging and the static bindings used for two-way mode. It also reports whether the service is running and its generated configuration exists, and offers a restart button. The interface is a client-side JavaScript view, so it depends on luci-base alone and needs no Lua runtime. Translations are included for German, Spanish, French, Brazilian Portuguese, Russian, Turkish, Ukrainian and Simplified Chinese. The daemon that consumes these options is submitted to the packages feed separately, as "wg-obfuscator: add new package". Signed-off-by: Alexey Cluster <cluster@cluster.wtf>
2224627 to
54e044e
Compare
|
No new review comments on this PR. While fixing the matching |
| "description": "Grant access to WireGuard Obfuscator configuration", | ||
| "read": { | ||
| "file": { | ||
| "/var/etc/wg-obfuscator.conf": [ "list" ] |
There was a problem hiding this comment.
list is the right permission now, but the path still won't match: rpc_check_path resolves symlinks and re-runs the ACL check against the realpath (file.c:269-277), and /var is a symlink to tmp (base-files/Makefile:224), so the grant is evaluated as /tmp/etc/wg-obfuscator.conf and non-root sessions still get EACCES. Grant both spellings, the way luci-app-adblock does for its /var/run paths.`` This is likely why the 25.12.5 test passed — that rpcd predates the symlink re-authorization.
| "/var/etc/wg-obfuscator.conf": [ "list" ] | |
| "/var/etc/wg-obfuscator.conf": [ "list" ], | |
| "/tmp/etc/wg-obfuscator.conf": [ "list" ] |
Generated by Claude Code
| o.placeholder = '0xdead'; | ||
| o.default = '0'; |
There was a problem hiding this comment.
nit: the dead-placeholder pair is back here — the field prefills with 0, so the 0xdead hint never shows. The description already documents that 0 disables the mark, so the default can go.
| o.placeholder = '0xdead'; | |
| o.default = '0'; | |
| o.placeholder = '0xdead'; |
Generated by Claude Code
Pull request details
Description
Adds a LuCI interface for
wg-obfuscator, the WireGuard traffic obfuscator.The page sits under Services → WireGuard Obfuscator and is a client-side JavaScript view, so it depends on
luci-basealone and needs no Lua runtime. It maps every UCI option that the daemon's configuration generator reads: listen address and port, target, obfuscation key, protocol masking, dummy padding, the idle/incoming/resolve timeouts, firewall mark, log destination and timestamps, maximum clients, and the static bindings used for two-way mode. Above the form it polls the service state throughubus service list, reports whether the generated configuration exists, counts the enabled instances and offers a restart button.Validation uses the stock
luci-basedatatypes (hostport,port,ipaddr,range) instead of hand-written checks. The static bindings field is validated line by line againsthost:port:localport, accepting hostnames since the daemon resolves them.Translations are included for German, Spanish, French, Brazilian Portuguese, Russian, Turkish, Ukrainian and Simplified Chinese;
po/templates/wg-obfuscator.potwas generated withbuild/i18n-sync.sh.Screenshot or video of changes (if applicable)
Maintainer (preferred)
@ClusterM
(New package. I am the upstream author of
wg-obfuscatorand will maintain this app.)Tested on
OpenWrt version: OpenWrt 25.12.5 (r33051-f5dae5ece4) on a Cudy WR3000 v1 (mediatek/filogic)
LuCI version: luci-base 26.180.75667~128a781
Web browser(s): Google Chrome 150.0.7871.186 (Official Build) (64-bit)
Verified on that device:
luci-i18n-wg-obfuscator-*packages build and install cleanly/admin/services/wg-obfuscatordispatches to the view and the menu dependency on/usr/bin/wg-obfuscatorresolvesservice listfor the status, and the init scriptrestart, which regenerates the daemon configuration/cgi-bin/luci/admin/translations/<lang>Checklist
Depends on openwrt/packages#30441, which adds the
wg-obfuscatordaemon this app configures and whichLUCI_DEPENDSreferences. Filed as a draft until that one lands.