Trial and registration/referral-bonus subscriptions usually last only a
few days, so the multi-day ending-soon reminders fired almost the moment
they were granted and needlessly alarmed newcomers.
Track this with a new subscription flag (suppress_early_expiry_notifications,
migration 0035): trial activation, referral welcome bonus and inviter bonus
grants set it, while a real paid purchase clears it on upsert. While set, the
notification worker skips the day-before stages but still sends the
hours-before reminder and the expiry/after-expiry notices, so users are
warned shortly before access ends. Once they pay for a full subscription the
complete reminder spectrum resumes.
Bring the ASCII, Windows 95 and light themes up to date with the
webapp changes since the last theme refresh:
- Flatten/bevel the new Telegram notifications banner icon badge.
- Square off the premium-server and referral-tariff dropdown help
pills and bevel the standalone referral surfaces (win95).
- Fix the selected-language check vanishing on the highlighted row
(black on ASCII, inverted bitmap on win95).
- Square the login-screen language trigger and render flag emoji
monochrome in the ASCII console palette.
- Add a soft drop shadow to the banner on the light theme.
Bump assets_version for all three CSS themes and update the theme
config tests accordingly.
Add a broadcast audience for users who registered but never had any subscription or trial (no Subscription rows at all), backed by a new get_user_ids_without_any_subscription DAL helper and a 'never' target in the webapp broadcast route.
Add GET /api/admin/broadcast/audience-counts so the audience dropdown shows the recipient count next to each option, with graceful fallback when counts are unavailable.
CodeQL still traced taint through the previous helpers: the endpoint
regex fallback returned source-derived text and the payload dict keys
flowed verbatim into the log. Resolve both by sourcing every logged
token from literal lookup tables — endpoints map to constant path
labels and payload keys map through a field-name allow-list, with
unknown keys/paths collapsing to <field>/<other>. No source-derived
string (key, value or id) reaches the logger.
Rebuild logged endpoints from constant path templates and reduce every
payload leaf to a JSON type token, so user/squad UUIDs and PII (email,
telegramId) can never reach the dry-run log as clear text. Resolves
CodeQL py/clear-text-logging-sensitive-data findings.
CodeQL flagged clear-text logging of sensitive information in the panel
dry-run logger: it dumped the full request payload (which can include
proxy credentials like trojanPassword/ssPassword and PII such as email
and telegramId) and the raw endpoint (embedding user UUIDs).
Recursively redact values under sensitive keys before building the
payload preview, and mask opaque id-like segments in logged endpoints.
Add a once-a-day anonymous heartbeat (PostHog) so maintainers can see
active installs and version/OS breakdowns. Self-hosted friendly: opt out
via TELEMETRY_ENABLED in .env or the Admin -> System toggle (applied
without a restart), or by clearing the endpoint/key.
- Share version resolution in bot/utils/app_version.py so the admin
sidebar and the beacon report the same build version
- TelemetryWorker sends an opaque install id plus coarse facts only
(version, OS/arch, python, locale, enabled providers, user-count
range); never tokens, domains or user data
- Register the worker in main_worker.py behind a Redis single-flight lock
- Expose TELEMETRY_* settings and an Admin -> System manifest toggle
- Document the payload and opt-out in docs/configuration/telemetry.md
- Cover bucketing, payload shape and anonymity with tests