This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch nm-vpn-username-capture
in repository enlightenment.
View the commit online.
commit 86f319fea8ff6b8d114a417fa45c81d44112436e
Author: [email protected] <[email protected]>
AuthorDate: Sun Jun 21 20:43:57 2026 -0600
docs: design for NM VPN username capture
NetworkManager never prompts for the OpenVPN username (it is a connection
property, not a secret), so importing an .ovpn with bare auth-user-pass
yields an unusable connection. Design adds a shared username-capture dialog
wired into both the post-import and connect-time paths.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
---
.../2026-06-21-nm-vpn-username-capture-design.md | 119 +++++++++++++++++++++
1 file changed, 119 insertions(+)
diff --git a/docs/superpowers/specs/2026-06-21-nm-vpn-username-capture-design.md b/docs/superpowers/specs/2026-06-21-nm-vpn-username-capture-design.md
new file mode 100644
index 000000000..fdf66c473
--- /dev/null
+++ b/docs/superpowers/specs/2026-06-21-nm-vpn-username-capture-design.md
@@ -0,0 +1,119 @@
+# NetworkManager VPN username capture — design
+
+**Date:** 2026-06-21
+**Module:** `src/modules/networkmanager`
+
+## Problem
+
+NetworkManager splits VPN credentials into two unrelated categories:
+
+| Field | Storage | How it is set |
+|-------|---------|----------------|
+| **username** | `vpn.data["username"]` — a connection **property** | Connection editor / import only |
+| **password** | `vpn.secrets["password"]` — a **secret** | Requested at connect time via the SecretAgent |
+
+The SecretAgent D-Bus API (`GetSecrets`) only ever deals with secrets. NM has no
+protocol path to prompt for a missing *property*, so it never asks for the
+username. Importing an `.ovpn` that carries a bare `auth-user-pass` (no inline
+credentials) produces a connection with `password-flags=1` but **no `username`
+key** in `vpn.data` — the connection is unusable and the agent dialog only shows
+a password field.
+
+Verified on the live `vpnbook-ca196-tcp443` connection:
+
+```
+vpn.data = "" connection-type = password-tls, password-flags = 1, ... # no username
+```
+
+This is long-standing, widely reported NetworkManager behaviour, not a defect in
+the Enlightenment module's agent dialog.
+
+### Known upstream reports
+
+- Red Hat Bugzilla #1535517 — *[RFE] NetworkManager OpenVPN does not prompt for username when missing*
+ https://bugzilla.redhat.com/show_bug.cgi?id=1535517
+- Red Hat Bugzilla #1548873 — *NetworkManager asks for a password when connecting to OpenVPN*
+ https://bugzilla.redhat.com/show_bug.cgi?id=1548873
+- Arch Linux Forums #286378 — *networkmanager-openvpn 1.10.2-3: can't save my VPN password*
+ https://bbs.archlinux.org/viewtopic.php?id=286378
+- Arch Linux Forums #225395 — *NetworkManager unable to connect to OpenVPN*
+ https://bbs.archlinux.org/viewtopic.php?id=225395
+- pop-os/cosmic-settings #1820 — *VPN connection fails with "No valid secrets" — password not passed to NetworkManager*
+ https://github.com/pop-os/cosmic-settings/issues/1820
+
+## Approach
+
+A reusable username-capture dialog that persists the entered value to
+`vpn.data["username"]` (a property, never a secret), wired into two entry
+points: just after import, and at connect time for connections that still lack a
+username (imported before this fix, or created elsewhere).
+
+## Components
+
+### 1. Shared helpers — new `e_networkmanager_vpn_username.{c,h}`
+
+- `Eina_Bool enm_vpn_username_needed(const char *svc_short, const char *conn_type, const char *current_username)`
+ Returns true when the VPN type uses username auth and `current_username` is
+ NULL/empty. For `openvpn`, needed when `conn_type` is `password` or
+ `password-tls`; for `pptp` / `l2tp` / `fortisslvpn` / `*swan` (xauth) / `vpnc`,
+ needed whenever the username is empty. Encodes the same per-type knowledge that
+ already lives in `_agent_vpn_default_secrets[]`.
+
+- `void enm_vpn_username_set(const char *conn_name, const char *username, Enm_Username_Done_Cb cb, void *data)`
+ Async `nmcli connection modify <name> vpn.data username=<val>`, reusing the
+ `ecore_exe_pipe_run` + `_shell_escape_single` pattern from
+ `e_networkmanager_import.c`.
+
+- `void enm_vpn_username_dialog(const char *conn_name, const char *type_label, const char *initial, Enm_Username_Entered_Cb cb, void *data)`
+ The shared dialog: a single non-password `elm_entry`, Connect/Cancel buttons,
+ Enter-to-confirm, Escape-to-cancel — mirroring `agent.c` conventions. Calls
+ `cb(username)` on OK, `cb(NULL)` on cancel.
+
+The source file carries a header comment explaining *why* it exists, citing the
+five upstream reports above with full URLs.
+
+### 2. Post-import entry point — `e_mod_main.c` + `e_networkmanager_import.c`
+
+- Add **stdout** capture to the import subprocess (currently only stderr is
+ piped) and parse the connection name from
+ `Connection '<name>' (uuid) successfully added`, passing it to the done cb.
+- In `_enm_vpn_import_done_cb`, on success query the new connection's
+ `connection-type` + `username` via `nmcli -g vpn.data connection show <name>`.
+ If `enm_vpn_username_needed`, show the shared dialog; on OK call
+ `enm_vpn_username_set`.
+
+### 3. Connect-time entry point — `agent.c` + `e_networkmanager.c`
+
+- In `_agent_get_secrets` (vpn branch) look up `username` / `connection-type`
+ from the already-parsed `info.vpn_data` via `_agent_vpn_data_find`. If
+ `enm_vpn_username_needed`, pass two new args up the `vpn_request` callback:
+ `Eina_Bool need_username` and `const char *conn_type`.
+- In `_vpn_dialog_new`, when `need_username` is set, prepend a synthetic username
+ row (plain entry), flagged in the dialog struct as a *property* field, distinct
+ from the secret fields.
+- In `_dialog_send_ok` (vpn branch): the property-username value is **not** sent
+ via `e_nm_agent_reply_vpn_secrets`; instead call `enm_vpn_username_set` to
+ persist it to `vpn.data`, then reply with the actual secrets.
+
+ **Caveat to verify during testing:** persisting mid-activation may only take
+ effect on the next connect attempt. If live testing shows the current attempt
+ fails, also include `username` in the returned secrets dict (as nm-applet
+ does) as a belt-and-suspenders measure. This is the single point resolved
+ against live behaviour rather than designed up front.
+
+### 4. Cleanup
+
+Remove the leftover `printf("NM: …")` debug lines in `e_networkmanager.c` and
+`agent.c` while touching these paths.
+
+## Testing
+
+- Manual: re-import the `vpnbook` `.ovpn`, confirm the username dialog appears,
+ verify `nmcli -g vpn.data connection show <name>` shows `username=`, then
+ connect (password-only prompt) and confirm the tunnel comes up.
+- Unit: a standalone test of the `enm_vpn_username_needed` type/conn-type matrix.
+
+## Out of scope
+
+A full VPN connection editor. This change only captures a missing username; it
+does not provide general editing of arbitrary VPN properties.
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.