diff --git a/Cargo.lock b/Cargo.lock index ba85eb1486..4c3a4e8592 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1474,7 +1474,6 @@ dependencies = [ "env_logger", "envy", "file_finder", - "form-data-builder", "fs", "futures 0.3.28", "git", @@ -2691,16 +2690,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "form-data-builder" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ff8fb4527b05539a9f573ba2831a1127038a7b45eea385a338a63dc5ab6829" -dependencies = [ - "base64 0.13.1", - "rand 0.8.5", -] - [[package]] name = "form_urlencoded" version = "1.2.0" diff --git a/Procfile b/Procfile index 122ad5139f..3f42c3a967 100644 --- a/Procfile +++ b/Procfile @@ -1,3 +1,4 @@ +web: cd ../zed.dev && PORT=3000 npm run dev collab: cd crates/collab && RUST_LOG=${RUST_LOG:-warn,collab=info} cargo run serve livekit: livekit-server --dev postgrest: postgrest crates/collab/admin_api.conf diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index da695f6dc4..1894023084 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -969,16 +969,6 @@ impl Client { Url::parse(&collab_url).context("invalid rpc url") } - // todo: this should probably be cached (And/or done better) - pub async fn get_collab_server_url( - http: Arc, - release_channel: Option, - ) -> Result { - let mut url = Self::get_rpc_url(http, release_channel).await?; - url.set_path(""); - Ok(url) - } - fn establish_websocket_connection( self: &Arc, credentials: &Credentials, diff --git a/crates/collab/.env.toml b/crates/collab/.env.toml index 46140ae9b3..01866012ea 100644 --- a/crates/collab/.env.toml +++ b/crates/collab/.env.toml @@ -2,14 +2,11 @@ DATABASE_URL = "postgres://postgres@localhost/zed" DATABASE_MAX_CONNECTIONS = 5 HTTP_PORT = 8080 API_TOKEN = "secret" -CLIENT_TOKEN = "618033988749894" INVITE_LINK_PREFIX = "http://localhost:3000/invites/" ZED_ENVIRONMENT = "development" LIVE_KIT_SERVER = "http://localhost:7880" LIVE_KIT_KEY = "devkey" LIVE_KIT_SECRET = "secret" -# SLACK_PANIC_CHANNEL = -# SLACK_API_KEY = # RUST_LOG=info # LOG_JSON=true diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index f703c88bc0..bc273cb12a 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -58,7 +58,6 @@ tracing = "0.1.34" tracing-log = "0.1.3" tracing-subscriber = { version = "0.3.11", features = ["env-filter", "json"] } uuid.workspace = true -form-data-builder = "1.0.1" [dev-dependencies] audio = { path = "../audio" } diff --git a/crates/collab/k8s/collab.template.yml b/crates/collab/k8s/collab.template.yml index eb9f4d9172..120e5f592f 100644 --- a/crates/collab/k8s/collab.template.yml +++ b/crates/collab/k8s/collab.template.yml @@ -90,11 +90,6 @@ spec: secretKeyRef: name: api key: token - - name: CLIENT_TOKEN - valueFrom: - secretKeyRef: - name: api - key: client_token - name: LIVE_KIT_SERVER valueFrom: secretKeyRef: @@ -110,16 +105,6 @@ spec: secretKeyRef: name: livekit key: secret - - name: SLACK_PANIC_CHANNEL - valueFrom: - secretKeyRef: - name: slack - key: api_key - - name: SLACK_API_KEY - valueFrom: - secretKeyRef: - name: slack - key: panic_channel - name: INVITE_LINK_PREFIX value: ${INVITE_LINK_PREFIX} - name: RUST_BACKTRACE diff --git a/crates/collab/src/api.rs b/crates/collab/src/api.rs index daca13fa85..a28aeac9ab 100644 --- a/crates/collab/src/api.rs +++ b/crates/collab/src/api.rs @@ -18,28 +18,19 @@ use serde::{Deserialize, Serialize}; use std::sync::Arc; use tower::ServiceBuilder; use tracing::instrument; -use util::{async_maybe, http::AsyncBody, ResultExt}; pub fn routes(rpc_server: Arc, state: Arc) -> Router { - let called_from_website = Router::new() + Router::new() .route("/user", get(get_authenticated_user)) .route("/users/:id/access_tokens", post(create_access_token)) .route("/panic", post(trace_panic)) .route("/rpc_server_snapshot", get(get_rpc_server_snapshot)) .layer( ServiceBuilder::new() - .layer(Extension(state.clone())) + .layer(Extension(state)) .layer(Extension(rpc_server)) .layer(middleware::from_fn(validate_api_token)), - ); - - let called_from_client = Router::new().route("/crash", post(trace_crash)).layer( - ServiceBuilder::new() - .layer(Extension(state)) - .layer(middleware::from_fn(validate_client_secret)), - ); - - called_from_website.merge(called_from_client) + ) } pub async fn validate_api_token(req: Request, next: Next) -> impl IntoResponse { @@ -73,37 +64,6 @@ pub async fn validate_api_token(req: Request, next: Next) -> impl IntoR Ok::<_, Error>(next.run(req).await) } -pub async fn validate_client_secret(req: Request, next: Next) -> impl IntoResponse { - let token = req - .headers() - .get(http::header::AUTHORIZATION) - .and_then(|header| header.to_str().ok()) - .ok_or_else(|| { - Error::Http( - StatusCode::BAD_REQUEST, - "missing authorization header".to_string(), - ) - })? - .strip_prefix("token ") - .ok_or_else(|| { - Error::Http( - StatusCode::BAD_REQUEST, - "invalid authorization header".to_string(), - ) - })?; - - let state = req.extensions().get::>().unwrap(); - - if token != state.config.client_token { - Err(Error::Http( - StatusCode::UNAUTHORIZED, - "invalid client secret".to_string(), - ))? - } - - Ok::<_, Error>(next.run(req).await) -} - #[derive(Debug, Deserialize)] struct AuthenticatedUserParams { github_user_id: Option, @@ -167,87 +127,6 @@ async fn trace_panic(panic: Json) -> Result<()> { Ok(()) } -/// IPSHeader is the first line of an .ips file (in JSON format) -/// https://developer.apple.com/documentation/xcode/interpreting-the-json-format-of-a-crash-report -#[derive(Debug, Serialize, Deserialize)] -struct IPSHeader { - timestamp: Option, - name: Option, - app_name: Option, - app_version: Option, - slice_uuid: Option, - build_version: Option, - platform: Option, - #[serde(rename = "bundleID")] - bundle_id: Option, - share_with_app_devs: Option, - is_first_party: Option, - bug_type: Option, - os_version: Option, - roots_installed: Option, - incident_id: Option, -} - -#[instrument(skip(content, app))] -async fn trace_crash(content: String, Extension(app): Extension>) -> Result<()> { - let Some(header) = content.split("\n").next() else { - return Err(Error::Http( - StatusCode::BAD_REQUEST, - "invalid .ips file".to_string(), - )); - }; - let header: IPSHeader = serde_json::from_slice(&header.as_bytes())?; - let text = content.as_str(); - - tracing::error!(app_version = %header.app_version.clone().unwrap_or_default(), - build_version = %header.build_version.unwrap_or_default(), - os_version = %header.os_version.unwrap_or_default(), - bundle_id = %header.bundle_id.clone().unwrap_or_default(), - text = %text, - "crash report"); - - async_maybe!({ - let api_key = app.config.slack_api_key.clone()?; - let channel = app.config.slack_panic_channel.clone()?; - - let mut body = form_data_builder::FormData::new(Vec::new()); - body.write_field("content", text).log_err()?; - body.write_field("channels", channel.as_str()).log_err()?; - body.write_field( - "filename", - format!("zed-crash-{}.ips", header.incident_id.unwrap_or_default()).as_str(), - ) - .log_err()?; - body.write_field( - "initial_comment", - format!( - "New crash in {} ({})", - header.bundle_id.unwrap_or_default(), - header.app_version.unwrap_or_default() - ) - .as_str(), - ) - .log_err()?; - let content_type = body.content_type_header(); - let body = AsyncBody::from(body.finish().log_err()?); - - let request = Request::post("https://slack.com/api/files.upload") - .header("Content-Type", content_type) - .header("Authorization", format!("Bearer {}", api_key)) - .body(body) - .log_err()?; - - let response = util::http::client().send(request).await.log_err()?; - if !response.status().is_success() { - tracing::error!(response = ?response, "failed to send crash report to slack"); - } - - Some(()) - }) - .await; - Ok(()) -} - async fn get_rpc_server_snapshot( Extension(rpc_server): Extension>, ) -> Result { diff --git a/crates/collab/src/lib.rs b/crates/collab/src/lib.rs index bf4270512e..aba9bd75d1 100644 --- a/crates/collab/src/lib.rs +++ b/crates/collab/src/lib.rs @@ -101,9 +101,6 @@ pub struct Config { pub rust_log: Option, pub log_json: Option, pub zed_environment: Arc, - pub slack_api_key: Option, - pub slack_panic_channel: Option, - pub client_token: String, } impl Config { diff --git a/crates/collab/src/tests/test_server.rs b/crates/collab/src/tests/test_server.rs index d6ea536dd1..cda0621cb3 100644 --- a/crates/collab/src/tests/test_server.rs +++ b/crates/collab/src/tests/test_server.rs @@ -465,7 +465,6 @@ impl TestServer { database_url: "".into(), database_max_connections: 0, api_token: "".into(), - client_token: "".into(), invite_link_prefix: "".into(), live_kit_server: None, live_kit_key: None, @@ -473,8 +472,6 @@ impl TestServer { rust_log: None, log_json: None, zed_environment: "test".into(), - slack_api_key: None, - slack_panic_channel: None, }, }) } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 6924b955f8..f67ba6cddb 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -710,12 +710,10 @@ async fn upload_previous_crashes( } let last_uploaded = KEY_VALUE_STORE .read_kvp(LAST_CRASH_UPLOADED)? - .unwrap_or("zed-2024-01-17-000000.ips".to_string()); // don't upload old crash reports from before we had this. + .unwrap_or("zed-2024-01-17-221900.ips".to_string()); // don't upload old crash reports from before we had this. let mut uploaded = last_uploaded.clone(); - let mut crash_report_url = - client::Client::get_collab_server_url(http.clone(), Some(release_channel)).await?; - crash_report_url.set_path("/crash"); + let crash_report_url = format!("{}/api/crash", &*client::ZED_SERVER_URL); for dir in [&*CRASHES_DIR, &*CRASHES_RETIRED_DIR] { let mut children = smol::fs::read_dir(&dir).await?; @@ -741,7 +739,7 @@ async fn upload_previous_crashes( .await .context("error reading crash file")?; - let request = Request::post(&crash_report_url.to_string()) + let request = Request::post(&crash_report_url) .redirect_policy(isahc::config::RedirectPolicy::Follow) .header("Content-Type", "text/plain") .header(