Skip to content

Commit

Permalink
Merge pull request #2908 from nextcloud/backport/2903/stable26
Browse files Browse the repository at this point in the history
[stable26] properly distinguish between inherited and unset permissions
  • Loading branch information
icewind1991 authored Apr 3, 2024
2 parents e67d8ad + 25dadc1 commit f4b0341
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 26 deletions.
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Folders can be configured from *Group folders* in the admin settings.
After a folder is created, the admin can give access to the folder to one or more groups, control their write/sharing permissions and assign a quota for the folder.
Note: Encrypting the contents of group folders is currently not supported.]]></description>
<version>14.0.8</version>
<version>14.0.9</version>
<licence>agpl</licence>
<author>Robin Appelman</author>
<namespace>GroupFolders</namespace>
Expand Down
11 changes: 8 additions & 3 deletions lib/DAV/ACLPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ public function propFind(PropFind $propFind, INode $node): void {

ksort($rulesByPath);
$inheritedPermissionsByMapping = [];
$inheritedMaskByMapping = [];
$mappings = [];
foreach ($rulesByPath as $rules) {
foreach ($rules as $rule) {
Expand All @@ -144,18 +145,22 @@ public function propFind(PropFind $propFind, INode $node): void {
if (!isset($inheritedPermissionsByMapping[$mappingKey])) {
$inheritedPermissionsByMapping[$mappingKey] = Constants::PERMISSION_ALL;
}
if (!isset($inheritedMaskByMapping[$mappingKey])) {
$inheritedMaskByMapping[$mappingKey] = 0;
}
$inheritedPermissionsByMapping[$mappingKey] = $rule->applyPermissions($inheritedPermissionsByMapping[$mappingKey]);
$inheritedMaskByMapping[$mappingKey] |= $rule->getMask();
}
}

return array_map(function ($mapping, $permissions) use ($fileInfo) {
return array_map(function ($mapping, $permissions, $mask) use ($fileInfo) {
return new Rule(
$mapping,
$fileInfo->getId(),
Constants::PERMISSION_ALL,
$mask,
$permissions
);
}, $mappings, $inheritedPermissionsByMapping);
}, $mappings, $inheritedPermissionsByMapping, $inheritedMaskByMapping);
});

