Mathijs van Veluw
1 year ago
committed by
GitHub
20 changed files with 842 additions and 8 deletions
@ -0,0 +1,19 @@ |
|||
CREATE TABLE auth_requests ( |
|||
uuid CHAR(36) NOT NULL PRIMARY KEY, |
|||
user_uuid CHAR(36) NOT NULL, |
|||
organization_uuid CHAR(36), |
|||
request_device_identifier CHAR(36) NOT NULL, |
|||
device_type INTEGER NOT NULL, |
|||
request_ip TEXT NOT NULL, |
|||
response_device_id CHAR(36), |
|||
access_code TEXT NOT NULL, |
|||
public_key TEXT NOT NULL, |
|||
enc_key TEXT NOT NULL, |
|||
master_password_hash TEXT NOT NULL, |
|||
approved BOOLEAN, |
|||
creation_date DATETIME NOT NULL, |
|||
response_date DATETIME, |
|||
authentication_date DATETIME, |
|||
FOREIGN KEY(user_uuid) REFERENCES users(uuid), |
|||
FOREIGN KEY(organization_uuid) REFERENCES organizations(uuid) |
|||
); |
@ -0,0 +1,19 @@ |
|||
CREATE TABLE auth_requests ( |
|||
uuid CHAR(36) NOT NULL PRIMARY KEY, |
|||
user_uuid CHAR(36) NOT NULL, |
|||
organization_uuid CHAR(36), |
|||
request_device_identifier CHAR(36) NOT NULL, |
|||
device_type INTEGER NOT NULL, |
|||
request_ip TEXT NOT NULL, |
|||
response_device_id CHAR(36), |
|||
access_code TEXT NOT NULL, |
|||
public_key TEXT NOT NULL, |
|||
enc_key TEXT NOT NULL, |
|||
master_password_hash TEXT NOT NULL, |
|||
approved BOOLEAN, |
|||
creation_date TIMESTAMP NOT NULL, |
|||
response_date TIMESTAMP, |
|||
authentication_date TIMESTAMP, |
|||
FOREIGN KEY(user_uuid) REFERENCES users(uuid), |
|||
FOREIGN KEY(organization_uuid) REFERENCES organizations(uuid) |
|||
); |
@ -0,0 +1,19 @@ |
|||
CREATE TABLE auth_requests ( |
|||
uuid TEXT NOT NULL PRIMARY KEY, |
|||
user_uuid TEXT NOT NULL, |
|||
organization_uuid TEXT, |
|||
request_device_identifier TEXT NOT NULL, |
|||
device_type INTEGER NOT NULL, |
|||
request_ip TEXT NOT NULL, |
|||
response_device_id TEXT, |
|||
access_code TEXT NOT NULL, |
|||
public_key TEXT NOT NULL, |
|||
enc_key TEXT NOT NULL, |
|||
master_password_hash TEXT NOT NULL, |
|||
approved BOOLEAN, |
|||
creation_date DATETIME NOT NULL, |
|||
response_date DATETIME, |
|||
authentication_date DATETIME, |
|||
FOREIGN KEY(user_uuid) REFERENCES users(uuid), |
|||
FOREIGN KEY(organization_uuid) REFERENCES organizations(uuid) |
|||
); |
@ -0,0 +1,148 @@ |
|||
use crate::crypto::ct_eq; |
|||
use chrono::{NaiveDateTime, Utc}; |
|||
|
|||
db_object! { |
|||
#[derive(Debug, Identifiable, Queryable, Insertable, AsChangeset, Deserialize, Serialize)] |
|||
#[diesel(table_name = auth_requests)] |
|||
#[diesel(treat_none_as_null = true)] |
|||
#[diesel(primary_key(uuid))] |
|||
pub struct AuthRequest { |
|||
pub uuid: String, |
|||
pub user_uuid: String, |
|||
pub organization_uuid: Option<String>, |
|||
|
|||
pub request_device_identifier: String, |
|||
pub device_type: i32, // https://github.com/bitwarden/server/blob/master/src/Core/Enums/DeviceType.cs
|
|||
|
|||
pub request_ip: String, |
|||
pub response_device_id: Option<String>, |
|||
|
|||
pub access_code: String, |
|||
pub public_key: String, |
|||
|
|||
pub enc_key: String, |
|||
|
|||
pub master_password_hash: String, |
|||
pub approved: Option<bool>, |
|||
pub creation_date: NaiveDateTime, |
|||
pub response_date: Option<NaiveDateTime>, |
|||
|
|||
pub authentication_date: Option<NaiveDateTime>, |
|||
} |
|||
} |
|||
|
|||
impl AuthRequest { |
|||
pub fn new( |
|||
user_uuid: String, |
|||
request_device_identifier: String, |
|||
device_type: i32, |
|||
request_ip: String, |
|||
access_code: String, |
|||
public_key: String, |
|||
) -> Self { |
|||
let now = Utc::now().naive_utc(); |
|||
|
|||
Self { |
|||
uuid: crate::util::get_uuid(), |
|||
user_uuid, |
|||
organization_uuid: None, |
|||
|
|||
request_device_identifier, |
|||
device_type, |
|||
request_ip, |
|||
response_device_id: None, |
|||
access_code, |
|||
public_key, |
|||
enc_key: String::new(), |
|||
master_password_hash: String::new(), |
|||
approved: None, |
|||
creation_date: now, |
|||
response_date: None, |
|||
authentication_date: None, |
|||
} |
|||
} |
|||
} |
|||
|
|||
use crate::db::DbConn; |
|||
|
|||
use crate::api::EmptyResult; |
|||
use crate::error::MapResult; |
|||
|
|||
impl AuthRequest { |
|||
pub async fn save(&mut self, conn: &mut DbConn) -> EmptyResult { |
|||
db_run! { conn: |
|||
sqlite, mysql { |
|||
match diesel::replace_into(auth_requests::table) |
|||
.values(AuthRequestDb::to_db(self)) |
|||
.execute(conn) |
|||
{ |
|||
Ok(_) => Ok(()), |
|||
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
|||
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => { |
|||
diesel::update(auth_requests::table) |
|||
.filter(auth_requests::uuid.eq(&self.uuid)) |
|||
.set(AuthRequestDb::to_db(self)) |
|||
.execute(conn) |
|||
.map_res("Error auth_request") |
|||
} |
|||
Err(e) => Err(e.into()), |
|||
}.map_res("Error auth_request") |
|||
} |
|||
postgresql { |
|||
let value = AuthRequestDb::to_db(self); |
|||
diesel::insert_into(auth_requests::table) |
|||
.values(&value) |
|||
.on_conflict(auth_requests::uuid) |
|||
.do_update() |
|||
.set(&value) |
|||
.execute(conn) |
|||
.map_res("Error saving auth_request") |
|||
} |
|||
} |
|||
} |
|||
|
|||
pub async fn find_by_uuid(uuid: &str, conn: &mut DbConn) -> Option<Self> { |
|||
db_run! {conn: { |
|||
auth_requests::table |
|||
.filter(auth_requests::uuid.eq(uuid)) |
|||
.first::<AuthRequestDb>(conn) |
|||
.ok() |
|||
.from_db() |
|||
}} |
|||
} |
|||
|
|||
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { |
|||
db_run! {conn: { |
|||
auth_requests::table |
|||
.filter(auth_requests::user_uuid.eq(user_uuid)) |
|||
.load::<AuthRequestDb>(conn).expect("Error loading auth_requests").from_db() |
|||
}} |
|||
} |
|||
|
|||
pub async fn find_created_before(dt: &NaiveDateTime, conn: &mut DbConn) -> Vec<Self> { |
|||
db_run! {conn: { |
|||
auth_requests::table |
|||
.filter(auth_requests::creation_date.lt(dt)) |
|||
.load::<AuthRequestDb>(conn).expect("Error loading auth_requests").from_db() |
|||
}} |
|||
} |
|||
|
|||
pub async fn delete(&self, conn: &mut DbConn) -> EmptyResult { |
|||
db_run! { conn: { |
|||
diesel::delete(auth_requests::table.filter(auth_requests::uuid.eq(&self.uuid))) |
|||
.execute(conn) |
|||
.map_res("Error deleting auth request") |
|||
}} |
|||
} |
|||
|
|||
pub fn check_access_code(&self, access_code: &str) -> bool { |
|||
ct_eq(&self.access_code, access_code) |
|||
} |
|||
|
|||
pub async fn purge_expired_auth_requests(conn: &mut DbConn) { |
|||
let expiry_time = Utc::now().naive_utc() - chrono::Duration::minutes(5); //after 5 minutes, clients reject the request
|
|||
for auth_request in Self::find_created_before(&expiry_time, conn).await { |
|||
auth_request.delete(conn).await.ok(); |
|||
} |
|||
} |
|||
} |
Loading…
Reference in new issue