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.
- aethervault_py-6.4.0/LICENSE +17 -0
- aethervault_py-6.4.0/MANIFEST.in +10 -0
- aethervault_py-6.4.0/PKG-INFO +200 -0
- aethervault_py-6.4.0/README.md +187 -0
- aethervault_py-6.4.0/aethervault/__init__.py +49 -0
- aethervault_py-6.4.0/aethervault/__main__.py +214 -0
- aethervault_py-6.4.0/aethervault/assets/aethersol.ico +0 -0
- aethervault_py-6.4.0/aethervault/assets/aethersol_logo.png +0 -0
- aethervault_py-6.4.0/aethervault/assets/screens/aethervault-demo.gif +0 -0
- aethervault_py-6.4.0/aethervault/assets/screens/entry.png +0 -0
- aethervault_py-6.4.0/aethervault/assets/screens/generator.png +0 -0
- aethervault_py-6.4.0/aethervault/assets/screens/health.png +0 -0
- aethervault_py-6.4.0/aethervault/assets/screens/login.png +0 -0
- aethervault_py-6.4.0/aethervault/assets/screens/vault.png +0 -0
- aethervault_py-6.4.0/aethervault/core/__init__.py +6 -0
- aethervault_py-6.4.0/aethervault/core/engine.py +226 -0
- aethervault_py-6.4.0/aethervault/core/password.py +67 -0
- aethervault_py-6.4.0/aethervault/docs/USER_GUIDE.html +238 -0
- aethervault_py-6.4.0/aethervault/docs/USER_GUIDE.md +163 -0
- aethervault_py-6.4.0/aethervault/gui/__init__.py +6 -0
- aethervault_py-6.4.0/aethervault/gui/app.py +1059 -0
- aethervault_py-6.4.0/aethervault/gui/click_to_copy_filter.py +24 -0
- aethervault_py-6.4.0/aethervault/gui/conflict_dialog.py +141 -0
- aethervault_py-6.4.0/aethervault/gui/credential_form.py +351 -0
- aethervault_py-6.4.0/aethervault/gui/credential_table.py +344 -0
- aethervault_py-6.4.0/aethervault/gui/dialogs.py +172 -0
- aethervault_py-6.4.0/aethervault/gui/password_strength.py +46 -0
- aethervault_py-6.4.0/aethervault/gui/theme.py +371 -0
- aethervault_py-6.4.0/aethervault/shared/__init__.py +6 -0
- aethervault_py-6.4.0/aethervault/shared/database.py +577 -0
- aethervault_py-6.4.0/aethervault/shared/models.py +54 -0
- aethervault_py-6.4.0/aethervault_py.egg-info/PKG-INFO +200 -0
- aethervault_py-6.4.0/aethervault_py.egg-info/SOURCES.txt +43 -0
- aethervault_py-6.4.0/aethervault_py.egg-info/dependency_links.txt +1 -0
- aethervault_py-6.4.0/aethervault_py.egg-info/entry_points.txt +2 -0
- aethervault_py-6.4.0/aethervault_py.egg-info/requires.txt +2 -0
- aethervault_py-6.4.0/aethervault_py.egg-info/top_level.txt +1 -0
- aethervault_py-6.4.0/pyproject.toml +37 -0
- aethervault_py-6.4.0/setup.cfg +4 -0
- aethervault_py-6.4.0/tests/test_core_logic.py +179 -0
- aethervault_py-6.4.0/tests/test_credential_entry.py +52 -0
- aethervault_py-6.4.0/tests/test_credential_form.py +78 -0
- aethervault_py-6.4.0/tests/test_db_manager.py +320 -0
- aethervault_py-6.4.0/tests/test_duress.py +95 -0
- 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
|
+

|
|
47
|
+
|
|
48
|
+

|
|
49
|
+

|
|
50
|
+

|
|
51
|
+

|
|
52
|
+

|
|
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
|
+

|
|
34
|
+
|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

|
|
38
|
+

|
|
39
|
+

|
|
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()
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|