phabricator_oauth/
client.rs1use oauth2::{
2 basic::{
3 BasicClient, BasicErrorResponse, BasicRevocationErrorResponse, BasicTokenIntrospectionResponse,
4 BasicTokenResponse, BasicTokenType
5 },
6 http::{HeaderMap, Method},
7 reqwest::async_http_client,
8 url::Url,
9 AccessToken, AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken, HttpRequest, RedirectUrl,
10 StandardRevocableToken, TokenUrl
11};
12use serde_json;
13use std::borrow::Cow;
14use serde::Deserialize;
15
16use crate::error::PhabOAuthError;
17use crate::user::PhabricatorUser;
18
19type Result<T> = std::result::Result<T, PhabOAuthError>;
20
21#[derive(Deserialize, Debug)]
22struct OAuthResponse<T> {
23 result: Option<T>,
24 }
27
28pub struct PhabOAuthClient {
29 redirect_url: String,
30 phabricator_url: String,
31 client: oauth2::Client<BasicErrorResponse, BasicTokenResponse, BasicTokenType, BasicTokenIntrospectionResponse, StandardRevocableToken, BasicRevocationErrorResponse>
32}
33
34impl PhabOAuthClient {
35 pub fn new(phid: String, secret: String, redirect_url: String, phabricator_url: String) -> Result<PhabOAuthClient> {
36 let client = BasicClient::new(
37 ClientId::new(phid),
38 Some(ClientSecret::new(secret)),
39 AuthUrl::new(format!("{}/oauthserver/auth/", phabricator_url))?,
40 Some(TokenUrl::new(format!("{}/oauthserver/token/", phabricator_url))?)
41 )
42 .set_redirect_uri(RedirectUrl::new(redirect_url.clone())?);
43
44 Ok(
45 PhabOAuthClient {
46 redirect_url,
47 phabricator_url,
48 client
49 }
50 )
51 }
52
53 pub fn get_auth_url(&self) -> Result<(Url, CsrfToken)> {
54 let url = RedirectUrl::new(self.redirect_url.clone())?;
55
56 let (auth_url, csrf_token) = self.client
57 .authorize_url(CsrfToken::new_random)
58 .set_redirect_uri(Cow::Owned(url))
59 .url();
60
61 Ok((auth_url, csrf_token))
62 }
63
64 pub async fn get_token(&self, code: String) -> Result<BasicTokenResponse> {
65 let token_response = self.client
66 .exchange_code(AuthorizationCode::new(code))
67 .request_async(async_http_client).await?;
68
69 Ok(token_response)
70 }
71
72 pub async fn get_user(&self, token: &AccessToken) -> Result<Option<PhabricatorUser>> {
73 let request_url = format!("{}/api/user.whoami?access_token={}", self.phabricator_url, token.secret());
74 let request = HttpRequest{
75 url: Url::parse(request_url.as_str())?,
76 headers: HeaderMap::new(),
77 method: Method::GET,
78 body: vec![]
79 };
80 let response = async_http_client(request).await?;
81 let json = String::from_utf8(response.body)?;
82 let user_result: OAuthResponse<PhabricatorUser> = serde_json::from_str(json.as_str())?;
83 Ok(user_result.result)
84 }
85}