refactor: separate from_interactive_url to pub fn
This commit is contained in:
parent
0057ae3be2
commit
d29e842035
59
src/auth.rs
59
src/auth.rs
|
@ -17,19 +17,15 @@ pub struct AccessToken(pub String);
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, FromStr, Display)]
|
#[derive(Debug, Clone, Serialize, Deserialize, FromStr, Display)]
|
||||||
pub struct RefreshToken(pub String);
|
pub struct RefreshToken(pub String);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Credentials {
|
|
||||||
pub access_token: AccessToken,
|
|
||||||
pub refresh_token: Option<RefreshToken>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Callback {
|
struct Callback {
|
||||||
code: String,
|
code: String,
|
||||||
state: String,
|
state: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Api {
|
impl Api {
|
||||||
/// Currently the only way to "authenticate" to an access token for this library.
|
/// Show a URL for the user to click on to log into tesla.com, the ask them to paste the
|
||||||
|
/// URL they end up on, which is a 404 page. The URL contains OAuth information needed to
|
||||||
|
/// complete authentication for an access key.
|
||||||
pub async fn from_interactive_url() -> Result<Api, TeslatteError> {
|
pub async fn from_interactive_url() -> Result<Api, TeslatteError> {
|
||||||
let login_form = Self::get_login_url_for_user().await;
|
let login_form = Self::get_login_url_for_user().await;
|
||||||
println!("{}", "-".repeat(80));
|
println!("{}", "-".repeat(80));
|
||||||
|
@ -44,10 +40,29 @@ page, where the URL will start with https://auth.tesla.com/void/callback?code=..
|
||||||
let callback_url = ask_input("Enter the whole URL of the 404 page: ");
|
let callback_url = ask_input("Enter the whole URL of the 404 page: ");
|
||||||
println!(); // Newline to make the next output more separated and clear.
|
println!(); // Newline to make the next output more separated and clear.
|
||||||
|
|
||||||
let callback = Self::extract_callback_from_url(&callback_url)?;
|
Api::from_callback_url(&login_form, &callback_url).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a [LoginForm] containing a URL the user should visit.
|
||||||
|
///
|
||||||
|
/// See [Api::from_callback_url()] for the next step.
|
||||||
|
pub async fn get_login_url_for_user() -> LoginForm {
|
||||||
|
let code = Code::new();
|
||||||
|
let state = random_string(8);
|
||||||
|
let url = Self::login_url(&code, &state);
|
||||||
|
LoginForm { url, code, state }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse a callback URL that the user was redirected to after logging in via
|
||||||
|
/// [Api::from_interactive_url()].
|
||||||
|
pub async fn from_callback_url(
|
||||||
|
login_form: &LoginForm,
|
||||||
|
callback_url: &str,
|
||||||
|
) -> Result<Api, TeslatteError> {
|
||||||
|
let callback = Self::extract_callback_from_url(callback_url)?;
|
||||||
if callback.state != login_form.state {
|
if callback.state != login_form.state {
|
||||||
return Err(TeslatteError::StateMismatch {
|
return Err(TeslatteError::StateMismatch {
|
||||||
request: login_form.state,
|
request: login_form.state.clone(),
|
||||||
callback: callback.state,
|
callback: callback.state,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -66,24 +81,6 @@ page, where the URL will start with https://auth.tesla.com/void/callback?code=..
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_credentials(credentials: Credentials) -> Api {
|
|
||||||
Api::new(credentials.access_token, credentials.refresh_token)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn credentials(&self) -> Credentials {
|
|
||||||
Credentials {
|
|
||||||
access_token: self.access_token.clone(),
|
|
||||||
refresh_token: self.refresh_token.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_login_url_for_user() -> LoginForm {
|
|
||||||
let code = Code::new();
|
|
||||||
let state = random_string(8);
|
|
||||||
let url = Self::login_url(&code, &state);
|
|
||||||
LoginForm { url, code, state }
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn exchange_auth_for_bearer(
|
async fn exchange_auth_for_bearer(
|
||||||
code: &Code,
|
code: &Code,
|
||||||
callback_code: &str,
|
callback_code: &str,
|
||||||
|
@ -214,9 +211,9 @@ pub struct RefreshTokenResponse {
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct LoginForm {
|
pub struct LoginForm {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
url: String,
|
pub url: String,
|
||||||
code: Code,
|
pub code: Code,
|
||||||
state: String,
|
pub state: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
|
@ -276,7 +273,7 @@ fn random_string(len: usize) -> String {
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ask_input(prompt: &str) -> String {
|
pub fn ask_input(prompt: &str) -> String {
|
||||||
print!("{}", prompt);
|
print!("{}", prompt);
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
stdout()
|
stdout()
|
||||||
|
|
|
@ -51,7 +51,6 @@ impl Display for RequestData<'_> {
|
||||||
|
|
||||||
pub struct Api {
|
pub struct Api {
|
||||||
pub access_token: AccessToken,
|
pub access_token: AccessToken,
|
||||||
// TODO: Why is this an Option?
|
|
||||||
pub refresh_token: Option<RefreshToken>,
|
pub refresh_token: Option<RefreshToken>,
|
||||||
client: Client,
|
client: Client,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue