diff --git a/public/language/en-GB/admin/manage/users.json b/public/language/en-GB/admin/manage/users.json
index 6a17cbf016..05fc3f043f 100644
--- a/public/language/en-GB/admin/manage/users.json
+++ b/public/language/en-GB/admin/manage/users.json
@@ -6,6 +6,7 @@
"validate-email": "Validate Email",
"send-validation-email": "Send Validation Email",
"password-reset-email": "Send Password Reset Email",
+ "force-password-reset": "Force Password Reset & Log User Out",
"ban": "Ban User(s)",
"temp-ban": "Ban User(s) Temporarily",
"unban": "Unban User(s)",
@@ -81,7 +82,9 @@
"alerts.confirm-remove-moderator": "Do you really want to remove this moderator?",
"alerts.remove-moderator-success": "User is no longer moderator.",
"alerts.confirm-validate-email": "Do you want to validate email(s) of these user(s)?",
+ "alerts.confirm-force-password-reset": "Are you sure you want to force the password reset and log out these user(s)?",
"alerts.validate-email-success": "Emails validated",
+ "alerts.validate-force-password-reset-success": "User(s) passwords have been reset and their existing sessions have been revoked.",
"alerts.password-reset-confirm": "Do you want to send password reset email(s) to these user(s)?",
"alerts.confirm-delete": "Warning!
Do you really want to delete user(s)?
This action is not reversable! Only the user account will be deleted, their posts and topics will remain.",
"alerts.delete-success": "User(s) Deleted!",
diff --git a/public/src/admin/manage/users.js b/public/src/admin/manage/users.js
index 9efb1807be..73e33b391b 100644
--- a/public/src/admin/manage/users.js
+++ b/public/src/admin/manage/users.js
@@ -175,6 +175,19 @@ define('admin/manage/users', ['translator', 'benchpress'], function (translator,
});
});
+ $('.force-password-reset').on('click', function () {
+ var uids = getSelectedUids();
+ if (!uids.length) {
+ return;
+ }
+
+ bootbox.confirm('[[admin/manage/users:alerts.confirm-force-password-reset]]', function (confirm) {
+ if (confirm) {
+ socket.emit('admin.user.forcePasswordReset', uids, done('[[admin/manage/users:alerts.validate-force-password-reset-success]]'));
+ }
+ });
+ });
+
$('.delete-user').on('click', function () {
var uids = getSelectedUids();
if (!uids.length) {
diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js
index efd193ede0..02ade56a89 100644
--- a/src/socket.io/admin/user.js
+++ b/src/socket.io/admin/user.js
@@ -126,6 +126,25 @@ User.sendPasswordResetEmail = function (socket, uids, callback) {
}, callback);
};
+User.forcePasswordReset = function (socket, uids, callback) {
+ if (!Array.isArray(uids)) {
+ return callback(new Error('[[error:invalid-data]]'));
+ }
+
+ uids = uids.filter(uid => parseInt(uid, 10));
+
+ async.each(uids, function (uid, next) {
+ async.waterfall([
+ function (next) {
+ user.setUserField(uid, 'passwordExpiry', Date.now(), next);
+ },
+ function (next) {
+ user.auth.revokeAllSessions(uid, next);
+ },
+ ], next);
+ }, callback);
+};
+
User.deleteUsers = function (socket, uids, callback) {
deleteUsers(socket, uids, function (uid, next) {
user.deleteAccount(uid, next);
diff --git a/src/views/admin/manage/users.tpl b/src/views/admin/manage/users.tpl
index 1490c8b1c4..4b65102352 100644
--- a/src/views/admin/manage/users.tpl
+++ b/src/views/admin/manage/users.tpl
@@ -11,6 +11,7 @@