From 36d793a3752e2f0b02f4cc42bedb9a1d9b76efc7 Mon Sep 17 00:00:00 2001 From: Marcos Spessatto Defendi Date: Mon, 22 Jan 2024 21:09:09 -0300 Subject: [PATCH] fix: ensure sessionId on Sessions documents (#31487) --- .changeset/clever-parrots-count.md | 5 +++ apps/meteor/app/api/server/api.ts | 32 +++++++++++-------- .../app/statistics/server/lib/SAUMonitor.ts | 2 +- .../externals/meteor/ddp-common.d.ts | 1 + apps/meteor/server/models/raw/Sessions.ts | 25 +++++++++------ 5 files changed, 40 insertions(+), 25 deletions(-) create mode 100644 .changeset/clever-parrots-count.md diff --git a/.changeset/clever-parrots-count.md b/.changeset/clever-parrots-count.md new file mode 100644 index 000000000000..cfc37f51719b --- /dev/null +++ b/.changeset/clever-parrots-count.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed a bug where some sessions were being saved without a sessionId diff --git a/apps/meteor/app/api/server/api.ts b/apps/meteor/app/api/server/api.ts index b74163903604..08e1ef17e348 100644 --- a/apps/meteor/app/api/server/api.ts +++ b/apps/meteor/app/api/server/api.ts @@ -108,6 +108,22 @@ const getRequestIP = (req: Request): string | null => { return forwardedFor[forwardedFor.length - httpForwardedCount]; }; +const generateConnection = ( + ipAddress: string, + httpHeaders: Record, +): { + id: string; + close: () => void; + clientAddress: string; + httpHeaders: Record; +} => ({ + id: Random.id(), + // eslint-disable-next-line @typescript-eslint/no-empty-function + close() {}, + httpHeaders, + clientAddress: ipAddress, +}); + let prometheusAPIUserAgent = false; export class APIClass extends Restivus { @@ -569,14 +585,7 @@ export class APIClass extends Restivus { let result; - const connection = { - id: Random.id(), - // eslint-disable-next-line @typescript-eslint/no-empty-function - close() {}, - token: this.token, - httpHeaders: this.request.headers, - clientAddress: this.requestIp, - }; + const connection = { ...generateConnection(this.requestIp, this.request.headers), token: this.token }; try { if (options.deprecationVersion) { @@ -761,12 +770,7 @@ export class APIClass extends Restivus { const args = loginCompatibility(this.bodyParams, request); const invocation = new DDPCommon.MethodInvocation({ - connection: { - // eslint-disable-next-line @typescript-eslint/no-empty-function - close() {}, - httpHeaders: this.request.headers, - clientAddress: getRequestIP(request) || '', - }, + connection: generateConnection(getRequestIP(request) || '', this.request.headers), }); let auth; diff --git a/apps/meteor/app/statistics/server/lib/SAUMonitor.ts b/apps/meteor/app/statistics/server/lib/SAUMonitor.ts index b3aa68337106..0db63a929491 100644 --- a/apps/meteor/app/statistics/server/lib/SAUMonitor.ts +++ b/apps/meteor/app/statistics/server/lib/SAUMonitor.ts @@ -146,7 +146,7 @@ export class SAUMonitorClass { const searchTerm = this._getSearchTerm(data); - await Sessions.insertOne({ ...data, searchTerm, createdAt: new Date() }); + await Sessions.createOrUpdate({ ...data, searchTerm }); } private async _finishSessionsFromDate(yesterday: Date, today: Date): Promise { diff --git a/apps/meteor/definition/externals/meteor/ddp-common.d.ts b/apps/meteor/definition/externals/meteor/ddp-common.d.ts index 3c1f3b854131..3a7f1538ab40 100644 --- a/apps/meteor/definition/externals/meteor/ddp-common.d.ts +++ b/apps/meteor/definition/externals/meteor/ddp-common.d.ts @@ -5,6 +5,7 @@ declare module 'meteor/ddp-common' { class MethodInvocation { constructor(options: { connection: { + id: string; close: () => void; clientAddress: string; httpHeaders: Record; diff --git a/apps/meteor/server/models/raw/Sessions.ts b/apps/meteor/server/models/raw/Sessions.ts index c02fc8b5de99..5fdd0ea6828d 100644 --- a/apps/meteor/server/models/raw/Sessions.ts +++ b/apps/meteor/server/models/raw/Sessions.ts @@ -1431,11 +1431,15 @@ export class SessionsRaw extends BaseRaw implements ISessionsModel { }; } + private isValidData(data: Omit): boolean { + return Boolean(data.year && data.month && data.day && data.sessionId && data.instanceId); + } + async createOrUpdate(data: Omit): Promise { // TODO: check if we should create a session when there is no loginToken or not const { year, month, day, sessionId, instanceId } = data; - if (!year || !month || !day || !sessionId || !instanceId) { + if (!this.isValidData(data)) { return; } @@ -1588,16 +1592,17 @@ export class SessionsRaw extends BaseRaw implements ISessionsModel { sessions.forEach((doc) => { const { year, month, day, sessionId, instanceId } = doc; delete doc._id; - - ops.push({ - updateOne: { - filter: { year, month, day, sessionId, instanceId }, - update: { - $set: doc, + if (this.isValidData(doc)) { + ops.push({ + updateOne: { + filter: { year, month, day, sessionId, instanceId }, + update: { + $set: doc, + }, + upsert: true, }, - upsert: true, - }, - }); + }); + } }); return this.col.bulkWrite(ops, { ordered: false });