Sfoglia il codice sorgente

Implement admin ability to enable/disable users

janost 4 anni fa
parent
commit
043aa27aa3

+ 0 - 0
migrations/mysql/2020-11-30-224000_add_user_enabled/down.sql


+ 1 - 0
migrations/mysql/2020-11-30-224000_add_user_enabled/up.sql

@@ -0,0 +1 @@
+ALTER TABLE users ADD COLUMN enabled BOOLEAN NOT NULL DEFAULT 1;

+ 0 - 0
migrations/postgresql/2020-11-30-224000_add_user_enabled/down.sql


+ 1 - 0
migrations/postgresql/2020-11-30-224000_add_user_enabled/up.sql

@@ -0,0 +1 @@
+ALTER TABLE users ADD COLUMN enabled BOOLEAN NOT NULL DEFAULT true;

+ 0 - 0
migrations/sqlite/2020-11-30-224000_add_user_enabled/down.sql


+ 1 - 0
migrations/sqlite/2020-11-30-224000_add_user_enabled/up.sql

@@ -0,0 +1 @@
+ALTER TABLE users ADD COLUMN enabled BOOLEAN NOT NULL DEFAULT 1;

+ 21 - 0
src/api/admin.rs

@@ -36,6 +36,8 @@ pub fn routes() -> Vec<Route> {
         logout,
         delete_user,
         deauth_user,
+        disable_user,
+        enable_user,
         remove_2fa,
         update_revision_users,
         post_config,
@@ -297,6 +299,7 @@ fn users_overview(_token: AdminToken, conn: DbConn) -> ApiResult<Html<String>> {
             usr["cipher_count"] = json!(Cipher::count_owned_by_user(&u.uuid, &conn));
             usr["attachment_count"] = json!(Attachment::count_by_user(&u.uuid, &conn));
             usr["attachment_size"] = json!(get_display_size(Attachment::size_by_user(&u.uuid, &conn) as i32));
+            usr["user_enabled"] = json!(u.enabled);
             usr
     }).collect();
 
@@ -319,6 +322,24 @@ fn deauth_user(uuid: String, _token: AdminToken, conn: DbConn) -> EmptyResult {
     user.save(&conn)
 }
 
+#[post("/users/<uuid>/disable")]
+fn disable_user(uuid: String, _token: AdminToken, conn: DbConn) -> EmptyResult {
+    let mut user = User::find_by_uuid(&uuid, &conn).map_res("User doesn't exist")?;
+    Device::delete_all_by_user(&user.uuid, &conn)?;
+    user.reset_security_stamp();
+    user.enabled = false;
+
+    user.save(&conn)
+}
+
+#[post("/users/<uuid>/enable")]
+fn enable_user(uuid: String, _token: AdminToken, conn: DbConn) -> EmptyResult {
+    let mut user = User::find_by_uuid(&uuid, &conn).map_res("User doesn't exist")?;
+    user.enabled = true;
+
+    user.save(&conn)
+}
+
 #[post("/users/<uuid>/remove-2fa")]
 fn remove_2fa(uuid: String, _token: AdminToken, conn: DbConn) -> EmptyResult {
     let mut user = User::find_by_uuid(&uuid, &conn).map_res("User doesn't exist")?;

+ 8 - 0
src/api/identity.rs

@@ -102,6 +102,14 @@ fn _password_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonResult
         )
     }
 
+    // Check if the user is disabled
+    if !user.enabled {
+        err!(
+            "This user has been disabled",
+            format!("IP: {}. Username: {}.", ip.ip, username)
+        )
+    }
+
     let now = Local::now();
 
     if user.verified_at.is_none() && CONFIG.mail_enabled() && CONFIG.signups_verify() {

+ 2 - 0
src/db/models/user.rs

@@ -11,6 +11,7 @@ db_object! {
     #[primary_key(uuid)]
     pub struct User {
         pub uuid: String,
+        pub enabled: bool,
         pub created_at: NaiveDateTime,
         pub updated_at: NaiveDateTime,
         pub verified_at: Option<NaiveDateTime>,
@@ -70,6 +71,7 @@ impl User {
 
         Self {
             uuid: crate::util::get_uuid(),
+            enabled: true,
             created_at: now,
             updated_at: now,
             verified_at: None,

+ 1 - 0
src/db/schemas/mysql/schema.rs

@@ -116,6 +116,7 @@ table! {
 table! {
     users (uuid) {
         uuid -> Text,
+        enabled -> Bool,
         created_at -> Datetime,
         updated_at -> Datetime,
         verified_at -> Nullable<Datetime>,

+ 1 - 0
src/db/schemas/postgresql/schema.rs

@@ -116,6 +116,7 @@ table! {
 table! {
     users (uuid) {
         uuid -> Text,
+        enabled -> Bool,
         created_at -> Timestamp,
         updated_at -> Timestamp,
         verified_at -> Nullable<Timestamp>,

+ 1 - 0
src/db/schemas/sqlite/schema.rs

@@ -116,6 +116,7 @@ table! {
 table! {
     users (uuid) {
         uuid -> Text,
+        enabled -> Bool,
         created_at -> Timestamp,
         updated_at -> Timestamp,
         verified_at -> Nullable<Timestamp>,

+ 26 - 0
src/static/templates/admin/users.hbs

@@ -22,6 +22,9 @@
                                 <strong>{{Name}}</strong>
                                 <span class="d-block">{{Email}}</span>
                                 <span class="d-block">
+                                    {{#unless user_enabled}}
+                                        <span class="badge badge-danger mr-2" title="User is disabled">Disabled</span>
+                                    {{/unless}}
                                     {{#if TwoFactorEnabled}}
                                         <span class="badge badge-success mr-2" title="2FA is enabled">2FA</span>
                                     {{/if}}
@@ -54,6 +57,11 @@
                             {{/if}}
                             <a class="d-block" href="#" onclick='deauthUser({{jsesc Id}})'>Deauthorize sessions</a>
                             <a class="d-block" href="#" onclick='deleteUser({{jsesc Id}}, {{jsesc Email}})'>Delete User</a>
+                            {{#if user_enabled}}
+                            <a class="d-block" href="#" onclick='disableUser({{jsesc Id}}, {{jsesc Email}})'>Disable User</a>
+                            {{else}}
+                            <a class="d-block" href="#" onclick='enableUser({{jsesc Id}}, {{jsesc Email}})'>Enable User</a>
+                            {{/if}}
                         </td>
                     </tr>
                     {{/each}}
@@ -113,6 +121,24 @@
             "Error deauthorizing sessions");
         return false;
     }
+    function disableUser(id, mail) {
+        var confirmed = confirm("Are you sure you want to disable user '" + mail + "'? This will also deauthorize their sessions.")
+        if (confirmed) {
+            _post("{{urlpath}}/admin/users/" + id + "/disable",
+                "User disabled successfully",
+                "Error disabling user");
+        }
+        return false;
+    }
+    function enableUser(id, mail) {
+        var confirmed = confirm("Are you sure you want to enable user '" + mail + "'?")
+        if (confirmed) {
+            _post("{{urlpath}}/admin/users/" + id + "/enable",
+                "User enabled successfully",
+                "Error enabling user");
+        }
+        return false;
+    }
     function updateRevisions() {
         _post("{{urlpath}}/admin/users/update_revision",
             "Success, clients will sync next time they connect",