Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEW] Token Controlled Access channels #8060

Merged
merged 10 commits into from
Dec 4, 2017
Next Next commit
Add token controlled access channels
  • Loading branch information
lindoelio authored and sampaiodiego committed Sep 6, 2017
commit 2aa247ab263408cfe0711f0225cbb60f1bed92da
1 change: 1 addition & 0 deletions .meteor/packages
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ rocketchat:spotify
rocketchat:statistics
rocketchat:streamer
rocketchat:theme
rocketchat:tokenpass
rocketchat:tooltip
rocketchat:tutum
rocketchat:ui
Expand Down
1 change: 1 addition & 0 deletions .meteor/versions
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ rocketchat:spotify@0.0.1
rocketchat:statistics@0.0.1
rocketchat:streamer@0.5.0
rocketchat:theme@0.0.1
rocketchat:tokenpass@0.0.1
rocketchat:tooltip@0.0.1
rocketchat:tutum@0.0.1
rocketchat:ui@0.1.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ RocketChat.ChannelSettings = new class {
const allOptions = _.toArray(this.options.get());
const allowedOptions = _.compact(_.map(allOptions, function(option) {
const ret = {...option};
if (option.validation == null || option.validation()) {
if (option.validation == null || option.validation(currentData)) {
ret.data = Object.assign({}, typeof option.data === 'function' ? option.data() : option.data, currentData);
return ret;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
position: absolute;
top: -1px;
right: 10px;
bottom: 0;

border-radius: 0 4px 4px 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,9 @@ Template.channelSettings.onCreated(function() {
const room = ChatRoom.findOne(this.data && this.data.rid);
const field = this.editing.get();
let value;
if (!this.settings[field]) {
return;
}
if (this.settings[field].type === 'select') {
value = this.$(`.channel-settings form [name=${ field }]:checked`).val();
} else if (this.settings[field].type === 'boolean') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Meteor.methods({
method: 'saveRoomSettings'
});
}
if (!['roomName', 'roomTopic', 'roomAnnouncement', 'roomDescription', 'roomType', 'readOnly', 'reactWhenReadOnly', 'systemMessages', 'default', 'joinCode'].some((s) => s === setting)) {
if (!['roomName', 'roomTopic', 'roomAnnouncement', 'roomDescription', 'roomType', 'readOnly', 'reactWhenReadOnly', 'systemMessages', 'default', 'joinCode', 'tokenpass'].some((s) => s === setting)) {
throw new Meteor.Error('error-invalid-settings', 'Invalid settings provided', {
method: 'saveRoomSettings'
});
Expand Down Expand Up @@ -65,6 +65,16 @@ Meteor.methods({
RocketChat.saveRoomType(rid, value, Meteor.user());
}
break;
case 'tokenpass':
check(value, {
require: String,
tokens: [{
token: String,
balance: String
}]
});
RocketChat.saveRoomTokenpass(rid, value);
break;
case 'readOnly':
if (value !== room.ro) {
RocketChat.saveRoomReadOnly(rid, value, Meteor.user());
Expand Down
25 changes: 25 additions & 0 deletions packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@
"Accounts_OAuth_Meteor_callback_url": "Meteor Callback URL",
"Accounts_OAuth_Meteor_id": "Meteor Id",
"Accounts_OAuth_Meteor_secret": "Meteor Secret",
"Accounts_OAuth_Tokenpass": "Tokenpass Login",
"Accounts_OAuth_Tokenpass_callback_url": "Tokenpass Callback URL",
"Accounts_OAuth_Tokenpass_id": "Tokenpass Id",
"Accounts_OAuth_Tokenpass_secret": "Tokenpass Secret",
"Accounts_OAuth_Twitter": "Twitter Login",
"Accounts_OAuth_Twitter_callback_url": "Twitter Callback URL",
"Accounts_OAuth_Twitter_id": "Twitter Id",
Expand Down Expand Up @@ -159,6 +163,7 @@
"All_channels": "All channels",
"All_logs": "All logs",
"All_messages": "All messages",
"All_added_tokens_will_be_required_by_the_user": "All added tokens will be required by the user",
"Allow_Invalid_SelfSigned_Certs": "Allow Invalid Self-Signed Certs",
"Allow_Invalid_SelfSigned_Certs_Description": "Allow invalid and self-signed SSL certificate's for link validation and previews.",
"Allow_switching_departments": "Allow visitor to switch departments",
Expand Down Expand Up @@ -203,6 +208,8 @@
"API_Shield_Types": "Shield Types",
"API_Shield_Types_Description": "Types of shields to enable as a comma separated list, choose from `online`, `channel` or `*` for all",
"API_Token": "API Token",
"API_Tokenpass_URL": "Tokenpass Server URL",
"API_Tokenpass_URL_Description": "Example: https://domain.com (excluding trailing slash)",
"API_Upper_Count_Limit": "Max Record Amount",
"API_Upper_Count_Limit_Description": "What is the maximum number of records the REST API should return (when not unlimited)?",
"API_User_Limit": "User Limit for adding all Users to Channel",
Expand All @@ -221,6 +228,7 @@
"Are_you_sure_you_want_to_delete_your_account": "Are you sure you want to delete your account?",
"Assign_admin": "Assigning admin",
"at": "at",
"At_least_one_added_token_is_required_by_the_user": "At least one added token is required by the user",
"AtlassianCrowd": "Atlassian Crowd",
"Attachment_File_Uploaded": "File Uploaded",
"Attribute_handling": "Attribute handling",
Expand Down Expand Up @@ -319,6 +327,7 @@
"Channel_Archived": "Channel with name `#%s` has been archived successfully",
"Channel_doesnt_exist": "The channel `#%s` does not exist.",
"Channel_name": "Channel name",
"Channel_Name_Placeholder": "Type channel name",
"Channel_to_listen_on": "Channel to listen on",
"Channel_Unarchived": "Channel with name `#%s` has been Unarchived successfully",
"Channels": "Channels",
Expand Down Expand Up @@ -356,6 +365,7 @@
"Color": "Color",
"Commands": "Commands",
"Comment_to_leave_on_closing_session": "Comment to leave on closing session",
"Common_Access": "Common Access",
"Compact": "Compact",
"Confirm_password": "Confirm your password",
"Conversation": "Conversation",
Expand Down Expand Up @@ -1123,6 +1133,7 @@
"Meta_msvalidate01": "MSValidate.01",
"Meta_robots": "Robots",
"Min_length_is": "Min length is %s",
"Minimum_balance": "Minimum balance",
"minutes": "minutes",
"Mobile": "Mobile",
"Mobile_Notifications_Default_Alert": "Mobile Notifications Default Alert",
Expand Down Expand Up @@ -1515,6 +1526,8 @@
"Report_exclamation_mark": "Report!",
"Report_sent": "Report sent",
"Report_this_message_question_mark": "Report this message?",
"Require_all_tokens": "Require all tokens",
"Require_any_token": "Require any token",
"Require_password_change": "Require password change",
"Resend_verification_email": "Resend verification email",
"Reset": "Reset",
Expand All @@ -1540,6 +1553,7 @@
"Room_has_been_deleted": "Room has been deleted",
"Room_has_been_archived": "Room has been archived",
"Room_has_been_unarchived": "Room has been unarchived",
"Room_tokenpass_config_changed_successfully": "Room tokenpass configuration changed successfully",
"Room_type_of_default_rooms_cant_be_changed": "This is a default room and the type can not be changed, please consult with your administrator.",
"Room_default_change_to_private_will_be_default_no_more": "This is a default channel and changing it to a private group will cause it to no longer be a default channel. Do you want to proceed?",
"Room_Info": "Room Info",
Expand Down Expand Up @@ -1803,6 +1817,17 @@
"to_see_more_details_on_how_to_integrate": "to see more details on how to integrate.",
"To_users": "To Users",
"Toggle_original_translated": "Toggle original/translated",
"Token_Access": "Token Access",
"Token_Controlled_Access": "Token Controlled Access",
"Token_required": "Token required",
"Tokenpass_Channels": "Tokenpass Channels",
"Tokens_Minimum_Needed_Balance": "Minimum needed token balance",
"Tokens_Minimum_Needed_Balance_Description": "Set minimum needed balance on each token. Blank or \"0\" for not limit.",
"Tokens_Minimum_Needed_Balance_Placeholder": "Balance value",
"Tokens_Required": "Tokens required",
"Tokens_Required_Input_Description": "Type one or more tokens asset names separated by comma.",
"Tokens_Required_Input_Error": "Invalid typed tokens.",
"Tokens_Required_Input_Placeholder": "Tokens asset names",
"Topic": "Topic",
"Travel_and_Places": "Travel & Places",
"Transcript_Enabled": "Ask visitor if they would like a transcript after chat closed",
Expand Down
15 changes: 13 additions & 2 deletions packages/rocketchat-lib/server/methods/createPrivateGroup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Meteor.methods({
createPrivateGroup(name, members, readOnly = false, customFields = {}) {
createPrivateGroup(name, members, readOnly = false, customFields = {}, extraData = {}) {
check(name, String);
check(members, Match.Optional([String]));

Expand All @@ -11,6 +11,17 @@ Meteor.methods({
throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'createPrivateGroup' });
}

return RocketChat.createRoom('p', name, Meteor.user() && Meteor.user().username, members, readOnly, {customFields});
// validate extra data schema
check(extraData, Match.ObjectIncluding({
tokenpass: Match.Maybe({
require: String,
tokens: [{
token: String,
balance: String
}]
})
}));

return RocketChat.createRoom('p', name, Meteor.user() && Meteor.user().username, members, readOnly, {customFields, ...extraData});
}
});
23 changes: 16 additions & 7 deletions packages/rocketchat-lib/server/methods/joinRoom.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
Meteor.methods({
joinRoom(rid, code) {

check(rid, String);

if (!Meteor.userId()) {
Expand All @@ -13,14 +12,24 @@ Meteor.methods({
throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'joinRoom' });
}

if ((room.t !== 'c') || (RocketChat.authz.hasPermission(Meteor.userId(), 'view-c-room') !== true)) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'joinRoom' });
}
// TODO we should have a 'beforeJoinRoom' call back so external services can do their own validations
const user = Meteor.user();
if (room.tokenpass && user && user.services && user.services.tokenpass) {
const balances = RocketChat.updateUserTokenpassBalances(user);

if (!RocketChat.Tokenpass.validateAccess(room.tokenpass, balances)) {
throw new Meteor.Error('error-not-allowed', 'Token required', { method: 'joinRoom' });
}
} else {
if ((room.t !== 'c') || (RocketChat.authz.hasPermission(Meteor.userId(), 'view-c-room') !== true)) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'joinRoom' });
}

if ((room.joinCodeRequired === true) && (code !== room.joinCode) && !RocketChat.authz.hasPermission(Meteor.userId(), 'join-without-join-code')) {
throw new Meteor.Error('error-code-invalid', 'Invalid Code', { method: 'joinRoom' });
if ((room.joinCodeRequired === true) && (code !== room.joinCode) && !RocketChat.authz.hasPermission(Meteor.userId(), 'join-without-join-code')) {
throw new Meteor.Error('error-code-invalid', 'Invalid Code', { method: 'joinRoom' });
}
}

return RocketChat.addUserToRoom(rid, Meteor.user());
return RocketChat.addUserToRoom(rid, user);
}
});
5 changes: 5 additions & 0 deletions packages/rocketchat-lib/startup/defaultRoomTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ RocketChat.roomTypes.add('channels', 30, {
return ['unread', 'category'].includes(preferences.roomsListExhibitionMode) && preferences.mergeChannels;
}
});

// public
RocketChat.roomTypes.add('c', 30, {
icon: 'hashtag',
Expand Down Expand Up @@ -102,6 +103,10 @@ RocketChat.roomTypes.add('p', 40, {
const user = Meteor.user();
const preferences = (user && user.settings && user.settings.preferences && user.settings.preferences) || {};
return !preferences.roomsListExhibitionMode || ['unread', 'category'].includes(preferences.roomsListExhibitionMode) && !preferences.mergeChannels && RocketChat.authz.hasAllPermission('view-p-room');
},

showJoinLink() {
return true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is going to just be true with no logic do we really need this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so, for private groups there is no logic because it will always show a "Room not found" message and will not render the "join link". unless it's a TCA private group and you can see it (because you have the needed token), in this case it will always show the join link =)

}
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.chip-container {
margin: 15px;

font-size: 15px;
list-style-type: none;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
height: 100%;
justify-content: center;

overflow-y: auto;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I remove this? I fixed that on #8637

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes please


&__wrapper {
position: relative;

Expand Down
6 changes: 6 additions & 0 deletions packages/rocketchat-theme/client/imports/forms/button.css
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,9 @@
}
}
}

@media (width < 780px) {
.rc-button--full {
width: 100%;
}
}
22 changes: 11 additions & 11 deletions packages/rocketchat-theme/client/imports/forms/switch.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@
&__input {
display: none;

&:checked {
& + .rc-switch__button {
border-color: #26d198;
background-color: var(--color-success);

& .rc-switch__button-inside {
transform: translate3d(1px, 1px, 0);
}
}
}

&:disabled {
& + .rc-switch__button {
cursor: default;
Expand All @@ -21,17 +32,6 @@
cursor: default;
}
}

&:checked {
& + .rc-switch__button {
border-color: #26d198;
background-color: var(--color-success);

& .rc-switch__button-inside {
transform: translate3d(1px, 1px, 0);
}
}
}
}

&__button {
Expand Down
8 changes: 6 additions & 2 deletions packages/rocketchat-theme/client/imports/forms/tags.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
flex-wrap: wrap;
justify-content: flex-start;

&--no-icon {
padding: 0;
}

&__tag {
display: flex;

Expand All @@ -22,13 +26,13 @@
background: var(--tags-background);
align-items: center;

&-avatar {
&-image {
width: var(--tags-avatar-size);
height: var(--tags-avatar-size);
margin-right: 0.5rem;
}

&-username {
&-text {
margin-right: 0.5rem;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/rocketchat-theme/client/imports/general/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ button {

.rc-icon {
width: 1em;
height: 1em;
height: 1em;

vertical-align: -0.15em;

overflow: hidden;
overflow: hidden;
}
19 changes: 19 additions & 0 deletions packages/rocketchat-theme/client/imports/general/forms.css
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,29 @@
font-size: var(--input-font-size);
}

.rc-form-fieldset {
padding: var(--default-padding);

border-width: var(--input-border-width);
border-color: var(--input-border-color);
border-radius: var(--input-border-radius);
background-color: transparent;

&--error {
color: var(--input-error-color);
border-color: var(--input-error-color);
}
}

.rc-form-legend {
margin: 0 -5px;

padding: 0 5px;

color: #2d343d;

font-size: 1rem;
font-weight: 500;
}

.rc-grid {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
--status-busy: var(--color-error);
--status-invisible: var(--color-gray-medium);
--status-invisible-sidebar: var(--color-darkest);
--default-padding: 1rem;
--default-small-padding: 1rem;

/*
Expand Down
3 changes: 3 additions & 0 deletions packages/rocketchat-tokenpass/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Tokenpass OAuth Flow

An implementation of the Tokenpass OAuth flow with Tokenpass using RocketChat CustomOAuth. See the [Tokenpass API Reference](http://apidocs.tokenly.com/tokenpass/#oauth-integration) for more details.
Loading