Merge pull request #1247 from janost/admin-disable-user

Implement admin ability to enable/disable users
This commit is contained in:
Daniel García 2020-12-08 15:43:56 +01:00 committed by GitHub
commit 6ebc83c3b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 63 additions and 0 deletions

View File

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

View File

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

View File

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

View File

@ -36,6 +36,8 @@ pub fn routes() -> Vec<Route> {
logout, logout,
delete_user, delete_user,
deauth_user, deauth_user,
disable_user,
enable_user,
remove_2fa, remove_2fa,
update_revision_users, update_revision_users,
post_config, 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["cipher_count"] = json!(Cipher::count_owned_by_user(&u.uuid, &conn));
usr["attachment_count"] = json!(Attachment::count_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["attachment_size"] = json!(get_display_size(Attachment::size_by_user(&u.uuid, &conn) as i32));
usr["user_enabled"] = json!(u.enabled);
usr["created_at"] = json!(&u.created_at.format("%Y-%m-%d %H:%M:%S").to_string()); usr["created_at"] = json!(&u.created_at.format("%Y-%m-%d %H:%M:%S").to_string());
usr["last_active"] = match u.last_active(&conn) { usr["last_active"] = match u.last_active(&conn) {
Some(timestamp) => json!(timestamp.format("%Y-%m-%d %H:%M:%S").to_string()), Some(timestamp) => json!(timestamp.format("%Y-%m-%d %H:%M:%S").to_string()),
@ -324,6 +327,24 @@ fn deauth_user(uuid: String, _token: AdminToken, conn: DbConn) -> EmptyResult {
user.save(&conn) 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")] #[post("/users/<uuid>/remove-2fa")]
fn remove_2fa(uuid: String, _token: AdminToken, conn: DbConn) -> EmptyResult { 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")?; let mut user = User::find_by_uuid(&uuid, &conn).map_res("User doesn't exist")?;

View File

@ -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(); let now = Local::now();
if user.verified_at.is_none() && CONFIG.mail_enabled() && CONFIG.signups_verify() { if user.verified_at.is_none() && CONFIG.mail_enabled() && CONFIG.signups_verify() {

View File

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

View File

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

View File

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

View File

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

View File

@ -24,6 +24,9 @@
<span class="d-block">Created at: {{created_at}}</span> <span class="d-block">Created at: {{created_at}}</span>
<span class="d-block">Last active: {{last_active}}</span> <span class="d-block">Last active: {{last_active}}</span>
<span class="d-block"> <span class="d-block">
{{#unless user_enabled}}
<span class="badge badge-danger mr-2" title="User is disabled">Disabled</span>
{{/unless}}
{{#if TwoFactorEnabled}} {{#if TwoFactorEnabled}}
<span class="badge badge-success mr-2" title="2FA is enabled">2FA</span> <span class="badge badge-success mr-2" title="2FA is enabled">2FA</span>
{{/if}} {{/if}}
@ -56,6 +59,11 @@
{{/if}} {{/if}}
<a class="d-block" href="#" onclick='deauthUser({{jsesc Id}})'>Deauthorize sessions</a> <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> <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> </td>
</tr> </tr>
{{/each}} {{/each}}
@ -115,6 +123,24 @@
"Error deauthorizing sessions"); "Error deauthorizing sessions");
return false; 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() { function updateRevisions() {
_post("{{urlpath}}/admin/users/update_revision", _post("{{urlpath}}/admin/users/update_revision",
"Success, clients will sync next time they connect", "Success, clients will sync next time they connect",