PrincipalProxyTrait.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-License-Identifier: AGPL-3.0-or-later
  5. */
  6. namespace OCA\DAV\Traits;
  7. use OCA\DAV\CalDAV\Proxy\Proxy;
  8. use OCA\DAV\CalDAV\Proxy\ProxyMapper;
  9. use Sabre\DAV\Exception;
  10. /**
  11. * Trait PrincipalTrait
  12. *
  13. * @package OCA\DAV\Traits
  14. */
  15. trait PrincipalProxyTrait {
  16. /**
  17. * Returns the list of members for a group-principal
  18. *
  19. * @param string $principal
  20. * @return string[]
  21. * @throws Exception
  22. */
  23. public function getGroupMemberSet($principal) {
  24. $members = [];
  25. if ($this->isProxyPrincipal($principal)) {
  26. $realPrincipal = $this->getPrincipalUriFromProxyPrincipal($principal);
  27. $principalArray = $this->getPrincipalByPath($realPrincipal);
  28. if (!$principalArray) {
  29. throw new Exception('Principal not found');
  30. }
  31. $proxies = $this->proxyMapper->getProxiesOf($principalArray['uri']);
  32. foreach ($proxies as $proxy) {
  33. if ($this->isReadProxyPrincipal($principal) && $proxy->getPermissions() === ProxyMapper::PERMISSION_READ) {
  34. $members[] = $proxy->getProxyId();
  35. }
  36. if ($this->isWriteProxyPrincipal($principal) && $proxy->getPermissions() === (ProxyMapper::PERMISSION_READ | ProxyMapper::PERMISSION_WRITE)) {
  37. $members[] = $proxy->getProxyId();
  38. }
  39. }
  40. }
  41. return $members;
  42. }
  43. /**
  44. * Returns the list of groups a principal is a member of
  45. *
  46. * @param string $principal
  47. * @param bool $needGroups
  48. * @return array
  49. * @throws Exception
  50. */
  51. public function getGroupMembership($principal, $needGroups = false) {
  52. [$prefix, $name] = \Sabre\Uri\split($principal);
  53. if ($prefix !== $this->principalPrefix) {
  54. return [];
  55. }
  56. $principalArray = $this->getPrincipalByPath($principal);
  57. if (!$principalArray) {
  58. throw new Exception('Principal not found');
  59. }
  60. $groups = [];
  61. $proxies = $this->proxyMapper->getProxiesFor($principal);
  62. foreach ($proxies as $proxy) {
  63. if ($proxy->getPermissions() === ProxyMapper::PERMISSION_READ) {
  64. $groups[] = $proxy->getOwnerId() . '/calendar-proxy-read';
  65. }
  66. if ($proxy->getPermissions() === (ProxyMapper::PERMISSION_READ | ProxyMapper::PERMISSION_WRITE)) {
  67. $groups[] = $proxy->getOwnerId() . '/calendar-proxy-write';
  68. }
  69. }
  70. return $groups;
  71. }
  72. /**
  73. * Updates the list of group members for a group principal.
  74. *
  75. * The principals should be passed as a list of uri's.
  76. *
  77. * @param string $principal
  78. * @param string[] $members
  79. * @throws Exception
  80. */
  81. public function setGroupMemberSet($principal, array $members) {
  82. [$principalUri, $target] = \Sabre\Uri\split($principal);
  83. if ($target !== 'calendar-proxy-write' && $target !== 'calendar-proxy-read') {
  84. throw new Exception('Setting members of the group is not supported yet');
  85. }
  86. $masterPrincipalArray = $this->getPrincipalByPath($principalUri);
  87. if (!$masterPrincipalArray) {
  88. throw new Exception('Principal not found');
  89. }
  90. $permission = ProxyMapper::PERMISSION_READ;
  91. if ($target === 'calendar-proxy-write') {
  92. $permission |= ProxyMapper::PERMISSION_WRITE;
  93. }
  94. [$prefix, $owner] = \Sabre\Uri\split($principalUri);
  95. $proxies = $this->proxyMapper->getProxiesOf($principalUri);
  96. foreach ($members as $member) {
  97. [$prefix, $name] = \Sabre\Uri\split($member);
  98. if ($prefix !== $this->principalPrefix) {
  99. throw new Exception('Invalid member group prefix: ' . $prefix);
  100. }
  101. $principalArray = $this->getPrincipalByPath($member);
  102. if (!$principalArray) {
  103. throw new Exception('Principal not found');
  104. }
  105. $found = false;
  106. foreach ($proxies as $proxy) {
  107. if ($proxy->getProxyId() === $member) {
  108. $found = true;
  109. $proxy->setPermissions($proxy->getPermissions() | $permission);
  110. $this->proxyMapper->update($proxy);
  111. $proxies = array_filter($proxies, function (Proxy $p) use ($proxy) {
  112. return $p->getId() !== $proxy->getId();
  113. });
  114. break;
  115. }
  116. }
  117. if ($found === false) {
  118. $proxy = new Proxy();
  119. $proxy->setOwnerId($principalUri);
  120. $proxy->setProxyId($member);
  121. $proxy->setPermissions($permission);
  122. $this->proxyMapper->insert($proxy);
  123. }
  124. }
  125. // Delete all remaining proxies
  126. foreach ($proxies as $proxy) {
  127. // Write and Read Proxies have individual requests,
  128. // so only delete proxies of this permission
  129. if ($proxy->getPermissions() === $permission) {
  130. $this->proxyMapper->delete($proxy);
  131. }
  132. }
  133. }
  134. /**
  135. * @param string $principalUri
  136. * @return bool
  137. */
  138. private function isProxyPrincipal(string $principalUri):bool {
  139. [$realPrincipalUri, $proxy] = \Sabre\Uri\split($principalUri);
  140. [$prefix, $userId] = \Sabre\Uri\split($realPrincipalUri);
  141. if (!isset($prefix) || !isset($userId)) {
  142. return false;
  143. }
  144. if ($prefix !== $this->principalPrefix) {
  145. return false;
  146. }
  147. return $proxy === 'calendar-proxy-read'
  148. || $proxy === 'calendar-proxy-write';
  149. }
  150. /**
  151. * @param string $principalUri
  152. * @return bool
  153. */
  154. private function isReadProxyPrincipal(string $principalUri):bool {
  155. [, $proxy] = \Sabre\Uri\split($principalUri);
  156. return $proxy === 'calendar-proxy-read';
  157. }
  158. /**
  159. * @param string $principalUri
  160. * @return bool
  161. */
  162. private function isWriteProxyPrincipal(string $principalUri):bool {
  163. [, $proxy] = \Sabre\Uri\split($principalUri);
  164. return $proxy === 'calendar-proxy-write';
  165. }
  166. /**
  167. * @param string $principalUri
  168. * @return string
  169. */
  170. private function getPrincipalUriFromProxyPrincipal(string $principalUri):string {
  171. [$realPrincipalUri, ] = \Sabre\Uri\split($principalUri);
  172. return $realPrincipalUri;
  173. }
  174. }