authenticator-tui 1.0.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 (27) hide show
  1. authenticator_tui-1.0.0/.gitignore +5 -0
  2. authenticator_tui-1.0.0/.gitlab-ci.yml +35 -0
  3. authenticator_tui-1.0.0/.python-version +1 -0
  4. authenticator_tui-1.0.0/LICENSE +21 -0
  5. authenticator_tui-1.0.0/PKG-INFO +117 -0
  6. authenticator_tui-1.0.0/README.md +88 -0
  7. authenticator_tui-1.0.0/features.md +100 -0
  8. authenticator_tui-1.0.0/pyproject.toml +58 -0
  9. authenticator_tui-1.0.0/screenshots/add_modal.svg +191 -0
  10. authenticator_tui-1.0.0/screenshots/big_code.svg +187 -0
  11. authenticator_tui-1.0.0/screenshots/filter.svg +181 -0
  12. authenticator_tui-1.0.0/screenshots/main.svg +184 -0
  13. authenticator_tui-1.0.0/scripts/capture_screenshots.py +46 -0
  14. authenticator_tui-1.0.0/scripts/demo.txt +10 -0
  15. authenticator_tui-1.0.0/semrel-required-plugins.txt +1 -0
  16. authenticator_tui-1.0.0/src/authenticator_tui/__init__.py +0 -0
  17. authenticator_tui-1.0.0/src/authenticator_tui/__main__.py +16 -0
  18. authenticator_tui-1.0.0/src/authenticator_tui/app.py +300 -0
  19. authenticator_tui-1.0.0/src/authenticator_tui/models.py +110 -0
  20. authenticator_tui-1.0.0/src/authenticator_tui/otp_file.py +24 -0
  21. authenticator_tui-1.0.0/src/authenticator_tui/widgets/__init__.py +3 -0
  22. authenticator_tui-1.0.0/src/authenticator_tui/widgets/add_modal.py +156 -0
  23. authenticator_tui-1.0.0/src/authenticator_tui/widgets/big_code_modal.py +82 -0
  24. authenticator_tui-1.0.0/src/authenticator_tui/widgets/otp_item.py +84 -0
  25. authenticator_tui-1.0.0/tests/__init__.py +0 -0
  26. authenticator_tui-1.0.0/tests/test_app.py +218 -0
  27. authenticator_tui-1.0.0/uv.lock +821 -0
