diff --git a/examples/github.rs b/examples/github.rs index bbb3644..1c8a4f2 100644 --- a/examples/github.rs +++ b/examples/github.rs @@ -14,17 +14,17 @@ //! use oauth2::basic::BasicClient; - // Alternatively, this can be `oauth2::curl::http_client` or a custom client. use oauth2::reqwest::http_client; use oauth2::{ AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken, RedirectUrl, Scope, TokenResponse, TokenUrl, }; +use url::Url; + use std::env; use std::io::{BufRead, BufReader, Write}; use std::net::TcpListener; -use url::Url; fn main() { let github_client_id = ClientId::new( @@ -60,88 +60,73 @@ fn main() { .add_scope(Scope::new("user:email".to_string())) .url(); + println!("Open this URL in your browser:\n{authorize_url}\n"); + + let (code, state) = { + // A very naive implementation of the redirect server. + let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); + + // The server will terminate itself after collecting the first code. + let Some(mut stream) = listener.incoming().flatten().next() else { + panic!("listener terminated without accepting a connection"); + }; + + let mut reader = BufReader::new(&stream); + + let mut request_line = String::new(); + reader.read_line(&mut request_line).unwrap(); + + let redirect_url = request_line.split_whitespace().nth(1).unwrap(); + let url = Url::parse(&("http://localhost".to_string() + redirect_url)).unwrap(); + + let code = url + .query_pairs() + .find(|(key, _)| key == "code") + .map(|(_, code)| AuthorizationCode::new(code.into_owned())) + .unwrap(); + + let state = url + .query_pairs() + .find(|(key, _)| key == "state") + .map(|(_, state)| CsrfToken::new(state.into_owned())) + .unwrap(); + + let message = "Go back to your terminal :)"; + let response = format!( + "HTTP/1.1 200 OK\r\ncontent-length: {}\r\n\r\n{}", + message.len(), + message + ); + stream.write_all(response.as_bytes()).unwrap(); + + (code, state) + }; + + println!("Github returned the following code:\n{}\n", code.secret()); println!( - "Open this URL in your browser:\n{}\n", - authorize_url.to_string() + "Github returned the following state:\n{} (expected `{}`)\n", + state.secret(), + csrf_state.secret() ); - // A very naive implementation of the redirect server. - let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); - for stream in listener.incoming() { - if let Ok(mut stream) = stream { - let code; - let state; - { - let mut reader = BufReader::new(&stream); - - let mut request_line = String::new(); - reader.read_line(&mut request_line).unwrap(); - - let redirect_url = request_line.split_whitespace().nth(1).unwrap(); - let url = Url::parse(&("http://localhost".to_string() + redirect_url)).unwrap(); - - let code_pair = url - .query_pairs() - .find(|pair| { - let &(ref key, _) = pair; - key == "code" - }) - .unwrap(); - - let (_, value) = code_pair; - code = AuthorizationCode::new(value.into_owned()); - - let state_pair = url - .query_pairs() - .find(|pair| { - let &(ref key, _) = pair; - key == "state" - }) - .unwrap(); - - let (_, value) = state_pair; - state = CsrfToken::new(value.into_owned()); - } - - let message = "Go back to your terminal :)"; - let response = format!( - "HTTP/1.1 200 OK\r\ncontent-length: {}\r\n\r\n{}", - message.len(), - message - ); - stream.write_all(response.as_bytes()).unwrap(); - - println!("Github returned the following code:\n{}\n", code.secret()); - println!( - "Github returned the following state:\n{} (expected `{}`)\n", - state.secret(), - csrf_state.secret() - ); - - // Exchange the code with a token. - let token_res = client.exchange_code(code).request(http_client); - - println!("Github returned the following token:\n{:?}\n", token_res); - - if let Ok(token) = token_res { - // NB: Github returns a single comma-separated "scope" parameter instead of multiple - // space-separated scopes. Github-specific clients can parse this scope into - // multiple scopes by splitting at the commas. Note that it's not safe for the - // library to do this by default because RFC 6749 allows scopes to contain commas. - let scopes = if let Some(scopes_vec) = token.scopes() { - scopes_vec - .iter() - .map(|comma_separated| comma_separated.split(',')) - .flatten() - .collect::>() - } else { - Vec::new() - }; - println!("Github returned the following scopes:\n{:?}\n", scopes); - } - - // The server will terminate itself after collecting the first code. - break; - } + // Exchange the code with a token. + let token_res = client.exchange_code(code).request(http_client); + + println!("Github returned the following token:\n{:?}\n", token_res); + + if let Ok(token) = token_res { + // NB: Github returns a single comma-separated "scope" parameter instead of multiple + // space-separated scopes. Github-specific clients can parse this scope into + // multiple scopes by splitting at the commas. Note that it's not safe for the + // library to do this by default because RFC 6749 allows scopes to contain commas. + let scopes = if let Some(scopes_vec) = token.scopes() { + scopes_vec + .iter() + .flat_map(|comma_separated| comma_separated.split(',')) + .collect::>() + } else { + Vec::new() + }; + println!("Github returned the following scopes:\n{:?}\n", scopes); } } diff --git a/examples/github_async.rs b/examples/github_async.rs index f2c2870..f768622 100644 --- a/examples/github_async.rs +++ b/examples/github_async.rs @@ -14,18 +14,18 @@ //! use oauth2::basic::BasicClient; - // Alternatively, this can be `oauth2::curl::http_client` or a custom client. use oauth2::reqwest::async_http_client; use oauth2::{ AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken, RedirectUrl, Scope, TokenResponse, TokenUrl, }; -use std::env; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::net::TcpListener; use url::Url; +use std::env; + #[tokio::main] async fn main() { let github_client_id = ClientId::new( @@ -61,18 +61,14 @@ async fn main() { .add_scope(Scope::new("user:email".to_string())) .url(); - println!( - "Open this URL in your browser:\n{}\n", - authorize_url.to_string() - ); + println!("Open this URL in your browser:\n{authorize_url}\n"); + + let (code, state) = { + // A very naive implementation of the redirect server. + let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap(); - // A very naive implementation of the redirect server. - let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap(); - loop { - if let Ok((mut stream, _)) = listener.accept().await { - let code; - let state; - { + loop { + if let Ok((mut stream, _)) = listener.accept().await { let mut reader = BufReader::new(&mut stream); let mut request_line = String::new(); @@ -81,71 +77,60 @@ async fn main() { let redirect_url = request_line.split_whitespace().nth(1).unwrap(); let url = Url::parse(&("http://localhost".to_string() + redirect_url)).unwrap(); - let code_pair = url + let code = url .query_pairs() - .find(|pair| { - let &(ref key, _) = pair; - key == "code" - }) + .find(|(key, _)| key == "code") + .map(|(_, code)| AuthorizationCode::new(code.into_owned())) .unwrap(); - let (_, value) = code_pair; - code = AuthorizationCode::new(value.into_owned()); - - let state_pair = url + let state = url .query_pairs() - .find(|pair| { - let &(ref key, _) = pair; - key == "state" - }) + .find(|(key, _)| key == "state") + .map(|(_, state)| CsrfToken::new(state.into_owned())) .unwrap(); - let (_, value) = state_pair; - state = CsrfToken::new(value.into_owned()); - } + let message = "Go back to your terminal :)"; + let response = format!( + "HTTP/1.1 200 OK\r\ncontent-length: {}\r\n\r\n{}", + message.len(), + message + ); + stream.write_all(response.as_bytes()).await.unwrap(); - let message = "Go back to your terminal :)"; - let response = format!( - "HTTP/1.1 200 OK\r\ncontent-length: {}\r\n\r\n{}", - message.len(), - message - ); - stream.write_all(response.as_bytes()).await.unwrap(); - - println!("Github returned the following code:\n{}\n", code.secret()); - println!( - "Github returned the following state:\n{} (expected `{}`)\n", - state.secret(), - csrf_state.secret() - ); - - // Exchange the code with a token. - let token_res = client - .exchange_code(code) - .request_async(async_http_client) - .await; - - println!("Github returned the following token:\n{:?}\n", token_res); - - if let Ok(token) = token_res { - // NB: Github returns a single comma-separated "scope" parameter instead of multiple - // space-separated scopes. Github-specific clients can parse this scope into - // multiple scopes by splitting at the commas. Note that it's not safe for the - // library to do this by default because RFC 6749 allows scopes to contain commas. - let scopes = if let Some(scopes_vec) = token.scopes() { - scopes_vec - .iter() - .map(|comma_separated| comma_separated.split(',')) - .flatten() - .collect::>() - } else { - Vec::new() - }; - println!("Github returned the following scopes:\n{:?}\n", scopes); + // The server will terminate itself after collecting the first code. + break (code, state); } - - // The server will terminate itself after collecting the first code. - break; } + }; + + println!("Github returned the following code:\n{}\n", code.secret()); + println!( + "Github returned the following state:\n{} (expected `{}`)\n", + state.secret(), + csrf_state.secret() + ); + + // Exchange the code with a token. + let token_res = client + .exchange_code(code) + .request_async(async_http_client) + .await; + + println!("Github returned the following token:\n{:?}\n", token_res); + + if let Ok(token) = token_res { + // NB: Github returns a single comma-separated "scope" parameter instead of multiple + // space-separated scopes. Github-specific clients can parse this scope into + // multiple scopes by splitting at the commas. Note that it's not safe for the + // library to do this by default because RFC 6749 allows scopes to contain commas. + let scopes = if let Some(scopes_vec) = token.scopes() { + scopes_vec + .iter() + .flat_map(|comma_separated| comma_separated.split(',')) + .collect::>() + } else { + Vec::new() + }; + println!("Github returned the following scopes:\n{:?}\n", scopes); } } diff --git a/examples/google.rs b/examples/google.rs index 9bd75ec..d12643c 100644 --- a/examples/google.rs +++ b/examples/google.rs @@ -20,10 +20,11 @@ use oauth2::{ AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken, PkceCodeChallenge, RedirectUrl, RevocationUrl, Scope, TokenUrl, }; +use url::Url; + use std::env; use std::io::{BufRead, BufReader, Write}; use std::net::TcpListener; -use url::Url; fn main() { let google_client_id = ClientId::new( @@ -73,90 +74,76 @@ fn main() { .set_pkce_challenge(pkce_code_challenge) .url(); + println!("Open this URL in your browser:\n{authorize_url}\n"); + + let (code, state) = { + // A very naive implementation of the redirect server. + let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); + + // The server will terminate itself after collecting the first code. + let Some(mut stream) = listener.incoming().flatten().next() else { + panic!("listener terminated without accepting a connection"); + }; + + let mut reader = BufReader::new(&stream); + + let mut request_line = String::new(); + reader.read_line(&mut request_line).unwrap(); + + let redirect_url = request_line.split_whitespace().nth(1).unwrap(); + let url = Url::parse(&("http://localhost".to_string() + redirect_url)).unwrap(); + + let code = url + .query_pairs() + .find(|(key, _)| key == "code") + .map(|(_, code)| AuthorizationCode::new(code.into_owned())) + .unwrap(); + + let state = url + .query_pairs() + .find(|(key, _)| key == "state") + .map(|(_, state)| CsrfToken::new(state.into_owned())) + .unwrap(); + + let message = "Go back to your terminal :)"; + let response = format!( + "HTTP/1.1 200 OK\r\ncontent-length: {}\r\n\r\n{}", + message.len(), + message + ); + stream.write_all(response.as_bytes()).unwrap(); + + (code, state) + }; + + println!("Google returned the following code:\n{}\n", code.secret()); + println!( + "Google returned the following state:\n{} (expected `{}`)\n", + state.secret(), + csrf_state.secret() + ); + + // Exchange the code with a token. + let token_response = client + .exchange_code(code) + .set_pkce_verifier(pkce_code_verifier) + .request(http_client); + println!( - "Open this URL in your browser:\n{}\n", - authorize_url.to_string() + "Google returned the following token:\n{:?}\n", + token_response ); - // A very naive implementation of the redirect server. - let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); - for stream in listener.incoming() { - if let Ok(mut stream) = stream { - let code; - let state; - { - let mut reader = BufReader::new(&stream); - - let mut request_line = String::new(); - reader.read_line(&mut request_line).unwrap(); - - let redirect_url = request_line.split_whitespace().nth(1).unwrap(); - let url = Url::parse(&("http://localhost".to_string() + redirect_url)).unwrap(); - - let code_pair = url - .query_pairs() - .find(|pair| { - let &(ref key, _) = pair; - key == "code" - }) - .unwrap(); - - let (_, value) = code_pair; - code = AuthorizationCode::new(value.into_owned()); - - let state_pair = url - .query_pairs() - .find(|pair| { - let &(ref key, _) = pair; - key == "state" - }) - .unwrap(); - - let (_, value) = state_pair; - state = CsrfToken::new(value.into_owned()); - } - - let message = "Go back to your terminal :)"; - let response = format!( - "HTTP/1.1 200 OK\r\ncontent-length: {}\r\n\r\n{}", - message.len(), - message - ); - stream.write_all(response.as_bytes()).unwrap(); - - println!("Google returned the following code:\n{}\n", code.secret()); - println!( - "Google returned the following state:\n{} (expected `{}`)\n", - state.secret(), - csrf_state.secret() - ); - - // Exchange the code with a token. - let token_response = client - .exchange_code(code) - .set_pkce_verifier(pkce_code_verifier) - .request(http_client); - - println!( - "Google returned the following token:\n{:?}\n", - token_response - ); - - // Revoke the obtained token - let token_response = token_response.unwrap(); - let token_to_revoke: StandardRevocableToken = match token_response.refresh_token() { - Some(token) => token.into(), - None => token_response.access_token().into(), - }; - - client - .revoke_token(token_to_revoke) - .unwrap() - .request(http_client) - .expect("Failed to revoke token"); - - // The server will terminate itself after revoking the token. - break; - } - } + // Revoke the obtained token + let token_response = token_response.unwrap(); + let token_to_revoke: StandardRevocableToken = match token_response.refresh_token() { + Some(token) => token.into(), + None => token_response.access_token().into(), + }; + + client + .revoke_token(token_to_revoke) + .unwrap() + .request(http_client) + .expect("Failed to revoke token"); } diff --git a/examples/google_devicecode.rs b/examples/google_devicecode.rs index 9abb02c..d246c98 100644 --- a/examples/google_devicecode.rs +++ b/examples/google_devicecode.rs @@ -19,6 +19,7 @@ use oauth2::devicecode::{DeviceAuthorizationResponse, ExtraDeviceAuthorizationFi use oauth2::reqwest::http_client; use oauth2::{AuthType, AuthUrl, ClientId, ClientSecret, DeviceAuthorizationUrl, Scope, TokenUrl}; use serde::{Deserialize, Serialize}; + use std::collections::HashMap; use std::env; @@ -68,8 +69,8 @@ fn main() { // Display the URL and user-code. println!( "Open this URL in your browser:\n{}\nand enter the code: {}", - details.verification_uri().to_string(), - details.user_code().secret().to_string() + details.verification_uri(), + details.user_code().secret(), ); // Now poll for the token diff --git a/examples/letterboxd.rs b/examples/letterboxd.rs index c19b83b..31c0175 100644 --- a/examples/letterboxd.rs +++ b/examples/letterboxd.rs @@ -117,7 +117,7 @@ impl SigningHttpClient { .append_pair("timestamp", &format!("{}", timestamp)); // create signature - let mut hmac = Hmac::::new_from_slice(&self.client_secret.secret().as_bytes()) + let mut hmac = Hmac::::new_from_slice(self.client_secret.secret().as_bytes()) .expect("HMAC can take key of any size"); hmac.update(method.as_str().as_bytes()); hmac.update(&[b'\0']); diff --git a/examples/microsoft_devicecode_common_user.rs b/examples/microsoft_devicecode_common_user.rs index d967386..2eca95f 100644 --- a/examples/microsoft_devicecode_common_user.rs +++ b/examples/microsoft_devicecode_common_user.rs @@ -2,6 +2,7 @@ use oauth2::basic::BasicClient; use oauth2::devicecode::StandardDeviceAuthorizationResponse; use oauth2::reqwest::async_http_client; use oauth2::{AuthUrl, ClientId, DeviceAuthorizationUrl, Scope, TokenUrl}; + use std::error::Error; #[tokio::main] @@ -27,8 +28,8 @@ async fn main() -> Result<(), Box> { eprintln!( "Open this URL in your browser:\n{}\nand enter the code: {}", - details.verification_uri().to_string(), - details.user_code().secret().to_string() + details.verification_uri(), + details.user_code().secret(), ); let token_result = client diff --git a/examples/microsoft_devicecode_tenant_user.rs b/examples/microsoft_devicecode_tenant_user.rs index 3aef10e..8638f57 100644 --- a/examples/microsoft_devicecode_tenant_user.rs +++ b/examples/microsoft_devicecode_tenant_user.rs @@ -2,6 +2,7 @@ use oauth2::basic::BasicClient; use oauth2::devicecode::StandardDeviceAuthorizationResponse; use oauth2::reqwest::async_http_client; use oauth2::{AuthUrl, ClientId, DeviceAuthorizationUrl, Scope, TokenUrl}; + use std::error::Error; // Reference: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code @@ -36,8 +37,8 @@ async fn main() -> Result<(), Box> { eprintln!( "Open this URL in your browser:\n{}\nand enter the code: {}", - details.verification_uri().to_string(), - details.user_code().secret().to_string() + details.verification_uri(), + details.user_code().secret(), ); let token_result = client diff --git a/examples/msgraph.rs b/examples/msgraph.rs index 0adc1fc..e0cc4b0 100644 --- a/examples/msgraph.rs +++ b/examples/msgraph.rs @@ -30,6 +30,7 @@ use oauth2::{ use std::env; use std::io::{BufRead, BufReader, Write}; use std::net::TcpListener; + use url::Url; fn main() { @@ -78,75 +79,61 @@ fn main() { .set_pkce_challenge(pkce_code_challenge) .url(); + println!("Open this URL in your browser:\n{authorize_url}\n"); + + let (code, state) = { + // A very naive implementation of the redirect server. + let listener = TcpListener::bind("127.0.0.1:3003").unwrap(); + + // The server will terminate itself after collecting the first code. + let Some(mut stream) = listener.incoming().flatten().next() else { + panic!("listener terminated without accepting a connection"); + }; + + let mut reader = BufReader::new(&stream); + + let mut request_line = String::new(); + reader.read_line(&mut request_line).unwrap(); + + let redirect_url = request_line.split_whitespace().nth(1).unwrap(); + let url = Url::parse(&("http://localhost".to_string() + redirect_url)).unwrap(); + + let code = url + .query_pairs() + .find(|(key, _)| key == "code") + .map(|(_, code)| AuthorizationCode::new(code.into_owned())) + .unwrap(); + + let state = url + .query_pairs() + .find(|(key, _)| key == "state") + .map(|(_, state)| CsrfToken::new(state.into_owned())) + .unwrap(); + + let message = "Go back to your terminal :)"; + let response = format!( + "HTTP/1.1 200 OK\r\ncontent-length: {}\r\n\r\n{}", + message.len(), + message + ); + stream.write_all(response.as_bytes()).unwrap(); + + (code, state) + }; + + println!("MS Graph returned the following code:\n{}\n", code.secret()); println!( - "Open this URL in your browser:\n{}\n", - authorize_url.to_string() + "MS Graph returned the following state:\n{} (expected `{}`)\n", + state.secret(), + csrf_state.secret() ); - // A very naive implementation of the redirect server. - let listener = TcpListener::bind("127.0.0.1:3003").unwrap(); - for stream in listener.incoming() { - if let Ok(mut stream) = stream { - let code; - let state; - { - let mut reader = BufReader::new(&stream); - - let mut request_line = String::new(); - reader.read_line(&mut request_line).unwrap(); - - let redirect_url = request_line.split_whitespace().nth(1).unwrap(); - let url = Url::parse(&("http://localhost".to_string() + redirect_url)).unwrap(); - - let code_pair = url - .query_pairs() - .find(|pair| { - let &(ref key, _) = pair; - key == "code" - }) - .unwrap(); - - let (_, value) = code_pair; - code = AuthorizationCode::new(value.into_owned()); - - let state_pair = url - .query_pairs() - .find(|pair| { - let &(ref key, _) = pair; - key == "state" - }) - .unwrap(); - - let (_, value) = state_pair; - state = CsrfToken::new(value.into_owned()); - } - - let message = "Go back to your terminal :)"; - let response = format!( - "HTTP/1.1 200 OK\r\ncontent-length: {}\r\n\r\n{}", - message.len(), - message - ); - stream.write_all(response.as_bytes()).unwrap(); - - println!("MS Graph returned the following code:\n{}\n", code.secret()); - println!( - "MS Graph returned the following state:\n{} (expected `{}`)\n", - state.secret(), - csrf_state.secret() - ); - - // Exchange the code with a token. - let token = client - .exchange_code(code) - // Send the PKCE code verifier in the token request - .set_pkce_verifier(pkce_code_verifier) - .request(http_client); - - println!("MS Graph returned the following token:\n{:?}\n", token); - - // The server will terminate itself after collecting the first code. - break; - } - } + // Exchange the code with a token. + let token = client + .exchange_code(code) + // Send the PKCE code verifier in the token request + .set_pkce_verifier(pkce_code_verifier) + .request(http_client); + + println!("MS Graph returned the following token:\n{:?}\n", token); } diff --git a/examples/wunderlist.rs b/examples/wunderlist.rs index be3221c..976e728 100644 --- a/examples/wunderlist.rs +++ b/examples/wunderlist.rs @@ -30,14 +30,13 @@ use oauth2::{ EmptyExtraTokenFields, ExtraTokenFields, RedirectUrl, RefreshToken, Scope, TokenResponse, TokenUrl, }; - use serde::{Deserialize, Serialize}; -use std::time::Duration; +use url::Url; use std::env; use std::io::{BufRead, BufReader, Write}; use std::net::TcpListener; -use url::Url; +use std::time::Duration; type SpecialTokenResponse = NonStandardTokenResponse; type SpecialClient = Client< @@ -167,80 +166,67 @@ fn main() { // Generate the authorization URL to which we'll redirect the user. let (authorize_url, csrf_state) = client.authorize_url(CsrfToken::new_random).url(); + println!("Open this URL in your browser:\n{authorize_url}\n"); + + let (code, state) = { + // A very naive implementation of the redirect server. + let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); + + // The server will terminate itself after collecting the first code. + let Some(mut stream) = listener.incoming().flatten().next() else { + panic!("listener terminated without accepting a connection"); + }; + + let mut reader = BufReader::new(&stream); + + let mut request_line = String::new(); + reader.read_line(&mut request_line).unwrap(); + + let redirect_url = request_line.split_whitespace().nth(1).unwrap(); + let url = Url::parse(&("http://localhost".to_string() + redirect_url)).unwrap(); + + let code = url + .query_pairs() + .find(|(key, _)| key == "code") + .map(|(_, code)| AuthorizationCode::new(code.into_owned())) + .unwrap(); + + let state = url + .query_pairs() + .find(|(key, _)| key == "state") + .map(|(_, state)| CsrfToken::new(state.into_owned())) + .unwrap(); + + let message = "Go back to your terminal :)"; + let response = format!( + "HTTP/1.1 200 OK\r\ncontent-length: {}\r\n\r\n{}", + message.len(), + message + ); + stream.write_all(response.as_bytes()).unwrap(); + + (code, state) + }; + + println!( + "Wunderlist returned the following code:\n{}\n", + code.secret() + ); println!( - "Open this URL in your browser:\n{}\n", - authorize_url.to_string() + "Wunderlist returned the following state:\n{} (expected `{}`)\n", + state.secret(), + csrf_state.secret() ); - // A very naive implementation of the redirect server. - let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); - for stream in listener.incoming() { - if let Ok(mut stream) = stream { - let code; - let state; - { - let mut reader = BufReader::new(&stream); - - let mut request_line = String::new(); - reader.read_line(&mut request_line).unwrap(); - - let redirect_url = request_line.split_whitespace().nth(1).unwrap(); - let url = Url::parse(&("http://localhost".to_string() + redirect_url)).unwrap(); - - let code_pair = url - .query_pairs() - .find(|pair| { - let &(ref key, _) = pair; - key == "code" - }) - .unwrap(); - - let (_, value) = code_pair; - code = AuthorizationCode::new(value.into_owned()); - - let state_pair = url - .query_pairs() - .find(|pair| { - let &(ref key, _) = pair; - key == "state" - }) - .unwrap(); - - let (_, value) = state_pair; - state = CsrfToken::new(value.into_owned()); - } - - let message = "Go back to your terminal :)"; - let response = format!( - "HTTP/1.1 200 OK\r\ncontent-length: {}\r\n\r\n{}", - message.len(), - message - ); - stream.write_all(response.as_bytes()).unwrap(); - - println!( - "Wunderlist returned the following code:\n{}\n", - code.secret() - ); - println!( - "Wunderlist returned the following state:\n{} (expected `{}`)\n", - state.secret(), - csrf_state.secret() - ); - - // Exchange the code with a token. - let token_res = client - .exchange_code(code) - .add_extra_param("client_id", client_id_str) - .add_extra_param("client_secret", client_secret_str) - .request(http_client); - - println!( - "Wunderlist returned the following token:\n{:?}\n", - token_res - ); - - break; - } - } + // Exchange the code with a token. + let token_res = client + .exchange_code(code) + .add_extra_param("client_id", client_id_str) + .add_extra_param("client_secret", client_secret_str) + .request(http_client); + + println!( + "Wunderlist returned the following token:\n{:?}\n", + token_res + ); } diff --git a/src/lib.rs b/src/lib.rs index 3a5744a..82102e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1116,7 +1116,7 @@ impl<'a> AuthorizationRequest<'a> { /// Enables custom flows other than the `code` and `token` (implicit flow) grant. /// pub fn set_response_type(mut self, response_type: &ResponseType) -> Self { - self.response_type = (&**response_type).to_owned().into(); + self.response_type = (**response_type).to_owned().into(); self } @@ -1156,13 +1156,13 @@ impl<'a> AuthorizationRequest<'a> { let url = { let mut pairs: Vec<(&str, &str)> = vec![ ("response_type", self.response_type.as_ref()), - ("client_id", &self.client_id), + ("client_id", self.client_id), ("state", self.state.secret()), ]; if let Some(ref pkce_challenge) = self.pkce_challenge { - pairs.push(("code_challenge", &pkce_challenge.as_str())); - pairs.push(("code_challenge_method", &pkce_challenge.method().as_str())); + pairs.push(("code_challenge", pkce_challenge.as_str())); + pairs.push(("code_challenge_method", pkce_challenge.method().as_str())); } if let Some(ref redirect_url) = self.redirect_url { @@ -1176,7 +1176,7 @@ impl<'a> AuthorizationRequest<'a> { let mut url: Url = self.auth_url.url().to_owned(); url.query_pairs_mut() - .extend_pairs(pairs.iter().map(|&(k, v)| (k, &v[..]))); + .extend_pairs(pairs.iter().map(|&(k, v)| (k, v))); url.query_pairs_mut() .extend_pairs(self.extra_params.iter().cloned()); @@ -1976,11 +1976,11 @@ fn endpoint_request<'a>( // before using them as HTTP Basic auth username and password. Note that this is // not standard for ordinary Basic auth, so curl won't do it for us. let urlencoded_id: String = - form_urlencoded::byte_serialize(&client_id.as_bytes()).collect(); + form_urlencoded::byte_serialize(client_id.as_bytes()).collect(); let urlencoded_secret: String = form_urlencoded::byte_serialize(secret.secret().as_bytes()).collect(); let b64_credential = - base64::encode(&format!("{}:{}", &urlencoded_id, urlencoded_secret)); + base64::encode(format!("{}:{}", &urlencoded_id, urlencoded_secret)); headers.append( AUTHORIZATION, HeaderValue::from_str(&format!("Basic {}", &b64_credential)).unwrap(), @@ -1988,7 +1988,7 @@ fn endpoint_request<'a>( } (AuthType::RequestBody, _) | (AuthType::BasicAuth, None) => { params.push(("client_id", client_id)); - if let Some(ref client_secret) = client_secret { + if let Some(client_secret) = client_secret { params.push(("client_secret", client_secret.secret())); } } @@ -2001,7 +2001,7 @@ fn endpoint_request<'a>( params.extend_from_slice( extra_params .iter() - .map(|&(ref k, ref v)| (k.as_ref(), v.as_ref())) + .map(|(k, v)| (k.as_ref(), v.as_ref())) .collect::>() .as_slice(), ); diff --git a/src/tests.rs b/src/tests.rs index 7abf17a..706994e 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -394,7 +394,7 @@ fn test_exchange_code_successful_with_complete_json_response() { token.scopes() ); assert_eq!(3600, token.expires_in().unwrap().as_secs()); - assert_eq!("foobar", token.refresh_token().clone().unwrap().secret()); + assert_eq!("foobar", token.refresh_token().unwrap().secret()); // Ensure that serialization produces an equivalent JSON value. let serialized_json = serde_json::to_string(&token).unwrap(); @@ -960,8 +960,8 @@ fn test_exchange_code_with_simple_json_error() { assert!(token.is_err()); let token_err = token.err().unwrap(); - match &token_err { - &RequestTokenError::ServerResponse(ref error_response) => { + match token_err { + RequestTokenError::ServerResponse(ref error_response) => { assert_eq!( BasicErrorResponseType::InvalidRequest, *error_response.error() @@ -1217,7 +1217,7 @@ mod colorful_extension { StandardErrorResponse, >; - #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] + #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] #[serde(rename_all = "lowercase")] pub enum ColorfulTokenType { Green, @@ -1225,7 +1225,7 @@ mod colorful_extension { } impl TokenType for ColorfulTokenType {} - #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] + #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] pub struct ColorfulFields { #[serde(rename = "shape")] #[serde(skip_serializing_if = "Option::is_none")] @@ -1243,7 +1243,7 @@ mod colorful_extension { } impl ExtraTokenFields for ColorfulFields {} - #[derive(Clone, Deserialize, PartialEq, Serialize)] + #[derive(Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(rename_all = "snake_case")] pub enum ColorfulErrorResponseType { TooDark, @@ -1285,7 +1285,7 @@ mod colorful_extension { impl RevocableToken for ColorfulRevocableToken { fn secret(&self) -> &str { match self { - ColorfulRevocableToken::Red(secret) => &secret, + ColorfulRevocableToken::Red(secret) => secret, } } @@ -1402,7 +1402,7 @@ fn test_extension_successful_with_complete_json_response() { token.scopes() ); assert_eq!(3600, token.expires_in().unwrap().as_secs()); - assert_eq!("foobar", token.refresh_token().clone().unwrap().secret()); + assert_eq!("foobar", token.refresh_token().unwrap().secret()); assert_eq!(Some(&"round".to_string()), token.extra_fields().shape()); assert_eq!(12, token.extra_fields().height()); @@ -1458,7 +1458,7 @@ fn test_extension_with_simple_json_error() { let token_err = token.err().unwrap(); match &token_err { - &RequestTokenError::ServerResponse(ref error_response) => { + RequestTokenError::ServerResponse(ref error_response) => { assert_eq!(ColorfulErrorResponseType::TooLight, *error_response.error()); assert_eq!( Some(&"stuff happened".to_string()), @@ -1694,7 +1694,7 @@ fn test_token_introspection_successful_with_basic_auth_minimal_response() { )) .unwrap(); - assert_eq!(true, introspection_response.active); + assert!(introspection_response.active); assert_eq!(None, introspection_response.scopes); assert_eq!(None, introspection_response.client_id); assert_eq!(None, introspection_response.username); @@ -1757,7 +1757,7 @@ fn test_token_introspection_successful_with_basic_auth_full_response() { )) .unwrap(); - assert_eq!(true, introspection_response.active); + assert!(introspection_response.active); assert_eq!( Some(vec![ Scope::new("email".to_string()), diff --git a/src/types.rs b/src/types.rs index b3cb47a..b95e449 100644 --- a/src/types.rs +++ b/src/types.rs @@ -501,12 +501,9 @@ impl PkceCodeChallenge { // The RFC specifies that the code verifier must have "a minimum length of 43 // characters and a maximum length of 128 characters". // This implies 32-96 octets of random data to be base64 encoded. - assert!(num_bytes >= 32 && num_bytes <= 96); + assert!((32..=96).contains(&num_bytes)); let random_bytes: Vec = (0..num_bytes).map(|_| thread_rng().gen::()).collect(); - PkceCodeVerifier::new(base64::encode_config( - &random_bytes, - base64::URL_SAFE_NO_PAD, - )) + PkceCodeVerifier::new(base64::encode_config(random_bytes, base64::URL_SAFE_NO_PAD)) } /// @@ -523,7 +520,7 @@ impl PkceCodeChallenge { assert!(code_verifier.secret().len() >= 43 && code_verifier.secret().len() <= 128); let digest = Sha256::digest(code_verifier.secret().as_bytes()); - let code_challenge = base64::encode_config(&digest, base64::URL_SAFE_NO_PAD); + let code_challenge = base64::encode_config(digest, base64::URL_SAFE_NO_PAD); Self { code_challenge, @@ -619,7 +616,7 @@ new_secret_type![ /// pub fn new_random_len(num_bytes: u32) -> Self { let random_bytes: Vec = (0..num_bytes).map(|_| thread_rng().gen::()).collect(); - CsrfToken::new(base64::encode_config(&random_bytes, base64::URL_SAFE_NO_PAD)) + CsrfToken::new(base64::encode_config(random_bytes, base64::URL_SAFE_NO_PAD)) } } ];