Skip to content

Commit 51bccd7

Browse files
committed
Make self reporting into a setting
1 parent aad8f69 commit 51bccd7

File tree

5 files changed

+76
-18
lines changed

5 files changed

+76
-18
lines changed

deltachat-jsonrpc/src/api.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,9 +375,10 @@ impl CommandApi {
375375
Ok(BlobObject::create_and_deduplicate(&ctx, file, file)?.to_abs_path())
376376
}
377377

378+
/// Deprecated 2025-04. Use the "self_reporting" config instead.
378379
async fn draft_self_report(&self, account_id: u32) -> Result<u32> {
379380
let ctx = self.get_context(account_id).await?;
380-
Ok(ctx.draft_self_report().await?.to_u32())
381+
Ok(ctx.send_self_report().await?.to_u32())
381382
}
382383

383384
/// Sets the given configuration key.

src/config.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,13 @@ pub enum Config {
428428
/// used for signatures, encryption to self and included in `Autocrypt` header.
429429
KeyId,
430430

431+
/// Send statistics to Delta Chat's developers.
432+
/// Can be exposed to the user as a setting.
433+
SelfReporting,
434+
435+
/// Last time statistics were sent to Delta Chat's developers
436+
LastSelfReportSent,
437+
431438
/// This key is sent to the self_reporting bot so that the bot can recognize the user
432439
/// without storing the email address
433440
SelfReportingId,

src/context.rs

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,33 @@ use std::sync::atomic::{AtomicBool, Ordering};
88
use std::sync::{Arc, OnceLock};
99
use std::time::Duration;
1010

11-
use anyhow::{Context as _, Result, bail, ensure};
11+
use anyhow::{bail, ensure, Context as _, Result};
1212
use async_channel::{self as channel, Receiver, Sender};
1313
use pgp::types::PublicKeyTrait;
1414
use ratelimit::Ratelimit;
1515
use tokio::sync::{Mutex, Notify, RwLock};
1616

17-
use crate::chat::{ChatId, ProtectionStatus, get_chat_cnt};
17+
use crate::chat::{get_chat_cnt, ChatId, ProtectionStatus};
1818
use crate::chatlist_events;
1919
use crate::config::Config;
2020
use crate::constants::{
2121
self, DC_BACKGROUND_FETCH_QUOTA_CHECK_RATELIMIT, DC_CHAT_ID_TRASH, DC_VERSION_STR,
2222
};
23-
use crate::contact::{Contact, ContactId, import_vcard, mark_contact_id_as_verified};
23+
use crate::contact::{import_vcard, mark_contact_id_as_verified, Contact, ContactId};
2424
use crate::debug_logging::DebugLogging;
2525
use crate::download::DownloadState;
2626
use crate::events::{Event, EventEmitter, EventType, Events};
2727
use crate::imap::{FolderMeaning, Imap, ServerMetadata};
28-
use crate::key::{load_self_secret_key, self_fingerprint};
28+
use crate::key::{load_self_public_key, load_self_secret_key, DcKey as _};
29+
use crate::log::LogExt;
2930
use crate::log::{info, warn};
3031
use crate::login_param::{ConfiguredLoginParam, EnteredLoginParam};
31-
use crate::message::{self, Message, MessageState, MsgId};
32+
use crate::message::{self, Message, MessageState, MsgId, Viewtype};
3233
use crate::param::{Param, Params};
3334
use crate::peer_channels::Iroh;
3435
use crate::push::PushSubscriber;
3536
use crate::quota::QuotaInfo;
36-
use crate::scheduler::{SchedulerState, convert_folder_meaning};
37+
use crate::scheduler::{convert_folder_meaning, SchedulerState};
3738
use crate::sql::Sql;
3839
use crate::stock_str::StockStrings;
3940
use crate::timesmearing::SmearedTimestamp;
@@ -1041,6 +1042,18 @@ impl Context {
10411042
.await?
10421043
.to_string(),
10431044
);
1045+
res.insert(
1046+
"self_reporting",
1047+
self.get_config_bool(Config::SelfReporting)
1048+
.await?
1049+
.to_string(),
1050+
);
1051+
res.insert(
1052+
"last_self_report_sent",
1053+
self.get_config_i64(Config::LastSelfReportSent)
1054+
.await?
1055+
.to_string(),
1056+
);
10441057

10451058
let elapsed = time_elapsed(&self.creation_time);
10461059
res.insert("uptime", duration_to_str(elapsed));
@@ -1160,7 +1173,8 @@ impl Context {
11601173
Some(id) => id,
11611174
None => {
11621175
let id = create_id();
1163-
self.set_config(Config::SelfReportingId, Some(&id)).await?;
1176+
self.set_config_internal(Config::SelfReportingId, Some(&id))
1177+
.await?;
11641178
id
11651179
}
11661180
};
@@ -1174,7 +1188,15 @@ impl Context {
11741188
///
11751189
/// On the other end, a bot will receive the message and make it available
11761190
/// to Delta Chat's developers.
1177-
pub async fn draft_self_report(&self) -> Result<ChatId> {
1191+
pub async fn send_self_report(&self) -> Result<ChatId> {
1192+
info!(self, "Sending self report.");
1193+
// Setting `Config::LastHousekeeping` at the beginning avoids endless loops when things do not
1194+
// work out for whatever reason or are interrupted by the OS.
1195+
self.set_config_internal(Config::LastSelfReportSent, Some(&time().to_string()))
1196+
.await
1197+
.log_err(self)
1198+
.ok();
1199+
11781200
const SELF_REPORTING_BOT_VCARD: &str = include_str!("../assets/self-reporting-bot.vcf");
11791201
let contact_id: ContactId = *import_vcard(self, SELF_REPORTING_BOT_VCARD)
11801202
.await?
@@ -1187,9 +1209,26 @@ impl Context {
11871209
.set_protection(self, ProtectionStatus::Protected, time(), Some(contact_id))
11881210
.await?;
11891211

1190-
let mut msg = Message::new_text(self.get_self_report().await?);
1212+
let mut msg = Message::new(Viewtype::File);
1213+
msg.set_text(
1214+
"The attachment contains anonymous usage statistics, \
1215+
because you enabled this in the settings. \
1216+
This helps us improve the security of Delta Chat. \
1217+
See TODO[blog post] for more information."
1218+
.to_string(),
1219+
);
1220+
msg.set_file_from_bytes(
1221+
self,
1222+
"statistics.txt",
1223+
self.get_self_report().await?.as_bytes(),
1224+
Some("text/plain"),
1225+
)?;
11911226

1192-
chat_id.set_draft(self, Some(&mut msg)).await?;
1227+
crate::chat::send_msg(self, chat_id, &mut msg)
1228+
.await
1229+
.context("Failed to send self_reporting message")
1230+
.log_err(self)
1231+
.ok();
11931232

11941233
Ok(chat_id)
11951234
}

src/context/context_tests.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -602,18 +602,15 @@ async fn test_get_next_msgs() -> Result<()> {
602602
async fn test_draft_self_report() -> Result<()> {
603603
let alice = TestContext::new_alice().await;
604604

605-
let chat_id = alice.draft_self_report().await?;
606-
let msg = get_chat_msg(&alice, chat_id, 0, 1).await;
605+
let chat_id = alice.send_self_report().await?;
606+
let msg = get_chat_msg(&alice, chat_id, 0, 2).await;
607607
assert_eq!(msg.get_info_type(), SystemMessage::ChatProtectionEnabled);
608608

609609
let chat = Chat::load_from_db(&alice, chat_id).await?;
610610
assert!(chat.is_protected());
611611

612-
let mut draft = chat_id.get_draft(&alice).await?.unwrap();
613-
assert!(draft.text.starts_with("core_version"));
614-
615-
// Test that sending into the protected chat works:
616-
let _sent = alice.send_msg(chat_id, &mut draft).await;
612+
let statistics_msg = get_chat_msg(&alice, chat_id, 1, 2).await;
613+
assert_eq!(statistics_msg.get_filename().unwrap(), "statistics.txt");
617614

618615
Ok(())
619616
}

src/scheduler.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,20 @@ async fn inbox_fetch_idle(ctx: &Context, imap: &mut Imap, mut session: Session)
507507
}
508508
};
509509

510+
//#[cfg(target_os = "android")] TODO
511+
if ctx.get_config_bool(Config::SelfReporting).await? {
512+
match ctx.get_config_i64(Config::LastSelfReportSent).await {
513+
Ok(last_selfreport_time) => {
514+
let next_selfreport_time = last_selfreport_time.saturating_add(30); // TODO increase to 1 day or 1 week
515+
if next_selfreport_time <= time() {
516+
ctx.send_self_report().await?;
517+
}
518+
}
519+
Err(err) => {
520+
warn!(ctx, "Failed to get last self_reporting time: {}", err);
521+
}
522+
}
523+
}
510524
match ctx.get_config_bool(Config::FetchedExistingMsgs).await {
511525
Ok(fetched_existing_msgs) => {
512526
if !fetched_existing_msgs {

0 commit comments

Comments
 (0)