diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bbaa12ecdd..9d8cf6522e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,6 +81,7 @@ jobs: MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }} APPLE_NOTARIZATION_USERNAME: ${{ secrets.APPLE_NOTARIZATION_USERNAME }} APPLE_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }} + ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }} steps: - name: Install Node uses: actions/setup-node@v3 diff --git a/Cargo.lock b/Cargo.lock index 564da956df..ddb47a656a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1367,6 +1367,7 @@ dependencies = [ "image", "lazy_static", "log", + "once_cell", "parking_lot 0.11.2", "postage", "rand 0.8.5", @@ -1377,6 +1378,7 @@ dependencies = [ "serde_derive", "serde_json", "settings", + "sha2 0.10.7", "smol", "sum_tree", "sysinfo", diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index 37d617821e..9bf04caa71 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -32,6 +32,7 @@ futures.workspace = true image = "0.23" lazy_static.workspace = true log.workspace = true +once_cell = "1.19.0" parking_lot.workspace = true postage.workspace = true rand.workspace = true @@ -39,6 +40,7 @@ schemars.workspace = true serde.workspace = true serde_derive.workspace = true serde_json.workspace = true +sha2 = "0.10" smol.workspace = true sysinfo.workspace = true tempfile.workspace = true diff --git a/crates/client/src/telemetry.rs b/crates/client/src/telemetry.rs index 1a8627f286..331683d5d1 100644 --- a/crates/client/src/telemetry.rs +++ b/crates/client/src/telemetry.rs @@ -4,16 +4,19 @@ use crate::TelemetrySettings; use chrono::{DateTime, Utc}; use futures::Future; use gpui::{AppContext, AppMetadata, BackgroundExecutor, Task}; +use once_cell::sync::Lazy; use parking_lot::Mutex; use release_channel::ReleaseChannel; use serde::Serialize; use settings::{Settings, SettingsStore}; -use std::{env, io::Write, mem, path::PathBuf, sync::Arc, time::Duration}; +use sha2::{Digest, Sha256}; +use std::io::Write; +use std::{env, mem, path::PathBuf, sync::Arc, time::Duration}; use sysinfo::{ CpuRefreshKind, Pid, PidExt, ProcessExt, ProcessRefreshKind, RefreshKind, System, SystemExt, }; use tempfile::NamedTempFile; -use util::http::{HttpClient, ZedHttpClient}; +use util::http::{self, HttpClient, Method, ZedHttpClient}; #[cfg(not(debug_assertions))] use util::ResultExt; use util::TryFutureExt; @@ -142,6 +145,13 @@ const FLUSH_INTERVAL: Duration = Duration::from_secs(1); #[cfg(not(debug_assertions))] const FLUSH_INTERVAL: Duration = Duration::from_secs(60 * 5); +static ZED_CLIENT_CHECKSUM_SEED: Lazy> = Lazy::new(|| { + option_env!("ZED_CLIENT_CHECKSUM_SEED") + .unwrap_or("development-checksum-seed") + .as_bytes() + .into() +}); + impl Telemetry { pub fn new(client: Arc, cx: &mut AppContext) -> Arc { let release_channel = @@ -540,9 +550,27 @@ impl Telemetry { serde_json::to_writer(&mut json_bytes, &request_body)?; } - this.http_client - .post_json(&this.http_client.zed_url("/api/events"), json_bytes.into()) - .await?; + let mut summer = Sha256::new(); + summer.update(&*ZED_CLIENT_CHECKSUM_SEED); + summer.update(&json_bytes); + summer.update(&*ZED_CLIENT_CHECKSUM_SEED); + let mut checksum = String::new(); + for byte in summer.finalize().as_slice() { + use std::fmt::Write; + write!(&mut checksum, "{:02x}", byte).unwrap(); + } + + let request = http::Request::builder() + .method(Method::POST) + .uri(&this.http_client.zed_url("/api/events")) + .header("Content-Type", "text/plain") + .header("x-zed-checksum", checksum) + .body(json_bytes.into()); + + let response = this.http_client.send(request?).await?; + if response.status() != 200 { + log::error!("Failed to send events: HTTP {:?}", response.status()); + } anyhow::Ok(()) } .log_err(),