Skip to content

Commit 79bbbd6

Browse files
authored
feat: auditing settings (#33935)
1 parent de6bd32 commit 79bbbd6

39 files changed

Lines changed: 504 additions & 127 deletions

File tree

apps/meteor/app/api/server/v1/assets.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Settings } from '@rocket.chat/models';
22
import { isAssetsUnsetAssetProps } from '@rocket.chat/rest-typings';
33

4+
import { updateAuditedByUser } from '../../../../server/settings/lib/auditedSettingUpdates';
45
import { RocketChatAssets, refreshClients } from '../../../assets/server';
56
import { notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener';
67
import { settings } from '../../../settings/server';
@@ -36,7 +37,12 @@ API.v1.addRoute(
3637

3738
const { key, value } = await RocketChatAssets.setAssetWithBuffer(fileBuffer, mimetype, assetName);
3839

39-
const { modifiedCount } = await Settings.updateValueById(key, value);
40+
const { modifiedCount } = await updateAuditedByUser({
41+
_id: this.userId,
42+
username: this.user.username!,
43+
ip: this.requestIp,
44+
useragent: this.request.headers['user-agent'] || '',
45+
})(Settings.updateValueById, key, value);
4046

4147
if (modifiedCount) {
4248
void notifyOnSettingChangedById(key);
@@ -68,7 +74,12 @@ API.v1.addRoute(
6874

6975
const { key, value } = await RocketChatAssets.unsetAsset(assetName);
7076

71-
const { modifiedCount } = await Settings.updateValueById(key, value);
77+
const { modifiedCount } = await updateAuditedByUser({
78+
_id: this.userId,
79+
username: this.user.username!,
80+
ip: this.requestIp,
81+
useragent: this.request.headers['user-agent'] || '',
82+
})(Settings.updateValueById, key, value);
7283

7384
if (modifiedCount) {
7485
void notifyOnSettingChangedById(key);

apps/meteor/app/api/server/v1/misc.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { v4 as uuidv4 } from 'uuid';
2020

2121
import { i18n } from '../../../../server/lib/i18n';
2222
import { SystemLogger } from '../../../../server/lib/logger/system';
23+
import { resetAuditedSettingByUser, updateAuditedByUser } from '../../../../server/settings/lib/auditedSettingUpdates';
2324
import { getLogs } from '../../../../server/stream/stdout';
2425
import { passwordPolicy } from '../../../lib/server';
2526
import { notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener';
@@ -683,20 +684,32 @@ API.v1.addRoute(
683684

684685
settingsIds.push('Deployment_FingerPrint_Verified');
685686

687+
const auditSettingOperation = updateAuditedByUser({
688+
_id: this.userId,
689+
username: this.user.username!,
690+
ip: this.requestIp,
691+
useragent: this.request.headers['user-agent'] || '',
692+
});
693+
686694
const promises = settingsIds.map((settingId) => {
687695
if (settingId === 'uniqueID') {
688-
return Settings.resetValueById('uniqueID', process.env.DEPLOYMENT_ID || uuidv4());
696+
return auditSettingOperation(Settings.resetValueById, 'uniqueID', process.env.DEPLOYMENT_ID || uuidv4());
689697
}
690698

691699
if (settingId === 'Cloud_Workspace_Access_Token_Expires_At') {
692-
return Settings.resetValueById('Cloud_Workspace_Access_Token_Expires_At', new Date(0));
700+
return auditSettingOperation(Settings.resetValueById, 'Cloud_Workspace_Access_Token_Expires_At', new Date(0));
693701
}
694702

695703
if (settingId === 'Deployment_FingerPrint_Verified') {
696-
return Settings.updateValueById('Deployment_FingerPrint_Verified', true);
704+
return auditSettingOperation(Settings.updateValueById, 'Deployment_FingerPrint_Verified', true);
697705
}
698706

699-
return Settings.resetValueById(settingId);
707+
return resetAuditedSettingByUser({
708+
_id: this.userId,
709+
username: this.user.username!,
710+
ip: this.requestIp,
711+
useragent: this.request.headers['user-agent'] || '',
712+
})(Settings.resetValueById, settingId);
700713
});
701714

702715
(await Promise.all(promises)).forEach((value, index) => {

apps/meteor/app/api/server/v1/settings.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { Meteor } from 'meteor/meteor';
1717
import type { FindOptions } from 'mongodb';
1818
import _ from 'underscore';
1919

20+
import { updateAuditedByUser } from '../../../../server/settings/lib/auditedSettingUpdates';
2021
import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
2122
import { disableCustomScripts } from '../../../lib/server/functions/disableCustomScripts';
2223
import { notifyOnSettingChanged, notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener';
@@ -200,9 +201,16 @@ API.v1.addRoute(
200201
return API.v1.success();
201202
}
202203

204+
const auditSettingOperation = updateAuditedByUser({
205+
_id: this.userId,
206+
username: this.user.username!,
207+
ip: this.requestIp,
208+
useragent: this.request.headers['user-agent'] || '',
209+
});
210+
203211
if (isSettingColor(setting) && isSettingsUpdatePropsColor(this.bodyParams)) {
204212
const updateOptionsPromise = Settings.updateOptionsById<ISettingColor>(this.urlParams._id, { editor: this.bodyParams.editor });
205-
const updateValuePromise = Settings.updateValueNotHiddenById(this.urlParams._id, this.bodyParams.value);
213+
const updateValuePromise = auditSettingOperation(Settings.updateValueNotHiddenById, this.urlParams._id, this.bodyParams.value);
206214

207215
const [updateOptionsResult, updateValueResult] = await Promise.all([updateOptionsPromise, updateValuePromise]);
208216

@@ -214,7 +222,12 @@ API.v1.addRoute(
214222
}
215223

216224
if (isSettingsUpdatePropDefault(this.bodyParams)) {
217-
const { matchedCount } = await Settings.updateValueNotHiddenById(this.urlParams._id, this.bodyParams.value);
225+
const { matchedCount } = await auditSettingOperation(
226+
Settings.updateValueNotHiddenById,
227+
this.urlParams._id,
228+
this.bodyParams.value,
229+
);
230+
218231
if (!matchedCount) {
219232
return API.v1.failure();
220233
}

apps/meteor/app/apps/server/bridges/settings.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { ISetting } from '@rocket.chat/apps-engine/definition/settings';
33
import { ServerSettingBridge } from '@rocket.chat/apps-engine/server/bridges/ServerSettingBridge';
44
import { Settings } from '@rocket.chat/models';
55

6+
import { updateAuditedByApp } from '../../../../server/settings/lib/auditedSettingUpdates';
67
import { notifyOnSettingChanged, notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener';
78

89
export class AppSettingBridge extends ServerSettingBridge {
@@ -56,7 +57,15 @@ export class AppSettingBridge extends ServerSettingBridge {
5657
throw new Error(`The setting "${setting.id}" is not readable.`);
5758
}
5859

59-
(await Settings.updateValueById(setting.id, setting.value)).modifiedCount && void notifyOnSettingChangedById(setting.id);
60+
if (
61+
(
62+
await updateAuditedByApp({
63+
_id: appId,
64+
})(Settings.updateValueById, setting.id, setting.value)
65+
).modifiedCount
66+
) {
67+
void notifyOnSettingChangedById(setting.id);
68+
}
6069
}
6170

6271
protected async incrementValue(id: string, value: number, appId: string): Promise<void> {

apps/meteor/app/authentication/server/startup/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ Accounts.insertUserDoc = async function (options, user) {
338338
if (!roles.includes('admin') && !hasAdmin) {
339339
roles.push('admin');
340340
if (settings.get('Show_Setup_Wizard') === 'pending') {
341+
// TODO: audit
341342
(await Settings.updateValueById('Show_Setup_Wizard', 'in_progress')).modifiedCount &&
342343
void notifyOnSettingChangedById('Show_Setup_Wizard');
343344
}

apps/meteor/app/cloud/server/functions/getOAuthAuthorizationUrl.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Settings } from '@rocket.chat/models';
22
import { Random } from '@rocket.chat/random';
33

4+
import { updateAuditedBySystem } from '../../../../server/settings/lib/auditedSettingUpdates';
45
import { notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener';
56
import { settings } from '../../../settings/server';
67
import { userScopes } from '../oauthScopes';
@@ -9,7 +10,9 @@ import { getRedirectUri } from './getRedirectUri';
910
export async function getOAuthAuthorizationUrl() {
1011
const state = Random.id();
1112

12-
await Settings.updateValueById('Cloud_Workspace_Registration_State', state);
13+
await updateAuditedBySystem({
14+
reason: 'getOAuthAuthorizationUrl',
15+
})(Settings.updateValueById, 'Cloud_Workspace_Registration_State', state);
1316

1417
void notifyOnSettingChangedById('Cloud_Workspace_Registration_State');
1518

apps/meteor/app/cloud/server/functions/removeWorkspaceRegistrationInfo.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Settings, WorkspaceCredentials } from '@rocket.chat/models';
22

33
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
4+
import { updateAuditedBySystem } from '../../../../server/settings/lib/auditedSettingUpdates';
45
import { notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener';
56

67
export async function removeWorkspaceRegistrationInfo() {
@@ -24,10 +25,12 @@ export async function removeWorkspaceRegistrationInfo() {
2425

2526
const promises = settingsIds.map((settingId) => {
2627
if (settingId === 'Show_Setup_Wizard') {
27-
return Settings.updateValueById('Show_Setup_Wizard', 'in_progress');
28+
return updateAuditedBySystem({
29+
reason: 'removeWorkspaceRegistrationInfo',
30+
})(Settings.updateValueById, 'Show_Setup_Wizard', 'in_progress');
2831
}
2932

30-
return Settings.resetValueById(settingId, null);
33+
return updateAuditedBySystem({ reason: 'removeWorkspaceRegistrationInfo' })(Settings.resetValueById, settingId, null);
3134
});
3235

3336
(await Promise.all(promises)).forEach((value, index) => {

apps/meteor/app/cloud/server/functions/saveRegistrationData.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { applyLicense } from '@rocket.chat/license';
22
import { Settings } from '@rocket.chat/models';
33

44
import { syncCloudData } from './syncWorkspace/syncCloudData';
5+
import { updateAuditedBySystem } from '../../../../server/settings/lib/auditedSettingUpdates';
56
import { notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener';
67
import { settings } from '../../../settings/server';
78

@@ -59,15 +60,24 @@ async function saveRegistrationDataBase({
5960
{ _id: 'Cloud_Workspace_Registration_Client_Uri', value: registration_client_uri },
6061
];
6162

62-
const promises = [...settingsData.map(({ _id, value }) => Settings.updateValueById(_id, value))];
63+
const promises = [
64+
...settingsData.map(({ _id, value }) =>
65+
updateAuditedBySystem({
66+
reason: 'saveRegistrationDataBase',
67+
})(Settings.updateValueById, _id, value),
68+
),
69+
];
6370

6471
(await Promise.all(promises)).forEach((value, index) => {
6572
if (value?.modifiedCount) {
6673
void notifyOnSettingChangedById(settingsData[index]._id);
6774
}
6875
});
6976

70-
// TODO: Why is this taking so long that needs a timeout?
77+
// Question: Why is this taking so long that needs a timeout?
78+
// Answer: we use cache that requires a 'roundtrip' through the db and the application
79+
// we need to make sure that the cache is updated before we continue the procedures
80+
// we don't actually need to wait a whole second for this, but look this is just a retry mechanism it doesn't mean that actually takes all this time
7181
for await (const retry of Array.from({ length: 10 })) {
7282
const isSettingsUpdated =
7383
settings.get('Register_Server') === true &&

apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { buildWorkspaceRegistrationData } from './buildRegistrationData';
55
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
66
import { syncWorkspace } from './syncWorkspace';
77
import { SystemLogger } from '../../../../server/lib/logger/system';
8+
import { updateAuditedBySystem } from '../../../../server/settings/lib/auditedSettingUpdates';
89
import { notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener';
910
import { settings } from '../../../settings/server';
1011

@@ -15,7 +16,6 @@ export async function startRegisterWorkspace(resend = false) {
1516

1617
return true;
1718
}
18-
1919
(await Settings.updateValueById('Register_Server', true)).modifiedCount && void notifyOnSettingChangedById('Register_Server');
2020

2121
const regInfo = await buildWorkspaceRegistrationData(undefined);
@@ -48,7 +48,9 @@ export async function startRegisterWorkspace(resend = false) {
4848
return false;
4949
}
5050

51-
await Settings.updateValueById('Cloud_Workspace_Id', payload.id);
51+
await updateAuditedBySystem({
52+
reason: 'startRegisterWorkspace',
53+
})(Settings.updateValueById, 'Cloud_Workspace_Id', payload.id);
5254

5355
return true;
5456
}

apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { supportedVersions as supportedVersionsFromBuild } from '../../../../uti
1212
import { buildVersionUpdateMessage } from '../../../../version-check/server/functions/buildVersionUpdateMessage';
1313
import { generateWorkspaceBearerHttpHeader } from '../getWorkspaceAccessToken';
1414
import { supportedVersionsChooseLatest } from './supportedVersionsChooseLatest';
15+
import { updateAuditedBySystem } from '../../../../../server/settings/lib/auditedSettingUpdates';
1516

1617
declare module '@rocket.chat/core-typings' {
1718
interface ILicenseV3 {
@@ -66,7 +67,15 @@ const cacheValueInSettings = <T extends SettingValue>(
6667
SystemLogger.debug(`Resetting cached value ${key} in settings`);
6768
const value = await fn();
6869

69-
(await Settings.updateValueById(key, value)).modifiedCount && void notifyOnSettingChangedById(key);
70+
if (
71+
(
72+
await updateAuditedBySystem({
73+
reason: 'cacheValueInSettings reset',
74+
})(Settings.updateValueById, key, value)
75+
).modifiedCount
76+
) {
77+
void notifyOnSettingChangedById(key);
78+
}
7079

7180
return value;
7281
};

0 commit comments

Comments
 (0)