diff --git a/packages/rocketchat-lib/lib/Message.coffee b/packages/rocketchat-lib/lib/Message.coffee deleted file mode 100644 index cbf6e92a89ff..000000000000 --- a/packages/rocketchat-lib/lib/Message.coffee +++ /dev/null @@ -1,26 +0,0 @@ -RocketChat.Message = - parse: (msg, language) -> - messageType = RocketChat.MessageTypes.getType(msg) - if messageType?.render? - return messageType.render(msg) - else if messageType?.template? - # render template - else if messageType?.message? - if not language and localStorage?.getItem('userLanguage') - language = localStorage.getItem('userLanguage') - if messageType.data?(msg)? - return TAPi18n.__(messageType.message, messageType.data(msg), language) - else - return TAPi18n.__(messageType.message, {}, language) - else - if msg.u?.username is RocketChat.settings.get('Chatops_Username') - msg.html = msg.msg - return msg.html - - msg.html = msg.msg - if _.trim(msg.html) isnt '' - msg.html = _.escapeHTML msg.html - - # message = RocketChat.callbacks.run 'renderMessage', msg - msg.html = msg.html.replace /\n/gm, '
' - return msg.html diff --git a/packages/rocketchat-lib/lib/Message.js b/packages/rocketchat-lib/lib/Message.js new file mode 100644 index 000000000000..1eefff6ccbac --- /dev/null +++ b/packages/rocketchat-lib/lib/Message.js @@ -0,0 +1,29 @@ +RocketChat.Message = { + parse(msg, language) { + const messageType = RocketChat.MessageTypes.getType(msg); + if (messageType) { + if (messageType.render) { + return messageType.render(msg); + } else if (messageType.template) { + // Render message + return; + } else if (messageType.message) { + if (!language && typeof localStorage !== 'undefined') { + language = localStorage.getItem('userLanguage'); + } + const data = (typeof messageType.data === 'function' && messageType.data(msg)) || {}; + return TAPi18n.__(messageType.message, data, language); + } + } + if (msg.u && msg.u.username === RocketChat.settings.get('Chatops_Username')) { + msg.html = msg.msg; + return msg.html; + } + msg.html = msg.msg; + if (_.trim(msg.html) !== '') { + msg.html = _.escapeHTML(msg.html); + } + msg.html = msg.html.replace(/\n/gm, '
'); + return msg.html; + } +}; diff --git a/packages/rocketchat-lib/lib/MessageTypes.coffee b/packages/rocketchat-lib/lib/MessageTypes.coffee deleted file mode 100644 index 7912e7fb943d..000000000000 --- a/packages/rocketchat-lib/lib/MessageTypes.coffee +++ /dev/null @@ -1,112 +0,0 @@ -RocketChat.MessageTypes = new class - types = {} - - registerType = (options) -> - types[options.id] = options - - getType = (message) -> - return types[message?.t] - - isSystemMessage = (message) -> - return types[message?.t]?.system - - registerType: registerType - getType: getType - isSystemMessage: isSystemMessage - -Meteor.startup -> - RocketChat.MessageTypes.registerType - id: 'r' - system: true - message: 'Room_name_changed' - data: (message) -> - return { room_name: message.msg, user_by: message.u.username } - - RocketChat.MessageTypes.registerType - id: 'au' - system: true - message: 'User_added_by' - data: (message) -> - return { user_added: message.msg, user_by: message.u.username } - - RocketChat.MessageTypes.registerType - id: 'ru' - system: true - message: 'User_removed_by' - data: (message) -> - return { user_removed: message.msg, user_by: message.u.username } - - RocketChat.MessageTypes.registerType - id: 'ul' - system: true - message: 'User_left' - data: (message) -> - return { user_left: message.u.username } - - RocketChat.MessageTypes.registerType - id: 'uj' - system: true - message: 'User_joined_channel' - data: (message) -> - return { user: message.u.username } - - RocketChat.MessageTypes.registerType - id: 'wm' - system: true - message: 'Welcome' - data: (message) -> - return { user: message.u.username } - - RocketChat.MessageTypes.registerType - id: 'rm' - system: true - message: 'Message_removed' - data: (message) -> - return { user: message.u.username } - - RocketChat.MessageTypes.registerType - id: 'rtc' - render: (message) -> - RocketChat.callbacks.run 'renderRtcMessage', message - - RocketChat.MessageTypes.registerType - id: 'user-muted' - system: true - message: 'User_muted_by' - data: (message) -> - return { user_muted: message.msg, user_by: message.u.username } - - RocketChat.MessageTypes.registerType - id: 'user-unmuted' - system: true - message: 'User_unmuted_by' - data: (message) -> - return { user_unmuted: message.msg, user_by: message.u.username } - - RocketChat.MessageTypes.registerType - id: 'subscription-role-added' - system: true - message: '__username__was_set__role__by__user_by_' - data: (message) -> - return { username: message.msg, role: message.role, user_by: message.u.username } - - RocketChat.MessageTypes.registerType - id: 'subscription-role-removed' - system: true - message: '__username__is_no_longer__role__defined_by__user_by_' - data: (message) -> - return { username: message.msg, role: message.role, user_by: message.u.username } - - RocketChat.MessageTypes.registerType - id: 'room-archived' - system: true - message: 'This_room_has_been_archived_by__username_' - data: (message) -> - return { username: message.u.username } - - RocketChat.MessageTypes.registerType - id: 'room-unarchived' - system: true - message: 'This_room_has_been_unarchived_by__username_' - data: (message) -> - return { username: message.u.username } diff --git a/packages/rocketchat-lib/lib/MessageTypes.js b/packages/rocketchat-lib/lib/MessageTypes.js new file mode 100644 index 000000000000..db57c899ad68 --- /dev/null +++ b/packages/rocketchat-lib/lib/MessageTypes.js @@ -0,0 +1,167 @@ +RocketChat.MessageTypes = new class { + constructor() { + this.types = {}; + } + + registerType(options) { + return this.types[options.id] = options; + } + + getType(message) { + return this.types[message && message.t]; + } + + isSystemMessage(message) { + const type = this.types[message && message.t]; + return type && type.system; + } + +}; + +Meteor.startup(function() { + RocketChat.MessageTypes.registerType({ + id: 'r', + system: true, + message: 'Room_name_changed', + data(message) { + return { + room_name: message.msg, + user_by: message.u.username + }; + } + }); + RocketChat.MessageTypes.registerType({ + id: 'au', + system: true, + message: 'User_added_by', + data(message) { + return { + user_added: message.msg, + user_by: message.u.username + }; + } + }); + RocketChat.MessageTypes.registerType({ + id: 'ru', + system: true, + message: 'User_removed_by', + data(message) { + return { + user_removed: message.msg, + user_by: message.u.username + }; + } + }); + RocketChat.MessageTypes.registerType({ + id: 'ul', + system: true, + message: 'User_left', + data(message) { + return { + user_left: message.u.username + }; + } + }); + RocketChat.MessageTypes.registerType({ + id: 'uj', + system: true, + message: 'User_joined_channel', + data(message) { + return { + user: message.u.username + }; + } + }); + RocketChat.MessageTypes.registerType({ + id: 'wm', + system: true, + message: 'Welcome', + data(message) { + return { + user: message.u.username + }; + } + }); + RocketChat.MessageTypes.registerType({ + id: 'rm', + system: true, + message: 'Message_removed', + data(message) { + return { + user: message.u.username + }; + } + }); + RocketChat.MessageTypes.registerType({ + id: 'rtc', + render(message) { + return RocketChat.callbacks.run('renderRtcMessage', message); + } + }); + RocketChat.MessageTypes.registerType({ + id: 'user-muted', + system: true, + message: 'User_muted_by', + data(message) { + return { + user_muted: message.msg, + user_by: message.u.username + }; + } + }); + RocketChat.MessageTypes.registerType({ + id: 'user-unmuted', + system: true, + message: 'User_unmuted_by', + data(message) { + return { + user_unmuted: message.msg, + user_by: message.u.username + }; + } + }); + RocketChat.MessageTypes.registerType({ + id: 'subscription-role-added', + system: true, + message: '__username__was_set__role__by__user_by_', + data(message) { + return { + username: message.msg, + role: message.role, + user_by: message.u.username + }; + } + }); + RocketChat.MessageTypes.registerType({ + id: 'subscription-role-removed', + system: true, + message: '__username__is_no_longer__role__defined_by__user_by_', + data(message) { + return { + username: message.msg, + role: message.role, + user_by: message.u.username + }; + } + }); + RocketChat.MessageTypes.registerType({ + id: 'room-archived', + system: true, + message: 'This_room_has_been_archived_by__username_', + data(message) { + return { + username: message.u.username + }; + } + }); + RocketChat.MessageTypes.registerType({ + id: 'room-unarchived', + system: true, + message: 'This_room_has_been_unarchived_by__username_', + data(message) { + return { + username: message.u.username + }; + } + }); +}); diff --git a/packages/rocketchat-lib/lib/slashCommand.coffee b/packages/rocketchat-lib/lib/slashCommand.coffee deleted file mode 100644 index 8e8b7b4ee701..000000000000 --- a/packages/rocketchat-lib/lib/slashCommand.coffee +++ /dev/null @@ -1,26 +0,0 @@ -RocketChat.slashCommands = - commands: {} - -RocketChat.slashCommands.add = (command, callback, options, result) -> - RocketChat.slashCommands.commands[command] = - command: command - callback: callback - params: options?.params - description: options?.description - clientOnly: options?.clientOnly or false - result: result - return - -RocketChat.slashCommands.run = (command, params, item) -> - if RocketChat.slashCommands.commands[command]?.callback? - callback = RocketChat.slashCommands.commands[command].callback - callback command, params, item - - -Meteor.methods - slashCommand: (command) -> - if not Meteor.userId() - throw new Meteor.Error 'error-invalid-user', 'Invalid user', { method: 'slashCommand' } - - RocketChat.slashCommands.run command.cmd, command.params, command.msg - diff --git a/packages/rocketchat-lib/lib/slashCommand.js b/packages/rocketchat-lib/lib/slashCommand.js new file mode 100644 index 000000000000..0a07065a15dc --- /dev/null +++ b/packages/rocketchat-lib/lib/slashCommand.js @@ -0,0 +1,31 @@ +RocketChat.slashCommands = { + commands: {} +}; + +RocketChat.slashCommands.add = function(command, callback, options = {}, result) { + RocketChat.slashCommands.commands[command] = { + command, + callback, + params: options.params, + description: options.description, + clientOnly: options.clientOnly || false, + result + }; +}; + +RocketChat.slashCommands.run = function(command, params, item) { + if (RocketChat.slashCommands.commands[command] && RocketChat.slashCommands.commands[command].callback) { + return RocketChat.slashCommands.commands[command].callback(command, params, item); + } +}; + +Meteor.methods({ + slashCommand(command) { + if (!Meteor.userId()) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'slashCommand' + }); + } + return RocketChat.slashCommands.run(command.cmd, command.params, command.msg); + } +}); diff --git a/packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.coffee b/packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.coffee deleted file mode 100644 index 96504f5d73e1..000000000000 --- a/packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.coffee +++ /dev/null @@ -1,22 +0,0 @@ -RocketChat.settings.get 'Site_Url', (key, value) -> - if value?.trim() isnt '' - host = value.replace(/\/$/, '') - prefix = "" - match = value.match(/([^/]+\/{2}[^/]+)(\/.+)/) - if match? - host = match[1] - prefix = match[2].replace(/\/$/, '') - - __meteor_runtime_config__.ROOT_URL = host - # __meteor_runtime_config__.ROOT_URL_PATH_PREFIX = prefix - - if Meteor.absoluteUrl.defaultOptions?.rootUrl? - Meteor.absoluteUrl.defaultOptions.rootUrl = host - - if Meteor.isServer - RocketChat.hostname = host.replace(/^https?:\/\//, '') - - process.env.MOBILE_ROOT_URL = host - process.env.MOBILE_DDP_URL = host - if WebAppInternals?.generateBoilerplate - WebAppInternals.generateBoilerplate() diff --git a/packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.js b/packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.js new file mode 100644 index 000000000000..17014a7dbe9b --- /dev/null +++ b/packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.js @@ -0,0 +1,26 @@ +/* globals WebAppInternals */ +RocketChat.settings.get('Site_Url', function(key, value) { + if (value == null || value.trim() === '') { + return; + } + let host = value.replace(/\/$/, ''); + // let prefix = ''; + const match = value.match(/([^\/]+\/{2}[^\/]+)(\/.+)/); + if (match != null) { + host = match[1]; + // prefix = match[2].replace(/\/$/, ''); + } + __meteor_runtime_config__.ROOT_URL = host; + + if (Meteor.absoluteUrl.defaultOptions && Meteor.absoluteUrl.defaultOptions.rootUrl) { + Meteor.absoluteUrl.defaultOptions.rootUrl = host; + } + if (Meteor.isServer) { + RocketChat.hostname = host.replace(/^https?:\/\//, ''); + process.env.MOBILE_ROOT_URL = host; + process.env.MOBILE_DDP_URL = host; + if (typeof WebAppInternals !== 'undefined' && WebAppInternals.generateBoilerplate) { + return WebAppInternals.generateBoilerplate(); + } + } +}); diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 750a8bf4ca7e..6e7e7c4022e4 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -59,14 +59,14 @@ Package.onUse(function(api) { api.addFiles('lib/placeholders.js'); api.addFiles('lib/promises.coffee'); api.addFiles('lib/roomTypesCommon.coffee'); - api.addFiles('lib/slashCommand.coffee'); - api.addFiles('lib/Message.coffee'); - api.addFiles('lib/MessageTypes.coffee'); + api.addFiles('lib/slashCommand.js'); + api.addFiles('lib/Message.js'); + api.addFiles('lib/MessageTypes.js'); api.addFiles('server/lib/bugsnag.js', 'server'); api.addFiles('server/lib/metrics.js', 'server'); - api.addFiles('server/lib/RateLimiter.coffee', 'server'); + api.addFiles('server/lib/RateLimiter.js', 'server'); // SERVER FUNCTIONS api.addFiles('server/functions/isDocker.js', 'server'); @@ -97,7 +97,7 @@ Package.onUse(function(api) { api.addFiles('server/lib/PushNotification.js', 'server'); api.addFiles('server/lib/defaultBlockedDomainsList.js', 'server'); api.addFiles('server/lib/notifyUsersOnMessage.js', 'server'); - api.addFiles('server/lib/roomTypes.coffee', 'server'); + api.addFiles('server/lib/roomTypes.js', 'server'); api.addFiles('server/lib/sendEmailOnMessage.js', 'server'); api.addFiles('server/lib/sendNotificationsOnMessage.js', 'server'); api.addFiles('server/lib/validateEmailDomain.js', 'server'); @@ -135,7 +135,7 @@ Package.onUse(function(api) { api.addFiles('server/methods/cleanChannelHistory.js', 'server'); api.addFiles('server/methods/createChannel.js', 'server'); api.addFiles('server/methods/createPrivateGroup.js', 'server'); - api.addFiles('server/methods/deleteMessage.coffee', 'server'); + api.addFiles('server/methods/deleteMessage.js', 'server'); api.addFiles('server/methods/deleteUserOwnAccount.js', 'server'); api.addFiles('server/methods/filterBadWords.js', ['server']); api.addFiles('server/methods/filterATAllTag.js', 'server'); @@ -150,11 +150,11 @@ Package.onUse(function(api) { api.addFiles('server/methods/leaveRoom.js', 'server'); api.addFiles('server/methods/removeOAuthService.js', 'server'); api.addFiles('server/methods/restartServer.js', 'server'); - api.addFiles('server/methods/robotMethods.coffee', 'server'); + api.addFiles('server/methods/robotMethods.js', 'server'); api.addFiles('server/methods/saveSetting.js', 'server'); - api.addFiles('server/methods/sendInvitationEmail.coffee', 'server'); + api.addFiles('server/methods/sendInvitationEmail.js', 'server'); api.addFiles('server/methods/sendMessage.coffee', 'server'); - api.addFiles('server/methods/sendSMTPTestEmail.coffee', 'server'); + api.addFiles('server/methods/sendSMTPTestEmail.js', 'server'); api.addFiles('server/methods/setAdminStatus.js', 'server'); api.addFiles('server/methods/setRealName.js', 'server'); api.addFiles('server/methods/setUsername.js', 'server'); @@ -170,7 +170,7 @@ Package.onUse(function(api) { api.addFiles('server/startup/settings.js', 'server'); // COMMON STARTUP - api.addFiles('lib/startup/settingsOnLoadSiteUrl.coffee'); + api.addFiles('lib/startup/settingsOnLoadSiteUrl.js'); // CLIENT LIB api.addFiles('client/Notifications.coffee', 'client'); diff --git a/packages/rocketchat-lib/server/lib/RateLimiter.coffee b/packages/rocketchat-lib/server/lib/RateLimiter.coffee deleted file mode 100644 index edeb8572f05c..000000000000 --- a/packages/rocketchat-lib/server/lib/RateLimiter.coffee +++ /dev/null @@ -1,30 +0,0 @@ -RocketChat.RateLimiter = new class - limitFunction: (fn, numRequests, timeInterval, matchers) -> - if process.env.TEST_MODE is 'true' - return fn - rateLimiter = new RateLimiter() - rateLimiter.addRule matchers, numRequests, timeInterval - return -> - match = {} - args = arguments - _.each matchers, (matcher, key) -> - match[key] = args[key] - - rateLimiter.increment match - rateLimitResult = rateLimiter.check match - if rateLimitResult.allowed - return fn.apply null, arguments - else - throw new Meteor.Error 'error-too-many-requests', "Error, too many requests. Please slow down. You must wait #{Math.ceil(rateLimitResult.timeToReset / 1000)} seconds before trying again.", { timeToReset: rateLimitResult.timeToReset, seconds: Math.ceil(rateLimitResult.timeToReset / 1000) } - - limitMethod: (methodName, numRequests, timeInterval, matchers) -> - if process.env.TEST_MODE is 'true' - return - match = - type: 'method' - name: methodName - - _.each matchers, (matcher, key) -> - match[key] = matchers[key] - - DDPRateLimiter.addRule match, numRequests, timeInterval diff --git a/packages/rocketchat-lib/server/lib/RateLimiter.js b/packages/rocketchat-lib/server/lib/RateLimiter.js new file mode 100644 index 000000000000..aa0554c8d566 --- /dev/null +++ b/packages/rocketchat-lib/server/lib/RateLimiter.js @@ -0,0 +1,41 @@ +/* globals RateLimiter */ +RocketChat.RateLimiter = new class { + limitFunction(fn, numRequests, timeInterval, matchers) { + if (process.env.TEST_MODE === 'true') { + return fn; + } + const rateLimiter = new RateLimiter(); + rateLimiter.addRule(matchers, numRequests, timeInterval); + return function(...args) { + const match = {}; + _.each(matchers, function(matcher, key) { + return match[key] = args[key]; + }); + rateLimiter.increment(match); + const rateLimitResult = rateLimiter.check(match); + if (rateLimitResult.allowed) { + return fn.apply(null, arguments); + } else { + throw new Meteor.Error('error-too-many-requests', `Error, too many requests. Please slow down. You must wait ${ Math.ceil(rateLimitResult.timeToReset / 1000) } seconds before trying again.`, { + timeToReset: rateLimitResult.timeToReset, + seconds: Math.ceil(rateLimitResult.timeToReset / 1000) + }); + } + }; + } + + limitMethod(methodName, numRequests, timeInterval, matchers) { + if (process.env.TEST_MODE === 'true') { + return; + } + const match = { + type: 'method', + name: methodName + }; + _.each(matchers, function(matcher, key) { + return match[key] = matchers[key]; + }); + return DDPRateLimiter.addRule(match, numRequests, timeInterval); + } + +}; diff --git a/packages/rocketchat-lib/server/lib/roomTypes.coffee b/packages/rocketchat-lib/server/lib/roomTypes.coffee deleted file mode 100644 index db0a3d2f17a3..000000000000 --- a/packages/rocketchat-lib/server/lib/roomTypes.coffee +++ /dev/null @@ -1,35 +0,0 @@ -RocketChat.roomTypes = new class roomTypesServer extends roomTypesCommon - ### add a publish for a room type - @param roomType: room type (e.g.: c (for channels), d (for direct channels)) - @param callback: function that will return the publish's data - ### - setPublish: (roomType, callback) -> - if @roomTypes[roomType]?.publish? - throw new Meteor.Error 'route-publish-exists', 'Publish for the given type already exists' - - unless @roomTypes[roomType]? - @roomTypes[roomType] = {} - - @roomTypes[roomType].publish = callback - - setRoomFind: (roomType, callback) -> - if @roomTypes[roomType]?.roomFind? - throw new Meteor.Error 'room-find-exists', 'Room find for the given type already exists' - - unless @roomTypes[roomType]? - @roomTypes[roomType] = {} - - @roomTypes[roomType].roomFind = callback - - getRoomFind: (roomType) -> - return unless @roomTypes[roomType]?.roomFind? - return @roomTypes[roomType].roomFind - - ### run the publish for a room type - @param scope: Meteor publish scope - @param roomType: room type (e.g.: c (for channels), d (for direct channels)) - @param identifier: identifier of the room - ### - runPublish: (scope, roomType, identifier) -> - return unless @roomTypes[roomType]?.publish? - return @roomTypes[roomType].publish.call scope, identifier diff --git a/packages/rocketchat-lib/server/lib/roomTypes.js b/packages/rocketchat-lib/server/lib/roomTypes.js new file mode 100644 index 000000000000..9f238a89205d --- /dev/null +++ b/packages/rocketchat-lib/server/lib/roomTypes.js @@ -0,0 +1,42 @@ +/* globals roomTypesCommon*/ +RocketChat.roomTypes = new class roomTypesServer extends roomTypesCommon { + /* add a publish for a room type + @param roomType: room type (e.g.: c (for channels), d (for direct channels)) + @param callback: function that will return the publish's data + */ + + setPublish(roomType, callback) { + if (this.roomTypes[roomType] && this.roomTypes[roomType].publish != null) { + throw new Meteor.Error('route-publish-exists', 'Publish for the given type already exists'); + } + if (this.roomTypes[roomType] == null) { + this.roomTypes[roomType] = {}; + } + return this.roomTypes[roomType].publish = callback; + } + + setRoomFind(roomType, callback) { + if (this.roomTypes[roomType] && this.roomTypes[roomType].roomFind != null) { + throw new Meteor.Error('room-find-exists', 'Room find for the given type already exists'); + } + if (this.roomTypes[roomType] == null) { + this.roomTypes[roomType] = {}; + } + return this.roomTypes[roomType].roomFind = callback; + } + getRoomFind(roomType) { + return this.roomTypes[roomType] && this.roomTypes[roomType].roomFind; + } + + + /* run the publish for a room type + @param scope: Meteor publish scope + @param roomType: room type (e.g.: c (for channels), d (for direct channels)) + @param identifier: identifier of the room + */ + + runPublish(scope, roomType, identifier) { + return this.roomTypes[roomType] && this.roomTypes[roomType].publish && this.roomTypes[roomType].publish.call(scope, identifier); + } + +}; diff --git a/packages/rocketchat-lib/server/methods/deleteMessage.coffee b/packages/rocketchat-lib/server/methods/deleteMessage.coffee deleted file mode 100644 index 04ab2e6f5f9b..000000000000 --- a/packages/rocketchat-lib/server/methods/deleteMessage.coffee +++ /dev/null @@ -1,30 +0,0 @@ -import moment from 'moment' - -Meteor.methods - deleteMessage: (message) -> - - check message, Match.ObjectIncluding({_id:String}) - - if not Meteor.userId() - throw new Meteor.Error 'error-invalid-user', 'Invalid user', { method: 'deleteMessage' } - - originalMessage = RocketChat.models.Messages.findOneById message._id, {fields: {u: 1, rid: 1, file: 1}} - if not originalMessage? - throw new Meteor.Error 'error-action-not-allowed', 'Not allowed', { method: 'deleteMessage', action: 'Delete_message' } - - hasPermission = RocketChat.authz.hasPermission(Meteor.userId(), 'delete-message', originalMessage.rid) - deleteAllowed = RocketChat.settings.get 'Message_AllowDeleting' - - deleteOwn = originalMessage?.u?._id is Meteor.userId() - - unless hasPermission or (deleteAllowed and deleteOwn) - throw new Meteor.Error 'error-action-not-allowed', 'Not allowed', { method: 'deleteMessage', action: 'Delete_message' } - - blockDeleteInMinutes = RocketChat.settings.get 'Message_AllowDeleting_BlockDeleteInMinutes' - if blockDeleteInMinutes? and blockDeleteInMinutes isnt 0 - msgTs = moment(originalMessage.ts) if originalMessage.ts? - currentTsDiff = moment().diff(msgTs, 'minutes') if msgTs? - if currentTsDiff > blockDeleteInMinutes - throw new Meteor.Error 'error-message-deleting-blocked', 'Message deleting is blocked', { method: 'deleteMessage' } - - RocketChat.deleteMessage(originalMessage, Meteor.user()); diff --git a/packages/rocketchat-lib/server/methods/deleteMessage.js b/packages/rocketchat-lib/server/methods/deleteMessage.js new file mode 100644 index 000000000000..73dd607fafcf --- /dev/null +++ b/packages/rocketchat-lib/server/methods/deleteMessage.js @@ -0,0 +1,53 @@ +import moment from 'moment'; + +Meteor.methods({ + deleteMessage(message) { + check(message, Match.ObjectIncluding({ + _id: String + })); + if (!Meteor.userId()) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'deleteMessage' + }); + } + const originalMessage = RocketChat.models.Messages.findOneById(message._id, { + fields: { + u: 1, + rid: 1, + file: 1 + } + }); + if (originalMessage == null) { + throw new Meteor.Error('error-action-not-allowed', 'Not allowed', { + method: 'deleteMessage', + action: 'Delete_message' + }); + } + const hasPermission = RocketChat.authz.hasPermission(Meteor.userId(), 'delete-message', originalMessage.rid); + const deleteAllowed = RocketChat.settings.get('Message_AllowDeleting'); + const deleteOwn = originalMessage && originalMessage.u && originalMessage.u._id === Meteor.userId(); + if (!(hasPermission || (deleteAllowed && deleteOwn))) { + throw new Meteor.Error('error-action-not-allowed', 'Not allowed', { + method: 'deleteMessage', + action: 'Delete_message' + }); + } + const blockDeleteInMinutes = RocketChat.settings.get('Message_AllowDeleting_BlockDeleteInMinutes'); + if (blockDeleteInMinutes != null && blockDeleteInMinutes !== 0) { + if (originalMessage.ts == null) { + return; + } + const msgTs = moment(originalMessage.ts); + if (msgTs == null) { + return; + } + const currentTsDiff = moment().diff(msgTs, 'minutes'); + if (currentTsDiff > blockDeleteInMinutes) { + throw new Meteor.Error('error-message-deleting-blocked', 'Message deleting is blocked', { + method: 'deleteMessage' + }); + } + } + return RocketChat.deleteMessage(originalMessage, Meteor.user()); + } +}); diff --git a/packages/rocketchat-lib/server/methods/robotMethods.coffee b/packages/rocketchat-lib/server/methods/robotMethods.coffee deleted file mode 100644 index 593a915416ab..000000000000 --- a/packages/rocketchat-lib/server/methods/robotMethods.coffee +++ /dev/null @@ -1,21 +0,0 @@ -Meteor.methods - 'robot.modelCall': (model, method, args) -> - - check model, String - check method, String - - unless Meteor.userId() - throw new Meteor.Error 'error-invalid-user', 'Invalid user', { method: 'robot.modelCall' } - - unless RocketChat.authz.hasRole Meteor.userId(), 'robot' - throw new Meteor.Error 'error-not-allowed', 'Not allowed', { method: 'robot.modelCall' } - - unless _.isFunction RocketChat.models[model]?[method] - throw new Meteor.Error 'error-invalid-method', 'Invalid method', { method: 'robot.modelCall' } - - call = RocketChat.models[model][method].apply(RocketChat.models[model], args) - - if call?.fetch?()? - return call.fetch() - else - return call diff --git a/packages/rocketchat-lib/server/methods/robotMethods.js b/packages/rocketchat-lib/server/methods/robotMethods.js new file mode 100644 index 000000000000..e14fbd287b01 --- /dev/null +++ b/packages/rocketchat-lib/server/methods/robotMethods.js @@ -0,0 +1,25 @@ +Meteor.methods({ + 'robot.modelCall'(model, method, args) { + check(model, String); + check(method, String); + if (!Meteor.userId()) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'robot.modelCall' + }); + } + if (!RocketChat.authz.hasRole(Meteor.userId(), 'robot')) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { + method: 'robot.modelCall' + }); + } + const m = RocketChat.models[model]; + + if (!m || !_.isFunction(m[method])) { + throw new Meteor.Error('error-invalid-method', 'Invalid method', { + method: 'robot.modelCall' + }); + } + const cursor = RocketChat.models[model][method].apply(RocketChat.models[model], args); + return cursor && cursor.fetch ? cursor.fetch() : cursor; + } +}); diff --git a/packages/rocketchat-lib/server/methods/sendInvitationEmail.coffee b/packages/rocketchat-lib/server/methods/sendInvitationEmail.coffee deleted file mode 100644 index 16a7f0396ec2..000000000000 --- a/packages/rocketchat-lib/server/methods/sendInvitationEmail.coffee +++ /dev/null @@ -1,42 +0,0 @@ -Meteor.methods - sendInvitationEmail: (emails) -> - - check emails, [String] - - if not Meteor.userId() - throw new Meteor.Error 'error-invalid-user', "Invalid user", { method: 'sendInvitationEmail' } - - unless RocketChat.authz.hasRole(Meteor.userId(), 'admin') - throw new Meteor.Error 'error-not-allowed', "Not allowed", { method: 'sendInvitationEmail' } - - rfcMailPattern = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ - validEmails = _.compact _.map emails, (email) -> return email if rfcMailPattern.test email - - header = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Header') || "") - footer = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Footer') || "") - - if RocketChat.settings.get('Invitation_Customized') - subject = RocketChat.settings.get('Invitation_Subject') - html = RocketChat.settings.get('Invitation_HTML') - else - subject = TAPi18n.__('Invitation_Subject_Default', { lng: Meteor.user()?.language || RocketChat.settings.get('language') || 'en' }) - html = TAPi18n.__('Invitation_HTML_Default', { lng: Meteor.user()?.language || RocketChat.settings.get('language') || 'en' }) - - subject = RocketChat.placeholders.replace(subject); - - for email in validEmails - @unblock() - - html = RocketChat.placeholders.replace(html, { email: email }); - - try - Email.send - to: email - from: RocketChat.settings.get 'From_Email' - subject: subject - html: header + html + footer - catch error - throw new Meteor.Error 'error-email-send-failed', 'Error trying to send email: ' + error.message, { method: 'sendInvitationEmail', message: error.message } - - - return validEmails diff --git a/packages/rocketchat-lib/server/methods/sendInvitationEmail.js b/packages/rocketchat-lib/server/methods/sendInvitationEmail.js new file mode 100644 index 000000000000..bbde68a48f8c --- /dev/null +++ b/packages/rocketchat-lib/server/methods/sendInvitationEmail.js @@ -0,0 +1,60 @@ + +Meteor.methods({ + sendInvitationEmail(emails) { + check(emails, [String]); + if (!Meteor.userId()) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'sendInvitationEmail' + }); + } + if (!RocketChat.authz.hasRole(Meteor.userId(), 'admin')) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { + method: 'sendInvitationEmail' + }); + } + const rfcMailPattern = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; + const validEmails = _.compact(_.map(emails, function(email) { + if (rfcMailPattern.test(email)) { + return email; + } + })); + const header = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Header') || ''); + const footer = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Footer') || ''); + let html; + let subject; + const user = Meteor.user(); + const lng = user.language || RocketChat.settings.get('language') || 'en'; + if (RocketChat.settings.get('Invitation_Customized')) { + subject = RocketChat.settings.get('Invitation_Subject'); + html = RocketChat.settings.get('Invitation_HTML'); + } else { + subject = TAPi18n.__('Invitation_Subject_Default', { + lng + }); + html = TAPi18n.__('Invitation_HTML_Default', { + lng + }); + } + subject = RocketChat.placeholders.replace(subject); + validEmails.forEach(email => { + this.unblock(); + html = RocketChat.placeholders.replace(html, { + email + }); + try { + Email.send({ + to: email, + from: RocketChat.settings.get('From_Email'), + subject, + html: header + html + footer + }); + } catch ({message}) { + throw new Meteor.Error('error-email-send-failed', `Error trying to send email: ${ message }`, { + method: 'sendInvitationEmail', + message + }); + } + }); + return validEmails; + } +}); diff --git a/packages/rocketchat-lib/server/methods/sendSMTPTestEmail.coffee b/packages/rocketchat-lib/server/methods/sendSMTPTestEmail.coffee deleted file mode 100644 index 10759ecdea5f..000000000000 --- a/packages/rocketchat-lib/server/methods/sendSMTPTestEmail.coffee +++ /dev/null @@ -1,37 +0,0 @@ -Meteor.methods - sendSMTPTestEmail: -> - if not Meteor.userId() - throw new Meteor.Error 'error-invalid-user', "Invalid user", { method: 'sendSMTPTestEmail' } - - user = Meteor.user() - unless user.emails?[0]?.address - throw new Meteor.Error 'error-invalid-email', "Invalid email", { method: 'sendSMTPTestEmail' } - - this.unblock() - - header = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Header') || ''); - footer = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Footer') || ''); - - console.log 'Sending test email to ' + user.emails[0].address - - try - Email.send - to: user.emails[0].address - from: RocketChat.settings.get('From_Email') - subject: "SMTP Test Email" - html: header + "

