diff --git a/.stylelintignore b/.stylelintignore index 5baac3a35e973..e69de29bb2d1d 100644 --- a/.stylelintignore +++ b/.stylelintignore @@ -1,2 +0,0 @@ -**/lesshat.less -**/_lesshat.import.less \ No newline at end of file diff --git a/.stylelintrc b/.stylelintrc index 1015f7d91ee41..2bbb45133d8ce 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -107,6 +107,5 @@ "value-list-comma-space-after": "always-single-line", "value-list-comma-space-before": "never", "value-list-max-empty-lines": 0, - }, - "ignoreFiles": "packages/rocketchat-livechat/app/client/stylesheets/utils/_lesshat.import.less" + } } diff --git a/client/routes/router.js b/client/routes/router.js index 9d5c7e6eb9d1c..f70a5ff6ebae5 100644 --- a/client/routes/router.js +++ b/client/routes/router.js @@ -27,7 +27,7 @@ FlowRouter.route('/', { Tracker.autorun(function(c) { if (FlowRouter.subsReady() === true) { Meteor.defer(function() { - if (Meteor.user().defaultRoom) { + if (Meteor.user() && Meteor.user().defaultRoom) { const room = Meteor.user().defaultRoom.split('/'); FlowRouter.go(room[0], { name: room[1] }, FlowRouter.current().queryParams); } else { diff --git a/package.json b/package.json index d5cbc7595b765..c2822e2d9e032 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "email": "support@rocket.chat" }, "devDependencies": { - "chimp": "^0.47.2", + "chimp": "^0.48.0", "eslint": "^3.19.0", "stylelint": "^7.10.1", "supertest": "^3.0.0", diff --git a/packages/rocketchat-authorization/client/lib/ChatPermissions.js b/packages/rocketchat-authorization/client/lib/ChatPermissions.js index d5eb40d050afa..1564612811087 100644 --- a/packages/rocketchat-authorization/client/lib/ChatPermissions.js +++ b/packages/rocketchat-authorization/client/lib/ChatPermissions.js @@ -1,6 +1,8 @@ RocketChat.authz.cachedCollection = new RocketChat.CachedCollection({ name: 'permissions', - eventType: 'onLogged' + eventType: 'onLogged', + userRelated: false }); +RocketChat.authz.cachedCollection.init(); this.ChatPermissions = RocketChat.authz.cachedCollection.collection; diff --git a/packages/rocketchat-authorization/server/functions/canAccessRoom.js b/packages/rocketchat-authorization/server/functions/canAccessRoom.js index 5e41811e28f8a..faf4164698f58 100644 --- a/packages/rocketchat-authorization/server/functions/canAccessRoom.js +++ b/packages/rocketchat-authorization/server/functions/canAccessRoom.js @@ -1,15 +1,19 @@ /* globals RocketChat */ RocketChat.authz.roomAccessValidators = [ - function(room, user) { + function(room, user = {}) { + if (room.t === 'c') { + if (!user._id && RocketChat.settings.get('Accounts_AllowAnonymousAccess') === true) { + return true; + } + + return RocketChat.authz.hasPermission(user._id, 'view-c-room'); + } + }, + function(room, user = {}) { const subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(room._id, user._id); if (subscription) { return subscription._room; } - }, - function(room, user) { - if (room.t === 'c') { - return RocketChat.authz.hasPermission(user._id, 'view-c-room'); - } } ]; diff --git a/packages/rocketchat-channel-settings/client/startup/tabBar.js b/packages/rocketchat-channel-settings/client/startup/tabBar.js index 8106391c3691f..8728bc01ddd90 100644 --- a/packages/rocketchat-channel-settings/client/startup/tabBar.js +++ b/packages/rocketchat-channel-settings/client/startup/tabBar.js @@ -2,6 +2,7 @@ Meteor.startup(() => { RocketChat.TabBar.addButton({ groups: ['channel', 'group', 'direct'], id: 'channel-settings', + anonymous: true, i18nTitle: 'Room_Info', icon: 'icon-info-circled', template: 'channelSettings', diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 3d121bb3bbe64..3c3fef7b11872 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -17,6 +17,7 @@ "Accessing_permissions": "Accessing permissions", "Account_SID": "Account SID", "Accounts": "Accounts", + "Accounts_AllowAnonymousAccess": "Allow anonymous access", "Accounts_AllowDeleteOwnAccount": "Allow users to delete own account", "Accounts_AllowedDomainsList": "Allowed Domains List", "Accounts_AllowedDomainsList_Description": "Comma-separated list of allowed domains", @@ -1227,6 +1228,7 @@ "Register": "Register a new account", "Registration": "Registration", "Registration_Succeeded": "Registration Succeeded", + "Register_or_login_to_send_messages": "Register or login to send messages", "Registration_via_Admin": "Registration via Admin", "Regular_Expressions": "Regular Expressions", "Release": "Release", diff --git a/packages/rocketchat-lib/client/lib/cachedCollection.js b/packages/rocketchat-lib/client/lib/cachedCollection.js index 23fd088e16942..6a9d9db88e05b 100644 --- a/packages/rocketchat-lib/client/lib/cachedCollection.js +++ b/packages/rocketchat-lib/client/lib/cachedCollection.js @@ -165,7 +165,7 @@ class CachedCollection { } localforage.getItem(this.name, (error, data) => { - if (data && (data.version < this.version || data.token !== this.getToken())) { + if (data && (data.version < this.version || data.token !== this.getToken() || this.getToken() === undefined)) { this.clearCache(); callback(false); return; diff --git a/packages/rocketchat-lib/client/lib/openRoom.coffee b/packages/rocketchat-lib/client/lib/openRoom.coffee index af932dfc5aa38..33e023abf9c97 100644 --- a/packages/rocketchat-lib/client/lib/openRoom.coffee +++ b/packages/rocketchat-lib/client/lib/openRoom.coffee @@ -5,12 +5,13 @@ currentTracker = undefined Meteor.defer -> currentTracker = Tracker.autorun (c) -> - if RoomManager.open(type + name).ready() isnt true - BlazeLayout.render 'main', { modal: RocketChat.Layout.isEmbedded(), center: 'loading' } + user = Meteor.user() + if (user? and not user.username?) or (not user? and RocketChat.settings.get('Accounts_AllowAnonymousAccess') is false) + BlazeLayout.render 'main' return - user = Meteor.user() - unless user?.username + if RoomManager.open(type + name).ready() isnt true + BlazeLayout.render 'main', { modal: RocketChat.Layout.isEmbedded(), center: 'loading' } return currentTracker = undefined diff --git a/packages/rocketchat-lib/server/methods/getRoomRoles.js b/packages/rocketchat-lib/server/methods/getRoomRoles.js index 18ccaed6dbefd..e35fdb3e33e96 100644 --- a/packages/rocketchat-lib/server/methods/getRoomRoles.js +++ b/packages/rocketchat-lib/server/methods/getRoomRoles.js @@ -3,7 +3,7 @@ Meteor.methods({ check(rid, String); - if (!Meteor.userId()) { + if (!Meteor.userId() && RocketChat.settings.get('Accounts_AllowAnonymousAccess') === false) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getRoomRoles' }); } diff --git a/packages/rocketchat-lib/server/models/Rooms.coffee b/packages/rocketchat-lib/server/models/Rooms.coffee index 1e11997cef5bd..1d58e578e1179 100644 --- a/packages/rocketchat-lib/server/models/Rooms.coffee +++ b/packages/rocketchat-lib/server/models/Rooms.coffee @@ -188,6 +188,22 @@ class ModelRooms extends RocketChat.models._Base return @find query, options + findByNameAndType: (name, type, options) -> + query = + t: type + name: name + + return @find query, options + + findByNameAndTypeNotDefault: (name, type, options) -> + query = + t: type + name: name + default: + $ne: true + + return @find query, options + findByNameAndTypeNotContainingUsername: (name, type, username, options) -> query = t: type diff --git a/packages/rocketchat-lib/server/startup/settings.js b/packages/rocketchat-lib/server/startup/settings.js index 87143f62c4b9d..b67af0cd860ff 100644 --- a/packages/rocketchat-lib/server/startup/settings.js +++ b/packages/rocketchat-lib/server/startup/settings.js @@ -8,6 +8,10 @@ RocketChat.settings.add('uniqueID', process.env.DEPLOYMENT_ID || Random.id(), { // if you add a node to the i18n.json with the same setting name but with `_Description` it will automatically work. RocketChat.settings.addGroup('Accounts', function() { + this.add('Accounts_AllowAnonymousAccess', false, { + type: 'boolean', + public: true + }); this.add('Accounts_AllowDeleteOwnAccount', false, { type: 'boolean', 'public': true, diff --git a/packages/rocketchat-lib/startup/defaultRoomTypes.js b/packages/rocketchat-lib/startup/defaultRoomTypes.js index a647e19a3c7a5..692ddb8765284 100644 --- a/packages/rocketchat-lib/startup/defaultRoomTypes.js +++ b/packages/rocketchat-lib/startup/defaultRoomTypes.js @@ -28,7 +28,7 @@ RocketChat.roomTypes.add('c', 10, { }, condition() { - return RocketChat.authz.hasAtLeastOnePermission(['view-c-room', 'view-joined-room']); + return RocketChat.authz.hasAtLeastOnePermission(['view-c-room', 'view-joined-room']) || RocketChat.settings.get('Accounts_AllowAnonymousAccess') === true; }, showJoinLink(roomId) { diff --git a/packages/rocketchat-theme/client/imports/base.less b/packages/rocketchat-theme/client/imports/base.less index b640e102ce875..b6c1c36339188 100644 --- a/packages/rocketchat-theme/client/imports/base.less +++ b/packages/rocketchat-theme/client/imports/base.less @@ -2685,7 +2685,7 @@ label.required::after { margin: 60px 20px 0 0; overflow: hidden; width: 100%; - height: calc(~'100% - 120px'); + height: calc(~'100% - 130px'); .message-cog-container { .message-action { diff --git a/packages/rocketchat-theme/server/server.js b/packages/rocketchat-theme/server/server.js index f6d81dc5d3736..940e4a1fdddfd 100644 --- a/packages/rocketchat-theme/server/server.js +++ b/packages/rocketchat-theme/server/server.js @@ -55,7 +55,7 @@ RocketChat.theme = new class { constructor() { this.variables = {}; this.packageCallbacks = []; - this.files = ['server/lesshat.less', 'server/colors.less']; + this.files = ['server/colors.less']; this.customCSS = ''; RocketChat.settings.add('css', ''); RocketChat.settings.addGroup('Layout'); diff --git a/packages/rocketchat-ui-flextab/client/flexTabBar.js b/packages/rocketchat-ui-flextab/client/flexTabBar.js index b65246f174866..a6627f9b1c39b 100644 --- a/packages/rocketchat-ui-flextab/client/flexTabBar.js +++ b/packages/rocketchat-ui-flextab/client/flexTabBar.js @@ -14,6 +14,10 @@ Template.flexTabBar.helpers({ }, visible() { + if (!Meteor.userId() && !this.anonymous) { + return 'hidden'; + } + if (this.groups.indexOf(Template.instance().tabBar.currentGroup()) === -1) { return 'hidden'; } diff --git a/packages/rocketchat-ui-login/client/login/form.html b/packages/rocketchat-ui-login/client/login/form.html index c761e8f19c5be..7171f0d9cf5af 100644 --- a/packages/rocketchat-ui-login/client/login/form.html +++ b/packages/rocketchat-ui-login/client/login/form.html @@ -7,7 +7,7 @@
{{#if state 'wait-activation'}}
-

{{{_ "Registration_Succeeded"}}}

+

{{{_ "Registration_Succeeded"}}}

{{{_ "Wait_activation_warning"}}}

{{{_ "Please_wait_activation"}}}

diff --git a/packages/rocketchat-ui-login/client/login/form.js b/packages/rocketchat-ui-login/client/login/form.js index b062b78e2f11a..ea51cf9c49be2 100644 --- a/packages/rocketchat-ui-login/client/login/form.js +++ b/packages/rocketchat-ui-login/client/login/form.js @@ -108,6 +108,8 @@ Template.loginForm.events({ return instance.state.set('login'); } else if (error && error.error === 'error-user-is-not-activated') { return instance.state.set('wait-activation'); + } else { + Session.set('forceLogin', false); } }); }); @@ -130,6 +132,7 @@ Template.loginForm.events({ } return; } + Session.set('forceLogin', false); if (user && user.language) { localStorage.setItem('userLanguage', user.language); return setLanguage(Meteor.user().language); diff --git a/packages/rocketchat-ui-master/client/main.js b/packages/rocketchat-ui-master/client/main.js index e90255fa0ff07..ba187b5e96868 100644 --- a/packages/rocketchat-ui-master/client/main.js +++ b/packages/rocketchat-ui-master/client/main.js @@ -110,7 +110,7 @@ Template.main.helpers({ return RocketChat.settings.get('Site_Name'); }, logged() { - if (Meteor.userId() != null) { + if (Meteor.userId() != null || (RocketChat.settings.get('Accounts_AllowAnonymousAccess') === true && Session.get('forceLogin') !== true)) { $('html').addClass('noscroll').removeClass('scroll'); return true; } else { @@ -134,7 +134,7 @@ Template.main.helpers({ return ready; }, hasUsername() { - return (Meteor.userId() != null) && (Meteor.user().username != null); + return (Meteor.userId() != null && Meteor.user().username != null) || (Meteor.userId() == null && RocketChat.settings.get('Accounts_AllowAnonymousAccess') === true); }, requirePasswordChange() { const user = Meteor.user(); diff --git a/packages/rocketchat-ui-message/client/message.coffee b/packages/rocketchat-ui-message/client/message.coffee index 067a409a6bde5..2684dfd9c0a3b 100644 --- a/packages/rocketchat-ui-message/client/message.coffee +++ b/packages/rocketchat-ui-message/client/message.coffee @@ -114,7 +114,7 @@ Template.message.helpers reactions: -> msgReactions = [] - userUsername = Meteor.user().username + userUsername = Meteor.user()?.username for emoji, reaction of @reactions total = reaction.usernames.length diff --git a/packages/rocketchat-ui-message/client/messageBox.coffee b/packages/rocketchat-ui-message/client/messageBox.coffee index 63afe5e6888b9..0052f30461469 100644 --- a/packages/rocketchat-ui-message/client/messageBox.coffee +++ b/packages/rocketchat-ui-message/client/messageBox.coffee @@ -30,7 +30,7 @@ Template.messageBox.helpers showFormattingTips: -> return RocketChat.settings.get('Message_ShowFormattingTips') and (RocketChat.Markdown or RocketChat.MarkdownCode or katexSyntax()) canJoin: -> - return RocketChat.roomTypes.verifyShowJoinLink @_id + return Meteor.userId()? and RocketChat.roomTypes.verifyShowJoinLink @_id joinCodeRequired: -> return Session.get('roomData' + this._id)?.joinCodeRequired subscribed: -> @@ -124,6 +124,9 @@ Template.messageBox.helpers showSandstorm: -> return Meteor.settings.public.sandstorm && !Meteor.isCordova + isAnonymous: -> + return not Meteor.userId()? and RocketChat.settings.get('Accounts_AllowAnonymousAccess') is true + firefoxPasteUpload = (fn) -> user = navigator.userAgent.match(/Firefox\/(\d+)\.\d/) if !user or user[1] > 49 @@ -178,6 +181,11 @@ Template.messageBox.events RoomHistoryManager.getRoom(@_id).loaded = undefined RoomManager.computation.invalidate() + 'click .register': (event) -> + event.stopPropagation() + event.preventDefault() + Session.set('forceLogin', true) + 'focus .input-message': (event, instance) -> KonchatNotification.removeRoomNotification @_id chatMessages[@_id].input = instance.find('.input-message') diff --git a/packages/rocketchat-ui-message/client/messageBox.html b/packages/rocketchat-ui-message/client/messageBox.html index 572405f723239..02e98fe5a1072 100644 --- a/packages/rocketchat-ui-message/client/messageBox.html +++ b/packages/rocketchat-ui-message/client/messageBox.html @@ -143,6 +143,11 @@ {{/if}} + {{#if isAnonymous}} +
+ +
+ {{/if}} {{/with}} {{/if}} diff --git a/packages/rocketchat-ui-sidenav/client/accountBox.js b/packages/rocketchat-ui-sidenav/client/accountBox.js index e5e4c2f6acf6f..d8dacd1406b2a 100644 --- a/packages/rocketchat-ui-sidenav/client/accountBox.js +++ b/packages/rocketchat-ui-sidenav/client/accountBox.js @@ -1,5 +1,14 @@ Template.accountBox.helpers({ myUserInfo() { + if (Meteor.user() == null && RocketChat.settings.get('Accounts_AllowAnonymousAccess')) { + return { + name: t('Anonymous'), + status: 'online', + visualStatus: t('online'), + username: 'anonymous' + }; + } + let visualStatus = 'online'; const user = Meteor.user() || {}; const { name, username } = user; @@ -41,6 +50,10 @@ Template.accountBox.events({ }, 'click .account-box'() { + if (Meteor.userId() == null && RocketChat.settings.get('Accounts_AllowAnonymousAccess')) { + return; + } + return AccountBox.toggle(); }, diff --git a/packages/rocketchat-ui-sidenav/client/channelsAnonymous.html b/packages/rocketchat-ui-sidenav/client/channelsAnonymous.html new file mode 100644 index 0000000000000..71f67470c1ada --- /dev/null +++ b/packages/rocketchat-ui-sidenav/client/channelsAnonymous.html @@ -0,0 +1,13 @@ + diff --git a/packages/rocketchat-ui-sidenav/client/channelsAnonymous.js b/packages/rocketchat-ui-sidenav/client/channelsAnonymous.js new file mode 100644 index 0000000000000..c4a121b093a65 --- /dev/null +++ b/packages/rocketchat-ui-sidenav/client/channelsAnonymous.js @@ -0,0 +1,23 @@ +Template.channelsAnonymous.helpers({ + isActive() { + const currentRoom = RocketChat.models.Rooms.findOne({ _id: Session.get('openedRoom') }); + if (currentRoom) { + return 'active'; + } + }, + + rooms() { + const query = { + t: 'c' + }; + + return RocketChat.models.Rooms.find(query, { sort: { name: 1 } }); + } +}); + +Template.channelsAnonymous.events({ + 'click .more-channels'() { + SideNav.setFlex('listChannelsFlex'); + SideNav.openFlex(); + } +}); diff --git a/packages/rocketchat-ui-sidenav/client/chatRoomItem.js b/packages/rocketchat-ui-sidenav/client/chatRoomItem.js index 340e188deacd9..fe2389e7bf314 100644 --- a/packages/rocketchat-ui-sidenav/client/chatRoomItem.js +++ b/packages/rocketchat-ui-sidenav/client/chatRoomItem.js @@ -32,7 +32,7 @@ Template.chatRoomItem.helpers({ }, active() { - if (Session.get('openedRoom') === this.rid) { + if (Session.get('openedRoom') && Session.get('openedRoom') === this.rid || Session.get('openedRoom') === this._id) { return 'active'; } }, diff --git a/packages/rocketchat-ui-sidenav/client/sideNav.html b/packages/rocketchat-ui-sidenav/client/sideNav.html index eec0bc309fd28..389eae9a8b9bb 100644 --- a/packages/rocketchat-ui-sidenav/client/sideNav.html +++ b/packages/rocketchat-ui-sidenav/client/sideNav.html @@ -3,8 +3,8 @@
{{> accountBox }}
+ {{> toolbar}} {{#if currentUser}} - {{> toolbar}} @@ -34,6 +34,12 @@

+ {{else}} +
+
+ {{> channelsAnonymous}} +
+
{{/if}}