From b942f44fbb96abaf0543d8b257965edb8c9e5a31 Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Thu, 28 Nov 2024 14:51:50 +0000 Subject: [PATCH 1/5] Allow Team Members to change Device Developer Mode part of #4778 Adds `device.memberEnableDeviceDeveloperMode` to configuration options. Defaults to `false`, but if set to `true` a Team Member as well as Team Owner can change the devices status --- docs/install/configuration.md | 7 +++++++ forge/routes/api/device.js | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/install/configuration.md b/docs/install/configuration.md index 01c07e819d..33e871784c 100644 --- a/docs/install/configuration.md +++ b/docs/install/configuration.md @@ -287,3 +287,10 @@ Option | Description `content_security_policy.directives` | Overrides the default set of directives, supplied as a JSON object defined by HelmetJS [here](https://helmetjs.github.io/#content-security-policy) `content_security_policy.report_only` | Enables reporting only mode. Default: `false` `content_security_policy.report_uri` | Provides at URI for reporting to be sent to if enabled + + +## Device Agent + +Option | Description +--------------|------------ +`device.memberEnableDeviceDeveloperMode` | Allows Team members to toggle Device Developer Mode. Default: `false` \ No newline at end of file diff --git a/forge/routes/api/device.js b/forge/routes/api/device.js index 550fff523f..d9ddf35e1f 100644 --- a/forge/routes/api/device.js +++ b/forge/routes/api/device.js @@ -768,7 +768,13 @@ module.exports = async function (app) { * @memberof module:forge/routes/api/device */ app.put('/:deviceId/mode', { - preHandler: app.needsPermission('device:edit'), + preHandler: async () => { + if (app.config.device?.memberEnableDeviceDeveloperMode === true) { + return app.needsPermission('device:editor') + } else { + return app.needsPermission('device:edit') + } + }, schema: { summary: 'Set device mode', tags: ['Devices'], From 88c23735bb342be38db6f94b00c97432bc7ed73e Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Thu, 28 Nov 2024 15:22:03 +0000 Subject: [PATCH 2/5] Update UI --- forge/ee/lib/deviceEditor/DeviceTunnelManager.js | 3 +++ frontend/src/pages/device/index.vue | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/forge/ee/lib/deviceEditor/DeviceTunnelManager.js b/forge/ee/lib/deviceEditor/DeviceTunnelManager.js index cc53ffefbc..a699c06054 100644 --- a/forge/ee/lib/deviceEditor/DeviceTunnelManager.js +++ b/forge/ee/lib/deviceEditor/DeviceTunnelManager.js @@ -59,6 +59,9 @@ class DeviceTunnelManager { this.closeTunnel(deviceId) } }) + if (app.config.device?.memberEnableDeviceDeveloperMode === true) { + app.config.features.register('memberEnableDeviceDeveloperMode', true) + } } /** diff --git a/frontend/src/pages/device/index.vue b/frontend/src/pages/device/index.vue index 6b4f50f21e..60f8785a48 100644 --- a/frontend/src/pages/device/index.vue +++ b/frontend/src/pages/device/index.vue @@ -188,6 +188,9 @@ export default { isOwner: function () { return this.teamMembership.role === Roles.Owner }, + isMember: function () { + return this.teamMembership.role === Roles.Member + }, isDevModeAvailable: function () { return !!this.features.deviceEditor }, @@ -198,10 +201,14 @@ export default { return this.device?.status === 'running' }, disableModeToggle: function () { + let user = this.isOwner + if (this.features.memberEnableDeviceDeveloperMode) { + user = this.isOwner || this.isMember + } return !this.isDevModeAvailable || !this.device || !this.agentSupportsDeviceAccess || - !this.isOwner + !user }, disableModeToggleReason: function () { if (!this.device) { From 5e26be9a449eef0d7f3d7ceeab3b2d18a7f84a3b Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Thu, 28 Nov 2024 16:04:44 +0000 Subject: [PATCH 3/5] Fix permision check --- forge/routes/api/device.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/forge/routes/api/device.js b/forge/routes/api/device.js index d9ddf35e1f..2e69aad813 100644 --- a/forge/routes/api/device.js +++ b/forge/routes/api/device.js @@ -762,19 +762,20 @@ module.exports = async function (app) { reply.send(await app.db.controllers.BrokerClient.createClientForFrontend(request.device)) }) + function permissionCheck() { + if (app.config.device?.memberEnableDeviceDeveloperMode === true ) { + return app.needsPermission('device:editor') + } else { + return app.needsPermission('device:edit') + } + } /** * Set device operating mode * @name /api/v1/devices/:deviceId/mode * @memberof module:forge/routes/api/device */ app.put('/:deviceId/mode', { - preHandler: async () => { - if (app.config.device?.memberEnableDeviceDeveloperMode === true) { - return app.needsPermission('device:editor') - } else { - return app.needsPermission('device:edit') - } - }, + preHandler: permissionCheck(), schema: { summary: 'Set device mode', tags: ['Devices'], From 5d992b71b79cb02c93d9e0bc5b871315a64ca513 Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Thu, 28 Nov 2024 16:15:22 +0000 Subject: [PATCH 4/5] Rollback configuration --- docs/install/configuration.md | 7 ------- forge/ee/lib/deviceEditor/DeviceTunnelManager.js | 3 --- forge/routes/api/device.js | 9 +-------- frontend/src/pages/device/index.vue | 15 ++++----------- 4 files changed, 5 insertions(+), 29 deletions(-) diff --git a/docs/install/configuration.md b/docs/install/configuration.md index 33e871784c..01c07e819d 100644 --- a/docs/install/configuration.md +++ b/docs/install/configuration.md @@ -287,10 +287,3 @@ Option | Description `content_security_policy.directives` | Overrides the default set of directives, supplied as a JSON object defined by HelmetJS [here](https://helmetjs.github.io/#content-security-policy) `content_security_policy.report_only` | Enables reporting only mode. Default: `false` `content_security_policy.report_uri` | Provides at URI for reporting to be sent to if enabled - - -## Device Agent - -Option | Description ---------------|------------ -`device.memberEnableDeviceDeveloperMode` | Allows Team members to toggle Device Developer Mode. Default: `false` \ No newline at end of file diff --git a/forge/ee/lib/deviceEditor/DeviceTunnelManager.js b/forge/ee/lib/deviceEditor/DeviceTunnelManager.js index a699c06054..cc53ffefbc 100644 --- a/forge/ee/lib/deviceEditor/DeviceTunnelManager.js +++ b/forge/ee/lib/deviceEditor/DeviceTunnelManager.js @@ -59,9 +59,6 @@ class DeviceTunnelManager { this.closeTunnel(deviceId) } }) - if (app.config.device?.memberEnableDeviceDeveloperMode === true) { - app.config.features.register('memberEnableDeviceDeveloperMode', true) - } } /** diff --git a/forge/routes/api/device.js b/forge/routes/api/device.js index 2e69aad813..e90e183714 100644 --- a/forge/routes/api/device.js +++ b/forge/routes/api/device.js @@ -762,20 +762,13 @@ module.exports = async function (app) { reply.send(await app.db.controllers.BrokerClient.createClientForFrontend(request.device)) }) - function permissionCheck() { - if (app.config.device?.memberEnableDeviceDeveloperMode === true ) { - return app.needsPermission('device:editor') - } else { - return app.needsPermission('device:edit') - } - } /** * Set device operating mode * @name /api/v1/devices/:deviceId/mode * @memberof module:forge/routes/api/device */ app.put('/:deviceId/mode', { - preHandler: permissionCheck(), + preHandler: app.needsPermission('device:editor'), schema: { summary: 'Set device mode', tags: ['Devices'], diff --git a/frontend/src/pages/device/index.vue b/frontend/src/pages/device/index.vue index 60f8785a48..330c1627fe 100644 --- a/frontend/src/pages/device/index.vue +++ b/frontend/src/pages/device/index.vue @@ -185,11 +185,8 @@ export default { isVisitingAdmin: function () { return this.teamMembership.role === Roles.Admin }, - isOwner: function () { - return this.teamMembership.role === Roles.Owner - }, isMember: function () { - return this.teamMembership.role === Roles.Member + return this.teamMembership.role === Roles.Member || this.teamMembership.role === Roles.Owner }, isDevModeAvailable: function () { return !!this.features.deviceEditor @@ -201,14 +198,10 @@ export default { return this.device?.status === 'running' }, disableModeToggle: function () { - let user = this.isOwner - if (this.features.memberEnableDeviceDeveloperMode) { - user = this.isOwner || this.isMember - } return !this.isDevModeAvailable || !this.device || !this.agentSupportsDeviceAccess || - !user + !this.isMember }, disableModeToggleReason: function () { if (!this.device) { @@ -217,8 +210,8 @@ export default { if (!this.agentSupportsDeviceAccess) { return 'Device Agent V0.8 or greater is required' } - if (!this.isOwner) { - return 'Only an owner can change the Device Mode' + if (!this.isMember) { + return 'Only an Owner or Member can change the Device Mode' } return undefined }, From 6e1d7b8d8dbe49fff6b83a8f6a117088632e37c3 Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Thu, 28 Nov 2024 16:30:30 +0000 Subject: [PATCH 5/5] Fix test --- test/unit/forge/routes/api/device_spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/forge/routes/api/device_spec.js b/test/unit/forge/routes/api/device_spec.js index 7cd27357ad..f6d4bf22a1 100644 --- a/test/unit/forge/routes/api/device_spec.js +++ b/test/unit/forge/routes/api/device_spec.js @@ -1284,7 +1284,7 @@ describe('Device API', async function () { settings.should.have.property('mode', 'developer') settings.should.have.property('editor') }) - it('team member can not set device to developer mode', async function () { + it('team member can set device to developer mode', async function () { const device = await createDevice({ name: 'Ad1', type: '', team: TestObjects.ATeam.hashid, as: TestObjects.tokens.alice }) const response = await app.inject({ method: 'PUT', @@ -1294,7 +1294,7 @@ describe('Device API', async function () { }, cookies: { sid: TestObjects.tokens.chris } }) - response.statusCode.should.equal(403) + response.statusCode.should.equal(200) }) }) })