aethervault-py 6.4.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 (45) hide show
  1. aethervault_py-6.4.0/LICENSE +17 -0
  2. aethervault_py-6.4.0/MANIFEST.in +10 -0
  3. aethervault_py-6.4.0/PKG-INFO +200 -0
  4. aethervault_py-6.4.0/README.md +187 -0
  5. aethervault_py-6.4.0/aethervault/__init__.py +49 -0
  6. aethervault_py-6.4.0/aethervault/__main__.py +214 -0
  7. aethervault_py-6.4.0/aethervault/assets/aethersol.ico +0 -0
  8. aethervault_py-6.4.0/aethervault/assets/aethersol_logo.png +0 -0
  9. aethervault_py-6.4.0/aethervault/assets/screens/aethervault-demo.gif +0 -0
  10. aethervault_py-6.4.0/aethervault/assets/screens/entry.png +0 -0
  11. aethervault_py-6.4.0/aethervault/assets/screens/generator.png +0 -0
  12. aethervault_py-6.4.0/aethervault/assets/screens/health.png +0 -0
  13. aethervault_py-6.4.0/aethervault/assets/screens/login.png +0 -0
  14. aethervault_py-6.4.0/aethervault/assets/screens/vault.png +0 -0
  15. aethervault_py-6.4.0/aethervault/core/__init__.py +6 -0
  16. aethervault_py-6.4.0/aethervault/core/engine.py +226 -0
  17. aethervault_py-6.4.0/aethervault/core/password.py +67 -0
  18. aethervault_py-6.4.0/aethervault/docs/USER_GUIDE.html +238 -0
  19. aethervault_py-6.4.0/aethervault/docs/USER_GUIDE.md +163 -0
  20. aethervault_py-6.4.0/aethervault/gui/__init__.py +6 -0
  21. aethervault_py-6.4.0/aethervault/gui/app.py +1059 -0
  22. aethervault_py-6.4.0/aethervault/gui/click_to_copy_filter.py +24 -0
  23. aethervault_py-6.4.0/aethervault/gui/conflict_dialog.py +141 -0
  24. aethervault_py-6.4.0/aethervault/gui/credential_form.py +351 -0
  25. aethervault_py-6.4.0/aethervault/gui/credential_table.py +344 -0
  26. aethervault_py-6.4.0/aethervault/gui/dialogs.py +172 -0
  27. aethervault_py-6.4.0/aethervault/gui/password_strength.py +46 -0
  28. aethervault_py-6.4.0/aethervault/gui/theme.py +371 -0
  29. aethervault_py-6.4.0/aethervault/shared/__init__.py +6 -0
  30. aethervault_py-6.4.0/aethervault/shared/database.py +577 -0
  31. aethervault_py-6.4.0/aethervault/shared/models.py +54 -0
  32. aethervault_py-6.4.0/aethervault_py.egg-info/PKG-INFO +200 -0
  33. aethervault_py-6.4.0/aethervault_py.egg-info/SOURCES.txt +43 -0
  34. aethervault_py-6.4.0/aethervault_py.egg-info/dependency_links.txt +1 -0
  35. aethervault_py-6.4.0/aethervault_py.egg-info/entry_points.txt +2 -0
  36. aethervault_py-6.4.0/aethervault_py.egg-info/requires.txt +2 -0
  37. aethervault_py-6.4.0/aethervault_py.egg-info/top_level.txt +1 -0
  38. aethervault_py-6.4.0/pyproject.toml +37 -0
  39. aethervault_py-6.4.0/setup.cfg +4 -0
  40. aethervault_py-6.4.0/tests/test_core_logic.py +179 -0
  41. aethervault_py-6.4.0/tests/test_credential_entry.py +52 -0
  42. aethervault_py-6.4.0/tests/test_credential_form.py +78 -0
  43. aethervault_py-6.4.0/tests/test_db_manager.py +320 -0
  44. aethervault_py-6.4.0/tests/test_duress.py +95 -0
  45. aethervault_py-6.4.0/tests/test_score_password.py +50 -0
