Fix impersonation in local development (#16755)

This PR fixes impersonation in local development by fetching the user
from the GitHub API so we can get their `github_user_id`.

The `github_user_id` is now required after #16704.

Since this is just a development flow, we're fetching the user on the
client as opposed to making changes on the server.

This request uses the `GITHUB_TOKEN` environment variable for
authentication, if it exists, or will make an unauthenticated GitHub API
request.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-08-23 10:49:34 -04:00 committed by GitHub
parent 5e869dadf9
commit 935cf542ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -5,7 +5,7 @@ mod socks;
pub mod telemetry;
pub mod user;
use anyhow::{anyhow, Context as _, Result};
use anyhow::{anyhow, bail, Context as _, Result};
use async_recursion::async_recursion;
use async_tungstenite::tungstenite::{
client::IntoClientRequest,
@ -1395,11 +1395,64 @@ impl Client {
id: u64,
}
let github_user = {
#[derive(Deserialize)]
struct GithubUser {
id: i32,
login: String,
}
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()
);
}
let user = 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")
})?;
user
};
// 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(&format!("github_login={login}")));
url.set_query(Some(&format!(
"github_login={}&github_user_id={}",
github_user.login, github_user.id
)));
let request: http_client::Request<AsyncBody> = Request::get(url.as_str())
.header("Authorization", format!("token {api_token}"))
.body("".into())?;