fix: Prevent invalid sessions update (#35010)

pull/35043/head
Diego Sampaio 12 months ago
parent 5a5ffb0697
commit 19388a33ea
No known key found for this signature in database
GPG Key ID: B71D302EB7F5183C
  1. 5
      .changeset/four-pugs-move.md
  2. 19
      apps/meteor/app/statistics/server/lib/SAUMonitor.ts
  3. 12
      packages/model-typings/src/models/ISessionsModel.ts
  4. 22
      packages/models/src/models/Sessions.ts

@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---
Prevent a bug that caused all sessions being marked as logged out if some required value was missing due to a race condition.

@ -127,9 +127,26 @@ export class SAUMonitorClass {
if (!this.isRunning()) {
return;
}
if (!userId) {
logger.warn(`Received 'accounts.logout' event without 'userId'`);
return;
}
const { id: sessionId } = connection;
if (!sessionId) {
logger.warn(`Received 'accounts.logout' event without 'sessionId'`);
return;
}
const session = await Sessions.getLoggedInByUserIdAndSessionId<Pick<ISession, 'loginToken'>>(userId, sessionId, {
projection: { loginToken: 1 },
});
if (!session?.loginToken) {
throw new Error('Session not found');
}
await Sessions.logoutBySessionIdAndUserId({ sessionId, userId });
await Sessions.logoutBySessionIdAndUserId({ loginToken: session.loginToken, userId });
});
}

@ -7,7 +7,7 @@ import type {
DeviceManagementPopulatedSession,
DeviceManagementSession,
} from '@rocket.chat/core-typings';
import type { BulkWriteResult, Document, UpdateResult, FindCursor, OptionalId } from 'mongodb';
import type { BulkWriteResult, Document, FindOptions, UpdateResult, FindCursor, OptionalId } from 'mongodb';
import type { IBaseModel } from './IBaseModel';
@ -127,10 +127,10 @@ export interface ISessionsModel extends IBaseModel<ISession> {
logoutByInstanceIdAndSessionIdAndUserId(instanceId: string, sessionId: string, userId: string): Promise<UpdateResult>;
logoutBySessionIdAndUserId({
sessionId,
loginToken,
userId,
}: {
sessionId: ISession['sessionId'];
loginToken: ISession['loginToken'];
userId: IUser['_id'];
}): Promise<UpdateResult | Document>;
@ -149,4 +149,10 @@ export interface ISessionsModel extends IBaseModel<ISession> {
updateDailySessionById(_id: ISession['_id'], record: Partial<ISession>): Promise<UpdateResult>;
updateAllSessionsByDateToComputed({ start, end }: DestructuredRange): Promise<UpdateResult | Document>;
getLoggedInByUserIdAndSessionId<T extends Document = ISession>(
userId: string,
sessionId: string,
options?: FindOptions<T>,
): Promise<T | null>;
}

@ -25,6 +25,7 @@ import type {
IndexDescription,
UpdateResult,
OptionalId,
FindOptions,
} from 'mongodb';
import { getCollectionName } from '../index';
@ -1534,19 +1535,12 @@ export class SessionsRaw extends BaseRaw<ISession> implements ISessionsModel {
}
async logoutBySessionIdAndUserId({
sessionId,
loginToken,
userId,
}: {
sessionId: ISession['sessionId'];
loginToken: ISession['loginToken'];
userId: IUser['_id'];
}): Promise<UpdateResult | Document> {
const query = {
sessionId,
userId,
logoutAt: { $exists: false },
};
const session = await this.findOne<Pick<ISession, 'loginToken'>>(query, { projection: { loginToken: 1 } });
const logoutAt = new Date();
const updateObj = {
$set: {
@ -1556,7 +1550,7 @@ export class SessionsRaw extends BaseRaw<ISession> implements ISessionsModel {
},
};
return this.updateMany({ userId, loginToken: session?.loginToken }, updateObj);
return this.updateMany({ userId, loginToken }, updateObj);
}
async logoutByloginTokenAndUserId({
@ -1622,4 +1616,12 @@ export class SessionsRaw extends BaseRaw<ISession> implements ISessionsModel {
},
);
}
async getLoggedInByUserIdAndSessionId<T extends Document = ISession>(
userId: string,
sessionId: string,
options?: FindOptions<T>,
): Promise<T | null> {
return this.findOne({ userId, sessionId, logoutAt: { $exists: false } }, options);
}
}

Loading…
Cancel
Save