twinfi 0.13.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. twinfi-0.13.0/LICENSE +21 -0
  2. twinfi-0.13.0/PKG-INFO +508 -0
  3. twinfi-0.13.0/README.md +467 -0
  4. twinfi-0.13.0/pyproject.toml +129 -0
  5. twinfi-0.13.0/setup.cfg +4 -0
  6. twinfi-0.13.0/twinfi.egg-info/PKG-INFO +508 -0
  7. twinfi-0.13.0/twinfi.egg-info/SOURCES.txt +85 -0
  8. twinfi-0.13.0/twinfi.egg-info/dependency_links.txt +1 -0
  9. twinfi-0.13.0/twinfi.egg-info/entry_points.txt +6 -0
  10. twinfi-0.13.0/twinfi.egg-info/requires.txt +6 -0
  11. twinfi-0.13.0/twinfi.egg-info/top_level.txt +2 -0
  12. twinfi-0.13.0/twinfi_cli/__init__.py +3 -0
  13. twinfi-0.13.0/twinfi_cli/__main__.py +6 -0
  14. twinfi-0.13.0/twinfi_cli/cli.py +219 -0
  15. twinfi-0.13.0/twinfi_cli/cmd/__init__.py +1 -0
  16. twinfi-0.13.0/twinfi_cli/cmd/clients.py +63 -0
  17. twinfi-0.13.0/twinfi_cli/cmd/completion.py +152 -0
  18. twinfi-0.13.0/twinfi_cli/cmd/config.py +134 -0
  19. twinfi-0.13.0/twinfi_cli/cmd/detect.py +77 -0
  20. twinfi-0.13.0/twinfi_cli/cmd/hotspot.py +98 -0
  21. twinfi-0.13.0/twinfi_cli/cmd/install.py +184 -0
  22. twinfi-0.13.0/twinfi_cli/cmd/profile.py +54 -0
  23. twinfi-0.13.0/twinfi_cli/cmd/qr.py +61 -0
  24. twinfi-0.13.0/twinfi_cli/cmd/service.py +199 -0
  25. twinfi-0.13.0/twinfi_cli/cmd/status.py +89 -0
  26. twinfi-0.13.0/twinfi_cli/cmd/usb.py +140 -0
  27. twinfi-0.13.0/twinfi_cli/config/__init__.py +1 -0
  28. twinfi-0.13.0/twinfi_cli/config/model.py +158 -0
  29. twinfi-0.13.0/twinfi_cli/config/store.py +116 -0
  30. twinfi-0.13.0/twinfi_cli/config/validate.py +122 -0
  31. twinfi-0.13.0/twinfi_cli/core/__init__.py +1 -0
  32. twinfi-0.13.0/twinfi_cli/core/errors.py +45 -0
  33. twinfi-0.13.0/twinfi_cli/core/fsutil.py +39 -0
  34. twinfi-0.13.0/twinfi_cli/core/lock.py +45 -0
  35. twinfi-0.13.0/twinfi_cli/core/log.py +71 -0
  36. twinfi-0.13.0/twinfi_cli/core/output.py +136 -0
  37. twinfi-0.13.0/twinfi_cli/core/paths.py +63 -0
  38. twinfi-0.13.0/twinfi_cli/core/shell.py +127 -0
  39. twinfi-0.13.0/twinfi_cli/data/com.github.twinfi.policy +24 -0
  40. twinfi-0.13.0/twinfi_cli/data/twinfi-sleep +42 -0
  41. twinfi-0.13.0/twinfi_cli/data/twinfi.openrc +13 -0
  42. twinfi-0.13.0/twinfi_cli/data/twinfi.runit +3 -0
  43. twinfi-0.13.0/twinfi_cli/data/twinfi.service +32 -0
  44. twinfi-0.13.0/twinfi_cli/hw/__init__.py +1 -0
  45. twinfi-0.13.0/twinfi_cli/hw/capability.py +87 -0
  46. twinfi-0.13.0/twinfi_cli/hw/combinations.py +164 -0
  47. twinfi-0.13.0/twinfi_cli/hw/interfaces.py +158 -0
  48. twinfi-0.13.0/twinfi_cli/hw/usb.py +188 -0
  49. twinfi-0.13.0/twinfi_cli/legacy.py +122 -0
  50. twinfi-0.13.0/twinfi_cli/net/__init__.py +1 -0
  51. twinfi-0.13.0/twinfi_cli/net/channels.py +205 -0
  52. twinfi-0.13.0/twinfi_cli/net/clients.py +213 -0
  53. twinfi-0.13.0/twinfi_cli/net/dnsmasq.py +50 -0
  54. twinfi-0.13.0/twinfi_cli/net/firewall.py +212 -0
  55. twinfi-0.13.0/twinfi_cli/net/hostapd.py +125 -0
  56. twinfi-0.13.0/twinfi_cli/net/iface.py +73 -0
  57. twinfi-0.13.0/twinfi_cli/net/nm.py +163 -0
  58. twinfi-0.13.0/twinfi_cli/net/strategies.py +406 -0
  59. twinfi-0.13.0/twinfi_cli/net/subnet.py +53 -0
  60. twinfi-0.13.0/twinfi_cli/net/supervisor.py +126 -0
  61. twinfi-0.13.0/twinfi_cli/net/transaction.py +48 -0
  62. twinfi-0.13.0/twinfi_cli/net/wpa.py +409 -0
  63. twinfi-0.13.0/twinfi_cli/services/__init__.py +1 -0
  64. twinfi-0.13.0/twinfi_cli/services/autostart.py +35 -0
  65. twinfi-0.13.0/twinfi_cli/services/detect.py +127 -0
  66. twinfi-0.13.0/twinfi_cli/services/guard.py +73 -0
  67. twinfi-0.13.0/twinfi_cli/services/hotspot.py +349 -0
  68. twinfi-0.13.0/twinfi_cli/services/installation.py +187 -0
  69. twinfi-0.13.0/twinfi_cli/services/watch.py +158 -0
  70. twinfi-0.13.0/twinfi_cli/state.py +76 -0
  71. twinfi-0.13.0/twinfi_gui/__init__.py +1 -0
  72. twinfi-0.13.0/twinfi_gui/__main__.py +6 -0
  73. twinfi-0.13.0/twinfi_gui/app.py +131 -0
  74. twinfi-0.13.0/twinfi_gui/backend.py +179 -0
  75. twinfi-0.13.0/twinfi_gui/compat.py +234 -0
  76. twinfi-0.13.0/twinfi_gui/data/com.github.twinfi.Gtk.desktop +13 -0
  77. twinfi-0.13.0/twinfi_gui/data/com.github.twinfi.Gtk.metainfo.xml +103 -0
  78. twinfi-0.13.0/twinfi_gui/data/icons/hicolor/scalable/apps/com.github.twinfi.Gtk.svg +25 -0
  79. twinfi-0.13.0/twinfi_gui/data/icons/hicolor/symbolic/apps/com.github.twinfi.Gtk-symbolic.svg +7 -0
  80. twinfi-0.13.0/twinfi_gui/helpers.py +221 -0
  81. twinfi-0.13.0/twinfi_gui/pages/__init__.py +1 -0
  82. twinfi-0.13.0/twinfi_gui/pages/clients.py +143 -0
  83. twinfi-0.13.0/twinfi_gui/pages/hotspot.py +190 -0
  84. twinfi-0.13.0/twinfi_gui/pages/settings.py +239 -0
  85. twinfi-0.13.0/twinfi_gui/share.py +72 -0
  86. twinfi-0.13.0/twinfi_gui/tray.py +418 -0
  87. twinfi-0.13.0/twinfi_gui/window.py +200 -0
