mod.rs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. use data_encoding::BASE32;
  2. use rocket::Route;
  3. use rocket_contrib::json::Json;
  4. use serde_json::Value;
  5. use crate::api::{JsonResult, JsonUpcase, NumberOrString, PasswordData};
  6. use crate::auth::Headers;
  7. use crate::crypto;
  8. use crate::db::{
  9. models::{TwoFactor, User},
  10. DbConn,
  11. };
  12. pub mod authenticator;
  13. pub mod duo;
  14. pub mod email;
  15. pub mod u2f;
  16. pub mod yubikey;
  17. pub fn routes() -> Vec<Route> {
  18. let mut routes = routes![
  19. get_twofactor,
  20. get_recover,
  21. recover,
  22. disable_twofactor,
  23. disable_twofactor_put,
  24. ];
  25. routes.append(&mut authenticator::routes());
  26. routes.append(&mut duo::routes());
  27. routes.append(&mut email::routes());
  28. routes.append(&mut u2f::routes());
  29. routes.append(&mut yubikey::routes());
  30. routes
  31. }
  32. #[get("/two-factor")]
  33. fn get_twofactor(headers: Headers, conn: DbConn) -> JsonResult {
  34. let twofactors = TwoFactor::find_by_user(&headers.user.uuid, &conn);
  35. let twofactors_json: Vec<Value> = twofactors.iter().map(TwoFactor::to_json_provider).collect();
  36. Ok(Json(json!({
  37. "Data": twofactors_json,
  38. "Object": "list",
  39. "ContinuationToken": null,
  40. })))
  41. }
  42. #[post("/two-factor/get-recover", data = "<data>")]
  43. fn get_recover(data: JsonUpcase<PasswordData>, headers: Headers) -> JsonResult {
  44. let data: PasswordData = data.into_inner().data;
  45. let user = headers.user;
  46. if !user.check_valid_password(&data.MasterPasswordHash) {
  47. err!("Invalid password");
  48. }
  49. Ok(Json(json!({
  50. "Code": user.totp_recover,
  51. "Object": "twoFactorRecover"
  52. })))
  53. }
  54. #[derive(Deserialize)]
  55. #[allow(non_snake_case)]
  56. struct RecoverTwoFactor {
  57. MasterPasswordHash: String,
  58. Email: String,
  59. RecoveryCode: String,
  60. }
  61. #[post("/two-factor/recover", data = "<data>")]
  62. fn recover(data: JsonUpcase<RecoverTwoFactor>, conn: DbConn) -> JsonResult {
  63. let data: RecoverTwoFactor = data.into_inner().data;
  64. use crate::db::models::User;
  65. // Get the user
  66. let mut user = match User::find_by_mail(&data.Email, &conn) {
  67. Some(user) => user,
  68. None => err!("Username or password is incorrect. Try again."),
  69. };
  70. // Check password
  71. if !user.check_valid_password(&data.MasterPasswordHash) {
  72. err!("Username or password is incorrect. Try again.")
  73. }
  74. // Check if recovery code is correct
  75. if !user.check_valid_recovery_code(&data.RecoveryCode) {
  76. err!("Recovery code is incorrect. Try again.")
  77. }
  78. // Remove all twofactors from the user
  79. TwoFactor::delete_all_by_user(&user.uuid, &conn)?;
  80. // Remove the recovery code, not needed without twofactors
  81. user.totp_recover = None;
  82. user.save(&conn)?;
  83. Ok(Json(json!({})))
  84. }
  85. fn _generate_recover_code(user: &mut User, conn: &DbConn) {
  86. if user.totp_recover.is_none() {
  87. let totp_recover = BASE32.encode(&crypto::get_random(vec![0u8; 20]));
  88. user.totp_recover = Some(totp_recover);
  89. user.save(conn).ok();
  90. }
  91. }
  92. #[derive(Deserialize)]
  93. #[allow(non_snake_case)]
  94. struct DisableTwoFactorData {
  95. MasterPasswordHash: String,
  96. Type: NumberOrString,
  97. }
  98. #[post("/two-factor/disable", data = "<data>")]
  99. fn disable_twofactor(data: JsonUpcase<DisableTwoFactorData>, headers: Headers, conn: DbConn) -> JsonResult {
  100. let data: DisableTwoFactorData = data.into_inner().data;
  101. let password_hash = data.MasterPasswordHash;
  102. let user = headers.user;
  103. if !user.check_valid_password(&password_hash) {
  104. err!("Invalid password");
  105. }
  106. let type_ = data.Type.into_i32()?;
  107. if let Some(twofactor) = TwoFactor::find_by_user_and_type(&user.uuid, type_, &conn) {
  108. twofactor.delete(&conn)?;
  109. }
  110. Ok(Json(json!({
  111. "Enabled": false,
  112. "Type": type_,
  113. "Object": "twoFactorProvider"
  114. })))
  115. }
  116. #[put("/two-factor/disable", data = "<data>")]
  117. fn disable_twofactor_put(data: JsonUpcase<DisableTwoFactorData>, headers: Headers, conn: DbConn) -> JsonResult {
  118. disable_twofactor(data, headers, conn)
  119. }