BoltClam 1.0.0: ClamAV desktop protection with Bolt sign-in
Adds the PyQt6 Windows client (Homepage, Scan & results, About & updates, Settings), ClamAV scanning and quarantine, browser-download watch with an exclusive scan gate, Bolt loopback/PKCE sign-in with DPAPI key storage, Gitea release feed with checksum verification, opt-in diagnostics, and Windows/portable build tooling. Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
# BoltClam
|
||||
|
||||
BoltClam is a Windows desktop front-end for **ClamAV**, built with PyQt6 and
|
||||
signed in with a Bolt account. It scans every user's home or the full disk,
|
||||
quarantines or deletes what ClamAV finds, watches browser downloads, and
|
||||
receives update notifications from the private Gitea release feed.
|
||||
|
||||

|
||||
|
||||
## What it does
|
||||
|
||||
- **Homepage** — a live protection summary: a shell gauge for engine,
|
||||
definitions, real-time protection and system firewall; security concerns;
|
||||
network details; recent detections; the signed-in user and Bolt plan.
|
||||
- **Scan & results** — user-home or full-disk scans, live progress, scan
|
||||
history, per-detection actions, and a quarantine manager with restore.
|
||||
- **About & updates** — app version, account and subscription, ClamAV
|
||||
version/definitions, release notes, beta/release channels, and
|
||||
checksum-verified downloads.
|
||||
- **Settings** — update channel, ClamAV install location, extra clamscan
|
||||
options, real-time protection, automatic response, logging/debug, and
|
||||
opt-in diagnostics upload to Bolt.
|
||||
- **Browser download protection** — watches the configured download folder
|
||||
of Chrome, Edge, Brave, Firefox, Vivaldi and Opera (plus every readable
|
||||
user's Downloads folder), waits for the file to settle, holds it with an
|
||||
exclusive Windows handle while ClamAV scans a copy, then quarantines or
|
||||
deletes it according to the setting.
|
||||
- **Bolt sign-in** — opens a Bolt-hosted sign-in page in the default
|
||||
browser, receives a one-time code on a loopback listener, and exchanges it
|
||||
through PKCE for an ordinary `bolt_live_...` API key. The key is stored
|
||||
with Windows DPAPI; the password is never seen or stored by BoltClam.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Windows 10 or 11, x64.
|
||||
- [ClamAV for Windows](https://www.clamav.net/downloads) installed separately.
|
||||
BoltClam does not bundle ClamAV binaries.
|
||||
- A Bolt account (the same account used by the iOS/Android/Boltville clients).
|
||||
- Internet access for sign-in, updates, and the first signature download.
|
||||
- Administrator rights are optional but improve coverage of other users'
|
||||
profiles and protected files.
|
||||
|
||||
## Install
|
||||
|
||||
### Portable build
|
||||
|
||||
1. Download `BoltClam-1.0.0-windows-x64-portable.zip` and extract the whole
|
||||
folder (not just `BoltClam.exe`).
|
||||
2. Run `BoltClam.exe`.
|
||||
3. Sign in with your Bolt account in the browser.
|
||||
4. Install ClamAV, open **Settings → ClamAV engine**, choose
|
||||
`clamscan.exe` (or use **Auto-detect**), and click **Update definitions**.
|
||||
5. Run a scan from **Scan & results**.
|
||||
|
||||
The portable build is assembled by
|
||||
`packaging/build_portable_windows.py` from official Python Embeddable,
|
||||
PyQt6 wheels, and the tiny `packaging/launcher.c` bootstrap. It is not signed;
|
||||
Windows SmartScreen may warn about an unknown publisher. Compare the SHA-256
|
||||
in `SHA256SUMS.txt` with the release.
|
||||
|
||||
### Installer / PyInstaller
|
||||
|
||||
On a Windows build machine with Python 3.11 x64:
|
||||
|
||||
```powershell
|
||||
.\build_windows.ps1
|
||||
```
|
||||
|
||||
This creates a one-folder build under `dist\BoltClam\`, a zip, and — when
|
||||
Inno Setup 6 is installed — `dist\BoltClam-1.0.0-Setup.exe`.
|
||||
Use `.\build_windows.ps1 -OneFile` for a single-file `BoltClam.exe`.
|
||||
`build_windows.bat` is a double-click wrapper.
|
||||
|
||||
## Updates
|
||||
|
||||
Release notifications are read from:
|
||||
|
||||
<https://git.themajesticnetwork.com/TheMajesticNetwork/BoltClam>
|
||||
|
||||
BoltClam calls the Bolt API (`/boltclam/updates`) rather than the Gitea API
|
||||
directly, so the Gitea token stays server-side. The API normalizes releases,
|
||||
filters them by channel, and proxies asset downloads:
|
||||
|
||||
- **Release** channel: stable releases only.
|
||||
- **Beta** channel: prereleases and stable releases.
|
||||
- Assets are downloaded through the API with the user's Bolt key.
|
||||
- If the release publishes `SHA256SUMS.txt`, the downloaded installer/zip is
|
||||
verified before it is offered for installation.
|
||||
|
||||
The Gitea repo is currently public and starts empty. The first release is
|
||||
created by pushing a `v*` tag once a Windows build runner is available (see
|
||||
`.gitea/workflows/windows-release.yml`) or by running `build_windows.ps1` on
|
||||
Windows and uploading the assets with `packaging/publish_release.ps1`.
|
||||
|
||||
## Server API
|
||||
|
||||
The BoltClam client uses the desk API at
|
||||
`https://api.themajesticnetwork.com` by default:
|
||||
|
||||
| Endpoint | Purpose |
|
||||
|---|---|
|
||||
| `GET /desk/auth/boltclam/start` | BoltClam-branded browser sign-in page; validates loopback redirect + PKCE. |
|
||||
| `POST /desk/auth/boltclam/login` | Email/password form handler; returns a one-time code to the app. |
|
||||
| `GET /desk/auth/oauth/{google\|discord}/start` | Existing provider flow, reused by the page's OAuth buttons. |
|
||||
| `POST /desk/auth/oauth/exchange` | Existing PKCE exchange; mints the `bolt_live_...` key. |
|
||||
| `GET /boltclam/account` | User, username/email, plan/subscription, balance. |
|
||||
| `GET /boltclam/updates?channel=release\|beta` | Normalized Gitea release feed. |
|
||||
| `GET /boltclam/updates/<release_id>/assets/<asset_id>` | Authenticated asset proxy. |
|
||||
| `POST /boltclam/logs` | Opt-in diagnostics zip upload. |
|
||||
| `GET /boltclam/admin/logs` | Owner-only log listing (master desk key). |
|
||||
|
||||
The server implementation lives in
|
||||
`/home/themajesticmagician/Documents/Server/tmn-api/ai/boltclam_api.py`
|
||||
(plus the small registration in `ai/desk_api.py` and the `boltclam` client
|
||||
name in `ai/desk_auth.py`). See `docs/BOLTCLAM.md` in that repository for
|
||||
deployment notes.
|
||||
|
||||
## Security and privacy
|
||||
|
||||
- The Bolt password is sent only to the Bolt-hosted sign-in page/API.
|
||||
BoltClam receives a device-scoped API key, stored with Windows DPAPI.
|
||||
- Signing out revokes only this PC's key.
|
||||
- No API key is written to settings or diagnostics.
|
||||
- Diagnostics upload is off by default. When enabled and explicitly sent,
|
||||
the zip contains app logs, settings, scan/quarantine summaries, a system
|
||||
summary and the account email. Tokens and passwords are redacted, emails
|
||||
in logs are redacted, and user-profile path prefixes become
|
||||
`%USERPROFILE%`. File contents are never included.
|
||||
- Quarantine files are renamed to `.quarantine`, made read-only/hidden where
|
||||
possible, and recorded with SHA-256 plus a JSON sidecar.
|
||||
- ClamAV extra options that would delete or move files (`--remove`, `--move`,
|
||||
`--copy`) are refused; remediation stays in BoltClam so it is recorded and
|
||||
reversible.
|
||||
|
||||
**Real-time protection is user-mode, not a kernel filter driver.** Holding a
|
||||
file with `dwShareMode = 0` makes Windows refuse other opens while ClamAV
|
||||
scans a copy, which is a strong speed bump, but it is not a guarantee against
|
||||
a kernel-level bypass. If another process already has the file open, BoltClam
|
||||
falls back to scanning a copy and records that in the event detail. Read
|
||||
[`docs/SECURITY.md`](docs/SECURITY.md) before relying on it as the only
|
||||
anti-malware layer.
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
.venv/bin/pip install -r requirements-dev.txt
|
||||
.venv/bin/pip install -e .
|
||||
.venv/bin/python -m boltclam
|
||||
QT_QPA_PLATFORM=offscreen .venv/bin/python -m pytest tests -q
|
||||
```
|
||||
|
||||
The app reads `BOLTCLAM_API_URL` to override the API base (useful for a
|
||||
local desk API). Tests redirect config/data with `BOLTCLAM_CONFIG_DIR` and
|
||||
`BOLTCLAM_DATA_DIR`; never point those at a real user profile.
|
||||
|
||||
## Repository
|
||||
|
||||
```text
|
||||
BoltClam/
|
||||
├── src/boltclam/ application, services and PyQt pages
|
||||
├── tests/ unit and offscreen UI tests
|
||||
├── resources/ icon, stylesheet rasters and OFL fonts
|
||||
├── packaging/ Windows portable builder, launcher, release helper
|
||||
├── installer/ Inno Setup script
|
||||
├── build_windows.ps1 PyInstaller + installer build on Windows
|
||||
├── BoltClam.spec PyInstaller definition
|
||||
└── .gitea/workflows/ Windows release workflow
|
||||
```
|
||||
|
||||
## Push / release
|
||||
|
||||
The remote is already configured:
|
||||
|
||||
```bash
|
||||
git remote -v
|
||||
# origin https://git.themajesticnetwork.com/TheMajesticNetwork/BoltClam.git
|
||||
```
|
||||
|
||||
Push the initial commit (Git will ask for your Gitea credentials/token):
|
||||
|
||||
```bash
|
||||
git push -u origin main
|
||||
git push origin v1.0.0
|
||||
```
|
||||
|
||||
Pushing the tag triggers the Windows release workflow **if** the repository
|
||||
has a Windows Actions runner and a `GITEA_TOKEN` secret. Without such a
|
||||
runner, build on a Windows PC with `build_windows.ps1` and upload the
|
||||
artifacts with `packaging/publish_release.ps1`.
|
||||
|
||||
## Licensing
|
||||
|
||||
BoltClam is internal software for The Majestic Network; no public license is
|
||||
granted by this repository. **PyQt6 is GPLv3-or-commercial**: distributing
|
||||
BoltClam binaries under proprietary terms requires a commercial PyQt license,
|
||||
or GPLv3 compliance. ClamAV is GPLv2 and is installed separately, not
|
||||
bundled. Fonts are under the SIL Open Font License. See
|
||||
[`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md).
|
||||
Reference in New Issue
Block a user