1use std::ops::Deref;
5
6use oauth2::{
7 http::{Method, Response},
8 AuthUrl, ClientId, ClientSecret, EndpointNotSet, EndpointSet, HttpRequest, HttpResponse,
9 RedirectUrl, TokenUrl,
10};
11
12use super::{Error, Result};
13
14type BasicClient = oauth2::basic::BasicClient<
15 EndpointSet,
16 EndpointNotSet,
17 EndpointNotSet,
18 EndpointNotSet,
19 EndpointSet,
20>;
21
22#[derive(Clone, Debug)]
25pub struct Client {
26 inner: BasicClient,
27
28 pub redirect_host: String,
30
31 pub redirect_port: u16,
33}
34
35impl Client {
36 pub fn new(
37 client_id: impl ToString,
38 client_secret: Option<impl ToString>,
39 auth_url: impl ToString,
40 token_url: impl ToString,
41 redirect_scheme: impl ToString,
42 redirect_host: impl ToString,
43 redirect_port: impl Into<u16>,
44 ) -> Result<Self> {
45 let redirect_host = redirect_host.to_string();
46 let redirect_port = redirect_port.into();
47
48 let mut client = oauth2::basic::BasicClient::new(ClientId::new(client_id.to_string()))
49 .set_auth_uri(AuthUrl::new(auth_url.to_string()).map_err(Error::BuildAuthUrlError)?)
50 .set_token_uri(TokenUrl::new(token_url.to_string()).map_err(Error::BuildTokenUrlError)?)
51 .set_redirect_uri({
52 let scheme = redirect_scheme.to_string();
53 RedirectUrl::new(format!("{scheme}://{redirect_host}:{redirect_port}"))
54 .map_err(Error::BuildRedirectUrlError)
55 }?);
56
57 if let Some(secret) = client_secret {
58 client = client.set_client_secret(ClientSecret::new(secret.to_string()));
59 }
60
61 Ok(Self {
62 inner: client,
63 redirect_host,
64 redirect_port,
65 })
66 }
67
68 pub(crate) async fn send_oauth2_request(oauth2_request: HttpRequest) -> Result<HttpResponse> {
69 let client = http::Client::new();
70
71 let response = client
72 .send(move |agent| match *oauth2_request.method() {
73 Method::GET => {
74 let mut request = agent.get(&oauth2_request.uri().to_string());
75
76 for (key, val) in oauth2_request.headers() {
77 let Ok(val) = val.to_str() else {
78 continue;
79 };
80
81 request = request.header(key, val);
82 }
83
84 Ok(request.call()?)
85 }
86 Method::POST => {
87 let mut request = agent.post(&oauth2_request.uri().to_string());
88
89 for (key, val) in oauth2_request.headers() {
90 let Ok(val) = val.to_str() else {
91 continue;
92 };
93
94 request = request.header(key, val);
95 }
96
97 Ok(request.send(oauth2_request.body())?)
98 }
99 _ => unreachable!(),
100 })
101 .await?;
102
103 let mut oauth2_response = Response::builder();
104
105 for (key, val) in response.headers() {
106 oauth2_response = oauth2_response.header(key, val);
107 }
108
109 let body = response
110 .into_body()
111 .read_to_vec()
112 .map_err(http::Error::from)?;
113
114 let oauth2_response = oauth2_response
115 .body(body)
116 .map_err(http::Error::from)
117 .map_err(Error::ReadResponseBodyError)?;
118
119 Ok(oauth2_response)
120 }
121}
122
123impl Deref for Client {
124 type Target = BasicClient;
125
126 fn deref(&self) -> &Self::Target {
127 &self.inner
128 }
129}