fix: make telemetry opt-in
This commit is contained in:
+8
-4
@@ -110,12 +110,16 @@ JMAP_SERVER_URL=https://your-jmap-server.com
|
||||
# Anonymous Telemetry
|
||||
# =============================================================================
|
||||
|
||||
# Anonymous instance telemetry is enabled by default. Heartbeats contain no PII:
|
||||
# version, platform, bucketed account counts, and feature toggles only. See
|
||||
# Anonymous instance telemetry is OPT-IN and disabled by default. Enabling it
|
||||
# helps us understand how Bulwark is used so we can make the product better.
|
||||
# Heartbeats contain no PII: version, platform, bucketed account counts, and
|
||||
# feature toggles only - never email addresses, hostnames, or IPs. See
|
||||
# https://bulwarkmail.org/docs/legal/privacy/telemetry for the full schema.
|
||||
#
|
||||
# Disable telemetry entirely (overrides the admin UI):
|
||||
# BULWARK_TELEMETRY=off
|
||||
# Enable telemetry (also toggleable in the admin UI):
|
||||
# BULWARK_TELEMETRY=on
|
||||
#
|
||||
# Setting this (on or off) locks the choice and disables the admin UI toggle.
|
||||
|
||||
# Directory for telemetry state: instance id, consent, login HMACs
|
||||
# (default: ./data/telemetry). For Docker, the default resolves to
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ Automatic browser detection with persistent preference. Configurable locale URL
|
||||
- Progressive Web App with service worker, install prompt, web push notifications for inbox mail, dynamic manifest, and configurable (per-domain) install screenshots
|
||||
- Automatic update check with server-side logging of new releases and a non-dismissible update notice
|
||||
- Structured logging (`text` or `json`) with category-based levels
|
||||
- Anonymous instance telemetry (opt-out via admin UI or `BULWARK_TELEMETRY=off`) – version, platform, bucketed account counts, feature toggles only
|
||||
- Anonymous instance telemetry (opt-in via admin UI, the installer, or `BULWARK_TELEMETRY=on`; off by default) – version, platform, bucketed account counts, feature toggles only
|
||||
- Release (`main`) and development (`dev`) Docker images on GHCR
|
||||
- Subpath deployment via `NEXT_PUBLIC_BASE_PATH` for mounting behind a reverse proxy
|
||||
- Demo mode with fixture data – no mail server required
|
||||
|
||||
@@ -118,9 +118,10 @@ export function TelemetryTab() {
|
||||
<header className="space-y-2">
|
||||
<h1 className="text-2xl font-semibold">Anonymous Usage Stats</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Bulwark sends one anonymous heartbeat per day so we can see how many instances are
|
||||
running, on what platforms, and which features they use. <strong>Enabled by default</strong>;
|
||||
one click below disables it. No email addresses, no hostnames, no IPs are sent.{' '}
|
||||
Bulwark can send one anonymous heartbeat per day so we can see how many instances are
|
||||
running, on what platforms, and which features they use. It's <strong>off by
|
||||
default</strong>; one click below enables it and helps us make the product better. No
|
||||
email addresses, no hostnames, no IPs are sent.{' '}
|
||||
<a
|
||||
href="https://bulwarkmail.org/docs/legal/privacy/telemetry"
|
||||
target="_blank"
|
||||
@@ -138,8 +139,8 @@ export function TelemetryTab() {
|
||||
<div className="font-medium">Status</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{status.consent === 'pending' && 'Initialising - no heartbeats sent yet.'}
|
||||
{status.consent === 'on' && 'Heartbeats are enabled (default).'}
|
||||
{status.consent === 'off' && 'Heartbeats are off.'}
|
||||
{status.consent === 'on' && 'Heartbeats are enabled. Thanks for helping us improve!'}
|
||||
{status.consent === 'off' && 'Heartbeats are off (default).'}
|
||||
{envOverridden && (
|
||||
<> Locked by <code>BULWARK_TELEMETRY</code> env var.</>
|
||||
)}
|
||||
|
||||
+11
-11
@@ -17,6 +17,7 @@ function idPath(): string { return path.join(getDir(), '.telemetry-id'); }
|
||||
function envOverride(): ConsentState | null {
|
||||
const v = (process.env.BULWARK_TELEMETRY ?? '').toLowerCase();
|
||||
if (v === 'off' || v === 'false' || v === '0' || v === 'no') return 'off';
|
||||
if (v === 'on' || v === 'true' || v === '1' || v === 'yes') return 'on';
|
||||
if (process.env.BULWARK_TELEMETRY_DISABLED) {
|
||||
const d = process.env.BULWARK_TELEMETRY_DISABLED.toLowerCase();
|
||||
if (d === '1' || d === 'true' || d === 'yes') return 'off';
|
||||
@@ -41,11 +42,13 @@ export async function getInstanceId(): Promise<string> {
|
||||
return fresh;
|
||||
}
|
||||
|
||||
// Default consent is 'on' - telemetry is anonymous and enabled by default.
|
||||
// Admins can disable via the UI, the BULWARK_TELEMETRY env var, or by clearing
|
||||
// the endpoint. See https://bulwarkmail.org/docs/legal/privacy/telemetry.
|
||||
// Default consent is 'off' - telemetry is opt-in. Admins can enable it during
|
||||
// install (BULWARK_TELEMETRY=on in .env.local), via the BULWARK_TELEMETRY env
|
||||
// var, or with one click in the admin UI. Heartbeats are anonymous: no PII,
|
||||
// just version/platform/feature toggles. Enabling helps us improve the product.
|
||||
// See https://bulwarkmail.org/docs/legal/privacy/telemetry.
|
||||
const DEFAULTS: TelemetryStateFile = {
|
||||
consent: 'on',
|
||||
consent: 'off',
|
||||
endpoint: DEFAULT_ENDPOINT,
|
||||
consentedAt: null,
|
||||
lastSentAt: null,
|
||||
@@ -64,13 +67,10 @@ export async function loadState(): Promise<TelemetryStateFile> {
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
});
|
||||
}
|
||||
// First-ever load on a fresh install: persist the default-on state with
|
||||
// an autoEnabledAt stamp so the admin UI can show "telemetry was
|
||||
// auto-enabled at <time>; disable here" without re-arming on restart.
|
||||
const fresh: TelemetryStateFile = {
|
||||
...DEFAULTS,
|
||||
consentedAt: new Date().toISOString(),
|
||||
};
|
||||
// First-ever load on a fresh install: persist the default-off state so the
|
||||
// instance id and (lack of) consent are stable across restarts. The admin
|
||||
// can opt in later via the UI or the BULWARK_TELEMETRY env var.
|
||||
const fresh: TelemetryStateFile = { ...DEFAULTS };
|
||||
await saveState(fresh);
|
||||
return fresh;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ CFG_OAUTH_ISSUER_URL=""
|
||||
CFG_SESSION_SECRET=""
|
||||
CFG_SETTINGS_SYNC_ENABLED="false"
|
||||
CFG_SETTINGS_DATA_DIR="./data/settings"
|
||||
CFG_TELEMETRY="false"
|
||||
CFG_LOG_FORMAT="text"
|
||||
CFG_LOG_LEVEL="info"
|
||||
CFG_APP_SHORT_NAME=""
|
||||
@@ -733,6 +734,30 @@ screen_security_config() {
|
||||
echo -e " ${DIM}You can add a SESSION_SECRET to .env.local at any time.${RESET}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
hr
|
||||
echo ""
|
||||
echo -e " ${BOLD}Anonymous Usage Stats${RESET}"
|
||||
echo ""
|
||||
echo -e " Bulwark can send one anonymous heartbeat per day. It helps us see how"
|
||||
echo -e " many instances run, on what platforms, and which features are enabled"
|
||||
echo -e " so we can ${BOLD}make the product better${RESET}."
|
||||
echo ""
|
||||
echo -e " ${STAR} ${BOLD}No private data${RESET} - no email addresses, hostnames, or IPs"
|
||||
echo -e " ${STAR} Just version, platform, and which features are turned on"
|
||||
echo -e " ${STAR} ${BOLD}Off by default${RESET} - you can change it any time in the admin UI"
|
||||
echo ""
|
||||
|
||||
prompt_yesno "Enable anonymous telemetry to help improve Bulwark?" "$CFG_TELEMETRY" "CFG_TELEMETRY"
|
||||
|
||||
if [[ "$CFG_TELEMETRY" == "true" ]]; then
|
||||
echo ""
|
||||
echo -e " ${OK} ${GREEN}Thanks! Telemetry will be enabled. We appreciate it.${RESET}"
|
||||
else
|
||||
echo ""
|
||||
note "Telemetry stays off. No heartbeats will be sent."
|
||||
fi
|
||||
|
||||
draw_footer
|
||||
read -r
|
||||
}
|
||||
@@ -948,6 +973,11 @@ screen_summary() {
|
||||
else
|
||||
echo -e " Session Secret ........ ${DIM}Not set${RESET}"
|
||||
fi
|
||||
if [[ "$CFG_TELEMETRY" == "true" ]]; then
|
||||
echo -e " Anonymous Telemetry ... ${GREEN}${BOLD}Enabled${RESET} ${DIM}(thank you!)${RESET}"
|
||||
else
|
||||
echo -e " Anonymous Telemetry ... ${DIM}Off${RESET}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Logging
|
||||
@@ -1093,6 +1123,20 @@ ENVEOF
|
||||
|
||||
cat >> "$ENV_FILE" << ENVEOF
|
||||
|
||||
# -- Anonymous Telemetry -------------------------------------------------------
|
||||
# Opt-in, anonymous heartbeats (no PII). Off by default; helps improve Bulwark.
|
||||
# Toggleable later in the admin UI unless this is set. See
|
||||
# https://bulwarkmail.org/docs/legal/privacy/telemetry
|
||||
ENVEOF
|
||||
|
||||
if [[ "$CFG_TELEMETRY" == "true" ]]; then
|
||||
echo "BULWARK_TELEMETRY=on" >> "$ENV_FILE"
|
||||
else
|
||||
echo "# BULWARK_TELEMETRY=on" >> "$ENV_FILE"
|
||||
fi
|
||||
|
||||
cat >> "$ENV_FILE" << ENVEOF
|
||||
|
||||
# -- Logging -------------------------------------------------------------------
|
||||
LOG_FORMAT=${CFG_LOG_FORMAT}
|
||||
LOG_LEVEL=${CFG_LOG_LEVEL}
|
||||
@@ -1340,6 +1384,11 @@ load_existing_config() {
|
||||
get_env_val "SESSION_SECRET"; [[ -n "$val" ]] && CFG_SESSION_SECRET="$val"
|
||||
get_env_val "SETTINGS_SYNC_ENABLED"; [[ -n "$val" ]] && CFG_SETTINGS_SYNC_ENABLED="$val"
|
||||
get_env_val "SETTINGS_DATA_DIR"; [[ -n "$val" ]] && CFG_SETTINGS_DATA_DIR="$val"
|
||||
get_env_val "BULWARK_TELEMETRY"
|
||||
case "$(echo "$val" | tr '[:upper:]' '[:lower:]')" in
|
||||
on|true|1|yes) CFG_TELEMETRY="true" ;;
|
||||
off|false|0|no) CFG_TELEMETRY="false" ;;
|
||||
esac
|
||||
get_env_val "LOG_FORMAT"; [[ -n "$val" ]] && CFG_LOG_FORMAT="$val"
|
||||
get_env_val "LOG_LEVEL"; [[ -n "$val" ]] && CFG_LOG_LEVEL="$val"
|
||||
get_env_val "LOGIN_COMPANY_NAME"; [[ -n "$val" ]] && CFG_LOGIN_COMPANY_NAME="$val"
|
||||
|
||||
Reference in New Issue
Block a user