Skip to content

Commit

Permalink
Merge branch 'new/account_sidebar_rewrite' of github.com:RocketChat/R…
Browse files Browse the repository at this point in the history
…ocket.Chat into new/rewrite_account_profile

* 'new/account_sidebar_rewrite' of github.com:RocketChat/Rocket.Chat:
  Fix sidenav close
  Regresion: Issue with reply button on broadcast channels (#18057)
  Regression: Infinite render loop on Setup Wizard (#18074)
  Regression: Improve Omnichannel Business Hours (#18050)
  Regression: Fix threads badge color indicators (#18048)
  Regression: Improve the logic to get request IPs (#18033)
  • Loading branch information
gabriellsh committed Jun 30, 2020
2 parents 1cf1f52 + 234fa85 commit 7de66a7
Show file tree
Hide file tree
Showing 82 changed files with 1,219 additions and 746 deletions.
32 changes: 27 additions & 5 deletions app/api/server/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,31 @@ let prometheusAPIUserAgent = false;

export let API = {};

const getRequestIP = (req) =>
req.headers['x-forwarded-for']
|| (req.connection && req.connection.remoteAddress)
|| (req.socket && req.socket.remoteAddress)
|| (req.connection && req.connection.socket && req.connection.socket.remoteAddress);
const getRequestIP = (req) => {
const socket = req.socket || req.connection?.socket;
const remoteAddress = req.headers['x-real-ip'] || socket?.remoteAddress || req.connection?.remoteAddress || null;
let forwardedFor = req.headers['x-forwarded-for'];

if (!socket) {
return remoteAddress || forwardedFor || null;
}

const httpForwardedCount = parseInt(process.env.HTTP_FORWARDED_COUNT) || 0;
if (httpForwardedCount <= 0) {
return remoteAddress;
}

if (!_.isString(forwardedFor)) {
return remoteAddress;
}

forwardedFor = forwardedFor.trim().split(/\s*,\s*/);
if (httpForwardedCount > forwardedFor.length) {
return remoteAddress;
}

return forwardedFor[forwardedFor.length - httpForwardedCount];
};

export class APIClass extends Restivus {
constructor(properties) {
Expand Down Expand Up @@ -462,6 +482,8 @@ export class APIClass extends Restivus {
const invocation = new DDPCommon.MethodInvocation({
connection: {
close() {},
httpHeaders: this.request.headers,
clientAddress: getRequestIP(this.request),
},
});

Expand Down
8 changes: 5 additions & 3 deletions app/authentication/server/lib/logLoginAttempts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ export const logFailedLoginAttempts = (login: ILoginAttempt): void => {
if (!settings.get('Login_Logs_ClientIp')) {
clientAddress = '-';
}
let forwardedFor = connection.httpHeaders['x-forwarded-for'];
let forwardedFor = connection.httpHeaders && connection.httpHeaders['x-forwarded-for'];
let realIp = connection.httpHeaders && connection.httpHeaders['x-real-ip'];
if (!settings.get('Login_Logs_ForwardedForIp')) {
forwardedFor = '-';
realIp = '-';
}
let userAgent = connection.httpHeaders['user-agent'];
let userAgent = connection.httpHeaders && connection.httpHeaders['user-agent'];
if (!settings.get('Login_Logs_UserAgent')) {
userAgent = '-';
}
console.log('Failed login detected - Username[%s] ClientAddress[%s] ForwardedFor[%s] UserAgent[%s]', user, clientAddress, forwardedFor, userAgent);
console.log('Failed login detected - Username[%s] ClientAddress[%s] ForwardedFor[%s] XRealIp[%s] UserAgent[%s]', user, clientAddress, forwardedFor, realIp, userAgent);
};
5 changes: 3 additions & 2 deletions app/authentication/server/lib/restrictLoginAttempts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { IUser } from '../../../../definition/IUser';
import { settings } from '../../../settings/server';
import { addMinutesToADate } from '../../../utils/lib/date.helper';
import Sessions from '../../../models/server/raw/Sessions';
import { getClientAddress } from '../../../../server/lib/getClientAddress';

export const isValidLoginAttemptByIp = async (ip: string): Promise<boolean> => {
const whitelist = String(settings.get('Block_Multiple_Failed_Logins_Ip_Whitelist')).split(',');
Expand Down Expand Up @@ -89,7 +90,7 @@ export const saveFailedLoginAttempts = async (login: ILoginAttempt): Promise<voi
};

await ServerEvents.insertOne({
ip: login.connection.clientAddress,
ip: getClientAddress(login.connection),
t: IServerEventType.FAILED_LOGIN_ATTEMPT,
ts: new Date(),
u: user,
Expand All @@ -98,7 +99,7 @@ export const saveFailedLoginAttempts = async (login: ILoginAttempt): Promise<voi

export const saveSuccessfulLogin = async (login: ILoginAttempt): Promise<void> => {
await ServerEvents.insertOne({
ip: login.connection.clientAddress,
ip: getClientAddress(login.connection),
t: IServerEventType.LOGIN,
ts: new Date(),
u: login.user,
Expand Down
3 changes: 2 additions & 1 deletion app/authentication/server/startup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
isValidLoginAttemptByIp,
} from '../lib/restrictLoginAttempts';
import './settings';
import { getClientAddress } from '../../../../server/lib/getClientAddress';

Accounts.config({
forbidClientAccountCreation: true,
Expand Down Expand Up @@ -296,7 +297,7 @@ Accounts.insertUserDoc = _.wrap(Accounts.insertUserDoc, function(insertUserDoc,
Accounts.validateLoginAttempt(function(login) {
login = callbacks.run('beforeValidateLogin', login);

if (!Promise.await(isValidLoginAttemptByIp(login.connection?.clientAddress))) {
if (!Promise.await(isValidLoginAttemptByIp(getClientAddress(login.connection)))) {
throw new Meteor.Error('error-login-blocked-for-ip', 'Login has been temporarily blocked For IP', {
function: 'Accounts.validateLoginAttempt',
});
Expand Down
13 changes: 11 additions & 2 deletions app/discussion/client/public/stylesheets/discussion.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,26 @@
flex-wrap: wrap;
}

.discussion-reply-lm {
padding: 4px 8px;
.discussion-reply-lm,
.reply-counter {
padding: 4px;

color: var(--color-gray);

font-size: 12px;
font-style: italic;

flex-grow: 0;
flex-shrink: 0;
}

.reply-counter {
color: var(--color-dark-light);

font-weight: 600;
margin-inline-start: 4px;
}

.discussions-list .load-more {
text-align: center;
text-transform: lowercase;
Expand Down
34 changes: 19 additions & 15 deletions app/livechat/client/views/app/business-hours/BusinessHours.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
import { IBusinessHour } from './IBusinessHour';
import { SingleBusinessHour } from './Single';
import { IBusinessHourBehavior } from './IBusinessHourBehavior';
import { SingleBusinessHourBehavior } from './Single';
import { ILivechatBusinessHour } from '../../../../../../definition/ILivechatBusinessHour';

class BusinessHoursManager {
private businessHour: IBusinessHour;
private behavior: IBusinessHourBehavior;

constructor(businessHour: IBusinessHour) {
this.setBusinessHourManager(businessHour);
constructor(businessHour: IBusinessHourBehavior) {
this.setBusinessHourBehavior(businessHour);
}

setBusinessHourManager(businessHour: IBusinessHour): void {
this.registerBusinessHourMethod(businessHour);
setBusinessHourBehavior(businessHour: IBusinessHourBehavior): void {
this.registerBusinessHourBehavior(businessHour);
}

registerBusinessHourMethod(businessHour: IBusinessHour): void {
this.businessHour = businessHour;
registerBusinessHourBehavior(behavior: IBusinessHourBehavior): void {
this.behavior = behavior;
}

getTemplate(): string {
return this.businessHour.getView();
return this.behavior.getView();
}

shouldShowCustomTemplate(businessHourData: ILivechatBusinessHour): boolean {
return this.businessHour.shouldShowCustomTemplate(businessHourData);
showCustomTemplate(businessHourData: ILivechatBusinessHour): boolean {
return this.behavior.showCustomTemplate(businessHourData);
}

shouldShowBackButton(): boolean {
return this.businessHour.shouldShowBackButton();
showBackButton(): boolean {
return this.behavior.showBackButton();
}

showTimezoneTemplate(): boolean {
return this.behavior.showTimezoneTemplate();
}
}

export const businessHourManager = new BusinessHoursManager(new SingleBusinessHour() as IBusinessHour);
export const businessHourManager = new BusinessHoursManager(new SingleBusinessHourBehavior());
7 changes: 0 additions & 7 deletions app/livechat/client/views/app/business-hours/IBusinessHour.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ILivechatBusinessHour } from '../../../../../../definition/ILivechatBusinessHour';

export interface IBusinessHourBehavior {
getView(): string;
showCustomTemplate(businessHourData: ILivechatBusinessHour): boolean;
showBackButton(): boolean;
showTimezoneTemplate(): boolean;
}
12 changes: 8 additions & 4 deletions app/livechat/client/views/app/business-hours/Single.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { IBusinessHour } from './IBusinessHour';
import { IBusinessHourBehavior } from './IBusinessHourBehavior';

export class SingleBusinessHour implements IBusinessHour {
export class SingleBusinessHourBehavior implements IBusinessHourBehavior {
getView(): string {
return 'livechatBusinessHoursForm';
}

shouldShowCustomTemplate(): boolean {
showCustomTemplate(): boolean {
return false;
}

shouldShowBackButton(): boolean {
showBackButton(): boolean {
return false;
}

showTimezoneTemplate(): boolean {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<template name="livechatBusinessHoursForm">
{{#requiresPermission 'view-livechat-business-hours'}}
<form class="rocket-form" id="businessHoursForm">
{{#if timezoneTemplate}}
{{> Template.dynamic template=timezoneTemplate data=data }}
{{/if}}

{{#if customFieldsTemplate}}
{{> Template.dynamic template=customFieldsTemplate data=data }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,19 @@ Template.livechatBusinessHoursForm.helpers({
return Template.instance().dayVars[day.day].open.get();
},
customFieldsTemplate() {
if (!businessHourManager.shouldShowCustomTemplate(Template.instance().businessHour.get())) {
if (!businessHourManager.showCustomTemplate(Template.instance().businessHour.get())) {
return;
}
return getCustomFormTemplate('livechatBusinessHoursForm');
},
timezoneTemplate() {
if (!businessHourManager.showTimezoneTemplate()) {
return;
}
return getCustomFormTemplate('livechatBusinessHoursTimezoneForm');
},
showBackButton() {
return businessHourManager.shouldShowBackButton();
return businessHourManager.showBackButton();
},
data() {
return Template.instance().businessHour;
Expand Down Expand Up @@ -157,24 +163,24 @@ Template.livechatBusinessHoursForm.onCreated(async function() {
...createDefaultBusinessHour(),
});
this.autorun(async () => {
if (FlowRouter.current().route.name.includes('new')) {
return;
}
const id = FlowRouter.getParam('_id');
const type = FlowRouter.getParam('type');
let url = 'livechat/business-hour';
if (id) {
url += `?_id=${ id }`;
if (id && type) {
url += `?_id=${ id }&type=${ type }`;
}
const { businessHour } = await APIClient.v1.get(url);
if (businessHour) {
this.businessHour.set(businessHour);
businessHour.workHours.forEach((d) => {
if (businessHour.timezone.name) {
this.dayVars[d.day].start.set(moment.utc(d.start.utc.time, 'HH:mm').tz(businessHour.timezone.name).format('HH:mm'));
this.dayVars[d.day].finish.set(moment.utc(d.finish.utc.time, 'HH:mm').tz(businessHour.timezone.name).format('HH:mm'));
} else {
this.dayVars[d.day].start.set(moment.utc(d.start.utc.time, 'HH:mm').local().format('HH:mm'));
this.dayVars[d.day].finish.set(moment.utc(d.finish.utc.time, 'HH:mm').local().format('HH:mm'));
}
this.dayVars[d.day].open.set(d.open);
});
if (!businessHour) {
return;
}
this.businessHour.set(businessHour);
businessHour.workHours.forEach((d) => {
this.dayVars[d.day].start.set(moment.utc(d.start.utc.time, 'HH:mm').tz(businessHour.timezone.name).format('HH:mm'));
this.dayVars[d.day].finish.set(moment.utc(d.finish.utc.time, 'HH:mm').tz(businessHour.timezone.name).format('HH:mm'));
this.dayVars[d.day].open.set(d.open);
});
});
});
4 changes: 2 additions & 2 deletions app/livechat/imports/server/rest/businessHours.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { findLivechatBusinessHour } from '../../../server/api/lib/businessHours'

API.v1.addRoute('livechat/business-hour', { authRequired: true }, {
get() {
const { _id } = this.queryParams;
const { businessHour } = Promise.await(findLivechatBusinessHour(this.userId, _id));
const { _id, type } = this.queryParams;
const { businessHour } = Promise.await(findLivechatBusinessHour(this.userId, _id, type));
return API.v1.success({
businessHour,
});
Expand Down
4 changes: 2 additions & 2 deletions app/livechat/server/api/lib/businessHours.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { hasPermissionAsync } from '../../../../authorization/server/functions/h
import { businessHourManager } from '../../business-hour';
import { ILivechatBusinessHour } from '../../../../../definition/ILivechatBusinessHour';

export async function findLivechatBusinessHour(userId: string, id?: string): Promise<Record<string, ILivechatBusinessHour>> {
export async function findLivechatBusinessHour(userId: string, id?: string, type?: string): Promise<Record<string, ILivechatBusinessHour>> {
if (!await hasPermissionAsync(userId, 'view-livechat-business-hours')) {
throw new Error('error-not-authorized');
}

return {
businessHour: await businessHourManager.getBusinessHour(id),
businessHour: await businessHourManager.getBusinessHour(id, type) as ILivechatBusinessHour,
};
}
Loading

0 comments on commit 7de66a7

Please sign in to comment.