Completed
Push — master ( 7b85da...a99c68 )
by
unknown
43:24
created
lib/private/Collaboration/Collaborators/RemotePlugin.php 2 patches
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -112,7 +112,7 @@  discard block
 block discarded – undo
112 112
 							$searchResult->markExactIdMatch($resultType);
113 113
 						}
114 114
 						$result['exact'][] = [
115
-							'label' => $contact['FN'] . " ($cloudId)",
115
+							'label' => $contact['FN']." ($cloudId)",
116 116
 							'uuid' => $contact['UID'],
117 117
 							'name' => $contact['FN'],
118 118
 							'type' => $cloudIdType,
@@ -124,7 +124,7 @@  discard block
 block discarded – undo
124 124
 						];
125 125
 					} else {
126 126
 						$result['wide'][] = [
127
-							'label' => $contact['FN'] . " ($cloudId)",
127
+							'label' => $contact['FN']." ($cloudId)",
128 128
 							'uuid' => $contact['UID'],
129 129
 							'name' => $contact['FN'],
130 130
 							'type' => $cloudIdType,
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
 				$localUser = $this->userManager->get($remoteUser);
155 155
 				if ($localUser === null || $search !== $localUser->getCloudId()) {
156 156
 					$result['exact'][] = [
157
-						'label' => $remoteUser . " ($serverUrl)",
157
+						'label' => $remoteUser." ($serverUrl)",
158 158
 						'uuid' => $remoteUser,
159 159
 						'name' => $remoteUser,
160 160
 						'value' => [
Please login to merge, or discard this patch.
Indentation   +135 added lines, -135 removed lines patch added patch discarded remove patch
@@ -16,150 +16,150 @@
 block discarded – undo
16 16
 use OCP\Share\IShare;
17 17
 
18 18
 class RemotePlugin implements ISearchPlugin {
19
-	protected bool $shareeEnumeration;
19
+    protected bool $shareeEnumeration;
20 20
 
21
-	private string $userId;
21
+    private string $userId;
22 22
 
23
-	public function __construct(
24
-		private IManager $contactsManager,
25
-		private ICloudIdManager $cloudIdManager,
26
-		private IConfig $config,
27
-		private IUserManager $userManager,
28
-		IUserSession $userSession,
29
-	) {
30
-		$this->userId = $userSession->getUser()?->getUID() ?? '';
31
-		$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
32
-	}
23
+    public function __construct(
24
+        private IManager $contactsManager,
25
+        private ICloudIdManager $cloudIdManager,
26
+        private IConfig $config,
27
+        private IUserManager $userManager,
28
+        IUserSession $userSession,
29
+    ) {
30
+        $this->userId = $userSession->getUser()?->getUID() ?? '';
31
+        $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
32
+    }
33 33
 
34
-	public function search($search, $limit, $offset, ISearchResult $searchResult): bool {
35
-		$result = ['wide' => [], 'exact' => []];
36
-		$resultType = new SearchResultType('remotes');
34
+    public function search($search, $limit, $offset, ISearchResult $searchResult): bool {
35
+        $result = ['wide' => [], 'exact' => []];
36
+        $resultType = new SearchResultType('remotes');
37 37
 
38
-		// Search in contacts
39
-		$addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN'], [
40
-			'limit' => $limit,
41
-			'offset' => $offset,
42
-			'enumeration' => false,
43
-			'fullmatch' => false,
44
-		]);
45
-		foreach ($addressBookContacts as $contact) {
46
-			if (isset($contact['isLocalSystemBook'])) {
47
-				continue;
48
-			}
49
-			if (isset($contact['CLOUD'])) {
50
-				$cloudIds = $contact['CLOUD'];
51
-				if (is_string($cloudIds)) {
52
-					$cloudIds = [$cloudIds];
53
-				}
54
-				$lowerSearch = strtolower($search);
55
-				foreach ($cloudIds as $cloudId) {
56
-					$cloudIdType = '';
57
-					if (\is_array($cloudId)) {
58
-						$cloudIdData = $cloudId;
59
-						$cloudId = $cloudIdData['value'];
60
-						$cloudIdType = $cloudIdData['type'];
61
-					}
62
-					try {
63
-						[$remoteUser, $serverUrl] = $this->splitUserRemote($cloudId);
64
-					} catch (\InvalidArgumentException $e) {
65
-						continue;
66
-					}
38
+        // Search in contacts
39
+        $addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN'], [
40
+            'limit' => $limit,
41
+            'offset' => $offset,
42
+            'enumeration' => false,
43
+            'fullmatch' => false,
44
+        ]);
45
+        foreach ($addressBookContacts as $contact) {
46
+            if (isset($contact['isLocalSystemBook'])) {
47
+                continue;
48
+            }
49
+            if (isset($contact['CLOUD'])) {
50
+                $cloudIds = $contact['CLOUD'];
51
+                if (is_string($cloudIds)) {
52
+                    $cloudIds = [$cloudIds];
53
+                }
54
+                $lowerSearch = strtolower($search);
55
+                foreach ($cloudIds as $cloudId) {
56
+                    $cloudIdType = '';
57
+                    if (\is_array($cloudId)) {
58
+                        $cloudIdData = $cloudId;
59
+                        $cloudId = $cloudIdData['value'];
60
+                        $cloudIdType = $cloudIdData['type'];
61
+                    }
62
+                    try {
63
+                        [$remoteUser, $serverUrl] = $this->splitUserRemote($cloudId);
64
+                    } catch (\InvalidArgumentException $e) {
65
+                        continue;
66
+                    }
67 67
 
68
-					$localUser = $this->userManager->get($remoteUser);
69
-					/**
70
-					 * Add local share if remote cloud id matches a local user ones
71
-					 */
72
-					if ($localUser !== null && $remoteUser !== $this->userId && $cloudId === $localUser->getCloudId()) {
73
-						$result['wide'][] = [
74
-							'label' => $contact['FN'],
75
-							'uuid' => $contact['UID'],
76
-							'value' => [
77
-								'shareType' => IShare::TYPE_USER,
78
-								'shareWith' => $remoteUser
79
-							],
80
-							'shareWithDisplayNameUnique' => $contact['EMAIL'] !== null && $contact['EMAIL'] !== '' ? $contact['EMAIL'] : $contact['UID'],
81
-						];
82
-					}
68
+                    $localUser = $this->userManager->get($remoteUser);
69
+                    /**
70
+                     * Add local share if remote cloud id matches a local user ones
71
+                     */
72
+                    if ($localUser !== null && $remoteUser !== $this->userId && $cloudId === $localUser->getCloudId()) {
73
+                        $result['wide'][] = [
74
+                            'label' => $contact['FN'],
75
+                            'uuid' => $contact['UID'],
76
+                            'value' => [
77
+                                'shareType' => IShare::TYPE_USER,
78
+                                'shareWith' => $remoteUser
79
+                            ],
80
+                            'shareWithDisplayNameUnique' => $contact['EMAIL'] !== null && $contact['EMAIL'] !== '' ? $contact['EMAIL'] : $contact['UID'],
81
+                        ];
82
+                    }
83 83
 
84
-					if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
85
-						if (strtolower($cloudId) === $lowerSearch) {
86
-							$searchResult->markExactIdMatch($resultType);
87
-						}
88
-						$result['exact'][] = [
89
-							'label' => $contact['FN'] . " ($cloudId)",
90
-							'uuid' => $contact['UID'],
91
-							'name' => $contact['FN'],
92
-							'type' => $cloudIdType,
93
-							'value' => [
94
-								'shareType' => IShare::TYPE_REMOTE,
95
-								'shareWith' => $cloudId,
96
-								'server' => $serverUrl,
97
-							],
98
-						];
99
-					} else {
100
-						$result['wide'][] = [
101
-							'label' => $contact['FN'] . " ($cloudId)",
102
-							'uuid' => $contact['UID'],
103
-							'name' => $contact['FN'],
104
-							'type' => $cloudIdType,
105
-							'value' => [
106
-								'shareType' => IShare::TYPE_REMOTE,
107
-								'shareWith' => $cloudId,
108
-								'server' => $serverUrl,
109
-							],
110
-						];
111
-					}
112
-				}
113
-			}
114
-		}
84
+                    if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
85
+                        if (strtolower($cloudId) === $lowerSearch) {
86
+                            $searchResult->markExactIdMatch($resultType);
87
+                        }
88
+                        $result['exact'][] = [
89
+                            'label' => $contact['FN'] . " ($cloudId)",
90
+                            'uuid' => $contact['UID'],
91
+                            'name' => $contact['FN'],
92
+                            'type' => $cloudIdType,
93
+                            'value' => [
94
+                                'shareType' => IShare::TYPE_REMOTE,
95
+                                'shareWith' => $cloudId,
96
+                                'server' => $serverUrl,
97
+                            ],
98
+                        ];
99
+                    } else {
100
+                        $result['wide'][] = [
101
+                            'label' => $contact['FN'] . " ($cloudId)",
102
+                            'uuid' => $contact['UID'],
103
+                            'name' => $contact['FN'],
104
+                            'type' => $cloudIdType,
105
+                            'value' => [
106
+                                'shareType' => IShare::TYPE_REMOTE,
107
+                                'shareWith' => $cloudId,
108
+                                'server' => $serverUrl,
109
+                            ],
110
+                        ];
111
+                    }
112
+                }
113
+            }
114
+        }
115 115
 
116
-		if (!$this->shareeEnumeration) {
117
-			$result['wide'] = [];
118
-		} else {
119
-			$result['wide'] = array_slice($result['wide'], $offset, $limit);
120
-		}
116
+        if (!$this->shareeEnumeration) {
117
+            $result['wide'] = [];
118
+        } else {
119
+            $result['wide'] = array_slice($result['wide'], $offset, $limit);
120
+        }
121 121
 
122
-		/**
123
-		 * Add generic share with remote item for valid cloud ids that are not users of the local instance
124
-		 */
125
-		if (!$searchResult->hasExactIdMatch($resultType) && $this->cloudIdManager->isValidCloudId($search) && $offset === 0) {
126
-			try {
127
-				[$remoteUser, $serverUrl] = $this->splitUserRemote($search);
128
-				$localUser = $this->userManager->get($remoteUser);
129
-				if ($localUser === null || $search !== $localUser->getCloudId()) {
130
-					$result['exact'][] = [
131
-						'label' => $remoteUser . " ($serverUrl)",
132
-						'uuid' => $remoteUser,
133
-						'name' => $remoteUser,
134
-						'value' => [
135
-							'shareType' => IShare::TYPE_REMOTE,
136
-							'shareWith' => $search,
137
-							'server' => $serverUrl,
138
-						],
139
-					];
140
-				}
141
-			} catch (\InvalidArgumentException $e) {
142
-			}
143
-		}
122
+        /**
123
+         * Add generic share with remote item for valid cloud ids that are not users of the local instance
124
+         */
125
+        if (!$searchResult->hasExactIdMatch($resultType) && $this->cloudIdManager->isValidCloudId($search) && $offset === 0) {
126
+            try {
127
+                [$remoteUser, $serverUrl] = $this->splitUserRemote($search);
128
+                $localUser = $this->userManager->get($remoteUser);
129
+                if ($localUser === null || $search !== $localUser->getCloudId()) {
130
+                    $result['exact'][] = [
131
+                        'label' => $remoteUser . " ($serverUrl)",
132
+                        'uuid' => $remoteUser,
133
+                        'name' => $remoteUser,
134
+                        'value' => [
135
+                            'shareType' => IShare::TYPE_REMOTE,
136
+                            'shareWith' => $search,
137
+                            'server' => $serverUrl,
138
+                        ],
139
+                    ];
140
+                }
141
+            } catch (\InvalidArgumentException $e) {
142
+            }
143
+        }
144 144
 
145
-		$searchResult->addResultSet($resultType, $result['wide'], $result['exact']);
145
+        $searchResult->addResultSet($resultType, $result['wide'], $result['exact']);
146 146
 
147
-		return true;
148
-	}
147
+        return true;
148
+    }
149 149
 
