fix: update /v1/users.logout to properly log out all user sessions (#37846)

This commit is contained in:
Ricardo Garim 2025-12-19 17:11:38 -03:00 committed by GitHub
parent cc3a99fa34
commit be80b724a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 24 additions and 1 deletions

View File

@ -0,0 +1,7 @@
---
'@rocket.chat/model-typings': patch
'@rocket.chat/models': patch
'@rocket.chat/meteor': patch
---
Fixes /v1/users.logout not marking user sessions as logged out, leaving stale sessions active.

View File

@ -1,6 +1,6 @@
import { MeteorError, Team, api, Calendar } from '@rocket.chat/core-services'; import { MeteorError, Team, api, Calendar } from '@rocket.chat/core-services';
import { type IExportOperation, type ILoginToken, type IPersonalAccessToken, type IUser, type UserStatus } from '@rocket.chat/core-typings'; import { type IExportOperation, type ILoginToken, type IPersonalAccessToken, type IUser, type UserStatus } from '@rocket.chat/core-typings';
import { Users, Subscriptions } from '@rocket.chat/models'; import { Users, Subscriptions, Sessions } from '@rocket.chat/models';
import { import {
isUserCreateParamsPOST, isUserCreateParamsPOST,
isUserSetActiveStatusParamsPOST, isUserSetActiveStatusParamsPOST,
@ -1283,6 +1283,8 @@ API.v1.addRoute(
throw new Meteor.Error('error-invalid-user-id', 'Invalid user id'); throw new Meteor.Error('error-invalid-user-id', 'Invalid user id');
} }
await Sessions.logoutAllByUserId(userId, this.userId);
void notifyOnUserChange({ clientAction: 'updated', id: userId, diff: { 'services.resume.loginTokens': [] } }); void notifyOnUserChange({ clientAction: 'updated', id: userId, diff: { 'services.resume.loginTokens': [] } });
return API.v1.success({ return API.v1.success({

View File

@ -144,6 +144,8 @@ export interface ISessionsModel extends IBaseModel<ISession> {
logoutBy?: IUser['_id']; logoutBy?: IUser['_id'];
}): Promise<UpdateResult | Document>; }): Promise<UpdateResult | Document>;
logoutAllByUserId(userId: IUser['_id'], logoutBy: IUser['_id']): Promise<UpdateResult | Document>;
createBatch(sessions: OptionalId<ISession>[]): Promise<BulkWriteResult | undefined>; createBatch(sessions: OptionalId<ISession>[]): Promise<BulkWriteResult | undefined>;
updateDailySessionById(_id: ISession['_id'], record: Partial<ISession>): Promise<UpdateResult>; updateDailySessionById(_id: ISession['_id'], record: Partial<ISession>): Promise<UpdateResult>;

View File

@ -1575,6 +1575,18 @@ export class SessionsRaw extends BaseRaw<ISession> implements ISessionsModel {
return this.updateMany({ userId, loginToken }, updateObj); return this.updateMany({ userId, loginToken }, updateObj);
} }
async logoutAllByUserId(userId: IUser['_id'], logoutBy: IUser['_id']): Promise<UpdateResult | Document> {
const logoutAt = new Date();
const updateObj = {
$set: {
logoutAt,
logoutBy,
},
};
return this.updateMany({ userId, logoutAt: { $exists: false } }, updateObj);
}
async createBatch(sessions: OptionalId<ISession>[]): Promise<BulkWriteResult | undefined> { async createBatch(sessions: OptionalId<ISession>[]): Promise<BulkWriteResult | undefined> {
if (!sessions || sessions.length === 0) { if (!sessions || sessions.length === 0) {
return; return;