@@ -0,0 +1,5 @@
1
+ otp.txt
2
+ __pycache__/
3
+ *.pyc
4
+ .gitlab-ci-local/
5
+ reports/
@@ -0,0 +1,35 @@
1
+ variables:
2
+ TRIVY_SERVER: "https://trivy.lab.gronlier.fr"
3
+ UV_PYTHON_DOWNLOADS: never # prevent uv from fetching a newer Python version
4
+ UV_NO_SYNC: "1"
5
+ PYTHON_REPOSITORY_USERNAME: pypi-oidc
6
+
7
+ include:
8
+ - component: $CI_SERVER_FQDN/to-be-continuous/semantic-release/gitlab-ci-semrel@4
9
+ inputs:
10
+ commit-spec: conventionalcommits
11
+ - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python@9
12
+ inputs:
13
+ image: python:3.13-alpine
14
+ pytest-enabled: true
15
+ ruff-enabled: true
16
+ ruff-args: "--fix"
17
+ mypy-enabled: true
18
+ pyright-enabled: true
19
+ publish-enabled: true
20
+
21
+ semantic-release:
22
+ allow_failure: true
23
+
24
+ py-publish:
25
+ variables:
26
+ PYTHON_PUBLISH_TOOL: twine
27
+ PYTHON_REPOSITORY_USERNAME: pypi-oidc
28
+ PYTHON_REPOSITORY_URL: "https://upload.pypi.org/legacy/"
29
+ before_script:
30
+ - !reference [.python-base, before_script]
31
+ - apk add --no-cache git # versioningit extension
32
+ id_tokens:
33
+ PYPI_ID_TOKEN:
34
+ aud: pypi
35
+ # aud: "$PYPI_OIDC_AUD"
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pierre Gronlier
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.
@@ -0,0 +1,117 @@
1
+ Metadata-Version: 2.4
2
+ Name: authenticator-tui
3
+ Version: 1.0.0
4
+ Summary: A keyboard-driven terminal UI for managing TOTP/HOTP one-time passwords
5
+ Project-URL: Homepage, https://gitlab.com/riphixel/authenticator-tui
6
+ Project-URL: Repository, https://gitlab.com/riphixel/authenticator-tui
7
+ Project-URL: Issues, https://gitlab.com/riphixel/authenticator-tui/-/issues
8
+ Author-email: Pierre Gronlier <pierre@gronlier.fr>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: 2fa,authenticator,hotp,mfa,otp,terminal,textual,totp,tui
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Environment :: Console :: Curses
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: End Users/Desktop
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Security
22
+ Classifier: Topic :: Terminals
23
+ Classifier: Topic :: Utilities
24
+ Requires-Python: >=3.13
25
+ Requires-Dist: pyotp>=2.10.0
26
+ Requires-Dist: pyperclip>=1.11.0
27
+ Requires-Dist: textual>=8.2.7
28
+ Description-Content-Type: text/markdown
29
+
30
+ # authenticator-tui
31
+
32
+ A terminal UI for managing TOTP/HOTP one-time passwords stored as `otpauth://` URLs.
33
+
34
+ <img width="700" src="screenshots/main.svg" alt="Main screen">
35
+
36
+ ## Features
37
+
38
+ - **Live codes** — TOTP codes refresh every second with a countdown progress bar
39
+ - **Filter** — press `f` and type to narrow the list by issuer or account
40
+ - **Add** — paste an `otpauth://` URL or fill in fields manually
41
+ - **Delete** — remove an entry with auto-save
42
+ - **Big code view** — press Enter on any entry to display the code in large digits
43
+ - **Clipboard** — click any entry to copy the code
44
+ - **Export** — write all entries to a file as `otpauth://` URLs
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ uv tool install git+https://gitlab.com/riphixel/authenticator-tui
50
+ ```
51
+
52
+ Or run directly without installing:
53
+
54
+ ```bash
55
+ uvx --from git+https://gitlab.com/riphixel/authenticator-tui authenticator-tui otp.txt
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ ```bash
61
+ authenticator-tui [path/to/otp.txt]
62
+ ```
63
+
64
+ If no file is given (or the path doesn't exist) a file picker appears on startup.
65
+ The file is auto-saved on every add or delete.
66
+
67
+ ## Keybindings
68
+
69
+ | Key | Action |
70
+ |---|---|
71
+ | `f` | Focus filter input |
72
+ | `↓` in filter | Jump to first list entry |
73
+ | `↑` on first entry | Jump back to filter |
74
+ | `a` | Add OTP (modal) |
75
+ | `d` | Delete selected OTP |
76
+ | `e` | Export to file (modal) |
77
+ | Enter | Show code in big digits |
78
+ | Click | Copy code to clipboard |
79
+ | Escape | Clear filter / close modal |
80
+ | `q` | Quit |
81
+
82
+ ## Screenshots
83
+
84
+ ### Filter
85
+
86
+ <img width="700" src="screenshots/filter.svg" alt="Filter">
87
+
88
+ ### Add OTP
89
+
90
+ <img width="700" src="screenshots/add_modal.svg" alt="Add OTP modal">
91
+
92
+ ### Big code view
93
+
94
+ <img width="700" src="screenshots/big_code.svg" alt="Big code">
95
+
96
+ ## File format
97
+
98
+ One `otpauth://` URL per line. Blank lines and lines starting with `#` are ignored.
99
+
100
+ ```
101
+ otpauth://totp/GitHub:alice@example.com?secret=JBSWY3DPEHPK3PXP&issuer=GitHub
102
+ otpauth://totp/PayPal:alice@example.com?secret=JBSWY3DPEHPK3PXP&issuer=PayPal
103
+ ```
104
+
105
+ ## Development
106
+
107
+ ```bash
108
+ uv sync
109
+ uv run authenticator-tui otp.txt
110
+
111
+ # tests
112
+ uv run pytest
113
+
114
+ # lint
115
+ uvx ruff check .
116
+ uvx ruff format --check .
117
+ ```
@@ -0,0 +1,88 @@
1
+ # authenticator-tui
2
+
3
+ A terminal UI for managing TOTP/HOTP one-time passwords stored as `otpauth://` URLs.
4
+
5
+ <img width="700" src="screenshots/main.svg" alt="Main screen">
6
+
7
+ ## Features
8
+
9
+ - **Live codes** — TOTP codes refresh every second with a countdown progress bar
10
+ - **Filter** — press `f` and type to narrow the list by issuer or account
11
+ - **Add** — paste an `otpauth://` URL or fill in fields manually
12
+ - **Delete** — remove an entry with auto-save
13
+ - **Big code view** — press Enter on any entry to display the code in large digits
14
+ - **Clipboard** — click any entry to copy the code
15
+ - **Export** — write all entries to a file as `otpauth://` URLs
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ uv tool install git+https://gitlab.com/riphixel/authenticator-tui
21
+ ```
22
+
23
+ Or run directly without installing:
24
+
25
+ ```bash
26
+ uvx --from git+https://gitlab.com/riphixel/authenticator-tui authenticator-tui otp.txt
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ```bash
32
+ authenticator-tui [path/to/otp.txt]
33
+ ```
34
+
35
+ If no file is given (or the path doesn't exist) a file picker appears on startup.
36
+ The file is auto-saved on every add or delete.
37
+
38
+ ## Keybindings
39
+
40
+ | Key | Action |
41
+ |---|---|
42
+ | `f` | Focus filter input |
43
+ | `↓` in filter | Jump to first list entry |
44
+ | `↑` on first entry | Jump back to filter |
45
+ | `a` | Add OTP (modal) |
46
+ | `d` | Delete selected OTP |
47
+ | `e` | Export to file (modal) |
48
+ | Enter | Show code in big digits |
49
+ | Click | Copy code to clipboard |
50
+ | Escape | Clear filter / close modal |
51
+ | `q` | Quit |
52
+
53
+ ## Screenshots
54
+
55
+ ### Filter
56
+
57
+ <img width="700" src="screenshots/filter.svg" alt="Filter">
58
+
59
+ ### Add OTP
60
+
61
+ <img width="700" src="screenshots/add_modal.svg" alt="Add OTP modal">
62
+
63
+ ### Big code view
64
+
65
+ <img width="700" src="screenshots/big_code.svg" alt="Big code">
66
+
67
+ ## File format
68
+
69
+ One `otpauth://` URL per line. Blank lines and lines starting with `#` are ignored.
70
+
71
+ ```
72
+ otpauth://totp/GitHub:alice@example.com?secret=JBSWY3DPEHPK3PXP&issuer=GitHub
73
+ otpauth://totp/PayPal:alice@example.com?secret=JBSWY3DPEHPK3PXP&issuer=PayPal
74
+ ```
75
+
76
+ ## Development
77
+
78
+ ```bash
79
+ uv sync
80
+ uv run authenticator-tui otp.txt
81
+
82
+ # tests
83
+ uv run pytest
84
+
85
+ # lint
86
+ uvx ruff check .
87
+ uvx ruff format --check .
88
+ ```
@@ -0,0 +1,100 @@
1
+ # authenticator-tui — Features
2
+
3
+ TUI application to manage TOTP/HOTP one-time passwords stored as `otpauth://` URLs.
4
+
5
+ **Run:** `uv run authenticator-tui [path/to/otp.txt]`
6
+
7
+ ---
8
+
9
+ ## File loading
10
+
11
+ - Accepts a file path as a CLI argument; loads immediately if the file exists
12
+ - Without a CLI argument (or if the path does not exist), shows a **file picker modal** on startup with the path pre-filled to `otp.txt` if that file exists in the current directory
13
+ - Validates `otpauth://` URL format on load; reports errors via notification
14
+
15
+ ## OTP display
16
+
17
+ - Lists all entries as scrollable rows: `Issuer / Account XXX XXX ████████░░ 18s`
18
+ - Codes split in the middle with a space for readability (e.g. `482 391`)
19
+ - **Live countdown progress bar** (`█`/`░` blocks, 10 chars wide) updated every second
20
+ - Remaining seconds shown next to the bar
21
+ - Codes refresh automatically when a new TOTP period begins
22
+
23
+ ## Filtering
24
+
25
+ - Filter bar always visible at the top of the screen; focused automatically on startup
26
+ - Press **`f`** to refocus the filter input at any time
27
+ - Matches against both **issuer** and **account** fields (case-insensitive)
28
+ - Press **`↓`** in the filter to jump focus to the first list entry
29
+ - Press **`↑`** on the first list entry to return focus to the filter input
30
+ - Press **Escape** while the filter is focused to clear it and return focus to the list
31
+
32
+ ## Add OTP (`a`)
33
+
34
+ Opens a modal with two tabs:
35
+
36
+ - **Paste URL** — paste a full `otpauth://totp/...` or `otpauth://hotp/...` URL; validates on submit
37
+ - **Manual** — form fields: Issuer, Account, Secret (required), Algorithm (SHA1 / SHA256 / SHA512), Digits (6 / 8), Period (seconds)
38
+ - Validates the secret by attempting code generation before accepting
39
+ - New entry is appended to the list and **auto-saved** to the source file
40
+
41
+ ## Delete OTP (`d`)
42
+
43
+ - Deletes the currently highlighted entry from the list
44
+ - **Auto-saves** the updated list to the source file immediately
45
+
46
+ ## Export (`e`)
47
+
48
+ - Opens a modal pre-filled with the current file path
49
+ - Writes all entries as `otpauth://` URLs (one per line) to the specified path
50
+ - Atomic write (writes to `.tmp` then renames) to avoid data loss
51
+
52
+ ## Big code view (Enter)
53
+
54
+ - Press **Enter** on any list entry to open a full-screen modal showing the code in large LED-style digits (Textual `Digits` widget)
55
+ - Includes issuer/account label and a 30-block countdown progress bar
56
+ - Refreshes every second; dismiss with any key or click
57
+
58
+ ## Clipboard copy
59
+
60
+ - **Click** any entry to copy the current code (without the middle space) to the clipboard via `pyperclip`
61
+ - Shows a brief notification confirming the copied code
62
+
63
+ ## OTP format support
64
+
65
+ - **TOTP** (`otpauth://totp/`) — time-based, configurable period (default 30s)
66
+ - **HOTP** (`otpauth://hotp/`) — counter-based
67
+ - Algorithms: SHA1 (default), SHA256, SHA512
68
+ - Code length: 6 digits (default) or 8 digits
69
+ - URL encoding preserved as `%XX` (not `+`) on save
70
+
71
+ ## Keybindings
72
+
73
+ | Key | Action |
74
+ |---|---|
75
+ | `a` | Add OTP (modal) |
76
+ | `d` | Delete highlighted OTP |
77
+ | `e` | Export to file (modal) |
78
+ | `f` | Focus filter input |
79
+ | `↓` in filter | Jump to first list entry |
80
+ | `↑` on first entry | Jump to filter input |
81
+ | Enter | Show code in big digits (modal) |
82
+ | Escape (filter focused) | Clear filter, return focus to list |
83
+ | Escape (list focused) | Quit app |
84
+ | Escape (modal open) | Close modal |
85
+ | `q` | Quit |
86
+ | Click | Copy code to clipboard |
87
+ | Up / Down | Navigate list |
88
+
89
+ ## Tests
90
+
91
+ Headless pytest suite using Textual's `run_test()` / `Pilot` API:
92
+
93
+ - File loading, filter narrowing, Escape restore
94
+ - Filter↔list keyboard navigation (`↓` / `↑`)
95
+ - Add modal open/cancel
96
+ - Delete with and without selection, file persistence
97
+ - Big code modal open/dismiss
98
+ - Escape context-aware: exits app from list, focuses list from filter, closes export modal
99
+
100
+ Run with: `uv run pytest`
@@ -0,0 +1,58 @@
1
+ [project]
2
+ name = "authenticator-tui"
3
+ dynamic = ["version"]
4
+ description = "A keyboard-driven terminal UI for managing TOTP/HOTP one-time passwords"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [
9
+ { name = "Pierre Gronlier", email = "pierre@gronlier.fr" }
10
+ ]
11
+ keywords = ["otp", "totp", "hotp", "2fa", "mfa", "authenticator", "tui", "terminal", "textual"]
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Environment :: Console",
15
+ "Environment :: Console :: Curses",
16
+ "Intended Audience :: Developers",
17
+ "Intended Audience :: End Users/Desktop",
18
+ "Operating System :: OS Independent",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3 :: Only",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Topic :: Security",
23
+ "Topic :: Terminals",
24
+ "Topic :: Utilities",
25
+ ]
26
+ requires-python = ">=3.13"
27
+ dependencies = [
28
+ "pyotp>=2.10.0",
29
+ "pyperclip>=1.11.0",
30
+ "textual>=8.2.7",
31
+ ]
32
+
33
+ [project.urls]
34
+ Homepage = "https://gitlab.com/riphixel/authenticator-tui"
35
+ Repository = "https://gitlab.com/riphixel/authenticator-tui"
36
+ Issues = "https://gitlab.com/riphixel/authenticator-tui/-/issues"
37
+
38
+ [project.scripts]
39
+ authenticator-tui = "authenticator_tui.__main__:main"
40
+
41
+ [build-system]
42
+ requires = ["hatchling", "versioningit"]
43
+ build-backend = "hatchling.build"
44
+
45
+ [tool.hatch.version]
46
+ source = "versioningit"
47
+ default-version = "0.0.0-dev"
48
+
49
+ [dependency-groups]
50
+ dev = [
51
+ "pytest>=8.0",
52
+ "pytest-asyncio>=0.23",
53
+ "textual-dev>=1.8.0",
54
+ "types-pyperclip>=1.11.0",
55
+ ]
56
+
57
+ [tool.pytest.ini_options]
58
+ asyncio_mode = "auto"