fix: prevent loading page on reconnect (#33770)

Co-authored-by: Diego Sampaio <chinello@gmail.com>
pull/33742/head
Guilherme Gazzo 2 years ago
parent b0cc33add2
commit 5d236fa43b
  1. 6
      .changeset/pretty-ladybugs-sneeze.md
  2. 12
      apps/meteor/app/authentication/server/startup/index.js
  3. 5
      apps/meteor/app/ui-cached-collection/client/models/CachedCollection.ts
  4. 27
      ee/apps/ddp-streamer/src/DDPStreamer.ts

@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/ddp-streamer": patch
---
Fixes page loading during reconnections

@ -23,12 +23,24 @@ import { setAvatarFromServiceWithValidation } from '../../../lib/server/function
import { notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener';
import * as Mailer from '../../../mailer/server/api';
import { settings } from '../../../settings/server';
import { getBaseUserFields } from '../../../utils/server/functions/getBaseUserFields';
import { safeGetMeteorUser } from '../../../utils/server/functions/safeGetMeteorUser';
import { isValidAttemptByUser, isValidLoginAttemptByIp } from '../lib/restrictLoginAttempts';
Accounts.config({
forbidClientAccountCreation: true,
});
/**
* Accounts calls `_initServerPublications` and holds the `_defaultPublishFields`, without Object.assign its not possible
* to extend the projection
*
* the idea is to send all required fields to the client during login
* we tried `defaultFieldsSelector` , but it changes all Meteor.userAsync projections which is undesirable
*
*
* we are removing the status here because meteor send 'offline'
*/
Object.assign(Accounts._defaultPublishFields.projection, (({ status, ...rest }) => rest)(getBaseUserFields()));
Meteor.startup(() => {
settings.watchMultiple(['Accounts_LoginExpiration', 'Site_Name', 'From_Email'], () => {

@ -83,6 +83,9 @@ export class CachedCollection<T extends { _id: string }, U = T> extends Emitter<
CachedCollectionManager.onLogin(() => {
void this.init();
});
Accounts.onLogout(() => {
this.ready.set(false);
});
}
protected get eventName(): `${Name}-changed` | `${string}/${Name}-changed` {
@ -342,8 +345,6 @@ export class CachedCollection<T extends { _id: string }, U = T> extends Emitter<
}
async init() {
this.ready.set(false);
if (await this.loadFromCache()) {
this.trySync();
} else {

@ -2,6 +2,7 @@ import crypto from 'crypto';
import { MeteorService, Presence, ServiceClass } from '@rocket.chat/core-services';
import { InstanceStatus } from '@rocket.chat/instance-status';
import { Users } from '@rocket.chat/models';
import polka from 'polka';
import { throttle } from 'underscore';
import WebSocket from 'ws';
@ -123,12 +124,34 @@ export class DDPStreamer extends ServiceClass {
}
});
server.on(DDP_EVENTS.LOGGED, (info) => {
async function sendUserData(client: Client, userId: string) {
// TODO figure out what fields to send. maybe to to export function getBaseUserFields to a package
const loggedUser = await Users.findOneById(userId, {
projection: { name: 1, username: 1, settings: 1, roles: 1, active: 1, statusLivechat: 1, statusDefault: 1, status: 1 },
});
if (!loggedUser) {
return;
}
// using setImmediate here so login's method result is sent before we send the user data
setImmediate(async () => server.added(client, 'users', userId, loggedUser));
}
server.on(DDP_EVENTS.LOGGED, async (info: Client) => {
const { userId, connection } = info;
Presence.newConnection(userId, connection.id, nodeID);
if (!userId) {
throw new Error('User not logged in');
}
await Presence.newConnection(userId, connection.id, nodeID);
this.updateConnections();
// mimic Meteor's default publication that sends user data after login
await sendUserData(info, userId);
server.emit('presence', { userId, connection });
this.api?.broadcast('accounts.login', { userId, connection });
});

Loading…
Cancel
Save