150
-	/**
151
-	 * split user and remote from federated cloud id
152
-	 *
153
-	 * @param string $address federated share address
154
-	 * @return array [user, remoteURL]
155
-	 * @throws \InvalidArgumentException
156
-	 */
157
-	public function splitUserRemote(string $address): array {
158
-		try {
159
-			$cloudId = $this->cloudIdManager->resolveCloudId($address);
160
-			return [$cloudId->getUser(), $this->cloudIdManager->removeProtocolFromUrl($cloudId->getRemote(), true)];
161
-		} catch (\InvalidArgumentException $e) {
162
-			throw new \InvalidArgumentException('Invalid Federated Cloud ID', 0, $e);
163
-		}
164
-	}
150
+    /**
151
+     * split user and remote from federated cloud id
152
+     *
153
+     * @param string $address federated share address
154
+     * @return array [user, remoteURL]
155
+     * @throws \InvalidArgumentException
156
+     */
157
+    public function splitUserRemote(string $address): array {
158
+        try {
159
+            $cloudId = $this->cloudIdManager->resolveCloudId($address);
160
+            return [$cloudId->getUser(), $this->cloudIdManager->removeProtocolFromUrl($cloudId->getRemote(), true)];
161
+        } catch (\InvalidArgumentException $e) {
162
+            throw new \InvalidArgumentException('Invalid Federated Cloud ID', 0, $e);
163
+        }
164
+    }
165 165
 }
