mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 13:00:58 +00:00
cli: print oauth errors better, respect slow_down (#169164)
For diagnosing https://github.com/microsoft/vscode/issues/169066
This commit is contained in:
parent
391acf8149
commit
82b239204c
|
@ -9,7 +9,9 @@ use crate::{
|
|||
state::{LauncherPaths, PersistedState},
|
||||
trace,
|
||||
util::{
|
||||
errors::{wrap, AnyError, RefreshTokenNotAvailableError, StatusError, WrappedError},
|
||||
errors::{
|
||||
wrap, AnyError, OAuthError, RefreshTokenNotAvailableError, StatusError, WrappedError,
|
||||
},
|
||||
input::prompt_options,
|
||||
},
|
||||
warning,
|
||||
|
@ -41,6 +43,12 @@ struct AuthenticationResponse {
|
|||
expires_in: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct AuthenticationError {
|
||||
error: String,
|
||||
error_description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(clap::ArgEnum, Serialize, Deserialize, Debug, Clone, Copy)]
|
||||
pub enum AuthProvider {
|
||||
Microsoft,
|
||||
|
@ -480,12 +488,26 @@ impl Auth {
|
|||
.send()
|
||||
.await?;
|
||||
|
||||
if !response.status().is_success() {
|
||||
return Err(StatusError::from_res(response).await?.into());
|
||||
let status_code = response.status().as_u16();
|
||||
let body = response.bytes().await?;
|
||||
if let Ok(body) = serde_json::from_slice::<AuthenticationResponse>(&body) {
|
||||
return Ok(StoredCredential::from_response(body, provider));
|
||||
}
|
||||
|
||||
let body = response.json::<AuthenticationResponse>().await?;
|
||||
Ok(StoredCredential::from_response(body, provider))
|
||||
if let Ok(res) = serde_json::from_slice::<AuthenticationError>(&body) {
|
||||
return Err(OAuthError {
|
||||
error: res.error,
|
||||
error_description: res.error_description,
|
||||
}
|
||||
.into());
|
||||
}
|
||||
|
||||
return Err(StatusError {
|
||||
body: String::from_utf8_lossy(&body).to_string(),
|
||||
status_code,
|
||||
url: provider.grant_uri().to_string(),
|
||||
}
|
||||
.into());
|
||||
}
|
||||
|
||||
/// Implements the device code flow, returning the credentials upon success.
|
||||
|
@ -540,16 +562,21 @@ impl Auth {
|
|||
};
|
||||
|
||||
let body = format!(
|
||||
"client_id={}&grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code={}",
|
||||
provider.client_id(),
|
||||
init_code_json.device_code
|
||||
);
|
||||
"client_id={}&grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code={}",
|
||||
provider.client_id(),
|
||||
init_code_json.device_code
|
||||
);
|
||||
|
||||
let mut interval_s = 5;
|
||||
while Utc::now() < expires_at {
|
||||
sleep(std::time::Duration::from_secs(5)).await;
|
||||
sleep(std::time::Duration::from_secs(interval_s)).await;
|
||||
|
||||
match self.do_grant(provider, body.clone()).await {
|
||||
Ok(creds) => return Ok(creds),
|
||||
Err(AnyError::OAuthError(e)) if e.error == "slow_down" => {
|
||||
interval_s += 5; // https://www.rfc-editor.org/rfc/rfc8628#section-3.5
|
||||
trace!(self.log, "refresh poll failed, slowing down");
|
||||
}
|
||||
Err(e) => {
|
||||
trace!(self.log, "refresh poll failed, retrying: {}", e);
|
||||
}
|
||||
|
|
|
@ -401,6 +401,23 @@ impl std::fmt::Display for MissingHomeDirectory {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OAuthError {
|
||||
pub error: String,
|
||||
pub error_description: Option<String>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for OAuthError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Error getting authorization: {} {}",
|
||||
self.error,
|
||||
self.error_description.as_deref().unwrap_or("")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CommandFailed {
|
||||
pub output: std::process::Output,
|
||||
|
@ -487,7 +504,8 @@ makeAnyError!(
|
|||
UpdatesNotConfigured,
|
||||
CorruptDownload,
|
||||
MissingHomeDirectory,
|
||||
CommandFailed
|
||||
CommandFailed,
|
||||
OAuthError
|
||||
);
|
||||
|
||||
impl From<reqwest::Error> for AnyError {
|
||||
|
|
Loading…
Reference in a new issue