ginger_shared_rs/
rocket_utils.rs

1use jsonwebtoken::decode;
2use jsonwebtoken::DecodingKey;
3use jsonwebtoken::Validation;
4use okapi::openapi3::Object;
5use okapi::openapi3::SecurityRequirement;
6use okapi::openapi3::SecurityScheme;
7use okapi::openapi3::SecuritySchemeData;
8use rocket::serde::Deserialize;
9use rocket::serde::Serialize;
10use rocket_okapi::gen::OpenApiGenerator;
11use rocket_okapi::request::OpenApiFromRequest;
12use rocket_okapi::request::RequestHeaderInput;
13use std::env;
14
15use rocket::{
16    http::Status,
17    request::{FromRequest, Outcome, Request},
18};
19
20
21
22#[derive(Serialize, Deserialize, Debug)]
23pub struct ISCClaims {
24    pub sub: String,
25    pub exp: usize,
26    pub org_id: String,
27    pub scopes: Vec<String>,
28}
29
30#[derive(Debug)]
31pub enum ISCClaimsError {
32    Missing,
33    Invalid,
34}
35
36
37
38#[rocket::async_trait]
39impl<'r> FromRequest<'r> for ISCClaims {
40    type Error = ISCClaimsError;
41
42    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
43        let keys: Vec<_> = request.headers().get("X-API-Authorization").collect();
44        if keys.len() != 1 {
45            return Outcome::Error((Status::Unauthorized, ISCClaimsError::Missing));
46        }
47
48        let token_str = keys[0].trim_start_matches("Bearer ").trim();
49        let secret = env::var("JWT_SECRET").expect("JWT_SECRET must be set");
50        let decoding_key = DecodingKey::from_secret(secret.as_ref());
51
52        match decode::<ISCClaims>(
53            token_str,
54            &decoding_key,
55            &Validation::new(jsonwebtoken::Algorithm::HS256),
56        ) {
57            Ok(token_data) => Outcome::Success(token_data.claims),
58            Err(_) => Outcome::Error((Status::Unauthorized, ISCClaimsError::Invalid)),
59        }
60    }
61}
62
63impl<'a> OpenApiFromRequest<'a> for ISCClaims {
64    fn from_request_input(
65        _gen: &mut OpenApiGenerator,
66        _name: String,
67        _required: bool,
68    ) -> rocket_okapi::Result<RequestHeaderInput> {
69        let security_scheme = SecurityScheme {
70            description: Some("Requires a Bearer token to access".to_owned()),
71            data: SecuritySchemeData::ApiKey {
72                name: "X-API-Authorization".to_owned(),
73                location: "header".to_owned(),
74            },
75            extensions: Object::default(),
76        };
77
78        let mut security_req = SecurityRequirement::new();
79        security_req.insert("BearerAPIAuth".to_owned(), Vec::new());
80
81        Ok(RequestHeaderInput::Security(
82            "BearerAPIAuth".to_owned(),
83            security_scheme,
84            security_req,
85        ))
86    }
87
88    fn get_responses(
89        _gen: &mut rocket_okapi::gen::OpenApiGenerator,
90    ) -> rocket_okapi::Result<okapi::openapi3::Responses> {
91        Ok(okapi::openapi3::Responses::default())
92    }
93}
94
95
96#[derive(Serialize, Deserialize)]
97pub struct APIClaims {
98    pub sub: String,
99    pub exp: usize,
100    pub group_id: i64,
101    pub scopes: Vec<String>,
102}
103
104#[derive(Debug)]
105pub enum APIClaimsError {
106    Missing,
107    Invalid,
108}
109
110#[derive(Serialize, Deserialize)]
111pub struct Claims {
112    pub sub: String,
113    pub exp: usize,
114    pub user_id: String,
115    pub token_type: String, // Add token_type to distinguish between access and refresh tokens
116    pub first_name: Option<String>,
117    pub last_name: Option<String>,
118    pub middle_name: Option<String>,
119    pub client_id: Option<String>,
120}
121#[derive(Debug)]
122pub enum ClaimsError {
123    Missing,
124    Invalid,
125}
126
127#[rocket::async_trait]
128impl<'r> FromRequest<'r> for APIClaims {
129    type Error = APIClaimsError;
130
131    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
132        let keys: Vec<_> = request.headers().get("X-API-Authorization").collect();
133        if keys.len() != 1 {
134            return Outcome::Error((Status::Unauthorized, APIClaimsError::Missing));
135        }
136
137        let token_str = keys[0].trim_start_matches("Bearer ").trim();
138        let secret = env::var("JWT_SECRET").expect("JWT_SECRET must be set");
139        let decoding_key = DecodingKey::from_secret(secret.as_ref());
140
141        match decode::<APIClaims>(
142            token_str,
143            &decoding_key,
144            &Validation::new(jsonwebtoken::Algorithm::HS256),
145        ) {
146            Ok(token_data) => Outcome::Success(token_data.claims),
147            Err(_) => Outcome::Error((Status::Unauthorized, APIClaimsError::Invalid)),
148        }
149    }
150}
151
152impl<'a> OpenApiFromRequest<'a> for APIClaims {
153    fn from_request_input(
154        _gen: &mut OpenApiGenerator,
155        _name: String,
156        _required: bool,
157    ) -> rocket_okapi::Result<RequestHeaderInput> {
158        let security_scheme = SecurityScheme {
159            description: Some("Requires a Bearer token to access".to_owned()),
160            data: SecuritySchemeData::ApiKey {
161                name: "X-API-Authorization".to_owned(),
162                location: "header".to_owned(),
163            },
164            extensions: Object::default(),
165        };
166
167        let mut security_req = SecurityRequirement::new();
168        security_req.insert("BearerAPIAuth".to_owned(), Vec::new());
169
170        Ok(RequestHeaderInput::Security(
171            "BearerAPIAuth".to_owned(),
172            security_scheme,
173            security_req,
174        ))
175    }
176
177    fn get_responses(
178        _gen: &mut rocket_okapi::gen::OpenApiGenerator,
179    ) -> rocket_okapi::Result<okapi::openapi3::Responses> {
180        Ok(okapi::openapi3::Responses::default())
181    }
182}
183
184#[rocket::async_trait]
185impl<'r> FromRequest<'r> for Claims {
186    type Error = ClaimsError;
187
188    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
189        let keys: Vec<_> = request.headers().get("Authorization").collect();
190        if keys.len() != 1 {
191            return Outcome::Error((Status::Unauthorized, ClaimsError::Missing));
192        }
193
194        let token_str = keys[0].trim_start_matches("Bearer ").trim();
195        let secret = env::var("JWT_SECRET").expect("JWT_SECRET must be set");
196        let decoding_key = DecodingKey::from_secret(secret.as_ref());
197
198        match decode::<Claims>(
199            token_str,
200            &decoding_key,
201            &Validation::new(jsonwebtoken::Algorithm::HS256),
202        ) {
203            Ok(token_data) => Outcome::Success(token_data.claims),
204            Err(_) => Outcome::Error((Status::Unauthorized, ClaimsError::Invalid)),
205        }
206    }
207}
208
209impl<'a> OpenApiFromRequest<'a> for Claims {
210    fn from_request_input(
211        _gen: &mut OpenApiGenerator,
212        _name: String,
213        _required: bool,
214    ) -> rocket_okapi::Result<RequestHeaderInput> {
215        let security_scheme = SecurityScheme {
216            description: Some("Requires a Bearer token to access".to_owned()),
217            data: SecuritySchemeData::ApiKey {
218                name: "Authorization".to_owned(),
219                location: "header".to_owned(),
220            },
221            extensions: Object::default(),
222        };
223
224        let mut security_req = SecurityRequirement::new();
225        security_req.insert("BearerAuth".to_owned(), Vec::new());
226
227        Ok(RequestHeaderInput::Security(
228            "BearerAuth".to_owned(),
229            security_scheme,
230            security_req,
231        ))
232    }
233
234    fn get_responses(
235        _gen: &mut rocket_okapi::gen::OpenApiGenerator,
236    ) -> rocket_okapi::Result<okapi::openapi3::Responses> {
237        Ok(okapi::openapi3::Responses::default())
238    }
239}