From d6e0ace192c294d31da21984833816d8e91f5791 Mon Sep 17 00:00:00 2001
From: BlackDex <black.dex@gmail.com>
Date: Fri, 1 Sep 2023 21:03:50 +0200
Subject: [PATCH] Fix Login With Device without MasterPassword

It looks like either something changed in the latest v2023.8.x versions,
or when using Biometrics to login, but the MasterPasswordHash is an
optional value during the Approve action.

This PR makes the MasterPasswordHash an optional value which resolves
this issues. Bitwarden works the same way.

I also changed the EncKey to an Option in the database since empty
strings as a default value is not nice in databases, better to use
`null` in these cases.

Fixes #3819
---
 .../down.sql                                  |  0
 .../up.sql                                    |  5 ++++
 .../down.sql                                  |  0
 .../up.sql                                    |  5 ++++
 .../down.sql                                  |  0
 .../up.sql                                    | 29 +++++++++++++++++++
 src/api/core/accounts.rs                      |  4 +--
 src/db/models/auth_request.rs                 |  8 ++---
 src/db/schemas/mysql/schema.rs                |  5 ++--
 src/db/schemas/postgresql/schema.rs           |  5 ++--
 src/db/schemas/sqlite/schema.rs               |  4 +--
 11 files changed, 53 insertions(+), 12 deletions(-)
 create mode 100644 migrations/mysql/2023-09-01-170620_update_auth_request_table/down.sql
 create mode 100644 migrations/mysql/2023-09-01-170620_update_auth_request_table/up.sql
 create mode 100644 migrations/postgresql/2023-09-01-170620_update_auth_request_table/down.sql
 create mode 100644 migrations/postgresql/2023-09-01-170620_update_auth_request_table/up.sql
 create mode 100644 migrations/sqlite/2023-09-01-170620_update_auth_request_table/down.sql
 create mode 100644 migrations/sqlite/2023-09-01-170620_update_auth_request_table/up.sql

