Chore: Convert Fiber models to async Step 1 (#23633)

Co-authored-by: Diego Sampaio <chinello@gmail.com>
Co-authored-by: Guilherme Gazzo <guilhermegazzo@gmail.com>
pull/23689/head
Rodrigo Nascimento 4 years ago committed by GitHub
parent 283d957788
commit f50609df0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      app/api/server/lib/integrations.ts
  2. 14
      app/api/server/lib/webdav.js
  3. 16
      app/api/server/lib/webdav.ts
  4. 22
      app/api/server/v1/channels.js
  5. 6
      app/api/server/v1/email-inbox.js
  6. 10
      app/api/server/v1/emoji-custom.js
  7. 22
      app/api/server/v1/groups.js
  8. 9
      app/api/server/v1/im.js
  9. 4
      app/api/server/v1/instances.ts
  10. 45
      app/api/server/v1/integrations.js
  11. 10
      app/api/server/v1/invites.js
  12. 24
      app/api/server/v1/permissions.ts
  13. 48
      app/api/server/v1/roles.ts
  14. 97
      app/api/server/v1/settings.ts
  15. 5
      app/apps/server/bridges/internal.ts
  16. 11
      app/apps/server/bridges/settings.ts
  17. 19
      app/apps/server/communication/rest.js
  18. 6
      app/apps/server/converters/settings.js
  19. 4
      app/apps/server/converters/uploads.js
  20. 17
      app/apps/server/cron.js
  21. 17
      app/authentication/server/lib/restrictLoginAttempts.ts
  22. 7
      app/authentication/server/startup/index.js
  23. 16
      app/authorization/client/hasPermission.ts
  24. 16
      app/authorization/server/functions/addUserRoles.ts
  25. 3
      app/authorization/server/functions/getRoles.js
  26. 4
      app/authorization/server/functions/getRoles.ts
  27. 3
      app/authorization/server/functions/getUsersInRole.js
  28. 14
      app/authorization/server/functions/getUsersInRole.ts
  29. 5
      app/authorization/server/functions/removeUserFromRoles.js
  30. 61
      app/authorization/server/functions/upsertPermissions.ts
  31. 14
      app/authorization/server/methods/addPermissionToRole.ts
  32. 9
      app/authorization/server/methods/addUserToRole.ts
  33. 14
      app/authorization/server/methods/deleteRole.ts
  34. 11
      app/authorization/server/methods/removeRoleFromPermission.ts
  35. 8
      app/authorization/server/methods/removeUserFromRole.js
  36. 6
      app/authorization/server/methods/saveRole.ts
  37. 25
      app/authorization/server/streamer/permissions/index.js
  38. 28
      app/authorization/server/streamer/permissions/index.ts
  39. 11
      app/autotranslate/server/permissions.js
  40. 9
      app/autotranslate/server/permissions.ts
  41. 12
      app/cas/server/cas_server.js
  42. 9
      app/channel-settings/server/functions/saveRoomName.js
  43. 14
      app/channel-settings/server/methods/saveRoomSettings.js
  44. 7
      app/cloud/server/functions/buildRegistrationData.js
  45. 7
      app/cloud/server/functions/startRegisterWorkspace.js
  46. 14
      app/cloud/server/functions/syncWorkspace.js
  47. 8
      app/cloud/server/methods.js
  48. 2
      app/crowd/server/crowd.js
  49. 8
      app/custom-sounds/server/methods/deleteCustomSound.js
  50. 12
      app/custom-sounds/server/methods/insertOrUpdateSound.js
  51. 6
      app/custom-sounds/server/methods/listCustomSounds.js
  52. 3
      app/discussion/server/permissions.ts
  53. 8
      app/emoji-custom/server/methods/deleteEmojiCustom.js
  54. 26
      app/emoji-custom/server/methods/insertOrUpdateEmoji.js
  55. 6
      app/emoji-custom/server/methods/listEmojiCustom.js
  56. 19
      app/federation/server/endpoints/dispatch.js
  57. 6
      app/federation/server/endpoints/requestFromLatest.js
  58. 4
      app/federation/server/endpoints/uploads.js
  59. 9
      app/federation/server/functions/addUser.js
  60. 15
      app/federation/server/functions/dashboard.js
  61. 69
      app/federation/server/functions/helpers.js
  62. 77
      app/federation/server/functions/helpers.ts
  63. 26
      app/federation/server/handler/index.js
  64. 2
      app/federation/server/hooks/afterCreateDirectRoom.js
  65. 2
      app/federation/server/hooks/afterCreateRoom.js
  66. 16
      app/federation/server/lib/crypt.js
  67. 8
      app/federation/server/lib/dns.js
  68. 8
      app/federation/server/lib/http.js
  69. 10
      app/federation/server/startup/generateKeys.js
  70. 30
      app/federation/server/startup/settings.ts
  71. 32
      app/file-upload/server/lib/FileUpload.js
  72. 6
      app/file-upload/server/lib/requests.js
  73. 6
      app/file-upload/server/methods/getS3FileUrl.js
  74. 5
      app/file-upload/server/methods/sendFileMessage.ts
  75. 12
      app/integrations/server/api/api.js
  76. 9
      app/integrations/server/lib/triggerHandler.js
  77. 15
      app/integrations/server/methods/clearIntegrationHistory.ts
  78. 13
      app/integrations/server/methods/incoming/addIncomingIntegration.js
  79. 15
      app/integrations/server/methods/incoming/deleteIncomingIntegration.ts
  80. 21
      app/integrations/server/methods/incoming/updateIncomingIntegration.js
  81. 11
      app/integrations/server/methods/outgoing/addOutgoingIntegration.js
  82. 17
      app/integrations/server/methods/outgoing/deleteOutgoingIntegration.ts
  83. 15
      app/integrations/server/methods/outgoing/replayOutgoingIntegration.ts
  84. 19
      app/integrations/server/methods/outgoing/updateOutgoingIntegration.js
  85. 9
      app/invites/server/functions/findOrCreateInvite.js
  86. 8
      app/invites/server/functions/listInvites.js
  87. 8
      app/invites/server/functions/removeInvite.js
  88. 9
      app/invites/server/functions/useInviteToken.js
  89. 7
      app/invites/server/functions/validateInviteToken.js
  90. 11
      app/lib/server/functions/deleteMessage.ts
  91. 13
      app/lib/server/functions/deleteUser.js
  92. 14
      app/lib/server/functions/relinquishRoomOwnerships.js
  93. 7
      app/lib/server/functions/setRoomAvatar.js
  94. 2
      app/lib/server/functions/setUserActiveStatus.js
  95. 5
      app/lib/server/functions/setUsername.js
  96. 5
      app/lib/server/lib/getRoomRoles.js
  97. 2
      app/lib/server/methods/deleteMessage.js
  98. 4
      app/lib/server/methods/deleteUserOwnAccount.js
  99. 12
      app/lib/server/methods/leaveRoom.ts
  100. 8
      app/lib/server/methods/refreshOAuthService.ts
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,7 +1,9 @@
import { Integrations } from '../../../models/server/raw';
import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { IIntegration } from '../../../../definition/IIntegration';
import { IUser } from '../../../../definition/IUser';
const hasIntegrationsPermission = async (userId, integration) => {
const hasIntegrationsPermission = async (userId: string, integration: IIntegration): Promise<boolean> => {
const type = integration.type === 'webhook-incoming' ? 'incoming' : 'outgoing';
if (await hasPermissionAsync(userId, `manage-${ type }-integrations`)) {
@ -15,7 +17,15 @@ const hasIntegrationsPermission = async (userId, integration) => {
return false;
};
export const findOneIntegration = async ({ userId, integrationId, createdBy }) => {
export const findOneIntegration = async ({
userId,
integrationId,
createdBy,
}: {
userId: string;
integrationId: string;
createdBy: IUser;
}): Promise<IIntegration> => {
const integration = await Integrations.findOneByIdAndCreatedByIfExists({ _id: integrationId, createdBy });
if (!integration) {
throw new Error('The integration does not exists.');

@ -1,14 +0,0 @@
import { WebdavAccounts } from '../../../models/server/raw';
export async function findWebdavAccountsByUserId({ uid }) {
return {
accounts: await WebdavAccounts.findWithUserId(uid, {
fields: {
_id: 1,
username: 1,
server_url: 1,
name: 1,
},
}).toArray(),
};
}

@ -0,0 +1,16 @@
import { WebdavAccounts } from '../../../models/server/raw';
import { IWebdavAccount } from '../../../../definition/IWebdavAccount';
export async function findWebdavAccountsByUserId({ uid }: { uid: string }): Promise<{ accounts: IWebdavAccount[] }> {
return {
accounts: await WebdavAccounts.findWithUserId(uid, {
projection: {
_id: 1,
username: 1,
// eslint-disable-next-line @typescript-eslint/camelcase
server_url: 1,
name: 1,
},
}).toArray(),
};
}

@ -2,7 +2,8 @@ import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';
import _ from 'underscore';
import { Rooms, Subscriptions, Messages, Uploads, Integrations, Users } from '../../../models/server';
import { Rooms, Subscriptions, Messages, Users } from '../../../models/server';
import { Integrations, Uploads } from '../../../models/server/raw';
import { canAccessRoom, hasPermission, hasAtLeastOnePermission, hasAllPermission } from '../../../authorization/server';
import { mountIntegrationQueryBasedOnPermissions } from '../../../integrations/server/lib/mountQueriesBasedOnPermission';
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
@ -294,19 +295,19 @@ API.v1.addRoute('channels.files', { authRequired: true }, {
const ourQuery = Object.assign({}, query, { rid: findResult._id });
const files = Uploads.find(ourQuery, {
const files = Promise.await(Uploads.find(ourQuery, {
sort: sort || { name: 1 },
skip: offset,
limit: count,
fields,
}).fetch();
}).toArray());
return API.v1.success({
files: files.map(addUserObjectToEveryObject),
count:
files.length,
offset,
total: Uploads.find(ourQuery).count(),
total: Promise.await(Uploads.find(ourQuery).count()),
});
},
});
@ -340,21 +341,24 @@ API.v1.addRoute('channels.getIntegrations', { authRequired: true }, {
}
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
const { sort, fields: projection, query } = this.parseJsonQuery();
ourQuery = Object.assign(mountIntegrationQueryBasedOnPermissions(this.userId), query, ourQuery);
const integrations = Integrations.find(ourQuery, {
const cursor = Integrations.find(ourQuery, {
sort: sort || { _createdAt: 1 },
skip: offset,
limit: count,
fields,
}).fetch();
projection,
});
const integrations = Promise.await(cursor.toArray());
const total = Promise.await(cursor.count());
return API.v1.success({
integrations,
count: integrations.length,
offset,
total: Integrations.find(ourQuery).count(),
total,
});
},
});

@ -3,7 +3,7 @@ import { check, Match } from 'meteor/check';
import { API } from '../api';
import { findEmailInboxes, findOneEmailInbox, insertOneOrUpdateEmailInbox } from '../lib/emailInbox';
import { hasPermission } from '../../../authorization/server/functions/hasPermission';
import { EmailInbox } from '../../../models';
import { EmailInbox } from '../../../models/server/raw';
import Users from '../../../models/server/models/Users';
import { sendTestEmailToInbox } from '../../../../server/features/EmailInbox/EmailInbox_Outgoing';
@ -79,12 +79,12 @@ API.v1.addRoute('email-inbox/:_id', { authRequired: true }, {
const { _id } = this.urlParams;
if (!_id) { throw new Error('error-invalid-param'); }
const emailInboxes = EmailInbox.findOneById(_id);
const emailInboxes = Promise.await(EmailInbox.findOneById(_id));
if (!emailInboxes) {
return API.v1.notFound();
}
EmailInbox.removeById(_id);
Promise.await(EmailInbox.removeById(_id));
return API.v1.success({ _id });
},
});

@ -1,6 +1,6 @@
import { Meteor } from 'meteor/meteor';
import { EmojiCustom } from '../../../models/server';
import { EmojiCustom } from '../../../models/server/raw';
import { API } from '../api';
import { getUploadFormData } from '../lib/getUploadFormData';
import { findEmojisCustom } from '../lib/emoji-custom';
@ -19,15 +19,15 @@ API.v1.addRoute('emoji-custom.list', { authRequired: true }, {
}
return API.v1.success({
emojis: {
update: EmojiCustom.find({ ...query, _updatedAt: { $gt: updatedSinceDate } }).fetch(),
remove: EmojiCustom.trashFindDeletedAfter(updatedSinceDate).fetch(),
update: Promise.await(EmojiCustom.find({ ...query, _updatedAt: { $gt: updatedSinceDate } }).toArray()),
remove: Promise.await(EmojiCustom.trashFindDeletedAfter(updatedSinceDate).toArray()),
},
});
}
return API.v1.success({
emojis: {
update: EmojiCustom.find(query).fetch(),
update: Promise.await(EmojiCustom.find(query).toArray()),
remove: [],
},
});
@ -88,7 +88,7 @@ API.v1.addRoute('emoji-custom.update', { authRequired: true }, {
throw new Meteor.Error('The required "_id" query param is missing.');
}
const emojiToUpdate = EmojiCustom.findOneById(fields._id);
const emojiToUpdate = Promise.await(EmojiCustom.findOneById(fields._id));
if (!emojiToUpdate) {
throw new Meteor.Error('Emoji not found.');
}

@ -3,7 +3,8 @@ import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';
import { mountIntegrationQueryBasedOnPermissions } from '../../../integrations/server/lib/mountQueriesBasedOnPermission';
import { Subscriptions, Rooms, Messages, Uploads, Integrations, Users } from '../../../models/server';
import { Subscriptions, Rooms, Messages, Users } from '../../../models/server';
import { Integrations, Uploads } from '../../../models/server/raw';
import { hasPermission, hasAtLeastOnePermission, canAccessRoom, hasAllPermission } from '../../../authorization/server';
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
import { API } from '../api';
@ -272,18 +273,18 @@ API.v1.addRoute('groups.files', { authRequired: true }, {
const ourQuery = Object.assign({}, query, { rid: findResult.rid });
const files = Uploads.find(ourQuery, {
const files = Promise.await(Uploads.find(ourQuery, {
sort: sort || { name: 1 },
skip: offset,
limit: count,
fields,
}).fetch();
}).toArray());
return API.v1.success({
files: files.map(addUserObjectToEveryObject),
count: files.length,
offset,
total: Uploads.find(ourQuery).count(),
total: Promise.await(Uploads.find(ourQuery).count()),
});
},
});
@ -312,21 +313,24 @@ API.v1.addRoute('groups.getIntegrations', { authRequired: true }, {
}
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
const { sort, fields: projection, query } = this.parseJsonQuery();
const ourQuery = Object.assign(mountIntegrationQueryBasedOnPermissions(this.userId), query, { channel: { $in: channelsToSearch } });
const integrations = Integrations.find(ourQuery, {
const cursor = Integrations.find(ourQuery, {
sort: sort || { _createdAt: 1 },
skip: offset,
limit: count,
fields,
}).fetch();
projection,
});
const integrations = Promise.await(cursor.toArray());
const total = Promise.await(cursor.count());
return API.v1.success({
integrations,
count: integrations.length,
offset,
total: Integrations.find(ourQuery).count(),
total,
});
},
});

@ -1,7 +1,8 @@
import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';
import { Subscriptions, Uploads, Users, Messages, Rooms } from '../../../models/server';
import { Subscriptions, Users, Messages, Rooms } from '../../../models/server';
import { Uploads } from '../../../models/server/raw';
import { canAccessRoom, hasPermission } from '../../../authorization/server';
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
import { settings } from '../../../settings/server';
@ -148,18 +149,18 @@ API.v1.addRoute(['dm.files', 'im.files'], { authRequired: true }, {
const ourQuery = Object.assign({}, query, { rid: findResult.room._id });
const files = Uploads.find(ourQuery, {
const files = Promise.await(Uploads.find(ourQuery, {
sort: sort || { name: 1 },
skip: offset,
limit: count,
fields,
}).fetch();
}).toArray());
return API.v1.success({
files: files.map(addUserObjectToEveryObject),
count: files.length,
offset,
total: Uploads.find(ourQuery).count(),
total: Promise.await(Uploads.find(ourQuery).count()),
});
},
});

