mod.rs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. mod accounts;
  2. mod ciphers;
  3. mod folders;
  4. mod organizations;
  5. pub mod two_factor;
  6. mod sends;
  7. pub use ciphers::purge_trashed_ciphers;
  8. pub use sends::purge_sends;
  9. pub fn routes() -> Vec<Route> {
  10. let mut mod_routes = routes![
  11. clear_device_token,
  12. put_device_token,
  13. get_eq_domains,
  14. post_eq_domains,
  15. put_eq_domains,
  16. hibp_breach,
  17. ];
  18. let mut routes = Vec::new();
  19. routes.append(&mut accounts::routes());
  20. routes.append(&mut ciphers::routes());
  21. routes.append(&mut folders::routes());
  22. routes.append(&mut organizations::routes());
  23. routes.append(&mut two_factor::routes());
  24. routes.append(&mut sends::routes());
  25. routes.append(&mut mod_routes);
  26. routes
  27. }
  28. //
  29. // Move this somewhere else
  30. //
  31. use rocket::Route;
  32. use rocket_contrib::json::Json;
  33. use rocket::response::Response;
  34. use serde_json::Value;
  35. use crate::{
  36. api::{JsonResult, JsonUpcase},
  37. auth::Headers,
  38. db::DbConn,
  39. error::Error,
  40. util::get_reqwest_client,
  41. };
  42. #[put("/devices/identifier/<uuid>/clear-token")]
  43. fn clear_device_token<'a>(uuid: String) -> Response<'a> {
  44. // This endpoint doesn't have auth header
  45. let _ = uuid;
  46. // uuid is not related to deviceId
  47. // This only clears push token
  48. // https://github.com/bitwarden/core/blob/master/src/Api/Controllers/DevicesController.cs#L109
  49. // https://github.com/bitwarden/core/blob/master/src/Core/Services/Implementations/DeviceService.cs#L37
  50. Response::new()
  51. }
  52. #[put("/devices/identifier/<uuid>/token", data = "<data>")]
  53. fn put_device_token(uuid: String, data: JsonUpcase<Value>, headers: Headers) -> Json<Value> {
  54. let _data: Value = data.into_inner().data;
  55. // Data has a single string value "PushToken"
  56. let _ = uuid;
  57. // uuid is not related to deviceId
  58. // TODO: This should save the push token, but we don't have push functionality
  59. Json(json!({
  60. "Id": headers.device.uuid,
  61. "Name": headers.device.name,
  62. "Type": headers.device.atype,
  63. "Identifier": headers.device.uuid,
  64. "CreationDate": crate::util::format_date(&headers.device.created_at),
  65. }))
  66. }
  67. #[derive(Serialize, Deserialize, Debug)]
  68. #[allow(non_snake_case)]
  69. struct GlobalDomain {
  70. Type: i32,
  71. Domains: Vec<String>,
  72. Excluded: bool,
  73. }
  74. const GLOBAL_DOMAINS: &str = include_str!("../../static/global_domains.json");
  75. #[get("/settings/domains")]
  76. fn get_eq_domains(headers: Headers) -> Json<Value> {
  77. _get_eq_domains(headers, false)
  78. }
  79. fn _get_eq_domains(headers: Headers, no_excluded: bool) -> Json<Value> {
  80. let user = headers.user;
  81. use serde_json::from_str;
  82. let equivalent_domains: Vec<Vec<String>> = from_str(&user.equivalent_domains).unwrap();
  83. let excluded_globals: Vec<i32> = from_str(&user.excluded_globals).unwrap();
  84. let mut globals: Vec<GlobalDomain> = from_str(GLOBAL_DOMAINS).unwrap();
  85. for global in &mut globals {
  86. global.Excluded = excluded_globals.contains(&global.Type);
  87. }
  88. if no_excluded {
  89. globals.retain(|g| !g.Excluded);
  90. }
  91. Json(json!({
  92. "EquivalentDomains": equivalent_domains,
  93. "GlobalEquivalentDomains": globals,
  94. "Object": "domains",
  95. }))
  96. }
  97. #[derive(Deserialize, Debug)]
  98. #[allow(non_snake_case)]
  99. struct EquivDomainData {
  100. ExcludedGlobalEquivalentDomains: Option<Vec<i32>>,
  101. EquivalentDomains: Option<Vec<Vec<String>>>,
  102. }
  103. #[post("/settings/domains", data = "<data>")]
  104. fn post_eq_domains(data: JsonUpcase<EquivDomainData>, headers: Headers, conn: DbConn) -> JsonResult {
  105. let data: EquivDomainData = data.into_inner().data;
  106. let excluded_globals = data.ExcludedGlobalEquivalentDomains.unwrap_or_default();
  107. let equivalent_domains = data.EquivalentDomains.unwrap_or_default();
  108. let mut user = headers.user;
  109. use serde_json::to_string;
  110. user.excluded_globals = to_string(&excluded_globals).unwrap_or_else(|_| "[]".to_string());
  111. user.equivalent_domains = to_string(&equivalent_domains).unwrap_or_else(|_| "[]".to_string());
  112. user.save(&conn)?;
  113. Ok(Json(json!({})))
  114. }
  115. #[put("/settings/domains", data = "<data>")]
  116. fn put_eq_domains(data: JsonUpcase<EquivDomainData>, headers: Headers, conn: DbConn) -> JsonResult {
  117. post_eq_domains(data, headers, conn)
  118. }
  119. #[get("/hibp/breach?<username>")]
  120. fn hibp_breach(username: String) -> JsonResult {
  121. let url = format!(
  122. "https://haveibeenpwned.com/api/v3/breachedaccount/{}?truncateResponse=false&includeUnverified=false",
  123. username
  124. );
  125. if let Some(api_key) = crate::CONFIG.hibp_api_key() {
  126. let hibp_client = get_reqwest_client();
  127. let res = hibp_client
  128. .get(&url)
  129. .header("hibp-api-key", api_key)
  130. .send()?;
  131. // If we get a 404, return a 404, it means no breached accounts
  132. if res.status() == 404 {
  133. return Err(Error::empty().with_code(404));
  134. }
  135. let value: Value = res.error_for_status()?.json()?;
  136. Ok(Json(value))
  137. } else {
  138. Ok(Json(json!([{
  139. "Name": "HaveIBeenPwned",
  140. "Title": "Manual HIBP Check",
  141. "Domain": "haveibeenpwned.com",
  142. "BreachDate": "2019-08-18T00:00:00Z",
  143. "AddedDate": "2019-08-18T00:00:00Z",
  144. "Description": format!("Go to: <a href=\"https://haveibeenpwned.com/account/{account}\" target=\"_blank\" rel=\"noreferrer\">https://haveibeenpwned.com/account/{account}</a> for a manual check.<br/><br/>HaveIBeenPwned API key not set!<br/>Go to <a href=\"https://haveibeenpwned.com/API/Key\" target=\"_blank\" rel=\"noreferrer\">https://haveibeenpwned.com/API/Key</a> to purchase an API key from HaveIBeenPwned.<br/><br/>", account=username),
  145. "LogoPath": "bwrs_static/hibp.png",
  146. "PwnCount": 0,
  147. "DataClasses": [
  148. "Error - No API key set!"
  149. ]
  150. }])))
  151. }
  152. }