Please login to merge, or discard this patch.
lib/private/Color.php 1 patch
Indentation   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -24,12 +24,12 @@
 block discarded – undo
24 24
 namespace OC;
25 25
 
26 26
 class Color {
27
-	public $r;
28
-	public $g;
29
-	public $b;
30
-	public function __construct($r, $g, $b) {
31
-		$this->r = $r;
32
-		$this->g = $g;
33
-		$this->b = $b;
34
-	}
27
+    public $r;
28
+    public $g;
29
+    public $b;
30
+    public function __construct($r, $g, $b) {
31
+        $this->r = $r;
32
+        $this->g = $g;
33
+        $this->b = $b;
34
+    }
35 35
 }
Please login to merge, or discard this patch.
lib/private/Lock/MemcacheLockingProvider.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -143,7 +143,7 @@
 block discarded – undo
143 143
 		} elseif ($existing === 'exclusive') {
144 144
 			return $existing;
145 145
 		} else {
146
-			return $existing . ' shared locks';
146
+			return $existing.' shared locks';
147 147
 		}
148 148
 	}
149 149
 }
Please login to merge, or discard this patch.
Indentation   +164 added lines, -164 removed lines patch added patch discarded remove patch
@@ -14,168 +14,168 @@
 block discarded – undo
14 14
 use OCP\Lock\LockedException;
15 15
 
