|  |  | @ -12,6 +12,11 @@ use crate::{ | 
			
		
	
		
			
				
					|  |  |  |     mail, CONFIG, | 
			
		
	
		
			
				
					|  |  |  | }; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | use rocket::{ | 
			
		
	
		
			
				
					|  |  |  |     http::Status, | 
			
		
	
		
			
				
					|  |  |  |     request::{FromRequest, Outcome, Request}, | 
			
		
	
		
			
				
					|  |  |  | }; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | pub fn routes() -> Vec<rocket::Route> { | 
			
		
	
		
			
				
					|  |  |  |     routes![ | 
			
		
	
		
			
				
					|  |  |  |         register, | 
			
		
	
	
		
			
				
					|  |  | @ -39,6 +44,7 @@ pub fn routes() -> Vec<rocket::Route> { | 
			
		
	
		
			
				
					|  |  |  |         api_key, | 
			
		
	
		
			
				
					|  |  |  |         rotate_api_key, | 
			
		
	
		
			
				
					|  |  |  |         get_known_device, | 
			
		
	
		
			
				
					|  |  |  |         get_known_device_from_path, | 
			
		
	
		
			
				
					|  |  |  |         put_avatar, | 
			
		
	
		
			
				
					|  |  |  |     ] | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
	
		
			
				
					|  |  | @ -872,8 +878,9 @@ async fn rotate_api_key(data: JsonUpcase<SecretVerificationRequest>, headers: He | 
			
		
	
		
			
				
					|  |  |  |     _api_key(data, true, headers, conn).await | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | // This variant is deprecated: https://github.com/bitwarden/server/pull/2682
 | 
			
		
	
		
			
				
					|  |  |  | #[get("/devices/knowndevice/<email>/<uuid>")] | 
			
		
	
		
			
				
					|  |  |  | async fn get_known_device(email: String, uuid: String, mut conn: DbConn) -> JsonResult { | 
			
		
	
		
			
				
					|  |  |  | async fn get_known_device_from_path(email: String, uuid: String, mut conn: DbConn) -> JsonResult { | 
			
		
	
		
			
				
					|  |  |  |     // This endpoint doesn't have auth header
 | 
			
		
	
		
			
				
					|  |  |  |     let mut result = false; | 
			
		
	
		
			
				
					|  |  |  |     if let Some(user) = User::find_by_mail(&email, &mut conn).await { | 
			
		
	
	
		
			
				
					|  |  | @ -881,3 +888,51 @@ async fn get_known_device(email: String, uuid: String, mut conn: DbConn) -> Json | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     Ok(Json(json!(result))) | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | #[get("/devices/knowndevice")] | 
			
		
	
		
			
				
					|  |  |  | async fn get_known_device(device: KnownDevice, conn: DbConn) -> JsonResult { | 
			
		
	
		
			
				
					|  |  |  |     get_known_device_from_path(device.email, device.uuid, conn).await | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | struct KnownDevice { | 
			
		
	
		
			
				
					|  |  |  |     email: String, | 
			
		
	
		
			
				
					|  |  |  |     uuid: String, | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | #[rocket::async_trait] | 
			
		
	
		
			
				
					|  |  |  | impl<'r> FromRequest<'r> for KnownDevice { | 
			
		
	
		
			
				
					|  |  |  |     type Error = &'static str; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> { | 
			
		
	
		
			
				
					|  |  |  |         let email = if let Some(email_b64) = req.headers().get_one("X-Request-Email") { | 
			
		
	
		
			
				
					|  |  |  |             let email_bytes = match data_encoding::BASE64URL.decode(email_b64.as_bytes()) { | 
			
		
	
		
			
				
					|  |  |  |                 Ok(bytes) => bytes, | 
			
		
	
		
			
				
					|  |  |  |                 Err(_) => { | 
			
		
	
		
			
				
					|  |  |  |                     return Outcome::Failure(( | 
			
		
	
		
			
				
					|  |  |  |                         Status::BadRequest, | 
			
		
	
		
			
				
					|  |  |  |                         "X-Request-Email value failed to decode as base64url", | 
			
		
	
		
			
				
					|  |  |  |                     )); | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |             }; | 
			
		
	
		
			
				
					|  |  |  |             match String::from_utf8(email_bytes) { | 
			
		
	
		
			
				
					|  |  |  |                 Ok(email) => email, | 
			
		
	
		
			
				
					|  |  |  |                 Err(_) => { | 
			
		
	
		
			
				
					|  |  |  |                     return Outcome::Failure((Status::BadRequest, "X-Request-Email value failed to decode as UTF-8")); | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |             return Outcome::Failure((Status::BadRequest, "X-Request-Email value is required")); | 
			
		
	
		
			
				
					|  |  |  |         }; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         let uuid = if let Some(uuid) = req.headers().get_one("X-Device-Identifier") { | 
			
		
	
		
			
				
					|  |  |  |             uuid.to_string() | 
			
		
	
		
			
				
					|  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |             return Outcome::Failure((Status::BadRequest, "X-Device-Identifier value is required")); | 
			
		
	
		
			
				
					|  |  |  |         }; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         Outcome::Success(KnownDevice { | 
			
		
	
		
			
				
					|  |  |  |             email, | 
			
		
	
		
			
				
					|  |  |  |             uuid, | 
			
		
	
		
			
				
					|  |  |  |         }) | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
	
		
			
				
					|  |  | 
 |