device.rs (5872B)
1 use crate::crypto; 2 use crate::util; 3 use chrono::{NaiveDateTime, Utc}; 4 5 db_object! { 6 #[derive(Insertable, Queryable)] 7 #[diesel(table_name = devices)] 8 #[diesel(treat_none_as_null = true)] 9 pub struct Device { 10 pub uuid: String, 11 created_at: NaiveDateTime, 12 pub updated_at: NaiveDateTime, 13 pub user_uuid: String, 14 name: String, 15 atype: i32, // https://github.com/bitwarden/server/blob/master/src/Core/Enums/DeviceType.cs 16 push_uuid: Option<String>, 17 push_token: Option<String>, 18 pub refresh_token: String, 19 twofactor_remember: Option<String>, 20 } 21 } 22 23 /// Local methods 24 impl Device { 25 pub fn new(uuid: String, user_uuid: String, name: String, atype: i32) -> Self { 26 let now = Utc::now().naive_utc(); 27 Self { 28 uuid, 29 created_at: now, 30 updated_at: now, 31 user_uuid, 32 name, 33 atype, 34 push_uuid: None, 35 push_token: None, 36 refresh_token: String::new(), 37 twofactor_remember: None, 38 } 39 } 40 41 pub fn delete_twofactor_remember(&mut self) { 42 self.twofactor_remember = None; 43 } 44 45 pub fn refresh_tokens(&mut self, user: &super::User, scope: Vec<String>) -> (String, i64) { 46 // If there is no refresh token, we create one 47 if self.refresh_token.is_empty() { 48 use data_encoding::BASE64URL; 49 self.refresh_token = crypto::encode_random_bytes::<64>(&BASE64URL); 50 } 51 // Update the expiration of the device and the last update date 52 let time_now = Utc::now(); 53 self.updated_at = time_now.naive_utc(); 54 // --- 55 // Disabled these keys to be added to the JWT since they could cause the JWT to get too large 56 // Also These key/value pairs are not used anywhere by either Vaultwarden or Bitwarden Clients 57 // Because these might get used in the future, and they are added by the Bitwarden Server, lets keep it, but then commented out 58 // --- 59 // fn arg: orgs: Vec<super::UserOrganization>, 60 // --- 61 // let orgowner: Vec<_> = orgs.iter().filter(|o| o.atype == 0).map(|o| o.org_uuid.clone()).collect(); 62 // let orgadmin: Vec<_> = orgs.iter().filter(|o| o.atype == 1).map(|o| o.org_uuid.clone()).collect(); 63 // let orguser: Vec<_> = orgs.iter().filter(|o| o.atype == 2).map(|o| o.org_uuid.clone()).collect(); 64 // let orgmanager: Vec<_> = orgs.iter().filter(|o| o.atype == 3).map(|o| o.org_uuid.clone()).collect(); 65 // Create the JWT claims struct, to send to the client 66 use crate::auth::{self, encode_jwt, LoginJwtClaims}; 67 let claims = LoginJwtClaims { 68 nbf: time_now.timestamp(), 69 exp: time_now 70 .checked_add_signed(*auth::get_default_validity()) 71 .expect("overflow") 72 .timestamp(), 73 iss: auth::get_jwt_login_issuer().to_owned(), 74 sub: user.uuid.clone(), 75 premium: true, 76 name: user.name.clone(), 77 email: user.email.clone(), 78 email_verified: true, 79 // --- 80 // Disabled these keys to be added to the JWT since they could cause the JWT to get too large 81 // Also These key/value pairs are not used anywhere by either Vaultwarden or Bitwarden Clients 82 // Because these might get used in the future, and they are added by the Bitwarden Server, lets keep it, but then commented out 83 // See: https://github.com/dani-garcia/vaultwarden/issues/4156 84 // --- 85 // orgowner, 86 // orgadmin, 87 // orguser, 88 // orgmanager, 89 sstamp: user.security_stamp.clone(), 90 device: self.uuid.clone(), 91 scope, 92 amr: vec!["Application".into()], 93 }; 94 95 ( 96 encode_jwt(&claims), 97 auth::get_default_validity().num_seconds(), 98 ) 99 } 100 } 101 102 use crate::api::EmptyResult; 103 use crate::db::DbConn; 104 use crate::error::MapResult; 105 106 /// Database methods 107 impl Device { 108 pub async fn save(&mut self, conn: &DbConn) -> EmptyResult { 109 self.updated_at = Utc::now().naive_utc(); 110 db_run! { conn: 111 { 112 util::retry( 113 || diesel::replace_into(devices::table).values(DeviceDb::to_db(self)).execute(conn), 114 10, 115 ).map_res("Error saving device") 116 } 117 } 118 } 119 120 pub async fn delete_all_by_user(user_uuid: &str, conn: &DbConn) -> EmptyResult { 121 db_run! { conn: { 122 diesel::delete(devices::table.filter(devices::user_uuid.eq(user_uuid))) 123 .execute(conn) 124 .map_res("Error removing devices for user") 125 }} 126 } 127 128 pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &DbConn) -> Option<Self> { 129 db_run! { conn: { 130 devices::table 131 .filter(devices::uuid.eq(uuid)) 132 .filter(devices::user_uuid.eq(user_uuid)) 133 .first::<DeviceDb>(conn) 134 .ok() 135 .from_db() 136 }} 137 } 138 139 pub async fn find_by_refresh_token(refresh_token: &str, conn: &DbConn) -> Option<Self> { 140 db_run! { conn: { 141 devices::table 142 .filter(devices::refresh_token.eq(refresh_token)) 143 .first::<DeviceDb>(conn) 144 .ok() 145 .from_db() 146 }} 147 } 148 149 pub async fn find_latest_active_by_user(user_uuid: &str, conn: &DbConn) -> Option<Self> { 150 db_run! { conn: { 151 devices::table 152 .filter(devices::user_uuid.eq(user_uuid)) 153 .order(devices::updated_at.desc()) 154 .first::<DeviceDb>(conn) 155 .ok() 156 .from_db() 157 }} 158 } 159 }