16 16
 class MemcacheLockingProvider extends AbstractLockingProvider {
17
-	/** @var array<string, array{time: int, ttl: int}> */
18
-	private array $oldTTLs = [];
19
-
20
-	public function __construct(
21
-		private IMemcache $memcache,
22
-		private ITimeFactory $timeFactory,
23
-		int $ttl = 3600,
24
-	) {
25
-		parent::__construct($ttl);
26
-	}
27
-
28
-	private function setTTL(string $path, ?int $ttl = null, mixed $compare = null): void {
29
-		if (is_null($ttl)) {
30
-			$ttl = $this->ttl;
31
-		}
32
-		if ($this->memcache instanceof IMemcacheTTL) {
33
-			if ($compare !== null) {
34
-				$this->memcache->compareSetTTL($path, $compare, $ttl);
35
-			} else {
36
-				$this->memcache->setTTL($path, $ttl);
37
-			}
38
-		}
39
-	}
40
-
41
-	private function getTTL(string $path): int {
42
-		if ($this->memcache instanceof IMemcacheTTL) {
43
-			$ttl = $this->memcache->getTTL($path);
44
-			return $ttl === false ? -1 : $ttl;
45
-		} else {
46
-			return -1;
47
-		}
48
-	}
49
-
50
-	public function isLocked(string $path, int $type): bool {
51
-		$lockValue = $this->memcache->get($path);
52
-		if ($type === self::LOCK_SHARED) {
53
-			return is_int($lockValue) && $lockValue > 0;
54
-		} elseif ($type === self::LOCK_EXCLUSIVE) {
55
-			return $lockValue === 'exclusive';
56
-		} else {
57
-			return false;
58
-		}
59
-	}
60
-
61
-	public function acquireLock(string $path, int $type, ?string $readablePath = null): void {
62
-		if ($type === self::LOCK_SHARED) {
63
-			// save the old TTL to for `restoreTTL`
64
-			$this->oldTTLs[$path] = [
65
-				'ttl' => $this->getTTL($path),
66
-				'time' => $this->timeFactory->getTime()
67
-			];
68
-			if (!$this->memcache->inc($path)) {
69
-				throw new LockedException($path, null, $this->getExistingLockForException($path), $readablePath);
70
-			}
71
-		} else {
72
-			// when getting exclusive locks, we know there are no old TTLs to restore
73
-			$this->memcache->add($path, 0);
74
-			// ttl is updated automatically when the `set` succeeds
75
-			if (!$this->memcache->cas($path, 0, 'exclusive')) {
76
-				throw new LockedException($path, null, $this->getExistingLockForException($path), $readablePath);
77
-			}
78
-			unset($this->oldTTLs[$path]);
79
-		}
80
-		$this->setTTL($path);
81
-		$this->markAcquire($path, $type);
82
-	}
83
-
84
-	public function releaseLock(string $path, int $type): void {
85
-		if ($type === self::LOCK_SHARED) {
86
-			$ownSharedLockCount = $this->getOwnSharedLockCount($path);
87
-			$newValue = 0;
88
-			if ($ownSharedLockCount === 0) { // if we are not holding the lock, don't try to release it
89
-				return;
90
-			}
91
-			if ($ownSharedLockCount === 1) {
92
-				$removed = $this->memcache->cad($path, 1); // if we're the only one having a shared lock we can remove it in one go
93
-				if (!$removed) { //someone else also has a shared lock, decrease only
94
-					$newValue = $this->memcache->dec($path);
95
-				}
96
-			} else {
97
-				// if we own more than one lock ourselves just decrease
98
-				$newValue = $this->memcache->dec($path);
99
-			}
100
-
101
-			if ($newValue > 0) {
102
-				$this->restoreTTL($path);
103
-			} else {
104
-				unset($this->oldTTLs[$path]);
105
-			}
106
-
107
-			// if we somehow release more locks then exists, reset the lock
108
-			if ($newValue < 0) {
109
-				$this->memcache->cad($path, $newValue);
110
-			}
111
-		} elseif ($type === self::LOCK_EXCLUSIVE) {
112
-			$this->memcache->cad($path, 'exclusive');
113
-		}
114
-		$this->markRelease($path, $type);
115
-	}
116
-
117
-	public function changeLock(string $path, int $targetType): void {
118
-		if ($targetType === self::LOCK_SHARED) {
119
-			if (!$this->memcache->cas($path, 'exclusive', 1)) {
120
-				throw new LockedException($path, null, $this->getExistingLockForException($path));
121
-			}
122
-		} elseif ($targetType === self::LOCK_EXCLUSIVE) {
123
-			// we can only change a shared lock to an exclusive if there's only a single owner of the shared lock
124
-			if (!$this->memcache->cas($path, 1, 'exclusive')) {
125
-				$this->restoreTTL($path);
126
-				throw new LockedException($path, null, $this->getExistingLockForException($path));
127
-			}
128
-			unset($this->oldTTLs[$path]);
129
-		}
130
-		$this->setTTL($path);
131
-		$this->markChange($path, $targetType);
132
-	}
133
-
134
-	/**
135
-	 * With shared locks, each time the lock is acquired, the ttl for the path is reset.
136
-	 *
137
-	 * Due to this "ttl extension" when a shared lock isn't freed correctly for any reason
138
-	 * the lock won't expire until no shared locks are required for the path for 1h.
139
-	 * This can lead to a client repeatedly trying to upload a file, and failing forever
140
-	 * because the lock never gets the opportunity to expire.
141
-	 *
142
-	 * To help the lock expire in this case, we lower the TTL back to what it was before we
143
-	 * took the shared lock *only* if nobody else got a shared lock after we did.
144
-	 *
145
-	 * This doesn't handle all cases where multiple requests are acquiring shared locks
146
-	 * but it should handle some of the more common ones and not hurt things further
147
-	 */
148
-	private function restoreTTL(string $path): void {
149
-		if (isset($this->oldTTLs[$path])) {
150
-			$saved = $this->oldTTLs[$path];
151
-			$elapsed = $this->timeFactory->getTime() - $saved['time'];
152
-
153
-			// old value to compare to when setting ttl in case someone else changes the lock in the middle of this function
154
-			$value = $this->memcache->get($path);
155
-
156
-			$currentTtl = $this->getTTL($path);
157
-
158
-			// what the old ttl would be given the time elapsed since we acquired the lock
159
-			// note that if this gets negative the key will be expired directly when we set the ttl
160
-			$remainingOldTtl = $saved['ttl'] - $elapsed;
161
-			// what the currently ttl would be if nobody else acquired a lock since we did (+1 to cover rounding errors)
162
-			$expectedTtl = $this->ttl - $elapsed + 1;
163
-
164
-			// check if another request has acquired a lock (and didn't release it yet)
165
-			if ($currentTtl <= $expectedTtl) {
166
-				$this->setTTL($path, $remainingOldTtl, $value);
167
-			}
168
-		}
169
-	}
170
-
171
-	private function getExistingLockForException(string $path): string {
172
-		$existing = $this->memcache->get($path);
173
-		if (!$existing) {
174
-			return 'none';
175
-		} elseif ($existing === 'exclusive') {
176
-			return $existing;
177
-		} else {
178
-			return $existing . ' shared locks';
179
-		}
180
-	}
17
+    /** @var array<string, array{time: int, ttl: int}> */
18
+    private array $oldTTLs = [];
19
+
20
+    public function __construct(
21
+        private IMemcache $memcache,
22
+        private ITimeFactory $timeFactory,
23
+        int $ttl = 3600,
24
+    ) {
25
+        parent::__construct($ttl);
26
+    }
27
+
28
+    private function setTTL(string $path, ?int $ttl = null, mixed $compare = null): void {
29
+        if (is_null($ttl)) {
30
+            $ttl = $this->ttl;
31
+        }
32
+        if ($this->memcache instanceof IMemcacheTTL) {
33
+            if ($compare !== null) {
34
+                $this->memcache->compareSetTTL($path, $compare, $ttl);
35
+            } else {
36
+                $this->memcache->setTTL($path, $ttl);
37
+            }
38
+        }
39
+    }
40
+
41
+    private function getTTL(string $path): int {
42
+        if ($this->memcache instanceof IMemcacheTTL) {
43
+            $ttl = $this->memcache->getTTL($path);
44
+            return $ttl === false ? -1 : $ttl;
45
+        } else {
46
+            return -1;
47
+        }
48
+    }
49
+
50
+    public function isLocked(string $path, int $type): bool {
51
+        $lockValue = $this->memcache->get($path);
52
+        if ($type === self::LOCK_SHARED) {
53
+            return is_int($lockValue) && $lockValue > 0;
54
+        } elseif ($type === self::LOCK_EXCLUSIVE) {
55
+            return $lockValue === 'exclusive';
56
+        } else {
57
+            return false;
58
+        }
59
+    }
60
+
61
+    public function acquireLock(string $path, int $type, ?string $readablePath = null): void {
62
+        if ($type === self::LOCK_SHARED) {
63
+            // save the old TTL to for `restoreTTL`
64
+            $this->oldTTLs[$path] = [
65
+                'ttl' => $this->getTTL($path),
66
+                'time' => $this->timeFactory->getTime()
67
+            ];
68
+            if (!$this->memcache->inc($path)) {
69
+                throw new LockedException($path, null, $this->getExistingLockForException($path), $readablePath);
70
+            }
71
+        } else {
72
+            // when getting exclusive locks, we know there are no old TTLs to restore
73
+            $this->memcache->add($path, 0);
74
+            // ttl is updated automatically when the `set` succeeds
75
+            if (!$this->memcache->cas($path, 0, 'exclusive')) {
76
+                throw new LockedException($path, null, $this->getExistingLockForException($path), $readablePath);
77
+            }
78
+            unset($this->oldTTLs[$path]);
79
+        }
80
+        $this->setTTL($path);
81
+        $this->markAcquire($path, $type);
82
+    }
83
+
84
+    public function releaseLock(string $path, int $type): void {
85
+        if ($type === self::LOCK_SHARED) {
86
+            $ownSharedLockCount = $this->getOwnSharedLockCount($path);
87
+            $newValue = 0;
88
+            if ($ownSharedLockCount === 0) { // if we are not holding the lock, don't try to release it
89
+                return;
90
+            }
91
+            if ($ownSharedLockCount === 1) {
92
+                $removed = $this->memcache->cad($path, 1); // if we're the only one having a shared lock we can remove it in one go
93
+                if (!$removed) { //someone else also has a shared lock, decrease only
94
+                    $newValue = $this->memcache->dec($path);
95
+                }
96
+            } else {
97
+                // if we own more than one lock ourselves just decrease
98
+                $newValue = $this->memcache->dec($path);
99
+            }
100
+
101
+            if ($newValue > 0) {
102
+                $this->restoreTTL($path);
103
+            } else {
104
+                unset($this->oldTTLs[$path]);
105
+            }
106
+
107
+            // if we somehow release more locks then exists, reset the lock
108
+            if ($newValue < 0) {
109
+                $this->memcache->cad($path, $newValue);
110
+            }
111
+        } elseif ($type === self::LOCK_EXCLUSIVE) {
112
+            $this->memcache->cad($path, 'exclusive');
113
+        }
114
+        $this->markRelease($path, $type);
115
+    }
116
+
117
+    public function changeLock(string $path, int $targetType): void {
118
+        if ($targetType === self::LOCK_SHARED) {
119
+            if (!$this->memcache->cas($path, 'exclusive', 1)) {
120
+                throw new LockedException($path, null, $this->getExistingLockForException($path));
121
+            }
122
+        } elseif ($targetType === self::LOCK_EXCLUSIVE) {
123
+            // we can only change a shared lock to an exclusive if there's only a single owner of the shared lock
124
+            if (!$this->memcache->cas($path, 1, 'exclusive')) {
125
+                $this->restoreTTL($path);
126
+                throw new LockedException($path, null, $this->getExistingLockForException($path));
127
+            }
128
+            unset($this->oldTTLs[$path]);
129
+        }
130
+        $this->setTTL($path);
131
+        $this->markChange($path, $targetType);
132
+    }
133
+
134
+    /**
135
+     * With shared locks, each time the lock is acquired, the ttl for the path is reset.
136
+     *
137
+     * Due to this "ttl extension" when a shared lock isn't freed correctly for any reason
138
+     * the lock won't expire until no shared locks are required for the path for 1h.
139
+     * This can lead to a client repeatedly trying to upload a file, and failing forever
140
+     * because the lock never gets the opportunity to expire.
141
+     *
142
+     * To help the lock expire in this case, we lower the TTL back to what it was before we
143
+     * took the shared lock *only* if nobody else got a shared lock after we did.
144
+     *
145
+     * This doesn't handle all cases where multiple requests are acquiring shared locks
146
+     * but it should handle some of the more common ones and not hurt things further
147
+     */
148
+    private function restoreTTL(string $path): void {
149
+        if (isset($this->oldTTLs[$path])) {
150
+            $saved = $this->oldTTLs[$path];
151
+            $elapsed = $this->timeFactory->getTime() - $saved['time'];
152
+
153
+            // old value to compare to when setting ttl in case someone else changes the lock in the middle of this function
154
+            $value = $this->memcache->get($path);
155
+
156
+            $currentTtl = $this->getTTL($path);
157
+
158
+            // what the old ttl would be given the time elapsed since we acquired the lock
159
+            // note that if this gets negative the key will be expired directly when we set the ttl
160
+            $remainingOldTtl = $saved['ttl'] - $elapsed;
161
+            // what the currently ttl would be if nobody else acquired a lock since we did (+1 to cover rounding errors)
162
+            $expectedTtl = $this->ttl - $elapsed + 1;
163
+
164
+            // check if another request has acquired a lock (and didn't release it yet)
165
+            if ($currentTtl <= $expectedTtl) {
166
+                $this->setTTL($path, $remainingOldTtl, $value);
167
+            }
168
+        }
169
+    }
170
+
171
+    private function getExistingLockForException(string $path): string {
172
+        $existing = $this->memcache->get($path);
173
+        if (!$existing) {
174
+            return 'none';
175
+        } elseif ($existing === 'exclusive') {
176
+            return $existing;
177
+        } else {
178
+            return $existing . ' shared locks';
179
+        }
180
+    }
181 181
 }