twinfi-0.13.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Karan Kumar Sah
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
twinfi-0.13.0/PKG-INFO ADDED
@@ -0,0 +1,508 @@
1
+ Metadata-Version: 2.4
2
+ Name: twinfi
3
+ Version: 0.13.0
4
+ Summary: Run a Wi-Fi hotspot on Linux while staying connected to Wi-Fi (AP+STA)
5
+ Author: twinfi contributors
6
+ Maintainer: krotrn
7
+ License: MIT
8
+ Project-URL: Homepage, https://krotrn.github.io/twinfi/
9
+ Project-URL: Documentation, https://krotrn.github.io/twinfi/
10
+ Project-URL: Source, https://github.com/krotrn/twinfi
11
+ Project-URL: Issues, https://github.com/krotrn/twinfi/issues
12
+ Project-URL: Changelog, https://github.com/krotrn/twinfi/blob/main/CHANGELOG.md
13
+ Keywords: wifi,wi-fi,hotspot,wifi-hotspot,access-point,ap-sta,ap+sta,tethering,wifi-direct,p2p,networkmanager,nmcli,hostapd,dnsmasq,linux,gtk4,libadwaita
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Environment :: Console
16
+ Classifier: Environment :: X11 Applications :: GTK
17
+ Classifier: Intended Audience :: End Users/Desktop
18
+ Classifier: Intended Audience :: System Administrators
19
+ Classifier: License :: OSI Approved :: MIT License
20
+ Classifier: Operating System :: POSIX :: Linux
21
+ Classifier: Environment :: X11 Applications :: Gnome
22
+ Classifier: Natural Language :: English
23
+ Classifier: Programming Language :: Python :: 3
24
+ Classifier: Programming Language :: Python :: 3 :: Only
25
+ Classifier: Programming Language :: Python :: 3.10
26
+ Classifier: Programming Language :: Python :: 3.11
27
+ Classifier: Programming Language :: Python :: 3.12
28
+ Classifier: Programming Language :: Python :: 3.13
29
+ Classifier: Programming Language :: Python :: 3.14
30
+ Classifier: Topic :: System :: Networking
31
+ Classifier: Topic :: System :: Networking :: Firewalls
32
+ Classifier: Topic :: System :: Systems Administration
33
+ Requires-Python: >=3.10
34
+ Description-Content-Type: text/markdown
35
+ License-File: LICENSE
36
+ Provides-Extra: gui
37
+ Requires-Dist: qrcode[pil]>=7.4; extra == "gui"
38
+ Provides-Extra: p2p
39
+ Requires-Dist: jeepney>=0.7; extra == "p2p"
40
+ Dynamic: license-file
41
+
42
+ # twinfi: Linux Wi-Fi hotspot that keeps your Wi-Fi connected
43
+
44
+ **Run a WiFi hotspot on Linux while staying connected to WiFi.**
45
+
46
+ [![CI](https://github.com/krotrn/twinfi/actions/workflows/ci.yml/badge.svg)](https://github.com/krotrn/twinfi/actions/workflows/ci.yml)
47
+ [![PyPI](https://img.shields.io/pypi/v/twinfi)](https://pypi.org/project/twinfi/)
48
+ [![Python](https://img.shields.io/pypi/pyversions/twinfi)](https://pypi.org/project/twinfi/)
49
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/krotrn/twinfi/blob/main/LICENSE)
50
+
51
+ twinfi is a command-line tool and GTK 4 desktop app for Linux that shares your
52
+ internet over a Wi-Fi hotspot while the same Wi-Fi card stays connected to
53
+ your Wi-Fi network (AP+STA mode). It works with NetworkManager, hostapd and
54
+ dnsmasq on Ubuntu, Debian, Fedora, Arch and other distributions.
55
+
56
+ `nmcli device wifi hotspot` takes over your WiFi card and drops your
57
+ connection. Most modern cards can actually be a client and an access point at
58
+ the same time ("AP+STA"). twinfi finds out whether yours can, sets the hotspot
59
+ up the right way for it, keeps it healthy, and cleans up completely when you
60
+ stop it.
61
+
62
+ <p align="center">
63
+ <img src="https://raw.githubusercontent.com/krotrn/twinfi/main/docs/screenshots/hotspot.png" alt="twinfi desktop app: hotspot running while Wi-Fi stays connected" width="300">
64
+ </p>
65
+
66
+ ```
67
+ $ twinfi detect
68
+
69
+ Capability report for wlo1
70
+ → Driver: iwlwifi
71
+ → Chipset: Intel Corporation Wi-Fi 6 AX200
72
+
73
+ ✔ AP mode (hotspot) yes
74
+ ✔ STA mode (WiFi client) yes
75
+ ✔ AP + STA at the same time yes
76
+ ✘ AP on a different channel than STA no
77
+
78
+ Methods
79
+ hostapd ready
80
+ nmcli ready
81
+
82
+ Verdict
83
+ ✔ Your card can run a hotspot while staying connected to WiFi.
84
+ ✔ The hotspot will use the same channel as your WiFi connection.
85
+ → Next: sudo twinfi start
86
+ ```
87
+
88
+ ## Features
89
+
90
+ - **Reads the hardware properly**: parses the driver's interface combinations
91
+ to decide whether AP+STA is possible and whether the hotspot must share the
92
+ WiFi channel.
93
+ - **Keeps your connection**: the hotspot runs on a virtual interface. If
94
+ your WiFi's channel can't host (radar/DFS channels, or 5 GHz channels the
95
+ card blocks), it runs as a Wi-Fi Direct group on a channel of its own, as
96
+ Windows does, on cards that support that. A mode that drops WiFi is used
97
+ only if you allow it (`--allow-disconnect`).
98
+ - **All-or-nothing setup**: every step registers its own undo, so a failure
99
+ part-way leaves nothing behind, and `stop` removes exactly what `start` added.
100
+ - **Stays up**: a watcher restarts the hotspot after suspend/resume or a
101
+ driver reset, moves it when your WiFi changes channel, and steps aside when
102
+ it would keep your WiFi from reconnecting.
103
+ - **Works with your firewall**: firewalld, iptables (including ufw/docker
104
+ setups) and nftables. Picks a hotspot subnet that doesn't clash with your
105
+ networks. DNS goes through your normal resolver, so captive portals and VPN
106
+ DNS keep working.
107
+ - **Fast**: 802.11n/ac + WMM, and the right regulatory country code.
108
+ - **Client management** (hostapd mode): list, kick, block, and rate-limit
109
+ clients, or let only the devices you list join.
110
+ - **Hidden network** option, and a QR code to join (`twinfi qr` or the app).
111
+ - **Safe by default**: a random password on first start (never a shared
112
+ default), passwords never on a command line, a scoped polkit action for the
113
+ GUI.
114
+ - **Desktop app** (GTK 4/libadwaita) with device management, QR-code sharing
115
+ and a system tray icon.
116
+
117
+ ## Install
118
+
119
+ One command for any distribution:
120
+
121
+ ```bash
122
+ curl -fsSL https://raw.githubusercontent.com/krotrn/twinfi/main/get.sh | sh
123
+ ```
124
+
125
+ It uses the package below for your distribution (pacman repository, PPA, or
126
+ the release `.deb` on Debian), and installs from source when there is none,
127
+ with the dependencies from your package manager. It also installs `hostapd`
128
+ and `dnsmasq`, and the desktop app's libraries when you're in a graphical
129
+ session. Run it again to update. Options go after `sh -s --`, e.g.
130
+ `curl -fsSL … | sh -s -- --cli-only`: `--cli-only`, `--gui`, `--source`
131
+ (skip the packages), `--dry-run` (show what it would run).
132
+
133
+ > **Coming from apsta?** twinfi is apsta's new name (since 0.13). Packages and
134
+ > `get.sh` replace apsta, and the first `sudo twinfi` command moves your
135
+ > settings from `/etc/apsta` and your boot service. The `apsta` command still
136
+ > works for now and reminds you of the new name. See the
137
+ > [changelog](https://github.com/krotrn/twinfi/blob/main/CHANGELOG.md) for each install route.
138
+
139
+ Or install it yourself:
140
+
141
+ ### Ubuntu / Pop!\_OS (PPA)
142
+
143
+ ```bash
144
+ sudo add-apt-repository ppa:krotrn/apsta
145
+ sudo apt update
146
+ sudo apt install twinfi
147
+ ```
148
+
149
+ ### Arch Linux and derivatives
150
+
151
+ ```bash
152
+ sudo tee -a /etc/pacman.conf >/dev/null <<'CONF'
153
+
154
+ [twinfi]
155
+ SigLevel = Optional TrustAll
156
+ Server = https://github.com/krotrn/twinfi/releases/download/arch-repo
157
+ CONF
158
+ sudo pacman -Sy twinfi # or: yay -S twinfi
159
+ sudo pacman -S --needed hostapd dnsmasq # recommended (hostapd mode)
160
+ ```
161
+
162
+ ### From source (any distribution)
163
+
164
+ ```bash
165
+ git clone https://github.com/krotrn/twinfi && cd twinfi
166
+ sudo ./install.sh # installs into /usr/local
167
+ sudo ./install.sh --uninstall # removes it again
168
+ ```
169
+
170
+ `sudo twinfi update` and `sudo twinfi uninstall` work the same way it was
171
+ installed, whichever route that was: the pacman repository, the PPA, the
172
+ `.deb`, or `install.sh`.
173
+
174
+ Runtime requirements: Python ≥ 3.10, NetworkManager, `iw`, `iproute2`.
175
+ Recommended: `hostapd` + `dnsmasq` (needed for client management), and one of
176
+ `iptables`/`nftables`/`firewalld`. On Fedora, openSUSE, Alpine and Void, the
177
+ Python library `jeepney` enables the [Wi-Fi Direct fallback](https://github.com/krotrn/twinfi/blob/main/docs/wifi-direct.md). Desktop app: see [Desktop app](#desktop-app).
178
+
179
+ > **pipx/pip users:** `sudo` can't see `~/.local/bin`. Install system-wide
180
+ > with `sudo pipx install --global twinfi` (pipx ≥ 1.5), or use the packages above.
181
+
182
+ ## Usage
183
+
184
+ ```bash
185
+ twinfi detect # what can my card do?
186
+ sudo twinfi start # start (keeps WiFi when the card allows it)
187
+ sudo twinfi start --allow-disconnect # also allow a mode that drops WiFi
188
+ sudo twinfi stop
189
+ twinfi status # --check: exit code only (0 running, 3 not)
190
+
191
+ sudo twinfi enable # start at boot, recover after sleep (systemd/OpenRC/runit)
192
+ sudo twinfi disable
193
+
194
+ sudo twinfi update # update to the latest release (alias: upgrade)
195
+ sudo twinfi uninstall # remove twinfi, its settings and its log (--keep-config keeps settings)
196
+ ```
197
+
198
+ ### Configuration
199
+
200
+ ```bash
201
+ twinfi config # show the active profile
202
+ sudo twinfi config --set ssid=MyHotspot --set band=a
203
+ sudo twinfi config --set method=p2p --set channel=149 # own channel, always on 5 GHz 149
204
+ sudo twinfi config --password-stdin # prompts; nothing ends up in shell history
205
+ sudo twinfi config --generate-password
206
+ sudo twinfi config --show-password
207
+ sudo twinfi qr # QR code a phone camera can scan to join
208
+
209
+ twinfi profile list
210
+ sudo twinfi profile create travel
211
+ sudo twinfi profile use travel
212
+ ```
213
+
214
+ Settings:
215
+
216
+ | Setting | Values | Meaning |
217
+ | ------- | ------ | ------- |
218
+ | `ssid`, `password` | | The network's name and password |
219
+ | `band` | `bg` (2.4 GHz), `a` (5 GHz) | Used whenever the hotspot has a channel of its own |
220
+ | `channel` | `auto` (default) or a number | `auto` picks the least crowded channel the card allows |
221
+ | `method` | `auto` (default), `hostapd`, `nmcli`, `p2p`, `nmcli-single` | How the hotspot runs. `p2p` (Wi-Fi Direct) always uses your band and channel, at the cost of shared speed ([details](https://github.com/krotrn/twinfi/blob/main/docs/wifi-direct.md)) |
222
+ | `interface` | `auto` (default) or a name | Which WiFi card to use |
223
+ | `hidden` | `yes`, `no` | Stop broadcasting the name; devices type it or scan the QR code |
224
+ | `allowed_macs` | MAC list | Only these devices may join (see below) |
225
+
226
+ On most laptop cards a normal hotspot has to share your WiFi's channel, so
227
+ `band` and `channel` can't always be followed. twinfi never ignores them
228
+ silently: `twinfi start`, `twinfi status` and the app's *Why it runs this way*
229
+ section say what it chose and why, and so does `/var/log/twinfi.log`.
230
+
231
+ Configuration lives in `/etc/twinfi/` and passwords in the root-only
232
+ `/etc/twinfi/secrets.json`.
233
+
234
+ ### Clients (hostapd mode)
235
+
236
+ ```bash
237
+ twinfi clients # connected stations with IP/hostname
238
+ sudo twinfi clients disconnect phone # by hostname, IP or MAC
239
+ sudo twinfi clients disconnect phone --block # and keep it out
240
+ sudo twinfi clients unblock aa:bb:cc:dd:ee:ff
241
+ sudo twinfi clients limit 192.168.42.17 8000 # Kbps, upload and download
242
+ sudo twinfi clients unlimit 192.168.42.17
243
+ ```
244
+
245
+ To let only your own devices join, list their MAC addresses. Anyone else is
246
+ refused even with the password. This needs hostapd mode; twinfi won't start a
247
+ hotspot it can't restrict.
248
+
249
+ ```bash
250
+ sudo twinfi config --set allowed_macs="aa:bb:cc:dd:ee:ff, 11:22:33:44:55:66"
251
+ sudo twinfi config --set allowed_macs= # anyone with the password again
252
+ ```
253
+
254
+ Phones often use a random MAC per network: look up the one they use for your
255
+ hotspot (Android: *Wi-Fi → your hotspot → Privacy*, or set it to the device
256
+ MAC; iPhone: *Private Wi-Fi Address*).
257
+
258
+ ### Scripting
259
+
260
+ `status`, `detect`, `config`, `clients` and `start` accept `--json`. See
261
+ [docs/json-output.md](https://github.com/krotrn/twinfi/blob/main/docs/json-output.md) for the keys and exit codes.
262
+
263
+ ```bash
264
+ twinfi status --json | jq -r '.clients[].ip'
265
+ ```
266
+
267
+ ## Desktop app
268
+
269
+ <p>
270
+ <img src="https://raw.githubusercontent.com/krotrn/twinfi/main/docs/screenshots/hotspot.png" alt="Hotspot tab" width="300">
271
+ <img src="https://raw.githubusercontent.com/krotrn/twinfi/main/docs/screenshots/devices.png" alt="Devices tab" width="300">
272
+ </p>
273
+ <p>
274
+ <img src="https://raw.githubusercontent.com/krotrn/twinfi/main/docs/screenshots/share.png" alt="Share dialog with QR code" width="300">
275
+ <img src="https://raw.githubusercontent.com/krotrn/twinfi/main/docs/screenshots/narrow.png" alt="Narrow window with tabs at the bottom" width="170">
276
+ </p>
277
+
278
+ Open **Hotspot (twinfi)** from your app menu, or run `twinfi-gtk`.
279
+
280
+ - **Hotspot**: one button to start/stop, whether you're still connected to
281
+ your WiFi, connection details, a profile switcher, and **Share**: a QR code
282
+ phones can scan, plus the password.
283
+ - **Devices**: everything connected, with a menu per device to limit its
284
+ speed, disconnect it, or block it. Blocked devices can be unblocked here.
285
+ - **Settings**: network name, password, band, interface, profiles, *Start
286
+ automatically* (boot + recovery after sleep), *Show in the tray at login*,
287
+ and what your WiFi card supports.
288
+
289
+ The window adapts to its size (tabs move to the bottom on narrow windows),
290
+ and follows your light/dark preference. Shortcuts: <kbd>Ctrl</kbd>+<kbd>R</kbd>
291
+ or <kbd>F5</kbd> refresh, <kbd>Ctrl</kbd>+<kbd>Q</kbd> quit.
292
+
293
+ **System tray.** While the app runs, an icon in the panel shows whether the
294
+ hotspot is on and how many devices are connected. Right-click it to start or
295
+ stop the hotspot, share it, open the device list, switch profile or band, turn
296
+ *Start automatically* on or off, or open Settings. Clicking the icon shows or
297
+ hides the window, and closing the window keeps the app in the tray. Turn on
298
+ *Show in the tray at login* in Settings (or run `twinfi-gtk --background`) to
299
+ start straight into the tray. It works wherever the panel supports
300
+ StatusNotifierItem: KDE Plasma, Xfce, Cinnamon, MATE, Budgie, LXQt, waybar and
301
+ other Wayland bars, and GNOME with the AppIndicator extension (included in
302
+ Ubuntu). Bars that only support the old XEmbed tray, such as i3bar and polybar,
303
+ need [snixembed](https://git.sr.ht/~steef/snixembed). Without a tray, the app
304
+ works as before: closing the window quits it.
305
+
306
+ Starting, stopping and changing settings ask for your password through
307
+ polkit. It's remembered for a few minutes, so you aren't asked on every click.
308
+
309
+ **Requirements.** The packages above install everything. From source, install
310
+ your distribution's GTK bindings:
311
+
312
+ | Distribution | Packages |
313
+ | ---------------------- | ------------------------------------------------------------------------------------- |
314
+ | Ubuntu / Debian / Mint | `python3-gi gir1.2-gtk-4.0 gir1.2-adw-1 python3-qrcode python3-pil` |
315
+ | Fedora | `python3-gobject gobject-introspection gtk4 libadwaita python3-qrcode python3-pillow` |
316
+ | Arch | `python-gobject gtk4 libadwaita python-qrcode python-pillow` |
317
+
318
+ It works with libadwaita 1.1 / GTK 4.6 and newer, and uses newer libadwaita
319
+ features when your system has them. CI checks it on Ubuntu 22.04, Debian 12,
320
+ Ubuntu 24.04, Fedora and Arch. `python3-qrcode` is optional; without it,
321
+ Share shows the name and password only.
322
+
323
+ ### Shell completion
324
+
325
+ The Arch and Debian/Ubuntu packages and `install.sh` install completions for
326
+ bash, zsh and fish. To install them yourself (for example after `pip install`),
327
+ pick your shell (`install -D` creates the folder when it doesn't exist yet):
328
+
329
+ ```bash
330
+ twinfi completion bash | sudo install -Dm644 /dev/stdin /etc/bash_completion.d/twinfi
331
+ twinfi completion zsh | sudo install -Dm644 /dev/stdin /usr/local/share/zsh/site-functions/_twinfi
332
+ twinfi completion fish | sudo install -Dm644 /dev/stdin /etc/fish/completions/twinfi.fish
333
+ ```
334
+
335
+ Then open a new terminal. zsh caches completions; if `twinfi <Tab>` still
336
+ does nothing, run `rm -f ~/.zcompdump*` and open another one.
337
+
338
+ ## How it works
339
+
340
+ `twinfi start` picks the first method that works on your machine:
341
+
342
+ | Method | When | WiFi stays up | Client management |
343
+ | -------------- | --------------------------------------- | ------------- | ----------------- |
344
+ | `hostapd` | card supports AP+STA, hostapd installed | yes | yes |
345
+ | `nmcli` | card supports AP+STA | yes | list/kick |
346
+ | `p2p` | WiFi's channel can't host; card can run Wi-Fi Direct on a second channel | yes (speed shared) | list/kick |
347
+ | `nmcli-single` | card supports AP only | **no** | list/kick |
348
+
349
+ ```mermaid
350
+ flowchart LR
351
+ S(["sudo twinfi start"]) --> H{"AP+STA card and<br/>hostapd installed?"}
352
+ H -- "yes" --> HA["hostapd ✔<br/>WiFi stays up"]
353
+ H -- "no / failed" --> N{"AP+STA card?"}
354
+ N -- "yes" --> NM["nmcli ✔<br/>WiFi stays up"]
355
+ N -- "no / failed" --> P{"Wi-Fi Direct on a<br/>second channel?"}
356
+ P -- "yes" --> PG["p2p ✔<br/>WiFi stays up, own channel"]
357
+ P -- "no / failed" --> D{"WiFi not connected, or<br/>--allow-disconnect?"}
358
+ D -- "yes" --> NS["nmcli-single ✔<br/>WiFi drops"]
359
+ D -- "no" --> E(["Explains why, suggests a fix"])
360
+ ```
361
+
362
+ A method that fails part-way is rolled back completely before the next one
363
+ is tried.
364
+
365
+ On single-channel cards (most laptop chips) the hotspot has to use the same
366
+ channel as your WiFi. twinfi reads it from the live connection. Some channels
367
+ can't host a hotspot: radar (DFS) channels 52–144, 6 GHz, and 5 GHz channels
368
+ the card's firmware blocks. On cards that can run a Wi-Fi Direct group on a
369
+ second channel (most Intel cards) twinfi then gives the hotspot a channel of
370
+ its own; the radio switches between the two, so they share its speed. See
371
+ [docs/wifi-direct.md](https://github.com/krotrn/twinfi/blob/main/docs/wifi-direct.md) for which cards and distributions
372
+ support it. On other cards twinfi refuses with an explanation; see
373
+ [docs/5ghz-wifi.md](https://github.com/krotrn/twinfi/blob/main/docs/5ghz-wifi.md).
374
+ The hotspot follows the connection when it changes channel (on systemd,
375
+ also when started with `twinfi start` or the GUI).
376
+
377
+ New to this? [docs/how-it-works.md](https://github.com/krotrn/twinfi/blob/main/docs/how-it-works.md) explains it in plain
378
+ language, with the common problems and fixes. For the design, see
379
+ [docs/ARCHITECTURE.md](https://github.com/krotrn/twinfi/blob/main/docs/ARCHITECTURE.md).
380
+
381
+ ## Troubleshooting
382
+
383
+ - **Won't start while connected to a 5 GHz network** (e.g. a phone hotspot
384
+ or a campus network on a DFS channel)? Your card can't host on that channel
385
+ and has no [Wi-Fi Direct fallback](https://github.com/krotrn/twinfi/blob/main/docs/wifi-direct.md) (`twinfi detect`
386
+ shows whether it does, and what's missing).
387
+ Switch the network to 2.4 GHz, or see [docs/5ghz-wifi.md](https://github.com/krotrn/twinfi/blob/main/docs/5ghz-wifi.md)
388
+ for why and the other fixes.
389
+ - `TWINFI_DEBUG=1 sudo twinfi start` prints every step; privileged runs also log
390
+ JSON lines to `/var/log/twinfi.log`.
391
+ - The service's own log: `journalctl -u twinfi`.
392
+ - In hostapd mode, `journalctl -u twinfi-hostapd -u twinfi-dnsmasq` shows the
393
+ daemons' own logs.
394
+ - Wrong verdict from `twinfi detect`? Please open an issue with
395
+ `twinfi detect --json` and `iw phy phy0 info`.
396
+
397
+ **Desktop app:**
398
+
399
+ - *"No polkit authentication agent is running"*: your session has no agent to
400
+ ask for the password. GNOME, KDE, Cinnamon, MATE and Xfce start one; on
401
+ i3/sway/Hyprland start one yourself, e.g. `polkit-gnome` or `lxpolkit`.
402
+ - *"Not authorized"*: your account isn't an administrator (not in `sudo` /
403
+ `wheel`).
404
+ - *"twinfi is not installed"* window: the desktop app can't find the `twinfi`
405
+ command. Install the CLI (it's in the same package) or put it on `PATH`.
406
+ - Settings changes apply to the next start; stop and start the hotspot.
407
+ - *No tray icon*: your panel needs StatusNotifierItem support. On GNOME,
408
+ install and turn on the *AppIndicator and KStatusNotifierItem Support*
409
+ extension; on i3bar or polybar, run `snixembed`. Without a tray the app
410
+ still works, it just quits when you close the window.
411
+
412
+ If your card can't do AP+STA, `twinfi recommend` suggests USB adapters with
413
+ in-kernel drivers that can (MediaTek mt7921au, mt7612u, mt7610u, mt7925u).
414
+
415
+ ## Compared with other tools
416
+
417
+ | | Keeps your Wi-Fi connected | Picks a mode for your card | Own channel when Wi-Fi is on a DFS / "no IR" channel | Undoes a failed start | GUI |
418
+ | --- | --- | --- | --- | --- | --- |
419
+ | **twinfi** | yes, when the card supports AP+STA | yes (`twinfi detect`) | yes, as a Wi-Fi Direct group (most Intel cards) | yes, step by step | GTK 4 |
420
+ | `nmcli device wifi hotspot` / GNOME Settings hotspot | no, the card becomes the hotspot | no | no | n/a | GNOME Settings |
421
+ | [create_ap](https://github.com/oblique/create_ap) | yes, with a virtual interface | partly | no | partly | no (archived in 2021) |
422
+ | [linux-wifi-hotspot](https://github.com/lakinduakash/linux-wifi-hotspot) | yes, with a virtual interface | partly | no | partly | GTK 3 |
423
+ | hostapd + dnsmasq by hand | if you set it up | you decide | you set it up | no | no |
424
+
425
+ twinfi also handles firewalld, iptables and nftables, picks a subnet that
426
+ doesn't clash with your networks, follows your Wi-Fi when it changes
427
+ channel, and survives suspend/resume.
428
+
429
+ ## Supported hardware
430
+
431
+ Any card whose driver reports an AP+STA interface combination can run a
432
+ hotspot while staying connected. `twinfi detect` tells you for your card.
433
+
434
+ | Card / chipset | Driver | Status |
435
+ | --- | --- | --- |
436
+ | Intel Wi-Fi 6 AX200, AX201 | `iwlwifi` (`iwlmvm`) | AP+STA on the Wi-Fi channel; Wi-Fi Direct fallback tested on AX201 |
437
+ | Other Intel Wi-Fi 5/6/6E (7260 … AX211) | `iwlwifi` (`iwlmvm`) | Expected to work like the AX201 |
438
+ | Intel Wi-Fi 7 (BE200 …) | `iwlwifi` (`iwlmld`) | Unknown, reports welcome |
439
+ | MediaTek USB: mt7921au, mt7925u, mt7612u, mt7610u | `mt76` family | AP+STA (suggested by `twinfi recommend`) |
440
+ | Realtek, Qualcomm/Atheros, Broadcom | various | Depends on the driver; run `twinfi detect` |
441
+
442
+ Tried twinfi on a card that isn't listed? Please
443
+ [open a hardware report](https://github.com/krotrn/twinfi/issues/new?template=hardware_report.yml)
444
+ with `twinfi detect --json`.
445
+
446
+ ## FAQ
447
+
448
+ ### How do I share Wi-Fi over Wi-Fi on Linux without disconnecting?
449
+
450
+ Install twinfi and run `sudo twinfi start`. If your card supports AP+STA, the
451
+ hotspot runs on a second, virtual interface and your Wi-Fi connection stays
452
+ up. `twinfi detect` tells you beforehand whether your card can.
453
+
454
+ ### Why does `nmcli device wifi hotspot` disconnect my Wi-Fi?
455
+
456
+ NetworkManager's hotspot turns the card itself into an access point, so it
457
+ can no longer be a client. twinfi adds a separate access-point interface next
458
+ to the client one instead.
459
+
460
+ ### How do I check if my Wi-Fi card supports AP+STA?
461
+
462
+ Run `twinfi detect`. It reads the driver's interface combinations (the same
463
+ data as `iw phy phy0 info`) and says whether AP and client can run at the
464
+ same time, and whether they must share a channel.
465
+
466
+ ### Can I run a 5 GHz hotspot while connected to Wi-Fi?
467
+
468
+ On most laptop cards the hotspot must use the same channel as your Wi-Fi, so
469
+ it's 5 GHz when your Wi-Fi is on 5 GHz. Radar (DFS) channels and channels the
470
+ firmware blocks can't host a hotspot; on those, twinfi uses a Wi-Fi Direct
471
+ group on its own channel when the card supports it. See
472
+ [5 GHz Wi-Fi](https://github.com/krotrn/twinfi/blob/main/docs/5ghz-wifi.md).
473
+
474
+ ### Which distributions does it work on?
475
+
476
+ Any Linux distribution with NetworkManager, `iw` and `iproute2`, and
477
+ Python 3.10 or newer. There are packages for Ubuntu and Pop!\_OS (PPA) and
478
+ Arch Linux, a package on PyPI, and an installer for everything else. CI
479
+ tests Ubuntu 22.04 and 24.04, Debian 12, Fedora and Arch.
480
+
481
+ ### Can I control the hotspot from the system tray?
482
+
483
+ Yes. While the desktop app runs it shows an icon in the panel: the menu
484
+ starts and stops the hotspot, shares it, switches profile or band and opens
485
+ Settings. Turn on *Show in the tray at login* in Settings to have it there
486
+ after every login. It works on KDE Plasma, Xfce, Cinnamon, MATE, Budgie,
487
+ LXQt, waybar and other Wayland bars, and on GNOME with the AppIndicator
488
+ extension.
489
+
490
+ ### Is twinfi an alternative to create_ap?
491
+
492
+ Yes. create_ap was archived in September 2021 and is no longer maintained.
493
+ twinfi covers the same use case (a hotspot from a Wi-Fi card that stays
494
+ connected) and adds capability detection, a Wi-Fi Direct fallback, full
495
+ rollback and a desktop app.
496
+
497
+ ## Contributing
498
+
499
+ Contributions are welcome. See [CONTRIBUTING.md](https://github.com/krotrn/twinfi/blob/main/CONTRIBUTING.md). The test
500
+ suite runs without root or WiFi hardware.
501
+
502
+ Security issues: see [SECURITY.md](https://github.com/krotrn/twinfi/blob/main/SECURITY.md).
503
+
504
+ ## License
505
+
506
+ MIT
507
+
508
+ <a href="https://www.buymeacoffee.com/krotrn" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me a Coffee" style="height: 60px !important;width: 217px !important;" ></a>