Addresses the three non-blocking notes from #292: - README's plugin_api requirement was stale (22) vs the manifest's real minimum (17, the onExit lifecycle addition) — corrected, and pinned the noctalia version floor to beta.7 (the first tagged release plugin_api actually reaches 17 in). - apply()'s privilege path ran the whole discovery+mutate script through `priv sh -c '...'`, which the documented sudoers rule (NOPASSWD: /usr/bin/nmcli) never covers — sudo -n always failed. Now the privilege prefix is applied to each of the two mutating nmcli calls individually, never to a wrapping shell. - Regenerated thumbnail.webp. Co-authored-by: nightwatch75 <nightwatch75@users.noreply.github.com>
This commit is contained in:
co-authored by
nightwatch75
parent
b9d21951ec
commit
f222cdee2b
@@ -75,8 +75,8 @@ neighbouring provider (what scroll sends).
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- noctalia v5.0.0-beta.6 or newer for the core plugin; the gesture remapping
|
- noctalia v5.0.0-beta.7 or newer (`plugin_api = 17`, for the `onExit`
|
||||||
and lookup tester need a newer build still (`plugin_api = 22`)
|
lifecycle cleanup in `service.luau`)
|
||||||
- NetworkManager (`networkmanager`, provides `nmcli`) with an active connection
|
- NetworkManager (`networkmanager`, provides `nmcli`) with an active connection
|
||||||
- Permission to modify system connections (see *Privileges* below)
|
- Permission to modify system connections (see *Privileges* below)
|
||||||
- `dig` (bind-tools/dnsutils) or `nslookup`, optional — only the lookup
|
- `dig` (bind-tools/dnsutils) or `nslookup`, optional — only the lookup
|
||||||
@@ -87,13 +87,19 @@ neighbouring provider (what scroll sends).
|
|||||||
*Privilege command* is **empty by default**: NetworkManager's polkit policy
|
*Privilege command* is **empty by default**: NetworkManager's polkit policy
|
||||||
usually lets active local sessions modify system connections without a
|
usually lets active local sessions modify system connections without a
|
||||||
password. If you get a "not authorized" error, set it to `pkexec` (shows
|
password. If you get a "not authorized" error, set it to `pkexec` (shows
|
||||||
noctalia's own polkit prompt) or `sudo -n` with a matching sudoers rule:
|
noctalia's own polkit prompt) or `sudo -n` with a matching sudoers rule.
|
||||||
|
The privilege command is applied to the `nmcli con mod` and `nmcli device
|
||||||
|
reapply` calls individually — never to a wrapping shell — so the sudoers
|
||||||
|
rule only ever needs to name `nmcli` itself:
|
||||||
|
|
||||||
```
|
```
|
||||||
# /etc/sudoers.d/nmcli-dns
|
# /etc/sudoers.d/nmcli-dns
|
||||||
youruser ALL=(root) NOPASSWD: /usr/bin/nmcli
|
youruser ALL=(root) NOPASSWD: /usr/bin/nmcli
|
||||||
```
|
```
|
||||||
|
|
||||||
|
With `pkexec`, this means an apply may show its polkit prompt twice (once
|
||||||
|
per elevated `nmcli` call) instead of once.
|
||||||
|
|
||||||
Or grant it via a polkit rule and keep the setting empty:
|
Or grant it via a polkit rule and keep the setting empty:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
-- binding that opens its own settings, and that default is exactly what's
|
-- binding that opens its own settings, and that default is exactly what's
|
||||||
-- wanted here.
|
-- wanted here.
|
||||||
|
|
||||||
local STATE_KEY = "dns_state"
|
local STATE_KEY = "dns_state" -- published by service.luau
|
||||||
|
|
||||||
local GLYPH_UNKNOWN = "globe"
|
local GLYPH_UNKNOWN = "globe"
|
||||||
|
|
||||||
local snapshot = nil -- last state published by the service
|
local snapshot = nil -- last state published by the service
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
-- "apply_request" entries this panel emits. Picking a provider applies it
|
-- "apply_request" entries this panel emits. Picking a provider applies it
|
||||||
-- immediately (one nmcli change, no reactivation).
|
-- immediately (one nmcli change, no reactivation).
|
||||||
|
|
||||||
local STATE_KEY = "dns_state"
|
local STATE_KEY = "dns_state" -- published by service.luau
|
||||||
local REQUEST_KEY = "apply_request"
|
local REQUEST_KEY = "apply_request" -- consumed by service.luau
|
||||||
|
|
||||||
local RESOLVE_TIMEOUT_MS = 4000
|
local RESOLVE_TIMEOUT_MS = 4000
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
id = "nightwatch75/dns-switcher"
|
id = "nightwatch75/dns-switcher"
|
||||||
name = "DNS Switcher"
|
name = "DNS Switcher"
|
||||||
version = "0.1.1"
|
version = "0.1.2"
|
||||||
plugin_api = 17
|
plugin_api = 17
|
||||||
author = "nightwatch75"
|
author = "nightwatch75"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
+20
-18
@@ -14,10 +14,13 @@
|
|||||||
-- reapply pushes the change onto the live connection without reactivating
|
-- reapply pushes the change onto the live connection without reactivating
|
||||||
-- it, so the network never drops. The privilege command is empty by default:
|
-- it, so the network never drops. The privilege command is empty by default:
|
||||||
-- NetworkManager's polkit policy lets active local sessions modify system
|
-- NetworkManager's polkit policy lets active local sessions modify system
|
||||||
-- connections on most desktop distros.
|
-- connections on most desktop distros. When set, it is prefixed onto each
|
||||||
|
-- of those two nmcli calls individually (never onto a wrapping shell), so a
|
||||||
|
-- sudoers NOPASSWD rule naming the nmcli binary itself is enough — see
|
||||||
|
-- apply() below and the README's Privileges section.
|
||||||
|
|
||||||
local STATE_KEY = "dns_state"
|
local STATE_KEY = "dns_state" -- published here, read by widget + panel
|
||||||
local REQUEST_KEY = "apply_request"
|
local REQUEST_KEY = "apply_request" -- sent by widget/panel, consumed here
|
||||||
|
|
||||||
local BUILTIN = {
|
local BUILTIN = {
|
||||||
{ id = "google", label = "Google", ip = "8.8.8.8 8.8.4.4", glyph = "brand-google" },
|
{ id = "google", label = "Google", ip = "8.8.8.8 8.8.4.4", glyph = "brand-google" },
|
||||||
@@ -52,10 +55,6 @@ local function trim(value)
|
|||||||
return (value:gsub("^%s+", ""):gsub("%s+$", ""))
|
return (value:gsub("^%s+", ""):gsub("%s+$", ""))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function shellQuote(value)
|
|
||||||
return "'" .. value:gsub("'", "'\\''") .. "'"
|
|
||||||
end
|
|
||||||
|
|
||||||
local function pollSeconds()
|
local function pollSeconds()
|
||||||
return math.max(2, tonumber(cfg("poll_seconds")) or 10)
|
return math.max(2, tonumber(cfg("poll_seconds")) or 10)
|
||||||
end
|
end
|
||||||
@@ -302,23 +301,26 @@ local function apply(provider)
|
|||||||
else
|
else
|
||||||
mods = 'ipv4.dns "' .. safeIp .. '" ipv4.ignore-auto-dns yes'
|
mods = 'ipv4.dns "' .. safeIp .. '" ipv4.ignore-auto-dns yes'
|
||||||
end
|
end
|
||||||
local inner = 'ACT=$(LC_ALL=C nmcli -t -f TYPE,DEVICE,UUID connection show --active 2>/dev/null); '
|
|
||||||
.. [[LINE=$(printf '%s\n' "$ACT" | grep -E '^(802-11-wireless|802-3-ethernet):' | head -n 1); ]]
|
|
||||||
.. [=[[ -n "$LINE" ] || LINE=$(printf '%s\n' "$ACT" | grep -v '^loopback:' | head -n 1); ]=]
|
|
||||||
.. [=[[ -n "$LINE" ] || exit 9; ]=]
|
|
||||||
.. 'DEV=$(printf \'%s\' "$LINE" | cut -d: -f2); '
|
|
||||||
.. 'UUID=$(printf \'%s\' "$LINE" | cut -d: -f3); '
|
|
||||||
.. 'nmcli con mod "$UUID" ' .. mods .. ' && nmcli device reapply "$DEV"'
|
|
||||||
|
|
||||||
local priv = cfg("privilege_command")
|
local priv = cfg("privilege_command")
|
||||||
if type(priv) ~= "string" then
|
if type(priv) ~= "string" then
|
||||||
priv = ""
|
priv = ""
|
||||||
end
|
end
|
||||||
priv = trim(priv)
|
priv = trim(priv)
|
||||||
local cmd = inner
|
-- Prefixed onto each nmcli invocation individually, never onto a
|
||||||
if priv ~= "" then
|
-- wrapping `sh -c`: the README's sudoers example authorizes the nmcli
|
||||||
cmd = priv .. " sh -c " .. shellQuote(inner)
|
-- binary itself (NOPASSWD: /usr/bin/nmcli), which never covers a shell
|
||||||
end
|
-- run under sudo. Discovering the device/uuid stays unprivileged either
|
||||||
|
-- way (it's a plain read), so only the two mutating calls need it.
|
||||||
|
local privPrefix = priv ~= "" and (priv .. " ") or ""
|
||||||
|
|
||||||
|
local cmd = 'ACT=$(LC_ALL=C nmcli -t -f TYPE,DEVICE,UUID connection show --active 2>/dev/null); '
|
||||||
|
.. [[LINE=$(printf '%s\n' "$ACT" | grep -E '^(802-11-wireless|802-3-ethernet):' | head -n 1); ]]
|
||||||
|
.. [=[[ -n "$LINE" ] || LINE=$(printf '%s\n' "$ACT" | grep -v '^loopback:' | head -n 1); ]=]
|
||||||
|
.. [=[[ -n "$LINE" ] || exit 9; ]=]
|
||||||
|
.. 'DEV=$(printf \'%s\' "$LINE" | cut -d: -f2); '
|
||||||
|
.. 'UUID=$(printf \'%s\' "$LINE" | cut -d: -f3); '
|
||||||
|
.. privPrefix .. 'nmcli con mod "$UUID" ' .. mods .. ' && ' .. privPrefix .. 'nmcli device reapply "$DEV"'
|
||||||
|
|
||||||
changing = true
|
changing = true
|
||||||
publish()
|
publish()
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 79 KiB |
Reference in New Issue
Block a user