diff --git a/changelog/unreleased/sharing-secure-view-role.md b/changelog/unreleased/sharing-secure-view-role.md new file mode 100644 index 0000000000..a60646f94d --- /dev/null +++ b/changelog/unreleased/sharing-secure-view-role.md @@ -0,0 +1,5 @@ +Enhancement: Secure viewer share role + +A new share role "Secure viewer" has been added. This role is applicable for files, folders and spaces and only allows viewing them (and their content). + +https://github.com/owncloud/ocis/pull/8907 diff --git a/services/graph/pkg/unifiedrole/unifiedrole.go b/services/graph/pkg/unifiedrole/unifiedrole.go index c06d3d4bb1..cd20a93ec9 100644 --- a/services/graph/pkg/unifiedrole/unifiedrole.go +++ b/services/graph/pkg/unifiedrole/unifiedrole.go @@ -27,6 +27,8 @@ const ( UnifiedRoleUploaderID = "1c996275-f1c9-4e71-abdf-a42f6495e960" // UnifiedRoleManagerID Unified role manager id. UnifiedRoleManagerID = "312c0871-5ef7-4b3a-85b6-0e4074c64049" + // UnifiedRoleSecureViewerID Unified role secure viewer id. + UnifiedRoleSecureViewerID = "aa97fe03-7980-45ac-9e50-b325749fd7e6" // UnifiedRoleConditionDrive defines constraint that matches a Driveroot/Spaceroot UnifiedRoleConditionDrive = "exists @Resource.Root" @@ -60,12 +62,13 @@ var legacyNames map[string]string = map[string]string{ UnifiedRoleViewerID: conversions.RoleViewer, // one V1 api the "spaceviewer" role was call "viewer" and the "spaceeditor" was "editor", // we need to stay compatible with that - UnifiedRoleSpaceViewerID: "viewer", - UnifiedRoleSpaceEditorID: "editor", - UnifiedRoleEditorID: conversions.RoleEditor, - UnifiedRoleFileEditorID: conversions.RoleFileEditor, - UnifiedRoleUploaderID: conversions.RoleUploader, - UnifiedRoleManagerID: conversions.RoleManager, + UnifiedRoleSpaceViewerID: "viewer", + UnifiedRoleSpaceEditorID: "editor", + UnifiedRoleEditorID: conversions.RoleEditor, + UnifiedRoleFileEditorID: conversions.RoleFileEditor, + UnifiedRoleUploaderID: conversions.RoleUploader, + UnifiedRoleManagerID: conversions.RoleManager, + UnifiedRoleSecureViewerID: conversions.RoleSecureViewer, } // NewViewerUnifiedRole creates a viewer role. @@ -191,6 +194,31 @@ func NewManagerUnifiedRole() *libregraph.UnifiedRoleDefinition { } } +// NewSecureViewerUnifiedRole creates a secure viewer role +func NewSecureViewerUnifiedRole() *libregraph.UnifiedRoleDefinition { + r := conversions.NewSecureViewerRole() + return &libregraph.UnifiedRoleDefinition{ + Id: proto.String(UnifiedRoleSecureViewerID), + Description: proto.String("View only documents, images and PDFs. Watermarks will be applied."), + DisplayName: displayName(r), + RolePermissions: []libregraph.UnifiedRolePermission{ + { + AllowedResourceActions: convert(r), + Condition: proto.String(UnifiedRoleConditionFile), + }, + { + AllowedResourceActions: convert(r), + Condition: proto.String(UnifiedRoleConditionFolder), + }, + { + AllowedResourceActions: convert(r), + Condition: proto.String(UnifiedRoleConditionDrive), + }, + }, + LibreGraphWeight: proto.Int32(0), + } +} + // NewUnifiedRoleFromID returns a unified role definition from the provided id func NewUnifiedRoleFromID(id string) (*libregraph.UnifiedRoleDefinition, error) { for _, definition := range GetBuiltinRoleDefinitionList() { @@ -213,6 +241,7 @@ func GetBuiltinRoleDefinitionList() []*libregraph.UnifiedRoleDefinition { NewFileEditorUnifiedRole(), NewUploaderUnifiedRole(), NewManagerUnifiedRole(), + NewSecureViewerUnifiedRole(), } } @@ -476,6 +505,8 @@ func displayName(role *conversions.Role) *string { displayName = "Can upload" case conversions.RoleManager: displayName = "Can manage" + case conversions.RoleSecureViewer: + displayName = "Can view (secure)" default: return nil } diff --git a/services/graph/pkg/unifiedrole/unifiedrole_test.go b/services/graph/pkg/unifiedrole/unifiedrole_test.go index 5b0e21ba91..b8d95e3ae7 100644 --- a/services/graph/pkg/unifiedrole/unifiedrole_test.go +++ b/services/graph/pkg/unifiedrole/unifiedrole_test.go @@ -31,6 +31,9 @@ var _ = Describe("unifiedroles", func() { Entry(rConversions.RoleManager, rConversions.NewManagerRole(), unifiedrole.NewManagerUnifiedRole(), unifiedrole.UnifiedRoleConditionDrive), Entry(rConversions.RoleSpaceViewer, rConversions.NewSpaceViewerRole(), unifiedrole.NewSpaceViewerUnifiedRole(), unifiedrole.UnifiedRoleConditionDrive), Entry(rConversions.RoleSpaceEditor, rConversions.NewSpaceEditorRole(), unifiedrole.NewSpaceEditorUnifiedRole(), unifiedrole.UnifiedRoleConditionDrive), + Entry(rConversions.RoleSecureViewer, rConversions.NewSecureViewerRole(), unifiedrole.NewSecureViewerUnifiedRole(), unifiedrole.UnifiedRoleConditionFile), + Entry(rConversions.RoleSecureViewer, rConversions.NewSecureViewerRole(), unifiedrole.NewSecureViewerUnifiedRole(), unifiedrole.UnifiedRoleConditionFolder), + Entry(rConversions.RoleSecureViewer, rConversions.NewSecureViewerRole(), unifiedrole.NewSecureViewerUnifiedRole(), unifiedrole.UnifiedRoleConditionDrive), ) DescribeTable("UnifiedRolePermissionsToCS3ResourcePermissions", @@ -54,6 +57,7 @@ var _ = Describe("unifiedroles", func() { Entry(rConversions.RoleEditor, rConversions.NewEditorRole(), unifiedrole.NewEditorUnifiedRole(), true), Entry(rConversions.RoleFileEditor, rConversions.NewFileEditorRole(), unifiedrole.NewFileEditorUnifiedRole(), true), Entry(rConversions.RoleManager, rConversions.NewManagerRole(), unifiedrole.NewManagerUnifiedRole(), true), + Entry(rConversions.RoleSecureViewer, rConversions.NewSecureViewerRole(), unifiedrole.NewSecureViewerUnifiedRole(), true), Entry("no match", rConversions.NewFileEditorRole(), unifiedrole.NewManagerUnifiedRole(), false), ) @@ -135,6 +139,7 @@ var _ = Describe("unifiedroles", func() { rolesToAction(unifiedrole.NewViewerUnifiedRole()), unifiedrole.UnifiedRoleConditionFolder, []*libregraph.UnifiedRoleDefinition{ + unifiedrole.NewSecureViewerUnifiedRole(), unifiedrole.NewViewerUnifiedRole(), }, ), @@ -144,6 +149,7 @@ var _ = Describe("unifiedroles", func() { rolesToAction(unifiedrole.NewViewerUnifiedRole()), unifiedrole.UnifiedRoleConditionFile, []*libregraph.UnifiedRoleDefinition{ + unifiedrole.NewSecureViewerUnifiedRole(), unifiedrole.NewViewerUnifiedRole(), }, ), @@ -153,6 +159,7 @@ var _ = Describe("unifiedroles", func() { rolesToAction(unifiedrole.NewFileEditorUnifiedRole()), unifiedrole.UnifiedRoleConditionFile, []*libregraph.UnifiedRoleDefinition{ + unifiedrole.NewSecureViewerUnifiedRole(), unifiedrole.NewViewerUnifiedRole(), unifiedrole.NewFileEditorUnifiedRole(), }, @@ -163,6 +170,7 @@ var _ = Describe("unifiedroles", func() { rolesToAction(unifiedrole.NewEditorUnifiedRole()), unifiedrole.UnifiedRoleConditionFolder, []*libregraph.UnifiedRoleDefinition{ + unifiedrole.NewSecureViewerUnifiedRole(), unifiedrole.NewUploaderUnifiedRole(), unifiedrole.NewViewerUnifiedRole(), unifiedrole.NewEditorUnifiedRole(), @@ -174,6 +182,7 @@ var _ = Describe("unifiedroles", func() { rolesToAction(unifiedrole.GetBuiltinRoleDefinitionList()...), unifiedrole.UnifiedRoleConditionFile, []*libregraph.UnifiedRoleDefinition{ + unifiedrole.NewSecureViewerUnifiedRole(), unifiedrole.NewViewerUnifiedRole(), unifiedrole.NewFileEditorUnifiedRole(), }, @@ -184,6 +193,7 @@ var _ = Describe("unifiedroles", func() { rolesToAction(unifiedrole.GetBuiltinRoleDefinitionList()...), unifiedrole.UnifiedRoleConditionFolder, []*libregraph.UnifiedRoleDefinition{ + unifiedrole.NewSecureViewerUnifiedRole(), unifiedrole.NewUploaderUnifiedRole(), unifiedrole.NewViewerUnifiedRole(), unifiedrole.NewEditorUnifiedRole(), @@ -195,6 +205,7 @@ var _ = Describe("unifiedroles", func() { rolesToAction(unifiedrole.GetBuiltinRoleDefinitionList()...), unifiedrole.UnifiedRoleConditionDrive, []*libregraph.UnifiedRoleDefinition{ + unifiedrole.NewSecureViewerUnifiedRole(), unifiedrole.NewSpaceViewerUnifiedRole(), unifiedrole.NewSpaceEditorUnifiedRole(), unifiedrole.NewManagerUnifiedRole(), diff --git a/tests/TestHelpers/GraphHelper.php b/tests/TestHelpers/GraphHelper.php index f273ff6a04..d6596c9aa4 100644 --- a/tests/TestHelpers/GraphHelper.php +++ b/tests/TestHelpers/GraphHelper.php @@ -1642,6 +1642,8 @@ class GraphHelper { return '1c996275-f1c9-4e71-abdf-a42f6495e960'; case 'Manager': return '312c0871-5ef7-4b3a-85b6-0e4074c64049'; + case 'Secure viewer': + return 'aa97fe03-7980-45ac-9e50-b325749fd7e6'; default: throw new \Exception('Role ' . $permissionsRole . ' not found'); } @@ -1674,6 +1676,8 @@ class GraphHelper { return 'Space Editor'; case '312c0871-5ef7-4b3a-85b6-0e4074c64049': return 'Manager'; + case 'aa97fe03-7980-45ac-9e50-b325749fd7e6': + return 'Secure viewer'; default: throw new \Exception('Permission role id: ' . $permissionsRoleId . ' not found'); } diff --git a/tests/acceptance/features/apiSharingNg/listPermissions.feature b/tests/acceptance/features/apiSharingNg/listPermissions.feature index 0186ebc0bb..003b5ac034 100644 --- a/tests/acceptance/features/apiSharingNg/listPermissions.feature +++ b/tests/acceptance/features/apiSharingNg/listPermissions.feature @@ -48,8 +48,8 @@ Feature: List a sharing permissions }, "@libre.graph.permissions.roles.allowedValues": { "type": "array", - "minItems": 3, - "maxItems": 3, + "minItems": 4, + "maxItems": 4, "uniqueItems": true, "items": { "oneOf": [ @@ -68,6 +68,41 @@ Feature: List a sharing permissions 1 ] }, + "description": { + "type": "string", + "enum": [ + "View only documents, images and PDFs. Watermarks will be applied." + ] + }, + "displayName": { + "type": "string", + "enum": [ + "Can view (secure)" + ] + }, + "id": { + "type": "string", + "enum": [ + "aa97fe03-7980-45ac-9e50-b325749fd7e6" + ] + } + } + }, + { + "type": "object", + "required": [ + "@libre.graph.weight", + "description", + "displayName", + "id" + ], + "properties": { + "@libre.graph.weight": { + "type": "integer", + "enum": [ + 2 + ] + }, "description": { "type": "string", "enum": [ @@ -100,7 +135,7 @@ Feature: List a sharing permissions "@libre.graph.weight": { "type": "integer", "enum": [ - 2 + 3 ] }, "description": { @@ -135,7 +170,7 @@ Feature: List a sharing permissions "@libre.graph.weight": { "type": "integer", "enum": [ - 3 + 4 ] }, "description": { @@ -207,8 +242,8 @@ Feature: List a sharing permissions }, "@libre.graph.permissions.roles.allowedValues": { "type": "array", - "minItems": 3, - "maxItems": 3, + "minItems": 4, + "maxItems": 4, "uniqueItems": true, "items": { "oneOf": [ @@ -224,6 +259,29 @@ Feature: List a sharing permissions "@libre.graph.weight": { "const": 1 }, + "description": { + "const": "View only documents, images and PDFs. Watermarks will be applied." + }, + "displayName": { + "const": "Can view (secure)" + }, + "id": { + "const": "aa97fe03-7980-45ac-9e50-b325749fd7e6" + } + } + }, + { + "type": "object", + "required": [ + "@libre.graph.weight", + "description", + "displayName", + "id" + ], + "properties": { + "@libre.graph.weight": { + "const": 2 + }, "description": { "const": "View and download." }, @@ -245,7 +303,7 @@ Feature: List a sharing permissions ], "properties": { "@libre.graph.weight": { - "const": 2 + "const": 3 }, "description": { "const": "View, download, upload, edit, add and delete." @@ -268,7 +326,7 @@ Feature: List a sharing permissions ], "properties": { "@libre.graph.weight": { - "const": 3 + "const": 4 }, "description": { "const": "View, download, upload, edit, add, delete and manage members." @@ -341,8 +399,8 @@ Feature: List a sharing permissions }, "@libre.graph.permissions.roles.allowedValues": { "type": "array", - "minItems": 3, - "maxItems": 3, + "minItems": 4, + "maxItems": 4, "uniqueItems": true, "items": { "oneOf": [ @@ -358,6 +416,29 @@ Feature: List a sharing permissions "@libre.graph.weight": { "const": 1 }, + "description": { + "const": "View only documents, images and PDFs. Watermarks will be applied." + }, + "displayName": { + "const": "Can view (secure)" + }, + "id": { + "const": "aa97fe03-7980-45ac-9e50-b325749fd7e6" + } + } + }, + { + "type": "object", + "required": [ + "@libre.graph.weight", + "description", + "displayName", + "id" + ], + "properties": { + "@libre.graph.weight": { + "const": 2 + }, "description": { "const": "View and download." }, @@ -379,7 +460,7 @@ Feature: List a sharing permissions ], "properties": { "@libre.graph.weight": { - "const": 2 + "const": 3 }, "description": { "const": "View, download, upload, edit, add and delete." @@ -402,7 +483,7 @@ Feature: List a sharing permissions ], "properties": { "@libre.graph.weight": { - "const": 3 + "const": 4 }, "description": { "const": "View, download, upload, edit, add, delete and manage members." @@ -603,8 +684,8 @@ Feature: List a sharing permissions }, "@libre.graph.permissions.roles.allowedValues": { "type": "array", - "minItems": 2, - "maxItems": 2, + "minItems": 3, + "maxItems": 3, "uniqueItems": true, "items": { "oneOf":[ @@ -620,6 +701,29 @@ Feature: List a sharing permissions "@libre.graph.weight": { "const": 1 }, + "description": { + "const": "View only documents, images and PDFs. Watermarks will be applied." + }, + "displayName": { + "const": "Can view (secure)" + }, + "id": { + "const": "aa97fe03-7980-45ac-9e50-b325749fd7e6" + } + } + }, + { + "type": "object", + "required": [ + "@libre.graph.weight", + "description", + "displayName", + "id" + ], + "properties": { + "@libre.graph.weight": { + "const": 2 + }, "description": { "const": "View and download." }, @@ -641,7 +745,7 @@ Feature: List a sharing permissions ], "properties": { "@libre.graph.weight": { - "const": 2 + "const": 3 }, "description": { "const": "View, download and edit." @@ -706,11 +810,34 @@ Feature: List a sharing permissions }, "@libre.graph.permissions.roles.allowedValues": { "type": "array", - "minItems": 3, - "maxItems": 3, + "minItems": 4, + "maxItems": 4, "uniqueItems": true, "items": { "oneOf":[ + { + "type": "object", + "required": [ + "@libre.graph.weight", + "description", + "displayName", + "id" + ], + "properties": { + "@libre.graph.weight": { + "const": 1 + }, + "description": { + "const": "View only documents, images and PDFs. Watermarks will be applied." + }, + "displayName": { + "const": "Can view (secure)" + }, + "id": { + "const": "aa97fe03-7980-45ac-9e50-b325749fd7e6" + } + } + }, { "type": "object", "required": [ @@ -721,7 +848,7 @@ Feature: List a sharing permissions ], "properties": { "@libre.graph.weight": { - "const": 1 + "const": 2 }, "description": { "const": "View, download and upload." @@ -744,7 +871,7 @@ Feature: List a sharing permissions ], "properties": { "@libre.graph.weight": { - "const": 2 + "const": 3 }, "description": { "const": "View and download." @@ -767,7 +894,7 @@ Feature: List a sharing permissions ], "properties": { "@libre.graph.weight": { - "const": 3 + "const": 4 }, "description": { "const": "View, download, upload, edit, add and delete." @@ -832,8 +959,8 @@ Feature: List a sharing permissions }, "@libre.graph.permissions.roles.allowedValues": { "type": "array", - "minItems": 2, - "maxItems": 2, + "minItems": 3, + "maxItems": 3, "uniqueItems": true, "items": { "oneOf":[ @@ -849,6 +976,29 @@ Feature: List a sharing permissions "@libre.graph.weight": { "const": 1 }, + "description": { + "const": "View only documents, images and PDFs. Watermarks will be applied." + }, + "displayName": { + "const": "Can view (secure)" + }, + "id": { + "const": "aa97fe03-7980-45ac-9e50-b325749fd7e6" + } + } + }, + { + "type": "object", + "required": [ + "@libre.graph.weight", + "description", + "displayName", + "id" + ], + "properties": { + "@libre.graph.weight": { + "const": 2 + }, "description": { "const": "View and download." }, @@ -870,7 +1020,7 @@ Feature: List a sharing permissions ], "properties": { "@libre.graph.weight": { - "const": 2 + "const": 3 }, "description": { "const": "View, download and edit." @@ -955,8 +1105,8 @@ Feature: List a sharing permissions }, "@libre.graph.permissions.roles.allowedValues": { "type": "array", - "minItems": 3, - "maxItems": 3, + "minItems": 4, + "maxItems": 4, "uniqueItems": true, "items": { "oneOf": [ @@ -972,6 +1122,29 @@ Feature: List a sharing permissions "@libre.graph.weight": { "const": 1 }, + "description": { + "const": "View only documents, images and PDFs. Watermarks will be applied." + }, + "displayName": { + "const": "Can view (secure)" + }, + "id": { + "const": "aa97fe03-7980-45ac-9e50-b325749fd7e6" + } + } + }, + { + "type": "object", + "required": [ + "@libre.graph.weight", + "description", + "displayName", + "id" + ], + "properties": { + "@libre.graph.weight": { + "const": 2 + }, "description": { "const": "View and download." }, @@ -993,7 +1166,7 @@ Feature: List a sharing permissions ], "properties": { "@libre.graph.weight": { - "const": 2 + "const": 3 }, "description": { "const": "View, download, upload, edit, add and delete." @@ -1016,7 +1189,7 @@ Feature: List a sharing permissions ], "properties": { "@libre.graph.weight": { - "const": 3 + "const": 4 }, "description": { "const": "View, download, upload, edit, add, delete and manage members." @@ -1186,8 +1359,8 @@ Feature: List a sharing permissions }, "@libre.graph.permissions.roles.allowedValues": { "type": "array", - "minItems": 1, - "maxItems": 1, + "minItems": 2, + "maxItems": 2, "uniqueItems": true, "items": { "oneOf": [ @@ -1203,6 +1376,29 @@ Feature: List a sharing permissions "@libre.graph.weight": { "const": 1 }, + "description": { + "const": "View only documents, images and PDFs. Watermarks will be applied." + }, + "displayName": { + "const": "Can view (secure)" + }, + "id": { + "const": "aa97fe03-7980-45ac-9e50-b325749fd7e6" + } + } + }, + { + "type": "object", + "required": [ + "@libre.graph.weight", + "description", + "displayName", + "id" + ], + "properties": { + "@libre.graph.weight": { + "const": 2 + }, "description": { "const": "View and download." },