@@ -0,0 +1,17 @@
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2026 AetherLock Contributors
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
@@ -0,0 +1,10 @@
1
+ # Created: 2026-07-27
2
+ # Last Edited: 2026-08-05 16:46 CT (America/Chicago)
3
+ # Path: MANIFEST.in
4
+ # Purpose: Include package data files in the source distribution for pip builds.
5
+
6
+ include aethervault/docs/USER_GUIDE.md
7
+ include aethervault/docs/USER_GUIDE.html
8
+ include aethervault/assets/aethersol.ico
9
+ include aethervault/assets/aethersol_logo.png
10
+ recursive-include aethervault/assets/screens *.png *.gif
@@ -0,0 +1,200 @@
1
+ Metadata-Version: 2.4
2
+ Name: aethervault-py
3
+ Version: 6.4.0
4
+ Summary: A secure, local-first password manager with AES-256 encryption
5
+ Author: AetherVault Team
6
+ License: GPL-3.0-only
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: PySide6>=6.5.0
11
+ Requires-Dist: cryptography>=41.0.0
12
+ Dynamic: license-file
13
+
14
+ <pre align="center">
15
+ ╔══════════════════════════════╗
16
+ ║ A E T H E R V A U L T ║
17
+ ║ Encrypted Password Vault ║
18
+ ╚══════════════════════════════╝
19
+ </pre>
20
+
21
+ <h1 align="center">AetherVault</h1>
22
+
23
+ <p align="center">
24
+ <em>Encrypted, local-first password manager</em>
25
+ <br>
26
+ Store, organize, and protect your credentials — encrypted with AES-256, right on your machine.
27
+ <br>
28
+ <strong><em>Your data stays yours. No cloud. No servers.</em></strong>
29
+ </p>
30
+
31
+ <p align="center">
32
+ <img src="https://img.shields.io/badge/Linux-%E2%9C%93-informational?logo=linux&logoColor=white" alt="Linux">
33
+ <img src="https://img.shields.io/badge/macOS-%E2%9C%93-informational?logo=apple&logoColor=white" alt="macOS">
34
+ <img src="https://img.shields.io/badge/Windows-%E2%9C%93-informational?logo=windows&logoColor=white" alt="Windows">
35
+ <img src="https://img.shields.io/badge/python-3.10+-blue?logo=python" alt="Python 3.10+">
36
+ <img src="https://img.shields.io/badge/license-GPLv3-blue" alt="GPLv3">
37
+ <img src="https://img.shields.io/badge/PySide6-6.5+-green" alt="PySide6 6.5+">
38
+ <img src="https://img.shields.io/pypi/v/aethervault-py?logo=pypi&logoColor=white&color=3776AB" alt="PyPI">
39
+ <img src="https://github.com/AetherSolDev/AetherVault/actions/workflows/build.yml/badge.svg" alt="Build">
40
+ </p>
41
+
42
+ ---
43
+
44
+ ## Screenshots
45
+
46
+ ![Demo](aethervault/assets/screens/aethervault-demo.gif)
47
+
48
+ ![Login](aethervault/assets/screens/login.png)
49
+ ![Vault](aethervault/assets/screens/vault.png)
50
+ ![Entry](aethervault/assets/screens/entry.png)
51
+ ![Generator](aethervault/assets/screens/generator.png)
52
+ ![Health](aethervault/assets/screens/health.png)
53
+
54
+ ---
55
+
56
+ ## Features
57
+
58
+ - **AES-256 encryption** — every password encrypted with Fernet (cryptography library), key derived with PBKDF2-SHA256
59
+ - **Master password auth** — setup/login flow; only the PBKDF2 hash is stored
60
+ - **Credential management** — add, edit, delete, search, sort, filter
61
+ - **Password generator** — configurable length and character sets
62
+ - **Password strength meter** — real-time scoring as you type
63
+ - **Password health report** — scan for weak, reused, or short passwords
64
+ - **Category & tag filters** — dynamic dropdowns, category click-to-filter
65
+ - **Custom fields** — key/value pairs on any entry (JSON-backed)
66
+ - **Rich text notes** — bold / italic / underline formatting toolbar
67
+ - **Favicon auto-fetch** — site icons pulled from Google's service
68
+ - **System tray** — minimize to tray, quick-lock from the tray menu
69
+ - **Dark / light theme** — toggle in Settings, persists across sessions
70
+ - **Auto-lock** — configurable 1/3/5/10/30 minutes or never
71
+ - **Duress password** *(optional)* — entering it at login permanently destroys the vault and all backups, indistinguishable from a failed login
72
+ - **Clipboard auto-clear** — copied passwords clear after 15 seconds
73
+ - **One-click backup** — timestamped filenames, auto-rotation keeps the 5 most recent
74
+ - **CSV import / export** — bulk add or migrate from other managers
75
+ - **Duplicate detection** — find and remove entries with matching title + username
76
+ - **Portable mode** — all data stays in the app directory (`.portable` marker)
77
+ - **Startup integrity check** — auto-detects corruption and recovers from backup
78
+
79
+ ---
80
+
81
+ ## Download a Pre-Built Executable
82
+
83
+ No Python or pip needed. Grab the binary for your platform from the
84
+ [Releases](https://github.com/AetherSolDev/AetherVault/releases) page
85
+ (or the latest [Actions build](https://github.com/AetherSolDev/AetherVault/actions) artifacts):
86
+
87
+ > Prefer a package manager? **`pip install aethervault-py`** (PyPI) works on Linux, macOS, and Windows.
88
+
89
+ | Platform | Download |
90
+ |----------|----------|
91
+ | Windows (x86_64) | [aethervault-windows-x86_64.exe](https://github.com/AetherSolDev/AetherVault/releases/latest/download/aethervault-windows-x86_64.exe) |
92
+ | Linux (x86_64) | [aethervault-linux-x86_64](https://github.com/AetherSolDev/AetherVault/releases/latest/download/aethervault-linux-x86_64) |
93
+ | macOS (Apple Silicon) | [aethervault-macos-arm64](https://github.com/AetherSolDev/AetherVault/releases/latest/download/aethervault-macos-arm64) |
94
+ | macOS (Intel) | [aethervault-macos-x86_64](https://github.com/AetherSolDev/AetherVault/releases/latest/download/aethervault-macos-x86_64) |
95
+
96
+ > The binaries are unsigned, so Windows SmartScreen and macOS Gatekeeper may warn on first run.
97
+ > Windows: click **More info → Run anyway**. macOS: `xattr -d com.apple.quarantine aethervault-macos`.
98
+ > Linux: the binary expects standard Qt/X11 system libraries.
99
+
100
+ ---
101
+
102
+ ## Quick Start
103
+
104
+ ### Install
105
+
106
+ AetherVault is on **PyPI** (`aethervault-py`) and published to GitHub Releases on every version tag.
107
+
108
+ **Option 1 — pip (recommended, all platforms):**
109
+ ```bash
110
+ pip install aethervault-py
111
+ # or
112
+ pip install --user aethervault-py
113
+ ```
114
+
115
+ **Option 2 — Global install (editable):**
116
+ ```bash
117
+ git clone https://github.com/AetherSolDev/AetherVault.git
118
+ cd AetherVault
119
+ pip install --user --break-system-packages -e .
120
+ ```
121
+
122
+ **Option 3 — Virtual environment:**
123
+ ```bash
124
+ git clone https://github.com/AetherSolDev/AetherVault.git
125
+ cd AetherVault
126
+ python -m venv venv
127
+ source venv/bin/activate # Windows: venv\Scripts\activate
128
+ pip install -e .
129
+ ```
130
+
131
+ **Option 4 — Build yourself (PyInstaller):**
132
+ ```bash
133
+ pip install pyinstaller
134
+ pyinstaller aethervault.spec
135
+ # Output in dist/aethervault/
136
+ ```
137
+
138
+ ### Run
139
+
140
+ ```bash
141
+ aethervault # Launch GUI (auto-detaches from terminal on Unix)
142
+ aethervault --version # Show installed version
143
+ aethervault --help # CLI usage
144
+ ```
145
+
146
+ ---
147
+
148
+ ## Usage
149
+
150
+ 1. **First launch** — set a master password (minimum 8 characters)
151
+ 2. **Login** — enter your master password to unlock the vault
152
+ 3. **Add entries** — click "Add New" and fill in the form
153
+ 4. **Generate passwords** — click "Generate" next to the password field
154
+ 5. **Copy to clipboard** — double-click a table cell or click the "Copy" buttons
155
+ 6. **Organize** — categories and tags group your entries
156
+ 7. **Backup** — File → Backup Vault (or auto-backup on save/shutdown)
157
+
158
+ | CLI Command | Description |
159
+ |-------------|-------------|
160
+ | `aethervault` | Launch the GUI (auto-detaches on Unix) |
161
+ | `aethervault --version` | Show installed version |
162
+ | `aethervault --debug` | Launch with debug logging |
163
+ | `aethervault --upgrade` / `-u` | Check for updates and auto-upgrade |
164
+ | `aethervault --foreground` / `-f` | Keep terminal attached (debugging) |
165
+
166
+ ---
167
+
168
+ ## Security
169
+
170
+ - Passwords are **never stored in plain text** — AES-256 via Fernet
171
+ - Master password is **never stored** — only its PBKDF2-SHA256 hash
172
+ - Encryption key derived from the master password hash (PBKDF2, 480K iterations)
173
+ - Clipboard **auto-cleared** after 15 seconds
174
+ - Auto-lock on **inactivity** or window focus loss
175
+ - SQLite with **parameterized queries** (no SQL injection)
176
+ - Startup **integrity check** with automatic recovery from backup
177
+ - Optional **duress password** — destroys the vault on coercion
178
+
179
+ ---
180
+
181
+ ## Data
182
+
183
+ | Data | Location |
184
+ |------|----------|
185
+ | Encrypted vault | `data/aethervault.db` |
186
+ | Master password hash | `data/.master.key` |
187
+ | App settings | `data/.app_settings.json` |
188
+ | Portable marker | `.portable` (enables portable mode) |
189
+
190
+ ---
191
+
192
+ ## Documentation
193
+
194
+ Full user guide: [`aethervault/docs/USER_GUIDE.md`](aethervault/docs/USER_GUIDE.md)
195
+
196
+ ---
197
+
198
+ ## License
199
+
200
+ [GPLv3](LICENSE) — Free as in freedom.
@@ -0,0 +1,187 @@
1
+ <pre align="center">
2
+ ╔══════════════════════════════╗
3
+ ║ A E T H E R V A U L T ║
4
+ ║ Encrypted Password Vault ║
5
+ ╚══════════════════════════════╝
6
+ </pre>
7
+
8
+ <h1 align="center">AetherVault</h1>
9
+
10
+ <p align="center">
11
+ <em>Encrypted, local-first password manager</em>
12
+ <br>
13
+ Store, organize, and protect your credentials — encrypted with AES-256, right on your machine.
14
+ <br>
15
+ <strong><em>Your data stays yours. No cloud. No servers.</em></strong>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <img src="https://img.shields.io/badge/Linux-%E2%9C%93-informational?logo=linux&logoColor=white" alt="Linux">
20
+ <img src="https://img.shields.io/badge/macOS-%E2%9C%93-informational?logo=apple&logoColor=white" alt="macOS">
21
+ <img src="https://img.shields.io/badge/Windows-%E2%9C%93-informational?logo=windows&logoColor=white" alt="Windows">
22
+ <img src="https://img.shields.io/badge/python-3.10+-blue?logo=python" alt="Python 3.10+">
23
+ <img src="https://img.shields.io/badge/license-GPLv3-blue" alt="GPLv3">
24
+ <img src="https://img.shields.io/badge/PySide6-6.5+-green" alt="PySide6 6.5+">
25
+ <img src="https://img.shields.io/pypi/v/aethervault-py?logo=pypi&logoColor=white&color=3776AB" alt="PyPI">
26
+ <img src="https://github.com/AetherSolDev/AetherVault/actions/workflows/build.yml/badge.svg" alt="Build">
27
+ </p>
28
+
29
+ ---
30
+
31
+ ## Screenshots
32
+
33
+ ![Demo](aethervault/assets/screens/aethervault-demo.gif)
34
+
35
+ ![Login](aethervault/assets/screens/login.png)
36
+ ![Vault](aethervault/assets/screens/vault.png)
37
+ ![Entry](aethervault/assets/screens/entry.png)
38
+ ![Generator](aethervault/assets/screens/generator.png)
39
+ ![Health](aethervault/assets/screens/health.png)
40
+
41
+ ---
42
+
43
+ ## Features
44
+
45
+ - **AES-256 encryption** — every password encrypted with Fernet (cryptography library), key derived with PBKDF2-SHA256
46
+ - **Master password auth** — setup/login flow; only the PBKDF2 hash is stored
47
+ - **Credential management** — add, edit, delete, search, sort, filter
48
+ - **Password generator** — configurable length and character sets
49
+ - **Password strength meter** — real-time scoring as you type
50
+ - **Password health report** — scan for weak, reused, or short passwords
51
+ - **Category & tag filters** — dynamic dropdowns, category click-to-filter
52
+ - **Custom fields** — key/value pairs on any entry (JSON-backed)
53
+ - **Rich text notes** — bold / italic / underline formatting toolbar
54
+ - **Favicon auto-fetch** — site icons pulled from Google's service
55
+ - **System tray** — minimize to tray, quick-lock from the tray menu
56
+ - **Dark / light theme** — toggle in Settings, persists across sessions
57
+ - **Auto-lock** — configurable 1/3/5/10/30 minutes or never
58
+ - **Duress password** *(optional)* — entering it at login permanently destroys the vault and all backups, indistinguishable from a failed login
59
+ - **Clipboard auto-clear** — copied passwords clear after 15 seconds
60
+ - **One-click backup** — timestamped filenames, auto-rotation keeps the 5 most recent
61
+ - **CSV import / export** — bulk add or migrate from other managers
62
+ - **Duplicate detection** — find and remove entries with matching title + username
63
+ - **Portable mode** — all data stays in the app directory (`.portable` marker)
64
+ - **Startup integrity check** — auto-detects corruption and recovers from backup
65
+
66
+ ---
67
+
68
+ ## Download a Pre-Built Executable
69
+
70
+ No Python or pip needed. Grab the binary for your platform from the
71
+ [Releases](https://github.com/AetherSolDev/AetherVault/releases) page
72
+ (or the latest [Actions build](https://github.com/AetherSolDev/AetherVault/actions) artifacts):
73
+
74
+ > Prefer a package manager? **`pip install aethervault-py`** (PyPI) works on Linux, macOS, and Windows.
75
+
76
+ | Platform | Download |
77
+ |----------|----------|
78
+ | Windows (x86_64) | [aethervault-windows-x86_64.exe](https://github.com/AetherSolDev/AetherVault/releases/latest/download/aethervault-windows-x86_64.exe) |
79
+ | Linux (x86_64) | [aethervault-linux-x86_64](https://github.com/AetherSolDev/AetherVault/releases/latest/download/aethervault-linux-x86_64) |
80
+ | macOS (Apple Silicon) | [aethervault-macos-arm64](https://github.com/AetherSolDev/AetherVault/releases/latest/download/aethervault-macos-arm64) |
81
+ | macOS (Intel) | [aethervault-macos-x86_64](https://github.com/AetherSolDev/AetherVault/releases/latest/download/aethervault-macos-x86_64) |
82
+
83
+ > The binaries are unsigned, so Windows SmartScreen and macOS Gatekeeper may warn on first run.
84
+ > Windows: click **More info → Run anyway**. macOS: `xattr -d com.apple.quarantine aethervault-macos`.
85
+ > Linux: the binary expects standard Qt/X11 system libraries.
86
+
87
+ ---
88
+
89
+ ## Quick Start
90
+
91
+ ### Install
92
+
93
+ AetherVault is on **PyPI** (`aethervault-py`) and published to GitHub Releases on every version tag.
94
+
95
+ **Option 1 — pip (recommended, all platforms):**
96
+ ```bash
97
+ pip install aethervault-py
98
+ # or
99
+ pip install --user aethervault-py
100
+ ```
101
+
102
+ **Option 2 — Global install (editable):**
103
+ ```bash
104
+ git clone https://github.com/AetherSolDev/AetherVault.git
105
+ cd AetherVault
106
+ pip install --user --break-system-packages -e .
107
+ ```
108
+
109
+ **Option 3 — Virtual environment:**
110
+ ```bash
111
+ git clone https://github.com/AetherSolDev/AetherVault.git
112
+ cd AetherVault
113
+ python -m venv venv
114
+ source venv/bin/activate # Windows: venv\Scripts\activate
115
+ pip install -e .
116
+ ```
117
+
118
+ **Option 4 — Build yourself (PyInstaller):**
119
+ ```bash
120
+ pip install pyinstaller
121
+ pyinstaller aethervault.spec
122
+ # Output in dist/aethervault/
123
+ ```
124
+
125
+ ### Run
126
+
127
+ ```bash
128
+ aethervault # Launch GUI (auto-detaches from terminal on Unix)
129
+ aethervault --version # Show installed version
130
+ aethervault --help # CLI usage
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Usage
136
+
137
+ 1. **First launch** — set a master password (minimum 8 characters)
138
+ 2. **Login** — enter your master password to unlock the vault
139
+ 3. **Add entries** — click "Add New" and fill in the form
140
+ 4. **Generate passwords** — click "Generate" next to the password field
141
+ 5. **Copy to clipboard** — double-click a table cell or click the "Copy" buttons
142
+ 6. **Organize** — categories and tags group your entries
143
+ 7. **Backup** — File → Backup Vault (or auto-backup on save/shutdown)
144
+
145
+ | CLI Command | Description |
146
+ |-------------|-------------|
147
+ | `aethervault` | Launch the GUI (auto-detaches on Unix) |
148
+ | `aethervault --version` | Show installed version |
149
+ | `aethervault --debug` | Launch with debug logging |
150
+ | `aethervault --upgrade` / `-u` | Check for updates and auto-upgrade |
151
+ | `aethervault --foreground` / `-f` | Keep terminal attached (debugging) |
152
+
153
+ ---
154
+
155
+ ## Security
156
+
157
+ - Passwords are **never stored in plain text** — AES-256 via Fernet
158
+ - Master password is **never stored** — only its PBKDF2-SHA256 hash
159
+ - Encryption key derived from the master password hash (PBKDF2, 480K iterations)
160
+ - Clipboard **auto-cleared** after 15 seconds
161
+ - Auto-lock on **inactivity** or window focus loss
162
+ - SQLite with **parameterized queries** (no SQL injection)
163
+ - Startup **integrity check** with automatic recovery from backup
164
+ - Optional **duress password** — destroys the vault on coercion
165
+
166
+ ---
167
+
168
+ ## Data
169
+
170
+ | Data | Location |
171
+ |------|----------|
172
+ | Encrypted vault | `data/aethervault.db` |
173
+ | Master password hash | `data/.master.key` |
174
+ | App settings | `data/.app_settings.json` |
175
+ | Portable marker | `.portable` (enables portable mode) |
176
+
177
+ ---
178
+
179
+ ## Documentation
180
+
181
+ Full user guide: [`aethervault/docs/USER_GUIDE.md`](aethervault/docs/USER_GUIDE.md)
182
+
183
+ ---
184
+
185
+ ## License
186
+
187
+ [GPLv3](LICENSE) — Free as in freedom.
@@ -0,0 +1,49 @@
1
+ # Created: 2026-07-24
2
+ # Last Edited: 2026-08-05 17:06 CT (America/Chicago)
3
+ # Path: aethervault/__init__.py
4
+ # Purpose: Package init for AetherVault source. Defines PROJECT_ROOT and portable mode.
5
+
6
+ """Package initializer providing PROJECT_ROOT, version constants, and portable mode controls."""
7
+
8
+ __version__ = "6.4.0"
9
+ VERSION = __version__
10
+ __app_name__ = "AetherVault"
11
+ APP_NAME = __app_name__
12
+
13
+ import os
14
+ import sys
15
+
16
+ if getattr(sys, "frozen", False):
17
+ PROJECT_ROOT = os.getcwd()
18
+ else:
19
+ PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
20
+
21
+ PORTABLE_MARKER = ".portable"
22
+
23
+
24
+ def is_portable() -> bool:
25
+ """Return True if the portable marker file exists in PROJECT_ROOT."""
26
+ return os.path.exists(os.path.join(PROJECT_ROOT, PORTABLE_MARKER))
27
+
28
+
29
+ def enable_portable_mode() -> bool:
30
+ """Create the portable marker file and return True, or return False on failure."""
31
+ try:
32
+ path = os.path.join(PROJECT_ROOT, PORTABLE_MARKER)
33
+ if not os.path.exists(path):
34
+ with open(path, "w") as f:
35
+ f.write("Portable mode enabled\n")
36
+ return True
37
+ except OSError:
38
+ return False
39
+
40
+
41
+ def disable_portable_mode() -> bool:
42
+ """Remove the portable marker file and return True, or return False on failure."""
43
+ try:
44
+ path = os.path.join(PROJECT_ROOT, PORTABLE_MARKER)
45
+ if os.path.exists(path):
46
+ os.remove(path)
47
+ return True
48
+ except OSError:
49
+ return False
@@ -0,0 +1,214 @@
1
+ # Created: 2026-07-24
2
+ # Last Edited: 2026-08-01 01:55 CT (America/Chicago)
3
+ # Path: aethervault/__main__.py
4
+ # Purpose: Application entry point with CLI switches (--version, --debug, --upgrade, --foreground).
5
+
6
+ """Application entry point with CLI switches (--version, --debug, --upgrade, --foreground)."""
7
+
8
+ import argparse
9
+ import json
10
+ import logging
11
+ import os
12
+ import subprocess
13
+ import sys
14
+ import urllib.request
15
+ import urllib.error
16
+ from typing import Optional
17
+
18
+ from PySide6.QtCore import QTimer
19
+ from PySide6.QtWidgets import QApplication
20
+
21
+ from aethervault import PROJECT_ROOT, VERSION
22
+ from aethervault.gui.app import PySidePWManager
23
+
24
+ GITHUB_TAGS_API = "https://api.github.com/repos/AetherSolDev/AetherVault/tags"
25
+
26
+
27
+ GIT_REPO_URL = "https://github.com/AetherSolDev/AetherVault.git"
28
+ RELEASES_URL = "https://github.com/AetherSolDev/AetherVault/releases/latest"
29
+
30
+
31
+ def _is_git_repo() -> bool:
32
+ """Return True if PROJECT_ROOT contains a .git directory."""
33
+ return os.path.isdir(os.path.join(PROJECT_ROOT, ".git"))
34
+
35
+
36
+ def _get_pip_command() -> str:
37
+ """Return the appropriate pip command (venv or system)."""
38
+ in_venv = sys.prefix != sys.base_prefix
39
+ if in_venv:
40
+ return os.path.join(sys.prefix, "bin", "pip")
41
+ return "pip"
42
+
43
+
44
+ def _fetch_latest_tag() -> Optional[str]:
45
+ """Fetch the latest version tag from GitHub. Returns tag string or None."""
46
+ try:
47
+ req = urllib.request.Request(GITHUB_TAGS_API, headers={"User-Agent": "AetherVault"})
48
+ with urllib.request.urlopen(req, timeout=10) as resp:
49
+ tags = json.loads(resp.read().decode())
50
+ except urllib.error.HTTPError as e:
51
+ print(f"Upgrade check failed (HTTP {e.code})")
52
+ return None
53
+ except (urllib.error.URLError, json.JSONDecodeError, OSError) as e:
54
+ print(f"Upgrade check failed: {e}")
55
+ return None
56
+
57
+ if not tags:
58
+ print("No version tags found on GitHub.")
59
+ return None
60
+
61
+ latest_tag = tags[0].get("name", "").lstrip("v")
62
+ if not latest_tag:
63
+ print("Could not determine latest version.")
64
+ return None
65
+
66
+ return latest_tag
67
+
68
+
69
+ def _perform_upgrade(latest_tag: str) -> bool:
70
+ """Perform the actual upgrade. Returns True on success."""
71
+ print(f"Upgrading AetherVault v{VERSION} → v{latest_tag} ...")
72
+ print()
73
+
74
+ try:
75
+ git_env = os.environ.copy()
76
+ git_env["GIT_DISCOVERY_ACROSS_FILESYSTEM"] = "1"
77
+
78
+ if _is_git_repo():
79
+ print("1. Pulling latest code via git ...", end=" ", flush=True)
80
+ result = subprocess.run(
81
+ ["git", "pull"],
82
+ cwd=PROJECT_ROOT,
83
+ capture_output=True, text=True, timeout=60,
84
+ env=git_env,
85
+ )
86
+ if result.returncode != 0:
87
+ print("FAILED")
88
+ print(result.stderr)
89
+ print("Tip: Set git safe.directory or GIT_DISCOVERY_ACROSS_FILESYSTEM")
90
+ return False
91
+ print("done")
92
+
93
+ print("2. Reinstalling package ...", end=" ", flush=True)
94
+ pip_cmd = _get_pip_command()
95
+ result = subprocess.run(
96
+ [pip_cmd, "install", "-e", "."],
97
+ cwd=PROJECT_ROOT,
98
+ capture_output=True, text=True, timeout=120,
99
+ )
100
+ if result.returncode != 0:
101
+ print("FAILED")
102
+ print(result.stderr)
103
+ return False
104
+ print("done")
105
+ else:
106
+ print("1. Upgrading via pip ...", end=" ", flush=True)
107
+ pip_cmd = _get_pip_command()
108
+ result = subprocess.run(
109
+ [pip_cmd, "install", "--upgrade", f"git+{GIT_REPO_URL}"],
110
+ capture_output=True, text=True, timeout=120,
111
+ )
112
+ if result.returncode != 0:
113
+ print("FAILED")
114
+ print(result.stderr)
115
+ return False
116
+ print("done")
117
+
118
+ print(f"\nUpgrade to v{latest_tag} complete!")
119
+ return True
120
+
121
+ except (subprocess.TimeoutExpired, OSError) as e:
122
+ print(f"FAILED — {e}")
123
+ return False
124
+
125
+
126
+ def check_for_upgrades() -> bool:
127
+ """Check GitHub tags for a newer version and upgrade if available. Returns True on success."""
128
+ latest_tag = _fetch_latest_tag()
129
+ if latest_tag is None:
130
+ return False
131
+
132
+ def parse_ver(v: str):
133
+ parts = v.split(".")
134
+ return tuple(int(p) if p.isdigit() else 0 for p in parts[:3])
135
+
136
+ current = parse_ver(VERSION)
137
+ latest = parse_ver(latest_tag)
138
+
139
+ if latest <= current:
140
+ print(f"You're up to date! (v{VERSION})")
141
+ return False
142
+
143
+ return _perform_upgrade(latest_tag)
144
+
145
+
146
+ def detach_from_terminal():
147
+ """Fork and release the terminal (Unix only). Parent exits, child continues."""
148
+ try:
149
+ pid = os.fork()
150
+ if pid > 0:
151
+ sys.exit(0)
152
+ os.setsid()
153
+ devnull = os.open(os.devnull, os.O_RDWR)
154
+ os.dup2(devnull, 0)
155
+ os.dup2(devnull, 1)
156
+ os.dup2(devnull, 2)
157
+ os.close(devnull)
158
+ except OSError:
159
+ pass
160
+
161
+
162
+ def run():
163
+ """Parse CLI arguments and run the application."""
164
+ parser = argparse.ArgumentParser(description="AetherVault — secure password manager")
165
+ parser.add_argument(
166
+ "--version", "-v",
167
+ action="store_true",
168
+ help="Show version and exit",
169
+ )
170
+ parser.add_argument(
171
+ "--debug", "-d",
172
+ action="store_true",
173
+ help="Enable debug logging to terminal",
174
+ )
175
+ parser.add_argument(
176
+ "--upgrade", "-u",
177
+ action="store_true",
178
+ help="Check for updates and auto-upgrade (git pull + pip install)",
179
+ )
180
+ parser.add_argument(
181
+ "--foreground", "-f",
182
+ action="store_true",
183
+ help="Keep terminal attached (for debugging)",
184
+ )
185
+ args = parser.parse_args()
186
+
187
+ if args.version:
188
+ print(f"AetherVault v{VERSION}")
189
+ sys.exit(0)
190
+
191
+ if args.upgrade:
192
+ check_for_upgrades()
193
+ sys.exit(0)
194
+
195
+ if args.debug:
196
+ logging.basicConfig(
197
+ level=logging.DEBUG,
198
+ stream=sys.stderr,
199
+ format="%(levelname)s:%(name)s:%(message)s",
200
+ )
201
+
202
+ if not args.foreground and sys.platform != "win32":
203
+ detach_from_terminal()
204
+
205
+ app = QApplication(sys.argv)
206
+ app.setStyle("Fusion")
207
+ window = PySidePWManager()
208
+ window.show()
209
+ QTimer.singleShot(500, window.check_setup_state)
210
+ sys.exit(app.exec())
211
+
212
+
213
+ if __name__ == "__main__":
214
+ run()