@@ -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())?;