$propFind->handle(self::GROUP_FOLDER_ID, function () use ($fileInfo) {
Expand Down
7 changes: 7 additions & 0 deletions src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,13 @@ class AclDavService {
inheritedAclsById[id] = acl
if (aclsById[id] == null) {
aclsById[id] = acl

aclsById[id].inheritedMask = acl.mask
aclsById[id].inheritedPermissions = acl.permissions
aclsById[id].mask = 0
} else {
aclsById[id].inheritedMask = acl.mask
aclsById[id].inheritedPermissions = acl.permissions
}
}
return {
Expand Down
23 changes: 16 additions & 7 deletions src/components/AclStateButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@
<div v-else>
<NcActions :aria-label="label" :v-tooltip="label">
<template #icon>
<component :is="icon" :size="16" />
<component :is="icon" :size="16" :class="{inherited: isInherited}" />
</template>
<NcActionRadio name="state"
:checked="state === STATES.INHERIT_ALLOW || state === STATES.INHERIT_DENY"
:checked="state === STATES.INHERIT_ALLOW || state === STATES.INHERIT_DENY || state === STATES.INHERIT_DEFAULT"
:disabled="disabled"
@change="$emit('update', STATES.INHERIT_ALLOW)">
@change="$emit('update', STATES.INHERIT_DEFAULT)">
{{ t('groupfolders', 'Inherit permission') }}
</NcActionRadio>
<NcActionRadio name="state"
Expand All @@ -62,17 +62,19 @@
<script>
import Check from 'vue-material-design-icons/Check.vue'
import Cancel from 'vue-material-design-icons/Cancel.vue'
import Minus from 'vue-material-design-icons/Minus.vue'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcPopoverMenu from '@nextcloud/vue/dist/Components/NcPopoverMenu.js'
import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
import NcActionRadio from '@nextcloud/vue/dist/Components/NcActionRadio.js'
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip.js'
const STATES = {
export const STATES = {
INHERIT_DENY: 0,
INHERIT_ALLOW: 1,
SELF_DENY: 2,
SELF_ALLOW: 3,
INHERIT_DEFAULT: 2,
SELF_DENY: 3,
SELF_ALLOW: 4,
}
export default {
Expand Down Expand Up @@ -113,10 +115,15 @@ export default {
},
computed: {
isAllowed() {
return this.state & 1
return this.state === STATES.INHERIT_ALLOW || this.state === STATES.SELF_ALLOW || this.state === STATES.INHERIT_DEFAULT
},
isInherited() {
return this.state === STATES.INHERIT_ALLOW || this.state === STATES.INHERIT_DENY || this.state === STATES.INHERIT_DEFAULT
},
icon() {
switch (this.state) {
case STATES.INHERIT_DEFAULT:
return Minus
case STATES.INHERIT_ALLOW:
case STATES.SELF_ALLOW:
return Check
Expand All @@ -126,6 +133,8 @@ export default {
},
label() {
switch (this.state) {
case STATES.INHERIT_DEFAULT:
return t('groupfolders', 'Unset')
case STATES.INHERIT_DENY:
return t('groupfolders', 'Denied (Inherited permission)')
case STATES.INHERIT_ALLOW:
Expand Down
38 changes: 23 additions & 15 deletions src/components/SharingSidebarView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,31 +83,31 @@
{{ getFullDisplayName(item.mappingDisplayName, item.mappingType) }}
</td>
<td class="state-column">
<AclStateButton :state="getState(OC.PERMISSION_READ, item.permissions, item.mask)"
<AclStateButton :state="getState(OC.PERMISSION_READ, item)"
:inherited="item.inherited"
:disabled="loading"
@update="changePermission(item, OC.PERMISSION_READ, $event)" />
</td>
<td class="state-column">
<AclStateButton :state="getState(OC.PERMISSION_UPDATE, item.permissions, item.mask)"
<AclStateButton :state="getState(OC.PERMISSION_UPDATE, item)"
:inherited="item.inherited"
:disabled="loading"
@update="changePermission(item, OC.PERMISSION_UPDATE, $event)" />
</td>
<td v-if="model.type === 'dir'" class="state-column">
<AclStateButton :state="getState(OC.PERMISSION_CREATE, item.permissions, item.mask)"
<AclStateButton :state="getState(OC.PERMISSION_CREATE, item)"
:inherited="item.inherited"
:disabled="loading"
@update="changePermission(item, OC.PERMISSION_CREATE, $event)" />
</td>
<td class="state-column">
<AclStateButton :state="getState(OC.PERMISSION_DELETE, item.permissions, item.mask)"
<AclStateButton :state="getState(OC.PERMISSION_DELETE, item)"
:inherited="item.inherited"
:disabled="loading"
@update="changePermission(item, OC.PERMISSION_DELETE, $event)" />
</td>
<td class="state-column">
<AclStateButton :state="getState(OC.PERMISSION_SHARE, item.permissions, item.mask)"
<AclStateButton :state="getState(OC.PERMISSION_SHARE, item)"
:inherited="item.inherited"
:disabled="loading"
@update="changePermission(item, OC.PERMISSION_SHARE, $event)" />
Expand Down Expand Up @@ -161,7 +161,7 @@
import Vue from 'vue'
import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
import AclStateButton from './AclStateButton.vue'
import AclStateButton, { STATES } from './AclStateButton.vue'
import Rule from './../model/Rule.js'
import BinaryTools from './../BinaryTools.js'
import client from './../client.js'
Expand Down Expand Up @@ -211,8 +211,8 @@ export default {
isAdmin() {
return this.aclCanManage
},
isInherited() {
return (permission, permissions, mask) => {
isNotInherited() {
return (permission, mask) => {
return (permission & ~mask) === 0
}
},
Expand All @@ -222,10 +222,18 @@ export default {
}
},
getState() {
return (permission, permissions, mask) => {
const inheritance = this.isInherited(permission, permissions, mask) << 1
const permitted = this.isAllowed(permission, permissions)
return inheritance | permitted
return (permission, item) => {
const permitted = this.isAllowed(permission, item.permissions)
if (this.isNotInherited(permission, item.mask)) {
return permitted ? STATES.SELF_ALLOW : STATES.SELF_DENY
} else {
const inheritPermitted = this.isAllowed(permission, item.inheritedPermissions)
if (this.isNotInherited(permission, item.inheritedMask)) {
return inheritPermitted ? STATES.INHERIT_ALLOW : STATES.INHERIT_DENY
} else {
return STATES.INHERIT_DEFAULT
}
}
}
},
},
Expand Down Expand Up @@ -330,13 +338,13 @@ export default {
},
changePermission(item, permission, $event) {
const index = this.list.indexOf(item)
const inherit = ($event < 2)
const allow = ($event & (0b01)) === 1
const inherit = $event === STATES.INHERIT_ALLOW || $event === STATES.INHERIT_DENY || $event === STATES.INHERIT_DEFAULT
const allow = $event === STATES.SELF_ALLOW
const bit = BinaryTools.firstHigh(permission)
item = item.clone()
if (inherit) {
item.mask = BinaryTools.clear(item.mask, bit)
// TODO check if: we can ignore permissions, since they are inherited
// we can ignore permissions, since they are inherited
} else {
item.mask = BinaryTools.set(item.mask, bit)
if (allow) {
Expand Down
2 changes: 2 additions & 0 deletions src/model/Rule.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export default class Rule {
this.mask = mask
this.permissions = permissions
this.inherited = inherited
this.inheritedMask = 0
this.inheritedPermissions = 31
}

getProperties() {
Expand Down

0 comments on commit f4b0341

Please sign in to comment.