From 000dec7b009d6036e58e059c07580c0061fd44f3 Mon Sep 17 00:00:00 2001 From: vynmera <39674991+vynmera@users.noreply.github.com> Date: Fri, 1 Jun 2018 20:56:28 +0000 Subject: [PATCH 1/5] Implement permissions.list, permissions.update and add tests --- .../rocketchat-api/server/v1/permissions.js | 63 ++++++++++ packages/rocketchat-i18n/i18n/en.i18n.json | 18 +-- tests/end-to-end/api/11-permissions.js | 111 ++++++++++++++++++ 3 files changed, 184 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-api/server/v1/permissions.js b/packages/rocketchat-api/server/v1/permissions.js index 68ccb81c01e78..fdc096701e00a 100644 --- a/packages/rocketchat-api/server/v1/permissions.js +++ b/packages/rocketchat-api/server/v1/permissions.js @@ -12,3 +12,66 @@ RocketChat.API.v1.addRoute('permissions', { authRequired: true }, { return RocketChat.API.v1.success(result); } }); + +RocketChat.API.v1.addRoute('permissions.list', { authRequired: true }, { + get() { + const result = Meteor.runAsUser(this.userId, () => Meteor.call('permissions/get')); + + return RocketChat.API.v1.success({ + permissions: result + }); + } +}); + +RocketChat.API.v1.addRoute('permissions.update', { authRequired: true }, { + post() { + if (!RocketChat.authz.hasPermission(this.userId, 'access-permissions')) { + return RocketChat.API.v1.failure('Editing permissions is not allowed', 'error-edit-permissions-not-allowed'); + } + + check(this.bodyParams, { + permissions: [ + Match.ObjectIncluding({ + _id: String, + roles: [String] + }) + ] + }); + + let permissionNotFound = false; + let roleNotFound = false; + Object.keys(this.bodyParams.permissions).forEach((key) => { + const element = this.bodyParams.permissions[key]; + + if (!RocketChat.models.Permissions.findOneById(element._id)) { + permissionNotFound = true; + } + + Object.keys(element.roles).forEach((key) => { + const subelement = element.roles[key]; + + if (!RocketChat.models.Roles.findOneById(subelement)) { + roleNotFound = true; + } + }); + }); + + if (permissionNotFound) { + return RocketChat.API.v1.failure('Invalid permission', 'error-invalid-permission'); + } else if (roleNotFound) { + return RocketChat.API.v1.failure('Invalid role', 'error-invalid-role'); + } + + Object.keys(this.bodyParams.permissions).forEach((key) => { + const element = this.bodyParams.permissions[key]; + + RocketChat.models.Permissions.createOrUpdate(element._id, element.roles); + }); + + const result = Meteor.runAsUser(this.userId, () => Meteor.call('permissions/get')); + + return RocketChat.API.v1.success({ + permissions: result + }); + } +}); diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 719eeb5b057c4..bf94b0132a6ad 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -38,7 +38,7 @@ "Accounts_BlockedDomainsList_Description": "Comma-separated list of blocked domains", "Accounts_BlockedUsernameList": "Blocked Username List", "Accounts_BlockedUsernameList_Description": "Comma-separated list of blocked usernames (case-insensitive)", - "Accounts_CustomFields_Description": "Should be a valid JSON where keys are the field names containing a dictionary of field settings. Example:
{\n \"role\": {\n  \"type\": \"select\",\n  \"defaultValue\": \"student\",\n  \"options\": [\"teacher\", \"student\"],\n  \"required\": true,\n  \"modifyRecordField\": {\n   \"array\": true,\n   \"field\": \"roles\"\n  }\n },\n \"twitter\": {\n  \"type\": \"text\",\n  \"required\": true,\n  \"minLength\": 2,\n  \"maxLength\": 10\n }\n} ", + "Accounts_CustomFields_Description": "Should be a valid JSON where keys are the field names containing a dictionary of field settings. Example:
{\n \"role\": {\n \"type\": \"select\",\n \"defaultValue\": \"student\",\n \"options\": [\"teacher\", \"student\"],\n \"required\": true,\n \"modifyRecordField\": {\n \"array\": true,\n \"field\": \"roles\"\n }\n },\n \"twitter\": {\n \"type\": \"text\",\n \"required\": true,\n \"minLength\": 2,\n \"maxLength\": 10\n }\n} ", "Accounts_CustomFieldsToShowInUserInfo": "Custom Fields to Show in User Info", "Accounts_DefaultUsernamePrefixSuggestion": "Default Username Prefix Suggestion", "Accounts_Default_User_Preferences": "Default User Preferences", @@ -574,7 +574,7 @@ "Custom_Sound_Saved_Successfully": "Custom sound saved successfully", "Custom_Sounds": "Custom Sounds", "Custom_Translations": "Custom Translations", - "Custom_Translations_Description": "Should be a valid JSON where keys are languages containing a dictionary of key and translations. Example:
{\n \"en\": {\n  \"Channels\": \"Rooms\"\n },\n \"pt\": {\n  \"Channels\": \"Salas\"\n }\n} ", + "Custom_Translations_Description": "Should be a valid JSON where keys are languages containing a dictionary of key and translations. Example:
{\n \"en\": {\n \"Channels\": \"Rooms\"\n },\n \"pt\": {\n \"Channels\": \"Salas\"\n }\n} ", "Customize": "Customize", "CustomSoundsFilesystem": "Custom Sounds Filesystem", "Dashboard": "Dashboard", @@ -740,6 +740,7 @@ "error-department-not-found": "Department not found", "error-direct-message-file-upload-not-allowed": "File sharing not allowed in direct messages", "error-duplicate-channel-name": "A channel with name '__channel_name__' exists", + "error-edit-permissions-not-allowed": "Editing permissions is not allowed", "error-email-domain-blacklisted": "The email domain is blacklisted", "error-email-send-failed": "Error trying to send email: __message__", "error-field-unavailable": "__field__ is already in use :(", @@ -767,6 +768,7 @@ "error-invalid-method": "Invalid method", "error-invalid-name": "Invalid name", "error-invalid-password": "Invalid password", + "error-invalid-permission": "Invalid permission", "error-invalid-redirectUri": "Invalid redirectUri", "error-invalid-role": "Invalid role", "error-invalid-room": "Invalid room", @@ -1959,11 +1961,11 @@ "SlackBridge_Out_Enabled_Description": "Choose whether SlackBridge should also send your messages back to Slack", "SlackBridge_start": "@%s has started a SlackBridge import at `#%s`. We'll let you know when it's finished.", "Slack_Users": "Slack's Users CSV", - "Slash_Gimme_Description": "Displays ༼ つ ◕_◕ ༽つ before your message", - "Slash_LennyFace_Description": "Displays ( ͡° ͜ʖ ͡°) after your message", - "Slash_Shrug_Description": "Displays ¯\\_(ツ)_/¯ after your message", - "Slash_Tableflip_Description": "Displays (╯°□°)╯︵ ┻━┻", - "Slash_TableUnflip_Description": "Displays ┬─┬ ノ( ゜-゜ノ)", + "Slash_Gimme_Description": "Displays ? ? ?_? ?? before your message", + "Slash_LennyFace_Description": "Displays ( ?° ?? ?°) after your message", + "Slash_Shrug_Description": "Displays ¯\\_(?)_/¯ after your message", + "Slash_Tableflip_Description": "Displays (?°?°)?? ???", + "Slash_TableUnflip_Description": "Displays ---? ?( ?-??)", "Slash_Topic_Description": "Set topic", "Slash_Topic_Params": "Topic message", "Smarsh_Email": "Smarsh Email", @@ -2446,7 +2448,7 @@ "Your_password_is_wrong": "Your password is wrong!", "Your_push_was_sent_to_s_devices": "Your push was sent to %s devices", "Your_server_link": "Your server link", - "Your_workspace_is_ready": "Your workspace is ready to use 🎉", + "Your_workspace_is_ready": "Your workspace is ready to use ??", "Worldwide": "Worldwide", "Country_Afghanistan": "Afghanistan", "Country_Albania": "Albania", diff --git a/tests/end-to-end/api/11-permissions.js b/tests/end-to-end/api/11-permissions.js index 86b702342c011..41daefa3803ca 100644 --- a/tests/end-to-end/api/11-permissions.js +++ b/tests/end-to-end/api/11-permissions.js @@ -8,6 +8,8 @@ describe('[Permissions]', function() { before(done => getCredentials(done)); + //DEPRECATED + // TODO: Remove this after three versions have been released. That means at 0.69 this should be gone. describe('[/permissions]', () => { it('should return all permissions that exists on the server, with respective roles', (done) => { request.get(api('permissions')) @@ -30,4 +32,113 @@ describe('[Permissions]', function() { .end(done); }); }); + + describe('[/permissions.list]', () => { + it('should return all permissions that exists on the server, with respective roles', (done) => { + request.get(api('permissions.list')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('permissions'); + + const firstElement = res.body.permissions[0]; + expect(firstElement).to.have.property('_id'); + expect(firstElement).to.have.property('roles').and.to.be.a('array'); + expect(firstElement).to.have.property('_updatedAt'); + expect(firstElement).to.have.property('meta'); + expect(firstElement.meta).to.have.property('revision'); + expect(firstElement.meta).to.have.property('created'); + expect(firstElement.meta).to.have.property('version'); + expect(firstElement).to.have.property('$loki'); + }) + .end(done); + }); + }); + + describe('[/permissions.update]', () => { + it('should change the permissions on the server', (done) => { + const permissions = [ + { + "_id": "add-oauth-service", + "roles": ["admin", "user"] + } + ]; + request.post(api('permissions.update')) + .set(credentials) + .send({ + permissions: permissions + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('permissions'); + + const firstElement = res.body.permissions[0]; + expect(firstElement).to.have.property('_id'); + expect(firstElement).to.have.property('roles').and.to.be.a('array'); + expect(firstElement).to.have.property('_updatedAt'); + expect(firstElement).to.have.property('meta'); + expect(firstElement.meta).to.have.property('revision'); + expect(firstElement.meta).to.have.property('created'); + expect(firstElement.meta).to.have.property('version'); + expect(firstElement).to.have.property('$loki'); + }) + .end(done); + }); + it('should 400 when trying to set an unknown permission', (done) => { + const permissions = [ + { + "_id": "this-permission-does-not-exist", + "roles": ["admin"] + } + ]; + request.post(api('permissions.update')) + .set(credentials) + .send({ + permissions: permissions + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + }) + .end(done); + }); + it('should 400 when trying to assign a permission to an unknown role', (done) => { + const permissions = [ + { + "_id": "add-oauth-service", + "roles": ["this-role-does-not-exist"] + } + ]; + request.post(api('permissions.update')) + .set(credentials) + .send({ + permissions: permissions + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + }) + .end(done); + }); + it('should 400 when trying to set permissions to a string', (done) => { + const permissions = ''; + request.post(api('permissions.update')) + .set(credentials) + .send({ + permissions: permissions + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + }) + .end(done); + }); + }); }); From 347c27c3bf0ac96e39d084f0fcd626ace2ac3779 Mon Sep 17 00:00:00 2001 From: vynmera <39674991+vynmera@users.noreply.github.com> Date: Fri, 1 Jun 2018 21:01:23 +0000 Subject: [PATCH 2/5] i18n fix --- packages/rocketchat-i18n/i18n/en.i18n.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index bf94b0132a6ad..ed01ba365aded 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -38,7 +38,7 @@ "Accounts_BlockedDomainsList_Description": "Comma-separated list of blocked domains", "Accounts_BlockedUsernameList": "Blocked Username List", "Accounts_BlockedUsernameList_Description": "Comma-separated list of blocked usernames (case-insensitive)", - "Accounts_CustomFields_Description": "Should be a valid JSON where keys are the field names containing a dictionary of field settings. Example:
{\n \"role\": {\n \"type\": \"select\",\n \"defaultValue\": \"student\",\n \"options\": [\"teacher\", \"student\"],\n \"required\": true,\n \"modifyRecordField\": {\n \"array\": true,\n \"field\": \"roles\"\n }\n },\n \"twitter\": {\n \"type\": \"text\",\n \"required\": true,\n \"minLength\": 2,\n \"maxLength\": 10\n }\n} ", + "Accounts_CustomFields_Description": "Should be a valid JSON where keys are the field names containing a dictionary of field settings. Example:
{\n \"role\": {\n  \"type\": \"select\",\n  \"defaultValue\": \"student\",\n  \"options\": [\"teacher\", \"student\"],\n  \"required\": true,\n  \"modifyRecordField\": {\n   \"array\": true,\n   \"field\": \"roles\"\n  }\n },\n \"twitter\": {\n  \"type\": \"text\",\n  \"required\": true,\n  \"minLength\": 2,\n  \"maxLength\": 10\n }\n} ", "Accounts_CustomFieldsToShowInUserInfo": "Custom Fields to Show in User Info", "Accounts_DefaultUsernamePrefixSuggestion": "Default Username Prefix Suggestion", "Accounts_Default_User_Preferences": "Default User Preferences", @@ -574,7 +574,7 @@ "Custom_Sound_Saved_Successfully": "Custom sound saved successfully", "Custom_Sounds": "Custom Sounds", "Custom_Translations": "Custom Translations", - "Custom_Translations_Description": "Should be a valid JSON where keys are languages containing a dictionary of key and translations. Example:
{\n \"en\": {\n \"Channels\": \"Rooms\"\n },\n \"pt\": {\n \"Channels\": \"Salas\"\n }\n} ", + "Custom_Translations_Description": "Should be a valid JSON where keys are languages containing a dictionary of key and translations. Example:
{\n \"en\": {\n  \"Channels\": \"Rooms\"\n },\n \"pt\": {\n  \"Channels\": \"Salas\"\n }\n} ", "Customize": "Customize", "CustomSoundsFilesystem": "Custom Sounds Filesystem", "Dashboard": "Dashboard", @@ -1961,11 +1961,11 @@ "SlackBridge_Out_Enabled_Description": "Choose whether SlackBridge should also send your messages back to Slack", "SlackBridge_start": "@%s has started a SlackBridge import at `#%s`. We'll let you know when it's finished.", "Slack_Users": "Slack's Users CSV", - "Slash_Gimme_Description": "Displays ? ? ?_? ?? before your message", - "Slash_LennyFace_Description": "Displays ( ?° ?? ?°) after your message", - "Slash_Shrug_Description": "Displays ¯\\_(?)_/¯ after your message", - "Slash_Tableflip_Description": "Displays (?°?°)?? ???", - "Slash_TableUnflip_Description": "Displays ---? ?( ?-??)", + "Slash_Gimme_Description": "Displays ༼ つ ◕_◕ ༽つ before your message", + "Slash_LennyFace_Description": "Displays ( ͡° ͜ʖ ͡°) after your message", + "Slash_Shrug_Description": "Displays ¯\\_(ツ)_/¯ after your message", + "Slash_Tableflip_Description": "Displays (╯°□°)╯︵ ┻━┻", + "Slash_TableUnflip_Description": "Displays ┬─┬ ノ( ゜-゜ノ)", "Slash_Topic_Description": "Set topic", "Slash_Topic_Params": "Topic message", "Smarsh_Email": "Smarsh Email", @@ -2448,7 +2448,7 @@ "Your_password_is_wrong": "Your password is wrong!", "Your_push_was_sent_to_s_devices": "Your push was sent to %s devices", "Your_server_link": "Your server link", - "Your_workspace_is_ready": "Your workspace is ready to use ??", + "Your_workspace_is_ready": "Your workspace is ready to use 🎉", "Worldwide": "Worldwide", "Country_Afghanistan": "Afghanistan", "Country_Albania": "Albania", From 8ec0298c61d972cf5f903f786fc57fe8b1fdc24f Mon Sep 17 00:00:00 2001 From: vynmera <39674991+vynmera@users.noreply.github.com> Date: Fri, 1 Jun 2018 21:11:37 +0000 Subject: [PATCH 3/5] Resolve linter issues --- tests/end-to-end/api/11-permissions.js | 28 +++++++++----------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/tests/end-to-end/api/11-permissions.js b/tests/end-to-end/api/11-permissions.js index 41daefa3803ca..c7bb2e890355e 100644 --- a/tests/end-to-end/api/11-permissions.js +++ b/tests/end-to-end/api/11-permissions.js @@ -61,15 +61,13 @@ describe('[Permissions]', function() { it('should change the permissions on the server', (done) => { const permissions = [ { - "_id": "add-oauth-service", - "roles": ["admin", "user"] + '_id': 'add-oauth-service', + 'roles': ['admin', 'user'] } ]; request.post(api('permissions.update')) .set(credentials) - .send({ - permissions: permissions - }) + .send({ permissions }) .expect('Content-Type', 'application/json') .expect(200) .expect((res) => { @@ -91,15 +89,13 @@ describe('[Permissions]', function() { it('should 400 when trying to set an unknown permission', (done) => { const permissions = [ { - "_id": "this-permission-does-not-exist", - "roles": ["admin"] + '_id': 'this-permission-does-not-exist', + 'roles': ['admin'] } ]; request.post(api('permissions.update')) .set(credentials) - .send({ - permissions: permissions - }) + .send({ permissions }) .expect('Content-Type', 'application/json') .expect(400) .expect((res) => { @@ -110,15 +106,13 @@ describe('[Permissions]', function() { it('should 400 when trying to assign a permission to an unknown role', (done) => { const permissions = [ { - "_id": "add-oauth-service", - "roles": ["this-role-does-not-exist"] + '_id': 'add-oauth-service', + 'roles': ['this-role-does-not-exist'] } ]; request.post(api('permissions.update')) .set(credentials) - .send({ - permissions: permissions - }) + .send({ permissions }) .expect('Content-Type', 'application/json') .expect(400) .expect((res) => { @@ -130,9 +124,7 @@ describe('[Permissions]', function() { const permissions = ''; request.post(api('permissions.update')) .set(credentials) - .send({ - permissions: permissions - }) + .send({ permissions }) .expect('Content-Type', 'application/json') .expect(400) .expect((res) => { From db30fe2d7864cb1587aede6cdc84eacd4bb2412a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=83=95=E3=82=A3=E3=83=B3=E3=83=A1=E3=83=A9?= <39674991+vynmera@users.noreply.github.com> Date: Fri, 8 Jun 2018 23:21:57 +0000 Subject: [PATCH 4/5] Add deprecation notice to old permissions --- packages/rocketchat-api/server/v1/permissions.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-api/server/v1/permissions.js b/packages/rocketchat-api/server/v1/permissions.js index fdc096701e00a..2fbb1a8ea339c 100644 --- a/packages/rocketchat-api/server/v1/permissions.js +++ b/packages/rocketchat-api/server/v1/permissions.js @@ -7,6 +7,9 @@ */ RocketChat.API.v1.addRoute('permissions', { authRequired: true }, { get() { + const warningMessage = 'The endpoint "permissions" is deprecated and will be removed after version v0.69'; + console.warn(warningMessage); + const result = Meteor.runAsUser(this.userId, () => Meteor.call('permissions/get')); return RocketChat.API.v1.success(result); From efaf52fd698b0158378fe132cf474f8d65896577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=83=95=E3=82=A3=E3=83=B3=E3=83=A1=E3=83=A9?= <39674991+vynmera@users.noreply.github.com> Date: Sat, 9 Jun 2018 01:28:00 +0200 Subject: [PATCH 5/5] not sure what I expected from phone editing --- packages/rocketchat-api/server/v1/permissions.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-api/server/v1/permissions.js b/packages/rocketchat-api/server/v1/permissions.js index 2fbb1a8ea339c..eb3f606ad0b4d 100644 --- a/packages/rocketchat-api/server/v1/permissions.js +++ b/packages/rocketchat-api/server/v1/permissions.js @@ -7,9 +7,9 @@ */ RocketChat.API.v1.addRoute('permissions', { authRequired: true }, { get() { - const warningMessage = 'The endpoint "permissions" is deprecated and will be removed after version v0.69'; - console.warn(warningMessage); - + const warningMessage = 'The endpoint "permissions" is deprecated and will be removed after version v0.69'; + console.warn(warningMessage); + const result = Meteor.runAsUser(this.userId, () => Meteor.call('permissions/get')); return RocketChat.API.v1.success(result);