@ -1,7 +1,7 @@
import { getInstanceConnection } from '../../../../server/stream/streamBroadcast';
import { hasPermission } from '../../../authorization/server';
import { API } from '../api';
import InstanceStatus from '../../../models/server/models/InstanceStatus';
import { InstanceStatus } from '../../../models/server/raw';
import { IInstanceStatus } from '../../../../definition/IInstanceStatus';
API.v1.addRoute('instances.get', { authRequired: true }, {
@ -10,7 +10,7 @@ API.v1.addRoute('instances.get', { authRequired: true }, {
return API.v1.unauthorized();
}
const instances = InstanceStatus.find().fetch();
const instances = Promise.await(InstanceStatus.find().toArray());
return API.v1.success({
instances: instances.map((instance: IInstanceStatus) => {

@ -2,7 +2,7 @@ import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';
import { hasAtLeastOnePermission } from '../../../authorization/server';
import { IntegrationHistory, Integrations } from '../../../models';
import { Integrations, IntegrationHistory } from '../../../models/server/raw';
import { API } from '../api';
import { mountIntegrationHistoryQueryBasedOnPermissions, mountIntegrationQueryBasedOnPermissions } from '../../../integrations/server/lib/mountQueriesBasedOnPermission';
import { findOneIntegration } from '../lib/integrations';
@ -63,21 +63,24 @@ API.v1.addRoute('integrations.history', { authRequired: true }, {
const { id } = this.queryParams;
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
const { sort, fields: projection, query } = this.parseJsonQuery();
const ourQuery = Object.assign(mountIntegrationHistoryQueryBasedOnPermissions(this.userId, id), query);
const history = IntegrationHistory.find(ourQuery, {
const cursor = IntegrationHistory.find(ourQuery, {
sort: sort || { _updatedAt: -1 },
skip: offset,
limit: count,
fields,
}).fetch();
projection,
});
const history = Promise.await(cursor.toArray());
const total = Promise.await(cursor.count());
return API.v1.success({
history,
offset,
items: history.length,
total: IntegrationHistory.find(ourQuery).count(),
total,
});
},
});
@ -94,21 +97,25 @@ API.v1.addRoute('integrations.list', { authRequired: true }, {
}
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
const { sort, fields: projection, query } = this.parseJsonQuery();
const ourQuery = Object.assign(mountIntegrationQueryBasedOnPermissions(this.userId), query);
const integrations = Integrations.find(ourQuery, {
const cursor = Integrations.find(ourQuery, {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
fields,
}).fetch();
projection,
});
const total = Promise.await(cursor.count());
const integrations = Promise.await(cursor.toArray());
return API.v1.success({
integrations,
offset,
items: integrations.length,
total: Integrations.find(ourQuery).count(),
total,
});
},
});
@ -138,9 +145,9 @@ API.v1.addRoute('integrations.remove', { authRequired: true }, {
switch (this.bodyParams.type) {
case 'webhook-outgoing':
if (this.bodyParams.target_url) {
integration = Integrations.findOne({ urls: this.bodyParams.target_url });
integration = Promise.await(Integrations.findOne({ urls: this.bodyParams.target_url }));
} else if (this.bodyParams.integrationId) {
integration = Integrations.findOne({ _id: this.bodyParams.integrationId });
integration = Promise.await(Integrations.findOne({ _id: this.bodyParams.integrationId }));
}
if (!integration) {
@ -155,7 +162,7 @@ API.v1.addRoute('integrations.remove', { authRequired: true }, {
integration,
});
case 'webhook-incoming':
integration = Integrations.findOne({ _id: this.bodyParams.integrationId });
integration = Promise.await(Integrations.findOne({ _id: this.bodyParams.integrationId }));
if (!integration) {
return API.v1.failure('No integration found.');
@ -217,9 +224,9 @@ API.v1.addRoute('integrations.update', { authRequired: true }, {
switch (this.bodyParams.type) {
case 'webhook-outgoing':
if (this.bodyParams.target_url) {
integration = Integrations.findOne({ urls: this.bodyParams.target_url });
integration = Promise.await(Integrations.findOne({ urls: this.bodyParams.target_url }));
} else if (this.bodyParams.integrationId) {
integration = Integrations.findOne({ _id: this.bodyParams.integrationId });
integration = Promise.await(Integrations.findOne({ _id: this.bodyParams.integrationId }));
}
if (!integration) {
@ -229,10 +236,10 @@ API.v1.addRoute('integrations.update', { authRequired: true }, {
Meteor.call('updateOutgoingIntegration', integration._id, this.bodyParams);
return API.v1.success({
integration: Integrations.findOne({ _id: integration._id }),
integration: Promise.await(Integrations.findOne({ _id: integration._id })),
});
case 'webhook-incoming':
integration = Integrations.findOne({ _id: this.bodyParams.integrationId });
integration = Promise.await(Integrations.findOne({ _id: this.bodyParams.integrationId }));
if (!integration) {
return API.v1.failure('No integration found.');
@ -241,7 +248,7 @@ API.v1.addRoute('integrations.update', { authRequired: true }, {
Meteor.call('updateIncomingIntegration', integration._id, this.bodyParams);
return API.v1.success({
integration: Integrations.findOne({ _id: integration._id }),
integration: Promise.await(Integrations.findOne({ _id: integration._id })),
});
default:
return API.v1.failure('Invalid integration type.');

@ -7,7 +7,7 @@ import { validateInviteToken } from '../../../invites/server/functions/validateI
API.v1.addRoute('listInvites', { authRequired: true }, {
get() {
const result = listInvites(this.userId);
const result = Promise.await(listInvites(this.userId));
return API.v1.success(result);
},
});
@ -15,7 +15,7 @@ API.v1.addRoute('listInvites', { authRequired: true }, {
API.v1.addRoute('findOrCreateInvite', { authRequired: true }, {
post() {
const { rid, days, maxUses } = this.bodyParams;
const result = findOrCreateInvite(this.userId, { rid, days, maxUses });
const result = Promise.await(findOrCreateInvite(this.userId, { rid, days, maxUses }));
return API.v1.success(result);
},
@ -24,7 +24,7 @@ API.v1.addRoute('findOrCreateInvite', { authRequired: true }, {
API.v1.addRoute('removeInvite/:_id', { authRequired: true }, {
delete() {
const { _id } = this.urlParams;
const result = removeInvite(this.userId, { _id });
const result = Promise.await(removeInvite(this.userId, { _id }));
return API.v1.success(result);
},
@ -34,7 +34,7 @@ API.v1.addRoute('useInviteToken', { authRequired: true }, {
post() {
const { token } = this.bodyParams;
// eslint-disable-next-line react-hooks/rules-of-hooks
const result = useInviteToken(this.userId, token);
const result = Promise.await(useInviteToken(this.userId, token));
return API.v1.success(result);
},
@ -46,7 +46,7 @@ API.v1.addRoute('validateInviteToken', { authRequired: false }, {
let valid = true;
try {
validateInviteToken(token);
Promise.await(validateInviteToken(token));
} catch (e) {
valid = false;
}

@ -1,31 +1,29 @@
import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';
import { hasPermission } from '../../../authorization';
import { Permissions, Roles } from '../../../models/server';
import { hasPermission } from '../../../authorization/server';
import { API } from '../api';
import { Permissions, Roles } from '../../../models/server/raw';
API.v1.addRoute('permissions.listAll', { authRequired: true }, {
get() {
const { updatedSince } = this.queryParams;
let updatedSinceDate;
let updatedSinceDate: Date | undefined;
if (updatedSince) {
if (isNaN(Date.parse(updatedSince))) {
throw new Meteor.Error('error-roomId-param-invalid', 'The "updatedSince" query parameter must be a valid date.');
} else {
updatedSinceDate = new Date(updatedSince);
}
updatedSinceDate = new Date(updatedSince);
}
let result;
Meteor.runAsUser(this.userId, () => { result = Meteor.call('permissions/get', updatedSinceDate); });
const result = Promise.await(Meteor.call('permissions/get', updatedSinceDate));
if (Array.isArray(result)) {
result = {
return API.v1.success({
update: result,
remove: [],
};
});
}
return API.v1.success(result);
@ -52,14 +50,14 @@ API.v1.addRoute('permissions.update', { authRequired: true }, {
Object.keys(this.bodyParams.permissions).forEach((key) => {
const element = this.bodyParams.permissions[key];
if (!Permissions.findOneById(element._id)) {
if (!Promise.await(Permissions.findOneById(element._id))) {
permissionNotFound = true;
}
Object.keys(element.roles).forEach((key) => {
const subelement = element.roles[key];
const subElement = element.roles[key];
if (!Roles.findOneById(subelement)) {
if (!Promise.await(Roles.findOneById(subElement))) {
roleNotFound = true;
}
});
@ -77,7 +75,7 @@ API.v1.addRoute('permissions.update', { authRequired: true }, {
Permissions.createOrUpdate(element._id, element.roles);
});
const result = Meteor.runAsUser(this.userId, () => Meteor.call('permissions/get'));
const result = Promise.await(Meteor.call('permissions/get'));
return API.v1.success({
permissions: result,

@ -1,15 +1,16 @@
import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';
import { Roles, Users } from '../../../models';
import { Users } from '../../../models/server';
import { API } from '../api';
import { getUsersInRole, hasPermission, hasRole } from '../../../authorization/server';
import { settings } from '../../../settings/server/index';
import { api } from '../../../../server/sdk/api';
import { Roles } from '../../../models/server/raw';
API.v1.addRoute('roles.list', { authRequired: true }, {
get() {
const roles = Roles.find({}, { fields: { _updatedAt: 0 } }).fetch();
const roles = Promise.await(Roles.find({}, { fields: { _updatedAt: 0 } }).toArray());
return API.v1.success({ roles });
},
@ -25,8 +26,8 @@ API.v1.addRoute('roles.sync', { authRequired: true }, {
return API.v1.success({
roles: {
update: Roles.findByUpdatedDate(new Date(updatedSince), { fields: API.v1.defaultFieldsToExclude }).fetch(),
remove: Roles.trashFindDeletedAfter(new Date(updatedSince)).fetch(),
update: Promise.await(Roles.findByUpdatedDate(new Date(updatedSince), { fields: API.v1.defaultFieldsToExclude }).toArray()),
remove: Promise.await(Roles.trashFindDeletedAfter(new Date(updatedSince)).toArray()),
},
});
},
@ -52,15 +53,15 @@ API.v1.addRoute('roles.create', { authRequired: true }, {
throw new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed');
}
if (Roles.findOneByIdOrName(roleData.name)) {
if (Promise.await(Roles.findOneByIdOrName(roleData.name))) {
throw new Meteor.Error('error-duplicate-role-names-not-allowed', 'Role name already exists');
}
if (['Users', 'Subscriptions'].includes(roleData.scope) === false) {
roleData.scope = 'Users';
}
const roleId = Roles.createWithRandomId(roleData.name, roleData.scope, roleData.description, false, roleData.mandatory2fa);
const a = Roles.createWithRandomId(roleData.name, roleData.scope, roleData.description, false, roleData.mandatory2fa);
const roleId = Promise.await(a).insertedId;
if (settings.get('UI_DisplayRoles')) {
api.broadcast('user.roleUpdate', {
@ -70,7 +71,7 @@ API.v1.addRoute('roles.create', { authRequired: true }, {
}
return API.v1.success({
role: Roles.findOneByIdOrName(roleId, { fields: API.v1.defaultFieldsToExclude }),
role: Promise.await(Roles.findOneByIdOrName(roleId, { fields: API.v1.defaultFieldsToExclude })),
});
},
});
@ -95,7 +96,7 @@ API.v1.addRoute('roles.addUserToRole', { authRequired: true }, {
});
return API.v1.success({
role: Roles.findOneByIdOrName(this.bodyParams.roleName, { fields: API.v1.defaultFieldsToExclude }),
role: Promise.await(Roles.findOneByIdOrName(this.bodyParams.roleName, { fields: API.v1.defaultFieldsToExclude })),
});
},
});
@ -121,13 +122,14 @@ API.v1.addRoute('roles.getUsersInRole', { authRequired: true }, {
if (roomId && !hasPermission(this.userId, 'view-other-user-channels')) {
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
const users = getUsersInRole(role, roomId, {
const users = Promise.await(getUsersInRole(role, roomId, {
limit: count,
sort: { username: 1 },
skip: offset,
fields,
});
return API.v1.success({ users: users.fetch(), total: users.count() });
}));
return API.v1.success({ users: Promise.await(users.toArray()), total: Promise.await(users.count()) });
},
});
@ -149,7 +151,7 @@ API.v1.addRoute('roles.update', { authRequired: true }, {
mandatory2fa: this.bodyParams.mandatory2fa,
};
const role = Roles.findOneByIdOrName(roleData.roleId);
const role = Promise.await(Roles.findOneByIdOrName(roleData.roleId));
if (!role) {
throw new Meteor.Error('error-invalid-roleId', 'This role does not exist');
@ -160,7 +162,7 @@ API.v1.addRoute('roles.update', { authRequired: true }, {
}
if (roleData.name) {
const otherRole = Roles.findOneByIdOrName(roleData.name);
const otherRole = Promise.await(Roles.findOneByIdOrName(roleData.name));
if (otherRole && otherRole._id !== role._id) {
throw new Meteor.Error('error-duplicate-role-names-not-allowed', 'Role name already exists');
}
@ -172,7 +174,7 @@ API.v1.addRoute('roles.update', { authRequired: true }, {
}
}
Roles.updateById(roleData.roleId, roleData.name, roleData.scope, roleData.description, roleData.mandatory2fa);
Promise.await(Roles.updateById(roleData.roleId, roleData.name, roleData.scope, roleData.description, roleData.mandatory2fa));
if (settings.get('UI_DisplayRoles')) {
api.broadcast('user.roleUpdate', {
@ -182,7 +184,7 @@ API.v1.addRoute('roles.update', { authRequired: true }, {
}
return API.v1.success({
role: Roles.findOneByIdOrName(roleData.roleId, { fields: API.v1.defaultFieldsToExclude }),
role: Promise.await(Roles.findOneByIdOrName(roleData.roleId, { fields: API.v1.defaultFieldsToExclude })),
});
},
});
@ -197,7 +199,7 @@ API.v1.addRoute('roles.delete', { authRequired: true }, {
throw new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed');
}
const role = Roles.findOneByIdOrName(this.bodyParams.roleId);
const role = Promise.await(Roles.findOneByIdOrName(this.bodyParams.roleId));
if (!role) {
throw new Meteor.Error('error-invalid-roleId', 'This role does not exist');
@ -207,13 +209,13 @@ API.v1.addRoute('roles.delete', { authRequired: true }, {
throw new Meteor.Error('error-role-protected', 'Cannot delete a protected role');
}
const existingUsers = Roles.findUsersInRole(role.name, role.scope);
const existingUsers = Promise.await(Roles.findUsersInRole(role.name, role.scope));
if (existingUsers && existingUsers.count() > 0) {
if (existingUsers && Promise.await(existingUsers.count()) > 0) {
throw new Meteor.Error('error-role-in-use', 'Cannot delete role because it\'s in use');
}
Roles.remove(role._id);
Promise.await(Roles.removeById(role._id));
return API.v1.success();
},
@ -243,7 +245,7 @@ API.v1.addRoute('roles.removeUserFromRole', { authRequired: true }, {
throw new Meteor.Error('error-invalid-user', 'There is no user with this username');
}
const role = Roles.findOneByIdOrName(data.roleName);
const role = Promise.await(Roles.findOneByIdOrName(data.roleName));
if (!role) {
throw new Meteor.Error('error-invalid-roleId', 'This role does not exist');
@ -254,13 +256,13 @@ API.v1.addRoute('roles.removeUserFromRole', { authRequired: true }, {
}
if (role._id === 'admin') {
const adminCount = Roles.findUsersInRole('admin').count();
const adminCount = Promise.await(Promise.await(Roles.findUsersInRole('admin')).count());
if (adminCount === 1) {
throw new Meteor.Error('error-admin-required', 'You need to have at least one admin');
}
}
Roles.removeUserRoles(user._id, role.name, data.scope);
Promise.await(Roles.removeUserRoles(user._id, [role.name], data.scope));
if (settings.get('UI_DisplayRoles')) {
api.broadcast('user.roleUpdate', {

@ -3,24 +3,65 @@ import { Match, check } from 'meteor/check';
import { ServiceConfiguration } from 'meteor/service-configuration';
import _ from 'underscore';
import { Settings } from '../../../models/server';
import { hasPermission } from '../../../authorization';
import { Settings } from '../../../models/server/raw';
import { hasPermission } from '../../../authorization/server';
import { API } from '../api';
import { SettingsEvents, settings } from '../../../settings/server';
import { setValue } from '../../../settings/server/raw';
import { ISetting, ISettingColor, isSettingAction, isSettingColor } from '../../../../definition/ISetting';
const fetchSettings = (query, sort, offset, count, fields) => {
const settings = Settings.find(query, {
const fetchSettings = async (query: Parameters<typeof Settings.find>[0], sort: Parameters<typeof Settings.find>[1]['sort'], offset: Parameters<typeof Settings.find>[1]['skip'], count: Parameters<typeof Settings.find>[1]['limit'], fields: Parameters<typeof Settings.find>[1]['projection']): Promise<ISetting[]> => {
const settings = await Settings.find(query, {
sort: sort || { _id: 1 },
skip: offset,
limit: count,
fields: Object.assign({ _id: 1, value: 1, enterprise: 1, invalidValue: 1, modules: 1 }, fields),
}).fetch();
projection: { _id: 1, value: 1, enterprise: 1, invalidValue: 1, modules: 1, ...fields },
}).toArray() as unknown as ISetting[];
SettingsEvents.emit('fetch-settings', settings);
return settings;
};
type OauthCustomConfiguration = {
_id: string;
clientId?: string;
custom: unknown;
service?: string;
serverURL: unknown;
tokenPath: unknown;
identityPath: unknown;
authorizePath: unknown;
scope: unknown;
loginStyle: unknown;
tokenSentVia: unknown;
identityTokenSentVia: unknown;
keyField: unknown;
usernameField: unknown;
emailField: unknown;
nameField: unknown;
avatarField: unknown;
rolesClaim: unknown;
groupsClaim: unknown;
mapChannels: unknown;
channelsMap: unknown;
channelsAdmin: unknown;
mergeUsers: unknown;
mergeRoles: unknown;
accessTokenParam: unknown;
showButton: unknown;
appId: unknown;
consumerKey: unknown;
clientConfig: unknown;
buttonLabelText: unknown;
buttonLabelColor: unknown;
buttonColor: unknown;
}
const isOauthCustomConfiguration = (config: any): config is OauthCustomConfiguration => Boolean(config);
// settings endpoints
API.v1.addRoute('settings.public', { authRequired: false }, {
get() {
@ -34,7 +75,7 @@ API.v1.addRoute('settings.public', { authRequired: false }, {
ourQuery = Object.assign({}, query, ourQuery);
const settings = fetchSettings(ourQuery, sort, offset, count, fields);
const settings = Promise.await(fetchSettings(ourQuery, sort, offset, count, fields));
return API.v1.success({
settings,
@ -47,11 +88,15 @@ API.v1.addRoute('settings.public', { authRequired: false }, {
API.v1.addRoute('settings.oauth', { authRequired: false }, {
get() {
const mountOAuthServices = () => {
const mountOAuthServices = (): object => {
const oAuthServicesEnabled = ServiceConfiguration.configurations.find({}, { fields: { secret: 0 } }).fetch();
return oAuthServicesEnabled.map((service) => {
if (service.custom || ['saml', 'cas', 'wordpress'].includes(service.service)) {
if (!isOauthCustomConfiguration(service)) {
return service;
}
if (service.custom || (service.service && ['saml', 'cas', 'wordpress'].includes(service.service))) {
return { ...service };
}
@ -93,7 +138,7 @@ API.v1.addRoute('settings', { authRequired: true }, {
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
let ourQuery = {
let ourQuery: Parameters<typeof Settings.find>[0] = {
hidden: { $ne: true },
};
@ -103,7 +148,7 @@ API.v1.addRoute('settings', { authRequired: true }, {
ourQuery = Object.assign({}, query, ourQuery);
const settings = fetchSettings(ourQuery, sort, offset, count, fields);
const settings = Promise.await(fetchSettings(ourQuery, sort, offset, count, fields));
return API.v1.success({
settings,
@ -119,26 +164,34 @@ API.v1.addRoute('settings/:_id', { authRequired: true }, {
if (!hasPermission(this.userId, 'view-privileged-setting')) {
return API.v1.unauthorized();
}
return API.v1.success(_.pick(Settings.findOneNotHiddenById(this.urlParams._id), '_id', 'value'));
const setting = Promise.await(Settings.findOneNotHiddenById(this.urlParams._id));
if (!setting) {
return API.v1.failure();
}
return API.v1.success(_.pick(setting, '_id', 'value'));
},
post: {
twoFactorRequired: true,
action() {
action(this: any): void {
if (!hasPermission(this.userId, 'edit-privileged-setting')) {
return API.v1.unauthorized();
}
// allow special handling of particular setting types
const setting = Settings.findOneNotHiddenById(this.urlParams._id);
if (setting.type === 'action' && this.bodyParams && this.bodyParams.execute) {
const setting = Promise.await(Settings.findOneNotHiddenById(this.urlParams._id));
if (!setting) {
return API.v1.failure();
}
if (isSettingAction(setting) && this.bodyParams && this.bodyParams.execute) {
// execute the configured method
Meteor.call(setting.value);
return API.v1.success();
}
if (setting.type === 'color' && this.bodyParams && this.bodyParams.editor && this.bodyParams.value) {
Settings.updateOptionsById(this.urlParams._id, { editor: this.bodyParams.editor });
if (isSettingColor(setting) && this.bodyParams && this.bodyParams.editor && this.bodyParams.value) {
Settings.updateOptionsById<ISettingColor>(this.urlParams._id, { editor: this.bodyParams.editor });
Settings.updateValueNotHiddenById(this.urlParams._id, this.bodyParams.value);
return API.v1.success();
}
@ -146,8 +199,12 @@ API.v1.addRoute('settings/:_id', { authRequired: true }, {
check(this.bodyParams, {
value: Match.Any,
});
if (Settings.updateValueNotHiddenById(this.urlParams._id, this.bodyParams.value)) {
settings.set(Settings.findOneNotHiddenById(this.urlParams._id));
if (Promise.await(Settings.updateValueNotHiddenById(this.urlParams._id, this.bodyParams.value))) {
const s = Promise.await(Settings.findOneNotHiddenById(this.urlParams._id));
if (!s) {
return API.v1.failure();
}
settings.set(s);
setValue(this.urlParams._id, this.bodyParams.value);
return API.v1.success();
}

@ -2,8 +2,9 @@ import { InternalBridge } from '@rocket.chat/apps-engine/server/bridges/Internal
import { ISetting } from '@rocket.chat/apps-engine/definition/settings';
import { AppServerOrchestrator } from '../orchestrator';
import { Subscriptions, Settings } from '../../../models/server';
import { Subscriptions } from '../../../models/server';
import { ISubscription } from '../../../../definition/ISubscription';
import { Settings } from '../../../models/server/raw';
export class AppInternalBridge extends InternalBridge {
// eslint-disable-next-line no-empty-function
@ -30,7 +31,7 @@ export class AppInternalBridge extends InternalBridge {
}
protected async getWorkspacePublicKey(): Promise<ISetting> {
const publicKeySetting = Settings.findById('Cloud_Workspace_PublicKey').fetch()[0];
const publicKeySetting = await Settings.findOneById('Cloud_Workspace_PublicKey');
return this.orch.getConverters()?.get('settings').convertToApp(publicKeySetting);
}

@ -1,7 +1,7 @@
import { ISetting } from '@rocket.chat/apps-engine/definition/settings';
import { ServerSettingBridge } from '@rocket.chat/apps-engine/server/bridges/ServerSettingBridge';
import { Settings } from '../../../models/server';
import { Settings } from '../../../models/server/raw';
import { AppServerOrchestrator } from '../orchestrator';
export class AppSettingBridge extends ServerSettingBridge {
@ -13,9 +13,8 @@ export class AppSettingBridge extends ServerSettingBridge {
protected async getAll(appId: string): Promise<Array<ISetting>> {
this.orch.debugLog(`The App ${ appId } is getting all the settings.`);
return Settings.find({ secret: false })
.fetch()
.map((s: ISetting) => this.orch.getConverters()?.get('settings').convertToApp(s));
const settings = await Settings.find({ secret: false }).toArray();
return settings.map((s) => this.orch.getConverters()?.get('settings').convertToApp(s));
}
protected async getOneById(id: string, appId: string): Promise<ISetting> {
@ -46,8 +45,8 @@ export class AppSettingBridge extends ServerSettingBridge {
protected async isReadableById(id: string, appId: string): Promise<boolean> {
this.orch.debugLog(`The App ${ appId } is checking if they can read the setting ${ id }.`);
return !Settings.findOneById(id).secret;
const setting = await Settings.findOneById(id);
return Boolean(setting && !setting.secret);
}
protected async updateOne(setting: ISetting & { id: string }, appId: string): Promise<void> {

@ -6,9 +6,10 @@ import { getUploadFormData } from '../../../api/server/lib/getUploadFormData';
import { getWorkspaceAccessToken, getUserCloudAccessToken } from '../../../cloud/server';
import { settings } from '../../../settings/server';
import { Info } from '../../../utils';
import { Settings, Users } from '../../../models/server';
import { Users } from '../../../models/server';
import { Apps } from '../orchestrator';
import { formatAppInstanceForRest } from '../../lib/misc/formatAppInstanceForRest';
import { Settings } from '../../../models/server/raw';
const appsEngineVersionForMarketplace = Info.marketplaceApiVersion.replace(/-.*/g, '');
const getDefaultHeaders = () => ({
@ -67,7 +68,7 @@ export class AppsRestApi {
// Gets the Apps from the marketplace
if (this.queryParams.marketplace) {
const headers = getDefaultHeaders();
const token = getWorkspaceAccessToken();
const token = Promise.await(getWorkspaceAccessToken());
if (token) {
headers.Authorization = `Bearer ${ token }`;
}
@ -91,7 +92,7 @@ export class AppsRestApi {
if (this.queryParams.categories) {
const headers = getDefaultHeaders();
const token = getWorkspaceAccessToken();
const token = Promise.await(getWorkspaceAccessToken());
if (token) {
headers.Authorization = `Bearer ${ token }`;
}
@ -187,7 +188,7 @@ export class AppsRestApi {
});
const marketplacePromise = new Promise((resolve, reject) => {
const token = getWorkspaceAccessToken();
const token = Promise.await(getWorkspaceAccessToken());
HTTP.get(`${ baseUrl }/v1/apps/${ this.bodyParams.appId }?appVersion=${ this.bodyParams.version }`, {
headers: {
@ -307,7 +308,7 @@ export class AppsRestApi {
const baseUrl = orchestrator.getMarketplaceUrl();
const headers = {};
const token = getWorkspaceAccessToken();
const token = Promise.await(getWorkspaceAccessToken());
if (token) {
headers.Authorization = `Bearer ${ token }`;
}
@ -337,7 +338,7 @@ export class AppsRestApi {
const baseUrl = orchestrator.getMarketplaceUrl();
const headers = {}; // DO NOT ATTACH THE FRAMEWORK/ENGINE VERSION HERE.
const token = getWorkspaceAccessToken();
const token = Promise.await(getWorkspaceAccessToken());
if (token) {
headers.Authorization = `Bearer ${ token }`;
}
@ -363,7 +364,7 @@ export class AppsRestApi {
const baseUrl = orchestrator.getMarketplaceUrl();
const headers = getDefaultHeaders();
const token = getWorkspaceAccessToken();
const token = Promise.await(getWorkspaceAccessToken());
if (token) {
headers.Authorization = `Bearer ${ token }`;
}
@ -507,12 +508,12 @@ export class AppsRestApi {
const baseUrl = orchestrator.getMarketplaceUrl();
const headers = getDefaultHeaders();
const token = getWorkspaceAccessToken();
const token = Promise.await(getWorkspaceAccessToken());
if (token) {
headers.Authorization = `Bearer ${ token }`;
}
const [workspaceIdSetting] = Settings.findById('Cloud_Workspace_Id').fetch();
const workspaceIdSetting = Promise.await(Settings.findOneById('Cloud_Workspace_Id'));
let result;
try {

@ -1,14 +1,14 @@
import { SettingType } from '@rocket.chat/apps-engine/definition/settings';
import { Settings } from '../../../models';
import { Settings } from '../../../models/server/raw';
export class AppSettingsConverter {
constructor(orch) {
this.orch = orch;
}
convertById(settingId) {
const setting = Settings.findOneNotHiddenById(settingId);
async convertById(settingId) {
const setting = await Settings.findOneNotHiddenById(settingId);
return this.convertToApp(setting);
}

@ -1,5 +1,5 @@
import { transformMappedData } from '../../lib/misc/transformMappedData';
import Uploads from '../../../models/server/models/Uploads';
import { Uploads } from '../../../models/server/raw';
export class AppUploadsConverter {
constructor(orch) {
@ -7,7 +7,7 @@ export class AppUploadsConverter {
}
convertById(id) {
const upload = Uploads.findOneById(id);
const upload = Promise.await(Uploads.findOneById(id));
return this.convertToApp(upload);
}

@ -6,8 +6,9 @@ import { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus';
import { Apps } from './orchestrator';
import { getWorkspaceAccessToken } from '../../cloud/server';
import { Settings, Users } from '../../models/server';
import { Users } from '../../models/server';
import { sendMessagesToAdmins } from '../../../server/lib/sendMessagesToAdmins';
import { Settings } from '../../models/server/raw';
const notifyAdminsAboutInvalidApps = Meteor.bindEnvironment(function _notifyAdminsAboutInvalidApps(apps) {
@ -27,7 +28,7 @@ const notifyAdminsAboutInvalidApps = Meteor.bindEnvironment(function _notifyAdmi
const rocketCatMessage = 'There is one or more apps in an invalid state. Go to Administration > Apps to review.';
const link = '/admin/apps';
sendMessagesToAdmins({
Promise.await(sendMessagesToAdmins({
msgs: ({ adminUser }) => ({ msg: `*${ TAPi18n.__(title, adminUser.language) }*\n${ TAPi18n.__(rocketCatMessage, adminUser.language) }` }),
banners: ({ adminUser }) => {
Users.removeBannerById(adminUser._id, { id });
@ -41,7 +42,7 @@ const notifyAdminsAboutInvalidApps = Meteor.bindEnvironment(function _notifyAdmi
link,
}];
},
});
}));
return apps;
});
@ -59,19 +60,19 @@ const notifyAdminsAboutRenewedApps = Meteor.bindEnvironment(function _notifyAdmi
const rocketCatMessage = 'There is one or more disabled apps with valid licenses. Go to Administration > Apps to review.';
sendMessagesToAdmins({
Promise.await(sendMessagesToAdmins({
msgs: ({ adminUser }) => ({ msg: `${ TAPi18n.__(rocketCatMessage, adminUser.language) }` }),
});
}));
});
export const appsUpdateMarketplaceInfo = Meteor.bindEnvironment(function _appsUpdateMarketplaceInfo() {
const token = getWorkspaceAccessToken();
const token = Promise.await(getWorkspaceAccessToken());
const baseUrl = Apps.getMarketplaceUrl();
const [workspaceIdSetting] = Settings.findById('Cloud_Workspace_Id').fetch();
const workspaceIdSetting = Promise.await(Settings.getValueById('Cloud_Workspace_Id'));
const currentSeats = Users.getActiveLocalUserCount();
const fullUrl = `${ baseUrl }/v1/workspaces/${ workspaceIdSetting.value }/apps?seats=${ currentSeats }`;
const fullUrl = `${ baseUrl }/v1/workspaces/${ workspaceIdSetting }/apps?seats=${ currentSeats }`;
const options = {
headers: {
Authorization: `Bearer ${ token }`,

@ -1,12 +1,10 @@
import moment from 'moment';
import { ILoginAttempt } from '../ILoginAttempt';
import { ServerEvents, Users, Rooms } from '../../../models/server/raw';
import { IServerEventType } from '../../../../definition/IServerEvent';
import { IUser } from '../../../../definition/IUser';
import { ServerEvents, Users, Rooms, Sessions } from '../../../models/server/raw';
import { IServerEventType, IServerEvent } from '../../../../definition/IServerEvent';
import { settings } from '../../../settings/server';
import { addMinutesToADate } from '../../../../lib/utils/addMinutesToADate';
import Sessions from '../../../models/server/raw/Sessions';
import { getClientAddress } from '../../../../server/lib/getClientAddress';
import { sendMessage } from '../../../lib/server/functions';
import { Logger } from '../../../logger/server';
@ -52,7 +50,7 @@ export const isValidLoginAttemptByIp = async (ip: string): Promise<boolean> => {
return true;
}
const lastLogin = await Sessions.findLastLoginByIp(ip) as {loginAt?: Date} | undefined;
const lastLogin = await Sessions.findLastLoginByIp(ip);
let failedAttemptsSinceLastLogin;
if (!lastLogin || !lastLogin.loginAt) {
@ -128,7 +126,7 @@ export const isValidAttemptByUser = async (login: ILoginAttempt): Promise<boolea
};
export const saveFailedLoginAttempts = async (login: ILoginAttempt): Promise<void> => {
const user: Partial<IUser> = {
const user: IServerEvent['u'] = {
_id: login.user?._id,
username: login.user?.username || login.methodArguments[0].user?.username,
};
@ -142,10 +140,15 @@ export const saveFailedLoginAttempts = async (login: ILoginAttempt): Promise<voi
};
export const saveSuccessfulLogin = async (login: ILoginAttempt): Promise<void> => {
const user: IServerEvent['u'] = {
_id: login.user?._id,
username: login.user?.username || login.methodArguments[0].user?.username,
};
await ServerEvents.insertOne({
ip: getClientAddress(login.connection),
t: IServerEventType.LOGIN,
ts: new Date(),
u: login.user,
u: user,
});
};

@ -8,8 +8,8 @@ import { escapeRegExp, escapeHTML } from '@rocket.chat/string-helpers';
import * as Mailer from '../../../mailer/server/api';
import { settings } from '../../../settings/server';
import { callbacks } from '../../../callbacks/server';
import { Roles, Users, Settings } from '../../../models/server';
import { Users as UsersRaw } from '../../../models/server/raw';
import { Users, Settings } from '../../../models/server';
import { Roles, Users as UsersRaw } from '../../../models/server/raw';
import { addUserRoles } from '../../../authorization/server';
import { getAvatarSuggestionForUser } from '../../../lib/server/functions';
import {
@ -186,8 +186,7 @@ Accounts.onCreateUser(function(options, user = {}) {
if (!user.active) {
const destinations = [];
Roles.findUsersInRole('admin').forEach((adminUser) => {
Promise.await(Roles.findUsersInRole('admin').toArray()).forEach((adminUser) => {
if (Array.isArray(adminUser.emails)) {
adminUser.emails.forEach((email) => {
destinations.push(`${ adminUser.name }<${ email.address }>`);

@ -7,11 +7,11 @@ import { IUser } from '../../../definition/IUser';
import { IRole } from '../../../definition/IRole';
import { IPermission } from '../../../definition/IPermission';
const isValidScope = (scope: IRole['scope']): scope is keyof typeof Models =>
const isValidScope = (scope: IRole['scope']): boolean =>
typeof scope === 'string' && scope in Models;
const createPermissionValidator = (quantifier: (predicate: (permissionId: IPermission['_id']) => boolean) => boolean) =>
(permissionIds: IPermission['_id'][], scope: IRole['scope'], userId: IUser['_id']): boolean => {
(permissionIds: IPermission['_id'][], scope: string | undefined, userId: IUser['_id']): boolean => {
const user: IUser | null = Models.Users.findOneById(userId, { fields: { roles: 1 } });
const checkEachPermission = quantifier.bind(permissionIds);
@ -34,7 +34,7 @@ const createPermissionValidator = (quantifier: (predicate: (permissionId: IPermi
return false;
}
const model = Models[roleScope];
const model = Models[roleScope as keyof typeof Models];
return model.isUserInRole && model.isUserInRole(userId, roleName, scope);
});
});
@ -46,8 +46,8 @@ const all = createPermissionValidator(Array.prototype.every);
const validatePermissions = (
permissions: IPermission['_id'] | IPermission['_id'][],
scope: IRole['scope'],
predicate: (permissionIds: IPermission['_id'][], scope: IRole['scope'], userId: IUser['_id']) => boolean,
scope: string | undefined,
predicate: (permissionIds: IPermission['_id'][], scope: string | undefined, userId: IUser['_id']) => boolean,
userId?: IUser['_id'] | null,
): boolean => {
userId = userId ?? Meteor.userId();
@ -65,17 +65,17 @@ const validatePermissions = (
export const hasAllPermission = (
permissions: IPermission['_id'] | IPermission['_id'][],
scope?: IRole['scope'],
scope?: string,
): boolean => validatePermissions(permissions, scope, all);
export const hasAtLeastOnePermission = (
permissions: IPermission['_id'] | IPermission['_id'][],
scope?: IRole['scope'],
scope?: string,
): boolean => validatePermissions(permissions, scope, atLeastOne);
export const userHasAllPermission = (
permissions: IPermission['_id'] | IPermission['_id'][],
scope?: IRole['scope'],
scope?: string,
userId?: IUser['_id'] | null,
): boolean => validatePermissions(permissions, scope, all, userId);

@ -2,9 +2,11 @@ import { Meteor } from 'meteor/meteor';
import _ from 'underscore';
import { getRoles } from './getRoles';
import { Users, Roles } from '../../../models';
import { Users } from '../../../models/server';
import { IRole, IUser } from '../../../../definition/IUser';
import { Roles } from '../../../models/server/raw';
export const addUserRoles = (userId, roleNames, scope) => {
export const addUserRoles = (userId: IUser['_id'], roleNames: IRole['name'][], scope?: string): boolean => {
if (!userId || !roleNames) {
return false;
}
@ -16,17 +18,19 @@ export const addUserRoles = (userId, roleNames, scope) => {
});
}
roleNames = [].concat(roleNames);
if (!Array.isArray(roleNames)) { // TODO: remove this check
roleNames = [roleNames];
}
const existingRoleNames = _.pluck(getRoles(), '_id');
const invalidRoleNames = _.difference(roleNames, existingRoleNames);
if (!_.isEmpty(invalidRoleNames)) {
for (const role of invalidRoleNames) {
Roles.createOrUpdate(role);
Promise.await(Roles.createOrUpdate(role));
}
}
Roles.addUserRoles(userId, roleNames, scope);
Promise.await(Roles.addUserRoles(userId, roleNames, scope));
return true;
};

@ -1,3 +0,0 @@
import { Roles } from '../../../models';
export const getRoles = () => Roles.find().fetch();

@ -0,0 +1,4 @@
import { IRole } from '../../../../definition/IUser';
import { Roles } from '../../../models/server/raw';
export const getRoles = (): IRole[] => Promise.await(Roles.find().toArray());

@ -1,3 +0,0 @@
import { Roles } from '../../../models';
export const getUsersInRole = (roleName, scope, options) => Roles.findUsersInRole(roleName, scope, options);

@ -0,0 +1,14 @@
import { Cursor, FindOneOptions, WithoutProjection } from 'mongodb';
import { IRole, IUser } from '../../../../definition/IUser';
import { Roles } from '../../../models/server/raw';
export function getUsersInRole(name: IRole['name'], scope?: string): Promise<Cursor<IUser>>;
export function getUsersInRole(name: IRole['name'], scope: string | undefined, options: WithoutProjection<FindOneOptions<IUser>>): Promise<Cursor<IUser>>;
export function getUsersInRole<P>(name: IRole['name'], scope: string | undefined, options: FindOneOptions<P extends IUser ? IUser : P>): Promise<Cursor<P>>;
export function getUsersInRole<P>(name: IRole['name'], scope: string | undefined, options?: any | undefined): Promise<Cursor<IUser | P>> { return Roles.findUsersInRole(name, scope, options); }

@ -2,7 +2,8 @@ import { Meteor } from 'meteor/meteor';
import _ from 'underscore';
import { getRoles } from './getRoles';
import { Users, Roles } from '../../../models';
import { Users } from '../../../models/server';
import { Roles } from '../../../models/server/raw';
export const removeUserFromRoles = (userId, roleNames, scope) => {
if (!userId || !roleNames) {
@ -27,7 +28,7 @@ export const removeUserFromRoles = (userId, roleNames, scope) => {
});
}
Roles.removeUserRoles(userId, roleNames, scope);
Promise.await(Roles.removeUserRoles(userId, roleNames, scope));
return true;
};

@ -1,11 +1,11 @@
/* eslint no-multi-spaces: 0 */
import Roles from '../../../models/server/models/Roles';
import Permissions from '../../../models/server/models/Permissions';
import Settings from '../../../models/server/models/Settings';
import { settings } from '../../../settings/server';
import { getSettingPermissionId, CONSTANTS } from '../../lib';
import { Permissions, Roles, Settings } from '../../../models/server/raw';
import { IPermission } from '../../../../definition/IPermission';
import { ISetting } from '../../../../definition/ISetting';
export const upsertPermissions = () => {
export const upsertPermissions = async (): Promise<void> => {
// Note:
// 1.if we need to create a role that can only edit channel message, but not edit group message
// then we can define edit-<type>-message instead of edit-message
@ -153,8 +153,8 @@ export const upsertPermissions = () => {
];
for (const permission of permissions) {
Permissions.create(permission._id, permission.roles);
for await (const permission of permissions) {
await Permissions.create(permission._id, permission.roles);
}
const defaultRoles = [
@ -171,29 +171,30 @@ export const upsertPermissions = () => {
{ name: 'livechat-manager', scope: 'Users', description: 'Livechat Manager' },
];
for (const role of defaultRoles) {
Roles.createOrUpdate(role.name, role.scope, role.description, true, false);
for await (const role of defaultRoles) {
await Roles.createOrUpdate(role.name, role.scope as 'Users' | 'Subscriptions', role.description, true, false);
}
const getPreviousPermissions = function(settingId) {
const previousSettingPermissions = {};
const getPreviousPermissions = async function(settingId?: string): Promise<Record<string, IPermission>> {
const previousSettingPermissions: {
[key: string]: IPermission;
} = {};
const selector = { level: CONSTANTS.SETTINGS_LEVEL };
if (settingId) {
selector.settingId = settingId;
}
const selector = { level: 'settings' as const, ...settingId && { settingId } };
Permissions.find(selector).forEach(
function(permission) {
await Permissions.find(selector).forEach(
function(permission: IPermission) {
previousSettingPermissions[permission._id] = permission;
});
return previousSettingPermissions;
};
const createSettingPermission = function(setting, previousSettingPermissions) {
const createSettingPermission = async function(setting: ISetting, previousSettingPermissions: {
[key: string]: IPermission;
}): Promise<void> {
const permissionId = getSettingPermissionId(setting._id);
const permission = {
level: CONSTANTS.SETTINGS_LEVEL,
const permission: Omit<IPermission, '_id'> = {
level: CONSTANTS.SETTINGS_LEVEL as 'settings' | undefined,
// copy those setting-properties which are needed to properly publish the setting-based permissions
settingId: setting._id,
group: setting.group,
@ -212,19 +213,19 @@ export const upsertPermissions = () => {
permission.sectionPermissionId = getSettingPermissionId(setting.section);
}
const existent = Permissions.findOne({
const existent = await Permissions.findOne({
_id: permissionId,
...permission,
}, { fields: { _id: 1 } });
if (!existent) {
try {
Permissions.upsert({ _id: permissionId }, { $set: permission });
await Permissions.update({ _id: permissionId }, { $set: permission }, { upsert: true });
} catch (e) {
if (!e.message.includes('E11000')) {
// E11000 refers to a MongoDB error that can occur when using unique indexes for upserts
// https://docs.mongodb.com/manual/reference/method/db.collection.update/#use-unique-indexes
Permissions.upsert({ _id: permissionId }, { $set: permission });
await Permissions.update({ _id: permissionId }, { $set: permission }, { upsert: true });
}
}
}
@ -232,17 +233,17 @@ export const upsertPermissions = () => {
delete previousSettingPermissions[permissionId];
};
const createPermissionsForExistingSettings = function() {
const previousSettingPermissions = getPreviousPermissions();
const createPermissionsForExistingSettings = async function(): Promise<void> {
const previousSettingPermissions = await getPreviousPermissions();
Settings.findNotHidden().fetch().forEach((setting) => {
(await Settings.findNotHidden().toArray()).forEach((setting) => {
createSettingPermission(setting, previousSettingPermissions);
});
// remove permissions for non-existent settings
for (const obsoletePermission in previousSettingPermissions) {
for await (const obsoletePermission of Object.keys(previousSettingPermissions)) {
if (previousSettingPermissions.hasOwnProperty(obsoletePermission)) {
Permissions.remove({ _id: obsoletePermission });
await Permissions.deleteOne({ _id: obsoletePermission });
}
}
};
@ -251,9 +252,9 @@ export const upsertPermissions = () => {
createPermissionsForExistingSettings();
// register a callback for settings for be create in higher-level-packages
settings.on('*', function([settingId]) {
const previousSettingPermissions = getPreviousPermissions(settingId);
const setting = Settings.findOneById(settingId);
settings.on('*', async function([settingId]) {
const previousSettingPermissions = await getPreviousPermissions(settingId);
const setting = await Settings.findOneById(settingId);
if (setting) {
if (!setting.hidden) {
createSettingPermission(setting, previousSettingPermissions);

@ -1,11 +1,12 @@
import { Meteor } from 'meteor/meteor';
import { Permissions } from '../../../models/server';
import { hasPermission } from '../functions/hasPermission';
import { CONSTANTS, AuthorizationUtils } from '../../lib';
import { Permissions } from '../../../models/server/raw';
Meteor.methods({
'authorization:addPermissionToRole'(permissionId, role) {
async 'authorization:addPermissionToRole'(permissionId, role) {
if (AuthorizationUtils.isPermissionRestrictedForRole(permissionId, role)) {
throw new Meteor.Error('error-action-not-allowed', 'Permission is restricted', {
method: 'authorization:addPermissionToRole',
@ -14,7 +15,14 @@ Meteor.methods({
}
const uid = Meteor.userId();
const permission = Permissions.findOneById(permissionId);
const permission = await Permissions.findOneById(permissionId);
if (!permission) {
throw new Meteor.Error('error-invalid-permission', 'Permission does not exist', {
method: 'authorization:addPermissionToRole',
action: 'Adding_permission',
});
}
if (!uid || !hasPermission(uid, 'access-permissions') || (permission.level === CONSTANTS.SETTINGS_LEVEL && !hasPermission(uid, 'access-setting-permissions'))) {
throw new Meteor.Error('error-action-not-allowed', 'Adding permission is not allowed', {

@ -1,13 +1,14 @@
import { Meteor } from 'meteor/meteor';
import _ from 'underscore';
import { Users, Roles } from '../../../models/server';
import { Users } from '../../../models/server';
import { settings } from '../../../settings/server';
import { hasPermission } from '../functions/hasPermission';
import { api } from '../../../../server/sdk/api';
import { Roles } from '../../../models/server/raw';
Meteor.methods({
'authorization:addUserToRole'(roleName, username, scope) {
async 'authorization:addUserToRole'(roleName, username, scope) {
if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'access-permissions')) {
throw new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed', {
method: 'authorization:addUserToRole',
@ -41,13 +42,13 @@ Meteor.methods({
}
// verify if user can be added to given scope
if (scope && !Roles.canAddUserToRole(user._id, roleName, scope)) {
if (scope && !await Roles.canAddUserToRole(user._id, roleName, scope)) {
throw new Meteor.Error('error-invalid-user', 'User is not part of given room', {
method: 'authorization:addUserToRole',
});
}
const add = Roles.addUserRoles(user._id, roleName, scope);
const add = await Roles.addUserRoles(user._id, [roleName], scope);
if (settings.get('UI_DisplayRoles')) {
api.broadcast('user.roleUpdate', {

@ -1,10 +1,10 @@
import { Meteor } from 'meteor/meteor';
import * as Models from '../../../models/server';
import { Roles } from '../../../models/server/raw';
import { hasPermission } from '../functions/hasPermission';
Meteor.methods({
'authorization:deleteRole'(roleName) {
async 'authorization:deleteRole'(roleName) {
if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'access-permissions')) {
throw new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed', {
method: 'authorization:deleteRole',
@ -12,7 +12,7 @@ Meteor.methods({
});
}
const role = Models.Roles.findOne(roleName);
const role = await Roles.findOne(roleName);
if (!role) {
throw new Meteor.Error('error-invalid-role', 'Invalid role', {
method: 'authorization:deleteRole',
@ -25,16 +25,14 @@ Meteor.methods({
});
}
const roleScope = role.scope || 'Users';
const model = Models[roleScope];
const existingUsers = model && model.findUsersInRoles && model.findUsersInRoles(roleName);
const users = await(await Roles.findUsersInRole(roleName)).count();
if (existingUsers && existingUsers.count() > 0) {
if (users > 0) {
throw new Meteor.Error('error-role-in-use', 'Cannot delete role because it\'s in use', {
method: 'authorization:deleteRole',
});
}
return Models.Roles.remove(role.name);
return Roles.removeById(role.name);
},
});

@ -1,13 +1,18 @@
import { Meteor } from 'meteor/meteor';
import { Permissions } from '../../../models/server';
import { hasPermission } from '../functions/hasPermission';
import { CONSTANTS } from '../../lib';
import { Permissions } from '../../../models/server/raw';
Meteor.methods({
'authorization:removeRoleFromPermission'(permissionId, role) {
async 'authorization:removeRoleFromPermission'(permissionId, role) {
const uid = Meteor.userId();
const permission = Permissions.findOneById(permissionId);
const permission = await Permissions.findOneById(permissionId);
if (!permission) {
throw new Meteor.Error('error-permission-not-found', 'Permission not found', { method: 'authorization:removeRoleFromPermission' });
}
if (!uid || !hasPermission(uid, 'access-permissions') || (permission.level === CONSTANTS.SETTINGS_LEVEL && !hasPermission(uid, 'access-setting-permissions'))) {
throw new Meteor.Error('error-action-not-allowed', 'Removing permission is not allowed', {

@ -1,13 +1,13 @@
import { Meteor } from 'meteor/meteor';
import _ from 'underscore';
import { Roles } from '../../../models/server';
import { settings } from '../../../settings/server';
import { hasPermission } from '../functions/hasPermission';
import { api } from '../../../../server/sdk/api';
import { Roles } from '../../../models/server/raw';
Meteor.methods({
'authorization:removeUserFromRole'(roleName, username, scope) {
async 'authorization:removeUserFromRole'(roleName, username, scope) {
if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'access-permissions')) {
throw new Meteor.Error('error-action-not-allowed', 'Access permissions is not allowed', {
method: 'authorization:removeUserFromRole',
@ -44,7 +44,7 @@ Meteor.methods({
},
}).count();
const userIsAdmin = user.roles.indexOf('admin') > -1;
const userIsAdmin = user.roles?.indexOf('admin') > -1;
if (adminCount === 1 && userIsAdmin) {
throw new Meteor.Error('error-action-not-allowed', 'Leaving the app without admins is not allowed', {
method: 'removeUserFromRole',
@ -53,7 +53,7 @@ Meteor.methods({
}
}
const remove = Roles.removeUserRoles(user._id, roleName, scope);
const remove = await Roles.removeUserRoles(user._id, [roleName], scope);
if (settings.get('UI_DisplayRoles')) {
api.broadcast('user.roleUpdate', {
type: 'removed',

@ -1,12 +1,12 @@
import { Meteor } from 'meteor/meteor';
import { Roles } from '../../../models/server';
import { settings } from '../../../settings/server';
import { hasPermission } from '../functions/hasPermission';
import { api } from '../../../../server/sdk/api';
import { Roles } from '../../../models/server/raw';
Meteor.methods({
'authorization:saveRole'(roleData) {
async 'authorization:saveRole'(roleData) {
if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'access-permissions')) {
throw new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed', {
method: 'authorization:saveRole',
@ -24,7 +24,7 @@ Meteor.methods({
roleData.scope = 'Users';
}
const update = Roles.createOrUpdate(roleData.name, roleData.scope, roleData.description, false, roleData.mandatory2fa);
const update = await Roles.createOrUpdate(roleData.name, roleData.scope, roleData.description, false, roleData.mandatory2fa);
if (settings.get('UI_DisplayRoles')) {
api.broadcast('user.roleUpdate', {
type: 'changed',

@ -1,25 +0,0 @@
import { Meteor } from 'meteor/meteor';
import Permissions from '../../../../models/server/models/Permissions';
Meteor.methods({
'permissions/get'(updatedAt) {
// TODO: should we return this for non logged users?
// TODO: we could cache this collection
const records = Permissions.find().fetch();
if (updatedAt instanceof Date) {
return {
update: records.filter((record) => record._updatedAt > updatedAt),
remove: Permissions.trashFindDeletedAfter(
updatedAt,
{},
{ fields: { _id: 1, _deletedAt: 1 } },
).fetch(),
};
}
return records;
},
});

@ -0,0 +1,28 @@
import { Meteor } from 'meteor/meteor';
import { check, Match } from 'meteor/check';
import { Permissions } from '../../../../models/server/raw';
Meteor.methods({
async 'permissions/get'(updatedAt: Date) {
check(updatedAt, Match.Maybe(Date));
// TODO: should we return this for non logged users?
// TODO: we could cache this collection
const records = await Permissions.find(updatedAt && { _updatedAt: { $gt: updatedAt } }).toArray();
if (updatedAt instanceof Date) {
return {
update: records,
remove: await Permissions.trashFindDeletedAfter(
updatedAt,
{},
{ fields: { _id: 1, _deletedAt: 1 } },
).toArray(),
};
}
return records;
},
});

@ -1,11 +0,0 @@
import { Meteor } from 'meteor/meteor';
import { Permissions } from '../../models';
Meteor.startup(() => {
if (Permissions) {
if (!Permissions.findOne({ _id: 'auto-translate' })) {
Permissions.insert({ _id: 'auto-translate', roles: ['admin'] });
}
}
});

@ -0,0 +1,9 @@
import { Meteor } from 'meteor/meteor';
import { Permissions } from '../../models/server/raw';
Meteor.startup(async () => {
if (!await Permissions.findOne({ _id: 'auto-translate' })) {
Permissions.create('auto-translate', ['admin']);
}
});

@ -10,7 +10,8 @@ import CAS from 'cas';
import { logger } from './cas_rocketchat';
import { settings } from '../../settings';
import { Rooms, CredentialTokens } from '../../models/server';
import { Rooms } from '../../models/server';
import { CredentialTokens } from '../../models/server/raw';
import { _setRealName } from '../../lib';
import { createRoom } from '../../lib/server/functions/createRoom';
@ -43,7 +44,7 @@ const casTicket = function(req, token, callback) {
service: `${ appUrl }/_cas/${ token }`,
});
cas.validate(ticketId, Meteor.bindEnvironment(function(err, status, username, details) {
cas.validate(ticketId, Meteor.bindEnvironment(async function(err, status, username, details) {
if (err) {
logger.error(`error when trying to validate: ${ err.message }`);
} else if (status) {
@ -54,11 +55,11 @@ const casTicket = function(req, token, callback) {
if (details && details.attributes) {
_.extend(user_info, { attributes: details.attributes });
}
CredentialTokens.create(token, user_info);
await CredentialTokens.create(token, user_info);
} else {
logger.error(`Unable to validate ticket: ${ ticketId }`);
}
// logger.debug("Receveied response: " + JSON.stringify(details, null , 4));
// logger.debug("Received response: " + JSON.stringify(details, null , 4));
callback();
}));
@ -114,7 +115,8 @@ Accounts.registerLoginHandler(function(options) {
return undefined;
}
const credentials = CredentialTokens.findOneById(options.cas.credentialToken);
// TODO: Sync wrapper due to the chain conversion to async models
const credentials = Promise.await(CredentialTokens.findOneNotExpiredById(options.cas.credentialToken));
if (credentials === undefined) {
throw new Meteor.Error(Accounts.LoginCancelledError.numericError,
'no matching login attempt found');

@ -1,6 +1,7 @@
import { Meteor } from 'meteor/meteor';
import { Rooms, Messages, Subscriptions, Integrations } from '../../../models/server';
import { Rooms, Messages, Subscriptions } from '../../../models/server';
import { Integrations } from '../../../models/server/raw';
import { roomTypes, getValidRoomName } from '../../../utils/server';
import { callbacks } from '../../../callbacks/server';
import { checkUsernameAvailability } from '../../../lib/server/functions';
@ -19,7 +20,7 @@ const updateRoomName = (rid, displayName, isDiscussion) => {
return Rooms.setNameById(rid, slugifiedRoomName, displayName) && Subscriptions.updateNameAndAlertByRoomId(rid, slugifiedRoomName, displayName);
};
export const saveRoomName = function(rid, displayName, user, sendMessage = true) {
export async function saveRoomName(rid, displayName, user, sendMessage = true) {
const room = Rooms.findOneById(rid);
if (roomTypes.getConfig(room.t).preventRenaming()) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
@ -35,10 +36,10 @@ export const saveRoomName = function(rid, displayName, user, sendMessage = true)
return;
}
Integrations.updateRoomName(room.name, displayName);
await Integrations.updateRoomName(room.name, displayName);
if (sendMessage) {
Messages.createRoomRenamedWithRoomIdRoomNameAndUser(rid, displayName, user);
}
callbacks.run('afterRoomNameChange', { rid, name: displayName, oldName: room.name });
return displayName;
};
}

@ -128,7 +128,7 @@ const validators = {
const settingSavers = {
roomName({ value, rid, user, room }) {
if (!saveRoomName(rid, value, user)) {
if (!Promise.await(saveRoomName(rid, value, user))) {
return;
}
@ -231,13 +231,13 @@ const settingSavers = {
favorite({ value, rid }) {
Rooms.saveFavoriteById(rid, value.favorite, value.defaultValue);
},
roomAvatar({ value, rid, user }) {
setRoomAvatar(rid, value, user);
async roomAvatar({ value, rid, user }) {
await setRoomAvatar(rid, value, user);
},
};
Meteor.methods({
saveRoomSettings(rid, settings, value) {
async saveRoomSettings(rid, settings, value) {
const userId = Meteor.userId();
if (!userId) {
@ -313,10 +313,10 @@ Meteor.methods({
});
// saving data
Object.keys(settings).forEach((setting) => {
for await (const setting of Object.keys(settings)) {
const value = settings[setting];
const saver = settingSavers[setting];
const saver = await settingSavers[setting];
if (saver) {
saver({
value,
@ -325,7 +325,7 @@ Meteor.methods({
user,
});
}
});
}
Meteor.defer(function() {
const room = Rooms.findOneById(rid);

@ -1,10 +1,11 @@
import { settings } from '../../../settings/server';
import { Users, Statistics } from '../../../models/server';
import { Users } from '../../../models/server';
import { Statistics } from '../../../models/server/raw';
import { statistics } from '../../../statistics';
import { LICENSE_VERSION } from '../license';
export function buildWorkspaceRegistrationData() {
const stats = Statistics.findLast() || statistics.get();
export async function buildWorkspaceRegistrationData() {
const stats = await Statistics.findLast() || statistics.get();
const address = settings.get('Site_Url');
const siteName = settings.get('Site_Name');

@ -7,18 +7,17 @@ import { Settings } from '../../../models';
import { buildWorkspaceRegistrationData } from './buildRegistrationData';
import { SystemLogger } from '../../../../server/lib/logger/system';
export function startRegisterWorkspace(resend = false) {
export async function startRegisterWorkspace(resend = false) {
const { workspaceRegistered, connectToCloud } = retrieveRegistrationStatus();
if ((workspaceRegistered && connectToCloud) || process.env.TEST_MODE) {
syncWorkspace(true);
await syncWorkspace(true);
return true;
}
Settings.updateValueById('Register_Server', true);
const regInfo = buildWorkspaceRegistrationData();
const regInfo = await buildWorkspaceRegistrationData();
const cloudUrl = settings.get('Cloud_Url');

@ -10,13 +10,13 @@ import { getAndCreateNpsSurvey } from '../../../../server/services/nps/getAndCre
import { NPS, Banner } from '../../../../server/sdk';
import { SystemLogger } from '../../../../server/lib/logger/system';
export function syncWorkspace(reconnectCheck = false) {
export async function syncWorkspace(reconnectCheck = false) {
const { workspaceRegistered, connectToCloud } = retrieveRegistrationStatus();
if (!workspaceRegistered || (!connectToCloud && !reconnectCheck)) {
return false;
}
const info = buildWorkspaceRegistrationData();
const info = await buildWorkspaceRegistrationData();
const workspaceUrl = settings.get('Cloud_Workspace_Registration_Client_Uri');
@ -64,11 +64,11 @@ export function syncWorkspace(reconnectCheck = false) {
const startAt = new Date(data.nps.startAt);
Promise.await(NPS.create({
await NPS.create({
npsId,
startAt,
expireAt: new Date(expireAt),
}));
});
const now = new Date();
@ -79,19 +79,19 @@ export function syncWorkspace(reconnectCheck = false) {
// add banners
if (data.banners) {
for (const banner of data.banners) {
for await (const banner of data.banners) {
const {
createdAt,
expireAt,
startAt,
} = banner;
Promise.await(Banner.create({
await Banner.create({
...banner,
createdAt: new Date(createdAt),
expireAt: new Date(expireAt),
startAt: new Date(startAt),
}));
});
}
}

@ -26,7 +26,7 @@ Meteor.methods({
return retrieveRegistrationStatus();
},
'cloud:getWorkspaceRegisterData'() {
async 'cloud:getWorkspaceRegisterData'() {
if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'cloud:getWorkspaceRegisterData' });
}
@ -35,9 +35,9 @@ Meteor.methods({
throw new Meteor.Error('error-not-authorized', 'Not authorized', { method: 'cloud:getWorkspaceRegisterData' });
}
return Buffer.from(JSON.stringify(buildWorkspaceRegistrationData())).toString('base64');
return Buffer.from(JSON.stringify(await buildWorkspaceRegistrationData())).toString('base64');
},
'cloud:registerWorkspace'() {
async 'cloud:registerWorkspace'() {
if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'cloud:startRegister' });
}
@ -48,7 +48,7 @@ Meteor.methods({
return startRegisterWorkspace();
},
'cloud:syncWorkspace'() {
async 'cloud:syncWorkspace'() {
if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'cloud:syncWorkspace' });
}

@ -208,7 +208,7 @@ export class CROWD {
if (settings.get('CROWD_Remove_Orphaned_Users') === true) {
logger.info('Removing user:', crowd_username);
Meteor.defer(function() {
deleteUser(user._id);
Promise.await(deleteUser(user._id));
logger.info('User removed:', crowd_username);
});
}

@ -1,16 +1,16 @@
import { Meteor } from 'meteor/meteor';
import { CustomSounds } from '../../../models';
import { CustomSounds } from '../../../models/server/raw';
import { hasPermission } from '../../../authorization';
import { Notifications } from '../../../notifications';
import { RocketChatFileCustomSoundsInstance } from '../startup/custom-sounds';
Meteor.methods({
deleteCustomSound(_id) {
async deleteCustomSound(_id) {
let sound = null;
if (hasPermission(this.userId, 'manage-sounds')) {
sound = CustomSounds.findOneById(_id);
sound = await CustomSounds.findOneById(_id);
} else {
throw new Meteor.Error('not_authorized');
}
@ -20,7 +20,7 @@ Meteor.methods({
}
RocketChatFileCustomSoundsInstance.deleteFile(`${ sound._id }.${ sound.extension }`);
CustomSounds.removeById(_id);
await CustomSounds.removeById(_id);
Notifications.notifyAll('deleteCustomSound', { soundData: sound });
return true;

@ -3,12 +3,12 @@ import s from 'underscore.string';
import { check } from 'meteor/check';
import { hasPermission } from '../../../authorization';
import { CustomSounds } from '../../../models';
import { CustomSounds } from '../../../models/server/raw';
import { Notifications } from '../../../notifications';
import { RocketChatFileCustomSoundsInstance } from '../startup/custom-sounds';
Meteor.methods({
insertOrUpdateSound(soundData) {
async insertOrUpdateSound(soundData) {
if (!hasPermission(this.userId, 'manage-sounds')) {
throw new Meteor.Error('not_authorized');
}
@ -34,9 +34,9 @@ Meteor.methods({
if (soundData._id) {
check(soundData._id, String);
matchingResults = CustomSounds.findByNameExceptId(soundData.name, soundData._id).fetch();
matchingResults = await CustomSounds.findByNameExceptId(soundData.name, soundData._id).toArray();
} else {
matchingResults = CustomSounds.findByName(soundData.name).fetch();
matchingResults = await CustomSounds.findByName(soundData.name).toArray();
}
if (matchingResults.length > 0) {
@ -50,7 +50,7 @@ Meteor.methods({
extension: soundData.extension,
};
const _id = CustomSounds.create(createSound);
const _id = await (await CustomSounds.create(createSound)).insertedId;
createSound._id = _id;
return _id;
@ -61,7 +61,7 @@ Meteor.methods({
}
if (soundData.name !== soundData.previousName) {
CustomSounds.setName(soundData._id, soundData.name);
await CustomSounds.setName(soundData._id, soundData.name);
Notifications.notifyAll('updateCustomSound', { soundData });
}

@ -1,9 +1,9 @@
import { Meteor } from 'meteor/meteor';
import { CustomSounds } from '../../../models';
import { CustomSounds } from '../../../models/server/raw';
Meteor.methods({
listCustomSounds() {
return CustomSounds.find({}).fetch();
async listCustomSounds() {
return CustomSounds.find({}).toArray();
},
});

@ -1,6 +1,7 @@
import { Meteor } from 'meteor/meteor';
import { Permissions } from '../../models';
import { Permissions } from '../../models/server/raw';
Meteor.startup(() => {
// Add permissions for discussion

@ -2,22 +2,22 @@ import { Meteor } from 'meteor/meteor';
import { api } from '../../../../server/sdk/api';
import { hasPermission } from '../../../authorization';
import { EmojiCustom } from '../../../models';
import { EmojiCustom } from '../../../models/server/raw';
import { RocketChatFileEmojiCustomInstance } from '../startup/emoji-custom';
Meteor.methods({
deleteEmojiCustom(emojiID) {
async deleteEmojiCustom(emojiID) {
if (!hasPermission(this.userId, 'manage-emoji')) {
throw new Meteor.Error('not_authorized');
}
const emoji = EmojiCustom.findOneById(emojiID);
const emoji = await EmojiCustom.findOneById(emojiID);
if (emoji == null) {
throw new Meteor.Error('Custom_Emoji_Error_Invalid_Emoji', 'Invalid emoji', { method: 'deleteEmojiCustom' });
}
RocketChatFileEmojiCustomInstance.deleteFile(encodeURIComponent(`${ emoji.name }.${ emoji.extension }`));
EmojiCustom.removeById(emojiID);
await EmojiCustom.removeById(emojiID);
api.broadcast('emoji.deleteCustom', emoji);
return true;

@ -4,12 +4,12 @@ import s from 'underscore.string';
import limax from 'limax';
import { hasPermission } from '../../../authorization';
import { EmojiCustom } from '../../../models';
import { EmojiCustom } from '../../../models/server/raw';
import { RocketChatFileEmojiCustomInstance } from '../startup/emoji-custom';
import { api } from '../../../../server/sdk/api';
Meteor.methods({
insertOrUpdateEmoji(emojiData) {
async insertOrUpdateEmoji(emojiData) {
if (!hasPermission(this.userId, 'manage-emoji')) {
throw new Meteor.Error('not_authorized');
}
@ -50,14 +50,14 @@ Meteor.methods({
let matchingResults = [];
if (emojiData._id) {
matchingResults = EmojiCustom.findByNameOrAliasExceptID(emojiData.name, emojiData._id).fetch();
for (const alias of emojiData.aliases) {
matchingResults = matchingResults.concat(EmojiCustom.findByNameOrAliasExceptID(alias, emojiData._id).fetch());
matchingResults = await EmojiCustom.findByNameOrAliasExceptID(emojiData.name, emojiData._id).toArray();
for await (const alias of emojiData.aliases) {
matchingResults = matchingResults.concat(await EmojiCustom.findByNameOrAliasExceptID(alias, emojiData._id).toArray());
}
} else {
matchingResults = EmojiCustom.findByNameOrAlias(emojiData.name).fetch();
for (const alias of emojiData.aliases) {
matchingResults = matchingResults.concat(EmojiCustom.findByNameOrAlias(alias).fetch());
matchingResults = await EmojiCustom.findByNameOrAlias(emojiData.name).toArray();
for await (const alias of emojiData.aliases) {
matchingResults = matchingResults.concat(await EmojiCustom.findByNameOrAlias(alias).toArray());
}
}
@ -77,7 +77,7 @@ Meteor.methods({
extension: emojiData.extension,
};
const _id = EmojiCustom.create(createEmoji);
const _id = (await EmojiCustom.create(createEmoji)).insertedId;
api.broadcast('emoji.updateCustom', createEmoji);
@ -90,7 +90,7 @@ Meteor.methods({
RocketChatFileEmojiCustomInstance.deleteFile(encodeURIComponent(`${ emojiData.previousName }.${ emojiData.extension }`));
RocketChatFileEmojiCustomInstance.deleteFile(encodeURIComponent(`${ emojiData.previousName }.${ emojiData.previousExtension }`));
EmojiCustom.setExtension(emojiData._id, emojiData.extension);
await EmojiCustom.setExtension(emojiData._id, emojiData.extension);
} else if (emojiData.name !== emojiData.previousName) {
const rs = RocketChatFileEmojiCustomInstance.getFileWithReadStream(encodeURIComponent(`${ emojiData.previousName }.${ emojiData.previousExtension }`));
if (rs !== null) {
@ -104,13 +104,13 @@ Meteor.methods({
}
if (emojiData.name !== emojiData.previousName) {
EmojiCustom.setName(emojiData._id, emojiData.name);
await EmojiCustom.setName(emojiData._id, emojiData.name);
}
if (emojiData.aliases) {
EmojiCustom.setAliases(emojiData._id, emojiData.aliases);
await EmojiCustom.setAliases(emojiData._id, emojiData.aliases);
} else {
EmojiCustom.setAliases(emojiData._id, []);
await EmojiCustom.setAliases(emojiData._id, []);
}
api.broadcast('emoji.updateCustom', emojiData);

@ -1,9 +1,9 @@
import { Meteor } from 'meteor/meteor';
import { EmojiCustom } from '../../../models';
import { EmojiCustom } from '../../../models/server/raw';
Meteor.methods({
listEmojiCustom(options = {}) {
return EmojiCustom.find(options).fetch();
async listEmojiCustom(options = {}) {
return EmojiCustom.find(options).toArray();
},
});

@ -4,12 +4,13 @@ import { API } from '../../../api/server';
import { serverLogger } from '../lib/logger';
import { contextDefinitions, eventTypes } from '../../../models/server/models/FederationEvents';
import {
FederationRoomEvents, FederationServers,
FederationRoomEvents,
Messages,
Rooms,
Subscriptions,
Users,
} from '../../../models/server';
import { FederationServers } from '../../../models/server/raw';
import { normalizers } from '../normalizers';
import { deleteRoom } from '../../../lib/server/functions';
import { Notifications } from '../../../notifications/server';
@ -139,7 +140,7 @@ const eventHandlers = {
// Refresh the servers list
if (federationAltered) {
FederationServers.refreshServers();
await FederationServers.refreshServers();
// Update the room's federation property
Rooms.update({ _id: roomId }, { $set: { 'federation.domains': domainsAfterAdd } });
@ -163,7 +164,7 @@ const eventHandlers = {
Subscriptions.removeByRoomIdAndUserId(roomId, user._id);
// Refresh the servers list
FederationServers.refreshServers();
await FederationServers.refreshServers();
// Update the room's federation property
Rooms.update({ _id: roomId }, { $set: { 'federation.domains': domainsAfterRemoval } });
@ -186,7 +187,7 @@ const eventHandlers = {
Subscriptions.removeByRoomIdAndUserId(roomId, user._id);
// Refresh the servers list
FederationServers.refreshServers();
await FederationServers.refreshServers();
// Update the room's federation property
Rooms.update({ _id: roomId }, { $set: { 'federation.domains': domainsAfterRemoval } });
@ -226,7 +227,7 @@ const eventHandlers = {
const { federation: { origin } } = denormalizedMessage;
const { upload, buffer } = getUpload(origin, denormalizedMessage.file._id);
const { upload, buffer } = await getUpload(origin, denormalizedMessage.file._id);
const oldUploadId = upload._id;
@ -444,7 +445,7 @@ const eventHandlers = {
};
API.v1.addRoute('federation.events.dispatch', { authRequired: false, rateLimiterOptions: { numRequestsAllowed: 30, intervalTimeInMS: 1000 } }, {
async post() {
post() {
if (!isFederationEnabled()) {
return API.v1.failure('Federation not enabled');
}
@ -454,7 +455,7 @@ API.v1.addRoute('federation.events.dispatch', { authRequired: false, rateLimiter
let payload;
try {
payload = decryptIfNeeded(this.request, this.bodyParams);
payload = Promise.await(decryptIfNeeded(this.request, this.bodyParams));
} catch (err) {
return API.v1.failure('Could not decrypt payload');
}
@ -472,7 +473,7 @@ API.v1.addRoute('federation.events.dispatch', { authRequired: false, rateLimiter
let eventResult;
if (eventHandlers[event.type]) {
eventResult = await eventHandlers[event.type](event);
eventResult = Promise.await(eventHandlers[event.type](event));
}
// If there was an error handling the event, take action
@ -480,7 +481,7 @@ API.v1.addRoute('federation.events.dispatch', { authRequired: false, rateLimiter
try {
serverLogger.debug({ msg: 'federation.events.dispatch => Event has missing parents', event });
requestEventsFromLatest(event.origin, getFederationDomain(), contextDefinitions.defineType(event), event.context, eventResult.latestEventIds);
Promise.await(requestEventsFromLatest(event.origin, getFederationDomain(), contextDefinitions.defineType(event), event.context, eventResult.latestEventIds));
// And stop handling the events
break;

@ -8,7 +8,7 @@ import { isFederationEnabled } from '../lib/isFederationEnabled';
import { dispatchEvents } from '../handler';
API.v1.addRoute('federation.events.requestFromLatest', { authRequired: false }, {
async post() {
post() {
if (!isFederationEnabled()) {
return API.v1.failure('Federation not enabled');
}
@ -18,7 +18,7 @@ API.v1.addRoute('federation.events.requestFromLatest', { authRequired: false },
let payload;
try {
payload = decryptIfNeeded(this.request, this.bodyParams);
payload = Promise.await(decryptIfNeeded(this.request, this.bodyParams));
} catch (err) {
return API.v1.failure('Could not decrypt payload');
}
@ -54,7 +54,7 @@ API.v1.addRoute('federation.events.requestFromLatest', { authRequired: false },
}
// Dispatch all the events, on the same request
dispatchEvents([fromDomain], missingEvents);
Promise.await(dispatchEvents([fromDomain], missingEvents));
return API.v1.success();
},

@ -1,5 +1,5 @@
import { API } from '../../../api/server';
import { Uploads } from '../../../models/server';
import { Uploads } from '../../../models/server/raw';
import { FileUpload } from '../../../file-upload/server';
import { isFederationEnabled } from '../lib/isFederationEnabled';
@ -11,7 +11,7 @@ API.v1.addRoute('federation.uploads', { authRequired: false }, {
const { upload_id } = this.requestParams();
const upload = Uploads.findOneById(upload_id);
const upload = Promise.await(Uploads.findOneById(upload_id));
if (!upload) {
return API.v1.failure('There is no such file in this server');

@ -1,15 +1,16 @@
import { Meteor } from 'meteor/meteor';
import * as federationErrors from './errors';
import { FederationServers, Users } from '../../../models/server';
import { Users } from '../../../models/server';
import { FederationServers } from '../../../models/server/raw';
import { getUserByUsername } from '../handler';
export function addUser(query) {
export async function addUser(query) {
if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'addUser' });
}
const user = getUserByUsername(query);
const user = await getUserByUsername(query);
if (!user) {
throw federationErrors.userNotFound(query);
@ -22,7 +23,7 @@ export function addUser(query) {
userId = Users.create(user);
// Refresh the servers list
FederationServers.refreshServers();
await FederationServers.refreshServers();
} catch (err) {
// This might get called twice by the createDirectMessage method
// so we need to handle the situation accordingly

@ -1,21 +1,22 @@
import { Meteor } from 'meteor/meteor';
import { FederationServers, FederationRoomEvents, Users } from '../../../models/server';
import { FederationRoomEvents, Users } from '../../../models/server';
import { FederationServers } from '../../../models/server/raw';
export function getStatistics() {
export async function getStatistics() {
const numberOfEvents = FederationRoomEvents.find().count();
const numberOfFederatedUsers = Users.findRemote().count();
const numberOfServers = FederationServers.find().count();
const numberOfServers = await FederationServers.find().count();
return { numberOfEvents, numberOfFederatedUsers, numberOfServers };
}
export function federationGetOverviewData() {
export async function federationGetOverviewData() {
if (!Meteor.userId()) {
throw new Meteor.Error('not-authorized');
}
const { numberOfEvents, numberOfFederatedUsers, numberOfServers } = getStatistics();
const { numberOfEvents, numberOfFederatedUsers, numberOfServers } = await getStatistics();
return {
data: [{
@ -31,12 +32,12 @@ export function federationGetOverviewData() {
};
}
export function federationGetServers() {
export async function federationGetServers() {
if (!Meteor.userId()) {
throw new Meteor.Error('not-authorized');
}
const servers = FederationServers.find().fetch();
const servers = await FederationServers.find().toArray();
return {
data: servers,

@ -1,69 +0,0 @@
import { Settings, Subscriptions, Users } from '../../../models/server';
import { STATUS_ENABLED, STATUS_REGISTERING } from '../constants';
export const getNameAndDomain = (fullyQualifiedName) => fullyQualifiedName.split('@');
export const isFullyQualified = (name) => name.indexOf('@') !== -1;
export function isRegisteringOrEnabled() {
const status = Settings.findOneById('FEDERATION_Status');
return [STATUS_ENABLED, STATUS_REGISTERING].includes(status && status.value);
}
export function updateStatus(status) {
Settings.updateValueById('FEDERATION_Status', status);
}
export function updateEnabled(enabled) {
Settings.updateValueById('FEDERATION_Enabled', enabled);
}
export const checkRoomType = (room) => room.t === 'p' || room.t === 'd';
export const checkRoomDomainsLength = (domains) => domains.length <= (process.env.FEDERATED_DOMAINS_LENGTH || 10);
export const hasExternalDomain = ({ federation }) => {
// same test as isFederated(room)
if (!federation) {
return false;
}
return federation.domains
.some((domain) => domain !== federation.origin);
};
export const isLocalUser = ({ federation }, localDomain) =>
!federation || federation.origin === localDomain;
export const getFederatedRoomData = (room) => {
let hasFederatedUser = false;
let users = null;
let subscriptions = null;
if (room.t === 'd') {
// Check if there is a federated user on this room
hasFederatedUser = room.usernames.some(isFullyQualified);
} else {
// Find all subscriptions of this room
subscriptions = Subscriptions.findByRoomIdWhenUsernameExists(room._id).fetch();
subscriptions = subscriptions.reduce((acc, s) => {
acc[s.u._id] = s;
return acc;
}, {});
// Get all user ids
const userIds = Object.keys(subscriptions);
// Load all the users
users = Users.findUsersWithUsernameByIds(userIds).fetch();
// Check if there is a federated user on this room
hasFederatedUser = users.some((u) => isFullyQualified(u.username));
}
return {
hasFederatedUser,
users,
subscriptions,
};
};

@ -0,0 +1,77 @@
import { IRoom, isDirectMessageRoom } from '../../../../definition/IRoom';
import { ISubscription } from '../../../../definition/ISubscription';
import { IRegisterUser, IUser } from '../../../../definition/IUser';
import { Subscriptions, Users } from '../../../models/server';
import { Settings } from '../../../models/server/raw';
import { STATUS_ENABLED, STATUS_REGISTERING } from '../constants';
export const getNameAndDomain = (fullyQualifiedName: string): string [] => fullyQualifiedName.split('@');
export const isFullyQualified = (name: string): boolean => name.indexOf('@') !== -1;
export async function isRegisteringOrEnabled(): Promise<boolean> {
const value = await Settings.getValueById('FEDERATION_Status');
return typeof value === 'string' && [STATUS_ENABLED, STATUS_REGISTERING].includes(value);
}
export async function updateStatus(status: string): Promise<void> {
await Settings.updateValueById('FEDERATION_Status', status);
}
export async function updateEnabled(enabled: boolean): Promise<void> {
await Settings.updateValueById('FEDERATION_Enabled', enabled);
}
export const checkRoomType = (room: IRoom): boolean => room.t === 'p' || room.t === 'd';
export const checkRoomDomainsLength = (domains: unknown[]): boolean => domains.length <= (process.env.FEDERATED_DOMAINS_LENGTH || 10);
export const hasExternalDomain = ({ federation }: { federation: { origin: string; domains: string[] } }): boolean => {
// same test as isFederated(room)
if (!federation) {
return false;
}
return federation.domains
.some((domain) => domain !== federation.origin);
};
export const isLocalUser = ({ federation }: { federation: { origin: string } }, localDomain: string): boolean =>
!federation || federation.origin === localDomain;
export const getFederatedRoomData = (room: IRoom): {
hasFederatedUser: boolean;
users: IUser[];
subscriptions: { [k: string]: ISubscription } | undefined;
} => {
if (isDirectMessageRoom(room)) {
// Check if there is a federated user on this room
return {
users: [],
hasFederatedUser: room.usernames.some(isFullyQualified),
subscriptions: undefined,
};
}
// Find all subscriptions of this room
const s = Subscriptions.findByRoomIdWhenUsernameExists(room._id).fetch() as ISubscription[];
const subscriptions = s.reduce((acc, s) => {
acc[s.u._id] = s;
return acc;
}, {} as { [k: string]: ISubscription });
// Get all user ids
const userIds = Object.keys(subscriptions);
// Load all the users
const users: IRegisterUser[] = Users.findUsersWithUsernameByIds(userIds).fetch();
// Check if there is a federated user on this room
const hasFederatedUser = users.some((u) => isFullyQualified(u.username));
return {
hasFederatedUser,
users,
subscriptions,
};
};

@ -5,7 +5,7 @@ import { clientLogger } from '../lib/logger';
import { isFederationEnabled } from '../lib/isFederationEnabled';
import { federationRequestToPeer } from '../lib/http';
export function federationSearchUsers(query) {
export async function federationSearchUsers(query) {
if (!isFederationEnabled()) {
throw disabled('client.searchUsers');
}
@ -16,12 +16,12 @@ export function federationSearchUsers(query) {
const uri = `/api/v1/federation.users.search?${ qs.stringify({ username, domain: peerDomain }) }`;
const { data: { users } } = federationRequestToPeer('GET', peerDomain, uri);
const { data: { users } } = await federationRequestToPeer('GET', peerDomain, uri);
return users;
}
export function getUserByUsername(query) {
export async function getUserByUsername(query) {
if (!isFederationEnabled()) {
throw disabled('client.searchUsers');
}
@ -32,12 +32,12 @@ export function getUserByUsername(query) {
const uri = `/api/v1/federation.users.getByUsername?${ qs.stringify({ username }) }`;
const { data: { user } } = federationRequestToPeer('GET', peerDomain, uri);
const { data: { user } } = await federationRequestToPeer('GET', peerDomain, uri);
return user;
}
export function requestEventsFromLatest(domain, fromDomain, contextType, contextQuery, latestEventIds) {
export async function requestEventsFromLatest(domain, fromDomain, contextType, contextQuery, latestEventIds) {
if (!isFederationEnabled()) {
throw disabled('client.requestEventsFromLatest');
}
@ -46,11 +46,11 @@ export function requestEventsFromLatest(domain, fromDomain, contextType, context
const uri = '/api/v1/federation.events.requestFromLatest';
federationRequestToPeer('POST', domain, uri, { fromDomain, contextType, contextQuery, latestEventIds });
await federationRequestToPeer('POST', domain, uri, { fromDomain, contextType, contextQuery, latestEventIds });
}
export function dispatchEvents(domains, events) {
export async function dispatchEvents(domains, events) {
if (!isFederationEnabled()) {
throw disabled('client.dispatchEvents');
}
@ -61,17 +61,17 @@ export function dispatchEvents(domains, events) {
const uri = '/api/v1/federation.events.dispatch';
for (const domain of domains) {
federationRequestToPeer('POST', domain, uri, { events }, { ignoreErrors: true });
for await (const domain of domains) {
await federationRequestToPeer('POST', domain, uri, { events }, { ignoreErrors: true });
}
}
export function dispatchEvent(domains, event) {
dispatchEvents([...new Set(domains)], [event]);
export async function dispatchEvent(domains, event) {
await dispatchEvents([...new Set(domains)], [event]);
}
export function getUpload(domain, fileId) {
const { data: { upload, buffer } } = federationRequestToPeer('GET', domain, `/api/v1/federation.uploads?${ qs.stringify({ upload_id: fileId }) }`);
export async function getUpload(domain, fileId) {
const { data: { upload, buffer } } = await federationRequestToPeer('GET', domain, `/api/v1/federation.uploads?${ qs.stringify({ upload_id: fileId }) }`);
return { upload, buffer: Buffer.from(buffer) };
}

@ -41,7 +41,7 @@ async function afterCreateDirectRoom(room, extras) {
}));
// Dispatch the events
dispatchEvents(normalizedRoom.federation.domains, [genesisEvent, ...events]);
await dispatchEvents(normalizedRoom.federation.domains, [genesisEvent, ...events]);
} catch (err) {
await deleteRoom(room._id);

@ -47,7 +47,7 @@ export async function doAfterCreateRoom(room, users, subscriptions) {
const genesisEvent = await FederationRoomEvents.createGenesisEvent(getFederationDomain(), normalizedRoom);
// Dispatch the events
dispatchEvents(normalizedRoom.federation.domains, [genesisEvent, ...addUserEvents]);
await dispatchEvents(normalizedRoom.federation.domains, [genesisEvent, ...addUserEvents]);
}
async function afterCreateRoom(roomOwner, room) {

@ -1,19 +1,19 @@
import { FederationKeys } from '../../../models/server';
import { FederationKeys } from '../../../models/server/raw';
import { getFederationDomain } from './getFederationDomain';
import { search } from './dns';
import { cryptLogger } from './logger';
export function decrypt(data, peerKey) {
export async function decrypt(data, peerKey) {
//
// Decrypt the payload
const payloadBuffer = Buffer.from(data);
// Decrypt with the peer's public key
try {
data = FederationKeys.loadKey(peerKey, 'public').decryptPublic(payloadBuffer);
data = (await FederationKeys.loadKey(peerKey, 'public')).decryptPublic(payloadBuffer);
// Decrypt with the local private key
data = FederationKeys.getPrivateKey().decrypt(data);
data = (await FederationKeys.getPrivateKey()).decrypt(data);
} catch (err) {
cryptLogger.error(err);
@ -23,7 +23,7 @@ export function decrypt(data, peerKey) {
return JSON.parse(data.toString());
}
export function decryptIfNeeded(request, bodyParams) {
export async function decryptIfNeeded(request, bodyParams) {
//
// Look for the domain that sent this event
const remotePeerDomain = request.headers['x-federation-domain'];
@ -48,17 +48,17 @@ export function decryptIfNeeded(request, bodyParams) {
return decrypt(bodyParams, peerKey);
}
export function encrypt(data, peerKey) {
export async function encrypt(data, peerKey) {
if (!data) {
return data;
}
try {
// Encrypt with the peer's public key
data = FederationKeys.loadKey(peerKey, 'public').encrypt(data);
data = (await FederationKeys.loadKey(peerKey, 'public')).encrypt(data);
// Encrypt with the local private key
return FederationKeys.getPrivateKey().encryptPrivate(data);
return (await FederationKeys.getPrivateKey()).encryptPrivate(data);
} catch (err) {
cryptLogger.error(err);

@ -17,12 +17,12 @@ const memoizedDnsResolveTXT = mem(dnsResolveTXT, { maxAge: cacheMaxAge });
const hubUrl = process.env.NODE_ENV === 'development' ? 'http://localhost:8080' : 'https://hub.rocket.chat';
export function registerWithHub(peerDomain, url, publicKey) {
export async function registerWithHub(peerDomain, url, publicKey) {
const body = { domain: peerDomain, url, public_key: publicKey };
try {
// If there is no DNS entry for that, get from the Hub
federationRequest('POST', `${ hubUrl }/api/v1/peers`, body);
await federationRequest('POST', `${ hubUrl }/api/v1/peers`, body);
return true;
} catch (err) {
@ -32,12 +32,12 @@ export function registerWithHub(peerDomain, url, publicKey) {
}
}
export function searchHub(peerDomain) {
export async function searchHub(peerDomain) {
try {
dnsLogger.debug(`searchHub: peerDomain=${ peerDomain }`);
// If there is no DNS entry for that, get from the Hub
const { data: { peer } } = federationRequest('GET', `${ hubUrl }/api/v1/peers?search=${ peerDomain }`);
const { data: { peer } } = await federationRequest('GET', `${ hubUrl }/api/v1/peers?search=${ peerDomain }`);
if (!peer) {
dnsLogger.debug(`searchHub: could not find peerDomain=${ peerDomain }`);

@ -6,14 +6,14 @@ import { getFederationDomain } from './getFederationDomain';
import { search } from './dns';
import { encrypt } from './crypt';
export function federationRequest(method, url, body, headers, peerKey = null) {
export async function federationRequest(method, url, body, headers, peerKey = null) {
let data = null;
if ((method === 'POST' || method === 'PUT') && body) {
data = EJSON.toJSONValue(body);
if (peerKey) {
data = encrypt(data, peerKey);
data = await encrypt(data, peerKey);
}
}
@ -22,7 +22,7 @@ export function federationRequest(method, url, body, headers, peerKey = null) {
return MeteorHTTP.call(method, url, { data, timeout: 2000, headers: { ...headers, 'x-federation-domain': getFederationDomain() } });
}
export function federationRequestToPeer(method, peerDomain, uri, body, options = {}) {
export async function federationRequestToPeer(method, peerDomain, uri, body, options = {}) {
const ignoreErrors = peerDomain === getFederationDomain() ? false : options.ignoreErrors;
const { url: baseUrl, publicKey } = search(peerDomain);
@ -39,7 +39,7 @@ export function federationRequestToPeer(method, peerDomain, uri, body, options =
try {
httpLogger.debug({ msg: 'federationRequestToPeer', url: `${ baseUrl }${ uri }` });
result = federationRequest(method, `${ baseUrl }${ uri }`, body, options.headers || {}, peerKey);
result = await federationRequest(method, `${ baseUrl }${ uri }`, body, options.headers || {}, peerKey);
} catch (err) {
httpLogger.error({ msg: `${ ignoreErrors ? '[IGNORED] ' : '' }Error`, err });

@ -1,6 +1,8 @@
import { FederationKeys } from '../../../models/server';
import { FederationKeys } from '../../../models/server/raw';
// Create key pair if needed
if (!FederationKeys.getPublicKey()) {
FederationKeys.generateKeys();
}
(async () => {
if (!await FederationKeys.getPublicKey()) {
await FederationKeys.generateKeys();
}
})();

@ -7,11 +7,11 @@ import { getFederationDiscoveryMethod } from '../lib/getFederationDiscoveryMetho
import { registerWithHub } from '../lib/dns';
import { enableCallbacks, disableCallbacks } from '../lib/callbacks';
import { setupLogger } from '../lib/logger';
import { FederationKeys } from '../../../models/server';
import { FederationKeys } from '../../../models/server/raw';
import { STATUS_ENABLED, STATUS_REGISTERING, STATUS_ERROR_REGISTERING, STATUS_DISABLED } from '../constants';
Meteor.startup(function() {
const federationPublicKey = FederationKeys.getPublicKeyString();
Meteor.startup(async function() {
const federationPublicKey = await FederationKeys.getPublicKeyString();
settingsRegistry.addGroup('Federation', function() {
this.add('FEDERATION_Enabled', false, {
@ -36,7 +36,7 @@ Meteor.startup(function() {
// disableReset: true,
});
this.add('FEDERATION_Public_Key', federationPublicKey, {
this.add('FEDERATION_Public_Key', federationPublicKey || '', {
readonly: true,
type: 'string',
multiline: true,
@ -65,26 +65,26 @@ Meteor.startup(function() {
});
});
const updateSettings = function(): void {
const updateSettings = async function(): Promise<void> {
// Get the key pair
if (getFederationDiscoveryMethod() === 'hub' && !isRegisteringOrEnabled()) {
if (getFederationDiscoveryMethod() === 'hub' && !Promise.await(isRegisteringOrEnabled())) {
// Register with hub
try {
updateStatus(STATUS_REGISTERING);
await updateStatus(STATUS_REGISTERING);
registerWithHub(getFederationDomain(), settings.get('Site_Url'), FederationKeys.getPublicKeyString());
await registerWithHub(getFederationDomain(), settings.get('Site_Url'), await FederationKeys.getPublicKeyString());
updateStatus(STATUS_ENABLED);
await updateStatus(STATUS_ENABLED);
} catch (err) {
// Disable federation
updateEnabled(false);
await updateEnabled(false);
updateStatus(STATUS_ERROR_REGISTERING);
await updateStatus(STATUS_ERROR_REGISTERING);
}
} else {
updateStatus(STATUS_ENABLED);
return;
}
await updateStatus(STATUS_ENABLED);
};
// Add settings listeners
@ -92,11 +92,11 @@ settings.watch('FEDERATION_Enabled', function enableOrDisable(value) {
setupLogger.info(`Federation is ${ value ? 'enabled' : 'disabled' }`);
if (value) {
updateSettings();
Promise.await(updateSettings());
enableCallbacks();
} else {
updateStatus(STATUS_DISABLED);
Promise.await(updateStatus(STATUS_DISABLED));
disableCallbacks();
}

@ -2,6 +2,7 @@ import fs from 'fs';
import stream from 'stream';
import { Meteor } from 'meteor/meteor';
import { Mongo } from 'meteor/mongo';
import streamBuffers from 'stream-buffers';
import Future from 'fibers/future';
import sharp from 'sharp';
@ -13,9 +14,7 @@ import filesize from 'filesize';
import { AppsEngineException } from '@rocket.chat/apps-engine/definition/exceptions';
import { settings } from '../../../settings/server';
import Uploads from '../../../models/server/models/Uploads';
import UserDataFiles from '../../../models/server/models/UserDataFiles';
import Avatars from '../../../models/server/models/Avatars';
import { Avatars, UserDataFiles, Uploads } from '../../../models/server/raw';
import Users from '../../../models/server/models/Users';
import Rooms from '../../../models/server/models/Rooms';
import Settings from '../../../models/server/models/Settings';
@ -41,6 +40,9 @@ settings.watch('FileUpload_MaxFileSize', function(value) {
}
});
const AvatarModel = new Mongo.Collection(Avatars.col.collectionName);
const UserDataFilesModel = new Mongo.Collection(UserDataFiles.col.collectionName);
const UploadsModel = new Mongo.Collection(Uploads.col.collectionName);
export const FileUpload = {
handlers: {},
@ -139,7 +141,7 @@ export const FileUpload = {
defaultUploads() {
return {
collection: Uploads.model,
collection: UploadsModel,
filter: new UploadFS.Filter({
onCheck: FileUpload.validateFileUpload,
}),
@ -161,7 +163,7 @@ export const FileUpload = {
defaultAvatars() {
return {
collection: Avatars.model,
collection: AvatarModel,
filter: new UploadFS.Filter({
onCheck: FileUpload.validateAvatarUpload,
}),
@ -176,7 +178,7 @@ export const FileUpload = {
defaultUserDataFiles() {
return {
collection: UserDataFiles.model,
collection: UserDataFilesModel,
getPath(file) {
return `${ settings.get('uniqueID') }/uploads/userData/${ file.userId }`;
},
@ -254,7 +256,7 @@ export const FileUpload = {
},
resizeImagePreview(file) {
file = Uploads.findOneById(file._id);
file = Promise.await(Uploads.findOneById(file._id));
file = FileUpload.addExtensionTo(file);
const image = FileUpload.getStore('Uploads')._store.getReadStream(file._id, file);
@ -279,7 +281,7 @@ export const FileUpload = {
return;
}
file = Uploads.findOneById(file._id);
file = Promise.await(Uploads.findOneById(file._id));
file = FileUpload.addExtensionTo(file);
const store = FileUpload.getStore('Uploads');
const image = store._store.getReadStream(file._id, file);
@ -378,11 +380,11 @@ export const FileUpload = {
}
// update file record to match user's username
const user = Users.findOneById(file.userId);
const oldAvatar = Avatars.findOneByName(user.username);
const oldAvatar = Promise.await(Avatars.findOneByName(user.username));
if (oldAvatar) {
Avatars.deleteFile(oldAvatar._id);
Promise.await(Avatars.deleteFile(oldAvatar._id));
}
Avatars.updateFileNameById(file._id, user.username);
Promise.await(Avatars.updateFileNameById(file._id, user.username));
// console.log('upload finished ->', file);
},
@ -571,11 +573,11 @@ export class FileUploadClass {
this.store.delete(fileId);
}
return this.model.deleteFile(fileId);
return Promise.await(this.model.deleteFile(fileId));
}
deleteById(fileId) {
const file = this.model.findOneById(fileId);
const file = Promise.await(this.model.findOneById(fileId));
if (!file) {
return;
@ -587,7 +589,7 @@ export class FileUploadClass {
}
deleteByName(fileName) {
const file = this.model.findOneByName(fileName);
const file = Promise.await(this.model.findOneByName(fileName));
if (!file) {
return;
@ -600,7 +602,7 @@ export class FileUploadClass {
deleteByRoomId(rid) {
const file = this.model.findOneByRoomId(rid);
const file = Promise.await(this.model.findOneByRoomId(rid));
if (!file) {
return;

@ -1,13 +1,13 @@
import { WebApp } from 'meteor/webapp';
import { FileUpload } from './FileUpload';
import { Uploads } from '../../../models';
import { Uploads } from '../../../models/server/raw';
WebApp.connectHandlers.use(FileUpload.getPath(), function(req, res, next) {
WebApp.connectHandlers.use(FileUpload.getPath(), async function(req, res, next) {
const match = /^\/([^\/]+)\/(.*)/.exec(req.url);
if (match && match[1]) {
const file = Uploads.findOneById(match[1]);
const file = await Uploads.findOneById(match[1]);
if (file) {
if (!FileUpload.requestCanAccessFiles(req)) {

@ -2,7 +2,7 @@ import { Meteor } from 'meteor/meteor';
import { UploadFS } from 'meteor/jalik:ufs';
import { settings } from '../../../settings/server';
import { Uploads } from '../../../models';
import { Uploads } from '../../../models/server/raw';
let protectedFiles;
@ -11,11 +11,11 @@ settings.watch('FileUpload_ProtectFiles', function(value) {
});
Meteor.methods({
getS3FileUrl(fileId) {
async getS3FileUrl(fileId) {
if (protectedFiles && !Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'sendFileMessage' });
}
const file = Uploads.findOneById(fileId);
const file = await Uploads.findOneById(fileId);
return UploadFS.getStore('AmazonS3:Uploads').getRedirectURL(file);
},

@ -3,8 +3,7 @@ import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';
import _ from 'underscore';
import { Uploads } from '../../../models/server';
import { Rooms } from '../../../models/server/raw';
import { Rooms, Uploads } from '../../../models/server/raw';
import { callbacks } from '../../../callbacks/server';
import { FileUpload } from '../lib/FileUpload';
import { canAccessRoom } from '../../../authorization/server/functions/canAccessRoom';
@ -35,7 +34,7 @@ Meteor.methods({
tmid: Match.Optional(String),
});
Uploads.updateFileComplete(file._id, user._id, _.omit(file, '_id'));
await Uploads.updateFileComplete(file._id, user._id, _.omit(file, '_id'));
const fileUrl = FileUpload.getPath(`${ file._id }/${ encodeURI(file.name) }`);

@ -14,6 +14,7 @@ import { incomingLogger } from '../logger';
import { processWebhookMessage } from '../../../lib/server';
import { API, APIClass, defaultRateLimiterOptions } from '../../../api/server';
import * as Models from '../../../models/server';
import { Integrations } from '../../../models/server/raw';
import { settings } from '../../../settings/server';
const compiledScripts = {};
@ -129,9 +130,10 @@ function removeIntegration(options, user) {
incomingLogger.info('Remove integration');
incomingLogger.debug(options);
const integrationToRemove = Models.Integrations.findOne({
urls: options.target_url,
});
const integrationToRemove = Promise.await(Integrations.findOneByUrl(options.target_url));
if (!integrationToRemove) {
return API.v1.failure('integration-not-found');
}
Meteor.runAsUser(user._id, () => Meteor.call('deleteOutgoingIntegration', integrationToRemove._id));
@ -373,10 +375,10 @@ const Api = new WebHookAPI({
}
}
this.integration = Models.Integrations.findOne({
this.integration = Promise.await(Integrations.findOne({
_id: this.request.params.integrationId,
token: decodeURIComponent(this.request.params.token),
});
}));
if (!this.integration) {
incomingLogger.info(`Invalid integration id ${ this.request.params.integrationId } or token ${ this.request.params.token }`);

@ -10,6 +10,7 @@ import Fiber from 'fibers';
import Future from 'fibers/future';
import * as Models from '../../../models/server';
import { Integrations, IntegrationHistory } from '../../../models/server/raw';
import { settings } from '../../../settings/server';
import { getRoomByNameOrIdWithOptionToJoin, processWebhookMessage } from '../../../lib/server';
import { outgoingLogger } from '../logger';
@ -22,7 +23,7 @@ export class RocketChatIntegrationHandler {
this.compiledScripts = {};
this.triggers = {};
Models.Integrations.find({ type: 'webhook-outgoing' }).fetch().forEach((data) => this.addIntegration(data));
Promise.await(Integrations.find({ type: 'webhook-outgoing' }).forEach((data) => this.addIntegration(data)));
}
addIntegration(record) {
@ -142,11 +143,11 @@ export class RocketChatIntegrationHandler {
}
if (historyId) {
Models.IntegrationHistory.update({ _id: historyId }, { $set: history });
Promise.await(IntegrationHistory.updateOne({ _id: historyId }, { $set: history }));
return historyId;
}
history._createdAt = new Date();
return Models.IntegrationHistory.insert(Object.assign({ _id: Random.id() }, history));
return Promise.await(IntegrationHistory.insertOne({ _id: Random.id(), ...history }));
}
// Trigger is the trigger, nameOrId is a string which is used to try and find a room, room is a room, message is a message, and data contains "user_name" if trigger.impersonateUser is truthful.
@ -715,7 +716,7 @@ export class RocketChatIntegrationHandler {
if (result.statusCode === 410) {
this.updateHistory({ historyId, step: 'after-process-http-status-410', error: true });
outgoingLogger.error(`Disabling the Integration "${ trigger.name }" because the status code was 401 (Gone).`);
Models.Integrations.update({ _id: trigger._id }, { $set: { enabled: false } });
Promise.await(Integrations.updateOne({ _id: trigger._id }, { $set: { enabled: false } }));
return;
}

@ -1,17 +1,20 @@
import { Meteor } from 'meteor/meteor';
import { hasPermission } from '../../../authorization';
import { IntegrationHistory, Integrations } from '../../../models';
import { hasPermission } from '../../../authorization/server';
import { IntegrationHistory, Integrations } from '../../../models/server/raw';
import notifications from '../../../notifications/server/lib/Notifications';
Meteor.methods({
clearIntegrationHistory(integrationId) {
async clearIntegrationHistory(integrationId) {
let integration;
if (hasPermission(this.userId, 'manage-outgoing-integrations') || hasPermission(this.userId, 'manage-outgoing-integrations', 'bot')) {
integration = Integrations.findOne(integrationId);
integration = await Integrations.findOneById(integrationId);
} else if (hasPermission(this.userId, 'manage-own-outgoing-integrations') || hasPermission(this.userId, 'manage-own-outgoing-integrations', 'bot')) {
integration = Integrations.findOne(integrationId, { fields: { '_createdBy._id': this.userId } });
integration = await Integrations.findOne({
_id: integrationId,
'_createdBy._id': this.userId,
});
} else {
throw new Meteor.Error('not_authorized', 'Unauthorized', { method: 'clearIntegrationHistory' });
}
@ -20,7 +23,7 @@ Meteor.methods({
throw new Meteor.Error('error-invalid-integration', 'Invalid integration', { method: 'clearIntegrationHistory' });
}
IntegrationHistory.removeByIntegrationId(integrationId);
await IntegrationHistory.removeByIntegrationId(integrationId);
notifications.streamIntegrationHistory.emit(integrationId, { type: 'removed' });

@ -4,13 +4,14 @@ import { Babel } from 'meteor/babel-compiler';
import _ from 'underscore';
import s from 'underscore.string';
import { hasPermission, hasAllPermission } from '../../../../authorization';
import { Users, Rooms, Integrations, Roles, Subscriptions } from '../../../../models';
import { hasPermission, hasAllPermission } from '../../../../authorization/server';
import { Users, Rooms, Subscriptions } from '../../../../models/server';
import { Integrations, Roles } from '../../../../models/server/raw';
const validChannelChars = ['@', '#'];
Meteor.methods({
addIncomingIntegration(integration) {
async addIncomingIntegration(integration) {
if (!hasPermission(this.userId, 'manage-incoming-integrations') && !hasPermission(this.userId, 'manage-own-incoming-integrations')) {
throw new Meteor.Error('not_authorized', 'Unauthorized', { method: 'addIncomingIntegration' });
}
@ -95,9 +96,11 @@ Meteor.methods({
integration._createdAt = new Date();
integration._createdBy = Users.findOne(this.userId, { fields: { username: 1 } });
Roles.addUserRoles(user._id, 'bot');
await Roles.addUserRoles(user._id, 'bot');
integration._id = Integrations.insert(integration);
const result = await Integrations.insertOne(integration);
integration._id = result.insertedId;
return integration;
},

@ -1,16 +1,19 @@
import { Meteor } from 'meteor/meteor';
import { hasPermission } from '../../../../authorization';
import { Integrations } from '../../../../models';
import { hasPermission } from '../../../../authorization/server';
import { Integrations } from '../../../../models/server/raw';
Meteor.methods({
deleteIncomingIntegration(integrationId) {
async deleteIncomingIntegration(integrationId) {
let integration;
if (hasPermission(this.userId, 'manage-incoming-integrations')) {
integration = Integrations.findOne(integrationId);
integration = Integrations.findOneById(integrationId);
} else if (hasPermission(this.userId, 'manage-own-incoming-integrations')) {
integration = Integrations.findOne(integrationId, { fields: { '_createdBy._id': this.userId } });
integration = Integrations.findOne({
_id: integrationId,
'_createdBy._id': this.userId,
});
} else {
throw new Meteor.Error('not_authorized', 'Unauthorized', { method: 'deleteIncomingIntegration' });
}
@ -19,7 +22,7 @@ Meteor.methods({
throw new Meteor.Error('error-invalid-integration', 'Invalid integration', { method: 'deleteIncomingIntegration' });
}
Integrations.remove({ _id: integrationId });
await Integrations.removeById(integrationId);
return true;
},

@ -3,13 +3,14 @@ import { Babel } from 'meteor/babel-compiler';
import _ from 'underscore';
import s from 'underscore.string';
import { Integrations, Rooms, Users, Roles, Subscriptions } from '../../../../models';
import { hasAllPermission, hasPermission } from '../../../../authorization';
import { Rooms, Users, Subscriptions } from '../../../../models/server';
import { Integrations, Roles } from '../../../../models/server/raw';
import { hasAllPermission, hasPermission } from '../../../../authorization/server';
const validChannelChars = ['@', '#'];
Meteor.methods({
updateIncomingIntegration(integrationId, integration) {
async updateIncomingIntegration(integrationId, integration) {
if (!_.isString(integration.channel) || integration.channel.trim() === '') {
throw new Meteor.Error('error-invalid-channel', 'Invalid channel', { method: 'updateIncomingIntegration' });
}
@ -25,9 +26,9 @@ Meteor.methods({
let currentIntegration;
if (hasPermission(this.userId, 'manage-incoming-integrations')) {
currentIntegration = Integrations.findOne(integrationId);
currentIntegration = await Integrations.findOneById(integrationId);
} else if (hasPermission(this.userId, 'manage-own-incoming-integrations')) {
currentIntegration = Integrations.findOne({ _id: integrationId, '_createdBy._id': this.userId });
currentIntegration = await Integrations.findOne({ _id: integrationId, '_createdBy._id': this.userId });
} else {
throw new Meteor.Error('not_authorized', 'Unauthorized', { method: 'updateIncomingIntegration' });
}
@ -43,14 +44,14 @@ Meteor.methods({
integration.scriptCompiled = Babel.compile(integration.script, babelOptions).code;
integration.scriptError = undefined;
Integrations.update(integrationId, {
await Integrations.updateOne({ _id: integrationId }, {
$set: { scriptCompiled: integration.scriptCompiled },
$unset: { scriptError: 1 },
});
} catch (e) {
integration.scriptCompiled = undefined;
integration.scriptError = _.pick(e, 'name', 'message', 'stack');
Integrations.update(integrationId, {
await Integrations.updateOne({ _id: integrationId }, {
$set: {
scriptError: integration.scriptError,
},
@ -100,9 +101,9 @@ Meteor.methods({
throw new Meteor.Error('error-invalid-post-as-user', 'Invalid Post As User', { method: 'updateIncomingIntegration' });
}
Roles.addUserRoles(user._id, 'bot');
await Roles.addUserRoles(user._id, 'bot');
Integrations.update(integrationId, {
await Integrations.updateOne({ _id: integrationId }, {
$set: {
enabled: integration.enabled,
name: integration.name,
@ -117,6 +118,6 @@ Meteor.methods({
},
});
return Integrations.findOne(integrationId);
return Integrations.findOneById(integrationId);
},
});

@ -1,11 +1,12 @@
import { Meteor } from 'meteor/meteor';
import { hasPermission } from '../../../../authorization';
import { Users, Integrations } from '../../../../models';
import { hasPermission } from '../../../../authorization/server';
import { Users } from '../../../../models/server';
import { Integrations } from '../../../../models/server/raw';
import { integrations } from '../../../lib/rocketchat';
Meteor.methods({
addOutgoingIntegration(integration) {
async addOutgoingIntegration(integration) {
if (!hasPermission(this.userId, 'manage-outgoing-integrations')
&& !hasPermission(this.userId, 'manage-own-outgoing-integrations')
&& !hasPermission(this.userId, 'manage-outgoing-integrations', 'bot')
@ -17,7 +18,9 @@ Meteor.methods({
integration._createdAt = new Date();
integration._createdBy = Users.findOne(this.userId, { fields: { username: 1 } });
integration._id = Integrations.insert(integration);
const result = await Integrations.insertOne(integration);
integration._id = result.insertedId;
return integration;
},

@ -1,16 +1,19 @@
import { Meteor } from 'meteor/meteor';
import { hasPermission } from '../../../../authorization';
import { IntegrationHistory, Integrations } from '../../../../models';
import { hasPermission } from '../../../../authorization/server';
import { IntegrationHistory, Integrations } from '../../../../models/server/raw';
Meteor.methods({
deleteOutgoingIntegration(integrationId) {
async deleteOutgoingIntegration(integrationId) {
let integration;
if (hasPermission(this.userId, 'manage-outgoing-integrations') || hasPermission(this.userId, 'manage-outgoing-integrations', 'bot')) {
integration = Integrations.findOne(integrationId);
integration = Integrations.findOneById(integrationId);
} else if (hasPermission(this.userId, 'manage-own-outgoing-integrations') || hasPermission(this.userId, 'manage-own-outgoing-integrations', 'bot')) {
integration = Integrations.findOne(integrationId, { fields: { '_createdBy._id': this.userId } });
integration = Integrations.findOne({
_id: integrationId,
'_createdBy._id': this.userId,
});
} else {
throw new Meteor.Error('not_authorized', 'Unauthorized', { method: 'deleteOutgoingIntegration' });
}
@ -19,8 +22,8 @@ Meteor.methods({
throw new Meteor.Error('error-invalid-integration', 'Invalid integration', { method: 'deleteOutgoingIntegration' });
}
Integrations.remove({ _id: integrationId });
IntegrationHistory.removeByIntegrationId(integrationId);
await Integrations.removeById(integrationId);
await IntegrationHistory.removeByIntegrationId(integrationId);
return true;
},

@ -1,17 +1,20 @@
import { Meteor } from 'meteor/meteor';
import { hasPermission } from '../../../../authorization';
import { Integrations, IntegrationHistory } from '../../../../models';
import { hasPermission } from '../../../../authorization/server';
import { Integrations, IntegrationHistory } from '../../../../models/server/raw';
import { triggerHandler } from '../../lib/triggerHandler';
Meteor.methods({
replayOutgoingIntegration({ integrationId, historyId }) {
async replayOutgoingIntegration({ integrationId, historyId }) {
let integration;
if (hasPermission(this.userId, 'manage-outgoing-integrations') || hasPermission(this.userId, 'manage-outgoing-integrations', 'bot')) {
integration = Integrations.findOne(integrationId);
integration = await Integrations.findOneById(integrationId);
} else if (hasPermission(this.userId, 'manage-own-outgoing-integrations') || hasPermission(this.userId, 'manage-own-outgoing-integrations', 'bot')) {
integration = Integrations.findOne(integrationId, { fields: { '_createdBy._id': this.userId } });
integration = await Integrations.findOne({
_id: integrationId,
'_createdBy._id': this.userId,
});
} else {
throw new Meteor.Error('not_authorized', 'Unauthorized', { method: 'replayOutgoingIntegration' });
}
@ -20,7 +23,7 @@ Meteor.methods({
throw new Meteor.Error('error-invalid-integration', 'Invalid integration', { method: 'replayOutgoingIntegration' });
}
const history = IntegrationHistory.findOneByIntegrationIdAndHistoryId(integration._id, historyId);
const history = await IntegrationHistory.findOneByIntegrationIdAndHistoryId(integration._id, historyId);
if (!history) {
throw new Meteor.Error('error-invalid-integration-history', 'Invalid Integration History', { method: 'replayOutgoingIntegration' });

@ -1,11 +1,12 @@
import { Meteor } from 'meteor/meteor';
import { hasPermission } from '../../../../authorization';
import { Integrations, Users } from '../../../../models';
import { hasPermission } from '../../../../authorization/server';
import { Users } from '../../../../models/server';
import { Integrations } from '../../../../models/server/raw';
import { integrations } from '../../../lib/rocketchat';
Meteor.methods({
updateOutgoingIntegration(integrationId, integration) {
async updateOutgoingIntegration(integrationId, integration) {
integration = integrations.validateOutgoing(integration, this.userId);
if (!integration.token || integration.token.trim() === '') {
@ -15,9 +16,9 @@ Meteor.methods({
let currentIntegration;
if (hasPermission(this.userId, 'manage-outgoing-integrations')) {
currentIntegration = Integrations.findOne(integrationId);
currentIntegration = await Integrations.findOneById(integrationId);
} else if (hasPermission(this.userId, 'manage-own-outgoing-integrations')) {
currentIntegration = Integrations.findOne({ _id: integrationId, '_createdBy._id': this.userId });
currentIntegration = await Integrations.findOne({ _id: integrationId, '_createdBy._id': this.userId });
} else {
throw new Meteor.Error('not_authorized', 'Unauthorized', { method: 'updateOutgoingIntegration' });
}
@ -26,18 +27,18 @@ Meteor.methods({
throw new Meteor.Error('invalid_integration', '[methods] updateOutgoingIntegration -> integration not found');
}
if (integration.scriptCompiled) {
Integrations.update(integrationId, {
await Integrations.updateOne({ _id: integrationId }, {
$set: { scriptCompiled: integration.scriptCompiled },
$unset: { scriptError: 1 },
});
} else {
Integrations.update(integrationId, {
await Integrations.updateOne({ _id: integrationId }, {
$set: { scriptError: integration.scriptError },
$unset: { scriptCompiled: 1 },
});
}
Integrations.update(integrationId, {
await Integrations.updateOne({ _id: integrationId }, {
$set: {
event: integration.event,
enabled: integration.enabled,
@ -65,6 +66,6 @@ Meteor.methods({
},
});
return Integrations.findOne(integrationId);
return Integrations.findOneById(integrationId);
},
});

@ -3,7 +3,8 @@ import { Random } from 'meteor/random';
import { hasPermission } from '../../../authorization';
import { Notifications } from '../../../notifications';
import { Invites, Subscriptions, Rooms } from '../../../models/server';
import { Subscriptions, Rooms } from '../../../models/server';
import { Invites } from '../../../models/server/raw';
import { settings } from '../../../settings';
import { getURL } from '../../../utils/lib/getURL';
import { roomTypes, RoomMemberActions } from '../../../utils/server';
@ -23,7 +24,7 @@ function getInviteUrl(invite) {
const possibleDays = [0, 1, 7, 15, 30];
const possibleUses = [0, 1, 5, 10, 25, 50, 100];
export const findOrCreateInvite = (userId, invite) => {
export const findOrCreateInvite = async (userId, invite) => {
if (!userId || !invite) {
return false;
}
@ -57,7 +58,7 @@ export const findOrCreateInvite = (userId, invite) => {
}
// Before anything, let's check if there's an existing invite with the same settings for the same channel and user and that has not yet expired.
const existing = Invites.findOneByUserRoomMaxUsesAndExpiration(userId, invite.rid, maxUses, days);
const existing = await Invites.findOneByUserRoomMaxUsesAndExpiration(userId, invite.rid, maxUses, days);
// If an existing invite was found, return it's _id instead of creating a new one.
if (existing) {
@ -86,7 +87,7 @@ export const findOrCreateInvite = (userId, invite) => {
uses: 0,
};
Invites.create(createInvite);
await Invites.insertOne(createInvite);
Notifications.notifyUser(userId, 'updateInvites', { invite: createInvite });
createInvite.url = getInviteUrl(createInvite);

@ -1,9 +1,9 @@
import { Meteor } from 'meteor/meteor';
import { hasPermission } from '../../../authorization';
import { Invites } from '../../../models';
import { hasPermission } from '../../../authorization/server';
import { Invites } from '../../../models/server/raw';
export const listInvites = (userId) => {
export const listInvites = async (userId) => {
if (!userId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'listInvites' });
}
@ -12,5 +12,5 @@ export const listInvites = (userId) => {
throw new Meteor.Error('not_authorized');
}
return Invites.find({}).fetch();
return Invites.find({}).toArray();
};

@ -1,9 +1,9 @@
import { Meteor } from 'meteor/meteor';
import { hasPermission } from '../../../authorization';
import Invites from '../../../models/server/models/Invites';
import { Invites } from '../../../models/server/raw';
export const removeInvite = (userId, invite) => {
export const removeInvite = async (userId, invite) => {
if (!userId || !invite) {
return false;
}
@ -17,13 +17,13 @@ export const removeInvite = (userId, invite) => {
}
// Before anything, let's check if there's an existing invite
const existing = Invites.findOneById(invite._id);
const existing = await Invites.findOneById(invite._id);
if (!existing) {
throw new Meteor.Error('invalid-invitation-id', 'Invalid Invitation _id', { method: 'removeInvite' });
}
Invites.removeById(invite._id);
await Invites.removeById(invite._id);
return true;
};

@ -1,11 +1,12 @@
import { Meteor } from 'meteor/meteor';
import { Invites, Users, Subscriptions } from '../../../models/server';
import { Users, Subscriptions } from '../../../models/server';
import { Invites } from '../../../models/server/raw';
import { validateInviteToken } from './validateInviteToken';
import { addUserToRoom } from '../../../lib/server/functions/addUserToRoom';
import { roomTypes, RoomMemberActions } from '../../../utils/server';
export const useInviteToken = (userId, token) => {
export const useInviteToken = async (userId, token) => {
if (!userId) {
throw new Meteor.Error('error-invalid-user', 'The user is invalid', { method: 'useInviteToken', field: 'userId' });
}
@ -14,7 +15,7 @@ export const useInviteToken = (userId, token) => {
throw new Meteor.Error('error-invalid-token', 'The invite token is invalid.', { method: 'useInviteToken', field: 'token' });
}
const { inviteData, room } = validateInviteToken(token);
const { inviteData, room } = await validateInviteToken(token);
if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.INVITE)) {
throw new Meteor.Error('error-room-type-not-allowed', 'Can\'t join room of this type via invite', { method: 'useInviteToken', field: 'token' });
@ -25,7 +26,7 @@ export const useInviteToken = (userId, token) => {
const subscription = Subscriptions.findOneByRoomIdAndUserId(room._id, user._id, { fields: { _id: 1 } });
if (!subscription) {
Invites.increaseUsageById(inviteData._id);
await Invites.increaseUsageById(inviteData._id);
}
// If the user already has an username, then join the invite room,

@ -1,13 +1,14 @@
import { Meteor } from 'meteor/meteor';
import { Invites, Rooms } from '../../../models';
import { Rooms } from '../../../models';
import { Invites } from '../../../models/server/raw';
export const validateInviteToken = (token) => {
export const validateInviteToken = async (token) => {
if (!token || typeof token !== 'string') {
throw new Meteor.Error('error-invalid-token', 'The invite token is invalid.', { method: 'validateInviteToken', field: 'token' });
}
const inviteData = Invites.findOneById(token);
const inviteData = await Invites.findOneById(token);
if (!inviteData) {
throw new Meteor.Error('error-invalid-token', 'The invite token is invalid.', { method: 'validateInviteToken', field: 'token' });
}

@ -2,14 +2,15 @@ import { Meteor } from 'meteor/meteor';
import { FileUpload } from '../../../file-upload/server';
import { settings } from '../../../settings/server';
import { Messages, Uploads, Rooms } from '../../../models/server';
import { Messages, Rooms } from '../../../models/server';
import { Uploads } from '../../../models/server/raw';
import { Notifications } from '../../../notifications/server';
import { callbacks } from '../../../callbacks/server';
import { Apps } from '../../../apps/server';
import { IMessage } from '../../../../definition/IMessage';
import { IUser } from '../../../../definition/IUser';
export const deleteMessage = function(message: IMessage, user: IUser): void {
export const deleteMessage = async function(message: IMessage, user: IUser): Promise<void> {
const deletedMsg = Messages.findOneById(message._id);
const isThread = deletedMsg.tcount > 0;
const keepHistory = settings.get('Message_KeepHistory') || isThread;
@ -36,9 +37,9 @@ export const deleteMessage = function(message: IMessage, user: IUser): void {
Messages.setHiddenById(message._id, true);
}
files.forEach((file) => {
file?._id && Uploads.update(file._id, { $set: { _hidden: true } });
});
for await (const file of files) {
file?._id && await Uploads.update({ _id: file._id }, { $set: { _hidden: true } });
}
} else {
if (!showDeletedStatus) {
Messages.removeById(message._id);

@ -2,7 +2,8 @@ import { Meteor } from 'meteor/meteor';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';
import { FileUpload } from '../../../file-upload/server';
import { Users, Subscriptions, Messages, Rooms, Integrations, FederationServers } from '../../../models/server';
import { Users, Subscriptions, Messages, Rooms } from '../../../models/server';
import { FederationServers, Integrations } from '../../../models/server/raw';
import { settings } from '../../../settings/server';
import { updateGroupDMsName } from './updateGroupDMsName';
import { relinquishRoomOwnerships } from './relinquishRoomOwnerships';
@ -10,7 +11,7 @@ import { getSubscribedRoomsForUserWithDetails, shouldRemoveOrChangeOwner } from
import { getUserSingleOwnedRooms } from './getUserSingleOwnedRooms';
import { api } from '../../../../server/sdk/api';
export const deleteUser = function(userId, confirmRelinquish = false) {
export async function deleteUser(userId, confirmRelinquish = false) {
const user = Users.findOneById(userId, {
fields: { username: 1, avatarOrigin: 1, federation: 1 },
});
@ -36,7 +37,7 @@ export const deleteUser = function(userId, confirmRelinquish = false) {
// Users without username can't do anything, so there is nothing to remove
if (user.username != null) {
relinquishRoomOwnerships(userId, subscribedRooms);
await relinquishRoomOwnerships(userId, subscribedRooms);
const messageErasureType = settings.get('Message_ErasureType');
switch (messageErasureType) {
@ -64,7 +65,7 @@ export const deleteUser = function(userId, confirmRelinquish = false) {
FileUpload.getStore('Avatars').deleteByName(user.username);
}
Integrations.disableByUserId(userId); // Disables all the integrations which rely on the user being deleted.
await Integrations.disableByUserId(userId); // Disables all the integrations which rely on the user being deleted.
api.broadcast('user.deleted', user);
}
@ -75,5 +76,5 @@ export const deleteUser = function(userId, confirmRelinquish = false) {
updateGroupDMsName(user);
// Refresh the servers list
FederationServers.refreshServers();
};
await FederationServers.refreshServers();
}

@ -1,5 +1,6 @@
import { FileUpload } from '../../../file-upload/server';
import { Subscriptions, Messages, Rooms, Roles } from '../../../models/server';
import { Subscriptions, Messages, Rooms } from '../../../models/server';
import { Roles } from '../../../models/server/raw';
const bulkRoomCleanUp = (rids) => {
// no bulk deletion for files
@ -12,11 +13,14 @@ const bulkRoomCleanUp = (rids) => {
]));
};
export const relinquishRoomOwnerships = function(userId, subscribedRooms, removeDirectMessages = true) {
export const relinquishRoomOwnerships = async function(userId, subscribedRooms, removeDirectMessages = true) {
// change owners
subscribedRooms
.filter(({ shouldChangeOwner }) => shouldChangeOwner)
.forEach(({ newOwner, rid }) => Roles.addUserRoles(newOwner, ['owner'], rid));
const changeOwner = subscribedRooms
.filter(({ shouldChangeOwner }) => shouldChangeOwner);
for await (const { newOwner, rid } of changeOwner) {
await Roles.addUserRoles(newOwner, ['owner'], rid);
}
const roomIdsToRemove = subscribedRooms.filter(({ shouldBeRemoved }) => shouldBeRemoved).map(({ rid }) => rid);

@ -2,13 +2,14 @@ import { Meteor } from 'meteor/meteor';
import { RocketChatFile } from '../../../file';
import { FileUpload } from '../../../file-upload';
import { Rooms, Avatars, Messages } from '../../../models/server';
import { Rooms, Messages } from '../../../models/server';
import { Avatars } from '../../../models/server/raw';
import { api } from '../../../../server/sdk/api';
export const setRoomAvatar = function(rid, dataURI, user) {
export const setRoomAvatar = async function(rid, dataURI, user) {
const fileStore = FileUpload.getStore('Avatars');
const current = Avatars.findOneByRoomId(rid);
const current = await Avatars.findOneByRoomId(rid);
if (!dataURI) {
fileStore.deleteByRoomId(rid);

@ -63,7 +63,7 @@ export function setUserActiveStatus(userId, active, confirmRelinquish = false) {
}
closeOmnichannelConversations(user, livechatSubscribedRooms);
relinquishRoomOwnerships(user, chatSubscribedRooms, false);
Promise.await(relinquishRoomOwnerships(user, chatSubscribedRooms, false));
}
if (active && !user.active) {

@ -3,7 +3,8 @@ import s from 'underscore.string';
import { Accounts } from 'meteor/accounts-base';
import { settings } from '../../../settings';
import { Users, Invites } from '../../../models/server';
import { Users } from '../../../models/server';
import { Invites } from '../../../models/server/raw';
import { hasPermission } from '../../../authorization';
import { RateLimiter } from '../lib';
import { addUserToRoom } from './addUserToRoom';
@ -70,7 +71,7 @@ export const _setUsername = function(userId, u, fullUser) {
// If it's the first username and the user has an invite Token, then join the invite room
if (!previousUsername && user.inviteToken) {
const inviteData = Invites.findOneById(user.inviteToken);
const inviteData = Promise.await(Invites.findOneById(user.inviteToken));
if (inviteData && inviteData.rid) {
addUserToRoom(inviteData.rid, user);
}

@ -1,7 +1,8 @@
import _ from 'underscore';
import { settings } from '../../../settings';
import { Subscriptions, Users, Roles } from '../../../models';
import { Subscriptions, Users } from '../../../models';
import { Roles } from '../../../models/server/raw';
export function getRoomRoles(rid) {
const options = {
@ -17,7 +18,7 @@ export function getRoomRoles(rid) {
const UI_Use_Real_Name = settings.get('UI_Use_Real_Name') === true;
const roles = Roles.find({ scope: 'Subscriptions', description: { $exists: 1, $ne: '' } }).fetch();
const roles = Promise.await(Roles.find({ scope: 'Subscriptions', description: { $exists: 1, $ne: '' } }).toArray());
const subscriptions = Subscriptions.findByRoomIdAndRoles(rid, _.pluck(roles, '_id'), options).fetch();
if (!UI_Use_Real_Name) {

@ -6,7 +6,7 @@ import { Messages } from '../../../models';
import { deleteMessage } from '../functions';
Meteor.methods({
deleteMessage(message) {
async deleteMessage(message) {
check(message, Match.ObjectIncluding({
_id: String,
}));

@ -9,7 +9,7 @@ import { Users } from '../../../models';
import { deleteUser } from '../functions';
Meteor.methods({
deleteUserOwnAccount(password, confirmRelinquish) {
async deleteUserOwnAccount(password, confirmRelinquish) {
check(password, String);
if (!Meteor.userId()) {
@ -39,7 +39,7 @@ Meteor.methods({
throw new Meteor.Error('error-invalid-username', 'Invalid username', { method: 'deleteUserOwnAccount' });
}
deleteUser(userId, confirmRelinquish);
await deleteUser(userId, confirmRelinquish);
return true;
},

@ -1,13 +1,14 @@
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import { hasPermission, hasRole, getUsersInRole } from '../../../authorization';
import { Subscriptions, Rooms } from '../../../models';
import { hasPermission, hasRole } from '../../../authorization/server';
import { Subscriptions, Rooms } from '../../../models/server';
import { removeUserFromRoom } from '../functions';
import { roomTypes, RoomMemberActions } from '../../../utils/server';
import { Roles } from '../../../models/server/raw';
Meteor.methods({
leaveRoom(rid) {
async leaveRoom(rid) {
check(rid, String);
if (!Meteor.userId()) {
@ -17,7 +18,7 @@ Meteor.methods({
const room = Rooms.findOneById(rid);
const user = Meteor.user();
if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.LEAVE)) {
if (!user || !roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.LEAVE)) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'leaveRoom' });
}
@ -32,7 +33,8 @@ Meteor.methods({
// If user is room owner, check if there are other owners. If there isn't anyone else, warn user to set a new owner.
if (hasRole(user._id, 'owner', room._id)) {
const numOwners = getUsersInRole('owner', room._id).count();
const cursor = await Roles.findUsersInRole('owner', room._id);
const numOwners = Promise.await(cursor.count());
if (numOwners === 1) {
throw new Meteor.Error('error-you-are-last-owner', 'You are the last owner. Please set new owner before leaving the room.', { method: 'leaveRoom' });
}

@ -1,11 +1,11 @@
import { Meteor } from 'meteor/meteor';
import { ServiceConfiguration } from 'meteor/service-configuration';
import { hasPermission } from '../../../authorization';
import { Settings } from '../../../models';
import { hasPermission } from '../../../authorization/server';
import { Settings } from '../../../models/server/raw';
Meteor.methods({
refreshOAuthService() {
async refreshOAuthService() {
if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'refreshOAuthService' });
}
@ -16,6 +16,6 @@ Meteor.methods({
ServiceConfiguration.configurations.remove({});
Settings.update({ _id: /^(Accounts_OAuth_|SAML_|CAS_|Blockstack_).+/ }, { $set: { _updatedAt: new Date() } }, { multi: true });
await Settings.update({ _id: /^(Accounts_OAuth_|SAML_|CAS_|Blockstack_).+/ }, { $set: { _updatedAt: new Date() } }, { multi: true });
},
});

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save