Passed
Push — master ( 978047...cd5bd1 )
by Blizzz
16:35 queued 13s
created
apps/dav/lib/CardDAV/SystemAddressbook.php 1 patch
Indentation   +299 added lines, -299 removed lines patch added patch discarded remove patch
@@ -49,326 +49,326 @@
 block discarded – undo
49 49
 use function in_array;
50 50
 
51 51
 class SystemAddressbook extends AddressBook {
52
-	public const URI_SHARED = 'z-server-generated--system';
53
-	/** @var IConfig */
54
-	private $config;
55
-	private IUserSession $userSession;
56
-	private ?TrustedServers $trustedServers;
57
-	private ?IRequest $request;
58
-	private ?IGroupManager $groupManager;
52
+    public const URI_SHARED = 'z-server-generated--system';
53
+    /** @var IConfig */
54
+    private $config;
55
+    private IUserSession $userSession;
56
+    private ?TrustedServers $trustedServers;
57
+    private ?IRequest $request;
58
+    private ?IGroupManager $groupManager;
59 59
 
60
-	public function __construct(BackendInterface $carddavBackend,
61
-		array $addressBookInfo,
62
-		IL10N $l10n,
63
-		IConfig $config,
64
-		IUserSession $userSession,
65
-		?IRequest $request = null,
66
-		?TrustedServers $trustedServers = null,
67
-		?IGroupManager $groupManager) {
68
-		parent::__construct($carddavBackend, $addressBookInfo, $l10n);
69
-		$this->config = $config;
70
-		$this->userSession = $userSession;
71
-		$this->request = $request;
72
-		$this->trustedServers = $trustedServers;
73
-		$this->groupManager = $groupManager;
60
+    public function __construct(BackendInterface $carddavBackend,
61
+        array $addressBookInfo,
62
+        IL10N $l10n,
63
+        IConfig $config,
64
+        IUserSession $userSession,
65
+        ?IRequest $request = null,
66
+        ?TrustedServers $trustedServers = null,
67
+        ?IGroupManager $groupManager) {
68
+        parent::__construct($carddavBackend, $addressBookInfo, $l10n);
69
+        $this->config = $config;
70
+        $this->userSession = $userSession;
71
+        $this->request = $request;
72
+        $this->trustedServers = $trustedServers;
73
+        $this->groupManager = $groupManager;
74 74
 
75
-		$this->addressBookInfo['{DAV:}displayname'] = $l10n->t('Accounts');
76
-		$this->addressBookInfo['{' . Plugin::NS_CARDDAV . '}addressbook-description'] = $l10n->t('System address book which holds all accounts');
77
-	}
75
+        $this->addressBookInfo['{DAV:}displayname'] = $l10n->t('Accounts');
76
+        $this->addressBookInfo['{' . Plugin::NS_CARDDAV . '}addressbook-description'] = $l10n->t('System address book which holds all accounts');
77
+    }
78 78
 
79
-	/**
80
-	 * No checkbox checked -> Show only the same user
81
-	 * 'Allow username autocompletion in share dialog' -> show everyone
82
-	 * 'Allow username autocompletion in share dialog' + 'Allow username autocompletion to users within the same groups' -> show only users in intersecting groups
83
-	 * 'Allow username autocompletion in share dialog' + 'Allow username autocompletion to users based on phone number integration' -> show only the same user
84
-	 * 'Allow username autocompletion in share dialog' + 'Allow username autocompletion to users within the same groups' + 'Allow username autocompletion to users based on phone number integration' -> show only users in intersecting groups
85
-	 */
86
-	public function getChildren() {
87
-		$shareEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
88
-		$shareEnumerationGroup = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
89
-		$shareEnumerationPhone = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
90
-		$user = $this->userSession->getUser();
91
-		if (!$user) {
92
-			// Should never happen because we don't allow anonymous access
93
-			return [];
94
-		}
95
-		if ($user->getBackendClassName() === 'Guests' || !$shareEnumeration || (!$shareEnumerationGroup && $shareEnumerationPhone)) {
96
-			$name = SyncService::getCardUri($user);
97
-			try {
98
-				return [parent::getChild($name)];
99
-			} catch (NotFound $e) {
100
-				return [];
101
-			}
102
-		}
103
-		if ($shareEnumerationGroup) {
104
-			if ($this->groupManager === null) {
105
-				// Group manager is not available, so we can't determine which data is safe
106
-				return [];
107
-			}
108
-			$groups = $this->groupManager->getUserGroups($user);
109
-			$names = [];
110
-			foreach ($groups as $group) {
111
-				$users = $group->getUsers();
112
-				foreach ($users as $groupUser) {
113
-					if ($groupUser->getBackendClassName() === 'Guests') {
114
-						continue;
115
-					}
116
-					$names[] = SyncService::getCardUri($groupUser);
117
-				}
118
-			}
119
-			return parent::getMultipleChildren(array_unique($names));
120
-		}
79
+    /**
80
+     * No checkbox checked -> Show only the same user
81
+     * 'Allow username autocompletion in share dialog' -> show everyone
82
+     * 'Allow username autocompletion in share dialog' + 'Allow username autocompletion to users within the same groups' -> show only users in intersecting groups
83
+     * 'Allow username autocompletion in share dialog' + 'Allow username autocompletion to users based on phone number integration' -> show only the same user
84
+     * 'Allow username autocompletion in share dialog' + 'Allow username autocompletion to users within the same groups' + 'Allow username autocompletion to users based on phone number integration' -> show only users in intersecting groups
85
+     */
86
+    public function getChildren() {
87
+        $shareEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
88
+        $shareEnumerationGroup = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
89
+        $shareEnumerationPhone = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
90
+        $user = $this->userSession->getUser();
91
+        if (!$user) {
92
+            // Should never happen because we don't allow anonymous access
93
+            return [];
94
+        }
95
+        if ($user->getBackendClassName() === 'Guests' || !$shareEnumeration || (!$shareEnumerationGroup && $shareEnumerationPhone)) {
96
+            $name = SyncService::getCardUri($user);
97
+            try {
98
+                return [parent::getChild($name)];
99
+            } catch (NotFound $e) {
100
+                return [];
101
+            }
102
+        }
103
+        if ($shareEnumerationGroup) {
104
+            if ($this->groupManager === null) {
105
+                // Group manager is not available, so we can't determine which data is safe
106
+                return [];
107
+            }
108
+            $groups = $this->groupManager->getUserGroups($user);
109
+            $names = [];
110
+            foreach ($groups as $group) {
111
+                $users = $group->getUsers();
112
+                foreach ($users as $groupUser) {
113
+                    if ($groupUser->getBackendClassName() === 'Guests') {
114
+                        continue;
115
+                    }
116
+                    $names[] = SyncService::getCardUri($groupUser);
117
+                }
118
+            }
119
+            return parent::getMultipleChildren(array_unique($names));
120
+        }
121 121
 
122
-		$children = parent::getChildren();
123
-		return array_filter($children, function (Card $child) {
124
-			// check only for URIs that begin with Guests:
125
-			return strpos($child->getName(), 'Guests:') !== 0;
126
-		});
127
-	}
122
+        $children = parent::getChildren();
123
+        return array_filter($children, function (Card $child) {
124
+            // check only for URIs that begin with Guests:
125
+            return strpos($child->getName(), 'Guests:') !== 0;
126
+        });
127
+    }
128 128
 
129
-	/**
130
-	 * @param array $paths
131
-	 * @return Card[]
132
-	 * @throws NotFound
133
-	 */
134
-	public function getMultipleChildren($paths): array {
135
-		$shareEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
136
-		$shareEnumerationGroup = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
137
-		$shareEnumerationPhone = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
138
-		$user = $this->userSession->getUser();
139
-		if (($user !== null && $user->getBackendClassName() === 'Guests') || !$shareEnumeration || (!$shareEnumerationGroup && $shareEnumerationPhone)) {
140
-			// No user or cards with no access
141
-			if ($user === null || !in_array(SyncService::getCardUri($user), $paths, true)) {
142
-				return [];
143
-			}
144
-			// Only return the own card
145
-			try {
146
-				return [parent::getChild(SyncService::getCardUri($user))];
147
-			} catch (NotFound $e) {
148
-				return [];
149
-			}
150
-		}
151
-		if ($shareEnumerationGroup) {
152
-			if ($this->groupManager === null || $user === null) {
153
-				// Group manager or user is not available, so we can't determine which data is safe
154
-				return [];
155
-			}
156
-			$groups = $this->groupManager->getUserGroups($user);
157
-			$allowedNames = [];
158
-			foreach ($groups as $group) {
159
-				$users = $group->getUsers();
160
-				foreach ($users as $groupUser) {
161
-					if ($groupUser->getBackendClassName() === 'Guests') {
162
-						continue;
163
-					}
164
-					$allowedNames[] = SyncService::getCardUri($groupUser);
165
-				}
166
-			}
167
-			return parent::getMultipleChildren(array_intersect($paths, $allowedNames));
168
-		}
169
-		if (!$this->isFederation()) {
170
-			return parent::getMultipleChildren($paths);
171
-		}
129
+    /**
130
+     * @param array $paths
131
+     * @return Card[]
132
+     * @throws NotFound
133
+     */
134
+    public function getMultipleChildren($paths): array {
135
+        $shareEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
136
+        $shareEnumerationGroup = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
137
+        $shareEnumerationPhone = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
138
+        $user = $this->userSession->getUser();
139
+        if (($user !== null && $user->getBackendClassName() === 'Guests') || !$shareEnumeration || (!$shareEnumerationGroup && $shareEnumerationPhone)) {
140
+            // No user or cards with no access
141
+            if ($user === null || !in_array(SyncService::getCardUri($user), $paths, true)) {
142
+                return [];
143
+            }
144
+            // Only return the own card
145
+            try {
146
+                return [parent::getChild(SyncService::getCardUri($user))];
147
+            } catch (NotFound $e) {
148
+                return [];
149
+            }
150
+        }
151
+        if ($shareEnumerationGroup) {
152
+            if ($this->groupManager === null || $user === null) {
153
+                // Group manager or user is not available, so we can't determine which data is safe
154
+                return [];
155
+            }
156
+            $groups = $this->groupManager->getUserGroups($user);
157
+            $allowedNames = [];
158
+            foreach ($groups as $group) {
159
+                $users = $group->getUsers();
160
+                foreach ($users as $groupUser) {
161
+                    if ($groupUser->getBackendClassName() === 'Guests') {
162
+                        continue;
163
+                    }
164
+                    $allowedNames[] = SyncService::getCardUri($groupUser);
165
+                }
166
+            }
167
+            return parent::getMultipleChildren(array_intersect($paths, $allowedNames));
168
+        }
169
+        if (!$this->isFederation()) {
170
+            return parent::getMultipleChildren($paths);
171
+        }
172 172
 
173
-		$objs = $this->carddavBackend->getMultipleCards($this->addressBookInfo['id'], $paths);
174
-		$children = [];
175
-		/** @var array $obj */
176
-		foreach ($objs as $obj) {
177
-			if (empty($obj)) {
178
-				continue;
179
-			}
180
-			$carddata = $this->extractCarddata($obj);
181
-			if (empty($carddata)) {
182
-				continue;
183
-			} else {
184
-				$obj['carddata'] = $carddata;
185
-			}
186
-			$children[] = new Card($this->carddavBackend, $this->addressBookInfo, $obj);
187
-		}
188
-		return $children;
189
-	}
173
+        $objs = $this->carddavBackend->getMultipleCards($this->addressBookInfo['id'], $paths);
174
+        $children = [];
175
+        /** @var array $obj */
176
+        foreach ($objs as $obj) {
177
+            if (empty($obj)) {
178
+                continue;
179
+            }
180
+            $carddata = $this->extractCarddata($obj);
181
+            if (empty($carddata)) {
182
+                continue;
183
+            } else {
184
+                $obj['carddata'] = $carddata;
185
+            }
186
+            $children[] = new Card($this->carddavBackend, $this->addressBookInfo, $obj);
187
+        }
188
+        return $children;
189
+    }
190 190
 
191
-	/**
192
-	 * @param string $name
193
-	 * @return Card
194
-	 * @throws NotFound
195
-	 * @throws Forbidden
196
-	 */
197
-	public function getChild($name): Card {
198
-		$user = $this->userSession->getUser();
199
-		$shareEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
200
-		$shareEnumerationGroup = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
201
-		$shareEnumerationPhone = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
202
-		if (($user !== null && $user->getBackendClassName() === 'Guests') || !$shareEnumeration || (!$shareEnumerationGroup && $shareEnumerationPhone)) {
203
-			$ownName = $user !== null ? SyncService::getCardUri($user) : null;
204
-			if ($ownName === $name) {
205
-				return parent::getChild($name);
206
-			}
207
-			throw new Forbidden();
208
-		}
209
-		if ($shareEnumerationGroup) {
210
-			if ($user === null || $this->groupManager === null) {
211
-				// Group manager is not available, so we can't determine which data is safe
212
-				throw new Forbidden();
213
-			}
214
-			$groups = $this->groupManager->getUserGroups($user);
215
-			foreach ($groups as $group) {
216
-				foreach ($group->getUsers() as $groupUser) {
217
-					if ($groupUser->getBackendClassName() === 'Guests') {
218
-						continue;
219
-					}
220
-					$otherName = SyncService::getCardUri($groupUser);
221
-					if ($otherName === $name) {
222
-						return parent::getChild($name);
223
-					}
224
-				}
225
-			}
226
-			throw new Forbidden();
227
-		}
228
-		if (!$this->isFederation()) {
229
-			return parent::getChild($name);
230
-		}
191
+    /**
192
+     * @param string $name
193
+     * @return Card
194
+     * @throws NotFound
195
+     * @throws Forbidden
196
+     */
197
+    public function getChild($name): Card {
198
+        $user = $this->userSession->getUser();
199
+        $shareEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
200
+        $shareEnumerationGroup = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
201
+        $shareEnumerationPhone = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
202
+        if (($user !== null && $user->getBackendClassName() === 'Guests') || !$shareEnumeration || (!$shareEnumerationGroup && $shareEnumerationPhone)) {
203
+            $ownName = $user !== null ? SyncService::getCardUri($user) : null;
204
+            if ($ownName === $name) {
205
+                return parent::getChild($name);
206
+            }
207
+            throw new Forbidden();
208
+        }
209
+        if ($shareEnumerationGroup) {
210
+            if ($user === null || $this->groupManager === null) {
211
+                // Group manager is not available, so we can't determine which data is safe
212
+                throw new Forbidden();
213
+            }
214
+            $groups = $this->groupManager->getUserGroups($user);
215
+            foreach ($groups as $group) {
216
+                foreach ($group->getUsers() as $groupUser) {
217
+                    if ($groupUser->getBackendClassName() === 'Guests') {
218
+                        continue;
219
+                    }
220
+                    $otherName = SyncService::getCardUri($groupUser);
221
+                    if ($otherName === $name) {
222
+                        return parent::getChild($name);
223
+                    }
224
+                }
225
+            }
226
+            throw new Forbidden();
227
+        }
228
+        if (!$this->isFederation()) {
229
+            return parent::getChild($name);
230
+        }
231 231
 
232
-		$obj = $this->carddavBackend->getCard($this->addressBookInfo['id'], $name);
233
-		if (!$obj) {
234
-			throw new NotFound('Card not found');
235
-		}
236
-		$carddata = $this->extractCarddata($obj);
237
-		if (empty($carddata)) {
238
-			throw new Forbidden();
239
-		} else {
240
-			$obj['carddata'] = $carddata;
241
-		}
242
-		return new Card($this->carddavBackend, $this->addressBookInfo, $obj);
243
-	}
232
+        $obj = $this->carddavBackend->getCard($this->addressBookInfo['id'], $name);
233
+        if (!$obj) {
234
+            throw new NotFound('Card not found');
235
+        }
236
+        $carddata = $this->extractCarddata($obj);
237
+        if (empty($carddata)) {
238
+            throw new Forbidden();
239
+        } else {
240
+            $obj['carddata'] = $carddata;
241
+        }
242
+        return new Card($this->carddavBackend, $this->addressBookInfo, $obj);
243
+    }
244 244
 
245
-	/**
246
-	 * @throws UnsupportedLimitOnInitialSyncException
247
-	 */
248
-	public function getChanges($syncToken, $syncLevel, $limit = null) {
249
-		if (!$syncToken && $limit) {
250
-			throw new UnsupportedLimitOnInitialSyncException();
251
-		}
245
+    /**
246
+     * @throws UnsupportedLimitOnInitialSyncException
247
+     */
248
+    public function getChanges($syncToken, $syncLevel, $limit = null) {
249
+        if (!$syncToken && $limit) {
250
+            throw new UnsupportedLimitOnInitialSyncException();
251
+        }
252 252
 
253
-		if (!$this->carddavBackend instanceof SyncSupport) {
254
-			return null;
255
-		}
253
+        if (!$this->carddavBackend instanceof SyncSupport) {
254
+            return null;
255
+        }
256 256
 
257
-		if (!$this->isFederation()) {
258
-			return parent::getChanges($syncToken, $syncLevel, $limit);
259
-		}
257
+        if (!$this->isFederation()) {
258
+            return parent::getChanges($syncToken, $syncLevel, $limit);
259
+        }
260 260
 
261
-		$changed = $this->carddavBackend->getChangesForAddressBook(
262
-			$this->addressBookInfo['id'],
263
-			$syncToken,
264
-			$syncLevel,
265
-			$limit
266
-		);
261
+        $changed = $this->carddavBackend->getChangesForAddressBook(
262
+            $this->addressBookInfo['id'],
263
+            $syncToken,
264
+            $syncLevel,
265
+            $limit
266
+        );
267 267
 
268
-		if (empty($changed)) {
269
-			return $changed;
270
-		}
268
+        if (empty($changed)) {
269
+            return $changed;
270
+        }
271 271
 
272
-		$added = $modified = $deleted = [];
273
-		foreach ($changed['added'] as $uri) {
274
-			try {
275
-				$this->getChild($uri);
276
-				$added[] = $uri;
277
-			} catch (NotFound | Forbidden $e) {
278
-				$deleted[] = $uri;
279
-			}
280
-		}
281
-		foreach ($changed['modified'] as $uri) {
282
-			try {
283
-				$this->getChild($uri);
284
-				$modified[] = $uri;
285
-			} catch (NotFound | Forbidden $e) {
286
-				$deleted[] = $uri;
287
-			}
288
-		}
289
-		$changed['added'] = $added;
290
-		$changed['modified'] = $modified;
291
-		$changed['deleted'] = $deleted;
292
-		return $changed;
293
-	}
272
+        $added = $modified = $deleted = [];
273
+        foreach ($changed['added'] as $uri) {
274
+            try {
275
+                $this->getChild($uri);
276
+                $added[] = $uri;
277
+            } catch (NotFound | Forbidden $e) {
278
+                $deleted[] = $uri;
279
+            }
280
+        }
281
+        foreach ($changed['modified'] as $uri) {
282
+            try {
283
+                $this->getChild($uri);
284
+                $modified[] = $uri;
285
+            } catch (NotFound | Forbidden $e) {
286
+                $deleted[] = $uri;
287
+            }
288
+        }
289
+        $changed['added'] = $added;
290
+        $changed['modified'] = $modified;
291
+        $changed['deleted'] = $deleted;
292
+        return $changed;
293
+    }
294 294
 
295
-	private function isFederation(): bool {
296
-		if ($this->trustedServers === null || $this->request === null) {
297
-			return false;
298
-		}
295
+    private function isFederation(): bool {
296
+        if ($this->trustedServers === null || $this->request === null) {
297
+            return false;
298
+        }
299 299
 
300
-		/** @psalm-suppress NoInterfaceProperties */
301
-		$server = $this->request->server;
302
-		if (!isset($server['PHP_AUTH_USER']) || $server['PHP_AUTH_USER'] !== 'system') {
303
-			return false;
304
-		}
300
+        /** @psalm-suppress NoInterfaceProperties */
301
+        $server = $this->request->server;
302
+        if (!isset($server['PHP_AUTH_USER']) || $server['PHP_AUTH_USER'] !== 'system') {
303
+            return false;
304
+        }
305 305
 
306
-		/** @psalm-suppress NoInterfaceProperties */
307
-		$sharedSecret = $server['PHP_AUTH_PW'] ?? null;
308
-		if ($sharedSecret === null) {
309
-			return false;
310
-		}
306
+        /** @psalm-suppress NoInterfaceProperties */
307
+        $sharedSecret = $server['PHP_AUTH_PW'] ?? null;
308
+        if ($sharedSecret === null) {
309
+            return false;
310
+        }
311 311
 
312
-		$servers = $this->trustedServers->getServers();
313
-		$trusted = array_filter($servers, function ($trustedServer) use ($sharedSecret) {
314
-			return $trustedServer['shared_secret'] === $sharedSecret;
315
-		});
316
-		// Authentication is fine, but it's not for a federated share
317
-		if (empty($trusted)) {
318
-			return false;
319
-		}
312
+        $servers = $this->trustedServers->getServers();
313
+        $trusted = array_filter($servers, function ($trustedServer) use ($sharedSecret) {
314
+            return $trustedServer['shared_secret'] === $sharedSecret;
315
+        });
316
+        // Authentication is fine, but it's not for a federated share
317
+        if (empty($trusted)) {
318
+            return false;
319
+        }
320 320
 
321
-		return true;
322
-	}
321
+        return true;
322
+    }
323 323
 
324
-	/**
325
-	 * If the validation doesn't work the card is "not found" so we
326
-	 * return empty carddata even if the carddata might exist in the local backend.
327
-	 * This can happen when a user sets the required properties
328
-	 * FN, N to a local scope only but the request is from
329
-	 * a federated share.
330
-	 *
331
-	 * @see https://github.com/nextcloud/server/issues/38042
332
-	 *
333
-	 * @param array $obj
334
-	 * @return string|null
335
-	 */
336
-	private function extractCarddata(array $obj): ?string {
337
-		$obj['acl'] = $this->getChildACL();
338
-		$cardData = $obj['carddata'];
339
-		/** @var VCard $vCard */
340
-		$vCard = Reader::read($cardData);
341
-		foreach ($vCard->children() as $child) {
342
-			$scope = $child->offsetGet('X-NC-SCOPE');
343
-			if ($scope !== null && $scope->getValue() === IAccountManager::SCOPE_LOCAL) {
344
-				$vCard->remove($child);
345
-			}
346
-		}
347
-		$messages = $vCard->validate();
348
-		if (!empty($messages)) {
349
-			return null;
350
-		}
324
+    /**
325
+     * If the validation doesn't work the card is "not found" so we
326
+     * return empty carddata even if the carddata might exist in the local backend.
327
+     * This can happen when a user sets the required properties
328
+     * FN, N to a local scope only but the request is from
329
+     * a federated share.
330
+     *
331
+     * @see https://github.com/nextcloud/server/issues/38042
332
+     *
333
+     * @param array $obj
334
+     * @return string|null
335
+     */
336
+    private function extractCarddata(array $obj): ?string {
337
+        $obj['acl'] = $this->getChildACL();
338
+        $cardData = $obj['carddata'];
339
+        /** @var VCard $vCard */
340
+        $vCard = Reader::read($cardData);
341
+        foreach ($vCard->children() as $child) {
342
+            $scope = $child->offsetGet('X-NC-SCOPE');
343
+            if ($scope !== null && $scope->getValue() === IAccountManager::SCOPE_LOCAL) {
344
+                $vCard->remove($child);
345
+            }
346
+        }
347
+        $messages = $vCard->validate();
348
+        if (!empty($messages)) {
349
+            return null;
350
+        }
351 351
 
352
-		return $vCard->serialize();
353
-	}
352
+        return $vCard->serialize();
353
+    }
354 354
 
355
-	/**
356
-	 * @return mixed
357
-	 * @throws Forbidden
358
-	 */
359
-	public function delete() {
360
-		if ($this->isFederation()) {
361
-			parent::delete();
362
-		}
363
-		throw new Forbidden();
364
-	}
355
+    /**
356
+     * @return mixed
357
+     * @throws Forbidden
358
+     */
359
+    public function delete() {
360
+        if ($this->isFederation()) {
361
+            parent::delete();
362
+        }
363
+        throw new Forbidden();
364
+    }
365 365
 
366
-	public function getACL() {
367
-		return array_filter(parent::getACL(), function ($acl) {
368
-			if (in_array($acl['privilege'], ['{DAV:}write', '{DAV:}all'], true)) {
369
-				return false;
370
-			}
371
-			return true;
372
-		});
373
-	}
366
+    public function getACL() {
367
+        return array_filter(parent::getACL(), function ($acl) {
368
+            if (in_array($acl['privilege'], ['{DAV:}write', '{DAV:}all'], true)) {
369
+                return false;
370
+            }
371
+            return true;
372
+        });
373
+    }
374 374
 }
Please login to merge, or discard this patch.