Opt-in weekly sending of statistics (#6851)

This way, the statistics / self-reporting bot will be made into an
opt-in regular sending of statistics, where you enable the setting once
and then they will be sent automatically. The statistics will be sent to
a bot, so that the user can see exactly which data is being sent, and
how often. The chat will be archived and muted by default, so that it
doesn't disturb the user.

The collected statistics will focus on the public-key-verification that
is performed while scanning a QR code. Later on, we can add more
statistics to collect.

**Context:**

_This is just to give a rough idea; I would need to write a lot more
than a few paragraphs in order to fully explain all the context here_.

End-to-end encrypted messengers are generally susceptible to MitM
attacks. In order to mitigate against this, messengers offer some way of
verifying the chat partner's public key. However, numerous studies found
that most popular messengers implement this public-key-verification in a
way that is not understood by users, and therefore ineffective - [a 2021
"State of Knowledge" paper
concludes:](https://dl.acm.org/doi/pdf/10.1145/3558482.3581773)

> Based on our evaluation, we have determined that all current E2EE
apps, particularly when operating in opportunistic E2EE mode, are
incapable of repelling active man-in-the-middle (MitM) attacks. In
addition, we find that none of the current E2EE apps provide better and
more usable [public key verification] ceremonies, resulting in insecure
E2EE communications against active MitM attacks.

This is why Delta Chat tries to go a different route: When the user
scans a QR code (regardless of whether the QR code creates a 1:1 chat,
invites to a group, or subscribes to a broadcast channel), a
public-key-verification is performed in the background, without the user
even having to know about this.

The statistics collected here are supposed to tell us whether Delta Chat
succeeds to nudge the users into using QR codes in a way that is secure
against MitM attacks.

**Plan for statistics-sending:**

- [x] Get this PR reviewed and merged (but don't make it available in
the UI yet; if Android wants to make a release in the meantime, I will
create a PR that removes the option there)
- [x] Set the interval to 1 week again (right now, it's 1 minute for
testing)
- [ ] Write something for people who are interested in what exactly we
count, and link to it (see `TODO[blog post]` in the code)
- [ ] Prepare a short survey for participants
- [ ] Fine-tune the texts at
https://github.com/deltachat/deltachat-android/pull/3794, and get it
reviewed and merged
- [ ] After the next release, ask people to enable the
statistics-sending
This commit is contained in:
Hocuri
2025-10-21 15:29:21 +02:00
committed by GitHub
parent 347938a9f9
commit 51b9e86d71
17 changed files with 1747 additions and 180 deletions

View File

@@ -14,7 +14,6 @@ use tokio::fs;
use crate::blob::BlobObject;
use crate::configure::EnteredLoginParam;
use crate::constants;
use crate::context::Context;
use crate::events::EventType;
use crate::log::{LogExt, info};
@@ -23,6 +22,7 @@ use crate::mimefactory::RECOMMENDED_FILE_SIZE;
use crate::provider::{Provider, get_provider_by_id};
use crate::sync::{self, Sync::*, SyncData};
use crate::tools::get_abs_path;
use crate::{constants, stats};
/// The available configuration keys.
#[derive(
@@ -408,9 +408,22 @@ pub enum Config {
/// used for signatures, encryption to self and included in `Autocrypt` header.
KeyId,
/// This key is sent to the self_reporting bot so that the bot can recognize the user
/// Send statistics to Delta Chat's developers.
/// Can be exposed to the user as a setting.
StatsSending,
/// Last time statistics were sent to Delta Chat's developers
StatsLastSent,
/// Last time `update_message_stats()` was called
StatsLastUpdate,
/// This key is sent to the statistics bot so that the bot can recognize the user
/// without storing the email address
SelfReportingId,
StatsId,
/// The last contact id that already existed when statistics-sending was enabled for the first time.
StatsLastOldContactId,
/// MsgId of webxdc map integration.
WebxdcIntegration,
@@ -576,8 +589,9 @@ impl Context {
/// Returns boolean configuration value for the given key.
pub async fn get_config_bool(&self, key: Config) -> Result<bool> {
Ok(self
.get_config_parsed::<i32>(key)
.get_config(key)
.await?
.and_then(|s| s.parse::<i32>().ok())
.map(|x| x != 0)
.unwrap_or_default())
}
@@ -716,10 +730,19 @@ impl Context {
true => self.scheduler.pause(self).await?,
_ => Default::default(),
};
if key == Config::StatsSending {
let old_value = self.get_config(key).await?;
let old_value = bool_from_config(old_value.as_deref());
let new_value = bool_from_config(value);
stats::pre_sending_config_change(self, old_value, new_value).await?;
}
self.set_config_internal(key, value).await?;
if key == Config::SentboxWatch {
self.last_full_folder_scan.lock().await.take();
}
if key == Config::StatsSending {
stats::maybe_send_stats(self).await?;
}
Ok(())
}
@@ -871,6 +894,10 @@ pub(crate) fn from_bool(val: bool) -> Option<&'static str> {
Some(if val { "1" } else { "0" })
}
pub(crate) fn bool_from_config(config: Option<&str>) -> bool {
config.is_some_and(|v| v.parse::<i32>().unwrap_or_default() != 0)
}
// Separate impl block for self address handling
impl Context {
/// Determine whether the specified addr maps to the/a self addr.