diff --git a/migrations/mysql/2023-09-01-170620_update_auth_request_table/down.sql b/migrations/mysql/2023-09-01-170620_update_auth_request_table/down.sql
new file mode 100644
index 00000000..e69de29b
diff --git a/migrations/mysql/2023-09-01-170620_update_auth_request_table/up.sql b/migrations/mysql/2023-09-01-170620_update_auth_request_table/up.sql
new file mode 100644
index 00000000..ef5cb01e
--- /dev/null
+++ b/migrations/mysql/2023-09-01-170620_update_auth_request_table/up.sql
@@ -0,0 +1,5 @@
+ALTER TABLE auth_requests
+MODIFY master_password_hash TEXT;
+
+ALTER TABLE auth_requests
+MODIFY enc_key TEXT;
diff --git a/migrations/postgresql/2023-09-01-170620_update_auth_request_table/down.sql b/migrations/postgresql/2023-09-01-170620_update_auth_request_table/down.sql
new file mode 100644
index 00000000..e69de29b
diff --git a/migrations/postgresql/2023-09-01-170620_update_auth_request_table/up.sql b/migrations/postgresql/2023-09-01-170620_update_auth_request_table/up.sql
new file mode 100644
index 00000000..5715316d
--- /dev/null
+++ b/migrations/postgresql/2023-09-01-170620_update_auth_request_table/up.sql
@@ -0,0 +1,5 @@
+ALTER TABLE auth_requests
+ALTER COLUMN master_password_hash DROP NOT NULL;
+
+ALTER TABLE auth_requests
+ALTER COLUMN enc_key DROP NOT NULL;
diff --git a/migrations/sqlite/2023-09-01-170620_update_auth_request_table/down.sql b/migrations/sqlite/2023-09-01-170620_update_auth_request_table/down.sql
new file mode 100644
index 00000000..e69de29b
diff --git a/migrations/sqlite/2023-09-01-170620_update_auth_request_table/up.sql b/migrations/sqlite/2023-09-01-170620_update_auth_request_table/up.sql
new file mode 100644
index 00000000..9fa0e5c2
--- /dev/null
+++ b/migrations/sqlite/2023-09-01-170620_update_auth_request_table/up.sql
@@ -0,0 +1,29 @@
+-- Create new auth_requests table with master_password_hash as nullable column
+CREATE TABLE auth_requests_new (
+    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,
+    master_password_hash        TEXT,
+    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)
+);
+
+-- Transfer current data to new table
+INSERT INTO	auth_requests_new SELECT * FROM auth_requests;
+
+-- Drop the old table
+DROP TABLE auth_requests;
+
+-- Rename the new table to the original name
+ALTER TABLE auth_requests_new RENAME TO auth_requests;
diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs
index 3feccd80..63df6194 100644
--- a/src/api/core/accounts.rs
+++ b/src/api/core/accounts.rs
@@ -1090,7 +1090,7 @@ async fn get_auth_request(uuid: &str, mut conn: DbConn) -> JsonResult {
 struct AuthResponseRequest {
     deviceIdentifier: String,
     key: String,
-    masterPasswordHash: String,
+    masterPasswordHash: Option<String>,
     requestApproved: bool,
 }
 
@@ -1111,7 +1111,7 @@ async fn put_auth_request(
     };
 
     auth_request.approved = Some(data.requestApproved);
-    auth_request.enc_key = data.key;
+    auth_request.enc_key = Some(data.key);
     auth_request.master_password_hash = data.masterPasswordHash;
     auth_request.response_device_id = Some(data.deviceIdentifier.clone());
     auth_request.save(&mut conn).await?;
diff --git a/src/db/models/auth_request.rs b/src/db/models/auth_request.rs
index 0b129ac1..2a004fb1 100644
--- a/src/db/models/auth_request.rs
+++ b/src/db/models/auth_request.rs
@@ -20,9 +20,9 @@ db_object! {
         pub access_code: String,
         pub public_key: String,
 
-        pub enc_key: String,
+        pub enc_key: Option<String>,
 
-        pub master_password_hash: String,
+        pub master_password_hash: Option<String>,
         pub approved: Option<bool>,
         pub creation_date: NaiveDateTime,
         pub response_date: Option<NaiveDateTime>,
@@ -53,8 +53,8 @@ impl AuthRequest {
             response_device_id: None,
             access_code,
             public_key,
-            enc_key: String::new(),
-            master_password_hash: String::new(),
+            enc_key: None,
+            master_password_hash: None,
             approved: None,
             creation_date: now,
             response_date: None,
diff --git a/src/db/schemas/mysql/schema.rs b/src/db/schemas/mysql/schema.rs
index c2b2c961..65036a08 100644
--- a/src/db/schemas/mysql/schema.rs
+++ b/src/db/schemas/mysql/schema.rs
@@ -297,8 +297,8 @@ table! {
         response_device_id -> Nullable<Text>,
         access_code -> Text,
         public_key -> Text,
-        enc_key -> Text,
-        master_password_hash -> Text,
+        enc_key -> Nullable<Text>,
+        master_password_hash -> Nullable<Text>,
         approved -> Nullable<Bool>,
         creation_date -> Timestamp,
         response_date -> Nullable<Timestamp>,
@@ -324,6 +324,7 @@ joinable!(users_collections -> collections (collection_uuid));
 joinable!(users_collections -> users (user_uuid));
 joinable!(users_organizations -> organizations (org_uuid));
 joinable!(users_organizations -> users (user_uuid));
+joinable!(users_organizations -> ciphers (org_uuid));
 joinable!(organization_api_key -> organizations (org_uuid));
 joinable!(emergency_access -> users (grantor_uuid));
 joinable!(groups -> organizations (organizations_uuid));
diff --git a/src/db/schemas/postgresql/schema.rs b/src/db/schemas/postgresql/schema.rs
index 4ae9e821..9d2fb55e 100644
--- a/src/db/schemas/postgresql/schema.rs
+++ b/src/db/schemas/postgresql/schema.rs
@@ -297,8 +297,8 @@ table! {
         response_device_id -> Nullable<Text>,
         access_code -> Text,
         public_key -> Text,
-        enc_key -> Text,
-        master_password_hash -> Text,
+        enc_key -> Nullable<Text>,
+        master_password_hash -> Nullable<Text>,
         approved -> Nullable<Bool>,
         creation_date -> Timestamp,
         response_date -> Nullable<Timestamp>,
@@ -324,6 +324,7 @@ joinable!(users_collections -> collections (collection_uuid));
 joinable!(users_collections -> users (user_uuid));
 joinable!(users_organizations -> organizations (org_uuid));
 joinable!(users_organizations -> users (user_uuid));
+joinable!(users_organizations -> ciphers (org_uuid));
 joinable!(organization_api_key -> organizations (org_uuid));
 joinable!(emergency_access -> users (grantor_uuid));
 joinable!(groups -> organizations (organizations_uuid));
diff --git a/src/db/schemas/sqlite/schema.rs b/src/db/schemas/sqlite/schema.rs
index 62c04e91..9d2fb55e 100644
--- a/src/db/schemas/sqlite/schema.rs
+++ b/src/db/schemas/sqlite/schema.rs
@@ -297,8 +297,8 @@ table! {
         response_device_id -> Nullable<Text>,
         access_code -> Text,
         public_key -> Text,
-        enc_key -> Text,
-        master_password_hash -> Text,
+        enc_key -> Nullable<Text>,
+        master_password_hash -> Nullable<Text>,
         approved -> Nullable<Bool>,
         creation_date -> Timestamp,
         response_date -> Nullable<Timestamp>,