1 //
2 // JWT Handling
3 //
4 use chrono::{Duration, Utc};
5 use num_traits::FromPrimitive;
6 use once_cell::sync::Lazy;
7 
8 use jsonwebtoken::{self, Algorithm, DecodingKey, EncodingKey, Header};
9 use serde::de::DeserializeOwned;
10 use serde::ser::Serialize;
11 
12 use crate::{
13     error::{Error, MapResult},
14     util::read_file,
15     CONFIG,
16 };
17 
18 const JWT_ALGORITHM: Algorithm = Algorithm::RS256;
19 
20 pub static DEFAULT_VALIDITY: Lazy<Duration> = Lazy::new(|| Duration::hours(2));
21 static JWT_HEADER: Lazy<Header> = Lazy::new(|| Header::new(JWT_ALGORITHM));
22 
23 pub static JWT_LOGIN_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|login", CONFIG.domain_origin()));
24 static JWT_INVITE_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|invite", CONFIG.domain_origin()));
25 static JWT_EMERGENCY_ACCESS_INVITE_ISSUER: Lazy<String> =
26     Lazy::new(|| format!("{}|emergencyaccessinvite", CONFIG.domain_origin()));
27 static JWT_DELETE_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|delete", CONFIG.domain_origin()));
28 static JWT_VERIFYEMAIL_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|verifyemail", CONFIG.domain_origin()));
29 static JWT_ADMIN_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|admin", CONFIG.domain_origin()));
30 static JWT_SEND_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|send", CONFIG.domain_origin()));
31 
32 static PRIVATE_RSA_KEY_VEC: Lazy<Vec<u8>> = Lazy::new(|| {
33     read_file(&CONFIG.private_rsa_key()).unwrap_or_else(|e| panic!("Error loading private RSA Key.\n{}", e))
34 });
35 static PRIVATE_RSA_KEY: Lazy<EncodingKey> = Lazy::new(|| {
36     EncodingKey::from_rsa_pem(&PRIVATE_RSA_KEY_VEC).unwrap_or_else(|e| panic!("Error decoding private RSA Key.\n{}", e))
37 });
38 static PUBLIC_RSA_KEY_VEC: Lazy<Vec<u8>> = Lazy::new(|| {
39     read_file(&CONFIG.public_rsa_key()).unwrap_or_else(|e| panic!("Error loading public RSA Key.\n{}", e))
40 });
41 static PUBLIC_RSA_KEY: Lazy<DecodingKey> = Lazy::new(|| {
42     DecodingKey::from_rsa_pem(&PUBLIC_RSA_KEY_VEC).unwrap_or_else(|e| panic!("Error decoding public RSA Key.\n{}", e))
43 });
44 
load_keys()45 pub fn load_keys() {
46     Lazy::force(&PRIVATE_RSA_KEY);
47     Lazy::force(&PUBLIC_RSA_KEY);
48 }
49 
encode_jwt<T: Serialize>(claims: &T) -> String50 pub fn encode_jwt<T: Serialize>(claims: &T) -> String {
51     match jsonwebtoken::encode(&JWT_HEADER, claims, &PRIVATE_RSA_KEY) {
52         Ok(token) => token,
53         Err(e) => panic!("Error encoding jwt {}", e),
54     }
55 }
56 
decode_jwt<T: DeserializeOwned>(token: &str, issuer: String) -> Result<T, Error>57 fn decode_jwt<T: DeserializeOwned>(token: &str, issuer: String) -> Result<T, Error> {
58     let validation = jsonwebtoken::Validation {
59         leeway: 30, // 30 seconds
60         validate_exp: true,
61         validate_nbf: true,
62         aud: None,
63         iss: Some(issuer),
64         sub: None,
65         algorithms: vec![JWT_ALGORITHM],
66     };
67 
68     let token = token.replace(char::is_whitespace, "");
69     jsonwebtoken::decode(&token, &PUBLIC_RSA_KEY, &validation).map(|d| d.claims).map_res("Error decoding JWT")
70 }
71 
decode_login(token: &str) -> Result<LoginJwtClaims, Error>72 pub fn decode_login(token: &str) -> Result<LoginJwtClaims, Error> {
73     decode_jwt(token, JWT_LOGIN_ISSUER.to_string())
74 }
75 
decode_invite(token: &str) -> Result<InviteJwtClaims, Error>76 pub fn decode_invite(token: &str) -> Result<InviteJwtClaims, Error> {
77     decode_jwt(token, JWT_INVITE_ISSUER.to_string())
78 }
79 
decode_emergency_access_invite(token: &str) -> Result<EmergencyAccessInviteJwtClaims, Error>80 pub fn decode_emergency_access_invite(token: &str) -> Result<EmergencyAccessInviteJwtClaims, Error> {
81     decode_jwt(token, JWT_EMERGENCY_ACCESS_INVITE_ISSUER.to_string())
82 }
83 
decode_delete(token: &str) -> Result<BasicJwtClaims, Error>84 pub fn decode_delete(token: &str) -> Result<BasicJwtClaims, Error> {
85     decode_jwt(token, JWT_DELETE_ISSUER.to_string())
86 }
87 
decode_verify_email(token: &str) -> Result<BasicJwtClaims, Error>88 pub fn decode_verify_email(token: &str) -> Result<BasicJwtClaims, Error> {
89     decode_jwt(token, JWT_VERIFYEMAIL_ISSUER.to_string())
90 }
91 
decode_admin(token: &str) -> Result<BasicJwtClaims, Error>92 pub fn decode_admin(token: &str) -> Result<BasicJwtClaims, Error> {
93     decode_jwt(token, JWT_ADMIN_ISSUER.to_string())
94 }
95 
decode_send(token: &str) -> Result<BasicJwtClaims, Error>96 pub fn decode_send(token: &str) -> Result<BasicJwtClaims, Error> {
97     decode_jwt(token, JWT_SEND_ISSUER.to_string())
98 }
99 
100 #[derive(Debug, Serialize, Deserialize)]
101 pub struct LoginJwtClaims {
102     // Not before
103     pub nbf: i64,
104     // Expiration time
105     pub exp: i64,
106     // Issuer
107     pub iss: String,
108     // Subject
109     pub sub: String,
110 
111     pub premium: bool,
112     pub name: String,
113     pub email: String,
114     pub email_verified: bool,
115 
116     pub orgowner: Vec<String>,
117     pub orgadmin: Vec<String>,
118     pub orguser: Vec<String>,
119     pub orgmanager: Vec<String>,
120 
121     // user security_stamp
122     pub sstamp: String,
123     // device uuid
124     pub device: String,
125     // [ "api", "offline_access" ]
126     pub scope: Vec<String>,
127     // [ "Application" ]
128     pub amr: Vec<String>,
129 }
130 
131 #[derive(Debug, Serialize, Deserialize)]
132 pub struct InviteJwtClaims {
133     // Not before
134     pub nbf: i64,
135     // Expiration time
136     pub exp: i64,
137     // Issuer
138     pub iss: String,
139     // Subject
140     pub sub: String,
141 
142     pub email: String,
143     pub org_id: Option<String>,
144     pub user_org_id: Option<String>,
145     pub invited_by_email: Option<String>,
146 }
147 
generate_invite_claims( uuid: String, email: String, org_id: Option<String>, user_org_id: Option<String>, invited_by_email: Option<String>, ) -> InviteJwtClaims148 pub fn generate_invite_claims(
149     uuid: String,
150     email: String,
151     org_id: Option<String>,
152     user_org_id: Option<String>,
153     invited_by_email: Option<String>,
154 ) -> InviteJwtClaims {
155     let time_now = Utc::now().naive_utc();
156     InviteJwtClaims {
157         nbf: time_now.timestamp(),
158         exp: (time_now + Duration::days(5)).timestamp(),
159         iss: JWT_INVITE_ISSUER.to_string(),
160         sub: uuid,
161         email,
162         org_id,
163         user_org_id,
164         invited_by_email,
165     }
166 }
167 
168 #[derive(Debug, Serialize, Deserialize)]
169 pub struct EmergencyAccessInviteJwtClaims {
170     // Not before
171     pub nbf: i64,
172     // Expiration time
173     pub exp: i64,
174     // Issuer
175     pub iss: String,
176     // Subject
177     pub sub: String,
178 
179     pub email: String,
180     pub emer_id: Option<String>,
181     pub grantor_name: Option<String>,
182     pub grantor_email: Option<String>,
183 }
184 
generate_emergency_access_invite_claims( uuid: String, email: String, emer_id: Option<String>, grantor_name: Option<String>, grantor_email: Option<String>, ) -> EmergencyAccessInviteJwtClaims185 pub fn generate_emergency_access_invite_claims(
186     uuid: String,
187     email: String,
188     emer_id: Option<String>,
189     grantor_name: Option<String>,
190     grantor_email: Option<String>,
191 ) -> EmergencyAccessInviteJwtClaims {
192     let time_now = Utc::now().naive_utc();
193     EmergencyAccessInviteJwtClaims {
194         nbf: time_now.timestamp(),
195         exp: (time_now + Duration::days(5)).timestamp(),
196         iss: JWT_EMERGENCY_ACCESS_INVITE_ISSUER.to_string(),
197         sub: uuid,
198         email,
199         emer_id,
200         grantor_name,
201         grantor_email,
202     }
203 }
204 
205 #[derive(Debug, Serialize, Deserialize)]
206 pub struct BasicJwtClaims {
207     // Not before
208     pub nbf: i64,
209     // Expiration time
210     pub exp: i64,
211     // Issuer
212     pub iss: String,
213     // Subject
214     pub sub: String,
215 }
216 
generate_delete_claims(uuid: String) -> BasicJwtClaims217 pub fn generate_delete_claims(uuid: String) -> BasicJwtClaims {
218     let time_now = Utc::now().naive_utc();
219     BasicJwtClaims {
220         nbf: time_now.timestamp(),
221         exp: (time_now + Duration::days(5)).timestamp(),
222         iss: JWT_DELETE_ISSUER.to_string(),
223         sub: uuid,
224     }
225 }
226 
generate_verify_email_claims(uuid: String) -> BasicJwtClaims227 pub fn generate_verify_email_claims(uuid: String) -> BasicJwtClaims {
228     let time_now = Utc::now().naive_utc();
229     BasicJwtClaims {
230         nbf: time_now.timestamp(),
231         exp: (time_now + Duration::days(5)).timestamp(),
232         iss: JWT_VERIFYEMAIL_ISSUER.to_string(),
233         sub: uuid,
234     }
235 }
236 
generate_admin_claims() -> BasicJwtClaims237 pub fn generate_admin_claims() -> BasicJwtClaims {
238     let time_now = Utc::now().naive_utc();
239     BasicJwtClaims {
240         nbf: time_now.timestamp(),
241         exp: (time_now + Duration::minutes(20)).timestamp(),
242         iss: JWT_ADMIN_ISSUER.to_string(),
243         sub: "admin_panel".to_string(),
244     }
245 }
246 
generate_send_claims(send_id: &str, file_id: &str) -> BasicJwtClaims247 pub fn generate_send_claims(send_id: &str, file_id: &str) -> BasicJwtClaims {
248     let time_now = Utc::now().naive_utc();
249     BasicJwtClaims {
250         nbf: time_now.timestamp(),
251         exp: (time_now + Duration::minutes(2)).timestamp(),
252         iss: JWT_SEND_ISSUER.to_string(),
253         sub: format!("{}/{}", send_id, file_id),
254     }
255 }
256 
257 //
258 // Bearer token authentication
259 //
260 use rocket::request::{FromRequest, Outcome, Request};
261 
262 use crate::db::{
263     models::{CollectionUser, Device, User, UserOrgStatus, UserOrgType, UserOrganization, UserStampException},
264     DbConn,
265 };
266 
267 pub struct Host {
268     pub host: String,
269 }
270 
271 impl<'a, 'r> FromRequest<'a, 'r> for Host {
272     type Error = &'static str;
273 
from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error>274     fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
275         let headers = request.headers();
276 
277         // Get host
278         let host = if CONFIG.domain_set() {
279             CONFIG.domain()
280         } else if let Some(referer) = headers.get_one("Referer") {
281             referer.to_string()
282         } else {
283             // Try to guess from the headers
284             use std::env;
285 
286             let protocol = if let Some(proto) = headers.get_one("X-Forwarded-Proto") {
287                 proto
288             } else if env::var("ROCKET_TLS").is_ok() {
289                 "https"
290             } else {
291                 "http"
292             };
293 
294             let host = if let Some(host) = headers.get_one("X-Forwarded-Host") {
295                 host
296             } else if let Some(host) = headers.get_one("Host") {
297                 host
298             } else {
299                 ""
300             };
301 
302             format!("{}://{}", protocol, host)
303         };
304 
305         Outcome::Success(Host {
306             host,
307         })
308     }
309 }
310 
311 pub struct Headers {
312     pub host: String,
313     pub device: Device,
314     pub user: User,
315 }
316 
317 impl<'a, 'r> FromRequest<'a, 'r> for Headers {
318     type Error = &'static str;
319 
from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error>320     fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
321         let headers = request.headers();
322 
323         let host = match Host::from_request(request) {
324             Outcome::Forward(_) => return Outcome::Forward(()),
325             Outcome::Failure(f) => return Outcome::Failure(f),
326             Outcome::Success(host) => host.host,
327         };
328 
329         // Get access_token
330         let access_token: &str = match headers.get_one("Authorization") {
331             Some(a) => match a.rsplit("Bearer ").next() {
332                 Some(split) => split,
333                 None => err_handler!("No access token provided"),
334             },
335             None => err_handler!("No access token provided"),
336         };
337 
338         // Check JWT token is valid and get device and user from it
339         let claims = match decode_login(access_token) {
340             Ok(claims) => claims,
341             Err(_) => err_handler!("Invalid claim"),
342         };
343 
344         let device_uuid = claims.device;
345         let user_uuid = claims.sub;
346 
347         let conn = match request.guard::<DbConn>() {
348             Outcome::Success(conn) => conn,
349             _ => err_handler!("Error getting DB"),
350         };
351 
352         let device = match Device::find_by_uuid(&device_uuid, &conn) {
353             Some(device) => device,
354             None => err_handler!("Invalid device id"),
355         };
356 
357         let user = match User::find_by_uuid(&user_uuid, &conn) {
358             Some(user) => user,
359             None => err_handler!("Device has no user associated"),
360         };
361 
362         if user.security_stamp != claims.sstamp {
363             if let Some(stamp_exception) =
364                 user.stamp_exception.as_deref().and_then(|s| serde_json::from_str::<UserStampException>(s).ok())
365             {
366                 let current_route = match request.route().and_then(|r| r.name) {
367                     Some(name) => name,
368                     _ => err_handler!("Error getting current route for stamp exception"),
369                 };
370 
371                 // Check if the stamp exception has expired first.
372                 // Then, check if the current route matches any of the allowed routes.
373                 // After that check the stamp in exception matches the one in the claims.
374                 if Utc::now().naive_utc().timestamp() > stamp_exception.expire {
375                     // If the stamp exception has been expired remove it from the database.
376                     // This prevents checking this stamp exception for new requests.
377                     let mut user = user;
378                     user.reset_stamp_exception();
379                     if let Err(e) = user.save(&conn) {
380                         error!("Error updating user: {:#?}", e);
381                     }
382                     err_handler!("Stamp exception is expired")
383                 } else if !stamp_exception.routes.contains(&current_route.to_string()) {
384                     err_handler!("Invalid security stamp: Current route and exception route do not match")
385                 } else if stamp_exception.security_stamp != claims.sstamp {
386                     err_handler!("Invalid security stamp for matched stamp exception")
387                 }
388             } else {
389                 err_handler!("Invalid security stamp")
390             }
391         }
392 
393         Outcome::Success(Headers {
394             host,
395             device,
396             user,
397         })
398     }
399 }
400 
401 pub struct OrgHeaders {
402     pub host: String,
403     pub device: Device,
404     pub user: User,
405     pub org_user_type: UserOrgType,
406     pub org_user: UserOrganization,
407     pub org_id: String,
408 }
409 
410 // org_id is usually the second path param ("/organizations/<org_id>"),
411 // but there are cases where it is a query value.
412 // First check the path, if this is not a valid uuid, try the query values.
get_org_id(request: &Request) -> Option<String>413 fn get_org_id(request: &Request) -> Option<String> {
414     if let Some(Ok(org_id)) = request.get_param::<String>(1) {
415         if uuid::Uuid::parse_str(&org_id).is_ok() {
416             return Some(org_id);
417         }
418     }
419 
420     if let Some(Ok(org_id)) = request.get_query_value::<String>("organizationId") {
421         if uuid::Uuid::parse_str(&org_id).is_ok() {
422             return Some(org_id);
423         }
424     }
425 
426     None
427 }
428 
429 impl<'a, 'r> FromRequest<'a, 'r> for OrgHeaders {
430     type Error = &'static str;
431 
from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error>432     fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
433         match request.guard::<Headers>() {
434             Outcome::Forward(_) => Outcome::Forward(()),
435             Outcome::Failure(f) => Outcome::Failure(f),
436             Outcome::Success(headers) => {
437                 match get_org_id(request) {
438                     Some(org_id) => {
439                         let conn = match request.guard::<DbConn>() {
440                             Outcome::Success(conn) => conn,
441                             _ => err_handler!("Error getting DB"),
442                         };
443 
444                         let user = headers.user;
445                         let org_user = match UserOrganization::find_by_user_and_org(&user.uuid, &org_id, &conn) {
446                             Some(user) => {
447                                 if user.status == UserOrgStatus::Confirmed as i32 {
448                                     user
449                                 } else {
450                                     err_handler!("The current user isn't confirmed member of the organization")
451                                 }
452                             }
453                             None => err_handler!("The current user isn't member of the organization"),
454                         };
455 
456                         Outcome::Success(Self {
457                             host: headers.host,
458                             device: headers.device,
459                             user,
460                             org_user_type: {
461                                 if let Some(org_usr_type) = UserOrgType::from_i32(org_user.atype) {
462                                     org_usr_type
463                                 } else {
464                                     // This should only happen if the DB is corrupted
465                                     err_handler!("Unknown user type in the database")
466                                 }
467                             },
468                             org_user,
469                             org_id,
470                         })
471                     }
472                     _ => err_handler!("Error getting the organization id"),
473                 }
474             }
475         }
476     }
477 }
478 
479 pub struct AdminHeaders {
480     pub host: String,
481     pub device: Device,
482     pub user: User,
483     pub org_user_type: UserOrgType,
484 }
485 
486 impl<'a, 'r> FromRequest<'a, 'r> for AdminHeaders {
487     type Error = &'static str;
488 
from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error>489     fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
490         match request.guard::<OrgHeaders>() {
491             Outcome::Forward(_) => Outcome::Forward(()),
492             Outcome::Failure(f) => Outcome::Failure(f),
493             Outcome::Success(headers) => {
494                 if headers.org_user_type >= UserOrgType::Admin {
495                     Outcome::Success(Self {
496                         host: headers.host,
497                         device: headers.device,
498                         user: headers.user,
499                         org_user_type: headers.org_user_type,
500                     })
501                 } else {
502                     err_handler!("You need to be Admin or Owner to call this endpoint")
503                 }
504             }
505         }
506     }
507 }
508 
509 impl From<AdminHeaders> for Headers {
from(h: AdminHeaders) -> Headers510     fn from(h: AdminHeaders) -> Headers {
511         Headers {
512             host: h.host,
513             device: h.device,
514             user: h.user,
515         }
516     }
517 }
518 
519 // col_id is usually the fourth path param ("/organizations/<org_id>/collections/<col_id>"),
520 // but there could be cases where it is a query value.
521 // First check the path, if this is not a valid uuid, try the query values.
get_col_id(request: &Request) -> Option<String>522 fn get_col_id(request: &Request) -> Option<String> {
523     if let Some(Ok(col_id)) = request.get_param::<String>(3) {
524         if uuid::Uuid::parse_str(&col_id).is_ok() {
525             return Some(col_id);
526         }
527     }
528 
529     if let Some(Ok(col_id)) = request.get_query_value::<String>("collectionId") {
530         if uuid::Uuid::parse_str(&col_id).is_ok() {
531             return Some(col_id);
532         }
533     }
534 
535     None
536 }
537 
538 /// The ManagerHeaders are used to check if you are at least a Manager
539 /// and have access to the specific collection provided via the <col_id>/collections/collectionId.
540 /// This does strict checking on the collection_id, ManagerHeadersLoose does not.
541 pub struct ManagerHeaders {
542     pub host: String,
543     pub device: Device,
544     pub user: User,
545     pub org_user_type: UserOrgType,
546 }
547 
548 impl<'a, 'r> FromRequest<'a, 'r> for ManagerHeaders {
549     type Error = &'static str;
550 
from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error>551     fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
552         match request.guard::<OrgHeaders>() {
553             Outcome::Forward(_) => Outcome::Forward(()),
554             Outcome::Failure(f) => Outcome::Failure(f),
555             Outcome::Success(headers) => {
556                 if headers.org_user_type >= UserOrgType::Manager {
557                     match get_col_id(request) {
558                         Some(col_id) => {
559                             let conn = match request.guard::<DbConn>() {
560                                 Outcome::Success(conn) => conn,
561                                 _ => err_handler!("Error getting DB"),
562                             };
563 
564                             if !headers.org_user.has_full_access() {
565                                 match CollectionUser::find_by_collection_and_user(
566                                     &col_id,
567                                     &headers.org_user.user_uuid,
568                                     &conn,
569                                 ) {
570                                     Some(_) => (),
571                                     None => err_handler!("The current user isn't a manager for this collection"),
572                                 }
573                             }
574                         }
575                         _ => err_handler!("Error getting the collection id"),
576                     }
577 
578                     Outcome::Success(Self {
579                         host: headers.host,
580                         device: headers.device,
581                         user: headers.user,
582                         org_user_type: headers.org_user_type,
583                     })
584                 } else {
585                     err_handler!("You need to be a Manager, Admin or Owner to call this endpoint")
586                 }
587             }
588         }
589     }
590 }
591 
592 impl From<ManagerHeaders> for Headers {
from(h: ManagerHeaders) -> Headers593     fn from(h: ManagerHeaders) -> Headers {
594         Headers {
595             host: h.host,
596             device: h.device,
597             user: h.user,
598         }
599     }
600 }
601 
602 /// The ManagerHeadersLoose is used when you at least need to be a Manager,
603 /// but there is no collection_id sent with the request (either in the path or as form data).
604 pub struct ManagerHeadersLoose {
605     pub host: String,
606     pub device: Device,
607     pub user: User,
608     pub org_user_type: UserOrgType,
609 }
610 
611 impl<'a, 'r> FromRequest<'a, 'r> for ManagerHeadersLoose {
612     type Error = &'static str;
613 
from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error>614     fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
615         match request.guard::<OrgHeaders>() {
616             Outcome::Forward(_) => Outcome::Forward(()),
617             Outcome::Failure(f) => Outcome::Failure(f),
618             Outcome::Success(headers) => {
619                 if headers.org_user_type >= UserOrgType::Manager {
620                     Outcome::Success(Self {
621                         host: headers.host,
622                         device: headers.device,
623                         user: headers.user,
624                         org_user_type: headers.org_user_type,
625                     })
626                 } else {
627                     err_handler!("You need to be a Manager, Admin or Owner to call this endpoint")
628                 }
629             }
630         }
631     }
632 }
633 
634 impl From<ManagerHeadersLoose> for Headers {
from(h: ManagerHeadersLoose) -> Headers635     fn from(h: ManagerHeadersLoose) -> Headers {
636         Headers {
637             host: h.host,
638             device: h.device,
639             user: h.user,
640         }
641     }
642 }
643 
644 pub struct OwnerHeaders {
645     pub host: String,
646     pub device: Device,
647     pub user: User,
648 }
649 
650 impl<'a, 'r> FromRequest<'a, 'r> for OwnerHeaders {
651     type Error = &'static str;
652 
from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error>653     fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
654         match request.guard::<OrgHeaders>() {
655             Outcome::Forward(_) => Outcome::Forward(()),
656             Outcome::Failure(f) => Outcome::Failure(f),
657             Outcome::Success(headers) => {
658                 if headers.org_user_type == UserOrgType::Owner {
659                     Outcome::Success(Self {
660                         host: headers.host,
661                         device: headers.device,
662                         user: headers.user,
663                     })
664                 } else {
665                     err_handler!("You need to be Owner to call this endpoint")
666                 }
667             }
668         }
669     }
670 }
671 
672 //
673 // Client IP address detection
674 //
675 use std::net::IpAddr;
676 
677 pub struct ClientIp {
678     pub ip: IpAddr,
679 }
680 
681 impl<'a, 'r> FromRequest<'a, 'r> for ClientIp {
682     type Error = ();
683 
from_request(req: &'a Request<'r>) -> Outcome<Self, Self::Error>684     fn from_request(req: &'a Request<'r>) -> Outcome<Self, Self::Error> {
685         let ip = if CONFIG._ip_header_enabled() {
686             req.headers().get_one(&CONFIG.ip_header()).and_then(|ip| {
687                 match ip.find(',') {
688                     Some(idx) => &ip[..idx],
689                     None => ip,
690                 }
691                 .parse()
692                 .map_err(|_| warn!("'{}' header is malformed: {}", CONFIG.ip_header(), ip))
693                 .ok()
694             })
695         } else {
696             None
697         };
698 
699         let ip = ip.or_else(|| req.remote().map(|r| r.ip())).unwrap_or_else(|| "0.0.0.0".parse().unwrap());
700 
701         Outcome::Success(ClientIp {
702             ip,
703         })
704     }
705 }
706