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,107 @@
|
||||
# BoltClam architecture
|
||||
|
||||
## Process layout
|
||||
|
||||
BoltClam is one PyQt6 process on the user's Windows desktop. It starts no
|
||||
Windows service and installs no driver. ClamAV remains an external program.
|
||||
|
||||
```
|
||||
BoltClam.exe (PyInstaller or portable launcher)
|
||||
└─ boltclam.app
|
||||
├─ MainWindow ── HomePage / ScanPage / AboutPage / SettingsPage
|
||||
├─ RealtimeProtection ── DownloadWatcher + QThreadPool scan tasks
|
||||
├─ ScanWorker / DefinitionWorker (QThread)
|
||||
├─ Storage (SQLite, WAL)
|
||||
├─ QuarantineService
|
||||
├─ ClamAVService → clamscan.exe / freshclam.exe
|
||||
└─ ApiClient → https://api.themajesticnetwork.com
|
||||
```
|
||||
|
||||
Settings are JSON under `%APPDATA%\BoltClam`; history and quarantine live
|
||||
under `%LOCALAPPDATA%\BoltClam`. `BOLTCLAM_CONFIG_DIR` and
|
||||
`BOLTCLAM_DATA_DIR` override both for tests and portable/development use.
|
||||
|
||||
## Page responsibilities
|
||||
|
||||
- **HomePage** calls `system_info.collect()` on a worker. PowerShell supplies
|
||||
Defender/firewall/network facts on Windows; missing data is "not reported".
|
||||
The shell gauge and concern list are derived from ClamAV state, definition
|
||||
age, real-time state, firewall, last scan, active detections and quarantine
|
||||
count. It never labels an unknown state as protected.
|
||||
- **ScanPage** persists scope/auto-response preferences immediately, runs
|
||||
`ScanWorker`, records each detection in SQLite before remediation, and
|
||||
exposes manual quarantine/delete/ignore after a scan. Quarantine management
|
||||
restores to the original path or a chosen path and refuses overwrites.
|
||||
- **AboutPage** calls `/boltclam/account` for user/plan data and
|
||||
`/boltclam/updates` for the release feed. Downloads use the API asset proxy
|
||||
and optionally verify `SHA256SUMS.txt`.
|
||||
- **SettingsPage** validates ClamAV paths and extra options, applies logging
|
||||
changes, updates the real-time watcher, and creates/uploads diagnostics
|
||||
bundles only when the user has opted in.
|
||||
|
||||
## Sign-in sequence
|
||||
|
||||
```
|
||||
BoltClam Browser Bolt desk API
|
||||
|-- PKCE verifier/challenge --| |
|
||||
|-- loopback listener :port/cb| |
|
||||
|-- open /desk/auth/boltclam/start?... ------------------->|
|
||||
| |<-- branded login page -----|
|
||||
| |-- email/password or OAuth->|
|
||||
|<-- 302 /cb?code=...&state=... ----------------------------|
|
||||
|-- POST /desk/auth/oauth/exchange (code+verifier) -------->|
|
||||
|<-- {api_key, user} --------------------------------------|
|
||||
|-- DPAPI-store key, GET /boltclam/account ---------------->|
|
||||
```
|
||||
|
||||
The one-time code is bound to the PKCE challenge, the exact loopback URI and
|
||||
a short TTL. The app rejects a callback whose state does not match. The API
|
||||
burns an exchange code on the first attempt, successful or not.
|
||||
|
||||
## Scan sequence
|
||||
|
||||
1. `ClamAVService.info()` locates `clamscan.exe`, runs `--version`, and
|
||||
chooses the managed database if it contains signatures.
|
||||
2. `scan_targets("homes")` reads the Windows `ProfileList` registry and
|
||||
falls back to `C:\Users`; `"full"` enumerates fixed local drives.
|
||||
3. `ScanWorker` starts clamscan with an argv list, no shell, and parses
|
||||
detections/progress/summary. Each `path: Signature FOUND` becomes a
|
||||
`Detection` row first, then quarantine/delete/notify is applied.
|
||||
4. The scan row is finished even on cancellation or process failure. The UI
|
||||
reloads history and the Homepage aggregates.
|
||||
|
||||
## Real-time sequence
|
||||
|
||||
`DownloadWatcher` polls each watched download folder at 1.5 s intervals (and
|
||||
refreshes browser preferences every 30 s), ignores in-progress suffixes, and
|
||||
waits for a stable size/mtime. `RealtimeScanTask` runs in a QThreadPool:
|
||||
|
||||
```
|
||||
stable file → exclusive handle (share=0) → copy → ClamAV scans copy
|
||||
→ clean: release → detection: release + quarantine/delete
|
||||
```
|
||||
|
||||
The exclusive handle is held for the entire scan. A fallback copy is used
|
||||
when the file is already open, with that fact recorded in the event detail.
|
||||
|
||||
## Update flow
|
||||
|
||||
- The Bolt API reads Gitea's `/api/v1/repos/TheMajesticNetwork/BoltClam/releases`,
|
||||
caches for five minutes, filters draft/prerelease by channel, and returns
|
||||
normalized release metadata.
|
||||
- Asset downloads go through the API, so a future private repository needs
|
||||
no desktop token. The API streams the Gitea asset with its own token.
|
||||
- The client compares semantic versions, selects a Windows `.exe`/`.zip`
|
||||
asset, downloads it to `%LOCALAPPDATA%\BoltClam\updates`, and verifies the
|
||||
release checksum when published.
|
||||
|
||||
## Storage schema
|
||||
|
||||
- `scans` — scope, status, paths JSON, counts, engine/DB versions, duration.
|
||||
- `detections` — scan id, path, signature, action, quarantine id, timestamp.
|
||||
- `quarantine` — id, original/quarantine path, signature, SHA-256, status.
|
||||
- `realtime_events` — download path, signature, action, detail, timestamp.
|
||||
|
||||
All writes open their own SQLite connection; WAL mode lets the UI read while
|
||||
a scan thread writes. Quarantine sidecars are JSON, so the record survives a
|
||||
database rebuild.
|
||||
@@ -0,0 +1,114 @@
|
||||
# BoltClam security model
|
||||
|
||||
BoltClam is a **signature-based second opinion**, not a replacement for
|
||||
Windows Defender or a kernel-level endpoint protection platform. This file
|
||||
states exactly what the user-mode protections do, where they stop, and what
|
||||
the app stores.
|
||||
|
||||
## Trust boundaries
|
||||
|
||||
- **Bolt API** (`api.themajesticnetwork.com`) is the only network service
|
||||
BoltClam talks to. It proxies Gitea release metadata and assets, so a
|
||||
Gitea token is never shipped to a desktop.
|
||||
- **ClamAV** is a separate, user-installed executable (`clamscan.exe` /
|
||||
`freshclam.exe`). BoltClam runs it as the current user and parses its
|
||||
output. BoltClam does not load ClamAV DLLs into its own process.
|
||||
- **Windows** is trusted for DPAPI, file handles, and security-center facts
|
||||
reported by PowerShell. If PowerShell or Defender cmdlets are unavailable,
|
||||
the UI says "not reported" rather than inventing a pass.
|
||||
- **Gitea** is trusted for release metadata only. Downloads are either
|
||||
proxied through the Bolt API or checked against a release SHA-256 when a
|
||||
checksum asset exists.
|
||||
|
||||
## Credentials
|
||||
|
||||
- Sign-in uses the existing desk API browser/PKCE flow. The password is
|
||||
entered on a Bolt-hosted page and is never sent to BoltClam.
|
||||
- The resulting `bolt_live_...` API key is stored in
|
||||
`%APPDATA%\BoltClam\credentials.dat` encrypted with Windows DPAPI
|
||||
(current-user scope, with an app-specific entropy value).
|
||||
- On non-Windows development hosts the credential store falls back to a
|
||||
mode-0600 local file and logs a warning. That fallback is for development
|
||||
only.
|
||||
- A key is never written to `settings.json`, logs, or diagnostics bundles.
|
||||
- Sign-out revokes only the key this PC used, then deletes the local copy.
|
||||
|
||||
## Scan and remediation
|
||||
|
||||
- Scans run `clamscan` with `--infected --verbose --stdout` and explicit
|
||||
argument lists (no shell). Extra options come from the user's settings and
|
||||
are parsed; `--remove`, `--move`, and `--copy` are refused so every action
|
||||
goes through BoltClam's recorded quarantine/delete path.
|
||||
- A detection is written to SQLite **before** remediation is attempted. If
|
||||
quarantine or delete fails, the record stays visible as `failed` instead of
|
||||
disappearing.
|
||||
- Quarantine moves the original file into
|
||||
`%LOCALAPPDATA%\BoltClam\quarantine`, renames it to `.quarantine`, records
|
||||
its SHA-256 and original path, and writes a JSON sidecar. Restore refuses to
|
||||
overwrite an existing file. Delete is permanent and explicitly confirmed.
|
||||
- The quarantine folder is user-writable. A malicious process already running
|
||||
as that user could tamper with it; strong tamper resistance would require a
|
||||
privileged service and kernel driver, which this app does not install.
|
||||
|
||||
## Real-time download gate
|
||||
|
||||
BoltClam watches browser download folders and waits for a file's size and
|
||||
mtime to stop changing. It then:
|
||||
|
||||
1. opens the file with `CreateFileW` and `dwShareMode = 0` (deny other
|
||||
opens) where possible;
|
||||
2. copies it to a private temp path through that handle;
|
||||
3. scans the copy with ClamAV while the original remains locked;
|
||||
4. on a clean result, releases the lock;
|
||||
5. on a detection, closes the lock and moves the file to quarantine (or
|
||||
deletes it if that setting was chosen).
|
||||
|
||||
This blocks ordinary `CreateFile` opens during the scan, including a
|
||||
double-click, which is the meaningful user-mode speed bump. It is **not**:
|
||||
|
||||
- a kernel minifilter, so a driver or a process using backup semantics can
|
||||
bypass it;
|
||||
- a guarantee when another process already holds the file open — BoltClam
|
||||
reports "File was in use; scanned a copy" and still remediates afterward;
|
||||
- protection for downloads made outside a watched browser download folder
|
||||
(curl, scripts, existing files, network shares);
|
||||
- a replacement for Windows Defender's real-time engine.
|
||||
|
||||
The **Notify only** response leaves the detected file in place. Use
|
||||
Quarantine (the default) if the machine must not retain detected downloads.
|
||||
Files larger than `BOLTCLAM_REALTIME_MAX_MB` (default 1024 MiB) are reported
|
||||
and not scanned in real time.
|
||||
|
||||
## Definitions and updates
|
||||
|
||||
- `freshclam` writes to BoltClam's own `%LOCALAPPDATA%\BoltClam\clamav-db`,
|
||||
avoiding a Program Files write. `clamscan` uses that database when present
|
||||
and otherwise falls back to the database beside the installed binary.
|
||||
- The signed-in user can see definition age in the Homepage and Settings.
|
||||
"Fresh" means no older than seven days; older than 30 days is critical.
|
||||
- Update downloads require a valid Bolt key. If the release includes
|
||||
`SHA256SUMS.txt`, the SHA-256 is verified before the installer is offered.
|
||||
Without a checksum asset the UI says so rather than claiming verification.
|
||||
- Run installers only from the BoltClam Gitea releases page. The app itself
|
||||
does not silently replace its own executable.
|
||||
|
||||
## Diagnostics
|
||||
|
||||
Uploading diagnostics is **opt-in and explicit**. The bundle contains:
|
||||
|
||||
- redacted app logs;
|
||||
- settings (API key absent);
|
||||
- scan/quarantine summaries and real-time event metadata (paths redacted to
|
||||
`%USERPROFILE%`);
|
||||
- ClamAV and system summary;
|
||||
- account email, so support can identify the upload.
|
||||
|
||||
It never contains file contents, browser history, passwords, API keys, or
|
||||
the DPAPI credential file. Logs cap size and rotate locally.
|
||||
|
||||
## Reporting a problem
|
||||
|
||||
For a security issue in BoltClam or the BoltClam API, contact The Majestic
|
||||
Network directly rather than opening a public issue with exploit details.
|
||||
Include the app version, Windows version, and the relevant redacted log
|
||||
excerpt.
|
||||
Reference in New Issue
Block a user