You have successfully sent an email

" + footer - catch error - throw new Meteor.Error 'error-email-send-failed', 'Error trying to send email: ' + error.message, { method: 'sendSMTPTestEmail', message: error.message } - - return { - message: "Your_mail_was_sent_to_s" - params: [user.emails[0].address] - } - -# Limit a user to sending 1 test mail/second -DDPRateLimiter.addRule - type: 'method' - name: 'sendSMTPTestEmail' - userId: (userId) -> - return true -, 1, 1000 diff --git a/packages/rocketchat-lib/server/methods/sendSMTPTestEmail.js b/packages/rocketchat-lib/server/methods/sendSMTPTestEmail.js new file mode 100644 index 000000000000..df861fd6a340 --- /dev/null +++ b/packages/rocketchat-lib/server/methods/sendSMTPTestEmail.js @@ -0,0 +1,44 @@ +Meteor.methods({ + sendSMTPTestEmail() { + if (!Meteor.userId()) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'sendSMTPTestEmail' + }); + } + const user = Meteor.user(); + if (!user.emails && !user.emails[0] && user.emails[0].address) { + throw new Meteor.Error('error-invalid-email', 'Invalid email', { + method: 'sendSMTPTestEmail' + }); + } + this.unblock(); + const header = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Header') || ''); + const footer = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Footer') || ''); + console.log(`Sending test email to ${ user.emails[0].address }`); + try { + Email.send({ + to: user.emails[0].address, + from: RocketChat.settings.get('From_Email'), + subject: 'SMTP Test Email', + html: `${ header }

You have successfully sent an email

${ footer }` + }); + } catch ({message}) { + throw new Meteor.Error('error-email-send-failed', `Error trying to send email: ${ message }`, { + method: 'sendSMTPTestEmail', + message + }); + } + return { + message: 'Your_mail_was_sent_to_s', + params: [user.emails[0].address] + }; + } +}); + +DDPRateLimiter.addRule({ + type: 'method', + name: 'sendSMTPTestEmail', + userId() { + return true; + } +}, 1, 1000);