@@ -7,14 +7,13 @@ pub mod telemetry;
pub mod user;
pub mod zed_urls;
-use anyhow::{Context as _, Result, anyhow, bail};
+use anyhow::{Context as _, Result, anyhow};
use async_recursion::async_recursion;
use async_tungstenite::tungstenite::{
client::IntoClientRequest,
error::Error as WebsocketError,
http::{HeaderValue, Request, StatusCode},
};
-use chrono::{DateTime, Utc};
use clock::SystemClock;
use cloud_api_client::CloudApiClient;
use credentials_provider::CredentialsProvider;
@@ -23,7 +22,7 @@ use futures::{
channel::oneshot, future::BoxFuture,
};
use gpui::{App, AsyncApp, Entity, Global, Task, WeakEntity, actions};
-use http_client::{AsyncBody, HttpClient, HttpClientWithUrl, http};
+use http_client::{HttpClient, HttpClientWithUrl, http};
use parking_lot::RwLock;
use postage::watch;
use proxy::connect_proxy_stream;
@@ -1379,96 +1378,31 @@ impl Client {
self: &Arc<Self>,
http: Arc<HttpClientWithUrl>,
login: String,
- mut api_token: String,
+ api_token: String,
) -> Result<Credentials> {
- #[derive(Deserialize)]
- struct AuthenticatedUserResponse {
- user: User,
+ #[derive(Serialize)]
+ struct ImpersonateUserBody {
+ github_login: String,
}
#[derive(Deserialize)]
- struct User {
- id: u64,
+ struct ImpersonateUserResponse {
+ user_id: u64,
+ access_token: String,
}
- let github_user = {
- #[derive(Deserialize)]
- struct GithubUser {
- id: i32,
- login: String,
- created_at: DateTime<Utc>,
- }
-
- let request = {
- let mut request_builder =
- Request::get(&format!("https://api.github.com/users/{login}"));
- if let Ok(github_token) = std::env::var("GITHUB_TOKEN") {
- request_builder =
- request_builder.header("Authorization", format!("Bearer {}", github_token));
- }
-
- request_builder.body(AsyncBody::empty())?
- };
-
- let mut response = http
- .send(request)
- .await
- .context("error fetching GitHub user")?;
-
- let mut body = Vec::new();
- response
- .body_mut()
- .read_to_end(&mut body)
- .await
- .context("error reading GitHub user")?;
-
- if !response.status().is_success() {
- let text = String::from_utf8_lossy(body.as_slice());
- bail!(
- "status error {}, response: {text:?}",
- response.status().as_u16()
- );
- }
-
- serde_json::from_slice::<GithubUser>(body.as_slice()).map_err(|err| {
- log::error!("Error deserializing: {:?}", err);
- log::error!(
- "GitHub API response text: {:?}",
- String::from_utf8_lossy(body.as_slice())
- );
- anyhow!("error deserializing GitHub user")
- })?
- };
-
- let query_params = [
- ("github_login", &github_user.login),
- ("github_user_id", &github_user.id.to_string()),
- (
- "github_user_created_at",
- &github_user.created_at.to_rfc3339(),
- ),
- ];
-
- // Use the collab server's admin API to retrieve the ID
- // of the impersonated user.
- let mut url = self.rpc_url(http.clone(), None).await?;
- url.set_path("/user");
- url.set_query(Some(
- &query_params
- .iter()
- .map(|(key, value)| {
- format!(
- "{}={}",
- key,
- url::form_urlencoded::byte_serialize(value.as_bytes()).collect::<String>()
- )
- })
- .collect::<Vec<String>>()
- .join("&"),
- ));
- let request: http_client::Request<AsyncBody> = Request::get(url.as_str())
- .header("Authorization", format!("token {api_token}"))
- .body("".into())?;
+ let url = self
+ .http
+ .build_zed_cloud_url("/internal/users/impersonate", &[])?;
+ let request = Request::post(url.as_str())
+ .header("Content-Type", "application/json")
+ .header("Authorization", format!("Bearer {api_token}"))
+ .body(
+ serde_json::to_string(&ImpersonateUserBody {
+ github_login: login,
+ })?
+ .into(),
+ )?;
let mut response = http.send(request).await?;
let mut body = String::new();
@@ -1479,13 +1413,11 @@ impl Client {
response.status().as_u16(),
body,
);
- let response: AuthenticatedUserResponse = serde_json::from_str(&body)?;
+ let response: ImpersonateUserResponse = serde_json::from_str(&body)?;
- // Use the admin API token to authenticate as the impersonated user.
- api_token.insert_str(0, "ADMIN_TOKEN:");
Ok(Credentials {
- user_id: response.user.id,
- access_token: api_token,
+ user_id: response.user_id,
+ access_token: response.access_token,
})
}
@@ -100,7 +100,6 @@ impl std::fmt::Display for SystemIdHeader {
pub fn routes(rpc_server: Arc<rpc::Server>) -> Router<(), Body> {
Router::new()
- .route("/user", get(legacy_update_or_create_authenticated_user))
.route("/users/look_up", get(look_up_user))
.route("/users/:id/access_tokens", post(create_access_token))
.route("/users/:id/refresh_llm_tokens", post(refresh_llm_tokens))
@@ -145,51 +144,6 @@ pub async fn validate_api_token<B>(req: Request<B>, next: Next<B>) -> impl IntoR
Ok::<_, Error>(next.run(req).await)
}
-#[derive(Debug, Deserialize)]
-struct AuthenticatedUserParams {
- github_user_id: i32,
- github_login: String,
- github_email: Option<String>,
- github_name: Option<String>,
- github_user_created_at: chrono::DateTime<chrono::Utc>,
-}
-
-#[derive(Debug, Serialize)]
-struct AuthenticatedUserResponse {
- user: User,
- metrics_id: String,
- feature_flags: Vec<String>,
-}
-
-/// This is a legacy endpoint that is no longer used in production.
-///
-/// It currently only exists to be used when developing Collab locally.
-async fn legacy_update_or_create_authenticated_user(
- Query(params): Query<AuthenticatedUserParams>,
- Extension(app): Extension<Arc<AppState>>,
-) -> Result<Json<AuthenticatedUserResponse>> {
- let initial_channel_id = app.config.auto_join_channel_id;
-
- let user = app
- .db
- .update_or_create_user_by_github_account(
- ¶ms.github_login,
- params.github_user_id,
- params.github_email.as_deref(),
- params.github_name.as_deref(),
- params.github_user_created_at,
- initial_channel_id,
- )
- .await?;
- let metrics_id = app.db.get_user_metrics_id(user.id).await?;
- let feature_flags = app.db.get_user_flags(user.id).await?;
- Ok(Json(AuthenticatedUserResponse {
- user,
- metrics_id,
- feature_flags,
- }))
-}
-
#[derive(Debug, Deserialize)]
struct LookUpUserParams {
identifier: String,
@@ -213,7 +213,7 @@ setTimeout(() => {
platform === "win32"
? "http://127.0.0.1:8080/rpc"
: "http://localhost:8080/rpc",
- ZED_ADMIN_API_TOKEN: "secret",
+ ZED_ADMIN_API_TOKEN: "internal-api-key-secret",
ZED_WINDOW_SIZE: size,
ZED_CLIENT_CHECKSUM_SEED: "development-checksum-seed",
RUST_LOG: process.env.RUST_LOG || "info",