Please login to merge, or discard this patch.
lib/public/Collaboration/Collaborators/SearchResultType.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -59,7 +59,7 @@
 block discarded – undo
59 59
 	 * @since 13.0.0
60 60
 	 */
61 61
 	protected function getValidatedType($type) {
62
-		$type = trim((string)$type);
62
+		$type = trim((string) $type);
63 63
 
64 64
 		if ($type === '') {
65 65
 			throw new \InvalidArgumentException('Type must not be empty');
Please login to merge, or discard this patch.
Indentation   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -12,44 +12,44 @@
 block discarded – undo
12 12
  * @since 13.0.0
13 13
  */
14 14
 class SearchResultType {
15
-	/** @var string */
16
-	protected $label;
17
-
18
-	/**
19
-	 * SearchResultType constructor.
20
-	 *
21
-	 * @param string $label
22
-	 * @since 13.0.0
23
-	 */
24
-	public function __construct($label) {
25
-		$this->label = $this->getValidatedType($label);
26
-	}
27
-
28
-	/**
29
-	 * @return string
30
-	 * @since 13.0.0
31
-	 */
32
-	public function getLabel() {
33
-		return $this->label;
34
-	}
35
-
36
-	/**
37
-	 * @param $type
38
-	 * @return string
39
-	 * @throws \InvalidArgumentException
40
-	 * @since 13.0.0
41
-	 */
42
-	protected function getValidatedType($type) {
43
-		$type = trim((string)$type);
44
-
45
-		if ($type === '') {
46
-			throw new \InvalidArgumentException('Type must not be empty');
47
-		}
48
-
49
-		if ($type === 'exact') {
50
-			throw new \InvalidArgumentException('Provided type is a reserved word');
51
-		}
52
-
53
-		return $type;
54
-	}
15
+    /** @var string */
16
+    protected $label;
17
+
18
+    /**
19
+     * SearchResultType constructor.
20
+     *
21
+     * @param string $label
22
+     * @since 13.0.0
23
+     */
24
+    public function __construct($label) {
25
+        $this->label = $this->getValidatedType($label);
26
+    }
27
+
28
+    /**
29
+     * @return string
30
+     * @since 13.0.0
31
+     */
32
+    public function getLabel() {
33
+        return $this->label;
34
+    }
35
+
36
+    /**
37
+     * @param $type
38
+     * @return string
39
+     * @throws \InvalidArgumentException
40
+     * @since 13.0.0
41
+     */
42
+    protected function getValidatedType($type) {
43
+        $type = trim((string)$type);
44
+
45
+        if ($type === '') {
46
+            throw new \InvalidArgumentException('Type must not be empty');
47
+        }
48
+
49
+        if ($type === 'exact') {
50
+            throw new \InvalidArgumentException('Provided type is a reserved word');
51
+        }
52
+
53
+        return $type;
54
+    }
55 55
 }
Please login to merge, or discard this patch.
lib/private/IntegrityCheck/Helpers/FileAccessHelper.php 2 patches
Indentation   +49 added lines, -49 removed lines patch added patch discarded remove patch
@@ -34,57 +34,57 @@
 block discarded – undo
34 34
  * @package OC\IntegrityCheck\Helpers
35 35
  */
36 36
 class FileAccessHelper {
37
-	/**
38
-	 * Wrapper around file_get_contents($filename, $data)
39
-	 *
40
-	 * @param string $filename
41
-	 * @return string|false
42
-	 */
43
-	public function file_get_contents(string $filename) {
44
-		return file_get_contents($filename);
45
-	}
37
+    /**
38
+     * Wrapper around file_get_contents($filename, $data)
39
+     *
40
+     * @param string $filename
41
+     * @return string|false
42
+     */
43
+    public function file_get_contents(string $filename) {
44
+        return file_get_contents($filename);
45
+    }
46 46
 
47
-	/**
48
-	 * Wrapper around file_exists($filename)
49
-	 *
50
-	 * @param string $filename
51
-	 * @return bool
52
-	 */
53
-	public function file_exists(string $filename): bool {
54
-		return file_exists($filename);
55
-	}
47
+    /**
48
+     * Wrapper around file_exists($filename)
49
+     *
50
+     * @param string $filename
51
+     * @return bool
52
+     */
53
+    public function file_exists(string $filename): bool {
54
+        return file_exists($filename);
55
+    }
56 56
 
57
-	/**
58
-	 * Wrapper around file_put_contents($filename, $data)
59
-	 *
60
-	 * @param string $filename
61
-	 * @param string $data
62
-	 * @return int
63
-	 * @throws \Exception
64
-	 */
65
-	public function file_put_contents(string $filename, string $data): int {
66
-		$bytesWritten = @file_put_contents($filename, $data);
67
-		if ($bytesWritten === false || $bytesWritten !== \strlen($data)) {
68
-			throw new \Exception('Failed to write into ' . $filename);
69
-		}
70
-		return $bytesWritten;
71
-	}
57
+    /**
58
+     * Wrapper around file_put_contents($filename, $data)
59
+     *
60
+     * @param string $filename
61
+     * @param string $data
62
+     * @return int
63
+     * @throws \Exception
64
+     */
65
+    public function file_put_contents(string $filename, string $data): int {
66
+        $bytesWritten = @file_put_contents($filename, $data);
67
+        if ($bytesWritten === false || $bytesWritten !== \strlen($data)) {
68
+            throw new \Exception('Failed to write into ' . $filename);
69
+        }
70
+        return $bytesWritten;
71
+    }
72 72
 
73
-	/**
74
-	 * @param string $path
75
-	 * @return bool
76
-	 */
77
-	public function is_writable(string $path): bool {
78
-		return is_writable($path);
79
-	}
73
+    /**
74
+     * @param string $path
75
+     * @return bool
76
+     */
77
+    public function is_writable(string $path): bool {
78
+        return is_writable($path);
79
+    }
80 80
 
81
-	/**
82
-	 * @param string $path
83
-	 * @throws \Exception
84
-	 */
85
-	public function assertDirectoryExists(string $path) {
86
-		if (!is_dir($path)) {
87
-			throw new \Exception('Directory ' . $path . ' does not exist.');
88
-		}
89
-	}
81
+    /**
82
+     * @param string $path
83
+     * @throws \Exception
84
+     */
85
+    public function assertDirectoryExists(string $path) {
86
+        if (!is_dir($path)) {
87
+            throw new \Exception('Directory ' . $path . ' does not exist.');
88
+        }
89
+    }
90 90
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -65,7 +65,7 @@  discard block
 block discarded – undo
65 65
 	public function file_put_contents(string $filename, string $data): int {
66 66
 		$bytesWritten = @file_put_contents($filename, $data);
67 67
 		if ($bytesWritten === false || $bytesWritten !== \strlen($data)) {
68
-			throw new \Exception('Failed to write into ' . $filename);
68
+			throw new \Exception('Failed to write into '.$filename);
69 69
 		}
70 70
 		return $bytesWritten;
71 71
 	}
@@ -84,7 +84,7 @@  discard block
 block discarded – undo
84 84
 	 */
85 85
 	public function assertDirectoryExists(string $path) {
86 86
 		if (!is_dir($path)) {
87
-			throw new \Exception('Directory ' . $path . ' does not exist.');
87
+			throw new \Exception('Directory '.$path.' does not exist.');
88 88
 		}
89 89
 	}
90 90
 }
Please login to merge, or discard this patch.
lib/private/Federation/CloudFederationNotification.php 1 patch
Indentation   +29 added lines, -29 removed lines patch added patch discarded remove patch
@@ -33,35 +33,35 @@
 block discarded – undo
33 33
  * @since 14.0.0
34 34
  */
35 35
 class CloudFederationNotification implements ICloudFederationNotification {
36
-	private $message = [];
36
+    private $message = [];
37 37
 
38
-	/**
39
-	 * add a message to the notification
40
-	 *
41
-	 * @param string $notificationType (e.g. SHARE_ACCEPTED)
42
-	 * @param string $resourceType (e.g. file, calendar, contact,...)
43
-	 * @param string $providerId id of the share
44
-	 * @param array $notification payload of the notification
45
-	 *
46
-	 * @since 14.0.0
47
-	 */
48
-	public function setMessage($notificationType, $resourceType, $providerId, array $notification) {
49
-		$this->message = [
50
-			'notificationType' => $notificationType,
51
-			'resourceType' => $resourceType,
52
-			'providerId' => $providerId,
53
-			'notification' => $notification,
54
-		];
55
-	}
38
+    /**
39
+     * add a message to the notification
40
+     *
41
+     * @param string $notificationType (e.g. SHARE_ACCEPTED)
42
+     * @param string $resourceType (e.g. file, calendar, contact,...)
43
+     * @param string $providerId id of the share
44
+     * @param array $notification payload of the notification
45
+     *
46
+     * @since 14.0.0
47
+     */
48
+    public function setMessage($notificationType, $resourceType, $providerId, array $notification) {
49
+        $this->message = [
50
+            'notificationType' => $notificationType,
51
+            'resourceType' => $resourceType,
52
+            'providerId' => $providerId,
53
+            'notification' => $notification,
54
+        ];
55
+    }
56 56
 
57
-	/**
58
-	 * get message, ready to send out
59
-	 *
60
-	 * @return array
61
-	 *
62
-	 * @since 14.0.0
63
-	 */
64
-	public function getMessage() {
65
-		return $this->message;
66
-	}
57
+    /**
58
+     * get message, ready to send out
59
+     *
60
+     * @return array
61
+     *
62
+     * @since 14.0.0
63
+     */
64
+    public function getMessage() {
65
+        return $this->message;
66
+    }
67 67
 }
Please login to merge, or discard this patch.
lib/private/Security/FeaturePolicy/FeaturePolicy.php 1 patch
Indentation   +36 added lines, -36 removed lines patch added patch discarded remove patch
@@ -27,51 +27,51 @@
 block discarded – undo
27 27
 namespace OC\Security\FeaturePolicy;
28 28
 
29 29
 class FeaturePolicy extends \OCP\AppFramework\Http\FeaturePolicy {
30
-	public function getAutoplayDomains(): array {
31
-		return $this->autoplayDomains;
32
-	}
30
+    public function getAutoplayDomains(): array {
31
+        return $this->autoplayDomains;
32
+    }
33 33
 
34
-	public function setAutoplayDomains(array $autoplayDomains): void {
35
-		$this->autoplayDomains = $autoplayDomains;
36
-	}
34
+    public function setAutoplayDomains(array $autoplayDomains): void {
35
+        $this->autoplayDomains = $autoplayDomains;
36
+    }
37 37
 
38
-	public function getCameraDomains(): array {
39
-		return $this->cameraDomains;
40
-	}
38
+    public function getCameraDomains(): array {
39
+        return $this->cameraDomains;
40
+    }
41 41
 
42
-	public function setCameraDomains(array $cameraDomains): void {
43
-		$this->cameraDomains = $cameraDomains;
44
-	}
42
+    public function setCameraDomains(array $cameraDomains): void {
43
+        $this->cameraDomains = $cameraDomains;
44
+    }
45 45
 
46
-	public function getFullscreenDomains(): array {
47
-		return $this->fullscreenDomains;
48
-	}
46
+    public function getFullscreenDomains(): array {
47
+        return $this->fullscreenDomains;
48
+    }
49 49
 
50
-	public function setFullscreenDomains(array $fullscreenDomains): void {
51
-		$this->fullscreenDomains = $fullscreenDomains;
52
-	}
50
+    public function setFullscreenDomains(array $fullscreenDomains): void {
51
+        $this->fullscreenDomains = $fullscreenDomains;
52
+    }
53 53
 
54
-	public function getGeolocationDomains(): array {
55
-		return $this->geolocationDomains;
56
-	}
54
+    public function getGeolocationDomains(): array {
55
+        return $this->geolocationDomains;
56
+    }
57 57
 
58
-	public function setGeolocationDomains(array $geolocationDomains): void {
59
-		$this->geolocationDomains = $geolocationDomains;
60
-	}
58
+    public function setGeolocationDomains(array $geolocationDomains): void {
59
+        $this->geolocationDomains = $geolocationDomains;
60
+    }
61 61
 
62
-	public function getMicrophoneDomains(): array {
63
-		return $this->microphoneDomains;
64
-	}
62
+    public function getMicrophoneDomains(): array {
63
+        return $this->microphoneDomains;
64
+    }
65 65
 
66
-	public function setMicrophoneDomains(array $microphoneDomains): void {
67
-		$this->microphoneDomains = $microphoneDomains;
68
-	}
66
+    public function setMicrophoneDomains(array $microphoneDomains): void {
67
+        $this->microphoneDomains = $microphoneDomains;
68
+    }
69 69
 
70
-	public function getPaymentDomains(): array {
71
-		return $this->paymentDomains;
72
-	}
70
+    public function getPaymentDomains(): array {
71
+        return $this->paymentDomains;
72
+    }
73 73
 
74
-	public function setPaymentDomains(array $paymentDomains): void {
75
-		$this->paymentDomains = $paymentDomains;
76
-	}
74
+    public function setPaymentDomains(array $paymentDomains): void {
75
+        $this->paymentDomains = $paymentDomains;
76
+    }
77 77
 }
Please login to merge, or discard this patch.
lib/private/Security/CSRF/CsrfToken.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -57,7 +57,7 @@
 block discarded – undo
57 57
 	public function getEncryptedValue(): string {
58 58
 		if ($this->encryptedValue === '') {
59 59
 			$sharedSecret = random_bytes(\strlen($this->value));
60
-			$this->encryptedValue = base64_encode($this->value ^ $sharedSecret) . ':' . base64_encode($sharedSecret);
60
+			$this->encryptedValue = base64_encode($this->value ^ $sharedSecret).':'.base64_encode($sharedSecret);
61 61
 		}
62 62
 
63 63
 		return $this->encryptedValue;
Please login to merge, or discard this patch.
Indentation   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -17,40 +17,40 @@
 block discarded – undo
17 17
  * @package OC\Security\CSRF
18 18
  */
19 19
 class CsrfToken {
20
-	private string $encryptedValue = '';
20
+    private string $encryptedValue = '';
21 21
 
22
-	/**
23
-	 * @param string $value Value of the token. Can be encrypted or not encrypted.
24
-	 */
25
-	public function __construct(
26
-		private string $value,
27
-	) {
28
-	}
22
+    /**
23
+     * @param string $value Value of the token. Can be encrypted or not encrypted.
24
+     */
25
+    public function __construct(
26
+        private string $value,
27
+    ) {
28
+    }
29 29
 
30
-	/**
31
-	 * Encrypted value of the token. This is used to mitigate BREACH alike
32
-	 * vulnerabilities. For display measures do use this functionality.
33
-	 */
34
-	public function getEncryptedValue(): string {
35
-		if ($this->encryptedValue === '') {
36
-			$sharedSecret = random_bytes(\strlen($this->value));
37
-			$this->encryptedValue = base64_encode($this->value ^ $sharedSecret) . ':' . base64_encode($sharedSecret);
38
-		}
30
+    /**
31
+     * Encrypted value of the token. This is used to mitigate BREACH alike
32
+     * vulnerabilities. For display measures do use this functionality.
33
+     */
34
+    public function getEncryptedValue(): string {
35
+        if ($this->encryptedValue === '') {
36
+            $sharedSecret = random_bytes(\strlen($this->value));
37
+            $this->encryptedValue = base64_encode($this->value ^ $sharedSecret) . ':' . base64_encode($sharedSecret);
38
+        }
39 39
 
40
-		return $this->encryptedValue;
41
-	}
40
+        return $this->encryptedValue;
41
+    }
42 42
 
43
-	/**
44
-	 * The unencrypted value of the token. Used for decrypting an already
45
-	 * encrypted token.
46
-	 */
47
-	public function getDecryptedValue(): string {
48
-		$token = explode(':', $this->value);
49
-		if (\count($token) !== 2) {
50
-			return '';
51
-		}
52
-		$obfuscatedToken = $token[0];
53
-		$secret = $token[1];
54
-		return base64_decode($obfuscatedToken) ^ base64_decode($secret);
55
-	}
43
+    /**
44
+     * The unencrypted value of the token. Used for decrypting an already
45
+     * encrypted token.
46
+     */
47
+    public function getDecryptedValue(): string {
48
+        $token = explode(':', $this->value);
49
+        if (\count($token) !== 2) {
50
+            return '';
51
+        }
52
+        $obfuscatedToken = $token[0];
53
+        $secret = $token[1];
54
+        return base64_decode($obfuscatedToken) ^ base64_decode($secret);
55
+    }
56 56
 }
Please login to merge, or discard this patch.
lib/private/Command/QueueBus.php 1 patch
Indentation   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -27,48 +27,48 @@
 block discarded – undo
27 27
 use OCP\Command\ICommand;
28 28
 
29 29
 class QueueBus implements IBus {
30
-	/**
31
-	 * @var ICommand[]|callable[]
32
-	 */
33
-	private $queue = [];
30
+    /**
31
+     * @var ICommand[]|callable[]
32
+     */
33
+    private $queue = [];
34 34
 
35
-	/**
36
-	 * Schedule a command to be fired
37
-	 *
38
-	 * @param \OCP\Command\ICommand | callable $command
39
-	 */
40
-	public function push($command) {
41
-		$this->queue[] = $command;
42
-	}
35
+    /**
36
+     * Schedule a command to be fired
37
+     *
38
+     * @param \OCP\Command\ICommand | callable $command
39
+     */
40
+    public function push($command) {
41
+        $this->queue[] = $command;
42
+    }
43 43
 
44
-	/**
45
-	 * Require all commands using a trait to be run synchronous
46
-	 *
47
-	 * @param string $trait
48
-	 */
49
-	public function requireSync($trait) {
50
-	}
44
+    /**
45
+     * Require all commands using a trait to be run synchronous
46
+     *
47
+     * @param string $trait
48
+     */
49
+    public function requireSync($trait) {
50
+    }
51 51
 
52
-	/**
53
-	 * @param \OCP\Command\ICommand | callable $command
54
-	 */
55
-	private function runCommand($command) {
56
-		if ($command instanceof ICommand) {
57
-			// ensure the command can be serialized
58
-			$serialized = serialize($command);
59
-			if (strlen($serialized) > 4000) {
60
-				throw new \InvalidArgumentException('Trying to push a command which serialized form can not be stored in the database (>4000 character)');
61
-			}
62
-			$unserialized = unserialize($serialized);
63
-			$unserialized->handle();
64
-		} else {
65
-			$command();
66
-		}
67
-	}
52
+    /**
53
+     * @param \OCP\Command\ICommand | callable $command
54
+     */
55
+    private function runCommand($command) {
56
+        if ($command instanceof ICommand) {
57
+            // ensure the command can be serialized
58
+            $serialized = serialize($command);
59
+            if (strlen($serialized) > 4000) {
60
+                throw new \InvalidArgumentException('Trying to push a command which serialized form can not be stored in the database (>4000 character)');
61
+            }
62
+            $unserialized = unserialize($serialized);
63
+            $unserialized->handle();
64
+        } else {
65
+            $command();
66
+        }
67
+    }
68 68
 
69
-	public function run() {
70
-		while ($command = array_shift($this->queue)) {
71
-			$this->runCommand($command);
72
-		}
73
-	}
69
+    public function run() {
70
+        while ($command = array_shift($this->queue)) {
71
+            $this->runCommand($command);
72
+        }
73
+    }
74 74
 }
Please login to merge, or discard this patch.