mahjong_service/auth/
github.rs

1use actix_web::web::Query;
2use serde::{Deserialize, Serialize};
3use service_contracts::UserPostSetAuthResponse;
4
5use crate::{
6    auth::{GetAuthInfo, UserRole},
7    env::{ENV_GITHUB_CLIENT_ID, ENV_GITHUB_SECRET},
8    http_server::DataStorage,
9};
10
11use super::AuthHandler;
12
13#[derive(Deserialize, Debug)]
14pub struct GithubCallbackQuery {
15    code: String,
16}
17
18pub struct GithubAuth {}
19
20impl GithubAuth {
21    pub async fn handle_callback(
22        query: Query<GithubCallbackQuery>,
23        storage: &DataStorage,
24        auth_handler: &mut AuthHandler<'_>,
25    ) -> Option<UserPostSetAuthResponse> {
26        #[derive(Serialize, Debug)]
27        struct GithubAccessBody {
28            client_id: String,
29            client_secret: String,
30            code: String,
31        }
32
33        let body = GithubAccessBody {
34            client_id: std::env::var(ENV_GITHUB_CLIENT_ID).unwrap(),
35            client_secret: std::env::var(ENV_GITHUB_SECRET).unwrap(),
36            code: query.code.clone(),
37        };
38
39        let url = "https://github.com/login/oauth/access_token";
40        let json_data = serde_json::to_string(&body).unwrap();
41
42        let client = reqwest::Client::new();
43
44        let response2 = client
45            .post(url)
46            .header("Content-Type", "application/json")
47            .body(json_data.to_owned())
48            .send()
49            .await
50            .unwrap();
51
52        let response_body_text2 = response2.text().await.unwrap();
53
54        #[derive(Deserialize, Debug)]
55        struct GithubAccessResponse {
56            access_token: String,
57        }
58
59        let response_body2 =
60            serde_qs::from_str::<GithubAccessResponse>(&response_body_text2).unwrap();
61
62        let access_token = response_body2.access_token.clone();
63        let response = client
64            .get("https://api.github.com/user")
65            .header("Content-Type", "application/json")
66            .header("User-Agent", "Rust Server")
67            .header("Authorization", format!("Bearer {}", access_token))
68            .send()
69            .await
70            .unwrap();
71        let response_body_text = response.text().await.unwrap();
72
73        #[derive(Deserialize, Debug)]
74        struct GithubUserResponse {
75            login: String,
76        }
77
78        let response_body3 =
79            serde_json::from_str::<GithubUserResponse>(&response_body_text).unwrap();
80
81        let existing_user = storage
82            .get_auth_info(GetAuthInfo::GithubUsername(response_body3.login.clone()))
83            .await
84            .unwrap();
85
86        if existing_user.is_none() {
87            let result = auth_handler
88                .create_github_user(&response_body3.login, &access_token, UserRole::Player)
89                .await;
90
91            if result.is_err() {
92                return None;
93            }
94        } else {
95            auth_handler.auth_info = existing_user;
96        }
97
98        let data = auth_handler.generate_token();
99
100        if data.is_err() {
101            return None;
102        }
103
104        Some(data.unwrap())
105    }
106}