|
|
3 هفته پیش | |
|---|---|---|
| certs | 3 هفته پیش | |
| static | 3 هفته پیش | |
| templates | 3 هفته پیش | |
| .gitignore | 3 هفته پیش | |
| README.md | 3 هفته پیش | |
| app.py | 3 هفته پیش | |
| config.example.toml | 3 هفته پیش | |
| pps_client.py | 3 هفته پیش | |
| requirements.txt | 3 هفته پیش | |
| worker.py | 3 هفته پیش |
A small web client for the Proofpoint Protection Server (PPS) quarantine. It lists quarantined mail by folder and runs bulk actions — Release, Report & Release, Delete, Move — as asynchronous background jobs, so the operator never waits on slow PPS API calls (deletes in particular).
Proof of concept: static login, plaintext secrets in a config file, no permission model. SAML/OIDC and RBAC come later.
templates/, static/): one page. A folder switcher scopes the whole
view to one quarantine folder; the list shows date / sender / recipient / subject with a
checkbox per row. Clicking a row opens the message content in an overlay over the list
(HTML parts render in a sandboxed iframe). Actions apply to all checked rows, which then
disappear from the list immediately.app.py, pps_client.py): Flask serves the UI and proxies the PPS
Quarantine Search REST API. Actions are queued and return instantly (HTTP 202).worker.py): a daemon thread drains a SQLite-backed job queue, batching
message ids into chunked PPS POSTs. Jobs are persistent, so queued work survives a
restart; a job left mid-flight is requeued on startup.| UI action | PPS API call(s) |
|---|---|
| Release | release without rescan; deletedfolder set so it leaves the folder |
| Report & Release | release (in place, no rescan) then move a copy to report_release_folder |
| Delete | delete with deletedfolder (moves to deleted items, not a hard delete) |
| Move | move to the folder chosen in the dropdown |
Report & Release keeps a copy in report_release_folder (default "Debugging - Josef")
for manual false-positive submission while the mail is delivered. If this PPS deployment's
release relocates the message to the deleted folder (like the admin GUI does), the worker
re-finds it there by its stable guid and moves it from there — no configuration needed.
Every message the background worker acts on is recorded in a dedicated, rotating log file
(worker_log, default worker.log — 5 MB × 5 files). One line per message, e.g.:
2026-07-14 17:39:56 job=#12 action=delete result=ok src='Quarantine' dst='Deleted' localguid=6:6:1 guid=g-aaa from='sender@spam.example' rcpt='victim@corp.com' subject='You won a prize'
result is ok or FAILED (failures also carry error=...). Fields are key=value for
easy grep. This is separate from the general application log (stdout, controlled by
log_level), which covers requests, job lifecycle, and PPS API calls.
python3 -m venv venv
venv/bin/pip install -r requirements.txt
cp config.example.toml config.toml
# edit config.toml: PPS host, API credentials, folders, login
venv/bin/python app.py
Open http://127.0.0.1:8080 and sign in with the [auth] credentials from config.toml.
folders array in config.toml is the source of truth for the switcher, the Move
dropdown, and the delete/report targets. Names must match PPS exactly (case- and
space-sensitive, e.g. "Debugging - Josef"); a wrong name only errors at action time.list_query = "from=*". The search API requires a from/rcpt/subject filter —
it can't list a folder by folder alone. A bare wildcard means "everything in the folder".
If your PPS doesn't treat from=* as match-all, set it to something like
rcpt=@yourdomain.com.default_days_back. The search API alone returns only the last 24h; this widens the
window (uses startdate).default_limit sets
the UI default; the operator can raise it to 1000.verify_tls. PPS admin certs are often self-signed; false skips verification (PoC).
Point it at a CA bundle path to verify instead.400 No required SSL certificate was sent. Set
client_cert (a combined cert+key PEM, or a cert PEM plus client_key for the key).
Note this is a TLS client cert, separate from the [pps] Basic-auth credentials —
the endpoint may require both.The account in [pps] must be a PPS admin with an API Role that has the Quarantine
module enabled (see the PPS management interface / a Proofpoint support ticket for PoD).
Auth is HTTP Basic against the admin port (default 10000).
app.py Flask app: routes, login, config, worker startup
pps_client.py PPS Quarantine REST client (search / get_raw / act)
worker.py SQLite job queue + background worker thread
config.example.toml Config template (copy to config.toml)
templates/ login.html, index.html
static/ app.js, style.css