Passed
Push — master ( 21b7e5...813bdc )
by Christoph
12:53 queued 10s
created
lib/private/SubAdmin.php 1 patch
Indentation   +246 added lines, -246 removed lines patch added patch discarded remove patch
@@ -39,252 +39,252 @@
 block discarded – undo
39 39
 
40 40
 class SubAdmin extends PublicEmitter implements ISubAdmin {
41 41
 
42
-	/** @var IUserManager */
43
-	private $userManager;
44
-
45
-	/** @var IGroupManager */
46
-	private $groupManager;
47
-
48
-	/** @var IDBConnection */
49
-	private $dbConn;
50
-
51
-	/**
52
-	 * @param IUserManager $userManager
53
-	 * @param IGroupManager $groupManager
54
-	 * @param IDBConnection $dbConn
55
-	 */
56
-	public function __construct(IUserManager $userManager,
57
-								IGroupManager $groupManager,
58
-								IDBConnection $dbConn) {
59
-		$this->userManager = $userManager;
60
-		$this->groupManager = $groupManager;
61
-		$this->dbConn = $dbConn;
62
-
63
-		$this->userManager->listen('\OC\User', 'postDelete', function($user) {
64
-			$this->post_deleteUser($user);
65
-		});
66
-		$this->groupManager->listen('\OC\Group', 'postDelete', function($group) {
67
-			$this->post_deleteGroup($group);
68
-		});
69
-	}
70
-
71
-	/**
72
-	 * add a SubAdmin
73
-	 * @param IUser $user user to be SubAdmin
74
-	 * @param IGroup $group group $user becomes subadmin of
75
-	 */
76
-	public function createSubAdmin(IUser $user, IGroup $group): void {
77
-		$qb = $this->dbConn->getQueryBuilder();
78
-
79
-		$qb->insert('group_admin')
80
-			->values([
81
-				'gid' => $qb->createNamedParameter($group->getGID()),
82
-				'uid' => $qb->createNamedParameter($user->getUID())
83
-			])
84
-			->execute();
85
-
86
-		$this->emit('\OC\SubAdmin', 'postCreateSubAdmin', [$user, $group]);
87
-		\OC_Hook::emit("OC_SubAdmin", "post_createSubAdmin", ["gid" => $group->getGID()]);
88
-	}
89
-
90
-	/**
91
-	 * delete a SubAdmin
92
-	 * @param IUser $user the user that is the SubAdmin
93
-	 * @param IGroup $group the group
94
-	 */
95
-	public function deleteSubAdmin(IUser $user, IGroup $group): void {
96
-		$qb = $this->dbConn->getQueryBuilder();
97
-
98
-		$qb->delete('group_admin')
99
-			->where($qb->expr()->eq('gid', $qb->createNamedParameter($group->getGID())))
100
-			->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
101
-			->execute();
102
-
103
-		$this->emit('\OC\SubAdmin', 'postDeleteSubAdmin', [$user, $group]);
104
-		\OC_Hook::emit("OC_SubAdmin", "post_deleteSubAdmin", ["gid" => $group->getGID()]);
105
-	}
106
-
107
-	/**
108
-	 * get groups of a SubAdmin
109
-	 * @param IUser $user the SubAdmin
110
-	 * @return IGroup[]
111
-	 */
112
-	public function getSubAdminsGroups(IUser $user): array {
113
-		$qb = $this->dbConn->getQueryBuilder();
114
-
115
-		$result = $qb->select('gid')
116
-			->from('group_admin')
117
-			->where($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
118
-			->execute();
119
-
120
-		$groups = [];
121
-		while($row = $result->fetch()) {
122
-			$group = $this->groupManager->get($row['gid']);
123
-			if(!is_null($group)) {
124
-				$groups[$group->getGID()] = $group;
125
-			}
126
-		}
127
-		$result->closeCursor();
128
-
129
-		return $groups;
130
-	}
131
-
132
-	/**
133
-	 * get an array of groupid and displayName for a user
134
-	 * @param IUser $user
135
-	 * @return array ['displayName' => displayname]
136
-	 */
137
-	public function getSubAdminsGroupsName(IUser $user): array {
138
-		return array_map(function($group) {
139
-			return ['displayName' => $group->getDisplayName()];
140
-		}, $this->getSubAdminsGroups($user));
141
-	}
142
-
143
-	/**
144
-	 * get SubAdmins of a group
145
-	 * @param IGroup $group the group
146
-	 * @return IUser[]
147
-	 */
148
-	public function getGroupsSubAdmins(IGroup $group): array {
149
-		$qb = $this->dbConn->getQueryBuilder();
150
-
151
-		$result = $qb->select('uid')
152
-			->from('group_admin')
153
-			->where($qb->expr()->eq('gid', $qb->createNamedParameter($group->getGID())))
154
-			->execute();
155
-
156
-		$users = [];
157
-		while($row = $result->fetch()) {
158
-			$user = $this->userManager->get($row['uid']);
159
-			if(!is_null($user)) {
160
-				$users[] = $user;
161
-			}
162
-		}
163
-		$result->closeCursor();
164
-
165
-		return $users;
166
-	}
167
-
168
-	/**
169
-	 * get all SubAdmins
170
-	 * @return array
171
-	 */
172
-	public function getAllSubAdmins(): array {
173
-		$qb = $this->dbConn->getQueryBuilder();
174
-
175
-		$result = $qb->select('*')
176
-			->from('group_admin')
177
-			->execute();
178
-
179
-		$subadmins = [];
180
-		while($row = $result->fetch()) {
181
-			$user = $this->userManager->get($row['uid']);
182
-			$group = $this->groupManager->get($row['gid']);
183
-			if(!is_null($user) && !is_null($group)) {
184
-				$subadmins[] = [
185
-					'user'  => $user,
186
-					'group' => $group
187
-				];
188
-			}
189
-		}
190
-		$result->closeCursor();
191
-
192
-		return $subadmins;
193
-	}
194
-
195
-	/**
196
-	 * checks if a user is a SubAdmin of a group
197
-	 * @param IUser $user
198
-	 * @param IGroup $group
199
-	 * @return bool
200
-	 */
201
-	public function isSubAdminOfGroup(IUser $user, IGroup $group): bool {
202
-		$qb = $this->dbConn->getQueryBuilder();
203
-
204
-		/*
42
+    /** @var IUserManager */
43
+    private $userManager;
44
+
45
+    /** @var IGroupManager */
46
+    private $groupManager;
47
+
48
+    /** @var IDBConnection */
49
+    private $dbConn;
50
+
51
+    /**
52
+     * @param IUserManager $userManager
53
+     * @param IGroupManager $groupManager
54
+     * @param IDBConnection $dbConn
55
+     */
56
+    public function __construct(IUserManager $userManager,
57
+                                IGroupManager $groupManager,
58
+                                IDBConnection $dbConn) {
59
+        $this->userManager = $userManager;
60
+        $this->groupManager = $groupManager;
61
+        $this->dbConn = $dbConn;
62
+
63
+        $this->userManager->listen('\OC\User', 'postDelete', function($user) {
64
+            $this->post_deleteUser($user);
65
+        });
66
+        $this->groupManager->listen('\OC\Group', 'postDelete', function($group) {
67
+            $this->post_deleteGroup($group);
68
+        });
69
+    }
70
+
71
+    /**
72
+     * add a SubAdmin
73
+     * @param IUser $user user to be SubAdmin
74
+     * @param IGroup $group group $user becomes subadmin of
75
+     */
76
+    public function createSubAdmin(IUser $user, IGroup $group): void {
77
+        $qb = $this->dbConn->getQueryBuilder();
78
+
79
+        $qb->insert('group_admin')
80
+            ->values([
81
+                'gid' => $qb->createNamedParameter($group->getGID()),
82
+                'uid' => $qb->createNamedParameter($user->getUID())
83
+            ])
84
+            ->execute();
85
+
86
+        $this->emit('\OC\SubAdmin', 'postCreateSubAdmin', [$user, $group]);
87
+        \OC_Hook::emit("OC_SubAdmin", "post_createSubAdmin", ["gid" => $group->getGID()]);
88
+    }
89
+
90
+    /**
91
+     * delete a SubAdmin
92
+     * @param IUser $user the user that is the SubAdmin
93
+     * @param IGroup $group the group
94
+     */
95
+    public function deleteSubAdmin(IUser $user, IGroup $group): void {
96
+        $qb = $this->dbConn->getQueryBuilder();
97
+
98
+        $qb->delete('group_admin')
99
+            ->where($qb->expr()->eq('gid', $qb->createNamedParameter($group->getGID())))
100
+            ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
101
+            ->execute();
102
+
103
+        $this->emit('\OC\SubAdmin', 'postDeleteSubAdmin', [$user, $group]);
104
+        \OC_Hook::emit("OC_SubAdmin", "post_deleteSubAdmin", ["gid" => $group->getGID()]);
105
+    }
106
+
107
+    /**
108
+     * get groups of a SubAdmin
109
+     * @param IUser $user the SubAdmin
110
+     * @return IGroup[]
111
+     */
112
+    public function getSubAdminsGroups(IUser $user): array {
113
+        $qb = $this->dbConn->getQueryBuilder();
114
+
115
+        $result = $qb->select('gid')
116
+            ->from('group_admin')
117
+            ->where($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
118
+            ->execute();
119
+
120
+        $groups = [];
121
+        while($row = $result->fetch()) {
122
+            $group = $this->groupManager->get($row['gid']);
123
+            if(!is_null($group)) {
124
+                $groups[$group->getGID()] = $group;
125
+            }
126
+        }
127
+        $result->closeCursor();
128
+
129
+        return $groups;
130
+    }
131
+
132
+    /**
133
+     * get an array of groupid and displayName for a user
134
+     * @param IUser $user
135
+     * @return array ['displayName' => displayname]
136
+     */
137
+    public function getSubAdminsGroupsName(IUser $user): array {
138
+        return array_map(function($group) {
139
+            return ['displayName' => $group->getDisplayName()];
140
+        }, $this->getSubAdminsGroups($user));
141
+    }
142
+
143
+    /**
144
+     * get SubAdmins of a group
145
+     * @param IGroup $group the group
146
+     * @return IUser[]
147
+     */
148
+    public function getGroupsSubAdmins(IGroup $group): array {
149
+        $qb = $this->dbConn->getQueryBuilder();
150
+
151
+        $result = $qb->select('uid')
152
+            ->from('group_admin')
153
+            ->where($qb->expr()->eq('gid', $qb->createNamedParameter($group->getGID())))
154
+            ->execute();
155
+
156
+        $users = [];
157
+        while($row = $result->fetch()) {
158
+            $user = $this->userManager->get($row['uid']);
159
+            if(!is_null($user)) {
160
+                $users[] = $user;
161
+            }
162
+        }
163
+        $result->closeCursor();
164
+
165
+        return $users;
166
+    }
167
+
168
+    /**
169
+     * get all SubAdmins
170
+     * @return array
171
+     */
172
+    public function getAllSubAdmins(): array {
173
+        $qb = $this->dbConn->getQueryBuilder();
174
+
175
+        $result = $qb->select('*')
176
+            ->from('group_admin')
177
+            ->execute();
178
+
179
+        $subadmins = [];
180
+        while($row = $result->fetch()) {
181
+            $user = $this->userManager->get($row['uid']);
182
+            $group = $this->groupManager->get($row['gid']);
183
+            if(!is_null($user) && !is_null($group)) {
184
+                $subadmins[] = [
185
+                    'user'  => $user,
186
+                    'group' => $group
187
+                ];
188
+            }
189
+        }
190
+        $result->closeCursor();
191
+
192
+        return $subadmins;
193
+    }
194
+
195
+    /**
196
+     * checks if a user is a SubAdmin of a group
197
+     * @param IUser $user
198
+     * @param IGroup $group
199
+     * @return bool
200
+     */
201
+    public function isSubAdminOfGroup(IUser $user, IGroup $group): bool {
202
+        $qb = $this->dbConn->getQueryBuilder();
203
+
204
+        /*
205 205
 		 * Primary key is ('gid', 'uid') so max 1 result possible here
206 206
 		 */
207
-		$result = $qb->select('*')
208
-			->from('group_admin')
209
-			->where($qb->expr()->eq('gid', $qb->createNamedParameter($group->getGID())))
210
-			->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
211
-			->execute();
212
-
213
-		$fetch =  $result->fetch();
214
-		$result->closeCursor();
215
-		$result = !empty($fetch) ? true : false;
216
-
217
-		return $result;
218
-	}
219
-
220
-	/**
221
-	 * checks if a user is a SubAdmin
222
-	 * @param IUser $user
223
-	 * @return bool
224
-	 */
225
-	public function isSubAdmin(IUser $user): bool {
226
-		// Check if the user is already an admin
227
-		if ($this->groupManager->isAdmin($user->getUID())) {
228
-			return true;
229
-		}
230
-
231
-		$qb = $this->dbConn->getQueryBuilder();
232
-
233
-		$result = $qb->select('gid')
234
-			->from('group_admin')
235
-			->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
236
-			->setMaxResults(1)
237
-			->execute();
238
-
239
-		$isSubAdmin = $result->fetch();
240
-		$result->closeCursor();
241
-
242
-		return $isSubAdmin !== false;
243
-	}
244
-
245
-	/**
246
-	 * checks if a user is a accessible by a subadmin
247
-	 * @param IUser $subadmin
248
-	 * @param IUser $user
249
-	 * @return bool
250
-	 */
251
-	public function isUserAccessible(IUser $subadmin, IUser $user): bool {
252
-		if(!$this->isSubAdmin($subadmin)) {
253
-			return false;
254
-		}
255
-		if($this->groupManager->isAdmin($user->getUID())) {
256
-			return false;
257
-		}
258
-		$accessibleGroups = $this->getSubAdminsGroups($subadmin);
259
-		foreach($accessibleGroups as $accessibleGroup) {
260
-			if($accessibleGroup->inGroup($user)) {
261
-				return true;
262
-			}
263
-		}
264
-		return false;
265
-	}
266
-
267
-	/**
268
-	 * delete all SubAdmins by $user
269
-	 * @param IUser $user
270
-	 */
271
-	private function post_deleteUser(IUser $user) {
272
-		$qb = $this->dbConn->getQueryBuilder();
273
-
274
-		$qb->delete('group_admin')
275
-			->where($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
276
-			->execute();
277
-	}
278
-
279
-	/**
280
-	 * delete all SubAdmins by $group
281
-	 * @param IGroup $group
282
-	 */
283
-	private function post_deleteGroup(IGroup $group) {
284
-		$qb = $this->dbConn->getQueryBuilder();
285
-
286
-		$qb->delete('group_admin')
287
-			->where($qb->expr()->eq('gid', $qb->createNamedParameter($group->getGID())))
288
-			->execute();
289
-	}
207
+        $result = $qb->select('*')
208
+            ->from('group_admin')
209
+            ->where($qb->expr()->eq('gid', $qb->createNamedParameter($group->getGID())))
210
+            ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
211
+            ->execute();
212
+
213
+        $fetch =  $result->fetch();
214
+        $result->closeCursor();
215
+        $result = !empty($fetch) ? true : false;
216
+
217
+        return $result;
218
+    }
219
+
220
+    /**
221
+     * checks if a user is a SubAdmin
222
+     * @param IUser $user
223
+     * @return bool
224
+     */
225
+    public function isSubAdmin(IUser $user): bool {
226
+        // Check if the user is already an admin
227
+        if ($this->groupManager->isAdmin($user->getUID())) {
228
+            return true;
229
+        }
230
+
231
+        $qb = $this->dbConn->getQueryBuilder();
232
+
233
+        $result = $qb->select('gid')
234
+            ->from('group_admin')
235
+            ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
236
+            ->setMaxResults(1)
237
+            ->execute();
238
+
239
+        $isSubAdmin = $result->fetch();
240
+        $result->closeCursor();
241
+
242
+        return $isSubAdmin !== false;
243
+    }
244
+
245
+    /**
246
+     * checks if a user is a accessible by a subadmin
247
+     * @param IUser $subadmin
248
+     * @param IUser $user
249
+     * @return bool
250
+     */
251
+    public function isUserAccessible(IUser $subadmin, IUser $user): bool {
252
+        if(!$this->isSubAdmin($subadmin)) {
253
+            return false;
254
+        }
255
+        if($this->groupManager->isAdmin($user->getUID())) {
256
+            return false;
257
+        }
258
+        $accessibleGroups = $this->getSubAdminsGroups($subadmin);
259
+        foreach($accessibleGroups as $accessibleGroup) {
260
+            if($accessibleGroup->inGroup($user)) {
261
+                return true;
262
+            }
263
+        }
264
+        return false;
265
+    }
266
+
267
+    /**
268
+     * delete all SubAdmins by $user
269
+     * @param IUser $user
270
+     */
271
+    private function post_deleteUser(IUser $user) {
272
+        $qb = $this->dbConn->getQueryBuilder();
273
+
274
+        $qb->delete('group_admin')
275
+            ->where($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
276
+            ->execute();
277
+    }
278
+
279
+    /**
280
+     * delete all SubAdmins by $group
281
+     * @param IGroup $group
282
+     */
283
+    private function post_deleteGroup(IGroup $group) {
284
+        $qb = $this->dbConn->getQueryBuilder();
285
+
286
+        $qb->delete('group_admin')
287
+            ->where($qb->expr()->eq('gid', $qb->createNamedParameter($group->getGID())))
288
+            ->execute();
289
+    }
290 290
 }
Please login to merge, or discard this patch.
lib/private/Share/Share.php 1 patch
Indentation   +1496 added lines, -1496 removed lines patch added patch discarded remove patch
@@ -49,1500 +49,1500 @@
 block discarded – undo
49 49
  */
50 50
 class Share extends Constants {
51 51
 
52
-	/** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask
53
-	 * Construct permissions for share() and setPermissions with Or (|) e.g.
54
-	 * Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE
55
-	 *
56
-	 * Check if permission is granted with And (&) e.g. Check if delete is
57
-	 * granted: if ($permissions & PERMISSION_DELETE)
58
-	 *
59
-	 * Remove permissions with And (&) and Not (~) e.g. Remove the update
60
-	 * permission: $permissions &= ~PERMISSION_UPDATE
61
-	 *
62
-	 * Apps are required to handle permissions on their own, this class only
63
-	 * stores and manages the permissions of shares
64
-	 * @see lib/public/constants.php
65
-	 */
66
-
67
-	/**
68
-	 * Register a sharing backend class that implements OCP\Share_Backend for an item type
69
-	 * @param string $itemType Item type
70
-	 * @param string $class Backend class
71
-	 * @param string $collectionOf (optional) Depends on item type
72
-	 * @param array $supportedFileExtensions (optional) List of supported file extensions if this item type depends on files
73
-	 * @return boolean true if backend is registered or false if error
74
-	 */
75
-	public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) {
76
-		if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') == 'yes') {
77
-			if (!isset(self::$backendTypes[$itemType])) {
78
-				self::$backendTypes[$itemType] = [
79
-					'class' => $class,
80
-					'collectionOf' => $collectionOf,
81
-					'supportedFileExtensions' => $supportedFileExtensions
82
-				];
83
-				return true;
84
-			}
85
-			\OCP\Util::writeLog('OCP\Share',
86
-				'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class']
87
-				.' is already registered for '.$itemType,
88
-				ILogger::WARN);
89
-		}
90
-		return false;
91
-	}
92
-
93
-	/**
94
-	 * Get the items of item type shared with the current user
95
-	 * @param string $itemType
96
-	 * @param int $format (optional) Format type must be defined by the backend
97
-	 * @param mixed $parameters (optional)
98
-	 * @param int $limit Number of items to return (optional) Returns all by default
99
-	 * @param boolean $includeCollections (optional)
100
-	 * @return mixed Return depends on format
101
-	 * @deprecated TESTS ONLY - this methods is only used by tests
102
-	 * called like this:
103
-	 * \OC\Share\Share::getItemsSharedWith('folder'); (apps/files_sharing/tests/UpdaterTest.php)
104
-	 */
105
-	public static function getItemsSharedWith() {
106
-		return self::getItems('folder', null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, self::FORMAT_NONE,
107
-			null, -1, false);
108
-	}
109
-
110
-	/**
111
-	 * Get the items of item type shared with a user
112
-	 * @param string $itemType
113
-	 * @param string $user id for which user we want the shares
114
-	 * @param int $format (optional) Format type must be defined by the backend
115
-	 * @param mixed $parameters (optional)
116
-	 * @param int $limit Number of items to return (optional) Returns all by default
117
-	 * @param boolean $includeCollections (optional)
118
-	 * @return mixed Return depends on format
119
-	 */
120
-	public static function getItemsSharedWithUser($itemType, $user, $format = self::FORMAT_NONE,
121
-												  $parameters = null, $limit = -1, $includeCollections = false) {
122
-		return self::getItems($itemType, null, self::$shareTypeUserAndGroups, $user, null, $format,
123
-			$parameters, $limit, $includeCollections);
124
-	}
125
-
126
-	/**
127
-	 * Get the item of item type shared with a given user by source
128
-	 * @param string $itemType
129
-	 * @param string $itemSource
130
-	 * @param string $user User to whom the item was shared
131
-	 * @param string $owner Owner of the share
132
-	 * @param int $shareType only look for a specific share type
133
-	 * @return array Return list of items with file_target, permissions and expiration
134
-	 */
135
-	public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null, $shareType = null) {
136
-		$shares = [];
137
-		$fileDependent = false;
138
-
139
-		$where = 'WHERE';
140
-		$fileDependentWhere = '';
141
-		if ($itemType === 'file' || $itemType === 'folder') {
142
-			$fileDependent = true;
143
-			$column = 'file_source';
144
-			$fileDependentWhere = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
145
-			$fileDependentWhere .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
146
-		} else {
147
-			$column = 'item_source';
148
-		}
149
-
150
-		$select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent);
151
-
152
-		$where .= ' `' . $column . '` = ? AND `item_type` = ? ';
153
-		$arguments = [$itemSource, $itemType];
154
-		// for link shares $user === null
155
-		if ($user !== null) {
156
-			$where .= ' AND `share_with` = ? ';
157
-			$arguments[] = $user;
158
-		}
159
-
160
-		if ($shareType !== null) {
161
-			$where .= ' AND `share_type` = ? ';
162
-			$arguments[] = $shareType;
163
-		}
164
-
165
-		if ($owner !== null) {
166
-			$where .= ' AND `uid_owner` = ? ';
167
-			$arguments[] = $owner;
168
-		}
169
-
170
-		$query = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` '. $fileDependentWhere . $where);
171
-
172
-		$result = \OC_DB::executeAudited($query, $arguments);
173
-
174
-		while ($row = $result->fetchRow()) {
175
-			if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
176
-				continue;
177
-			}
178
-			if ($fileDependent && (int)$row['file_parent'] === -1) {
179
-				// if it is a mount point we need to get the path from the mount manager
180
-				$mountManager = \OC\Files\Filesystem::getMountManager();
181
-				$mountPoint = $mountManager->findByStorageId($row['storage_id']);
182
-				if (!empty($mountPoint)) {
183
-					$path = $mountPoint[0]->getMountPoint();
184
-					$path = trim($path, '/');
185
-					$path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt`
186
-					$row['path'] = $path;
187
-				} else {
188
-					\OC::$server->getLogger()->warning(
189
-						'Could not resolve mount point for ' . $row['storage_id'],
190
-						['app' => 'OCP\Share']
191
-					);
192
-				}
193
-			}
194
-			$shares[] = $row;
195
-		}
196
-
197
-		//if didn't found a result than let's look for a group share.
198
-		if(empty($shares) && $user !== null) {
199
-			$userObject = \OC::$server->getUserManager()->get($user);
200
-			$groups = [];
201
-			if ($userObject) {
202
-				$groups = \OC::$server->getGroupManager()->getUserGroupIds($userObject);
203
-			}
204
-
205
-			if (!empty($groups)) {
206
-				$where = $fileDependentWhere . ' WHERE `' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)';
207
-				$arguments = [$itemSource, $itemType, $groups];
208
-				$types = [null, null, IQueryBuilder::PARAM_STR_ARRAY];
209
-
210
-				if ($owner !== null) {
211
-					$where .= ' AND `uid_owner` = ?';
212
-					$arguments[] = $owner;
213
-					$types[] = null;
214
-				}
215
-
216
-				// TODO: inject connection, hopefully one day in the future when this
217
-				// class isn't static anymore...
218
-				$conn = \OC::$server->getDatabaseConnection();
219
-				$result = $conn->executeQuery(
220
-					'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
221
-					$arguments,
222
-					$types
223
-				);
224
-
225
-				while ($row = $result->fetch()) {
226
-					$shares[] = $row;
227
-				}
228
-			}
229
-		}
230
-
231
-		return $shares;
232
-
233
-	}
234
-
235
-	/**
236
-	 * Get the item of item type shared with the current user by source
237
-	 * @param string $itemType
238
-	 * @param string $itemSource
239
-	 * @param int $format (optional) Format type must be defined by the backend
240
-	 * @param mixed $parameters
241
-	 * @param boolean $includeCollections
242
-	 * @param string $shareWith (optional) define against which user should be checked, default: current user
243
-	 * @return array
244
-	 */
245
-	public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
246
-													 $parameters = null, $includeCollections = false, $shareWith = null) {
247
-		$shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith;
248
-		return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format,
249
-			$parameters, 1, $includeCollections, true);
250
-	}
251
-
252
-	/**
253
-	 * Get the shared item of item type owned by the current user
254
-	 * @param string $itemType
255
-	 * @param string $itemSource
256
-	 * @param int $format (optional) Format type must be defined by the backend
257
-	 * @param mixed $parameters
258
-	 * @param boolean $includeCollections
259
-	 * @return mixed Return depends on format
260
-	 */
261
-	public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
262
-										 $parameters = null, $includeCollections = false) {
263
-		return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
264
-			$parameters, -1, $includeCollections);
265
-	}
266
-
267
-	/**
268
-	 * Share an item with a user, group, or via private link
269
-	 * @param string $itemType
270
-	 * @param string $itemSource
271
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
272
-	 * @param string $shareWith User or group the item is being shared with
273
-	 * @param int $permissions CRUDS
274
-	 * @param string $itemSourceName
275
-	 * @param \DateTime|null $expirationDate
276
-	 * @return boolean|string Returns true on success or false on failure, Returns token on success for links
277
-	 * @throws \OC\HintException when the share type is remote and the shareWith is invalid
278
-	 * @throws \Exception
279
-	 * @since 5.0.0 - parameter $itemSourceName was added in 6.0.0, parameter $expirationDate was added in 7.0.0, parameter $passwordChanged added in 9.0.0
280
-	 * @deprecated 14.0.0 TESTS ONLY - this methods is as of 2018-06 only used by tests
281
-	 * called like this:
282
-	 * \OC\Share\Share::shareItem('test', 1, \OCP\Share::SHARE_TYPE_USER, $otherUserId, \OCP\Constants::PERMISSION_READ);
283
-	 */
284
-	public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions) {
285
-		$backend = self::getBackend($itemType);
286
-
287
-		if ($backend->isShareTypeAllowed($shareType) === false) {
288
-			$message = 'Sharing failed, because the backend does not allow shares from type %i';
289
-			throw new \Exception(sprintf($message, $shareType));
290
-		}
291
-
292
-		$uidOwner = \OC_User::getUser();
293
-
294
-		// Verify share type and sharing conditions are met
295
-		if ($shareType === self::SHARE_TYPE_USER) {
296
-			if ($shareWith == $uidOwner) {
297
-				$message = 'Sharing failed, because you can not share with yourself';
298
-				throw new \Exception($message);
299
-			}
300
-			if (!\OC::$server->getUserManager()->userExists($shareWith)) {
301
-				$message = 'Sharing failed, because the user %s does not exist';
302
-				throw new \Exception(sprintf($message, $shareWith));
303
-			}
304
-			// Check if the item source is already shared with the user, either from the same owner or a different user
305
-			if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups,
306
-				$shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
307
-				// Only allow the same share to occur again if it is the same
308
-				// owner and is not a user share, this use case is for increasing
309
-				// permissions for a specific user
310
-				if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
311
-					$message = 'Sharing failed, because this item is already shared with %s';
312
-					throw new \Exception(sprintf($message, $shareWith));
313
-				}
314
-			}
315
-			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_USER,
316
-				$shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
317
-				// Only allow the same share to occur again if it is the same
318
-				// owner and is not a user share, this use case is for increasing
319
-				// permissions for a specific user
320
-				if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
321
-					$message = 'Sharing failed, because this item is already shared with user %s';
322
-					throw new \Exception(sprintf($message, $shareWith));
323
-				}
324
-			}
325
-		}
326
-
327
-		// Put the item into the database
328
-		$result = self::put('test', $itemSource, self::SHARE_TYPE_USER, $shareWith, $uidOwner, $permissions);
329
-
330
-		return $result ? true : false;
331
-	}
332
-
333
-	/**
334
-	 * Unshare an item from a user, group, or delete a private link
335
-	 * @param string $itemType
336
-	 * @param string $itemSource
337
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
338
-	 * @param string $shareWith User or group the item is being shared with
339
-	 * @param string $owner owner of the share, if null the current user is used
340
-	 * @return boolean true on success or false on failure
341
-	 */
342
-	public static function unshare($itemType, $itemSource, $shareType, $shareWith, $owner = null) {
343
-
344
-		// check if it is a valid itemType
345
-		self::getBackend($itemType);
346
-
347
-		$items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, $owner, $shareType);
348
-
349
-		$toDelete = [];
350
-		$newParent = null;
351
-		$currentUser = $owner ? $owner : \OC_User::getUser();
352
-		foreach ($items as $item) {
353
-			// delete the item with the expected share_type and owner
354
-			if ((int)$item['share_type'] === (int)$shareType && $item['uid_owner'] === $currentUser) {
355
-				$toDelete = $item;
356
-				// if there is more then one result we don't have to delete the children
357
-				// but update their parent. For group shares the new parent should always be
358
-				// the original group share and not the db entry with the unique name
359
-			} else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
360
-				$newParent = $item['parent'];
361
-			} else {
362
-				$newParent = $item['id'];
363
-			}
364
-		}
365
-
366
-		if (!empty($toDelete)) {
367
-			self::unshareItem($toDelete, $newParent);
368
-			return true;
369
-		}
370
-		return false;
371
-	}
372
-
373
-	/**
374
-	 * Checks whether a share has expired, calls unshareItem() if yes.
375
-	 * @param array $item Share data (usually database row)
376
-	 * @return boolean True if item was expired, false otherwise.
377
-	 */
378
-	protected static function expireItem(array $item) {
379
-
380
-		$result = false;
381
-
382
-		// only use default expiration date for link shares
383
-		if ((int) $item['share_type'] === self::SHARE_TYPE_LINK) {
384
-
385
-			// calculate expiration date
386
-			if (!empty($item['expiration'])) {
387
-				$userDefinedExpire = new \DateTime($item['expiration']);
388
-				$expires = $userDefinedExpire->getTimestamp();
389
-			} else {
390
-				$expires = null;
391
-			}
392
-
393
-
394
-			// get default expiration settings
395
-			$defaultSettings = Helper::getDefaultExpireSetting();
396
-			$expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires);
397
-
398
-
399
-			if (is_int($expires)) {
400
-				$now = time();
401
-				if ($now > $expires) {
402
-					self::unshareItem($item);
403
-					$result = true;
404
-				}
405
-			}
406
-		}
407
-		return $result;
408
-	}
409
-
410
-	/**
411
-	 * Unshares a share given a share data array
412
-	 * @param array $item Share data (usually database row)
413
-	 * @param int $newParent parent ID
414
-	 * @return null
415
-	 */
416
-	protected static function unshareItem(array $item, $newParent = null) {
417
-
418
-		$shareType = (int)$item['share_type'];
419
-		$shareWith = null;
420
-		if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
421
-			$shareWith = $item['share_with'];
422
-		}
423
-
424
-		// Pass all the vars we have for now, they may be useful
425
-		$hookParams = [
426
-			'id'            => $item['id'],
427
-			'itemType'      => $item['item_type'],
428
-			'itemSource'    => $item['item_source'],
429
-			'shareType'     => $shareType,
430
-			'shareWith'     => $shareWith,
431
-			'itemParent'    => $item['parent'],
432
-			'uidOwner'      => $item['uid_owner'],
433
-		];
434
-		if($item['item_type'] === 'file' || $item['item_type'] === 'folder') {
435
-			$hookParams['fileSource'] = $item['file_source'];
436
-			$hookParams['fileTarget'] = $item['file_target'];
437
-		}
438
-
439
-		\OC_Hook::emit(\OCP\Share::class, 'pre_unshare', $hookParams);
440
-		$deletedShares = Helper::delete($item['id'], false, null, $newParent);
441
-		$deletedShares[] = $hookParams;
442
-		$hookParams['deletedShares'] = $deletedShares;
443
-		\OC_Hook::emit(\OCP\Share::class, 'post_unshare', $hookParams);
444
-		if ((int)$item['share_type'] === \OCP\Share::SHARE_TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
445
-			list(, $remote) = Helper::splitUserRemote($item['share_with']);
446
-			self::sendRemoteUnshare($remote, $item['id'], $item['token']);
447
-		}
448
-	}
449
-
450
-	/**
451
-	 * Get the backend class for the specified item type
452
-	 * @param string $itemType
453
-	 * @throws \Exception
454
-	 * @return \OCP\Share_Backend
455
-	 */
456
-	public static function getBackend($itemType) {
457
-		$l = \OC::$server->getL10N('lib');
458
-		if (isset(self::$backends[$itemType])) {
459
-			return self::$backends[$itemType];
460
-		} else if (isset(self::$backendTypes[$itemType]['class'])) {
461
-			$class = self::$backendTypes[$itemType]['class'];
462
-			if (class_exists($class)) {
463
-				self::$backends[$itemType] = new $class;
464
-				if (!(self::$backends[$itemType] instanceof \OCP\Share_Backend)) {
465
-					$message = 'Sharing backend %s must implement the interface OCP\Share_Backend';
466
-					$message_t = $l->t('Sharing backend %s must implement the interface OCP\Share_Backend', [$class]);
467
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $class), ILogger::ERROR);
468
-					throw new \Exception($message_t);
469
-				}
470
-				return self::$backends[$itemType];
471
-			} else {
472
-				$message = 'Sharing backend %s not found';
473
-				$message_t = $l->t('Sharing backend %s not found', [$class]);
474
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $class), ILogger::ERROR);
475
-				throw new \Exception($message_t);
476
-			}
477
-		}
478
-		$message = 'Sharing backend for %s not found';
479
-		$message_t = $l->t('Sharing backend for %s not found', [$itemType]);
480
-		\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemType), ILogger::ERROR);
481
-		throw new \Exception($message_t);
482
-	}
483
-
484
-	/**
485
-	 * Check if resharing is allowed
486
-	 * @return boolean true if allowed or false
487
-	 *
488
-	 * Resharing is allowed by default if not configured
489
-	 */
490
-	public static function isResharingAllowed() {
491
-		if (!isset(self::$isResharingAllowed)) {
492
-			if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') {
493
-				self::$isResharingAllowed = true;
494
-			} else {
495
-				self::$isResharingAllowed = false;
496
-			}
497
-		}
498
-		return self::$isResharingAllowed;
499
-	}
500
-
501
-	/**
502
-	 * Get a list of collection item types for the specified item type
503
-	 * @param string $itemType
504
-	 * @return array
505
-	 */
506
-	private static function getCollectionItemTypes($itemType) {
507
-		$collectionTypes = [$itemType];
508
-		foreach (self::$backendTypes as $type => $backend) {
509
-			if (in_array($backend['collectionOf'], $collectionTypes)) {
510
-				$collectionTypes[] = $type;
511
-			}
512
-		}
513
-		// TODO Add option for collections to be collection of themselves, only 'folder' does it now...
514
-		if (isset(self::$backendTypes[$itemType]) && (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder')) {
515
-			unset($collectionTypes[0]);
516
-		}
517
-		// Return array if collections were found or the item type is a
518
-		// collection itself - collections can be inside collections
519
-		if (count($collectionTypes) > 0) {
520
-			return $collectionTypes;
521
-		}
522
-		return false;
523
-	}
524
-
525
-	/**
526
-	 * Get the owners of items shared with a user.
527
-	 *
528
-	 * @param string $user The user the items are shared with.
529
-	 * @param string $type The type of the items shared with the user.
530
-	 * @param boolean $includeCollections Include collection item types (optional)
531
-	 * @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
532
-	 * @return array
533
-	 * @deprecated TESTS ONLY - this methods is only used by tests
534
-	 * called like this:
535
-	 * \OC\Share\Share::getSharedItemsOwners($this->user, $this->type, true)
536
-	 */
537
-	public static function getSharedItemsOwners($user, $type, $includeCollections = false, $includeOwner = false) {
538
-		// First, we find out if $type is part of a collection (and if that collection is part of
539
-		// another one and so on).
540
-		$collectionTypes = [];
541
-		if (!$includeCollections || !$collectionTypes = self::getCollectionItemTypes($type)) {
542
-			$collectionTypes[] = $type;
543
-		}
544
-
545
-		// Of these collection types, along with our original $type, we make a
546
-		// list of the ones for which a sharing backend has been registered.
547
-		// FIXME: Ideally, we wouldn't need to nest getItemsSharedWith in this loop but just call it
548
-		// with its $includeCollections parameter set to true. Unfortunately, this fails currently.
549
-		$allMaybeSharedItems = [];
550
-		foreach ($collectionTypes as $collectionType) {
551
-			if (isset(self::$backends[$collectionType])) {
552
-				$allMaybeSharedItems[$collectionType] = self::getItemsSharedWithUser(
553
-					$collectionType,
554
-					$user,
555
-					self::FORMAT_NONE
556
-				);
557
-			}
558
-		}
559
-
560
-		$owners = [];
561
-		if ($includeOwner) {
562
-			$owners[] = $user;
563
-		}
564
-
565
-		// We take a look at all shared items of the given $type (or of the collections it is part of)
566
-		// and find out their owners. Then, we gather the tags for the original $type from all owners,
567
-		// and return them as elements of a list that look like "Tag (owner)".
568
-		foreach ($allMaybeSharedItems as $collectionType => $maybeSharedItems) {
569
-			foreach ($maybeSharedItems as $sharedItem) {
570
-				if (isset($sharedItem['id'])) { //workaround for https://github.com/owncloud/core/issues/2814
571
-					$owners[] = $sharedItem['uid_owner'];
572
-				}
573
-			}
574
-		}
575
-
576
-		return $owners;
577
-	}
578
-
579
-	/**
580
-	 * Get shared items from the database
581
-	 * @param string $itemType
582
-	 * @param string $item Item source or target (optional)
583
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
584
-	 * @param string $shareWith User or group the item is being shared with
585
-	 * @param string $uidOwner User that is the owner of shared items (optional)
586
-	 * @param int $format Format to convert items to with formatItems() (optional)
587
-	 * @param mixed $parameters to pass to formatItems() (optional)
588
-	 * @param int $limit Number of items to return, -1 to return all matches (optional)
589
-	 * @param boolean $includeCollections Include collection item types (optional)
590
-	 * @param boolean $itemShareWithBySource (optional)
591
-	 * @param boolean $checkExpireDate
592
-	 * @return array
593
-	 *
594
-	 * See public functions getItem(s)... for parameter usage
595
-	 *
596
-	 */
597
-	public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
598
-									$uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
599
-									$includeCollections = false, $itemShareWithBySource = false, $checkExpireDate  = true) {
600
-		if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') != 'yes') {
601
-			return [];
602
-		}
603
-		$backend = self::getBackend($itemType);
604
-		$collectionTypes = false;
605
-		// Get filesystem root to add it to the file target and remove from the
606
-		// file source, match file_source with the file cache
607
-		if ($itemType == 'file' || $itemType == 'folder') {
608
-			if(!is_null($uidOwner)) {
609
-				$root = \OC\Files\Filesystem::getRoot();
610
-			} else {
611
-				$root = '';
612
-			}
613
-			$where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
614
-			if (!isset($item)) {
615
-				$where .= ' AND `file_target` IS NOT NULL ';
616
-			}
617
-			$where .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
618
-			$fileDependent = true;
619
-			$queryArgs = [];
620
-		} else {
621
-			$fileDependent = false;
622
-			$root = '';
623
-			$collectionTypes = self::getCollectionItemTypes($itemType);
624
-			if ($includeCollections && !isset($item) && $collectionTypes) {
625
-				// If includeCollections is true, find collections of this item type, e.g. a music album contains songs
626
-				if (!in_array($itemType, $collectionTypes)) {
627
-					$itemTypes = array_merge([$itemType], $collectionTypes);
628
-				} else {
629
-					$itemTypes = $collectionTypes;
630
-				}
631
-				$placeholders = implode(',', array_fill(0, count($itemTypes), '?'));
632
-				$where = ' WHERE `item_type` IN ('.$placeholders.'))';
633
-				$queryArgs = $itemTypes;
634
-			} else {
635
-				$where = ' WHERE `item_type` = ?';
636
-				$queryArgs = [$itemType];
637
-			}
638
-		}
639
-		if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
640
-			$where .= ' AND `share_type` != ?';
641
-			$queryArgs[] = self::SHARE_TYPE_LINK;
642
-		}
643
-		if (isset($shareType)) {
644
-			// Include all user and group items
645
-			if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
646
-				$where .= ' AND ((`share_type` in (?, ?) AND `share_with` = ?) ';
647
-				$queryArgs[] = self::SHARE_TYPE_USER;
648
-				$queryArgs[] = self::$shareTypeGroupUserUnique;
649
-				$queryArgs[] = $shareWith;
650
-
651
-				$user = \OC::$server->getUserManager()->get($shareWith);
652
-				$groups = [];
653
-				if ($user) {
654
-					$groups = \OC::$server->getGroupManager()->getUserGroupIds($user);
655
-				}
656
-				if (!empty($groups)) {
657
-					$placeholders = implode(',', array_fill(0, count($groups), '?'));
658
-					$where .= ' OR (`share_type` = ? AND `share_with` IN ('.$placeholders.')) ';
659
-					$queryArgs[] = self::SHARE_TYPE_GROUP;
660
-					$queryArgs = array_merge($queryArgs, $groups);
661
-				}
662
-				$where .= ')';
663
-				// Don't include own group shares
664
-				$where .= ' AND `uid_owner` != ?';
665
-				$queryArgs[] = $shareWith;
666
-			} else {
667
-				$where .= ' AND `share_type` = ?';
668
-				$queryArgs[] = $shareType;
669
-				if (isset($shareWith)) {
670
-					$where .= ' AND `share_with` = ?';
671
-					$queryArgs[] = $shareWith;
672
-				}
673
-			}
674
-		}
675
-		if (isset($uidOwner)) {
676
-			$where .= ' AND `uid_owner` = ?';
677
-			$queryArgs[] = $uidOwner;
678
-			if (!isset($shareType)) {
679
-				// Prevent unique user targets for group shares from being selected
680
-				$where .= ' AND `share_type` != ?';
681
-				$queryArgs[] = self::$shareTypeGroupUserUnique;
682
-			}
683
-			if ($fileDependent) {
684
-				$column = 'file_source';
685
-			} else {
686
-				$column = 'item_source';
687
-			}
688
-		} else {
689
-			if ($fileDependent) {
690
-				$column = 'file_target';
691
-			} else {
692
-				$column = 'item_target';
693
-			}
694
-		}
695
-		if (isset($item)) {
696
-			$collectionTypes = self::getCollectionItemTypes($itemType);
697
-			if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
698
-				$where .= ' AND (';
699
-			} else {
700
-				$where .= ' AND';
701
-			}
702
-			// If looking for own shared items, check item_source else check item_target
703
-			if (isset($uidOwner) || $itemShareWithBySource) {
704
-				// If item type is a file, file source needs to be checked in case the item was converted
705
-				if ($fileDependent) {
706
-					$where .= ' `file_source` = ?';
707
-					$column = 'file_source';
708
-				} else {
709
-					$where .= ' `item_source` = ?';
710
-					$column = 'item_source';
711
-				}
712
-			} else {
713
-				if ($fileDependent) {
714
-					$where .= ' `file_target` = ?';
715
-					$item = \OC\Files\Filesystem::normalizePath($item);
716
-				} else {
717
-					$where .= ' `item_target` = ?';
718
-				}
719
-			}
720
-			$queryArgs[] = $item;
721
-			if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
722
-				$placeholders = implode(',', array_fill(0, count($collectionTypes), '?'));
723
-				$where .= ' OR `item_type` IN ('.$placeholders.'))';
724
-				$queryArgs = array_merge($queryArgs, $collectionTypes);
725
-			}
726
-		}
727
-
728
-		if ($shareType == self::$shareTypeUserAndGroups && $limit === 1) {
729
-			// Make sure the unique user target is returned if it exists,
730
-			// unique targets should follow the group share in the database
731
-			// If the limit is not 1, the filtering can be done later
732
-			$where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
733
-		} else {
734
-			$where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
735
-		}
736
-
737
-		if ($limit != -1 && !$includeCollections) {
738
-			// The limit must be at least 3, because filtering needs to be done
739
-			if ($limit < 3) {
740
-				$queryLimit = 3;
741
-			} else {
742
-				$queryLimit = $limit;
743
-			}
744
-		} else {
745
-			$queryLimit = null;
746
-		}
747
-		$select = self::createSelectStatement($format, $fileDependent, $uidOwner);
748
-		$root = strlen($root);
749
-		$query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
750
-		$result = $query->execute($queryArgs);
751
-		if ($result === false) {
752
-			\OCP\Util::writeLog('OCP\Share',
753
-				\OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
754
-				ILogger::ERROR);
755
-		}
756
-		$items = [];
757
-		$targets = [];
758
-		$switchedItems = [];
759
-		$mounts = [];
760
-		while ($row = $result->fetchRow()) {
761
-			self::transformDBResults($row);
762
-			// Filter out duplicate group shares for users with unique targets
763
-			if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
764
-				continue;
765
-			}
766
-			if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
767
-				$row['share_type'] = self::SHARE_TYPE_GROUP;
768
-				$row['unique_name'] = true; // remember that we use a unique name for this user
769
-				$row['share_with'] = $items[$row['parent']]['share_with'];
770
-				// if the group share was unshared from the user we keep the permission, otherwise
771
-				// we take the permission from the parent because this is always the up-to-date
772
-				// permission for the group share
773
-				if ($row['permissions'] > 0) {
774
-					$row['permissions'] = $items[$row['parent']]['permissions'];
775
-				}
776
-				// Remove the parent group share
777
-				unset($items[$row['parent']]);
778
-				if ($row['permissions'] == 0) {
779
-					continue;
780
-				}
781
-			} else if (!isset($uidOwner)) {
782
-				// Check if the same target already exists
783
-				if (isset($targets[$row['id']])) {
784
-					// Check if the same owner shared with the user twice
785
-					// through a group and user share - this is allowed
786
-					$id = $targets[$row['id']];
787
-					if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) {
788
-						// Switch to group share type to ensure resharing conditions aren't bypassed
789
-						if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
790
-							$items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
791
-							$items[$id]['share_with'] = $row['share_with'];
792
-						}
793
-						// Switch ids if sharing permission is granted on only
794
-						// one share to ensure correct parent is used if resharing
795
-						if (~(int)$items[$id]['permissions'] & \OCP\Constants::PERMISSION_SHARE
796
-							&& (int)$row['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
797
-							$items[$row['id']] = $items[$id];
798
-							$switchedItems[$id] = $row['id'];
799
-							unset($items[$id]);
800
-							$id = $row['id'];
801
-						}
802
-						$items[$id]['permissions'] |= (int)$row['permissions'];
803
-
804
-					}
805
-					continue;
806
-				} elseif (!empty($row['parent'])) {
807
-					$targets[$row['parent']] = $row['id'];
808
-				}
809
-			}
810
-			// Remove root from file source paths if retrieving own shared items
811
-			if (isset($uidOwner) && isset($row['path'])) {
812
-				if (isset($row['parent'])) {
813
-					$query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
814
-					$parentResult = $query->execute([$row['parent']]);
815
-					if ($result === false) {
816
-						\OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
817
-							\OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
818
-							ILogger::ERROR);
819
-					} else {
820
-						$parentRow = $parentResult->fetchRow();
821
-						$tmpPath = $parentRow['file_target'];
822
-						// find the right position where the row path continues from the target path
823
-						$pos = strrpos($row['path'], $parentRow['file_target']);
824
-						$subPath = substr($row['path'], $pos);
825
-						$splitPath = explode('/', $subPath);
826
-						foreach (array_slice($splitPath, 2) as $pathPart) {
827
-							$tmpPath = $tmpPath . '/' . $pathPart;
828
-						}
829
-						$row['path'] = $tmpPath;
830
-					}
831
-				} else {
832
-					if (!isset($mounts[$row['storage']])) {
833
-						$mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']);
834
-						if (is_array($mountPoints) && !empty($mountPoints)) {
835
-							$mounts[$row['storage']] = current($mountPoints);
836
-						}
837
-					}
838
-					if (!empty($mounts[$row['storage']])) {
839
-						$path = $mounts[$row['storage']]->getMountPoint().$row['path'];
840
-						$relPath = substr($path, $root); // path relative to data/user
841
-						$row['path'] = rtrim($relPath, '/');
842
-					}
843
-				}
844
-			}
845
-
846
-			if($checkExpireDate) {
847
-				if (self::expireItem($row)) {
848
-					continue;
849
-				}
850
-			}
851
-			// Check if resharing is allowed, if not remove share permission
852
-			if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) {
853
-				$row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE;
854
-			}
855
-			// Add display names to result
856
-			$row['share_with_displayname'] = $row['share_with'];
857
-			if ( isset($row['share_with']) && $row['share_with'] != '' &&
858
-				$row['share_type'] === self::SHARE_TYPE_USER) {
859
-				$shareWithUser = \OC::$server->getUserManager()->get($row['share_with']);
860
-				$row['share_with_displayname'] = $shareWithUser === null ? $row['share_with'] : $shareWithUser->getDisplayName();
861
-			} else if(isset($row['share_with']) && $row['share_with'] != '' &&
862
-				$row['share_type'] === self::SHARE_TYPE_REMOTE) {
863
-				$addressBookEntries = \OC::$server->getContactsManager()->search($row['share_with'], ['CLOUD']);
864
-				foreach ($addressBookEntries as $entry) {
865
-					foreach ($entry['CLOUD'] as $cloudID) {
866
-						if ($cloudID === $row['share_with']) {
867
-							$row['share_with_displayname'] = $entry['FN'];
868
-						}
869
-					}
870
-				}
871
-			}
872
-			if ( isset($row['uid_owner']) && $row['uid_owner'] != '') {
873
-				$ownerUser = \OC::$server->getUserManager()->get($row['uid_owner']);
874
-				$row['displayname_owner'] = $ownerUser === null ? $row['uid_owner'] : $ownerUser->getDisplayName();
875
-			}
876
-
877
-			if ($row['permissions'] > 0) {
878
-				$items[$row['id']] = $row;
879
-			}
880
-
881
-		}
882
-
883
-		// group items if we are looking for items shared with the current user
884
-		if (isset($shareWith) && $shareWith === \OCP\User::getUser()) {
885
-			$items = self::groupItems($items, $itemType);
886
-		}
887
-
888
-		if (!empty($items)) {
889
-			$collectionItems = [];
890
-			foreach ($items as &$row) {
891
-				// Return only the item instead of a 2-dimensional array
892
-				if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) {
893
-					if ($format == self::FORMAT_NONE) {
894
-						return $row;
895
-					} else {
896
-						break;
897
-					}
898
-				}
899
-				// Check if this is a collection of the requested item type
900
-				if ($includeCollections && $collectionTypes && $row['item_type'] !== 'folder' && in_array($row['item_type'], $collectionTypes)) {
901
-					if (($collectionBackend = self::getBackend($row['item_type']))
902
-						&& $collectionBackend instanceof \OCP\Share_Backend_Collection) {
903
-						// Collections can be inside collections, check if the item is a collection
904
-						if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) {
905
-							$collectionItems[] = $row;
906
-						} else {
907
-							$collection = [];
908
-							$collection['item_type'] = $row['item_type'];
909
-							if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
910
-								$collection['path'] = basename($row['path']);
911
-							}
912
-							$row['collection'] = $collection;
913
-							// Fetch all of the children sources
914
-							$children = $collectionBackend->getChildren($row[$column]);
915
-							foreach ($children as $child) {
916
-								$childItem = $row;
917
-								$childItem['item_type'] = $itemType;
918
-								if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') {
919
-									$childItem['item_source'] = $child['source'];
920
-									$childItem['item_target'] = $child['target'];
921
-								}
922
-								if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
923
-									if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
924
-										$childItem['file_source'] = $child['source'];
925
-									} else { // TODO is this really needed if we already know that we use the file backend?
926
-										$meta = \OC\Files\Filesystem::getFileInfo($child['file_path']);
927
-										$childItem['file_source'] = $meta['fileid'];
928
-									}
929
-									$childItem['file_target'] =
930
-										\OC\Files\Filesystem::normalizePath($child['file_path']);
931
-								}
932
-								if (isset($item)) {
933
-									if ($childItem[$column] == $item) {
934
-										// Return only the item instead of a 2-dimensional array
935
-										if ($limit == 1) {
936
-											if ($format == self::FORMAT_NONE) {
937
-												return $childItem;
938
-											} else {
939
-												// Unset the items array and break out of both loops
940
-												$items = [];
941
-												$items[] = $childItem;
942
-												break 2;
943
-											}
944
-										} else {
945
-											$collectionItems[] = $childItem;
946
-										}
947
-									}
948
-								} else {
949
-									$collectionItems[] = $childItem;
950
-								}
951
-							}
952
-						}
953
-					}
954
-					// Remove collection item
955
-					$toRemove = $row['id'];
956
-					if (array_key_exists($toRemove, $switchedItems)) {
957
-						$toRemove = $switchedItems[$toRemove];
958
-					}
959
-					unset($items[$toRemove]);
960
-				} elseif ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) {
961
-					// FIXME: Thats a dirty hack to improve file sharing performance,
962
-					// see github issue #10588 for more details
963
-					// Need to find a solution which works for all back-ends
964
-					$collectionBackend = self::getBackend($row['item_type']);
965
-					$sharedParents = $collectionBackend->getParents($row['item_source']);
966
-					foreach ($sharedParents as $parent) {
967
-						$collectionItems[] = $parent;
968
-					}
969
-				}
970
-			}
971
-			if (!empty($collectionItems)) {
972
-				$collectionItems = array_unique($collectionItems, SORT_REGULAR);
973
-				$items = array_merge($items, $collectionItems);
974
-			}
975
-
976
-			// filter out invalid items, these can appear when subshare entries exist
977
-			// for a group in which the requested user isn't a member any more
978
-			$items = array_filter($items, function($item) {
979
-				return $item['share_type'] !== self::$shareTypeGroupUserUnique;
980
-			});
981
-
982
-			return self::formatResult($items, $column, $backend, $format, $parameters);
983
-		} elseif ($includeCollections && $collectionTypes && in_array('folder', $collectionTypes)) {
984
-			// FIXME: Thats a dirty hack to improve file sharing performance,
985
-			// see github issue #10588 for more details
986
-			// Need to find a solution which works for all back-ends
987
-			$collectionItems = [];
988
-			$collectionBackend = self::getBackend('folder');
989
-			$sharedParents = $collectionBackend->getParents($item, $shareWith, $uidOwner);
990
-			foreach ($sharedParents as $parent) {
991
-				$collectionItems[] = $parent;
992
-			}
993
-			if ($limit === 1) {
994
-				return reset($collectionItems);
995
-			}
996
-			return self::formatResult($collectionItems, $column, $backend, $format, $parameters);
997
-		}
998
-
999
-		return [];
1000
-	}
1001
-
1002
-	/**
1003
-	 * group items with link to the same source
1004
-	 *
1005
-	 * @param array $items
1006
-	 * @param string $itemType
1007
-	 * @return array of grouped items
1008
-	 */
1009
-	protected static function groupItems($items, $itemType) {
1010
-
1011
-		$fileSharing = $itemType === 'file' || $itemType === 'folder';
1012
-
1013
-		$result = [];
1014
-
1015
-		foreach ($items as $item) {
1016
-			$grouped = false;
1017
-			foreach ($result as $key => $r) {
1018
-				// for file/folder shares we need to compare file_source, otherwise we compare item_source
1019
-				// only group shares if they already point to the same target, otherwise the file where shared
1020
-				// before grouping of shares was added. In this case we don't group them toi avoid confusions
1021
-				if (( $fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) ||
1022
-					(!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) {
1023
-					// add the first item to the list of grouped shares
1024
-					if (!isset($result[$key]['grouped'])) {
1025
-						$result[$key]['grouped'][] = $result[$key];
1026
-					}
1027
-					$result[$key]['permissions'] = (int) $item['permissions'] | (int) $r['permissions'];
1028
-					$result[$key]['grouped'][] = $item;
1029
-					$grouped = true;
1030
-					break;
1031
-				}
1032
-			}
1033
-
1034
-			if (!$grouped) {
1035
-				$result[] = $item;
1036
-			}
1037
-
1038
-		}
1039
-
1040
-		return $result;
1041
-	}
1042
-
1043
-	/**
1044
-	 * Put shared item into the database
1045
-	 * @param string $itemType Item type
1046
-	 * @param string $itemSource Item source
1047
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1048
-	 * @param string $shareWith User or group the item is being shared with
1049
-	 * @param string $uidOwner User that is the owner of shared item
1050
-	 * @param int $permissions CRUDS permissions
1051
-	 * @throws \Exception
1052
-	 * @return mixed id of the new share or false
1053
-	 * @deprecated TESTS ONLY - this methods is only used by tests
1054
-	 * called like this:
1055
-	 * self::put('test', $itemSource, self::SHARE_TYPE_USER, $shareWith, $uidOwner, $permissions);
1056
-	 */
1057
-	private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1058
-								$permissions) {
1059
-
1060
-		$queriesToExecute = [];
1061
-		$suggestedItemTarget = null;
1062
-		$groupFileTarget = $fileTarget = $suggestedFileTarget = $filePath = '';
1063
-		$groupItemTarget = $itemTarget = $fileSource = $parent = 0;
1064
-
1065
-		$result = self::checkReshare('test', $itemSource, self::SHARE_TYPE_USER, $shareWith, $uidOwner, $permissions, null, null);
1066
-		if(!empty($result)) {
1067
-			$parent = $result['parent'];
1068
-			$itemSource = $result['itemSource'];
1069
-			$fileSource = $result['fileSource'];
1070
-			$suggestedItemTarget = $result['suggestedItemTarget'];
1071
-			$suggestedFileTarget = $result['suggestedFileTarget'];
1072
-			$filePath = $result['filePath'];
1073
-		}
1074
-
1075
-		$isGroupShare = false;
1076
-			$users = [$shareWith];
1077
-			$itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1078
-				$suggestedItemTarget);
1079
-
1080
-		$run = true;
1081
-		$error = '';
1082
-		$preHookData = [
1083
-			'itemType' => $itemType,
1084
-			'itemSource' => $itemSource,
1085
-			'shareType' => $shareType,
1086
-			'uidOwner' => $uidOwner,
1087
-			'permissions' => $permissions,
1088
-			'fileSource' => $fileSource,
1089
-			'expiration' => null,
1090
-			'token' => null,
1091
-			'run' => &$run,
1092
-			'error' => &$error
1093
-		];
1094
-
1095
-		$preHookData['itemTarget'] = $itemTarget;
1096
-		$preHookData['shareWith'] = $shareWith;
1097
-
1098
-		\OC_Hook::emit(\OCP\Share::class, 'pre_shared', $preHookData);
1099
-
1100
-		if ($run === false) {
1101
-			throw new \Exception($error);
1102
-		}
1103
-
1104
-		foreach ($users as $user) {
1105
-			$sourceId = ($itemType === 'file' || $itemType === 'folder') ? $fileSource : $itemSource;
1106
-			$sourceExists = self::getItemSharedWithBySource($itemType, $sourceId, self::FORMAT_NONE, null, true, $user);
1107
-
1108
-			$userShareType = $shareType;
1109
-
1110
-			if ($sourceExists && $sourceExists['item_source'] === $itemSource) {
1111
-				$fileTarget = $sourceExists['file_target'];
1112
-				$itemTarget = $sourceExists['item_target'];
1113
-
1114
-			} elseif(!$sourceExists)  {
1115
-
1116
-				$itemTarget = Helper::generateTarget($itemType, $itemSource, $userShareType, $user,
1117
-					$uidOwner, $suggestedItemTarget, $parent);
1118
-				if (isset($fileSource)) {
1119
-						$fileTarget = Helper::generateTarget('file', $filePath, $userShareType,
1120
-							$user, $uidOwner, $suggestedFileTarget, $parent);
1121
-				} else {
1122
-					$fileTarget = null;
1123
-				}
1124
-
1125
-			} else {
1126
-
1127
-				// group share which doesn't exists until now, check if we need a unique target for this user
1128
-
1129
-				$itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $user,
1130
-					$uidOwner, $suggestedItemTarget, $parent);
1131
-
1132
-				// do we also need a file target
1133
-				if (isset($fileSource)) {
1134
-					$fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user,
1135
-						$uidOwner, $suggestedFileTarget, $parent);
1136
-				} else {
1137
-					$fileTarget = null;
1138
-				}
1139
-
1140
-				if (($itemTarget === $groupItemTarget) &&
1141
-					(!isset($fileSource) || $fileTarget === $groupFileTarget)) {
1142
-					continue;
1143
-				}
1144
-			}
1145
-
1146
-			$queriesToExecute[] = [
1147
-				'itemType'			=> $itemType,
1148
-				'itemSource'		=> $itemSource,
1149
-				'itemTarget'		=> $itemTarget,
1150
-				'shareType'			=> $userShareType,
1151
-				'shareWith'			=> $user,
1152
-				'uidOwner'			=> $uidOwner,
1153
-				'permissions'		=> $permissions,
1154
-				'shareTime'			=> time(),
1155
-				'fileSource'		=> $fileSource,
1156
-				'fileTarget'		=> $fileTarget,
1157
-				'token'				=> null,
1158
-				'parent'			=> $parent,
1159
-				'expiration'		=> null,
1160
-			];
1161
-
1162
-		}
1163
-
1164
-		$id = false;
1165
-
1166
-		foreach ($queriesToExecute as $shareQuery) {
1167
-			$shareQuery['parent'] = $parent;
1168
-			$id = self::insertShare($shareQuery);
1169
-		}
1170
-
1171
-		$postHookData = [
1172
-			'itemType' => $itemType,
1173
-			'itemSource' => $itemSource,
1174
-			'parent' => $parent,
1175
-			'shareType' => $shareType,
1176
-			'uidOwner' => $uidOwner,
1177
-			'permissions' => $permissions,
1178
-			'fileSource' => $fileSource,
1179
-			'id' => $parent,
1180
-			'token' => null,
1181
-			'expirationDate' => null,
1182
-		];
1183
-
1184
-		$postHookData['shareWith'] = $isGroupShare ? $shareWith['group'] : $shareWith;
1185
-		$postHookData['itemTarget'] = $isGroupShare ? $groupItemTarget : $itemTarget;
1186
-		$postHookData['fileTarget'] = $isGroupShare ? $groupFileTarget : $fileTarget;
1187
-
1188
-		\OC_Hook::emit(\OCP\Share::class, 'post_shared', $postHookData);
1189
-
1190
-
1191
-		return $id ? $id : false;
1192
-	}
1193
-
1194
-	/**
1195
-	 * @param string $itemType
1196
-	 * @param string $itemSource
1197
-	 * @param int $shareType
1198
-	 * @param string $shareWith
1199
-	 * @param string $uidOwner
1200
-	 * @param int $permissions
1201
-	 * @param string|null $itemSourceName
1202
-	 * @param null|\DateTime $expirationDate
1203
-	 * @deprecated TESTS ONLY - this methods is only used by tests
1204
-	 * called like this:
1205
-	 * self::checkReshare('test', $itemSource, self::SHARE_TYPE_USER, $shareWith, $uidOwner, $permissions, null, null);
1206
-	 */
1207
-	private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) {
1208
-		$backend = self::getBackend($itemType);
1209
-
1210
-		$result = [];
1211
-
1212
-		$column = ($itemType === 'file' || $itemType === 'folder') ? 'file_source' : 'item_source';
1213
-
1214
-		$checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true);
1215
-		if ($checkReshare) {
1216
-			// Check if attempting to share back to owner
1217
-			if ($checkReshare['uid_owner'] == $shareWith) {
1218
-				$message = 'Sharing %1$s failed, because the user %2$s is the original sharer';
1219
-				throw new \Exception(sprintf($message, $itemSourceName, $shareWith));
1220
-			}
1221
-		}
1222
-
1223
-		if ($checkReshare && $checkReshare['uid_owner'] !== \OC_User::getUser()) {
1224
-			// Check if share permissions is granted
1225
-			if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1226
-				if (~(int)$checkReshare['permissions'] & $permissions) {
1227
-					$message = 'Sharing %1$s failed, because the permissions exceed permissions granted to %2$s';
1228
-					throw new \Exception(sprintf($message, $itemSourceName, $uidOwner));
1229
-				} else {
1230
-					// TODO Don't check if inside folder
1231
-					$result['parent'] = $checkReshare['id'];
1232
-
1233
-					$result['expirationDate'] = $expirationDate;
1234
-					// $checkReshare['expiration'] could be null and then is always less than any value
1235
-					if(isset($checkReshare['expiration']) && $checkReshare['expiration'] < $expirationDate) {
1236
-						$result['expirationDate'] = $checkReshare['expiration'];
1237
-					}
1238
-
1239
-					// only suggest the same name as new target if it is a reshare of the
1240
-					// same file/folder and not the reshare of a child
1241
-					if ($checkReshare[$column] === $itemSource) {
1242
-						$result['filePath'] = $checkReshare['file_target'];
1243
-						$result['itemSource'] = $checkReshare['item_source'];
1244
-						$result['fileSource'] = $checkReshare['file_source'];
1245
-						$result['suggestedItemTarget'] = $checkReshare['item_target'];
1246
-						$result['suggestedFileTarget'] = $checkReshare['file_target'];
1247
-					} else {
1248
-						$result['filePath'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $backend->getFilePath($itemSource, $uidOwner) : null;
1249
-						$result['suggestedItemTarget'] = null;
1250
-						$result['suggestedFileTarget'] = null;
1251
-						$result['itemSource'] = $itemSource;
1252
-						$result['fileSource'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $itemSource : null;
1253
-					}
1254
-				}
1255
-			} else {
1256
-				$message = 'Sharing %s failed, because resharing is not allowed';
1257
-				throw new \Exception(sprintf($message, $itemSourceName));
1258
-			}
1259
-		} else {
1260
-			$result['parent'] = null;
1261
-			$result['suggestedItemTarget'] = null;
1262
-			$result['suggestedFileTarget'] = null;
1263
-			$result['itemSource'] = $itemSource;
1264
-			$result['expirationDate'] = $expirationDate;
1265
-			if (!$backend->isValidSource($itemSource, $uidOwner)) {
1266
-				$message = 'Sharing %1$s failed, because the sharing backend for '
1267
-					.'%2$s could not find its source';
1268
-				throw new \Exception(sprintf($message, $itemSource, $itemType));
1269
-			}
1270
-			if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
1271
-				$result['filePath'] = $backend->getFilePath($itemSource, $uidOwner);
1272
-					$meta = \OC\Files\Filesystem::getFileInfo($result['filePath']);
1273
-					$result['fileSource'] = $meta['fileid'];
1274
-				if ($result['fileSource'] == -1) {
1275
-					$message = 'Sharing %s failed, because the file could not be found in the file cache';
1276
-					throw new \Exception(sprintf($message, $itemSource));
1277
-				}
1278
-			} else {
1279
-				$result['filePath'] = null;
1280
-				$result['fileSource'] = null;
1281
-			}
1282
-		}
1283
-
1284
-		return $result;
1285
-	}
1286
-
1287
-	/**
1288
-	 *
1289
-	 * @param array $shareData
1290
-	 * @return mixed false in case of a failure or the id of the new share
1291
-	 */
1292
-	private static function insertShare(array $shareData) {
1293
-
1294
-		$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
1295
-			.' `item_type`, `item_source`, `item_target`, `share_type`,'
1296
-			.' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
1297
-			.' `file_target`, `token`, `parent`, `expiration`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)');
1298
-		$query->bindValue(1, $shareData['itemType']);
1299
-		$query->bindValue(2, $shareData['itemSource']);
1300
-		$query->bindValue(3, $shareData['itemTarget']);
1301
-		$query->bindValue(4, $shareData['shareType']);
1302
-		$query->bindValue(5, $shareData['shareWith']);
1303
-		$query->bindValue(6, $shareData['uidOwner']);
1304
-		$query->bindValue(7, $shareData['permissions']);
1305
-		$query->bindValue(8, $shareData['shareTime']);
1306
-		$query->bindValue(9, $shareData['fileSource']);
1307
-		$query->bindValue(10, $shareData['fileTarget']);
1308
-		$query->bindValue(11, $shareData['token']);
1309
-		$query->bindValue(12, $shareData['parent']);
1310
-		$query->bindValue(13, $shareData['expiration'], 'datetime');
1311
-		$result = $query->execute();
1312
-
1313
-		$id = false;
1314
-		if ($result) {
1315
-			$id =  \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
1316
-		}
1317
-
1318
-		return $id;
1319
-
1320
-	}
1321
-
1322
-	/**
1323
-	 * construct select statement
1324
-	 * @param int $format
1325
-	 * @param boolean $fileDependent ist it a file/folder share or a generla share
1326
-	 * @param string $uidOwner
1327
-	 * @return string select statement
1328
-	 */
1329
-	private static function createSelectStatement($format, $fileDependent, $uidOwner = null) {
1330
-		$select = '*';
1331
-		if ($format == self::FORMAT_STATUSES) {
1332
-			if ($fileDependent) {
1333
-				$select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `storage`, '
1334
-					. '`share_with`, `uid_owner` , `file_source`, `stime`, `*PREFIX*share`.`permissions`, '
1335
-					. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1336
-					. '`uid_initiator`';
1337
-			} else {
1338
-				$select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`';
1339
-			}
1340
-		} else {
1341
-			if (isset($uidOwner)) {
1342
-				if ($fileDependent) {
1343
-					$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,'
1344
-						. ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
1345
-						. ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`, '
1346
-						. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1347
-				} else {
1348
-					$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
1349
-						. ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
1350
-				}
1351
-			} else {
1352
-				if ($fileDependent) {
1353
-					if ($format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_GET_FOLDER_CONTENTS || $format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_FILE_APP_ROOT) {
1354
-						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
1355
-							. '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
1356
-							. '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1357
-							. '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
1358
-					} else {
1359
-						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,'
1360
-							. '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,'
1361
-							. '`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`,'
1362
-							. '`stime`, `expiration`, `token`, `storage`, `mail_send`,'
1363
-							. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1364
-					}
1365
-				}
1366
-			}
1367
-		}
1368
-		return $select;
1369
-	}
1370
-
1371
-
1372
-	/**
1373
-	 * transform db results
1374
-	 * @param array $row result
1375
-	 */
1376
-	private static function transformDBResults(&$row) {
1377
-		if (isset($row['id'])) {
1378
-			$row['id'] = (int) $row['id'];
1379
-		}
1380
-		if (isset($row['share_type'])) {
1381
-			$row['share_type'] = (int) $row['share_type'];
1382
-		}
1383
-		if (isset($row['parent'])) {
1384
-			$row['parent'] = (int) $row['parent'];
1385
-		}
1386
-		if (isset($row['file_parent'])) {
1387
-			$row['file_parent'] = (int) $row['file_parent'];
1388
-		}
1389
-		if (isset($row['file_source'])) {
1390
-			$row['file_source'] = (int) $row['file_source'];
1391
-		}
1392
-		if (isset($row['permissions'])) {
1393
-			$row['permissions'] = (int) $row['permissions'];
1394
-		}
1395
-		if (isset($row['storage'])) {
1396
-			$row['storage'] = (int) $row['storage'];
1397
-		}
1398
-		if (isset($row['stime'])) {
1399
-			$row['stime'] = (int) $row['stime'];
1400
-		}
1401
-		if (isset($row['expiration']) && $row['share_type'] !== self::SHARE_TYPE_LINK) {
1402
-			// discard expiration date for non-link shares, which might have been
1403
-			// set by ancient bugs
1404
-			$row['expiration'] = null;
1405
-		}
1406
-	}
1407
-
1408
-	/**
1409
-	 * format result
1410
-	 * @param array $items result
1411
-	 * @param string $column is it a file share or a general share ('file_target' or 'item_target')
1412
-	 * @param \OCP\Share_Backend $backend sharing backend
1413
-	 * @param int $format
1414
-	 * @param array $parameters additional format parameters
1415
-	 * @return array format result
1416
-	 */
1417
-	private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE , $parameters = null) {
1418
-		if ($format === self::FORMAT_NONE) {
1419
-			return $items;
1420
-		} else if ($format === self::FORMAT_STATUSES) {
1421
-			$statuses = [];
1422
-			foreach ($items as $item) {
1423
-				if ($item['share_type'] === self::SHARE_TYPE_LINK) {
1424
-					if ($item['uid_initiator'] !== \OC::$server->getUserSession()->getUser()->getUID()) {
1425
-						continue;
1426
-					}
1427
-					$statuses[$item[$column]]['link'] = true;
1428
-				} else if (!isset($statuses[$item[$column]])) {
1429
-					$statuses[$item[$column]]['link'] = false;
1430
-				}
1431
-				if (!empty($item['file_target'])) {
1432
-					$statuses[$item[$column]]['path'] = $item['path'];
1433
-				}
1434
-			}
1435
-			return $statuses;
1436
-		} else {
1437
-			return $backend->formatItems($items, $format, $parameters);
1438
-		}
1439
-	}
1440
-
1441
-	/**
1442
-	 * remove protocol from URL
1443
-	 *
1444
-	 * @param string $url
1445
-	 * @return string
1446
-	 */
1447
-	public static function removeProtocolFromUrl($url) {
1448
-		if (strpos($url, 'https://') === 0) {
1449
-			return substr($url, strlen('https://'));
1450
-		} else if (strpos($url, 'http://') === 0) {
1451
-			return substr($url, strlen('http://'));
1452
-		}
1453
-
1454
-		return $url;
1455
-	}
1456
-
1457
-	/**
1458
-	 * try http post first with https and then with http as a fallback
1459
-	 *
1460
-	 * @param string $remoteDomain
1461
-	 * @param string $urlSuffix
1462
-	 * @param array $fields post parameters
1463
-	 * @return array
1464
-	 */
1465
-	private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) {
1466
-		$protocol = 'https://';
1467
-		$result = [
1468
-			'success' => false,
1469
-			'result' => '',
1470
-		];
1471
-		$try = 0;
1472
-		$discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
1473
-		while ($result['success'] === false && $try < 2) {
1474
-			$federationEndpoints = $discoveryService->discover($protocol . $remoteDomain, 'FEDERATED_SHARING');
1475
-			$endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
1476
-			$client = \OC::$server->getHTTPClientService()->newClient();
1477
-
1478
-			try {
1479
-				$response = $client->post(
1480
-					$protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT,
1481
-					[
1482
-						'body' => $fields,
1483
-						'connect_timeout' => 10,
1484
-					]
1485
-				);
1486
-
1487
-				$result = ['success' => true, 'result' => $response->getBody()];
1488
-			} catch (\Exception $e) {
1489
-				$result = ['success' => false, 'result' => $e->getMessage()];
1490
-			}
1491
-
1492
-			$try++;
1493
-			$protocol = 'http://';
1494
-		}
1495
-
1496
-		return $result;
1497
-	}
1498
-
1499
-	/**
1500
-	 * send server-to-server unshare to remote server
1501
-	 *
1502
-	 * @param string $remote url
1503
-	 * @param int $id share id
1504
-	 * @param string $token
1505
-	 * @return bool
1506
-	 */
1507
-	private static function sendRemoteUnshare($remote, $id, $token) {
1508
-		$url = rtrim($remote, '/');
1509
-		$fields = ['token' => $token, 'format' => 'json'];
1510
-		$url = self::removeProtocolFromUrl($url);
1511
-		$result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
1512
-		$status = json_decode($result['result'], true);
1513
-
1514
-		return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200));
1515
-	}
1516
-
1517
-	/**
1518
-	 * @return int
1519
-	 */
1520
-	public static function getExpireInterval() {
1521
-		return (int)\OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1522
-	}
1523
-
1524
-	/**
1525
-	 * Checks whether the given path is reachable for the given owner
1526
-	 *
1527
-	 * @param string $path path relative to files
1528
-	 * @param string $ownerStorageId storage id of the owner
1529
-	 *
1530
-	 * @return boolean true if file is reachable, false otherwise
1531
-	 */
1532
-	private static function isFileReachable($path, $ownerStorageId) {
1533
-		// if outside the home storage, file is always considered reachable
1534
-		if (!(substr($ownerStorageId, 0, 6) === 'home::' ||
1535
-			substr($ownerStorageId, 0, 13) === 'object::user:'
1536
-		)) {
1537
-			return true;
1538
-		}
1539
-
1540
-		// if inside the home storage, the file has to be under "/files/"
1541
-		$path = ltrim($path, '/');
1542
-		if (substr($path, 0, 6) === 'files/') {
1543
-			return true;
1544
-		}
1545
-
1546
-		return false;
1547
-	}
52
+    /** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask
53
+     * Construct permissions for share() and setPermissions with Or (|) e.g.
54
+     * Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE
55
+     *
56
+     * Check if permission is granted with And (&) e.g. Check if delete is
57
+     * granted: if ($permissions & PERMISSION_DELETE)
58
+     *
59
+     * Remove permissions with And (&) and Not (~) e.g. Remove the update
60
+     * permission: $permissions &= ~PERMISSION_UPDATE
61
+     *
62
+     * Apps are required to handle permissions on their own, this class only
63
+     * stores and manages the permissions of shares
64
+     * @see lib/public/constants.php
65
+     */
66
+
67
+    /**
68
+     * Register a sharing backend class that implements OCP\Share_Backend for an item type
69
+     * @param string $itemType Item type
70
+     * @param string $class Backend class
71
+     * @param string $collectionOf (optional) Depends on item type
72
+     * @param array $supportedFileExtensions (optional) List of supported file extensions if this item type depends on files
73
+     * @return boolean true if backend is registered or false if error
74
+     */
75
+    public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) {
76
+        if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') == 'yes') {
77
+            if (!isset(self::$backendTypes[$itemType])) {
78
+                self::$backendTypes[$itemType] = [
79
+                    'class' => $class,
80
+                    'collectionOf' => $collectionOf,
81
+                    'supportedFileExtensions' => $supportedFileExtensions
82
+                ];
83
+                return true;
84
+            }
85
+            \OCP\Util::writeLog('OCP\Share',
86
+                'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class']
87
+                .' is already registered for '.$itemType,
88
+                ILogger::WARN);
89
+        }
90
+        return false;
91
+    }
92
+
93
+    /**
94
+     * Get the items of item type shared with the current user
95
+     * @param string $itemType
96
+     * @param int $format (optional) Format type must be defined by the backend
97
+     * @param mixed $parameters (optional)
98
+     * @param int $limit Number of items to return (optional) Returns all by default
99
+     * @param boolean $includeCollections (optional)
100
+     * @return mixed Return depends on format
101
+     * @deprecated TESTS ONLY - this methods is only used by tests
102
+     * called like this:
103
+     * \OC\Share\Share::getItemsSharedWith('folder'); (apps/files_sharing/tests/UpdaterTest.php)
104
+     */
105
+    public static function getItemsSharedWith() {
106
+        return self::getItems('folder', null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, self::FORMAT_NONE,
107
+            null, -1, false);
108
+    }
109
+
110
+    /**
111
+     * Get the items of item type shared with a user
112
+     * @param string $itemType
113
+     * @param string $user id for which user we want the shares
114
+     * @param int $format (optional) Format type must be defined by the backend
115
+     * @param mixed $parameters (optional)
116
+     * @param int $limit Number of items to return (optional) Returns all by default
117
+     * @param boolean $includeCollections (optional)
118
+     * @return mixed Return depends on format
119
+     */
120
+    public static function getItemsSharedWithUser($itemType, $user, $format = self::FORMAT_NONE,
121
+                                                    $parameters = null, $limit = -1, $includeCollections = false) {
122
+        return self::getItems($itemType, null, self::$shareTypeUserAndGroups, $user, null, $format,
123
+            $parameters, $limit, $includeCollections);
124
+    }
125
+
126
+    /**
127
+     * Get the item of item type shared with a given user by source
128
+     * @param string $itemType
129
+     * @param string $itemSource
130
+     * @param string $user User to whom the item was shared
131
+     * @param string $owner Owner of the share
132
+     * @param int $shareType only look for a specific share type
133
+     * @return array Return list of items with file_target, permissions and expiration
134
+     */
135
+    public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null, $shareType = null) {
136
+        $shares = [];
137
+        $fileDependent = false;
138
+
139
+        $where = 'WHERE';
140
+        $fileDependentWhere = '';
141
+        if ($itemType === 'file' || $itemType === 'folder') {
142
+            $fileDependent = true;
143
+            $column = 'file_source';
144
+            $fileDependentWhere = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
145
+            $fileDependentWhere .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
146
+        } else {
147
+            $column = 'item_source';
148
+        }
149
+
150
+        $select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent);
151
+
152
+        $where .= ' `' . $column . '` = ? AND `item_type` = ? ';
153
+        $arguments = [$itemSource, $itemType];
154
+        // for link shares $user === null
155
+        if ($user !== null) {
156
+            $where .= ' AND `share_with` = ? ';
157
+            $arguments[] = $user;
158
+        }
159
+
160
+        if ($shareType !== null) {
161
+            $where .= ' AND `share_type` = ? ';
162
+            $arguments[] = $shareType;
163
+        }
164
+
165
+        if ($owner !== null) {
166
+            $where .= ' AND `uid_owner` = ? ';
167
+            $arguments[] = $owner;
168
+        }
169
+
170
+        $query = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` '. $fileDependentWhere . $where);
171
+
172
+        $result = \OC_DB::executeAudited($query, $arguments);
173
+
174
+        while ($row = $result->fetchRow()) {
175
+            if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
176
+                continue;
177
+            }
178
+            if ($fileDependent && (int)$row['file_parent'] === -1) {
179
+                // if it is a mount point we need to get the path from the mount manager
180
+                $mountManager = \OC\Files\Filesystem::getMountManager();
181
+                $mountPoint = $mountManager->findByStorageId($row['storage_id']);
182
+                if (!empty($mountPoint)) {
183
+                    $path = $mountPoint[0]->getMountPoint();
184
+                    $path = trim($path, '/');
185
+                    $path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt`
186
+                    $row['path'] = $path;
187
+                } else {
188
+                    \OC::$server->getLogger()->warning(
189
+                        'Could not resolve mount point for ' . $row['storage_id'],
190
+                        ['app' => 'OCP\Share']
191
+                    );
192
+                }
193
+            }
194
+            $shares[] = $row;
195
+        }
196
+
197
+        //if didn't found a result than let's look for a group share.
198
+        if(empty($shares) && $user !== null) {
199
+            $userObject = \OC::$server->getUserManager()->get($user);
200
+            $groups = [];
201
+            if ($userObject) {
202
+                $groups = \OC::$server->getGroupManager()->getUserGroupIds($userObject);
203
+            }
204
+
205
+            if (!empty($groups)) {
206
+                $where = $fileDependentWhere . ' WHERE `' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)';
207
+                $arguments = [$itemSource, $itemType, $groups];
208
+                $types = [null, null, IQueryBuilder::PARAM_STR_ARRAY];
209
+
210
+                if ($owner !== null) {
211
+                    $where .= ' AND `uid_owner` = ?';
212
+                    $arguments[] = $owner;
213
+                    $types[] = null;
214
+                }
215
+
216
+                // TODO: inject connection, hopefully one day in the future when this
217
+                // class isn't static anymore...
218
+                $conn = \OC::$server->getDatabaseConnection();
219
+                $result = $conn->executeQuery(
220
+                    'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
221
+                    $arguments,
222
+                    $types
223
+                );
224
+
225
+                while ($row = $result->fetch()) {
226
+                    $shares[] = $row;
227
+                }
228
+            }
229
+        }
230
+
231
+        return $shares;
232
+
233
+    }
234
+
235
+    /**
236
+     * Get the item of item type shared with the current user by source
237
+     * @param string $itemType
238
+     * @param string $itemSource
239
+     * @param int $format (optional) Format type must be defined by the backend
240
+     * @param mixed $parameters
241
+     * @param boolean $includeCollections
242
+     * @param string $shareWith (optional) define against which user should be checked, default: current user
243
+     * @return array
244
+     */
245
+    public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
246
+                                                        $parameters = null, $includeCollections = false, $shareWith = null) {
247
+        $shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith;
248
+        return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format,
249
+            $parameters, 1, $includeCollections, true);
250
+    }
251
+
252
+    /**
253
+     * Get the shared item of item type owned by the current user
254
+     * @param string $itemType
255
+     * @param string $itemSource
256
+     * @param int $format (optional) Format type must be defined by the backend
257
+     * @param mixed $parameters
258
+     * @param boolean $includeCollections
259
+     * @return mixed Return depends on format
260
+     */
261
+    public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
262
+                                            $parameters = null, $includeCollections = false) {
263
+        return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
264
+            $parameters, -1, $includeCollections);
265
+    }
266
+
267
+    /**
268
+     * Share an item with a user, group, or via private link
269
+     * @param string $itemType
270
+     * @param string $itemSource
271
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
272
+     * @param string $shareWith User or group the item is being shared with
273
+     * @param int $permissions CRUDS
274
+     * @param string $itemSourceName
275
+     * @param \DateTime|null $expirationDate
276
+     * @return boolean|string Returns true on success or false on failure, Returns token on success for links
277
+     * @throws \OC\HintException when the share type is remote and the shareWith is invalid
278
+     * @throws \Exception
279
+     * @since 5.0.0 - parameter $itemSourceName was added in 6.0.0, parameter $expirationDate was added in 7.0.0, parameter $passwordChanged added in 9.0.0
280
+     * @deprecated 14.0.0 TESTS ONLY - this methods is as of 2018-06 only used by tests
281
+     * called like this:
282
+     * \OC\Share\Share::shareItem('test', 1, \OCP\Share::SHARE_TYPE_USER, $otherUserId, \OCP\Constants::PERMISSION_READ);
283
+     */
284
+    public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions) {
285
+        $backend = self::getBackend($itemType);
286
+
287
+        if ($backend->isShareTypeAllowed($shareType) === false) {
288
+            $message = 'Sharing failed, because the backend does not allow shares from type %i';
289
+            throw new \Exception(sprintf($message, $shareType));
290
+        }
291
+
292
+        $uidOwner = \OC_User::getUser();
293
+
294
+        // Verify share type and sharing conditions are met
295
+        if ($shareType === self::SHARE_TYPE_USER) {
296
+            if ($shareWith == $uidOwner) {
297
+                $message = 'Sharing failed, because you can not share with yourself';
298
+                throw new \Exception($message);
299
+            }
300
+            if (!\OC::$server->getUserManager()->userExists($shareWith)) {
301
+                $message = 'Sharing failed, because the user %s does not exist';
302
+                throw new \Exception(sprintf($message, $shareWith));
303
+            }
304
+            // Check if the item source is already shared with the user, either from the same owner or a different user
305
+            if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups,
306
+                $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
307
+                // Only allow the same share to occur again if it is the same
308
+                // owner and is not a user share, this use case is for increasing
309
+                // permissions for a specific user
310
+                if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
311
+                    $message = 'Sharing failed, because this item is already shared with %s';
312
+                    throw new \Exception(sprintf($message, $shareWith));
313
+                }
314
+            }
315
+            if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_USER,
316
+                $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
317
+                // Only allow the same share to occur again if it is the same
318
+                // owner and is not a user share, this use case is for increasing
319
+                // permissions for a specific user
320
+                if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
321
+                    $message = 'Sharing failed, because this item is already shared with user %s';
322
+                    throw new \Exception(sprintf($message, $shareWith));
323
+                }
324
+            }
325
+        }
326
+
327
+        // Put the item into the database
328
+        $result = self::put('test', $itemSource, self::SHARE_TYPE_USER, $shareWith, $uidOwner, $permissions);
329
+
330
+        return $result ? true : false;
331
+    }
332
+
333
+    /**
334
+     * Unshare an item from a user, group, or delete a private link
335
+     * @param string $itemType
336
+     * @param string $itemSource
337
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
338
+     * @param string $shareWith User or group the item is being shared with
339
+     * @param string $owner owner of the share, if null the current user is used
340
+     * @return boolean true on success or false on failure
341
+     */
342
+    public static function unshare($itemType, $itemSource, $shareType, $shareWith, $owner = null) {
343
+
344
+        // check if it is a valid itemType
345
+        self::getBackend($itemType);
346
+
347
+        $items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, $owner, $shareType);
348
+
349
+        $toDelete = [];
350
+        $newParent = null;
351
+        $currentUser = $owner ? $owner : \OC_User::getUser();
352
+        foreach ($items as $item) {
353
+            // delete the item with the expected share_type and owner
354
+            if ((int)$item['share_type'] === (int)$shareType && $item['uid_owner'] === $currentUser) {
355
+                $toDelete = $item;
356
+                // if there is more then one result we don't have to delete the children
357
+                // but update their parent. For group shares the new parent should always be
358
+                // the original group share and not the db entry with the unique name
359
+            } else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
360
+                $newParent = $item['parent'];
361
+            } else {
362
+                $newParent = $item['id'];
363
+            }
364
+        }
365
+
366
+        if (!empty($toDelete)) {
367
+            self::unshareItem($toDelete, $newParent);
368
+            return true;
369
+        }
370
+        return false;
371
+    }
372
+
373
+    /**
374
+     * Checks whether a share has expired, calls unshareItem() if yes.
375
+     * @param array $item Share data (usually database row)
376
+     * @return boolean True if item was expired, false otherwise.
377
+     */
378
+    protected static function expireItem(array $item) {
379
+
380
+        $result = false;
381
+
382
+        // only use default expiration date for link shares
383
+        if ((int) $item['share_type'] === self::SHARE_TYPE_LINK) {
384
+
385
+            // calculate expiration date
386
+            if (!empty($item['expiration'])) {
387
+                $userDefinedExpire = new \DateTime($item['expiration']);
388
+                $expires = $userDefinedExpire->getTimestamp();
389
+            } else {
390
+                $expires = null;
391
+            }
392
+
393
+
394
+            // get default expiration settings
395
+            $defaultSettings = Helper::getDefaultExpireSetting();
396
+            $expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires);
397
+
398
+
399
+            if (is_int($expires)) {
400
+                $now = time();
401
+                if ($now > $expires) {
402
+                    self::unshareItem($item);
403
+                    $result = true;
404
+                }
405
+            }
406
+        }
407
+        return $result;
408
+    }
409
+
410
+    /**
411
+     * Unshares a share given a share data array
412
+     * @param array $item Share data (usually database row)
413
+     * @param int $newParent parent ID
414
+     * @return null
415
+     */
416
+    protected static function unshareItem(array $item, $newParent = null) {
417
+
418
+        $shareType = (int)$item['share_type'];
419
+        $shareWith = null;
420
+        if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
421
+            $shareWith = $item['share_with'];
422
+        }
423
+
424
+        // Pass all the vars we have for now, they may be useful
425
+        $hookParams = [
426
+            'id'            => $item['id'],
427
+            'itemType'      => $item['item_type'],
428
+            'itemSource'    => $item['item_source'],
429
+            'shareType'     => $shareType,
430
+            'shareWith'     => $shareWith,
431
+            'itemParent'    => $item['parent'],
432
+            'uidOwner'      => $item['uid_owner'],
433
+        ];
434
+        if($item['item_type'] === 'file' || $item['item_type'] === 'folder') {
435
+            $hookParams['fileSource'] = $item['file_source'];
436
+            $hookParams['fileTarget'] = $item['file_target'];
437
+        }
438
+
439
+        \OC_Hook::emit(\OCP\Share::class, 'pre_unshare', $hookParams);
440
+        $deletedShares = Helper::delete($item['id'], false, null, $newParent);
441
+        $deletedShares[] = $hookParams;
442
+        $hookParams['deletedShares'] = $deletedShares;
443
+        \OC_Hook::emit(\OCP\Share::class, 'post_unshare', $hookParams);
444
+        if ((int)$item['share_type'] === \OCP\Share::SHARE_TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
445
+            list(, $remote) = Helper::splitUserRemote($item['share_with']);
446
+            self::sendRemoteUnshare($remote, $item['id'], $item['token']);
447
+        }
448
+    }
449
+
450
+    /**
451
+     * Get the backend class for the specified item type
452
+     * @param string $itemType
453
+     * @throws \Exception
454
+     * @return \OCP\Share_Backend
455
+     */
456
+    public static function getBackend($itemType) {
457
+        $l = \OC::$server->getL10N('lib');
458
+        if (isset(self::$backends[$itemType])) {
459
+            return self::$backends[$itemType];
460
+        } else if (isset(self::$backendTypes[$itemType]['class'])) {
461
+            $class = self::$backendTypes[$itemType]['class'];
462
+            if (class_exists($class)) {
463
+                self::$backends[$itemType] = new $class;
464
+                if (!(self::$backends[$itemType] instanceof \OCP\Share_Backend)) {
465
+                    $message = 'Sharing backend %s must implement the interface OCP\Share_Backend';
466
+                    $message_t = $l->t('Sharing backend %s must implement the interface OCP\Share_Backend', [$class]);
467
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $class), ILogger::ERROR);
468
+                    throw new \Exception($message_t);
469
+                }
470
+                return self::$backends[$itemType];
471
+            } else {
472
+                $message = 'Sharing backend %s not found';
473
+                $message_t = $l->t('Sharing backend %s not found', [$class]);
474
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $class), ILogger::ERROR);
475
+                throw new \Exception($message_t);
476
+            }
477
+        }
478
+        $message = 'Sharing backend for %s not found';
479
+        $message_t = $l->t('Sharing backend for %s not found', [$itemType]);
480
+        \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemType), ILogger::ERROR);
481
+        throw new \Exception($message_t);
482
+    }
483
+
484
+    /**
485
+     * Check if resharing is allowed
486
+     * @return boolean true if allowed or false
487
+     *
488
+     * Resharing is allowed by default if not configured
489
+     */
490
+    public static function isResharingAllowed() {
491
+        if (!isset(self::$isResharingAllowed)) {
492
+            if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') {
493
+                self::$isResharingAllowed = true;
494
+            } else {
495
+                self::$isResharingAllowed = false;
496
+            }
497
+        }
498
+        return self::$isResharingAllowed;
499
+    }
500
+
501
+    /**
502
+     * Get a list of collection item types for the specified item type
503
+     * @param string $itemType
504
+     * @return array
505
+     */
506
+    private static function getCollectionItemTypes($itemType) {
507
+        $collectionTypes = [$itemType];
508
+        foreach (self::$backendTypes as $type => $backend) {
509
+            if (in_array($backend['collectionOf'], $collectionTypes)) {
510
+                $collectionTypes[] = $type;
511
+            }
512
+        }
513
+        // TODO Add option for collections to be collection of themselves, only 'folder' does it now...
514
+        if (isset(self::$backendTypes[$itemType]) && (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder')) {
515
+            unset($collectionTypes[0]);
516
+        }
517
+        // Return array if collections were found or the item type is a
518
+        // collection itself - collections can be inside collections
519
+        if (count($collectionTypes) > 0) {
520
+            return $collectionTypes;
521
+        }
522
+        return false;
523
+    }
524
+
525
+    /**
526
+     * Get the owners of items shared with a user.
527
+     *
528
+     * @param string $user The user the items are shared with.
529
+     * @param string $type The type of the items shared with the user.
530
+     * @param boolean $includeCollections Include collection item types (optional)
531
+     * @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
532
+     * @return array
533
+     * @deprecated TESTS ONLY - this methods is only used by tests
534
+     * called like this:
535
+     * \OC\Share\Share::getSharedItemsOwners($this->user, $this->type, true)
536
+     */
537
+    public static function getSharedItemsOwners($user, $type, $includeCollections = false, $includeOwner = false) {
538
+        // First, we find out if $type is part of a collection (and if that collection is part of
539
+        // another one and so on).
540
+        $collectionTypes = [];
541
+        if (!$includeCollections || !$collectionTypes = self::getCollectionItemTypes($type)) {
542
+            $collectionTypes[] = $type;
543
+        }
544
+
545
+        // Of these collection types, along with our original $type, we make a
546
+        // list of the ones for which a sharing backend has been registered.
547
+        // FIXME: Ideally, we wouldn't need to nest getItemsSharedWith in this loop but just call it
548
+        // with its $includeCollections parameter set to true. Unfortunately, this fails currently.
549
+        $allMaybeSharedItems = [];
550
+        foreach ($collectionTypes as $collectionType) {
551
+            if (isset(self::$backends[$collectionType])) {
552
+                $allMaybeSharedItems[$collectionType] = self::getItemsSharedWithUser(
553
+                    $collectionType,
554
+                    $user,
555
+                    self::FORMAT_NONE
556
+                );
557
+            }
558
+        }
559
+
560
+        $owners = [];
561
+        if ($includeOwner) {
562
+            $owners[] = $user;
563
+        }
564
+
565
+        // We take a look at all shared items of the given $type (or of the collections it is part of)
566
+        // and find out their owners. Then, we gather the tags for the original $type from all owners,
567
+        // and return them as elements of a list that look like "Tag (owner)".
568
+        foreach ($allMaybeSharedItems as $collectionType => $maybeSharedItems) {
569
+            foreach ($maybeSharedItems as $sharedItem) {
570
+                if (isset($sharedItem['id'])) { //workaround for https://github.com/owncloud/core/issues/2814
571
+                    $owners[] = $sharedItem['uid_owner'];
572
+                }
573
+            }
574
+        }
575
+
576
+        return $owners;
577
+    }
578
+
579
+    /**
580
+     * Get shared items from the database
581
+     * @param string $itemType
582
+     * @param string $item Item source or target (optional)
583
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
584
+     * @param string $shareWith User or group the item is being shared with
585
+     * @param string $uidOwner User that is the owner of shared items (optional)
586
+     * @param int $format Format to convert items to with formatItems() (optional)
587
+     * @param mixed $parameters to pass to formatItems() (optional)
588
+     * @param int $limit Number of items to return, -1 to return all matches (optional)
589
+     * @param boolean $includeCollections Include collection item types (optional)
590
+     * @param boolean $itemShareWithBySource (optional)
591
+     * @param boolean $checkExpireDate
592
+     * @return array
593
+     *
594
+     * See public functions getItem(s)... for parameter usage
595
+     *
596
+     */
597
+    public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
598
+                                    $uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
599
+                                    $includeCollections = false, $itemShareWithBySource = false, $checkExpireDate  = true) {
600
+        if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') != 'yes') {
601
+            return [];
602
+        }
603
+        $backend = self::getBackend($itemType);
604
+        $collectionTypes = false;
605
+        // Get filesystem root to add it to the file target and remove from the
606
+        // file source, match file_source with the file cache
607
+        if ($itemType == 'file' || $itemType == 'folder') {
608
+            if(!is_null($uidOwner)) {
609
+                $root = \OC\Files\Filesystem::getRoot();
610
+            } else {
611
+                $root = '';
612
+            }
613
+            $where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
614
+            if (!isset($item)) {
615
+                $where .= ' AND `file_target` IS NOT NULL ';
616
+            }
617
+            $where .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
618
+            $fileDependent = true;
619
+            $queryArgs = [];
620
+        } else {
621
+            $fileDependent = false;
622
+            $root = '';
623
+            $collectionTypes = self::getCollectionItemTypes($itemType);
624
+            if ($includeCollections && !isset($item) && $collectionTypes) {
625
+                // If includeCollections is true, find collections of this item type, e.g. a music album contains songs
626
+                if (!in_array($itemType, $collectionTypes)) {
627
+                    $itemTypes = array_merge([$itemType], $collectionTypes);
628
+                } else {
629
+                    $itemTypes = $collectionTypes;
630
+                }
631
+                $placeholders = implode(',', array_fill(0, count($itemTypes), '?'));
632
+                $where = ' WHERE `item_type` IN ('.$placeholders.'))';
633
+                $queryArgs = $itemTypes;
634
+            } else {
635
+                $where = ' WHERE `item_type` = ?';
636
+                $queryArgs = [$itemType];
637
+            }
638
+        }
639
+        if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
640
+            $where .= ' AND `share_type` != ?';
641
+            $queryArgs[] = self::SHARE_TYPE_LINK;
642
+        }
643
+        if (isset($shareType)) {
644
+            // Include all user and group items
645
+            if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
646
+                $where .= ' AND ((`share_type` in (?, ?) AND `share_with` = ?) ';
647
+                $queryArgs[] = self::SHARE_TYPE_USER;
648
+                $queryArgs[] = self::$shareTypeGroupUserUnique;
649
+                $queryArgs[] = $shareWith;
650
+
651
+                $user = \OC::$server->getUserManager()->get($shareWith);
652
+                $groups = [];
653
+                if ($user) {
654
+                    $groups = \OC::$server->getGroupManager()->getUserGroupIds($user);
655
+                }
656
+                if (!empty($groups)) {
657
+                    $placeholders = implode(',', array_fill(0, count($groups), '?'));
658
+                    $where .= ' OR (`share_type` = ? AND `share_with` IN ('.$placeholders.')) ';
659
+                    $queryArgs[] = self::SHARE_TYPE_GROUP;
660
+                    $queryArgs = array_merge($queryArgs, $groups);
661
+                }
662
+                $where .= ')';
663
+                // Don't include own group shares
664
+                $where .= ' AND `uid_owner` != ?';
665
+                $queryArgs[] = $shareWith;
666
+            } else {
667
+                $where .= ' AND `share_type` = ?';
668
+                $queryArgs[] = $shareType;
669
+                if (isset($shareWith)) {
670
+                    $where .= ' AND `share_with` = ?';
671
+                    $queryArgs[] = $shareWith;
672
+                }
673
+            }
674
+        }
675
+        if (isset($uidOwner)) {
676
+            $where .= ' AND `uid_owner` = ?';
677
+            $queryArgs[] = $uidOwner;
678
+            if (!isset($shareType)) {
679
+                // Prevent unique user targets for group shares from being selected
680
+                $where .= ' AND `share_type` != ?';
681
+                $queryArgs[] = self::$shareTypeGroupUserUnique;
682
+            }
683
+            if ($fileDependent) {
684
+                $column = 'file_source';
685
+            } else {
686
+                $column = 'item_source';
687
+            }
688
+        } else {
689
+            if ($fileDependent) {
690
+                $column = 'file_target';
691
+            } else {
692
+                $column = 'item_target';
693
+            }
694
+        }
695
+        if (isset($item)) {
696
+            $collectionTypes = self::getCollectionItemTypes($itemType);
697
+            if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
698
+                $where .= ' AND (';
699
+            } else {
700
+                $where .= ' AND';
701
+            }
702
+            // If looking for own shared items, check item_source else check item_target
703
+            if (isset($uidOwner) || $itemShareWithBySource) {
704
+                // If item type is a file, file source needs to be checked in case the item was converted
705
+                if ($fileDependent) {
706
+                    $where .= ' `file_source` = ?';
707
+                    $column = 'file_source';
708
+                } else {
709
+                    $where .= ' `item_source` = ?';
710
+                    $column = 'item_source';
711
+                }
712
+            } else {
713
+                if ($fileDependent) {
714
+                    $where .= ' `file_target` = ?';
715
+                    $item = \OC\Files\Filesystem::normalizePath($item);
716
+                } else {
717
+                    $where .= ' `item_target` = ?';
718
+                }
719
+            }
720
+            $queryArgs[] = $item;
721
+            if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
722
+                $placeholders = implode(',', array_fill(0, count($collectionTypes), '?'));
723
+                $where .= ' OR `item_type` IN ('.$placeholders.'))';
724
+                $queryArgs = array_merge($queryArgs, $collectionTypes);
725
+            }
726
+        }
727
+
728
+        if ($shareType == self::$shareTypeUserAndGroups && $limit === 1) {
729
+            // Make sure the unique user target is returned if it exists,
730
+            // unique targets should follow the group share in the database
731
+            // If the limit is not 1, the filtering can be done later
732
+            $where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
733
+        } else {
734
+            $where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
735
+        }
736
+
737
+        if ($limit != -1 && !$includeCollections) {
738
+            // The limit must be at least 3, because filtering needs to be done
739
+            if ($limit < 3) {
740
+                $queryLimit = 3;
741
+            } else {
742
+                $queryLimit = $limit;
743
+            }
744
+        } else {
745
+            $queryLimit = null;
746
+        }
747
+        $select = self::createSelectStatement($format, $fileDependent, $uidOwner);
748
+        $root = strlen($root);
749
+        $query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
750
+        $result = $query->execute($queryArgs);
751
+        if ($result === false) {
752
+            \OCP\Util::writeLog('OCP\Share',
753
+                \OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
754
+                ILogger::ERROR);
755
+        }
756
+        $items = [];
757
+        $targets = [];
758
+        $switchedItems = [];
759
+        $mounts = [];
760
+        while ($row = $result->fetchRow()) {
761
+            self::transformDBResults($row);
762
+            // Filter out duplicate group shares for users with unique targets
763
+            if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
764
+                continue;
765
+            }
766
+            if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
767
+                $row['share_type'] = self::SHARE_TYPE_GROUP;
768
+                $row['unique_name'] = true; // remember that we use a unique name for this user
769
+                $row['share_with'] = $items[$row['parent']]['share_with'];
770
+                // if the group share was unshared from the user we keep the permission, otherwise
771
+                // we take the permission from the parent because this is always the up-to-date
772
+                // permission for the group share
773
+                if ($row['permissions'] > 0) {
774
+                    $row['permissions'] = $items[$row['parent']]['permissions'];
775
+                }
776
+                // Remove the parent group share
777
+                unset($items[$row['parent']]);
778
+                if ($row['permissions'] == 0) {
779
+                    continue;
780
+                }
781
+            } else if (!isset($uidOwner)) {
782
+                // Check if the same target already exists
783
+                if (isset($targets[$row['id']])) {
784
+                    // Check if the same owner shared with the user twice
785
+                    // through a group and user share - this is allowed
786
+                    $id = $targets[$row['id']];
787
+                    if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) {
788
+                        // Switch to group share type to ensure resharing conditions aren't bypassed
789
+                        if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
790
+                            $items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
791
+                            $items[$id]['share_with'] = $row['share_with'];
792
+                        }
793
+                        // Switch ids if sharing permission is granted on only
794
+                        // one share to ensure correct parent is used if resharing
795
+                        if (~(int)$items[$id]['permissions'] & \OCP\Constants::PERMISSION_SHARE
796
+                            && (int)$row['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
797
+                            $items[$row['id']] = $items[$id];
798
+                            $switchedItems[$id] = $row['id'];
799
+                            unset($items[$id]);
800
+                            $id = $row['id'];
801
+                        }
802
+                        $items[$id]['permissions'] |= (int)$row['permissions'];
803
+
804
+                    }
805
+                    continue;
806
+                } elseif (!empty($row['parent'])) {
807
+                    $targets[$row['parent']] = $row['id'];
808
+                }
809
+            }
810
+            // Remove root from file source paths if retrieving own shared items
811
+            if (isset($uidOwner) && isset($row['path'])) {
812
+                if (isset($row['parent'])) {
813
+                    $query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
814
+                    $parentResult = $query->execute([$row['parent']]);
815
+                    if ($result === false) {
816
+                        \OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
817
+                            \OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
818
+                            ILogger::ERROR);
819
+                    } else {
820
+                        $parentRow = $parentResult->fetchRow();
821
+                        $tmpPath = $parentRow['file_target'];
822
+                        // find the right position where the row path continues from the target path
823
+                        $pos = strrpos($row['path'], $parentRow['file_target']);
824
+                        $subPath = substr($row['path'], $pos);
825
+                        $splitPath = explode('/', $subPath);
826
+                        foreach (array_slice($splitPath, 2) as $pathPart) {
827
+                            $tmpPath = $tmpPath . '/' . $pathPart;
828
+                        }
829
+                        $row['path'] = $tmpPath;
830
+                    }
831
+                } else {
832
+                    if (!isset($mounts[$row['storage']])) {
833
+                        $mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']);
834
+                        if (is_array($mountPoints) && !empty($mountPoints)) {
835
+                            $mounts[$row['storage']] = current($mountPoints);
836
+                        }
837
+                    }
838
+                    if (!empty($mounts[$row['storage']])) {
839
+                        $path = $mounts[$row['storage']]->getMountPoint().$row['path'];
840
+                        $relPath = substr($path, $root); // path relative to data/user
841
+                        $row['path'] = rtrim($relPath, '/');
842
+                    }
843
+                }
844
+            }
845
+
846
+            if($checkExpireDate) {
847
+                if (self::expireItem($row)) {
848
+                    continue;
849
+                }
850
+            }
851
+            // Check if resharing is allowed, if not remove share permission
852
+            if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) {
853
+                $row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE;
854
+            }
855
+            // Add display names to result
856
+            $row['share_with_displayname'] = $row['share_with'];
857
+            if ( isset($row['share_with']) && $row['share_with'] != '' &&
858
+                $row['share_type'] === self::SHARE_TYPE_USER) {
859
+                $shareWithUser = \OC::$server->getUserManager()->get($row['share_with']);
860
+                $row['share_with_displayname'] = $shareWithUser === null ? $row['share_with'] : $shareWithUser->getDisplayName();
861
+            } else if(isset($row['share_with']) && $row['share_with'] != '' &&
862
+                $row['share_type'] === self::SHARE_TYPE_REMOTE) {
863
+                $addressBookEntries = \OC::$server->getContactsManager()->search($row['share_with'], ['CLOUD']);
864
+                foreach ($addressBookEntries as $entry) {
865
+                    foreach ($entry['CLOUD'] as $cloudID) {
866
+                        if ($cloudID === $row['share_with']) {
867
+                            $row['share_with_displayname'] = $entry['FN'];
868
+                        }
869
+                    }
870
+                }
871
+            }
872
+            if ( isset($row['uid_owner']) && $row['uid_owner'] != '') {
873
+                $ownerUser = \OC::$server->getUserManager()->get($row['uid_owner']);
874
+                $row['displayname_owner'] = $ownerUser === null ? $row['uid_owner'] : $ownerUser->getDisplayName();
875
+            }
876
+
877
+            if ($row['permissions'] > 0) {
878
+                $items[$row['id']] = $row;
879
+            }
880
+
881
+        }
882
+
883
+        // group items if we are looking for items shared with the current user
884
+        if (isset($shareWith) && $shareWith === \OCP\User::getUser()) {
885
+            $items = self::groupItems($items, $itemType);
886
+        }
887
+
888
+        if (!empty($items)) {
889
+            $collectionItems = [];
890
+            foreach ($items as &$row) {
891
+                // Return only the item instead of a 2-dimensional array
892
+                if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) {
893
+                    if ($format == self::FORMAT_NONE) {
894
+                        return $row;
895
+                    } else {
896
+                        break;
897
+                    }
898
+                }
899
+                // Check if this is a collection of the requested item type
900
+                if ($includeCollections && $collectionTypes && $row['item_type'] !== 'folder' && in_array($row['item_type'], $collectionTypes)) {
901
+                    if (($collectionBackend = self::getBackend($row['item_type']))
902
+                        && $collectionBackend instanceof \OCP\Share_Backend_Collection) {
903
+                        // Collections can be inside collections, check if the item is a collection
904
+                        if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) {
905
+                            $collectionItems[] = $row;
906
+                        } else {
907
+                            $collection = [];
908
+                            $collection['item_type'] = $row['item_type'];
909
+                            if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
910
+                                $collection['path'] = basename($row['path']);
911
+                            }
912
+                            $row['collection'] = $collection;
913
+                            // Fetch all of the children sources
914
+                            $children = $collectionBackend->getChildren($row[$column]);
915
+                            foreach ($children as $child) {
916
+                                $childItem = $row;
917
+                                $childItem['item_type'] = $itemType;
918
+                                if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') {
919
+                                    $childItem['item_source'] = $child['source'];
920
+                                    $childItem['item_target'] = $child['target'];
921
+                                }
922
+                                if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
923
+                                    if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
924
+                                        $childItem['file_source'] = $child['source'];
925
+                                    } else { // TODO is this really needed if we already know that we use the file backend?
926
+                                        $meta = \OC\Files\Filesystem::getFileInfo($child['file_path']);
927
+                                        $childItem['file_source'] = $meta['fileid'];
928
+                                    }
929
+                                    $childItem['file_target'] =
930
+                                        \OC\Files\Filesystem::normalizePath($child['file_path']);
931
+                                }
932
+                                if (isset($item)) {
933
+                                    if ($childItem[$column] == $item) {
934
+                                        // Return only the item instead of a 2-dimensional array
935
+                                        if ($limit == 1) {
936
+                                            if ($format == self::FORMAT_NONE) {
937
+                                                return $childItem;
938
+                                            } else {
939
+                                                // Unset the items array and break out of both loops
940
+                                                $items = [];
941
+                                                $items[] = $childItem;
942
+                                                break 2;
943
+                                            }
944
+                                        } else {
945
+                                            $collectionItems[] = $childItem;
946
+                                        }
947
+                                    }
948
+                                } else {
949
+                                    $collectionItems[] = $childItem;
950
+                                }
951
+                            }
952
+                        }
953
+                    }
954
+                    // Remove collection item
955
+                    $toRemove = $row['id'];
956
+                    if (array_key_exists($toRemove, $switchedItems)) {
957
+                        $toRemove = $switchedItems[$toRemove];
958
+                    }
959
+                    unset($items[$toRemove]);
960
+                } elseif ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) {
961
+                    // FIXME: Thats a dirty hack to improve file sharing performance,
962
+                    // see github issue #10588 for more details
963
+                    // Need to find a solution which works for all back-ends
964
+                    $collectionBackend = self::getBackend($row['item_type']);
965
+                    $sharedParents = $collectionBackend->getParents($row['item_source']);
966
+                    foreach ($sharedParents as $parent) {
967
+                        $collectionItems[] = $parent;
968
+                    }
969
+                }
970
+            }
971
+            if (!empty($collectionItems)) {
972
+                $collectionItems = array_unique($collectionItems, SORT_REGULAR);
973
+                $items = array_merge($items, $collectionItems);
974
+            }
975
+
976
+            // filter out invalid items, these can appear when subshare entries exist
977
+            // for a group in which the requested user isn't a member any more
978
+            $items = array_filter($items, function($item) {
979
+                return $item['share_type'] !== self::$shareTypeGroupUserUnique;
980
+            });
981
+
982
+            return self::formatResult($items, $column, $backend, $format, $parameters);
983
+        } elseif ($includeCollections && $collectionTypes && in_array('folder', $collectionTypes)) {
984
+            // FIXME: Thats a dirty hack to improve file sharing performance,
985
+            // see github issue #10588 for more details
986
+            // Need to find a solution which works for all back-ends
987
+            $collectionItems = [];
988
+            $collectionBackend = self::getBackend('folder');
989
+            $sharedParents = $collectionBackend->getParents($item, $shareWith, $uidOwner);
990
+            foreach ($sharedParents as $parent) {
991
+                $collectionItems[] = $parent;
992
+            }
993
+            if ($limit === 1) {
994
+                return reset($collectionItems);
995
+            }
996
+            return self::formatResult($collectionItems, $column, $backend, $format, $parameters);
997
+        }
998
+
999
+        return [];
1000
+    }
1001
+
1002
+    /**
1003
+     * group items with link to the same source
1004
+     *
1005
+     * @param array $items
1006
+     * @param string $itemType
1007
+     * @return array of grouped items
1008
+     */
1009
+    protected static function groupItems($items, $itemType) {
1010
+
1011
+        $fileSharing = $itemType === 'file' || $itemType === 'folder';
1012
+
1013
+        $result = [];
1014
+
1015
+        foreach ($items as $item) {
1016
+            $grouped = false;
1017
+            foreach ($result as $key => $r) {
1018
+                // for file/folder shares we need to compare file_source, otherwise we compare item_source
1019
+                // only group shares if they already point to the same target, otherwise the file where shared
1020
+                // before grouping of shares was added. In this case we don't group them toi avoid confusions
1021
+                if (( $fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) ||
1022
+                    (!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) {
1023
+                    // add the first item to the list of grouped shares
1024
+                    if (!isset($result[$key]['grouped'])) {
1025
+                        $result[$key]['grouped'][] = $result[$key];
1026
+                    }
1027
+                    $result[$key]['permissions'] = (int) $item['permissions'] | (int) $r['permissions'];
1028
+                    $result[$key]['grouped'][] = $item;
1029
+                    $grouped = true;
1030
+                    break;
1031
+                }
1032
+            }
1033
+
1034
+            if (!$grouped) {
1035
+                $result[] = $item;
1036
+            }
1037
+
1038
+        }
1039
+
1040
+        return $result;
1041
+    }
1042
+
1043
+    /**
1044
+     * Put shared item into the database
1045
+     * @param string $itemType Item type
1046
+     * @param string $itemSource Item source
1047
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1048
+     * @param string $shareWith User or group the item is being shared with
1049
+     * @param string $uidOwner User that is the owner of shared item
1050
+     * @param int $permissions CRUDS permissions
1051
+     * @throws \Exception
1052
+     * @return mixed id of the new share or false
1053
+     * @deprecated TESTS ONLY - this methods is only used by tests
1054
+     * called like this:
1055
+     * self::put('test', $itemSource, self::SHARE_TYPE_USER, $shareWith, $uidOwner, $permissions);
1056
+     */
1057
+    private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1058
+                                $permissions) {
1059
+
1060
+        $queriesToExecute = [];
1061
+        $suggestedItemTarget = null;
1062
+        $groupFileTarget = $fileTarget = $suggestedFileTarget = $filePath = '';
1063
+        $groupItemTarget = $itemTarget = $fileSource = $parent = 0;
1064
+
1065
+        $result = self::checkReshare('test', $itemSource, self::SHARE_TYPE_USER, $shareWith, $uidOwner, $permissions, null, null);
1066
+        if(!empty($result)) {
1067
+            $parent = $result['parent'];
1068
+            $itemSource = $result['itemSource'];
1069
+            $fileSource = $result['fileSource'];
1070
+            $suggestedItemTarget = $result['suggestedItemTarget'];
1071
+            $suggestedFileTarget = $result['suggestedFileTarget'];
1072
+            $filePath = $result['filePath'];
1073
+        }
1074
+
1075
+        $isGroupShare = false;
1076
+            $users = [$shareWith];
1077
+            $itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1078
+                $suggestedItemTarget);
1079
+
1080
+        $run = true;
1081
+        $error = '';
1082
+        $preHookData = [
1083
+            'itemType' => $itemType,
1084
+            'itemSource' => $itemSource,
1085
+            'shareType' => $shareType,
1086
+            'uidOwner' => $uidOwner,
1087
+            'permissions' => $permissions,
1088
+            'fileSource' => $fileSource,
1089
+            'expiration' => null,
1090
+            'token' => null,
1091
+            'run' => &$run,
1092
+            'error' => &$error
1093
+        ];
1094
+
1095
+        $preHookData['itemTarget'] = $itemTarget;
1096
+        $preHookData['shareWith'] = $shareWith;
1097
+
1098
+        \OC_Hook::emit(\OCP\Share::class, 'pre_shared', $preHookData);
1099
+
1100
+        if ($run === false) {
1101
+            throw new \Exception($error);
1102
+        }
1103
+
1104
+        foreach ($users as $user) {
1105
+            $sourceId = ($itemType === 'file' || $itemType === 'folder') ? $fileSource : $itemSource;
1106
+            $sourceExists = self::getItemSharedWithBySource($itemType, $sourceId, self::FORMAT_NONE, null, true, $user);
1107
+
1108
+            $userShareType = $shareType;
1109
+
1110
+            if ($sourceExists && $sourceExists['item_source'] === $itemSource) {
1111
+                $fileTarget = $sourceExists['file_target'];
1112
+                $itemTarget = $sourceExists['item_target'];
1113
+
1114
+            } elseif(!$sourceExists)  {
1115
+
1116
+                $itemTarget = Helper::generateTarget($itemType, $itemSource, $userShareType, $user,
1117
+                    $uidOwner, $suggestedItemTarget, $parent);
1118
+                if (isset($fileSource)) {
1119
+                        $fileTarget = Helper::generateTarget('file', $filePath, $userShareType,
1120
+                            $user, $uidOwner, $suggestedFileTarget, $parent);
1121
+                } else {
1122
+                    $fileTarget = null;
1123
+                }
1124
+
1125
+            } else {
1126
+
1127
+                // group share which doesn't exists until now, check if we need a unique target for this user
1128
+
1129
+                $itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $user,
1130
+                    $uidOwner, $suggestedItemTarget, $parent);
1131
+
1132
+                // do we also need a file target
1133
+                if (isset($fileSource)) {
1134
+                    $fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user,
1135
+                        $uidOwner, $suggestedFileTarget, $parent);
1136
+                } else {
1137
+                    $fileTarget = null;
1138
+                }
1139
+
1140
+                if (($itemTarget === $groupItemTarget) &&
1141
+                    (!isset($fileSource) || $fileTarget === $groupFileTarget)) {
1142
+                    continue;
1143
+                }
1144
+            }
1145
+
1146
+            $queriesToExecute[] = [
1147
+                'itemType'			=> $itemType,
1148
+                'itemSource'		=> $itemSource,
1149
+                'itemTarget'		=> $itemTarget,
1150
+                'shareType'			=> $userShareType,
1151
+                'shareWith'			=> $user,
1152
+                'uidOwner'			=> $uidOwner,
1153
+                'permissions'		=> $permissions,
1154
+                'shareTime'			=> time(),
1155
+                'fileSource'		=> $fileSource,
1156
+                'fileTarget'		=> $fileTarget,
1157
+                'token'				=> null,
1158
+                'parent'			=> $parent,
1159
+                'expiration'		=> null,
1160
+            ];
1161
+
1162
+        }
1163
+
1164
+        $id = false;
1165
+
1166
+        foreach ($queriesToExecute as $shareQuery) {
1167
+            $shareQuery['parent'] = $parent;
1168
+            $id = self::insertShare($shareQuery);
1169
+        }
1170
+
1171
+        $postHookData = [
1172
+            'itemType' => $itemType,
1173
+            'itemSource' => $itemSource,
1174
+            'parent' => $parent,
1175
+            'shareType' => $shareType,
1176
+            'uidOwner' => $uidOwner,
1177
+            'permissions' => $permissions,
1178
+            'fileSource' => $fileSource,
1179
+            'id' => $parent,
1180
+            'token' => null,
1181
+            'expirationDate' => null,
1182
+        ];
1183
+
1184
+        $postHookData['shareWith'] = $isGroupShare ? $shareWith['group'] : $shareWith;
1185
+        $postHookData['itemTarget'] = $isGroupShare ? $groupItemTarget : $itemTarget;
1186
+        $postHookData['fileTarget'] = $isGroupShare ? $groupFileTarget : $fileTarget;
1187
+
1188
+        \OC_Hook::emit(\OCP\Share::class, 'post_shared', $postHookData);
1189
+
1190
+
1191
+        return $id ? $id : false;
1192
+    }
1193
+
1194
+    /**
1195
+     * @param string $itemType
1196
+     * @param string $itemSource
1197
+     * @param int $shareType
1198
+     * @param string $shareWith
1199
+     * @param string $uidOwner
1200
+     * @param int $permissions
1201
+     * @param string|null $itemSourceName
1202
+     * @param null|\DateTime $expirationDate
1203
+     * @deprecated TESTS ONLY - this methods is only used by tests
1204
+     * called like this:
1205
+     * self::checkReshare('test', $itemSource, self::SHARE_TYPE_USER, $shareWith, $uidOwner, $permissions, null, null);
1206
+     */
1207
+    private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) {
1208
+        $backend = self::getBackend($itemType);
1209
+
1210
+        $result = [];
1211
+
1212
+        $column = ($itemType === 'file' || $itemType === 'folder') ? 'file_source' : 'item_source';
1213
+
1214
+        $checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true);
1215
+        if ($checkReshare) {
1216
+            // Check if attempting to share back to owner
1217
+            if ($checkReshare['uid_owner'] == $shareWith) {
1218
+                $message = 'Sharing %1$s failed, because the user %2$s is the original sharer';
1219
+                throw new \Exception(sprintf($message, $itemSourceName, $shareWith));
1220
+            }
1221
+        }
1222
+
1223
+        if ($checkReshare && $checkReshare['uid_owner'] !== \OC_User::getUser()) {
1224
+            // Check if share permissions is granted
1225
+            if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1226
+                if (~(int)$checkReshare['permissions'] & $permissions) {
1227
+                    $message = 'Sharing %1$s failed, because the permissions exceed permissions granted to %2$s';
1228
+                    throw new \Exception(sprintf($message, $itemSourceName, $uidOwner));
1229
+                } else {
1230
+                    // TODO Don't check if inside folder
1231
+                    $result['parent'] = $checkReshare['id'];
1232
+
1233
+                    $result['expirationDate'] = $expirationDate;
1234
+                    // $checkReshare['expiration'] could be null and then is always less than any value
1235
+                    if(isset($checkReshare['expiration']) && $checkReshare['expiration'] < $expirationDate) {
1236
+                        $result['expirationDate'] = $checkReshare['expiration'];
1237
+                    }
1238
+
1239
+                    // only suggest the same name as new target if it is a reshare of the
1240
+                    // same file/folder and not the reshare of a child
1241
+                    if ($checkReshare[$column] === $itemSource) {
1242
+                        $result['filePath'] = $checkReshare['file_target'];
1243
+                        $result['itemSource'] = $checkReshare['item_source'];
1244
+                        $result['fileSource'] = $checkReshare['file_source'];
1245
+                        $result['suggestedItemTarget'] = $checkReshare['item_target'];
1246
+                        $result['suggestedFileTarget'] = $checkReshare['file_target'];
1247
+                    } else {
1248
+                        $result['filePath'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $backend->getFilePath($itemSource, $uidOwner) : null;
1249
+                        $result['suggestedItemTarget'] = null;
1250
+                        $result['suggestedFileTarget'] = null;
1251
+                        $result['itemSource'] = $itemSource;
1252
+                        $result['fileSource'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $itemSource : null;
1253
+                    }
1254
+                }
1255
+            } else {
1256
+                $message = 'Sharing %s failed, because resharing is not allowed';
1257
+                throw new \Exception(sprintf($message, $itemSourceName));
1258
+            }
1259
+        } else {
1260
+            $result['parent'] = null;
1261
+            $result['suggestedItemTarget'] = null;
1262
+            $result['suggestedFileTarget'] = null;
1263
+            $result['itemSource'] = $itemSource;
1264
+            $result['expirationDate'] = $expirationDate;
1265
+            if (!$backend->isValidSource($itemSource, $uidOwner)) {
1266
+                $message = 'Sharing %1$s failed, because the sharing backend for '
1267
+                    .'%2$s could not find its source';
1268
+                throw new \Exception(sprintf($message, $itemSource, $itemType));
1269
+            }
1270
+            if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
1271
+                $result['filePath'] = $backend->getFilePath($itemSource, $uidOwner);
1272
+                    $meta = \OC\Files\Filesystem::getFileInfo($result['filePath']);
1273
+                    $result['fileSource'] = $meta['fileid'];
1274
+                if ($result['fileSource'] == -1) {
1275
+                    $message = 'Sharing %s failed, because the file could not be found in the file cache';
1276
+                    throw new \Exception(sprintf($message, $itemSource));
1277
+                }
1278
+            } else {
1279
+                $result['filePath'] = null;
1280
+                $result['fileSource'] = null;
1281
+            }
1282
+        }
1283
+
1284
+        return $result;
1285
+    }
1286
+
1287
+    /**
1288
+     *
1289
+     * @param array $shareData
1290
+     * @return mixed false in case of a failure or the id of the new share
1291
+     */
1292
+    private static function insertShare(array $shareData) {
1293
+
1294
+        $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
1295
+            .' `item_type`, `item_source`, `item_target`, `share_type`,'
1296
+            .' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
1297
+            .' `file_target`, `token`, `parent`, `expiration`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)');
1298
+        $query->bindValue(1, $shareData['itemType']);
1299
+        $query->bindValue(2, $shareData['itemSource']);
1300
+        $query->bindValue(3, $shareData['itemTarget']);
1301
+        $query->bindValue(4, $shareData['shareType']);
1302
+        $query->bindValue(5, $shareData['shareWith']);
1303
+        $query->bindValue(6, $shareData['uidOwner']);
1304
+        $query->bindValue(7, $shareData['permissions']);
1305
+        $query->bindValue(8, $shareData['shareTime']);
1306
+        $query->bindValue(9, $shareData['fileSource']);
1307
+        $query->bindValue(10, $shareData['fileTarget']);
1308
+        $query->bindValue(11, $shareData['token']);
1309
+        $query->bindValue(12, $shareData['parent']);
1310
+        $query->bindValue(13, $shareData['expiration'], 'datetime');
1311
+        $result = $query->execute();
1312
+
1313
+        $id = false;
1314
+        if ($result) {
1315
+            $id =  \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
1316
+        }
1317
+
1318
+        return $id;
1319
+
1320
+    }
1321
+
1322
+    /**
1323
+     * construct select statement
1324
+     * @param int $format
1325
+     * @param boolean $fileDependent ist it a file/folder share or a generla share
1326
+     * @param string $uidOwner
1327
+     * @return string select statement
1328
+     */
1329
+    private static function createSelectStatement($format, $fileDependent, $uidOwner = null) {
1330
+        $select = '*';
1331
+        if ($format == self::FORMAT_STATUSES) {
1332
+            if ($fileDependent) {
1333
+                $select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `storage`, '
1334
+                    . '`share_with`, `uid_owner` , `file_source`, `stime`, `*PREFIX*share`.`permissions`, '
1335
+                    . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1336
+                    . '`uid_initiator`';
1337
+            } else {
1338
+                $select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`';
1339
+            }
1340
+        } else {
1341
+            if (isset($uidOwner)) {
1342
+                if ($fileDependent) {
1343
+                    $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,'
1344
+                        . ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
1345
+                        . ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`, '
1346
+                        . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1347
+                } else {
1348
+                    $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
1349
+                        . ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
1350
+                }
1351
+            } else {
1352
+                if ($fileDependent) {
1353
+                    if ($format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_GET_FOLDER_CONTENTS || $format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_FILE_APP_ROOT) {
1354
+                        $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
1355
+                            . '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
1356
+                            . '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1357
+                            . '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
1358
+                    } else {
1359
+                        $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,'
1360
+                            . '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,'
1361
+                            . '`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`,'
1362
+                            . '`stime`, `expiration`, `token`, `storage`, `mail_send`,'
1363
+                            . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1364
+                    }
1365
+                }
1366
+            }
1367
+        }
1368
+        return $select;
1369
+    }
1370
+
1371
+
1372
+    /**
1373
+     * transform db results
1374
+     * @param array $row result
1375
+     */
1376
+    private static function transformDBResults(&$row) {
1377
+        if (isset($row['id'])) {
1378
+            $row['id'] = (int) $row['id'];
1379
+        }
1380
+        if (isset($row['share_type'])) {
1381
+            $row['share_type'] = (int) $row['share_type'];
1382
+        }
1383
+        if (isset($row['parent'])) {
1384
+            $row['parent'] = (int) $row['parent'];
1385
+        }
1386
+        if (isset($row['file_parent'])) {
1387
+            $row['file_parent'] = (int) $row['file_parent'];
1388
+        }
1389
+        if (isset($row['file_source'])) {
1390
+            $row['file_source'] = (int) $row['file_source'];
1391
+        }
1392
+        if (isset($row['permissions'])) {
1393
+            $row['permissions'] = (int) $row['permissions'];
1394
+        }
1395
+        if (isset($row['storage'])) {
1396
+            $row['storage'] = (int) $row['storage'];
1397
+        }
1398
+        if (isset($row['stime'])) {
1399
+            $row['stime'] = (int) $row['stime'];
1400
+        }
1401
+        if (isset($row['expiration']) && $row['share_type'] !== self::SHARE_TYPE_LINK) {
1402
+            // discard expiration date for non-link shares, which might have been
1403
+            // set by ancient bugs
1404
+            $row['expiration'] = null;
1405
+        }
1406
+    }
1407
+
1408
+    /**
1409
+     * format result
1410
+     * @param array $items result
1411
+     * @param string $column is it a file share or a general share ('file_target' or 'item_target')
1412
+     * @param \OCP\Share_Backend $backend sharing backend
1413
+     * @param int $format
1414
+     * @param array $parameters additional format parameters
1415
+     * @return array format result
1416
+     */
1417
+    private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE , $parameters = null) {
1418
+        if ($format === self::FORMAT_NONE) {
1419
+            return $items;
1420
+        } else if ($format === self::FORMAT_STATUSES) {
1421
+            $statuses = [];
1422
+            foreach ($items as $item) {
1423
+                if ($item['share_type'] === self::SHARE_TYPE_LINK) {
1424
+                    if ($item['uid_initiator'] !== \OC::$server->getUserSession()->getUser()->getUID()) {
1425
+                        continue;
1426
+                    }
1427
+                    $statuses[$item[$column]]['link'] = true;
1428
+                } else if (!isset($statuses[$item[$column]])) {
1429
+                    $statuses[$item[$column]]['link'] = false;
1430
+                }
1431
+                if (!empty($item['file_target'])) {
1432
+                    $statuses[$item[$column]]['path'] = $item['path'];
1433
+                }
1434
+            }
1435
+            return $statuses;
1436
+        } else {
1437
+            return $backend->formatItems($items, $format, $parameters);
1438
+        }
1439
+    }
1440
+
1441
+    /**
1442
+     * remove protocol from URL
1443
+     *
1444
+     * @param string $url
1445
+     * @return string
1446
+     */
1447
+    public static function removeProtocolFromUrl($url) {
1448
+        if (strpos($url, 'https://') === 0) {
1449
+            return substr($url, strlen('https://'));
1450
+        } else if (strpos($url, 'http://') === 0) {
1451
+            return substr($url, strlen('http://'));
1452
+        }
1453
+
1454
+        return $url;
1455
+    }
1456
+
1457
+    /**
1458
+     * try http post first with https and then with http as a fallback
1459
+     *
1460
+     * @param string $remoteDomain
1461
+     * @param string $urlSuffix
1462
+     * @param array $fields post parameters
1463
+     * @return array
1464
+     */
1465
+    private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) {
1466
+        $protocol = 'https://';
1467
+        $result = [
1468
+            'success' => false,
1469
+            'result' => '',
1470
+        ];
1471
+        $try = 0;
1472
+        $discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
1473
+        while ($result['success'] === false && $try < 2) {
1474
+            $federationEndpoints = $discoveryService->discover($protocol . $remoteDomain, 'FEDERATED_SHARING');
1475
+            $endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
1476
+            $client = \OC::$server->getHTTPClientService()->newClient();
1477
+
1478
+            try {
1479
+                $response = $client->post(
1480
+                    $protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT,
1481
+                    [
1482
+                        'body' => $fields,
1483
+                        'connect_timeout' => 10,
1484
+                    ]
1485
+                );
1486
+
1487
+                $result = ['success' => true, 'result' => $response->getBody()];
1488
+            } catch (\Exception $e) {
1489
+                $result = ['success' => false, 'result' => $e->getMessage()];
1490
+            }
1491
+
1492
+            $try++;
1493
+            $protocol = 'http://';
1494
+        }
1495
+
1496
+        return $result;
1497
+    }
1498
+
1499
+    /**
1500
+     * send server-to-server unshare to remote server
1501
+     *
1502
+     * @param string $remote url
1503
+     * @param int $id share id
1504
+     * @param string $token
1505
+     * @return bool
1506
+     */
1507
+    private static function sendRemoteUnshare($remote, $id, $token) {
1508
+        $url = rtrim($remote, '/');
1509
+        $fields = ['token' => $token, 'format' => 'json'];
1510
+        $url = self::removeProtocolFromUrl($url);
1511
+        $result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
1512
+        $status = json_decode($result['result'], true);
1513
+
1514
+        return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200));
1515
+    }
1516
+
1517
+    /**
1518
+     * @return int
1519
+     */
1520
+    public static function getExpireInterval() {
1521
+        return (int)\OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1522
+    }
1523
+
1524
+    /**
1525
+     * Checks whether the given path is reachable for the given owner
1526
+     *
1527
+     * @param string $path path relative to files
1528
+     * @param string $ownerStorageId storage id of the owner
1529
+     *
1530
+     * @return boolean true if file is reachable, false otherwise
1531
+     */
1532
+    private static function isFileReachable($path, $ownerStorageId) {
1533
+        // if outside the home storage, file is always considered reachable
1534
+        if (!(substr($ownerStorageId, 0, 6) === 'home::' ||
1535
+            substr($ownerStorageId, 0, 13) === 'object::user:'
1536
+        )) {
1537
+            return true;
1538
+        }
1539
+
1540
+        // if inside the home storage, the file has to be under "/files/"
1541
+        $path = ltrim($path, '/');
1542
+        if (substr($path, 0, 6) === 'files/') {
1543
+            return true;
1544
+        }
1545
+
1546
+        return false;
1547
+    }
1548 1548
 }
Please login to merge, or discard this patch.
lib/private/AppFramework/Middleware/OCSMiddleware.php 1 patch
Indentation   +109 added lines, -109 removed lines patch added patch discarded remove patch
@@ -40,116 +40,116 @@
 block discarded – undo
40 40
 
41 41
 class OCSMiddleware extends Middleware {
42 42
 
43
-	/** @var IRequest */
44
-	private $request;
45
-
46
-	/** @var int */
47
-	private $ocsVersion;
48
-
49
-	/**
50
-	 * @param IRequest $request
51
-	 */
52
-	public function __construct(IRequest $request) {
53
-		$this->request = $request;
54
-	}
55
-
56
-	/**
57
-	 * @param Controller $controller
58
-	 * @param string $methodName
59
-	 */
60
-	public function beforeController($controller, $methodName) {
61
-		if ($controller instanceof OCSController) {
62
-			if (substr_compare($this->request->getScriptName(), '/ocs/v2.php', -strlen('/ocs/v2.php')) === 0) {
63
-				$this->ocsVersion = 2;
64
-			} else {
65
-				$this->ocsVersion = 1;
66
-			}
67
-			$controller->setOCSVersion($this->ocsVersion);
68
-		}
69
-	}
70
-
71
-	/**
72
-	 * @param Controller $controller
73
-	 * @param string $methodName
74
-	 * @param \Exception $exception
75
-	 * @throws \Exception
76
-	 * @return BaseResponse
77
-	 */
78
-	public function afterException($controller, $methodName, \Exception $exception) {
79
-		if ($controller instanceof OCSController && $exception instanceof OCSException) {
80
-			$code = $exception->getCode();
81
-			if ($code === 0) {
82
-				$code = API::RESPOND_UNKNOWN_ERROR;
83
-			}
84
-
85
-			return $this->buildNewResponse($controller, $code, $exception->getMessage());
86
-		}
87
-
88
-		throw $exception;
89
-	}
90
-
91
-	/**
92
-	 * @param Controller $controller
93
-	 * @param string $methodName
94
-	 * @param Response $response
95
-	 * @return \OCP\AppFramework\Http\Response
96
-	 */
97
-	public function afterController($controller, $methodName, Response $response) {
98
-		/*
43
+    /** @var IRequest */
44
+    private $request;
45
+
46
+    /** @var int */
47
+    private $ocsVersion;
48
+
49
+    /**
50
+     * @param IRequest $request
51
+     */
52
+    public function __construct(IRequest $request) {
53
+        $this->request = $request;
54
+    }
55
+
56
+    /**
57
+     * @param Controller $controller
58
+     * @param string $methodName
59
+     */
60
+    public function beforeController($controller, $methodName) {
61
+        if ($controller instanceof OCSController) {
62
+            if (substr_compare($this->request->getScriptName(), '/ocs/v2.php', -strlen('/ocs/v2.php')) === 0) {
63
+                $this->ocsVersion = 2;
64
+            } else {
65
+                $this->ocsVersion = 1;
66
+            }
67
+            $controller->setOCSVersion($this->ocsVersion);
68
+        }
69
+    }
70
+
71
+    /**
72
+     * @param Controller $controller
73
+     * @param string $methodName
74
+     * @param \Exception $exception
75
+     * @throws \Exception
76
+     * @return BaseResponse
77
+     */
78
+    public function afterException($controller, $methodName, \Exception $exception) {
79
+        if ($controller instanceof OCSController && $exception instanceof OCSException) {
80
+            $code = $exception->getCode();
81
+            if ($code === 0) {
82
+                $code = API::RESPOND_UNKNOWN_ERROR;
83
+            }
84
+
85
+            return $this->buildNewResponse($controller, $code, $exception->getMessage());
86
+        }
87
+
88
+        throw $exception;
89
+    }
90
+
91
+    /**
92
+     * @param Controller $controller
93
+     * @param string $methodName
94
+     * @param Response $response
95
+     * @return \OCP\AppFramework\Http\Response
96
+     */
97
+    public function afterController($controller, $methodName, Response $response) {
98
+        /*
99 99
 		 * If a different middleware has detected that a request unauthorized or forbidden
100 100
 		 * we need to catch the response and convert it to a proper OCS response.
101 101
 		 */
102
-		if ($controller instanceof OCSController && !($response instanceof BaseResponse)) {
103
-			if ($response->getStatus() === Http::STATUS_UNAUTHORIZED ||
104
-				$response->getStatus() === Http::STATUS_FORBIDDEN) {
105
-
106
-				$message = '';
107
-				if ($response instanceof JSONResponse) {
108
-					/** @var DataResponse $response */
109
-					$message = $response->getData()['message'];
110
-				}
111
-
112
-				return $this->buildNewResponse($controller, API::RESPOND_UNAUTHORISED, $message);
113
-			}
114
-		}
115
-
116
-		return $response;
117
-	}
118
-
119
-	/**
120
-	 * @param Controller $controller
121
-	 * @param int $code
122
-	 * @param string $message
123
-	 * @return V1Response|V2Response
124
-	 */
125
-	private function buildNewResponse(Controller $controller, $code, $message) {
126
-		$format = $this->getFormat($controller);
127
-
128
-		$data = new DataResponse();
129
-		$data->setStatus($code);
130
-		if ($this->ocsVersion === 1) {
131
-			$response = new V1Response($data, $format, $message);
132
-		} else {
133
-			$response = new V2Response($data, $format, $message);
134
-		}
135
-
136
-		return $response;
137
-	}
138
-
139
-	/**
140
-	 * @param Controller $controller
141
-	 * @return string
142
-	 */
143
-	private function getFormat(Controller $controller) {
144
-		// get format from the url format or request format parameter
145
-		$format = $this->request->getParam('format');
146
-
147
-		// if none is given try the first Accept header
148
-		if($format === null) {
149
-			$headers = $this->request->getHeader('Accept');
150
-			$format = $controller->getResponderByHTTPHeader($headers, 'xml');
151
-		}
152
-
153
-		return $format;
154
-	}
102
+        if ($controller instanceof OCSController && !($response instanceof BaseResponse)) {
103
+            if ($response->getStatus() === Http::STATUS_UNAUTHORIZED ||
104
+                $response->getStatus() === Http::STATUS_FORBIDDEN) {
105
+
106
+                $message = '';
107
+                if ($response instanceof JSONResponse) {
108
+                    /** @var DataResponse $response */
109
+                    $message = $response->getData()['message'];
110
+                }
111
+
112
+                return $this->buildNewResponse($controller, API::RESPOND_UNAUTHORISED, $message);
113
+            }
114
+        }
115
+
116
+        return $response;
117
+    }
118
+
119
+    /**
120
+     * @param Controller $controller
121
+     * @param int $code
122
+     * @param string $message
123
+     * @return V1Response|V2Response
124
+     */
125
+    private function buildNewResponse(Controller $controller, $code, $message) {
126
+        $format = $this->getFormat($controller);
127
+
128
+        $data = new DataResponse();
129
+        $data->setStatus($code);
130
+        if ($this->ocsVersion === 1) {
131
+            $response = new V1Response($data, $format, $message);
132
+        } else {
133
+            $response = new V2Response($data, $format, $message);
134
+        }
135
+
136
+        return $response;
137
+    }
138
+
139
+    /**
140
+     * @param Controller $controller
141
+     * @return string
142
+     */
143
+    private function getFormat(Controller $controller) {
144
+        // get format from the url format or request format parameter
145
+        $format = $this->request->getParam('format');
146
+
147
+        // if none is given try the first Accept header
148
+        if($format === null) {
149
+            $headers = $this->request->getHeader('Accept');
150
+            $format = $controller->getResponderByHTTPHeader($headers, 'xml');
151
+        }
152
+
153
+        return $format;
154
+    }
155 155
 }
Please login to merge, or discard this patch.
lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php 2 patches
Indentation   +167 added lines, -167 removed lines patch added patch discarded remove patch
@@ -67,103 +67,103 @@  discard block
 block discarded – undo
67 67
  * check fails
68 68
  */
69 69
 class SecurityMiddleware extends Middleware {
70
-	/** @var INavigationManager */
71
-	private $navigationManager;
72
-	/** @var IRequest */
73
-	private $request;
74
-	/** @var ControllerMethodReflector */
75
-	private $reflector;
76
-	/** @var string */
77
-	private $appName;
78
-	/** @var IURLGenerator */
79
-	private $urlGenerator;
80
-	/** @var ILogger */
81
-	private $logger;
82
-	/** @var bool */
83
-	private $isLoggedIn;
84
-	/** @var bool */
85
-	private $isAdminUser;
86
-	/** @var bool */
87
-	private $isSubAdmin;
88
-	/** @var IAppManager */
89
-	private $appManager;
90
-	/** @var IL10N */
91
-	private $l10n;
92
-
93
-	public function __construct(IRequest $request,
94
-								ControllerMethodReflector $reflector,
95
-								INavigationManager $navigationManager,
96
-								IURLGenerator $urlGenerator,
97
-								ILogger $logger,
98
-								string $appName,
99
-								bool $isLoggedIn,
100
-								bool $isAdminUser,
101
-								bool $isSubAdmin,
102
-								IAppManager $appManager,
103
-								IL10N $l10n
104
-	) {
105
-		$this->navigationManager = $navigationManager;
106
-		$this->request = $request;
107
-		$this->reflector = $reflector;
108
-		$this->appName = $appName;
109
-		$this->urlGenerator = $urlGenerator;
110
-		$this->logger = $logger;
111
-		$this->isLoggedIn = $isLoggedIn;
112
-		$this->isAdminUser = $isAdminUser;
113
-		$this->isSubAdmin = $isSubAdmin;
114
-		$this->appManager = $appManager;
115
-		$this->l10n = $l10n;
116
-	}
117
-
118
-	/**
119
-	 * This runs all the security checks before a method call. The
120
-	 * security checks are determined by inspecting the controller method
121
-	 * annotations
122
-	 * @param Controller $controller the controller
123
-	 * @param string $methodName the name of the method
124
-	 * @throws SecurityException when a security check fails
125
-	 *
126
-	 * @suppress PhanUndeclaredClassConstant
127
-	 */
128
-	public function beforeController($controller, $methodName) {
129
-
130
-		// this will set the current navigation entry of the app, use this only
131
-		// for normal HTML requests and not for AJAX requests
132
-		$this->navigationManager->setActiveEntry($this->appName);
133
-
134
-		if (get_class($controller) === \OCA\Talk\Controller\PageController::class && $methodName === 'showCall') {
135
-			$this->navigationManager->setActiveEntry('spreed');
136
-		}
137
-
138
-		// security checks
139
-		$isPublicPage = $this->reflector->hasAnnotation('PublicPage');
140
-		if(!$isPublicPage) {
141
-			if(!$this->isLoggedIn) {
142
-				throw new NotLoggedInException();
143
-			}
144
-
145
-			if($this->reflector->hasAnnotation('SubAdminRequired')
146
-				&& !$this->isSubAdmin
147
-				&& !$this->isAdminUser) {
148
-				throw new NotAdminException($this->l10n->t('Logged in user must be an admin or sub admin'));
149
-			}
150
-			if(!$this->reflector->hasAnnotation('SubAdminRequired')
151
-				&& !$this->reflector->hasAnnotation('NoAdminRequired')
152
-				&& !$this->isAdminUser) {
153
-				throw new NotAdminException($this->l10n->t('Logged in user must be an admin'));
154
-			}
155
-		}
156
-
157
-		// Check for strict cookie requirement
158
-		if($this->reflector->hasAnnotation('StrictCookieRequired') || !$this->reflector->hasAnnotation('NoCSRFRequired')) {
159
-			if(!$this->request->passesStrictCookieCheck()) {
160
-				throw new StrictCookieMissingException();
161
-			}
162
-		}
163
-		// CSRF check - also registers the CSRF token since the session may be closed later
164
-		Util::callRegister();
165
-		if(!$this->reflector->hasAnnotation('NoCSRFRequired')) {
166
-			/*
70
+    /** @var INavigationManager */
71
+    private $navigationManager;
72
+    /** @var IRequest */
73
+    private $request;
74
+    /** @var ControllerMethodReflector */
75
+    private $reflector;
76
+    /** @var string */
77
+    private $appName;
78
+    /** @var IURLGenerator */
79
+    private $urlGenerator;
80
+    /** @var ILogger */
81
+    private $logger;
82
+    /** @var bool */
83
+    private $isLoggedIn;
84
+    /** @var bool */
85
+    private $isAdminUser;
86
+    /** @var bool */
87
+    private $isSubAdmin;
88
+    /** @var IAppManager */
89
+    private $appManager;
90
+    /** @var IL10N */
91
+    private $l10n;
92
+
93
+    public function __construct(IRequest $request,
94
+                                ControllerMethodReflector $reflector,
95
+                                INavigationManager $navigationManager,
96
+                                IURLGenerator $urlGenerator,
97
+                                ILogger $logger,
98
+                                string $appName,
99
+                                bool $isLoggedIn,
100
+                                bool $isAdminUser,
101
+                                bool $isSubAdmin,
102
+                                IAppManager $appManager,
103
+                                IL10N $l10n
104
+    ) {
105
+        $this->navigationManager = $navigationManager;
106
+        $this->request = $request;
107
+        $this->reflector = $reflector;
108
+        $this->appName = $appName;
109
+        $this->urlGenerator = $urlGenerator;
110
+        $this->logger = $logger;
111
+        $this->isLoggedIn = $isLoggedIn;
112
+        $this->isAdminUser = $isAdminUser;
113
+        $this->isSubAdmin = $isSubAdmin;
114
+        $this->appManager = $appManager;
115
+        $this->l10n = $l10n;
116
+    }
117
+
118
+    /**
119
+     * This runs all the security checks before a method call. The
120
+     * security checks are determined by inspecting the controller method
121
+     * annotations
122
+     * @param Controller $controller the controller
123
+     * @param string $methodName the name of the method
124
+     * @throws SecurityException when a security check fails
125
+     *
126
+     * @suppress PhanUndeclaredClassConstant
127
+     */
128
+    public function beforeController($controller, $methodName) {
129
+
130
+        // this will set the current navigation entry of the app, use this only
131
+        // for normal HTML requests and not for AJAX requests
132
+        $this->navigationManager->setActiveEntry($this->appName);
133
+
134
+        if (get_class($controller) === \OCA\Talk\Controller\PageController::class && $methodName === 'showCall') {
135
+            $this->navigationManager->setActiveEntry('spreed');
136
+        }
137
+
138
+        // security checks
139
+        $isPublicPage = $this->reflector->hasAnnotation('PublicPage');
140
+        if(!$isPublicPage) {
141
+            if(!$this->isLoggedIn) {
142
+                throw new NotLoggedInException();
143
+            }
144
+
145
+            if($this->reflector->hasAnnotation('SubAdminRequired')
146
+                && !$this->isSubAdmin
147
+                && !$this->isAdminUser) {
148
+                throw new NotAdminException($this->l10n->t('Logged in user must be an admin or sub admin'));
149
+            }
150
+            if(!$this->reflector->hasAnnotation('SubAdminRequired')
151
+                && !$this->reflector->hasAnnotation('NoAdminRequired')
152
+                && !$this->isAdminUser) {
153
+                throw new NotAdminException($this->l10n->t('Logged in user must be an admin'));
154
+            }
155
+        }
156
+
157
+        // Check for strict cookie requirement
158
+        if($this->reflector->hasAnnotation('StrictCookieRequired') || !$this->reflector->hasAnnotation('NoCSRFRequired')) {
159
+            if(!$this->request->passesStrictCookieCheck()) {
160
+                throw new StrictCookieMissingException();
161
+            }
162
+        }
163
+        // CSRF check - also registers the CSRF token since the session may be closed later
164
+        Util::callRegister();
165
+        if(!$this->reflector->hasAnnotation('NoCSRFRequired')) {
166
+            /*
167 167
 			 * Only allow the CSRF check to fail on OCS Requests. This kind of
168 168
 			 * hacks around that we have no full token auth in place yet and we
169 169
 			 * do want to offer CSRF checks for web requests.
@@ -171,75 +171,75 @@  discard block
 block discarded – undo
171 171
 			 * Additionally we allow Bearer authenticated requests to pass on OCS routes.
172 172
 			 * This allows oauth apps (e.g. moodle) to use the OCS endpoints
173 173
 			 */
174
-			if(!$this->request->passesCSRFCheck() && !(
175
-					$controller instanceof OCSController && (
176
-						$this->request->getHeader('OCS-APIREQUEST') === 'true' ||
177
-						strpos($this->request->getHeader('Authorization'), 'Bearer ') === 0
178
-					)
179
-				)) {
180
-				throw new CrossSiteRequestForgeryException();
181
-			}
182
-		}
183
-
184
-		/**
185
-		 * Checks if app is enabled (also includes a check whether user is allowed to access the resource)
186
-		 * The getAppPath() check is here since components such as settings also use the AppFramework and
187
-		 * therefore won't pass this check.
188
-		 * If page is public, app does not need to be enabled for current user/visitor
189
-		 */
190
-		try {
191
-			$appPath = $this->appManager->getAppPath($this->appName);
192
-		} catch (AppPathNotFoundException $e) {
193
-			$appPath = false;
194
-		}
195
-
196
-		if ($appPath !== false && !$isPublicPage && !$this->appManager->isEnabledForUser($this->appName)) {
197
-			throw new AppNotEnabledException();
198
-		}
199
-	}
200
-
201
-	/**
202
-	 * If an SecurityException is being caught, ajax requests return a JSON error
203
-	 * response and non ajax requests redirect to the index
204
-	 * @param Controller $controller the controller that is being called
205
-	 * @param string $methodName the name of the method that will be called on
206
-	 *                           the controller
207
-	 * @param \Exception $exception the thrown exception
208
-	 * @throws \Exception the passed in exception if it can't handle it
209
-	 * @return Response a Response object or null in case that the exception could not be handled
210
-	 */
211
-	public function afterException($controller, $methodName, \Exception $exception): Response {
212
-		if($exception instanceof SecurityException) {
213
-			if($exception instanceof StrictCookieMissingException) {
214
-				return new RedirectResponse(\OC::$WEBROOT);
215
-			}
216
-			if (stripos($this->request->getHeader('Accept'),'html') === false) {
217
-				$response = new JSONResponse(
218
-					['message' => $exception->getMessage()],
219
-					$exception->getCode()
220
-				);
221
-			} else {
222
-				if($exception instanceof NotLoggedInException) {
223
-					$params = [];
224
-					if (isset($this->request->server['REQUEST_URI'])) {
225
-						$params['redirect_url'] = $this->request->server['REQUEST_URI'];
226
-					}
227
-					$url = $this->urlGenerator->linkToRoute('core.login.showLoginForm', $params);
228
-					$response = new RedirectResponse($url);
229
-				} else {
230
-					$response = new TemplateResponse('core', '403', ['message' => $exception->getMessage()], 'guest');
231
-					$response->setStatus($exception->getCode());
232
-				}
233
-			}
234
-
235
-			$this->logger->logException($exception, [
236
-				'level' => ILogger::DEBUG,
237
-				'app' => 'core',
238
-			]);
239
-			return $response;
240
-		}
241
-
242
-		throw $exception;
243
-	}
174
+            if(!$this->request->passesCSRFCheck() && !(
175
+                    $controller instanceof OCSController && (
176
+                        $this->request->getHeader('OCS-APIREQUEST') === 'true' ||
177
+                        strpos($this->request->getHeader('Authorization'), 'Bearer ') === 0
178
+                    )
179
+                )) {
180
+                throw new CrossSiteRequestForgeryException();
181
+            }
182
+        }
183
+
184
+        /**
185
+         * Checks if app is enabled (also includes a check whether user is allowed to access the resource)
186
+         * The getAppPath() check is here since components such as settings also use the AppFramework and
187
+         * therefore won't pass this check.
188
+         * If page is public, app does not need to be enabled for current user/visitor
189
+         */
190
+        try {
191
+            $appPath = $this->appManager->getAppPath($this->appName);
192
+        } catch (AppPathNotFoundException $e) {
193
+            $appPath = false;
194
+        }
195
+
196
+        if ($appPath !== false && !$isPublicPage && !$this->appManager->isEnabledForUser($this->appName)) {
197
+            throw new AppNotEnabledException();
198
+        }
199
+    }
200
+
201
+    /**
202
+     * If an SecurityException is being caught, ajax requests return a JSON error
203
+     * response and non ajax requests redirect to the index
204
+     * @param Controller $controller the controller that is being called
205
+     * @param string $methodName the name of the method that will be called on
206
+     *                           the controller
207
+     * @param \Exception $exception the thrown exception
208
+     * @throws \Exception the passed in exception if it can't handle it
209
+     * @return Response a Response object or null in case that the exception could not be handled
210
+     */
211
+    public function afterException($controller, $methodName, \Exception $exception): Response {
212
+        if($exception instanceof SecurityException) {
213
+            if($exception instanceof StrictCookieMissingException) {
214
+                return new RedirectResponse(\OC::$WEBROOT);
215
+            }
216
+            if (stripos($this->request->getHeader('Accept'),'html') === false) {
217
+                $response = new JSONResponse(
218
+                    ['message' => $exception->getMessage()],
219
+                    $exception->getCode()
220
+                );
221
+            } else {
222
+                if($exception instanceof NotLoggedInException) {
223
+                    $params = [];
224
+                    if (isset($this->request->server['REQUEST_URI'])) {
225
+                        $params['redirect_url'] = $this->request->server['REQUEST_URI'];
226
+                    }
227
+                    $url = $this->urlGenerator->linkToRoute('core.login.showLoginForm', $params);
228
+                    $response = new RedirectResponse($url);
229
+                } else {
230
+                    $response = new TemplateResponse('core', '403', ['message' => $exception->getMessage()], 'guest');
231
+                    $response->setStatus($exception->getCode());
232
+                }
233
+            }
234
+
235
+            $this->logger->logException($exception, [
236
+                'level' => ILogger::DEBUG,
237
+                'app' => 'core',
238
+            ]);
239
+            return $response;
240
+        }
241
+
242
+        throw $exception;
243
+    }
244 244
 
245 245
 }
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -137,17 +137,17 @@  discard block
 block discarded – undo
137 137
 
138 138
 		// security checks
139 139
 		$isPublicPage = $this->reflector->hasAnnotation('PublicPage');
140
-		if(!$isPublicPage) {
141
-			if(!$this->isLoggedIn) {
140
+		if (!$isPublicPage) {
141
+			if (!$this->isLoggedIn) {
142 142
 				throw new NotLoggedInException();
143 143
 			}
144 144
 
145
-			if($this->reflector->hasAnnotation('SubAdminRequired')
145
+			if ($this->reflector->hasAnnotation('SubAdminRequired')
146 146
 				&& !$this->isSubAdmin
147 147
 				&& !$this->isAdminUser) {
148 148
 				throw new NotAdminException($this->l10n->t('Logged in user must be an admin or sub admin'));
149 149
 			}
150
-			if(!$this->reflector->hasAnnotation('SubAdminRequired')
150
+			if (!$this->reflector->hasAnnotation('SubAdminRequired')
151 151
 				&& !$this->reflector->hasAnnotation('NoAdminRequired')
152 152
 				&& !$this->isAdminUser) {
153 153
 				throw new NotAdminException($this->l10n->t('Logged in user must be an admin'));
@@ -155,14 +155,14 @@  discard block
 block discarded – undo
155 155
 		}
156 156
 
157 157
 		// Check for strict cookie requirement
158
-		if($this->reflector->hasAnnotation('StrictCookieRequired') || !$this->reflector->hasAnnotation('NoCSRFRequired')) {
159
-			if(!$this->request->passesStrictCookieCheck()) {
158
+		if ($this->reflector->hasAnnotation('StrictCookieRequired') || !$this->reflector->hasAnnotation('NoCSRFRequired')) {
159
+			if (!$this->request->passesStrictCookieCheck()) {
160 160
 				throw new StrictCookieMissingException();
161 161
 			}
162 162
 		}
163 163
 		// CSRF check - also registers the CSRF token since the session may be closed later
164 164
 		Util::callRegister();
165
-		if(!$this->reflector->hasAnnotation('NoCSRFRequired')) {
165
+		if (!$this->reflector->hasAnnotation('NoCSRFRequired')) {
166 166
 			/*
167 167
 			 * Only allow the CSRF check to fail on OCS Requests. This kind of
168 168
 			 * hacks around that we have no full token auth in place yet and we
@@ -171,7 +171,7 @@  discard block
 block discarded – undo
171 171
 			 * Additionally we allow Bearer authenticated requests to pass on OCS routes.
172 172
 			 * This allows oauth apps (e.g. moodle) to use the OCS endpoints
173 173
 			 */
174
-			if(!$this->request->passesCSRFCheck() && !(
174
+			if (!$this->request->passesCSRFCheck() && !(
175 175
 					$controller instanceof OCSController && (
176 176
 						$this->request->getHeader('OCS-APIREQUEST') === 'true' ||
177 177
 						strpos($this->request->getHeader('Authorization'), 'Bearer ') === 0
@@ -209,17 +209,17 @@  discard block
 block discarded – undo
209 209
 	 * @return Response a Response object or null in case that the exception could not be handled
210 210
 	 */
211 211
 	public function afterException($controller, $methodName, \Exception $exception): Response {
212
-		if($exception instanceof SecurityException) {
213
-			if($exception instanceof StrictCookieMissingException) {
212
+		if ($exception instanceof SecurityException) {
213
+			if ($exception instanceof StrictCookieMissingException) {
214 214
 				return new RedirectResponse(\OC::$WEBROOT);
215 215
 			}
216
-			if (stripos($this->request->getHeader('Accept'),'html') === false) {
216
+			if (stripos($this->request->getHeader('Accept'), 'html') === false) {
217 217
 				$response = new JSONResponse(
218 218
 					['message' => $exception->getMessage()],
219 219
 					$exception->getCode()
220 220
 				);
221 221
 			} else {
222
-				if($exception instanceof NotLoggedInException) {
222
+				if ($exception instanceof NotLoggedInException) {
223 223
 					$params = [];
224 224
 					if (isset($this->request->server['REQUEST_URI'])) {
225 225
 						$params['redirect_url'] = $this->request->server['REQUEST_URI'];
Please login to merge, or discard this patch.
lib/private/AppFramework/Http.php 2 patches
Indentation   +115 added lines, -115 removed lines patch added patch discarded remove patch
@@ -34,121 +34,121 @@
 block discarded – undo
34 34
 
35 35
 class Http extends BaseHttp {
36 36
 
37
-	private $server;
38
-	private $protocolVersion;
39
-	protected $headers;
40
-
41
-	/**
42
-	 * @param array $server $_SERVER
43
-	 * @param string $protocolVersion the http version to use defaults to HTTP/1.1
44
-	 */
45
-	public function __construct($server, $protocolVersion='HTTP/1.1') {
46
-		$this->server = $server;
47
-		$this->protocolVersion = $protocolVersion;
48
-
49
-		$this->headers = [
50
-			self::STATUS_CONTINUE => 'Continue',
51
-			self::STATUS_SWITCHING_PROTOCOLS => 'Switching Protocols',
52
-			self::STATUS_PROCESSING => 'Processing',
53
-			self::STATUS_OK => 'OK',
54
-			self::STATUS_CREATED => 'Created',
55
-			self::STATUS_ACCEPTED => 'Accepted',
56
-			self::STATUS_NON_AUTHORATIVE_INFORMATION => 'Non-Authorative Information',
57
-			self::STATUS_NO_CONTENT => 'No Content',
58
-			self::STATUS_RESET_CONTENT => 'Reset Content',
59
-			self::STATUS_PARTIAL_CONTENT => 'Partial Content',
60
-			self::STATUS_MULTI_STATUS => 'Multi-Status', // RFC 4918
61
-			self::STATUS_ALREADY_REPORTED => 'Already Reported', // RFC 5842
62
-			self::STATUS_IM_USED => 'IM Used', // RFC 3229
63
-			self::STATUS_MULTIPLE_CHOICES => 'Multiple Choices',
64
-			self::STATUS_MOVED_PERMANENTLY => 'Moved Permanently',
65
-			self::STATUS_FOUND => 'Found',
66
-			self::STATUS_SEE_OTHER => 'See Other',
67
-			self::STATUS_NOT_MODIFIED => 'Not Modified',
68
-			self::STATUS_USE_PROXY => 'Use Proxy',
69
-			self::STATUS_RESERVED => 'Reserved',
70
-			self::STATUS_TEMPORARY_REDIRECT => 'Temporary Redirect',
71
-			self::STATUS_BAD_REQUEST => 'Bad request',
72
-			self::STATUS_UNAUTHORIZED => 'Unauthorized',
73
-			self::STATUS_PAYMENT_REQUIRED => 'Payment Required',
74
-			self::STATUS_FORBIDDEN => 'Forbidden',
75
-			self::STATUS_NOT_FOUND => 'Not Found',
76
-			self::STATUS_METHOD_NOT_ALLOWED => 'Method Not Allowed',
77
-			self::STATUS_NOT_ACCEPTABLE => 'Not Acceptable',
78
-			self::STATUS_PROXY_AUTHENTICATION_REQUIRED => 'Proxy Authentication Required',
79
-			self::STATUS_REQUEST_TIMEOUT => 'Request Timeout',
80
-			self::STATUS_CONFLICT => 'Conflict',
81
-			self::STATUS_GONE => 'Gone',
82
-			self::STATUS_LENGTH_REQUIRED => 'Length Required',
83
-			self::STATUS_PRECONDITION_FAILED => 'Precondition failed',
84
-			self::STATUS_REQUEST_ENTITY_TOO_LARGE => 'Request Entity Too Large',
85
-			self::STATUS_REQUEST_URI_TOO_LONG => 'Request-URI Too Long',
86
-			self::STATUS_UNSUPPORTED_MEDIA_TYPE => 'Unsupported Media Type',
87
-			self::STATUS_REQUEST_RANGE_NOT_SATISFIABLE => 'Requested Range Not Satisfiable',
88
-			self::STATUS_EXPECTATION_FAILED => 'Expectation Failed',
89
-			self::STATUS_IM_A_TEAPOT => 'I\'m a teapot', // RFC 2324
90
-			self::STATUS_UNPROCESSABLE_ENTITY => 'Unprocessable Entity', // RFC 4918
91
-			self::STATUS_LOCKED => 'Locked', // RFC 4918
92
-			self::STATUS_FAILED_DEPENDENCY => 'Failed Dependency', // RFC 4918
93
-			self::STATUS_UPGRADE_REQUIRED => 'Upgrade required',
94
-			self::STATUS_PRECONDITION_REQUIRED => 'Precondition required', // draft-nottingham-http-new-status
95
-			self::STATUS_TOO_MANY_REQUESTS => 'Too Many Requests', // draft-nottingham-http-new-status
96
-			self::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE => 'Request Header Fields Too Large', // draft-nottingham-http-new-status
97
-			self::STATUS_INTERNAL_SERVER_ERROR => 'Internal Server Error',
98
-			self::STATUS_NOT_IMPLEMENTED => 'Not Implemented',
99
-			self::STATUS_BAD_GATEWAY => 'Bad Gateway',
100
-			self::STATUS_SERVICE_UNAVAILABLE => 'Service Unavailable',
101
-			self::STATUS_GATEWAY_TIMEOUT => 'Gateway Timeout',
102
-			self::STATUS_HTTP_VERSION_NOT_SUPPORTED => 'HTTP Version not supported',
103
-			self::STATUS_VARIANT_ALSO_NEGOTIATES => 'Variant Also Negotiates',
104
-			self::STATUS_INSUFFICIENT_STORAGE => 'Insufficient Storage', // RFC 4918
105
-			self::STATUS_LOOP_DETECTED => 'Loop Detected', // RFC 5842
106
-			self::STATUS_BANDWIDTH_LIMIT_EXCEEDED => 'Bandwidth Limit Exceeded', // non-standard
107
-			self::STATUS_NOT_EXTENDED => 'Not extended',
108
-			self::STATUS_NETWORK_AUTHENTICATION_REQUIRED => 'Network Authentication Required', // draft-nottingham-http-new-status
109
-		];
110
-	}
111
-
112
-
113
-	/**
114
-	 * Gets the correct header
115
-	 * @param int Http::CONSTANT $status the constant from the Http class
116
-	 * @param \DateTime $lastModified formatted last modified date
117
-	 * @param string $ETag the etag
118
-	 * @return string
119
-	 */
120
-	public function getStatusHeader($status, \DateTime $lastModified=null, 
121
-									$ETag=null) {
122
-
123
-		if(!is_null($lastModified)) {
124
-			$lastModified = $lastModified->format(\DateTime::RFC2822);
125
-		}
126
-
127
-		// if etag or lastmodified have not changed, return a not modified
128
-		if ((isset($this->server['HTTP_IF_NONE_MATCH'])
129
-			&& trim(trim($this->server['HTTP_IF_NONE_MATCH']), '"') === (string)$ETag)
130
-
131
-			||
132
-
133
-			(isset($this->server['HTTP_IF_MODIFIED_SINCE'])
134
-			&& trim($this->server['HTTP_IF_MODIFIED_SINCE']) === 
135
-				$lastModified)) {
136
-
137
-			$status = self::STATUS_NOT_MODIFIED;
138
-		}
139
-
140
-		// we have one change currently for the http 1.0 header that differs
141
-		// from 1.1: STATUS_TEMPORARY_REDIRECT should be STATUS_FOUND
142
-		// if this differs any more, we want to create childclasses for this
143
-		if($status === self::STATUS_TEMPORARY_REDIRECT 
144
-			&& $this->protocolVersion === 'HTTP/1.0') {
145
-
146
-			$status = self::STATUS_FOUND;
147
-		}
148
-
149
-		return $this->protocolVersion . ' ' . $status . ' ' . 
150
-			$this->headers[$status];
151
-	}
37
+    private $server;
38
+    private $protocolVersion;
39
+    protected $headers;
40
+
41
+    /**
42
+     * @param array $server $_SERVER
43
+     * @param string $protocolVersion the http version to use defaults to HTTP/1.1
44
+     */
45
+    public function __construct($server, $protocolVersion='HTTP/1.1') {
46
+        $this->server = $server;
47
+        $this->protocolVersion = $protocolVersion;
48
+
49
+        $this->headers = [
50
+            self::STATUS_CONTINUE => 'Continue',
51
+            self::STATUS_SWITCHING_PROTOCOLS => 'Switching Protocols',
52
+            self::STATUS_PROCESSING => 'Processing',
53
+            self::STATUS_OK => 'OK',
54
+            self::STATUS_CREATED => 'Created',
55
+            self::STATUS_ACCEPTED => 'Accepted',
56
+            self::STATUS_NON_AUTHORATIVE_INFORMATION => 'Non-Authorative Information',
57
+            self::STATUS_NO_CONTENT => 'No Content',
58
+            self::STATUS_RESET_CONTENT => 'Reset Content',
59
+            self::STATUS_PARTIAL_CONTENT => 'Partial Content',
60
+            self::STATUS_MULTI_STATUS => 'Multi-Status', // RFC 4918
61
+            self::STATUS_ALREADY_REPORTED => 'Already Reported', // RFC 5842
62
+            self::STATUS_IM_USED => 'IM Used', // RFC 3229
63
+            self::STATUS_MULTIPLE_CHOICES => 'Multiple Choices',
64
+            self::STATUS_MOVED_PERMANENTLY => 'Moved Permanently',
65
+            self::STATUS_FOUND => 'Found',
66
+            self::STATUS_SEE_OTHER => 'See Other',
67
+            self::STATUS_NOT_MODIFIED => 'Not Modified',
68
+            self::STATUS_USE_PROXY => 'Use Proxy',
69
+            self::STATUS_RESERVED => 'Reserved',
70
+            self::STATUS_TEMPORARY_REDIRECT => 'Temporary Redirect',
71
+            self::STATUS_BAD_REQUEST => 'Bad request',
72
+            self::STATUS_UNAUTHORIZED => 'Unauthorized',
73
+            self::STATUS_PAYMENT_REQUIRED => 'Payment Required',
74
+            self::STATUS_FORBIDDEN => 'Forbidden',
75
+            self::STATUS_NOT_FOUND => 'Not Found',
76
+            self::STATUS_METHOD_NOT_ALLOWED => 'Method Not Allowed',
77
+            self::STATUS_NOT_ACCEPTABLE => 'Not Acceptable',
78
+            self::STATUS_PROXY_AUTHENTICATION_REQUIRED => 'Proxy Authentication Required',
79
+            self::STATUS_REQUEST_TIMEOUT => 'Request Timeout',
80
+            self::STATUS_CONFLICT => 'Conflict',
81
+            self::STATUS_GONE => 'Gone',
82
+            self::STATUS_LENGTH_REQUIRED => 'Length Required',
83
+            self::STATUS_PRECONDITION_FAILED => 'Precondition failed',
84
+            self::STATUS_REQUEST_ENTITY_TOO_LARGE => 'Request Entity Too Large',
85
+            self::STATUS_REQUEST_URI_TOO_LONG => 'Request-URI Too Long',
86
+            self::STATUS_UNSUPPORTED_MEDIA_TYPE => 'Unsupported Media Type',
87
+            self::STATUS_REQUEST_RANGE_NOT_SATISFIABLE => 'Requested Range Not Satisfiable',
88
+            self::STATUS_EXPECTATION_FAILED => 'Expectation Failed',
89
+            self::STATUS_IM_A_TEAPOT => 'I\'m a teapot', // RFC 2324
90
+            self::STATUS_UNPROCESSABLE_ENTITY => 'Unprocessable Entity', // RFC 4918
91
+            self::STATUS_LOCKED => 'Locked', // RFC 4918
92
+            self::STATUS_FAILED_DEPENDENCY => 'Failed Dependency', // RFC 4918
93
+            self::STATUS_UPGRADE_REQUIRED => 'Upgrade required',
94
+            self::STATUS_PRECONDITION_REQUIRED => 'Precondition required', // draft-nottingham-http-new-status
95
+            self::STATUS_TOO_MANY_REQUESTS => 'Too Many Requests', // draft-nottingham-http-new-status
96
+            self::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE => 'Request Header Fields Too Large', // draft-nottingham-http-new-status
97
+            self::STATUS_INTERNAL_SERVER_ERROR => 'Internal Server Error',
98
+            self::STATUS_NOT_IMPLEMENTED => 'Not Implemented',
99
+            self::STATUS_BAD_GATEWAY => 'Bad Gateway',
100
+            self::STATUS_SERVICE_UNAVAILABLE => 'Service Unavailable',
101
+            self::STATUS_GATEWAY_TIMEOUT => 'Gateway Timeout',
102
+            self::STATUS_HTTP_VERSION_NOT_SUPPORTED => 'HTTP Version not supported',
103
+            self::STATUS_VARIANT_ALSO_NEGOTIATES => 'Variant Also Negotiates',
104
+            self::STATUS_INSUFFICIENT_STORAGE => 'Insufficient Storage', // RFC 4918
105
+            self::STATUS_LOOP_DETECTED => 'Loop Detected', // RFC 5842
106
+            self::STATUS_BANDWIDTH_LIMIT_EXCEEDED => 'Bandwidth Limit Exceeded', // non-standard
107
+            self::STATUS_NOT_EXTENDED => 'Not extended',
108
+            self::STATUS_NETWORK_AUTHENTICATION_REQUIRED => 'Network Authentication Required', // draft-nottingham-http-new-status
109
+        ];
110
+    }
111
+
112
+
113
+    /**
114
+     * Gets the correct header
115
+     * @param int Http::CONSTANT $status the constant from the Http class
116
+     * @param \DateTime $lastModified formatted last modified date
117
+     * @param string $ETag the etag
118
+     * @return string
119
+     */
120
+    public function getStatusHeader($status, \DateTime $lastModified=null, 
121
+                                    $ETag=null) {
122
+
123
+        if(!is_null($lastModified)) {
124
+            $lastModified = $lastModified->format(\DateTime::RFC2822);
125
+        }
126
+
127
+        // if etag or lastmodified have not changed, return a not modified
128
+        if ((isset($this->server['HTTP_IF_NONE_MATCH'])
129
+            && trim(trim($this->server['HTTP_IF_NONE_MATCH']), '"') === (string)$ETag)
130
+
131
+            ||
132
+
133
+            (isset($this->server['HTTP_IF_MODIFIED_SINCE'])
134
+            && trim($this->server['HTTP_IF_MODIFIED_SINCE']) === 
135
+                $lastModified)) {
136
+
137
+            $status = self::STATUS_NOT_MODIFIED;
138
+        }
139
+
140
+        // we have one change currently for the http 1.0 header that differs
141
+        // from 1.1: STATUS_TEMPORARY_REDIRECT should be STATUS_FOUND
142
+        // if this differs any more, we want to create childclasses for this
143
+        if($status === self::STATUS_TEMPORARY_REDIRECT 
144
+            && $this->protocolVersion === 'HTTP/1.0') {
145
+
146
+            $status = self::STATUS_FOUND;
147
+        }
148
+
149
+        return $this->protocolVersion . ' ' . $status . ' ' . 
150
+            $this->headers[$status];
151
+    }
152 152
 
153 153
 
154 154
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -42,7 +42,7 @@  discard block
 block discarded – undo
42 42
 	 * @param array $server $_SERVER
43 43
 	 * @param string $protocolVersion the http version to use defaults to HTTP/1.1
44 44
 	 */
45
-	public function __construct($server, $protocolVersion='HTTP/1.1') {
45
+	public function __construct($server, $protocolVersion = 'HTTP/1.1') {
46 46
 		$this->server = $server;
47 47
 		$this->protocolVersion = $protocolVersion;
48 48
 
@@ -117,16 +117,16 @@  discard block
 block discarded – undo
117 117
 	 * @param string $ETag the etag
118 118
 	 * @return string
119 119
 	 */
120
-	public function getStatusHeader($status, \DateTime $lastModified=null, 
121
-									$ETag=null) {
120
+	public function getStatusHeader($status, \DateTime $lastModified = null, 
121
+									$ETag = null) {
122 122
 
123
-		if(!is_null($lastModified)) {
123
+		if (!is_null($lastModified)) {
124 124
 			$lastModified = $lastModified->format(\DateTime::RFC2822);
125 125
 		}
126 126
 
127 127
 		// if etag or lastmodified have not changed, return a not modified
128 128
 		if ((isset($this->server['HTTP_IF_NONE_MATCH'])
129
-			&& trim(trim($this->server['HTTP_IF_NONE_MATCH']), '"') === (string)$ETag)
129
+			&& trim(trim($this->server['HTTP_IF_NONE_MATCH']), '"') === (string) $ETag)
130 130
 
131 131
 			||
132 132
 
@@ -140,13 +140,13 @@  discard block
 block discarded – undo
140 140
 		// we have one change currently for the http 1.0 header that differs
141 141
 		// from 1.1: STATUS_TEMPORARY_REDIRECT should be STATUS_FOUND
142 142
 		// if this differs any more, we want to create childclasses for this
143
-		if($status === self::STATUS_TEMPORARY_REDIRECT 
143
+		if ($status === self::STATUS_TEMPORARY_REDIRECT 
144 144
 			&& $this->protocolVersion === 'HTTP/1.0') {
145 145
 
146 146
 			$status = self::STATUS_FOUND;
147 147
 		}
148 148
 
149
-		return $this->protocolVersion . ' ' . $status . ' ' . 
149
+		return $this->protocolVersion.' '.$status.' '. 
150 150
 			$this->headers[$status];
151 151
 	}
152 152
 
Please login to merge, or discard this patch.
lib/private/legacy/OC_Defaults.php 2 patches
Indentation   +265 added lines, -265 removed lines patch added patch discarded remove patch
@@ -37,298 +37,298 @@
 block discarded – undo
37 37
  */
38 38
 class OC_Defaults {
39 39
 
40
-	private $theme;
40
+    private $theme;
41 41
 
42
-	private $defaultEntity;
43
-	private $defaultName;
44
-	private $defaultTitle;
45
-	private $defaultBaseUrl;
46
-	private $defaultSyncClientUrl;
47
-	private $defaultiOSClientUrl;
48
-	private $defaultiTunesAppId;
49
-	private $defaultAndroidClientUrl;
50
-	private $defaultDocBaseUrl;
51
-	private $defaultDocVersion;
52
-	private $defaultSlogan;
53
-	private $defaultColorPrimary;
54
-	private $defaultTextColorPrimary;
42
+    private $defaultEntity;
43
+    private $defaultName;
44
+    private $defaultTitle;
45
+    private $defaultBaseUrl;
46
+    private $defaultSyncClientUrl;
47
+    private $defaultiOSClientUrl;
48
+    private $defaultiTunesAppId;
49
+    private $defaultAndroidClientUrl;
50
+    private $defaultDocBaseUrl;
51
+    private $defaultDocVersion;
52
+    private $defaultSlogan;
53
+    private $defaultColorPrimary;
54
+    private $defaultTextColorPrimary;
55 55
 
56
-	public function __construct() {
57
-		$config = \OC::$server->getConfig();
56
+    public function __construct() {
57
+        $config = \OC::$server->getConfig();
58 58
 
59
-		$this->defaultEntity = 'Nextcloud'; /* e.g. company name, used for footers and copyright notices */
60
-		$this->defaultName = 'Nextcloud'; /* short name, used when referring to the software */
61
-		$this->defaultTitle = 'Nextcloud'; /* can be a longer name, for titles */
62
-		$this->defaultBaseUrl = 'https://nextcloud.com';
63
-		$this->defaultSyncClientUrl = $config->getSystemValue('customclient_desktop', 'https://nextcloud.com/install/#install-clients');
64
-		$this->defaultiOSClientUrl = $config->getSystemValue('customclient_ios', 'https://geo.itunes.apple.com/us/app/nextcloud/id1125420102?mt=8');
65
-		$this->defaultiTunesAppId = $config->getSystemValue('customclient_ios_appid', '1125420102');
66
-		$this->defaultAndroidClientUrl = $config->getSystemValue('customclient_android', 'https://play.google.com/store/apps/details?id=com.nextcloud.client');
67
-		$this->defaultDocBaseUrl = 'https://docs.nextcloud.com';
68
-		$this->defaultDocVersion = \OC_Util::getVersion()[0]; // used to generate doc links
69
-		$this->defaultColorPrimary = '#0082c9';
70
-		$this->defaultTextColorPrimary = '#ffffff';
59
+        $this->defaultEntity = 'Nextcloud'; /* e.g. company name, used for footers and copyright notices */
60
+        $this->defaultName = 'Nextcloud'; /* short name, used when referring to the software */
61
+        $this->defaultTitle = 'Nextcloud'; /* can be a longer name, for titles */
62
+        $this->defaultBaseUrl = 'https://nextcloud.com';
63
+        $this->defaultSyncClientUrl = $config->getSystemValue('customclient_desktop', 'https://nextcloud.com/install/#install-clients');
64
+        $this->defaultiOSClientUrl = $config->getSystemValue('customclient_ios', 'https://geo.itunes.apple.com/us/app/nextcloud/id1125420102?mt=8');
65
+        $this->defaultiTunesAppId = $config->getSystemValue('customclient_ios_appid', '1125420102');
66
+        $this->defaultAndroidClientUrl = $config->getSystemValue('customclient_android', 'https://play.google.com/store/apps/details?id=com.nextcloud.client');
67
+        $this->defaultDocBaseUrl = 'https://docs.nextcloud.com';
68
+        $this->defaultDocVersion = \OC_Util::getVersion()[0]; // used to generate doc links
69
+        $this->defaultColorPrimary = '#0082c9';
70
+        $this->defaultTextColorPrimary = '#ffffff';
71 71
 
72
-		$themePath = OC::$SERVERROOT . '/themes/' . OC_Util::getTheme() . '/defaults.php';
73
-		if (file_exists($themePath)) {
74
-			// prevent defaults.php from printing output
75
-			ob_start();
76
-			require_once $themePath;
77
-			ob_end_clean();
78
-			if (class_exists('OC_Theme')) {
79
-				$this->theme = new OC_Theme();
80
-			}
81
-		}
82
-	}
72
+        $themePath = OC::$SERVERROOT . '/themes/' . OC_Util::getTheme() . '/defaults.php';
73
+        if (file_exists($themePath)) {
74
+            // prevent defaults.php from printing output
75
+            ob_start();
76
+            require_once $themePath;
77
+            ob_end_clean();
78
+            if (class_exists('OC_Theme')) {
79
+                $this->theme = new OC_Theme();
80
+            }
81
+        }
82
+    }
83 83
 
84
-	/**
85
-	 * @param string $method
86
-	 */
87
-	private function themeExist($method) {
88
-		if (isset($this->theme) && method_exists($this->theme, $method)) {
89
-			return true;
90
-		}
91
-		return false;
92
-	}
84
+    /**
85
+     * @param string $method
86
+     */
87
+    private function themeExist($method) {
88
+        if (isset($this->theme) && method_exists($this->theme, $method)) {
89
+            return true;
90
+        }
91
+        return false;
92
+    }
93 93
 
94
-	/**
95
-	 * Returns the base URL
96
-	 * @return string URL
97
-	 */
98
-	public function getBaseUrl() {
99
-		if ($this->themeExist('getBaseUrl')) {
100
-			return $this->theme->getBaseUrl();
101
-		} else {
102
-			return $this->defaultBaseUrl;
103
-		}
104
-	}
94
+    /**
95
+     * Returns the base URL
96
+     * @return string URL
97
+     */
98
+    public function getBaseUrl() {
99
+        if ($this->themeExist('getBaseUrl')) {
100
+            return $this->theme->getBaseUrl();
101
+        } else {
102
+            return $this->defaultBaseUrl;
103
+        }
104
+    }
105 105
 
106
-	/**
107
-	 * Returns the URL where the sync clients are listed
108
-	 * @return string URL
109
-	 */
110
-	public function getSyncClientUrl() {
111
-		if ($this->themeExist('getSyncClientUrl')) {
112
-			return $this->theme->getSyncClientUrl();
113
-		} else {
114
-			return $this->defaultSyncClientUrl;
115
-		}
116
-	}
106
+    /**
107
+     * Returns the URL where the sync clients are listed
108
+     * @return string URL
109
+     */
110
+    public function getSyncClientUrl() {
111
+        if ($this->themeExist('getSyncClientUrl')) {
112
+            return $this->theme->getSyncClientUrl();
113
+        } else {
114
+            return $this->defaultSyncClientUrl;
115
+        }
116
+    }
117 117
 
118
-	/**
119
-	 * Returns the URL to the App Store for the iOS Client
120
-	 * @return string URL
121
-	 */
122
-	public function getiOSClientUrl() {
123
-		if ($this->themeExist('getiOSClientUrl')) {
124
-			return $this->theme->getiOSClientUrl();
125
-		} else {
126
-			return $this->defaultiOSClientUrl;
127
-		}
128
-	}
118
+    /**
119
+     * Returns the URL to the App Store for the iOS Client
120
+     * @return string URL
121
+     */
122
+    public function getiOSClientUrl() {
123
+        if ($this->themeExist('getiOSClientUrl')) {
124
+            return $this->theme->getiOSClientUrl();
125
+        } else {
126
+            return $this->defaultiOSClientUrl;
127
+        }
128
+    }
129 129
 
130
-	/**
131
-	 * Returns the AppId for the App Store for the iOS Client
132
-	 * @return string AppId
133
-	 */
134
-	public function getiTunesAppId() {
135
-		if ($this->themeExist('getiTunesAppId')) {
136
-			return $this->theme->getiTunesAppId();
137
-		} else {
138
-			return $this->defaultiTunesAppId;
139
-		}
140
-	}
130
+    /**
131
+     * Returns the AppId for the App Store for the iOS Client
132
+     * @return string AppId
133
+     */
134
+    public function getiTunesAppId() {
135
+        if ($this->themeExist('getiTunesAppId')) {
136
+            return $this->theme->getiTunesAppId();
137
+        } else {
138
+            return $this->defaultiTunesAppId;
139
+        }
140
+    }
141 141
 
142
-	/**
143
-	 * Returns the URL to Google Play for the Android Client
144
-	 * @return string URL
145
-	 */
146
-	public function getAndroidClientUrl() {
147
-		if ($this->themeExist('getAndroidClientUrl')) {
148
-			return $this->theme->getAndroidClientUrl();
149
-		} else {
150
-			return $this->defaultAndroidClientUrl;
151
-		}
152
-	}
142
+    /**
143
+     * Returns the URL to Google Play for the Android Client
144
+     * @return string URL
145
+     */
146
+    public function getAndroidClientUrl() {
147
+        if ($this->themeExist('getAndroidClientUrl')) {
148
+            return $this->theme->getAndroidClientUrl();
149
+        } else {
150
+            return $this->defaultAndroidClientUrl;
151
+        }
152
+    }
153 153
 
154
-	/**
155
-	 * Returns the documentation URL
156
-	 * @return string URL
157
-	 */
158
-	public function getDocBaseUrl() {
159
-		if ($this->themeExist('getDocBaseUrl')) {
160
-			return $this->theme->getDocBaseUrl();
161
-		} else {
162
-			return $this->defaultDocBaseUrl;
163
-		}
164
-	}
154
+    /**
155
+     * Returns the documentation URL
156
+     * @return string URL
157
+     */
158
+    public function getDocBaseUrl() {
159
+        if ($this->themeExist('getDocBaseUrl')) {
160
+            return $this->theme->getDocBaseUrl();
161
+        } else {
162
+            return $this->defaultDocBaseUrl;
163
+        }
164
+    }
165 165
 
166
-	/**
167
-	 * Returns the title
168
-	 * @return string title
169
-	 */
170
-	public function getTitle() {
171
-		if ($this->themeExist('getTitle')) {
172
-			return $this->theme->getTitle();
173
-		} else {
174
-			return $this->defaultTitle;
175
-		}
176
-	}
166
+    /**
167
+     * Returns the title
168
+     * @return string title
169
+     */
170
+    public function getTitle() {
171
+        if ($this->themeExist('getTitle')) {
172
+            return $this->theme->getTitle();
173
+        } else {
174
+            return $this->defaultTitle;
175
+        }
176
+    }
177 177
 
178
-	/**
179
-	 * Returns the short name of the software
180
-	 * @return string title
181
-	 */
182
-	public function getName() {
183
-		if ($this->themeExist('getName')) {
184
-			return $this->theme->getName();
185
-		} else {
186
-			return $this->defaultName;
187
-		}
188
-	}
178
+    /**
179
+     * Returns the short name of the software
180
+     * @return string title
181
+     */
182
+    public function getName() {
183
+        if ($this->themeExist('getName')) {
184
+            return $this->theme->getName();
185
+        } else {
186
+            return $this->defaultName;
187
+        }
188
+    }
189 189
 
190
-	/**
191
-	 * Returns the short name of the software containing HTML strings
192
-	 * @return string title
193
-	 */
194
-	public function getHTMLName() {
195
-		if ($this->themeExist('getHTMLName')) {
196
-			return $this->theme->getHTMLName();
197
-		} else {
198
-			return $this->defaultName;
199
-		}
200
-	}
190
+    /**
191
+     * Returns the short name of the software containing HTML strings
192
+     * @return string title
193
+     */
194
+    public function getHTMLName() {
195
+        if ($this->themeExist('getHTMLName')) {
196
+            return $this->theme->getHTMLName();
197
+        } else {
198
+            return $this->defaultName;
199
+        }
200
+    }
201 201
 
202
-	/**
203
-	 * Returns entity (e.g. company name) - used for footer, copyright
204
-	 * @return string entity name
205
-	 */
206
-	public function getEntity() {
207
-		if ($this->themeExist('getEntity')) {
208
-			return $this->theme->getEntity();
209
-		} else {
210
-			return $this->defaultEntity;
211
-		}
212
-	}
202
+    /**
203
+     * Returns entity (e.g. company name) - used for footer, copyright
204
+     * @return string entity name
205
+     */
206
+    public function getEntity() {
207
+        if ($this->themeExist('getEntity')) {
208
+            return $this->theme->getEntity();
209
+        } else {
210
+            return $this->defaultEntity;
211
+        }
212
+    }
213 213
 
214
-	/**
215
-	 * Returns slogan
216
-	 * @return string slogan
217
-	 */
218
-	public function getSlogan() {
219
-		if ($this->themeExist('getSlogan')) {
220
-			return $this->theme->getSlogan();
221
-		} else {
222
-			if ($this->defaultSlogan === null) {
223
-				$l10n = \OC::$server->getL10N('lib');
224
-				$this->defaultSlogan = $l10n->t('a safe home for all your data');
225
-			}
226
-			return $this->defaultSlogan;
227
-		}
228
-	}
214
+    /**
215
+     * Returns slogan
216
+     * @return string slogan
217
+     */
218
+    public function getSlogan() {
219
+        if ($this->themeExist('getSlogan')) {
220
+            return $this->theme->getSlogan();
221
+        } else {
222
+            if ($this->defaultSlogan === null) {
223
+                $l10n = \OC::$server->getL10N('lib');
224
+                $this->defaultSlogan = $l10n->t('a safe home for all your data');
225
+            }
226
+            return $this->defaultSlogan;
227
+        }
228
+    }
229 229
 
230
-	/**
231
-	 * Returns logo claim
232
-	 * @return string logo claim
233
-	 * @deprecated 13.0.0
234
-	 */
235
-	public function getLogoClaim() {
236
-		return '';
237
-	}
230
+    /**
231
+     * Returns logo claim
232
+     * @return string logo claim
233
+     * @deprecated 13.0.0
234
+     */
235
+    public function getLogoClaim() {
236
+        return '';
237
+    }
238 238
 
239
-	/**
240
-	 * Returns short version of the footer
241
-	 * @return string short footer
242
-	 */
243
-	public function getShortFooter() {
244
-		if ($this->themeExist('getShortFooter')) {
245
-			$footer = $this->theme->getShortFooter();
246
-		} else {
247
-			$footer = '<a href="'. $this->getBaseUrl() . '" target="_blank"' .
248
-				' rel="noreferrer noopener">' .$this->getEntity() . '</a>'.
249
-				' – ' . $this->getSlogan();
250
-		}
239
+    /**
240
+     * Returns short version of the footer
241
+     * @return string short footer
242
+     */
243
+    public function getShortFooter() {
244
+        if ($this->themeExist('getShortFooter')) {
245
+            $footer = $this->theme->getShortFooter();
246
+        } else {
247
+            $footer = '<a href="'. $this->getBaseUrl() . '" target="_blank"' .
248
+                ' rel="noreferrer noopener">' .$this->getEntity() . '</a>'.
249
+                ' – ' . $this->getSlogan();
250
+        }
251 251
 
252
-		return $footer;
253
-	}
252
+        return $footer;
253
+    }
254 254
 
255
-	/**
256
-	 * Returns long version of the footer
257
-	 * @return string long footer
258
-	 */
259
-	public function getLongFooter() {
260
-		if ($this->themeExist('getLongFooter')) {
261
-			$footer = $this->theme->getLongFooter();
262
-		} else {
263
-			$footer = $this->getShortFooter();
264
-		}
255
+    /**
256
+     * Returns long version of the footer
257
+     * @return string long footer
258
+     */
259
+    public function getLongFooter() {
260
+        if ($this->themeExist('getLongFooter')) {
261
+            $footer = $this->theme->getLongFooter();
262
+        } else {
263
+            $footer = $this->getShortFooter();
264
+        }
265 265
 
266
-		return $footer;
267
-	}
266
+        return $footer;
267
+    }
268 268
 
269
-	/**
270
-	 * @param string $key
271
-	 * @return string URL to doc with key
272
-	 */
273
-	public function buildDocLinkToKey($key) {
274
-		if ($this->themeExist('buildDocLinkToKey')) {
275
-			return $this->theme->buildDocLinkToKey($key);
276
-		}
277
-		return $this->getDocBaseUrl() . '/server/' . $this->defaultDocVersion . '/go.php?to=' . $key;
278
-	}
269
+    /**
270
+     * @param string $key
271
+     * @return string URL to doc with key
272
+     */
273
+    public function buildDocLinkToKey($key) {
274
+        if ($this->themeExist('buildDocLinkToKey')) {
275
+            return $this->theme->buildDocLinkToKey($key);
276
+        }
277
+        return $this->getDocBaseUrl() . '/server/' . $this->defaultDocVersion . '/go.php?to=' . $key;
278
+    }
279 279
 
280
-	/**
281
-	 * Returns primary color
282
-	 * @return string
283
-	 */
284
-	public function getColorPrimary() {
280
+    /**
281
+     * Returns primary color
282
+     * @return string
283
+     */
284
+    public function getColorPrimary() {
285 285
 
286
-		if ($this->themeExist('getColorPrimary')) {
287
-			return $this->theme->getColorPrimary();
288
-		}
289
-		if ($this->themeExist('getMailHeaderColor')) {
290
-			return $this->theme->getMailHeaderColor();
291
-		}
292
-		return $this->defaultColorPrimary;
293
-	}
286
+        if ($this->themeExist('getColorPrimary')) {
287
+            return $this->theme->getColorPrimary();
288
+        }
289
+        if ($this->themeExist('getMailHeaderColor')) {
290
+            return $this->theme->getMailHeaderColor();
291
+        }
292
+        return $this->defaultColorPrimary;
293
+    }
294 294
 
295
-	/**
296
-	 * @return array scss variables to overwrite
297
-	 */
298
-	public function getScssVariables() {
299
-		if($this->themeExist('getScssVariables')) {
300
-			return $this->theme->getScssVariables();
301
-		}
302
-		return [];
303
-	}
295
+    /**
296
+     * @return array scss variables to overwrite
297
+     */
298
+    public function getScssVariables() {
299
+        if($this->themeExist('getScssVariables')) {
300
+            return $this->theme->getScssVariables();
301
+        }
302
+        return [];
303
+    }
304 304
 
305
-	public function shouldReplaceIcons() {
306
-		return false;
307
-	}
305
+    public function shouldReplaceIcons() {
306
+        return false;
307
+    }
308 308
 
309
-	/**
310
-	 * Themed logo url
311
-	 *
312
-	 * @param bool $useSvg Whether to point to the SVG image or a fallback
313
-	 * @return string
314
-	 */
315
-	public function getLogo($useSvg = true) {
316
-		if ($this->themeExist('getLogo')) {
317
-			return $this->theme->getLogo($useSvg);
318
-		}
309
+    /**
310
+     * Themed logo url
311
+     *
312
+     * @param bool $useSvg Whether to point to the SVG image or a fallback
313
+     * @return string
314
+     */
315
+    public function getLogo($useSvg = true) {
316
+        if ($this->themeExist('getLogo')) {
317
+            return $this->theme->getLogo($useSvg);
318
+        }
319 319
 
320
-		if($useSvg) {
321
-			$logo = \OC::$server->getURLGenerator()->imagePath('core', 'logo/logo.svg');
322
-		} else {
323
-			$logo = \OC::$server->getURLGenerator()->imagePath('core', 'logo/logo.png');
324
-		}
325
-		return $logo . '?v=' . hash('sha1', implode('.', \OCP\Util::getVersion()));
326
-	}
320
+        if($useSvg) {
321
+            $logo = \OC::$server->getURLGenerator()->imagePath('core', 'logo/logo.svg');
322
+        } else {
323
+            $logo = \OC::$server->getURLGenerator()->imagePath('core', 'logo/logo.png');
324
+        }
325
+        return $logo . '?v=' . hash('sha1', implode('.', \OCP\Util::getVersion()));
326
+    }
327 327
 
328
-	public function getTextColorPrimary() {
329
-		if ($this->themeExist('getTextColorPrimary')) {
330
-			return $this->theme->getTextColorPrimary();
331
-		}
332
-		return $this->defaultTextColorPrimary;
333
-	}
328
+    public function getTextColorPrimary() {
329
+        if ($this->themeExist('getTextColorPrimary')) {
330
+            return $this->theme->getTextColorPrimary();
331
+        }
332
+        return $this->defaultTextColorPrimary;
333
+    }
334 334
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -69,7 +69,7 @@  discard block
 block discarded – undo
69 69
 		$this->defaultColorPrimary = '#0082c9';
70 70
 		$this->defaultTextColorPrimary = '#ffffff';
71 71
 
72
-		$themePath = OC::$SERVERROOT . '/themes/' . OC_Util::getTheme() . '/defaults.php';
72
+		$themePath = OC::$SERVERROOT.'/themes/'.OC_Util::getTheme().'/defaults.php';
73 73
 		if (file_exists($themePath)) {
74 74
 			// prevent defaults.php from printing output
75 75
 			ob_start();
@@ -244,9 +244,9 @@  discard block
 block discarded – undo
244 244
 		if ($this->themeExist('getShortFooter')) {
245 245
 			$footer = $this->theme->getShortFooter();
246 246
 		} else {
247
-			$footer = '<a href="'. $this->getBaseUrl() . '" target="_blank"' .
248
-				' rel="noreferrer noopener">' .$this->getEntity() . '</a>'.
249
-				' – ' . $this->getSlogan();
247
+			$footer = '<a href="'.$this->getBaseUrl().'" target="_blank"'.
248
+				' rel="noreferrer noopener">'.$this->getEntity().'</a>'.
249
+				' – '.$this->getSlogan();
250 250
 		}
251 251
 
252 252
 		return $footer;
@@ -274,7 +274,7 @@  discard block
 block discarded – undo
274 274
 		if ($this->themeExist('buildDocLinkToKey')) {
275 275
 			return $this->theme->buildDocLinkToKey($key);
276 276
 		}
277
-		return $this->getDocBaseUrl() . '/server/' . $this->defaultDocVersion . '/go.php?to=' . $key;
277
+		return $this->getDocBaseUrl().'/server/'.$this->defaultDocVersion.'/go.php?to='.$key;
278 278
 	}
279 279
 
280 280
 	/**
@@ -296,7 +296,7 @@  discard block
 block discarded – undo
296 296
 	 * @return array scss variables to overwrite
297 297
 	 */
298 298
 	public function getScssVariables() {
299
-		if($this->themeExist('getScssVariables')) {
299
+		if ($this->themeExist('getScssVariables')) {
300 300
 			return $this->theme->getScssVariables();
301 301
 		}
302 302
 		return [];
@@ -317,12 +317,12 @@  discard block
 block discarded – undo
317 317
 			return $this->theme->getLogo($useSvg);
318 318
 		}
319 319
 
320
-		if($useSvg) {
320
+		if ($useSvg) {
321 321
 			$logo = \OC::$server->getURLGenerator()->imagePath('core', 'logo/logo.svg');
322 322
 		} else {
323 323
 			$logo = \OC::$server->getURLGenerator()->imagePath('core', 'logo/logo.png');
324 324
 		}
325
-		return $logo . '?v=' . hash('sha1', implode('.', \OCP\Util::getVersion()));
325
+		return $logo.'?v='.hash('sha1', implode('.', \OCP\Util::getVersion()));
326 326
 	}
327 327
 
328 328
 	public function getTextColorPrimary() {
Please login to merge, or discard this patch.
lib/private/legacy/OC_Files.php 2 patches
Indentation   +380 added lines, -380 removed lines patch added patch discarded remove patch
@@ -50,385 +50,385 @@
 block discarded – undo
50 50
  *
51 51
  */
52 52
 class OC_Files {
53
-	const FILE = 1;
54
-	const ZIP_FILES = 2;
55
-	const ZIP_DIR = 3;
56
-
57
-	const UPLOAD_MIN_LIMIT_BYTES = 1048576; // 1 MiB
58
-
59
-
60
-	private static $multipartBoundary = '';
61
-
62
-	/**
63
-	 * @return string
64
-	 */
65
-	private static function getBoundary() {
66
-		if (empty(self::$multipartBoundary)) {
67
-			self::$multipartBoundary = md5(mt_rand());
68
-		}
69
-		return self::$multipartBoundary;
70
-	}
71
-
72
-	/**
73
-	 * @param string $filename
74
-	 * @param string $name
75
-	 * @param array $rangeArray ('from'=>int,'to'=>int), ...
76
-	 */
77
-	private static function sendHeaders($filename, $name, array $rangeArray) {
78
-		OC_Response::setContentDispositionHeader($name, 'attachment');
79
-		header('Content-Transfer-Encoding: binary', true);
80
-		header('Pragma: public');// enable caching in IE
81
-		header('Expires: 0');
82
-		header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
83
-		$fileSize = \OC\Files\Filesystem::filesize($filename);
84
-		$type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
85
-		if ($fileSize > -1) {
86
-			if (!empty($rangeArray)) {
87
-				http_response_code(206);
88
-				header('Accept-Ranges: bytes', true);
89
-				if (count($rangeArray) > 1) {
90
-				$type = 'multipart/byteranges; boundary='.self::getBoundary();
91
-				// no Content-Length header here
92
-				}
93
-				else {
94
-				header(sprintf('Content-Range: bytes %d-%d/%d', $rangeArray[0]['from'], $rangeArray[0]['to'], $fileSize), true);
95
-				OC_Response::setContentLengthHeader($rangeArray[0]['to'] - $rangeArray[0]['from'] + 1);
96
-				}
97
-			}
98
-			else {
99
-				OC_Response::setContentLengthHeader($fileSize);
100
-			}
101
-		}
102
-		header('Content-Type: '.$type, true);
103
-	}
104
-
105
-	/**
106
-	 * return the content of a file or return a zip file containing multiple files
107
-	 *
108
-	 * @param string $dir
109
-	 * @param string $files ; separated list of files to download
110
-	 * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
111
-	 */
112
-	public static function get($dir, $files, $params = null) {
113
-
114
-		$view = \OC\Files\Filesystem::getView();
115
-		$getType = self::FILE;
116
-		$filename = $dir;
117
-		try {
118
-
119
-			if (is_array($files) && count($files) === 1) {
120
-				$files = $files[0];
121
-			}
122
-
123
-			if (!is_array($files)) {
124
-				$filename = $dir . '/' . $files;
125
-				if (!$view->is_dir($filename)) {
126
-					self::getSingleFile($view, $dir, $files, is_null($params) ? [] : $params);
127
-					return;
128
-				}
129
-			}
130
-
131
-			$name = 'download';
132
-			if (is_array($files)) {
133
-				$getType = self::ZIP_FILES;
134
-				$basename = basename($dir);
135
-				if ($basename) {
136
-					$name = $basename;
137
-				}
138
-
139
-				$filename = $dir . '/' . $name;
140
-			} else {
141
-				$filename = $dir . '/' . $files;
142
-				$getType = self::ZIP_DIR;
143
-				// downloading root ?
144
-				if ($files !== '') {
145
-					$name = $files;
146
-				}
147
-			}
148
-
149
-			self::lockFiles($view, $dir, $files);
150
-
151
-			/* Calculate filesize and number of files */
152
-			if ($getType === self::ZIP_FILES) {
153
-				$fileInfos = [];
154
-				$fileSize = 0;
155
-				foreach ($files as $file) {
156
-					$fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $file);
157
-					$fileSize += $fileInfo->getSize();
158
-					$fileInfos[] = $fileInfo;
159
-				}
160
-				$numberOfFiles = self::getNumberOfFiles($fileInfos);
161
-			} elseif ($getType === self::ZIP_DIR) {
162
-				$fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $files);
163
-				$fileSize = $fileInfo->getSize();
164
-				$numberOfFiles = self::getNumberOfFiles([$fileInfo]);
165
-			}
166
-
167
-			$streamer = new Streamer(\OC::$server->getRequest(), $fileSize, $numberOfFiles);
168
-			OC_Util::obEnd();
169
-
170
-			$streamer->sendHeaders($name);
171
-			$executionTime = (int)OC::$server->getIniWrapper()->getNumeric('max_execution_time');
172
-			if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
173
-				@set_time_limit(0);
174
-			}
175
-			ignore_user_abort(true);
176
-
177
-			if ($getType === self::ZIP_FILES) {
178
-				foreach ($files as $file) {
179
-					$file = $dir . '/' . $file;
180
-					if (\OC\Files\Filesystem::is_file($file)) {
181
-						$userFolder = \OC::$server->getRootFolder()->get(\OC\Files\Filesystem::getRoot());
182
-						$file = $userFolder->get($file);
183
-						if($file instanceof \OC\Files\Node\File) {
184
-							try {
185
-								$fh = $file->fopen('r');
186
-							} catch (\OCP\Files\NotPermittedException $e) {
187
-								continue;
188
-							}
189
-							$fileSize = $file->getSize();
190
-							$fileTime = $file->getMTime();
191
-						} else {
192
-							// File is not a file? …
193
-							\OC::$server->getLogger()->debug(
194
-								'File given, but no Node available. Name {file}',
195
-								[ 'app' => 'files', 'file' => $file ]
196
-							);
197
-							continue;
198
-						}
199
-						$streamer->addFileFromStream($fh, $file->getName(), $fileSize, $fileTime);
200
-						fclose($fh);
201
-					} elseif (\OC\Files\Filesystem::is_dir($file)) {
202
-						$streamer->addDirRecursive($file);
203
-					}
204
-				}
205
-			} elseif ($getType === self::ZIP_DIR) {
206
-				$file = $dir . '/' . $files;
207
-				$streamer->addDirRecursive($file);
208
-			}
209
-			$streamer->finalize();
210
-			set_time_limit($executionTime);
211
-			self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
212
-		} catch (\OCP\Lock\LockedException $ex) {
213
-			self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
214
-			OC::$server->getLogger()->logException($ex);
215
-			$l = \OC::$server->getL10N('core');
216
-			$hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
217
-			\OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint, 200);
218
-		} catch (\OCP\Files\ForbiddenException $ex) {
219
-			self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
220
-			OC::$server->getLogger()->logException($ex);
221
-			$l = \OC::$server->getL10N('core');
222
-			\OC_Template::printErrorPage($l->t('Can\'t read file'), $ex->getMessage(), 200);
223
-		} catch (\Exception $ex) {
224
-			self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
225
-			OC::$server->getLogger()->logException($ex);
226
-			$l = \OC::$server->getL10N('core');
227
-			$hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
228
-			\OC_Template::printErrorPage($l->t('Can\'t read file'), $hint, 200);
229
-		}
230
-	}
231
-
232
-	/**
233
-	 * @param string $rangeHeaderPos
234
-	 * @param int $fileSize
235
-	 * @return array $rangeArray ('from'=>int,'to'=>int), ...
236
-	 */
237
-	private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize) {
238
-		$rArray=explode(',', $rangeHeaderPos);
239
-		$minOffset = 0;
240
-		$ind = 0;
241
-
242
-		$rangeArray = [];
243
-
244
-		foreach ($rArray as $value) {
245
-			$ranges = explode('-', $value);
246
-			if (is_numeric($ranges[0])) {
247
-				if ($ranges[0] < $minOffset) { // case: bytes=500-700,601-999
248
-					$ranges[0] = $minOffset;
249
-				}
250
-				if ($ind > 0 && $rangeArray[$ind-1]['to']+1 == $ranges[0]) { // case: bytes=500-600,601-999
251
-					$ind--;
252
-					$ranges[0] = $rangeArray[$ind]['from'];
253
-				}
254
-			}
255
-
256
-			if (is_numeric($ranges[0]) && is_numeric($ranges[1]) && $ranges[0] < $fileSize && $ranges[0] <= $ranges[1]) {
257
-				// case: x-x
258
-				if ($ranges[1] >= $fileSize) {
259
-					$ranges[1] = $fileSize-1;
260
-				}
261
-				$rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $ranges[1], 'size' => $fileSize ];
262
-				$minOffset = $ranges[1] + 1;
263
-				if ($minOffset >= $fileSize) {
264
-					break;
265
-				}
266
-			}
267
-			elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) {
268
-				// case: x-
269
-				$rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $fileSize-1, 'size' => $fileSize ];
270
-				break;
271
-			}
272
-			elseif (is_numeric($ranges[1])) {
273
-				// case: -x
274
-				if ($ranges[1] > $fileSize) {
275
-					$ranges[1] = $fileSize;
276
-				}
277
-				$rangeArray[$ind++] = [ 'from' => $fileSize-$ranges[1], 'to' => $fileSize-1, 'size' => $fileSize ];
278
-				break;
279
-			}
280
-		}
281
-		return $rangeArray;
282
-	}
283
-
284
-	/**
285
-	 * @param View $view
286
-	 * @param string $name
287
-	 * @param string $dir
288
-	 * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
289
-	 */
290
-	private static function getSingleFile($view, $dir, $name, $params) {
291
-		$filename = $dir . '/' . $name;
292
-		$file = null;
293
-
294
-		try {
295
-			$userFolder = \OC::$server->getRootFolder()->get(\OC\Files\Filesystem::getRoot());
296
-			$file = $userFolder->get($filename);
297
-			if(!$file instanceof \OC\Files\Node\File || !$file->isReadable()) {
298
-				http_response_code(403);
299
-				die('403 Forbidden');
300
-			}
301
-			$fileSize = $file->getSize();
302
-		} catch (\OCP\Files\NotPermittedException $e) {
303
-			http_response_code(403);
304
-			die('403 Forbidden');
305
-		} catch (\OCP\Files\InvalidPathException $e) {
306
-			http_response_code(403);
307
-			die('403 Forbidden');
308
-		} catch (\OCP\Files\NotFoundException $e) {
309
-			http_response_code(404);
310
-			$tmpl = new OC_Template('', '404', 'guest');
311
-			$tmpl->printPage();
312
-			exit();
313
-		}
314
-
315
-		OC_Util::obEnd();
316
-		$view->lockFile($filename, ILockingProvider::LOCK_SHARED);
317
-
318
-		$rangeArray = [];
319
-
320
-		if (isset($params['range']) && substr($params['range'], 0, 6) === 'bytes=') {
321
-			$rangeArray = self::parseHttpRangeHeader(substr($params['range'], 6), $fileSize);
322
-		}
323
-
324
-		self::sendHeaders($filename, $name, $rangeArray);
325
-
326
-		if (isset($params['head']) && $params['head']) {
327
-			return;
328
-		}
329
-
330
-		if (!empty($rangeArray)) {
331
-			try {
332
-				if (count($rangeArray) == 1) {
333
-				$view->readfilePart($filename, $rangeArray[0]['from'], $rangeArray[0]['to']);
334
-				}
335
-				else {
336
-				// check if file is seekable (if not throw UnseekableException)
337
-				// we have to check it before body contents
338
-				$view->readfilePart($filename, $rangeArray[0]['size'], $rangeArray[0]['size']);
339
-
340
-				$type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
341
-
342
-				foreach ($rangeArray as $range) {
343
-					echo "\r\n--".self::getBoundary()."\r\n".
344
-						 "Content-type: ".$type."\r\n".
345
-						 "Content-range: bytes ".$range['from']."-".$range['to']."/".$range['size']."\r\n\r\n";
346
-					$view->readfilePart($filename, $range['from'], $range['to']);
347
-				}
348
-				echo "\r\n--".self::getBoundary()."--\r\n";
349
-				}
350
-			} catch (\OCP\Files\UnseekableException $ex) {
351
-				// file is unseekable
352
-				header_remove('Accept-Ranges');
353
-				header_remove('Content-Range');
354
-				http_response_code(200);
355
-				self::sendHeaders($filename, $name, []);
356
-				$view->readfile($filename);
357
-			}
358
-		}
359
-		else {
360
-			$view->readfile($filename);
361
-		}
362
-	}
363
-
364
-	/**
365
-	 * Returns the total (recursive) number of files and folders in the given
366
-	 * FileInfos.
367
-	 *
368
-	 * @param \OCP\Files\FileInfo[] $fileInfos the FileInfos to count
369
-	 * @return int the total number of files and folders
370
-	 */
371
-	private static function getNumberOfFiles($fileInfos) {
372
-		$numberOfFiles = 0;
373
-
374
-		$view = new View();
375
-
376
-		while ($fileInfo = array_pop($fileInfos)) {
377
-			$numberOfFiles++;
378
-
379
-			if ($fileInfo->getType() === \OCP\Files\FileInfo::TYPE_FOLDER) {
380
-				$fileInfos = array_merge($fileInfos, $view->getDirectoryContent($fileInfo->getPath()));
381
-			}
382
-		}
383
-
384
-		return $numberOfFiles;
385
-	}
386
-
387
-	/**
388
-	 * @param View $view
389
-	 * @param string $dir
390
-	 * @param string[]|string $files
391
-	 */
392
-	public static function lockFiles($view, $dir, $files) {
393
-		if (!is_array($files)) {
394
-			$file = $dir . '/' . $files;
395
-			$files = [$file];
396
-		}
397
-		foreach ($files as $file) {
398
-			$file = $dir . '/' . $file;
399
-			$view->lockFile($file, ILockingProvider::LOCK_SHARED);
400
-			if ($view->is_dir($file)) {
401
-				$contents = $view->getDirectoryContent($file);
402
-				$contents = array_map(function($fileInfo) use ($file) {
403
-					/** @var \OCP\Files\FileInfo $fileInfo */
404
-					return $file . '/' . $fileInfo->getName();
405
-				}, $contents);
406
-				self::lockFiles($view, $dir, $contents);
407
-			}
408
-		}
409
-	}
410
-
411
-	/**
412
-	 * @param string $dir
413
-	 * @param $files
414
-	 * @param integer $getType
415
-	 * @param View $view
416
-	 * @param string $filename
417
-	 */
418
-	private static function unlockAllTheFiles($dir, $files, $getType, $view, $filename) {
419
-		if ($getType === self::FILE) {
420
-			$view->unlockFile($filename, ILockingProvider::LOCK_SHARED);
421
-		}
422
-		if ($getType === self::ZIP_FILES) {
423
-			foreach ($files as $file) {
424
-				$file = $dir . '/' . $file;
425
-				$view->unlockFile($file, ILockingProvider::LOCK_SHARED);
426
-			}
427
-		}
428
-		if ($getType === self::ZIP_DIR) {
429
-			$file = $dir . '/' . $files;
430
-			$view->unlockFile($file, ILockingProvider::LOCK_SHARED);
431
-		}
432
-	}
53
+    const FILE = 1;
54
+    const ZIP_FILES = 2;
55
+    const ZIP_DIR = 3;
56
+
57
+    const UPLOAD_MIN_LIMIT_BYTES = 1048576; // 1 MiB
58
+
59
+
60
+    private static $multipartBoundary = '';
61
+
62
+    /**
63
+     * @return string
64
+     */
65
+    private static function getBoundary() {
66
+        if (empty(self::$multipartBoundary)) {
67
+            self::$multipartBoundary = md5(mt_rand());
68
+        }
69
+        return self::$multipartBoundary;
70
+    }
71
+
72
+    /**
73
+     * @param string $filename
74
+     * @param string $name
75
+     * @param array $rangeArray ('from'=>int,'to'=>int), ...
76
+     */
77
+    private static function sendHeaders($filename, $name, array $rangeArray) {
78
+        OC_Response::setContentDispositionHeader($name, 'attachment');
79
+        header('Content-Transfer-Encoding: binary', true);
80
+        header('Pragma: public');// enable caching in IE
81
+        header('Expires: 0');
82
+        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
83
+        $fileSize = \OC\Files\Filesystem::filesize($filename);
84
+        $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
85
+        if ($fileSize > -1) {
86
+            if (!empty($rangeArray)) {
87
+                http_response_code(206);
88
+                header('Accept-Ranges: bytes', true);
89
+                if (count($rangeArray) > 1) {
90
+                $type = 'multipart/byteranges; boundary='.self::getBoundary();
91
+                // no Content-Length header here
92
+                }
93
+                else {
94
+                header(sprintf('Content-Range: bytes %d-%d/%d', $rangeArray[0]['from'], $rangeArray[0]['to'], $fileSize), true);
95
+                OC_Response::setContentLengthHeader($rangeArray[0]['to'] - $rangeArray[0]['from'] + 1);
96
+                }
97
+            }
98
+            else {
99
+                OC_Response::setContentLengthHeader($fileSize);
100
+            }
101
+        }
102
+        header('Content-Type: '.$type, true);
103
+    }
104
+
105
+    /**
106
+     * return the content of a file or return a zip file containing multiple files
107
+     *
108
+     * @param string $dir
109
+     * @param string $files ; separated list of files to download
110
+     * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
111
+     */
112
+    public static function get($dir, $files, $params = null) {
113
+
114
+        $view = \OC\Files\Filesystem::getView();
115
+        $getType = self::FILE;
116
+        $filename = $dir;
117
+        try {
118
+
119
+            if (is_array($files) && count($files) === 1) {
120
+                $files = $files[0];
121
+            }
122
+
123
+            if (!is_array($files)) {
124
+                $filename = $dir . '/' . $files;
125
+                if (!$view->is_dir($filename)) {
126
+                    self::getSingleFile($view, $dir, $files, is_null($params) ? [] : $params);
127
+                    return;
128
+                }
129
+            }
130
+
131
+            $name = 'download';
132
+            if (is_array($files)) {
133
+                $getType = self::ZIP_FILES;
134
+                $basename = basename($dir);
135
+                if ($basename) {
136
+                    $name = $basename;
137
+                }
138
+
139
+                $filename = $dir . '/' . $name;
140
+            } else {
141
+                $filename = $dir . '/' . $files;
142
+                $getType = self::ZIP_DIR;
143
+                // downloading root ?
144
+                if ($files !== '') {
145
+                    $name = $files;
146
+                }
147
+            }
148
+
149
+            self::lockFiles($view, $dir, $files);
150
+
151
+            /* Calculate filesize and number of files */
152
+            if ($getType === self::ZIP_FILES) {
153
+                $fileInfos = [];
154
+                $fileSize = 0;
155
+                foreach ($files as $file) {
156
+                    $fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $file);
157
+                    $fileSize += $fileInfo->getSize();
158
+                    $fileInfos[] = $fileInfo;
159
+                }
160
+                $numberOfFiles = self::getNumberOfFiles($fileInfos);
161
+            } elseif ($getType === self::ZIP_DIR) {
162
+                $fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $files);
163
+                $fileSize = $fileInfo->getSize();
164
+                $numberOfFiles = self::getNumberOfFiles([$fileInfo]);
165
+            }
166
+
167
+            $streamer = new Streamer(\OC::$server->getRequest(), $fileSize, $numberOfFiles);
168
+            OC_Util::obEnd();
169
+
170
+            $streamer->sendHeaders($name);
171
+            $executionTime = (int)OC::$server->getIniWrapper()->getNumeric('max_execution_time');
172
+            if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
173
+                @set_time_limit(0);
174
+            }
175
+            ignore_user_abort(true);
176
+
177
+            if ($getType === self::ZIP_FILES) {
178
+                foreach ($files as $file) {
179
+                    $file = $dir . '/' . $file;
180
+                    if (\OC\Files\Filesystem::is_file($file)) {
181
+                        $userFolder = \OC::$server->getRootFolder()->get(\OC\Files\Filesystem::getRoot());
182
+                        $file = $userFolder->get($file);
183
+                        if($file instanceof \OC\Files\Node\File) {
184
+                            try {
185
+                                $fh = $file->fopen('r');
186
+                            } catch (\OCP\Files\NotPermittedException $e) {
187
+                                continue;
188
+                            }
189
+                            $fileSize = $file->getSize();
190
+                            $fileTime = $file->getMTime();
191
+                        } else {
192
+                            // File is not a file? …
193
+                            \OC::$server->getLogger()->debug(
194
+                                'File given, but no Node available. Name {file}',
195
+                                [ 'app' => 'files', 'file' => $file ]
196
+                            );
197
+                            continue;
198
+                        }
199
+                        $streamer->addFileFromStream($fh, $file->getName(), $fileSize, $fileTime);
200
+                        fclose($fh);
201
+                    } elseif (\OC\Files\Filesystem::is_dir($file)) {
202
+                        $streamer->addDirRecursive($file);
203
+                    }
204
+                }
205
+            } elseif ($getType === self::ZIP_DIR) {
206
+                $file = $dir . '/' . $files;
207
+                $streamer->addDirRecursive($file);
208
+            }
209
+            $streamer->finalize();
210
+            set_time_limit($executionTime);
211
+            self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
212
+        } catch (\OCP\Lock\LockedException $ex) {
213
+            self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
214
+            OC::$server->getLogger()->logException($ex);
215
+            $l = \OC::$server->getL10N('core');
216
+            $hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
217
+            \OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint, 200);
218
+        } catch (\OCP\Files\ForbiddenException $ex) {
219
+            self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
220
+            OC::$server->getLogger()->logException($ex);
221
+            $l = \OC::$server->getL10N('core');
222
+            \OC_Template::printErrorPage($l->t('Can\'t read file'), $ex->getMessage(), 200);
223
+        } catch (\Exception $ex) {
224
+            self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
225
+            OC::$server->getLogger()->logException($ex);
226
+            $l = \OC::$server->getL10N('core');
227
+            $hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
228
+            \OC_Template::printErrorPage($l->t('Can\'t read file'), $hint, 200);
229
+        }
230
+    }
231
+
232
+    /**
233
+     * @param string $rangeHeaderPos
234
+     * @param int $fileSize
235
+     * @return array $rangeArray ('from'=>int,'to'=>int), ...
236
+     */
237
+    private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize) {
238
+        $rArray=explode(',', $rangeHeaderPos);
239
+        $minOffset = 0;
240
+        $ind = 0;
241
+
242
+        $rangeArray = [];
243
+
244
+        foreach ($rArray as $value) {
245
+            $ranges = explode('-', $value);
246
+            if (is_numeric($ranges[0])) {
247
+                if ($ranges[0] < $minOffset) { // case: bytes=500-700,601-999
248
+                    $ranges[0] = $minOffset;
249
+                }
250
+                if ($ind > 0 && $rangeArray[$ind-1]['to']+1 == $ranges[0]) { // case: bytes=500-600,601-999
251
+                    $ind--;
252
+                    $ranges[0] = $rangeArray[$ind]['from'];
253
+                }
254
+            }
255
+
256
+            if (is_numeric($ranges[0]) && is_numeric($ranges[1]) && $ranges[0] < $fileSize && $ranges[0] <= $ranges[1]) {
257
+                // case: x-x
258
+                if ($ranges[1] >= $fileSize) {
259
+                    $ranges[1] = $fileSize-1;
260
+                }
261
+                $rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $ranges[1], 'size' => $fileSize ];
262
+                $minOffset = $ranges[1] + 1;
263
+                if ($minOffset >= $fileSize) {
264
+                    break;
265
+                }
266
+            }
267
+            elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) {
268
+                // case: x-
269
+                $rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $fileSize-1, 'size' => $fileSize ];
270
+                break;
271
+            }
272
+            elseif (is_numeric($ranges[1])) {
273
+                // case: -x
274
+                if ($ranges[1] > $fileSize) {
275
+                    $ranges[1] = $fileSize;
276
+                }
277
+                $rangeArray[$ind++] = [ 'from' => $fileSize-$ranges[1], 'to' => $fileSize-1, 'size' => $fileSize ];
278
+                break;
279
+            }
280
+        }
281
+        return $rangeArray;
282
+    }
283
+
284
+    /**
285
+     * @param View $view
286
+     * @param string $name
287
+     * @param string $dir
288
+     * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
289
+     */
290
+    private static function getSingleFile($view, $dir, $name, $params) {
291
+        $filename = $dir . '/' . $name;
292
+        $file = null;
293
+
294
+        try {
295
+            $userFolder = \OC::$server->getRootFolder()->get(\OC\Files\Filesystem::getRoot());
296
+            $file = $userFolder->get($filename);
297
+            if(!$file instanceof \OC\Files\Node\File || !$file->isReadable()) {
298
+                http_response_code(403);
299
+                die('403 Forbidden');
300
+            }
301
+            $fileSize = $file->getSize();
302
+        } catch (\OCP\Files\NotPermittedException $e) {
303
+            http_response_code(403);
304
+            die('403 Forbidden');
305
+        } catch (\OCP\Files\InvalidPathException $e) {
306
+            http_response_code(403);
307
+            die('403 Forbidden');
308
+        } catch (\OCP\Files\NotFoundException $e) {
309
+            http_response_code(404);
310
+            $tmpl = new OC_Template('', '404', 'guest');
311
+            $tmpl->printPage();
312
+            exit();
313
+        }
314
+
315
+        OC_Util::obEnd();
316
+        $view->lockFile($filename, ILockingProvider::LOCK_SHARED);
317
+
318
+        $rangeArray = [];
319
+
320
+        if (isset($params['range']) && substr($params['range'], 0, 6) === 'bytes=') {
321
+            $rangeArray = self::parseHttpRangeHeader(substr($params['range'], 6), $fileSize);
322
+        }
323
+
324
+        self::sendHeaders($filename, $name, $rangeArray);
325
+
326
+        if (isset($params['head']) && $params['head']) {
327
+            return;
328
+        }
329
+
330
+        if (!empty($rangeArray)) {
331
+            try {
332
+                if (count($rangeArray) == 1) {
333
+                $view->readfilePart($filename, $rangeArray[0]['from'], $rangeArray[0]['to']);
334
+                }
335
+                else {
336
+                // check if file is seekable (if not throw UnseekableException)
337
+                // we have to check it before body contents
338
+                $view->readfilePart($filename, $rangeArray[0]['size'], $rangeArray[0]['size']);
339
+
340
+                $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
341
+
342
+                foreach ($rangeArray as $range) {
343
+                    echo "\r\n--".self::getBoundary()."\r\n".
344
+                            "Content-type: ".$type."\r\n".
345
+                            "Content-range: bytes ".$range['from']."-".$range['to']."/".$range['size']."\r\n\r\n";
346
+                    $view->readfilePart($filename, $range['from'], $range['to']);
347
+                }
348
+                echo "\r\n--".self::getBoundary()."--\r\n";
349
+                }
350
+            } catch (\OCP\Files\UnseekableException $ex) {
351
+                // file is unseekable
352
+                header_remove('Accept-Ranges');
353
+                header_remove('Content-Range');
354
+                http_response_code(200);
355
+                self::sendHeaders($filename, $name, []);
356
+                $view->readfile($filename);
357
+            }
358
+        }
359
+        else {
360
+            $view->readfile($filename);
361
+        }
362
+    }
363
+
364
+    /**
365
+     * Returns the total (recursive) number of files and folders in the given
366
+     * FileInfos.
367
+     *
368
+     * @param \OCP\Files\FileInfo[] $fileInfos the FileInfos to count
369
+     * @return int the total number of files and folders
370
+     */
371
+    private static function getNumberOfFiles($fileInfos) {
372
+        $numberOfFiles = 0;
373
+
374
+        $view = new View();
375
+
376
+        while ($fileInfo = array_pop($fileInfos)) {
377
+            $numberOfFiles++;
378
+
379
+            if ($fileInfo->getType() === \OCP\Files\FileInfo::TYPE_FOLDER) {
380
+                $fileInfos = array_merge($fileInfos, $view->getDirectoryContent($fileInfo->getPath()));
381
+            }
382
+        }
383
+
384
+        return $numberOfFiles;
385
+    }
386
+
387
+    /**
388
+     * @param View $view
389
+     * @param string $dir
390
+     * @param string[]|string $files
391
+     */
392
+    public static function lockFiles($view, $dir, $files) {
393
+        if (!is_array($files)) {
394
+            $file = $dir . '/' . $files;
395
+            $files = [$file];
396
+        }
397
+        foreach ($files as $file) {
398
+            $file = $dir . '/' . $file;
399
+            $view->lockFile($file, ILockingProvider::LOCK_SHARED);
400
+            if ($view->is_dir($file)) {
401
+                $contents = $view->getDirectoryContent($file);
402
+                $contents = array_map(function($fileInfo) use ($file) {
403
+                    /** @var \OCP\Files\FileInfo $fileInfo */
404
+                    return $file . '/' . $fileInfo->getName();
405
+                }, $contents);
406
+                self::lockFiles($view, $dir, $contents);
407
+            }
408
+        }
409
+    }
410
+
411
+    /**
412
+     * @param string $dir
413
+     * @param $files
414
+     * @param integer $getType
415
+     * @param View $view
416
+     * @param string $filename
417
+     */
418
+    private static function unlockAllTheFiles($dir, $files, $getType, $view, $filename) {
419
+        if ($getType === self::FILE) {
420
+            $view->unlockFile($filename, ILockingProvider::LOCK_SHARED);
421
+        }
422
+        if ($getType === self::ZIP_FILES) {
423
+            foreach ($files as $file) {
424
+                $file = $dir . '/' . $file;
425
+                $view->unlockFile($file, ILockingProvider::LOCK_SHARED);
426
+            }
427
+        }
428
+        if ($getType === self::ZIP_DIR) {
429
+            $file = $dir . '/' . $files;
430
+            $view->unlockFile($file, ILockingProvider::LOCK_SHARED);
431
+        }
432
+    }
433 433
 
434 434
 }
Please login to merge, or discard this patch.
Braces   +6 added lines, -12 removed lines patch added patch discarded remove patch
@@ -89,13 +89,11 @@  discard block
 block discarded – undo
89 89
 				if (count($rangeArray) > 1) {
90 90
 				$type = 'multipart/byteranges; boundary='.self::getBoundary();
91 91
 				// no Content-Length header here
92
-				}
93
-				else {
92
+				} else {
94 93
 				header(sprintf('Content-Range: bytes %d-%d/%d', $rangeArray[0]['from'], $rangeArray[0]['to'], $fileSize), true);
95 94
 				OC_Response::setContentLengthHeader($rangeArray[0]['to'] - $rangeArray[0]['from'] + 1);
96 95
 				}
97
-			}
98
-			else {
96
+			} else {
99 97
 				OC_Response::setContentLengthHeader($fileSize);
100 98
 			}
101 99
 		}
@@ -263,13 +261,11 @@  discard block
 block discarded – undo
263 261
 				if ($minOffset >= $fileSize) {
264 262
 					break;
265 263
 				}
266
-			}
267
-			elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) {
264
+			} elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) {
268 265
 				// case: x-
269 266
 				$rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $fileSize-1, 'size' => $fileSize ];
270 267
 				break;
271
-			}
272
-			elseif (is_numeric($ranges[1])) {
268
+			} elseif (is_numeric($ranges[1])) {
273 269
 				// case: -x
274 270
 				if ($ranges[1] > $fileSize) {
275 271
 					$ranges[1] = $fileSize;
@@ -331,8 +327,7 @@  discard block
 block discarded – undo
331 327
 			try {
332 328
 				if (count($rangeArray) == 1) {
333 329
 				$view->readfilePart($filename, $rangeArray[0]['from'], $rangeArray[0]['to']);
334
-				}
335
-				else {
330
+				} else {
336 331
 				// check if file is seekable (if not throw UnseekableException)
337 332
 				// we have to check it before body contents
338 333
 				$view->readfilePart($filename, $rangeArray[0]['size'], $rangeArray[0]['size']);
@@ -355,8 +350,7 @@  discard block
 block discarded – undo
355 350
 				self::sendHeaders($filename, $name, []);
356 351
 				$view->readfile($filename);
357 352
 			}
358
-		}
359
-		else {
353
+		} else {
360 354
 			$view->readfile($filename);
361 355
 		}
362 356
 	}
Please login to merge, or discard this patch.
lib/private/legacy/OC_Hook.php 1 patch
Indentation   +103 added lines, -103 removed lines patch added patch discarded remove patch
@@ -34,118 +34,118 @@
 block discarded – undo
34 34
  * @deprecated 18.0.0 use events and the \OCP\EventDispatcher\IEventDispatcher service
35 35
  */
36 36
 class OC_Hook {
37
-	public static $thrownExceptions = [];
37
+    public static $thrownExceptions = [];
38 38
 
39
-	static private $registered = [];
39
+    static private $registered = [];
40 40
 
41
-	/**
42
-	 * connects a function to a hook
43
-	 *
44
-	 * @param string $signalClass class name of emitter
45
-	 * @param string $signalName name of signal
46
-	 * @param string|object $slotClass class name of slot
47
-	 * @param string $slotName name of slot
48
-	 * @return bool
49
-	 *
50
-	 * This function makes it very easy to connect to use hooks.
51
-	 *
52
-	 * TODO: write example
53
-	 */
54
-	static public function connect($signalClass, $signalName, $slotClass, $slotName ) {
55
-		// If we're trying to connect to an emitting class that isn't
56
-		// yet registered, register it
57
-		if( !array_key_exists($signalClass, self::$registered )) {
58
-			self::$registered[$signalClass] = [];
59
-		}
60
-		// If we're trying to connect to an emitting method that isn't
61
-		// yet registered, register it with the emitting class
62
-		if( !array_key_exists( $signalName, self::$registered[$signalClass] )) {
63
-			self::$registered[$signalClass][$signalName] = [];
64
-		}
41
+    /**
42
+     * connects a function to a hook
43
+     *
44
+     * @param string $signalClass class name of emitter
45
+     * @param string $signalName name of signal
46
+     * @param string|object $slotClass class name of slot
47
+     * @param string $slotName name of slot
48
+     * @return bool
49
+     *
50
+     * This function makes it very easy to connect to use hooks.
51
+     *
52
+     * TODO: write example
53
+     */
54
+    static public function connect($signalClass, $signalName, $slotClass, $slotName ) {
55
+        // If we're trying to connect to an emitting class that isn't
56
+        // yet registered, register it
57
+        if( !array_key_exists($signalClass, self::$registered )) {
58
+            self::$registered[$signalClass] = [];
59
+        }
60
+        // If we're trying to connect to an emitting method that isn't
61
+        // yet registered, register it with the emitting class
62
+        if( !array_key_exists( $signalName, self::$registered[$signalClass] )) {
63
+            self::$registered[$signalClass][$signalName] = [];
64
+        }
65 65
 
66
-		// don't connect hooks twice
67
-		foreach (self::$registered[$signalClass][$signalName] as $hook) {
68
-			if ($hook['class'] === $slotClass and $hook['name'] === $slotName) {
69
-				return false;
70
-			}
71
-		}
72
-		// Connect the hook handler to the requested emitter
73
-		self::$registered[$signalClass][$signalName][] = [
74
-			"class" => $slotClass,
75
-			"name" => $slotName
76
-		];
66
+        // don't connect hooks twice
67
+        foreach (self::$registered[$signalClass][$signalName] as $hook) {
68
+            if ($hook['class'] === $slotClass and $hook['name'] === $slotName) {
69
+                return false;
70
+            }
71
+        }
72
+        // Connect the hook handler to the requested emitter
73
+        self::$registered[$signalClass][$signalName][] = [
74
+            "class" => $slotClass,
75
+            "name" => $slotName
76
+        ];
77 77
 
78
-		// No chance for failure ;-)
79
-		return true;
80
-	}
78
+        // No chance for failure ;-)
79
+        return true;
80
+    }
81 81
 
82
-	/**
83
-	 * emits a signal
84
-	 *
85
-	 * @param string $signalClass class name of emitter
86
-	 * @param string $signalName name of signal
87
-	 * @param mixed $params default: array() array with additional data
88
-	 * @return bool true if slots exists or false if not
89
-	 * @throws \OC\HintException
90
-	 * @throws \OC\ServerNotAvailableException Emits a signal. To get data from the slot use references!
91
-	 *
92
-	 * TODO: write example
93
-	 */
94
-	static public function emit($signalClass, $signalName, $params = []) {
82
+    /**
83
+     * emits a signal
84
+     *
85
+     * @param string $signalClass class name of emitter
86
+     * @param string $signalName name of signal
87
+     * @param mixed $params default: array() array with additional data
88
+     * @return bool true if slots exists or false if not
89
+     * @throws \OC\HintException
90
+     * @throws \OC\ServerNotAvailableException Emits a signal. To get data from the slot use references!
91
+     *
92
+     * TODO: write example
93
+     */
94
+    static public function emit($signalClass, $signalName, $params = []) {
95 95
 
96
-		// Return false if no hook handlers are listening to this
97
-		// emitting class
98
-		if( !array_key_exists($signalClass, self::$registered )) {
99
-			return false;
100
-		}
96
+        // Return false if no hook handlers are listening to this
97
+        // emitting class
98
+        if( !array_key_exists($signalClass, self::$registered )) {
99
+            return false;
100
+        }
101 101
 
102
-		// Return false if no hook handlers are listening to this
103
-		// emitting method
104
-		if( !array_key_exists( $signalName, self::$registered[$signalClass] )) {
105
-			return false;
106
-		}
102
+        // Return false if no hook handlers are listening to this
103
+        // emitting method
104
+        if( !array_key_exists( $signalName, self::$registered[$signalClass] )) {
105
+            return false;
106
+        }
107 107
 
108
-		// Call all slots
109
-		foreach( self::$registered[$signalClass][$signalName] as $i ) {
110
-			try {
111
-				call_user_func( [ $i["class"], $i["name"] ], $params );
112
-			} catch (Exception $e){
113
-				self::$thrownExceptions[] = $e;
114
-				\OC::$server->getLogger()->logException($e);
115
-				if($e instanceof \OC\HintException) {
116
-					throw $e;
117
-				}
118
-				if($e instanceof \OC\ServerNotAvailableException) {
119
-					throw $e;
120
-				}
121
-			}
122
-		}
108
+        // Call all slots
109
+        foreach( self::$registered[$signalClass][$signalName] as $i ) {
110
+            try {
111
+                call_user_func( [ $i["class"], $i["name"] ], $params );
112
+            } catch (Exception $e){
113
+                self::$thrownExceptions[] = $e;
114
+                \OC::$server->getLogger()->logException($e);
115
+                if($e instanceof \OC\HintException) {
116
+                    throw $e;
117
+                }
118
+                if($e instanceof \OC\ServerNotAvailableException) {
119
+                    throw $e;
120
+                }
121
+            }
122
+        }
123 123
 
124
-		return true;
125
-	}
124
+        return true;
125
+    }
126 126
 
127
-	/**
128
-	 * clear hooks
129
-	 * @param string $signalClass
130
-	 * @param string $signalName
131
-	 */
132
-	static public function clear($signalClass='', $signalName='') {
133
-		if ($signalClass) {
134
-			if ($signalName) {
135
-				self::$registered[$signalClass][$signalName]=[];
136
-			}else{
137
-				self::$registered[$signalClass]=[];
138
-			}
139
-		}else{
140
-			self::$registered=[];
141
-		}
142
-	}
127
+    /**
128
+     * clear hooks
129
+     * @param string $signalClass
130
+     * @param string $signalName
131
+     */
132
+    static public function clear($signalClass='', $signalName='') {
133
+        if ($signalClass) {
134
+            if ($signalName) {
135
+                self::$registered[$signalClass][$signalName]=[];
136
+            }else{
137
+                self::$registered[$signalClass]=[];
138
+            }
139
+        }else{
140
+            self::$registered=[];
141
+        }
142
+    }
143 143
 
144
-	/**
145
-	 * DO NOT USE!
146
-	 * For unit tests ONLY!
147
-	 */
148
-	static public function getHooks() {
149
-		return self::$registered;
150
-	}
144
+    /**
145
+     * DO NOT USE!
146
+     * For unit tests ONLY!
147
+     */
148
+    static public function getHooks() {
149
+        return self::$registered;
150
+    }
151 151
 }
Please login to merge, or discard this patch.
apps/user_ldap/lib/Connection.php 2 patches
Indentation   +616 added lines, -616 removed lines patch added patch discarded remove patch
@@ -69,621 +69,621 @@
 block discarded – undo
69 69
  * @property string ldapGroupDisplayName
70 70
  */
71 71
 class Connection extends LDAPUtility {
72
-	private $ldapConnectionRes = null;
73
-	private $configPrefix;
74
-	private $configID;
75
-	private $configured = false;
76
-	//whether connection should be kept on __destruct
77
-	private $dontDestruct = false;
78
-
79
-	/**
80
-	 * @var bool runtime flag that indicates whether supported primary groups are available
81
-	 */
82
-	public $hasPrimaryGroups = true;
83
-
84
-	/**
85
-	 * @var bool runtime flag that indicates whether supported POSIX gidNumber are available
86
-	 */
87
-	public $hasGidNumber = true;
88
-
89
-	//cache handler
90
-	protected $cache;
91
-
92
-	/** @var Configuration settings handler **/
93
-	protected $configuration;
94
-
95
-	protected $doNotValidate = false;
96
-
97
-	protected $ignoreValidation = false;
98
-
99
-	protected $bindResult = [];
100
-
101
-	/**
102
-	 * Constructor
103
-	 * @param ILDAPWrapper $ldap
104
-	 * @param string $configPrefix a string with the prefix for the configkey column (appconfig table)
105
-	 * @param string|null $configID a string with the value for the appid column (appconfig table) or null for on-the-fly connections
106
-	 */
107
-	public function __construct(ILDAPWrapper $ldap, $configPrefix = '', $configID = 'user_ldap') {
108
-		parent::__construct($ldap);
109
-		$this->configPrefix = $configPrefix;
110
-		$this->configID = $configID;
111
-		$this->configuration = new Configuration($configPrefix,
112
-												 !is_null($configID));
113
-		$memcache = \OC::$server->getMemCacheFactory();
114
-		if($memcache->isAvailable()) {
115
-			$this->cache = $memcache->createDistributed();
116
-		}
117
-		$helper = new Helper(\OC::$server->getConfig());
118
-		$this->doNotValidate = !in_array($this->configPrefix,
119
-			$helper->getServerConfigurationPrefixes());
120
-	}
121
-
122
-	public function __destruct() {
123
-		if(!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
124
-			@$this->ldap->unbind($this->ldapConnectionRes);
125
-			$this->bindResult = [];
126
-		}
127
-	}
128
-
129
-	/**
130
-	 * defines behaviour when the instance is cloned
131
-	 */
132
-	public function __clone() {
133
-		$this->configuration = new Configuration($this->configPrefix,
134
-												 !is_null($this->configID));
135
-		if(count($this->bindResult) !== 0 && $this->bindResult['result'] === true) {
136
-			$this->bindResult = [];
137
-		}
138
-		$this->ldapConnectionRes = null;
139
-		$this->dontDestruct = true;
140
-	}
141
-
142
-	/**
143
-	 * @param string $name
144
-	 * @return bool|mixed
145
-	 */
146
-	public function __get($name) {
147
-		if(!$this->configured) {
148
-			$this->readConfiguration();
149
-		}
150
-
151
-		return $this->configuration->$name;
152
-	}
153
-
154
-	/**
155
-	 * @param string $name
156
-	 * @param mixed $value
157
-	 */
158
-	public function __set($name, $value) {
159
-		$this->doNotValidate = false;
160
-		$before = $this->configuration->$name;
161
-		$this->configuration->$name = $value;
162
-		$after = $this->configuration->$name;
163
-		if($before !== $after) {
164
-			if ($this->configID !== '' && $this->configID !== null) {
165
-				$this->configuration->saveConfiguration();
166
-			}
167
-			$this->validateConfiguration();
168
-		}
169
-	}
170
-
171
-	/**
172
-	 * @param string $rule
173
-	 * @return array
174
-	 * @throws \RuntimeException
175
-	 */
176
-	public function resolveRule($rule) {
177
-		return $this->configuration->resolveRule($rule);
178
-	}
179
-
180
-	/**
181
-	 * sets whether the result of the configuration validation shall
182
-	 * be ignored when establishing the connection. Used by the Wizard
183
-	 * in early configuration state.
184
-	 * @param bool $state
185
-	 */
186
-	public function setIgnoreValidation($state) {
187
-		$this->ignoreValidation = (bool)$state;
188
-	}
189
-
190
-	/**
191
-	 * initializes the LDAP backend
192
-	 * @param bool $force read the config settings no matter what
193
-	 */
194
-	public function init($force = false) {
195
-		$this->readConfiguration($force);
196
-		$this->establishConnection();
197
-	}
198
-
199
-	/**
200
-	 * Returns the LDAP handler
201
-	 */
202
-	public function getConnectionResource() {
203
-		if(!$this->ldapConnectionRes) {
204
-			$this->init();
205
-		} else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
206
-			$this->ldapConnectionRes = null;
207
-			$this->establishConnection();
208
-		}
209
-		if(is_null($this->ldapConnectionRes)) {
210
-			\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, ILogger::ERROR);
211
-			throw new ServerNotAvailableException('Connection to LDAP server could not be established');
212
-		}
213
-		return $this->ldapConnectionRes;
214
-	}
215
-
216
-	/**
217
-	 * resets the connection resource
218
-	 */
219
-	public function resetConnectionResource() {
220
-		if(!is_null($this->ldapConnectionRes)) {
221
-			@$this->ldap->unbind($this->ldapConnectionRes);
222
-			$this->ldapConnectionRes = null;
223
-			$this->bindResult = [];
224
-		}
225
-	}
226
-
227
-	/**
228
-	 * @param string|null $key
229
-	 * @return string
230
-	 */
231
-	private function getCacheKey($key) {
232
-		$prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
233
-		if(is_null($key)) {
234
-			return $prefix;
235
-		}
236
-		return $prefix.hash('sha256', $key);
237
-	}
238
-
239
-	/**
240
-	 * @param string $key
241
-	 * @return mixed|null
242
-	 */
243
-	public function getFromCache($key) {
244
-		if(!$this->configured) {
245
-			$this->readConfiguration();
246
-		}
247
-		if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
248
-			return null;
249
-		}
250
-		$key = $this->getCacheKey($key);
251
-
252
-		return json_decode(base64_decode($this->cache->get($key)), true);
253
-	}
254
-
255
-	/**
256
-	 * @param string $key
257
-	 * @param mixed $value
258
-	 *
259
-	 * @return string
260
-	 */
261
-	public function writeToCache($key, $value) {
262
-		if(!$this->configured) {
263
-			$this->readConfiguration();
264
-		}
265
-		if(is_null($this->cache)
266
-			|| !$this->configuration->ldapCacheTTL
267
-			|| !$this->configuration->ldapConfigurationActive) {
268
-			return null;
269
-		}
270
-		$key   = $this->getCacheKey($key);
271
-		$value = base64_encode(json_encode($value));
272
-		$this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
273
-	}
274
-
275
-	public function clearCache() {
276
-		if(!is_null($this->cache)) {
277
-			$this->cache->clear($this->getCacheKey(null));
278
-		}
279
-	}
280
-
281
-	/**
282
-	 * Caches the general LDAP configuration.
283
-	 * @param bool $force optional. true, if the re-read should be forced. defaults
284
-	 * to false.
285
-	 * @return null
286
-	 */
287
-	private function readConfiguration($force = false) {
288
-		if((!$this->configured || $force) && !is_null($this->configID)) {
289
-			$this->configuration->readConfiguration();
290
-			$this->configured = $this->validateConfiguration();
291
-		}
292
-	}
293
-
294
-	/**
295
-	 * set LDAP configuration with values delivered by an array, not read from configuration
296
-	 * @param array $config array that holds the config parameters in an associated array
297
-	 * @param array &$setParameters optional; array where the set fields will be given to
298
-	 * @return boolean true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
299
-	 */
300
-	public function setConfiguration($config, &$setParameters = null) {
301
-		if(is_null($setParameters)) {
302
-			$setParameters = [];
303
-		}
304
-		$this->doNotValidate = false;
305
-		$this->configuration->setConfiguration($config, $setParameters);
306
-		if(count($setParameters) > 0) {
307
-			$this->configured = $this->validateConfiguration();
308
-		}
309
-
310
-
311
-		return $this->configured;
312
-	}
313
-
314
-	/**
315
-	 * saves the current Configuration in the database and empties the
316
-	 * cache
317
-	 * @return null
318
-	 */
319
-	public function saveConfiguration() {
320
-		$this->configuration->saveConfiguration();
321
-		$this->clearCache();
322
-	}
323
-
324
-	/**
325
-	 * get the current LDAP configuration
326
-	 * @return array
327
-	 */
328
-	public function getConfiguration() {
329
-		$this->readConfiguration();
330
-		$config = $this->configuration->getConfiguration();
331
-		$cta = $this->configuration->getConfigTranslationArray();
332
-		$result = [];
333
-		foreach($cta as $dbkey => $configkey) {
334
-			switch($configkey) {
335
-				case 'homeFolderNamingRule':
336
-					if(strpos($config[$configkey], 'attr:') === 0) {
337
-						$result[$dbkey] = substr($config[$configkey], 5);
338
-					} else {
339
-						$result[$dbkey] = '';
340
-					}
341
-					break;
342
-				case 'ldapBase':
343
-				case 'ldapBaseUsers':
344
-				case 'ldapBaseGroups':
345
-				case 'ldapAttributesForUserSearch':
346
-				case 'ldapAttributesForGroupSearch':
347
-					if(is_array($config[$configkey])) {
348
-						$result[$dbkey] = implode("\n", $config[$configkey]);
349
-						break;
350
-					} //else follows default
351
-				default:
352
-					$result[$dbkey] = $config[$configkey];
353
-			}
354
-		}
355
-		return $result;
356
-	}
357
-
358
-	private function doSoftValidation() {
359
-		//if User or Group Base are not set, take over Base DN setting
360
-		foreach(['ldapBaseUsers', 'ldapBaseGroups'] as $keyBase) {
361
-			$val = $this->configuration->$keyBase;
362
-			if(empty($val)) {
363
-				$this->configuration->$keyBase = $this->configuration->ldapBase;
364
-			}
365
-		}
366
-
367
-		foreach(['ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
368
-			'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute']
369
-				as $expertSetting => $effectiveSetting) {
370
-			$uuidOverride = $this->configuration->$expertSetting;
371
-			if(!empty($uuidOverride)) {
372
-				$this->configuration->$effectiveSetting = $uuidOverride;
373
-			} else {
374
-				$uuidAttributes = Access::UUID_ATTRIBUTES;
375
-				array_unshift($uuidAttributes, 'auto');
376
-				if(!in_array($this->configuration->$effectiveSetting,
377
-							$uuidAttributes)
378
-					&& (!is_null($this->configID))) {
379
-					$this->configuration->$effectiveSetting = 'auto';
380
-					$this->configuration->saveConfiguration();
381
-					\OCP\Util::writeLog('user_ldap',
382
-										'Illegal value for the '.
383
-										$effectiveSetting.', '.'reset to '.
384
-										'autodetect.', ILogger::INFO);
385
-				}
386
-
387
-			}
388
-		}
389
-
390
-		$backupPort = (int)$this->configuration->ldapBackupPort;
391
-		if ($backupPort <= 0) {
392
-			$this->configuration->backupPort = $this->configuration->ldapPort;
393
-		}
394
-
395
-		//make sure empty search attributes are saved as simple, empty array
396
-		$saKeys = ['ldapAttributesForUserSearch',
397
-			'ldapAttributesForGroupSearch'];
398
-		foreach($saKeys as $key) {
399
-			$val = $this->configuration->$key;
400
-			if(is_array($val) && count($val) === 1 && empty($val[0])) {
401
-				$this->configuration->$key = [];
402
-			}
403
-		}
404
-
405
-		if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
406
-			&& $this->configuration->ldapTLS) {
407
-			$this->configuration->ldapTLS = false;
408
-			\OCP\Util::writeLog(
409
-				'user_ldap',
410
-				'LDAPS (already using secure connection) and TLS do not work together. Switched off TLS.',
411
-				ILogger::INFO
412
-			);
413
-		}
414
-	}
415
-
416
-	/**
417
-	 * @return bool
418
-	 */
419
-	private function doCriticalValidation() {
420
-		$configurationOK = true;
421
-		$errorStr = 'Configuration Error (prefix '.
422
-			(string)$this->configPrefix .'): ';
423
-
424
-		//options that shall not be empty
425
-		$options = ['ldapHost', 'ldapPort', 'ldapUserDisplayName',
426
-			'ldapGroupDisplayName', 'ldapLoginFilter'];
427
-		foreach($options as $key) {
428
-			$val = $this->configuration->$key;
429
-			if(empty($val)) {
430
-				switch($key) {
431
-					case 'ldapHost':
432
-						$subj = 'LDAP Host';
433
-						break;
434
-					case 'ldapPort':
435
-						$subj = 'LDAP Port';
436
-						break;
437
-					case 'ldapUserDisplayName':
438
-						$subj = 'LDAP User Display Name';
439
-						break;
440
-					case 'ldapGroupDisplayName':
441
-						$subj = 'LDAP Group Display Name';
442
-						break;
443
-					case 'ldapLoginFilter':
444
-						$subj = 'LDAP Login Filter';
445
-						break;
446
-					default:
447
-						$subj = $key;
448
-						break;
449
-				}
450
-				$configurationOK = false;
451
-				\OCP\Util::writeLog(
452
-					'user_ldap',
453
-					$errorStr.'No '.$subj.' given!',
454
-					ILogger::WARN
455
-				);
456
-			}
457
-		}
458
-
459
-		//combinations
460
-		$agent = $this->configuration->ldapAgentName;
461
-		$pwd = $this->configuration->ldapAgentPassword;
462
-		if (
463
-			($agent === ''  && $pwd !== '')
464
-			|| ($agent !== '' && $pwd === '')
465
-		) {
466
-			\OCP\Util::writeLog(
467
-				'user_ldap',
468
-				$errorStr.'either no password is given for the user ' .
469
-					'agent or a password is given, but not an LDAP agent.',
470
-				ILogger::WARN);
471
-			$configurationOK = false;
472
-		}
473
-
474
-		$base = $this->configuration->ldapBase;
475
-		$baseUsers = $this->configuration->ldapBaseUsers;
476
-		$baseGroups = $this->configuration->ldapBaseGroups;
477
-
478
-		if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
479
-			\OCP\Util::writeLog(
480
-				'user_ldap',
481
-				$errorStr.'Not a single Base DN given.',
482
-				ILogger::WARN
483
-			);
484
-			$configurationOK = false;
485
-		}
486
-
487
-		if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
488
-		   === false) {
489
-			\OCP\Util::writeLog(
490
-				'user_ldap',
491
-				$errorStr.'login filter does not contain %uid place holder.',
492
-				ILogger::WARN
493
-			);
494
-			$configurationOK = false;
495
-		}
496
-
497
-		return $configurationOK;
498
-	}
499
-
500
-	/**
501
-	 * Validates the user specified configuration
502
-	 * @return bool true if configuration seems OK, false otherwise
503
-	 */
504
-	private function validateConfiguration() {
505
-
506
-		if($this->doNotValidate) {
507
-			//don't do a validation if it is a new configuration with pure
508
-			//default values. Will be allowed on changes via __set or
509
-			//setConfiguration
510
-			return false;
511
-		}
512
-
513
-		// first step: "soft" checks: settings that are not really
514
-		// necessary, but advisable. If left empty, give an info message
515
-		$this->doSoftValidation();
516
-
517
-		//second step: critical checks. If left empty or filled wrong, mark as
518
-		//not configured and give a warning.
519
-		return $this->doCriticalValidation();
520
-	}
521
-
522
-
523
-	/**
524
-	 * Connects and Binds to LDAP
525
-	 *
526
-	 * @throws ServerNotAvailableException
527
-	 */
528
-	private function establishConnection() {
529
-		if(!$this->configuration->ldapConfigurationActive) {
530
-			return null;
531
-		}
532
-		static $phpLDAPinstalled = true;
533
-		if(!$phpLDAPinstalled) {
534
-			return false;
535
-		}
536
-		if(!$this->ignoreValidation && !$this->configured) {
537
-			\OCP\Util::writeLog(
538
-				'user_ldap',
539
-				'Configuration is invalid, cannot connect',
540
-				ILogger::WARN
541
-			);
542
-			return false;
543
-		}
544
-		if(!$this->ldapConnectionRes) {
545
-			if(!$this->ldap->areLDAPFunctionsAvailable()) {
546
-				$phpLDAPinstalled = false;
547
-				\OCP\Util::writeLog(
548
-					'user_ldap',
549
-					'function ldap_connect is not available. Make sure that the PHP ldap module is installed.',
550
-					ILogger::ERROR
551
-				);
552
-
553
-				return false;
554
-			}
555
-			if($this->configuration->turnOffCertCheck) {
556
-				if(putenv('LDAPTLS_REQCERT=never')) {
557
-					\OCP\Util::writeLog('user_ldap',
558
-						'Turned off SSL certificate validation successfully.',
559
-						ILogger::DEBUG);
560
-				} else {
561
-					\OCP\Util::writeLog(
562
-						'user_ldap',
563
-						'Could not turn off SSL certificate validation.',
564
-						ILogger::WARN
565
-					);
566
-				}
567
-			}
568
-
569
-			$isOverrideMainServer = ($this->configuration->ldapOverrideMainServer
570
-				|| $this->getFromCache('overrideMainServer'));
571
-			$isBackupHost = (trim($this->configuration->ldapBackupHost) !== "");
572
-			$bindStatus = false;
573
-			try {
574
-				if (!$isOverrideMainServer) {
575
-					$this->doConnect($this->configuration->ldapHost,
576
-						$this->configuration->ldapPort);
577
-					return $this->bind();
578
-				}
579
-			} catch (ServerNotAvailableException $e) {
580
-				if(!$isBackupHost) {
581
-					throw $e;
582
-				}
583
-			}
584
-
585
-			//if LDAP server is not reachable, try the Backup (Replica!) Server
586
-			if($isBackupHost || $isOverrideMainServer) {
587
-				$this->doConnect($this->configuration->ldapBackupHost,
588
-								 $this->configuration->ldapBackupPort);
589
-				$this->bindResult = [];
590
-				$bindStatus = $this->bind();
591
-				$error = $this->ldap->isResource($this->ldapConnectionRes) ?
592
-					$this->ldap->errno($this->ldapConnectionRes) : -1;
593
-				if($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
594
-					//when bind to backup server succeeded and failed to main server,
595
-					//skip contacting him until next cache refresh
596
-					$this->writeToCache('overrideMainServer', true);
597
-				}
598
-			}
599
-
600
-			return $bindStatus;
601
-		}
602
-		return null;
603
-	}
604
-
605
-	/**
606
-	 * @param string $host
607
-	 * @param string $port
608
-	 * @return bool
609
-	 * @throws \OC\ServerNotAvailableException
610
-	 */
611
-	private function doConnect($host, $port) {
612
-		if ($host === '') {
613
-			return false;
614
-		}
615
-
616
-		$this->ldapConnectionRes = $this->ldap->connect($host, $port);
617
-
618
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
619
-			throw new ServerNotAvailableException('Could not set required LDAP Protocol version.');
620
-		}
621
-
622
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
623
-			throw new ServerNotAvailableException('Could not disable LDAP referrals.');
624
-		}
625
-
626
-		if($this->configuration->ldapTLS) {
627
-			if(!$this->ldap->startTls($this->ldapConnectionRes)) {
628
-				throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.');
629
-			}
630
-		}
631
-
632
-		return true;
633
-	}
634
-
635
-	/**
636
-	 * Binds to LDAP
637
-	 */
638
-	public function bind() {
639
-		if(!$this->configuration->ldapConfigurationActive) {
640
-			return false;
641
-		}
642
-		$cr = $this->ldapConnectionRes;
643
-		if(!$this->ldap->isResource($cr)) {
644
-			$cr = $this->getConnectionResource();
645
-		}
646
-
647
-		if(
648
-			count($this->bindResult) !== 0
649
-			&& $this->bindResult['dn'] === $this->configuration->ldapAgentName
650
-			&& \OC::$server->getHasher()->verify(
651
-				$this->configPrefix . $this->configuration->ldapAgentPassword,
652
-				$this->bindResult['hash']
653
-			)
654
-		) {
655
-			// don't attempt to bind again with the same data as before
656
-			// bind might have been invoked via getConnectionResource(),
657
-			// but we need results specifically for e.g. user login
658
-			return $this->bindResult['result'];
659
-		}
660
-
661
-		$ldapLogin = @$this->ldap->bind($cr,
662
-										$this->configuration->ldapAgentName,
663
-										$this->configuration->ldapAgentPassword);
664
-
665
-		$this->bindResult = [
666
-			'dn' => $this->configuration->ldapAgentName,
667
-			'hash' => \OC::$server->getHasher()->hash($this->configPrefix . $this->configuration->ldapAgentPassword),
668
-			'result' => $ldapLogin,
669
-		];
670
-
671
-		if(!$ldapLogin) {
672
-			$errno = $this->ldap->errno($cr);
673
-
674
-			\OCP\Util::writeLog('user_ldap',
675
-				'Bind failed: ' . $errno . ': ' . $this->ldap->error($cr),
676
-				ILogger::WARN);
677
-
678
-			// Set to failure mode, if LDAP error code is not LDAP_SUCCESS or LDAP_INVALID_CREDENTIALS
679
-			// or (needed for Apple Open Directory:) LDAP_INSUFFICIENT_ACCESS
680
-			if($errno !== 0 && $errno !== 49 && $errno !== 50) {
681
-				$this->ldapConnectionRes = null;
682
-			}
683
-
684
-			return false;
685
-		}
686
-		return true;
687
-	}
72
+    private $ldapConnectionRes = null;
73
+    private $configPrefix;
74
+    private $configID;
75
+    private $configured = false;
76
+    //whether connection should be kept on __destruct
77
+    private $dontDestruct = false;
78
+
79
+    /**
80
+     * @var bool runtime flag that indicates whether supported primary groups are available
81
+     */
82
+    public $hasPrimaryGroups = true;
83
+
84
+    /**
85
+     * @var bool runtime flag that indicates whether supported POSIX gidNumber are available
86
+     */
87
+    public $hasGidNumber = true;
88
+
89
+    //cache handler
90
+    protected $cache;
91
+
92
+    /** @var Configuration settings handler **/
93
+    protected $configuration;
94
+
95
+    protected $doNotValidate = false;
96
+
97
+    protected $ignoreValidation = false;
98
+
99
+    protected $bindResult = [];
100
+
101
+    /**
102
+     * Constructor
103
+     * @param ILDAPWrapper $ldap
104
+     * @param string $configPrefix a string with the prefix for the configkey column (appconfig table)
105
+     * @param string|null $configID a string with the value for the appid column (appconfig table) or null for on-the-fly connections
106
+     */
107
+    public function __construct(ILDAPWrapper $ldap, $configPrefix = '', $configID = 'user_ldap') {
108
+        parent::__construct($ldap);
109
+        $this->configPrefix = $configPrefix;
110
+        $this->configID = $configID;
111
+        $this->configuration = new Configuration($configPrefix,
112
+                                                    !is_null($configID));
113
+        $memcache = \OC::$server->getMemCacheFactory();
114
+        if($memcache->isAvailable()) {
115
+            $this->cache = $memcache->createDistributed();
116
+        }
117
+        $helper = new Helper(\OC::$server->getConfig());
118
+        $this->doNotValidate = !in_array($this->configPrefix,
119
+            $helper->getServerConfigurationPrefixes());
120
+    }
121
+
122
+    public function __destruct() {
123
+        if(!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
124
+            @$this->ldap->unbind($this->ldapConnectionRes);
125
+            $this->bindResult = [];
126
+        }
127
+    }
128
+
129
+    /**
130
+     * defines behaviour when the instance is cloned
131
+     */
132
+    public function __clone() {
133
+        $this->configuration = new Configuration($this->configPrefix,
134
+                                                    !is_null($this->configID));
135
+        if(count($this->bindResult) !== 0 && $this->bindResult['result'] === true) {
136
+            $this->bindResult = [];
137
+        }
138
+        $this->ldapConnectionRes = null;
139
+        $this->dontDestruct = true;
140
+    }
141
+
142
+    /**
143
+     * @param string $name
144
+     * @return bool|mixed
145
+     */
146
+    public function __get($name) {
147
+        if(!$this->configured) {
148
+            $this->readConfiguration();
149
+        }
150
+
151
+        return $this->configuration->$name;
152
+    }
153
+
154
+    /**
155
+     * @param string $name
156
+     * @param mixed $value
157
+     */
158
+    public function __set($name, $value) {
159
+        $this->doNotValidate = false;
160
+        $before = $this->configuration->$name;
161
+        $this->configuration->$name = $value;
162
+        $after = $this->configuration->$name;
163
+        if($before !== $after) {
164
+            if ($this->configID !== '' && $this->configID !== null) {
165
+                $this->configuration->saveConfiguration();
166
+            }
167
+            $this->validateConfiguration();
168
+        }
169
+    }
170
+
171
+    /**
172
+     * @param string $rule
173
+     * @return array
174
+     * @throws \RuntimeException
175
+     */
176
+    public function resolveRule($rule) {
177
+        return $this->configuration->resolveRule($rule);
178
+    }
179
+
180
+    /**
181
+     * sets whether the result of the configuration validation shall
182
+     * be ignored when establishing the connection. Used by the Wizard
183
+     * in early configuration state.
184
+     * @param bool $state
185
+     */
186
+    public function setIgnoreValidation($state) {
187
+        $this->ignoreValidation = (bool)$state;
188
+    }
189
+
190
+    /**
191
+     * initializes the LDAP backend
192
+     * @param bool $force read the config settings no matter what
193
+     */
194
+    public function init($force = false) {
195
+        $this->readConfiguration($force);
196
+        $this->establishConnection();
197
+    }
198
+
199
+    /**
200
+     * Returns the LDAP handler
201
+     */
202
+    public function getConnectionResource() {
203
+        if(!$this->ldapConnectionRes) {
204
+            $this->init();
205
+        } else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
206
+            $this->ldapConnectionRes = null;
207
+            $this->establishConnection();
208
+        }
209
+        if(is_null($this->ldapConnectionRes)) {
210
+            \OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, ILogger::ERROR);
211
+            throw new ServerNotAvailableException('Connection to LDAP server could not be established');
212
+        }
213
+        return $this->ldapConnectionRes;
214
+    }
215
+
216
+    /**
217
+     * resets the connection resource
218
+     */
219
+    public function resetConnectionResource() {
220
+        if(!is_null($this->ldapConnectionRes)) {
221
+            @$this->ldap->unbind($this->ldapConnectionRes);
222
+            $this->ldapConnectionRes = null;
223
+            $this->bindResult = [];
224
+        }
225
+    }
226
+
227
+    /**
228
+     * @param string|null $key
229
+     * @return string
230
+     */
231
+    private function getCacheKey($key) {
232
+        $prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
233
+        if(is_null($key)) {
234
+            return $prefix;
235
+        }
236
+        return $prefix.hash('sha256', $key);
237
+    }
238
+
239
+    /**
240
+     * @param string $key
241
+     * @return mixed|null
242
+     */
243
+    public function getFromCache($key) {
244
+        if(!$this->configured) {
245
+            $this->readConfiguration();
246
+        }
247
+        if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
248
+            return null;
249
+        }
250
+        $key = $this->getCacheKey($key);
251
+
252
+        return json_decode(base64_decode($this->cache->get($key)), true);
253
+    }
254
+
255
+    /**
256
+     * @param string $key
257
+     * @param mixed $value
258
+     *
259
+     * @return string
260
+     */
261
+    public function writeToCache($key, $value) {
262
+        if(!$this->configured) {
263
+            $this->readConfiguration();
264
+        }
265
+        if(is_null($this->cache)
266
+            || !$this->configuration->ldapCacheTTL
267
+            || !$this->configuration->ldapConfigurationActive) {
268
+            return null;
269
+        }
270
+        $key   = $this->getCacheKey($key);
271
+        $value = base64_encode(json_encode($value));
272
+        $this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
273
+    }
274
+
275
+    public function clearCache() {
276
+        if(!is_null($this->cache)) {
277
+            $this->cache->clear($this->getCacheKey(null));
278
+        }
279
+    }
280
+
281
+    /**
282
+     * Caches the general LDAP configuration.
283
+     * @param bool $force optional. true, if the re-read should be forced. defaults
284
+     * to false.
285
+     * @return null
286
+     */
287
+    private function readConfiguration($force = false) {
288
+        if((!$this->configured || $force) && !is_null($this->configID)) {
289
+            $this->configuration->readConfiguration();
290
+            $this->configured = $this->validateConfiguration();
291
+        }
292
+    }
293
+
294
+    /**
295
+     * set LDAP configuration with values delivered by an array, not read from configuration
296
+     * @param array $config array that holds the config parameters in an associated array
297
+     * @param array &$setParameters optional; array where the set fields will be given to
298
+     * @return boolean true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
299
+     */
300
+    public function setConfiguration($config, &$setParameters = null) {
301
+        if(is_null($setParameters)) {
302
+            $setParameters = [];
303
+        }
304
+        $this->doNotValidate = false;
305
+        $this->configuration->setConfiguration($config, $setParameters);
306
+        if(count($setParameters) > 0) {
307
+            $this->configured = $this->validateConfiguration();
308
+        }
309
+
310
+
311
+        return $this->configured;
312
+    }
313
+
314
+    /**
315
+     * saves the current Configuration in the database and empties the
316
+     * cache
317
+     * @return null
318
+     */
319
+    public function saveConfiguration() {
320
+        $this->configuration->saveConfiguration();
321
+        $this->clearCache();
322
+    }
323
+
324
+    /**
325
+     * get the current LDAP configuration
326
+     * @return array
327
+     */
328
+    public function getConfiguration() {
329
+        $this->readConfiguration();
330
+        $config = $this->configuration->getConfiguration();
331
+        $cta = $this->configuration->getConfigTranslationArray();
332
+        $result = [];
333
+        foreach($cta as $dbkey => $configkey) {
334
+            switch($configkey) {
335
+                case 'homeFolderNamingRule':
336
+                    if(strpos($config[$configkey], 'attr:') === 0) {
337
+                        $result[$dbkey] = substr($config[$configkey], 5);
338
+                    } else {
339
+                        $result[$dbkey] = '';
340
+                    }
341
+                    break;
342
+                case 'ldapBase':
343
+                case 'ldapBaseUsers':
344
+                case 'ldapBaseGroups':
345
+                case 'ldapAttributesForUserSearch':
346
+                case 'ldapAttributesForGroupSearch':
347
+                    if(is_array($config[$configkey])) {
348
+                        $result[$dbkey] = implode("\n", $config[$configkey]);
349
+                        break;
350
+                    } //else follows default
351
+                default:
352
+                    $result[$dbkey] = $config[$configkey];
353
+            }
354
+        }
355
+        return $result;
356
+    }
357
+
358
+    private function doSoftValidation() {
359
+        //if User or Group Base are not set, take over Base DN setting
360
+        foreach(['ldapBaseUsers', 'ldapBaseGroups'] as $keyBase) {
361
+            $val = $this->configuration->$keyBase;
362
+            if(empty($val)) {
363
+                $this->configuration->$keyBase = $this->configuration->ldapBase;
364
+            }
365
+        }
366
+
367
+        foreach(['ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
368
+            'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute']
369
+                as $expertSetting => $effectiveSetting) {
370
+            $uuidOverride = $this->configuration->$expertSetting;
371
+            if(!empty($uuidOverride)) {
372
+                $this->configuration->$effectiveSetting = $uuidOverride;
373
+            } else {
374
+                $uuidAttributes = Access::UUID_ATTRIBUTES;
375
+                array_unshift($uuidAttributes, 'auto');
376
+                if(!in_array($this->configuration->$effectiveSetting,
377
+                            $uuidAttributes)
378
+                    && (!is_null($this->configID))) {
379
+                    $this->configuration->$effectiveSetting = 'auto';
380
+                    $this->configuration->saveConfiguration();
381
+                    \OCP\Util::writeLog('user_ldap',
382
+                                        'Illegal value for the '.
383
+                                        $effectiveSetting.', '.'reset to '.
384
+                                        'autodetect.', ILogger::INFO);
385
+                }
386
+
387
+            }
388
+        }
389
+
390
+        $backupPort = (int)$this->configuration->ldapBackupPort;
391
+        if ($backupPort <= 0) {
392
+            $this->configuration->backupPort = $this->configuration->ldapPort;
393
+        }
394
+
395
+        //make sure empty search attributes are saved as simple, empty array
396
+        $saKeys = ['ldapAttributesForUserSearch',
397
+            'ldapAttributesForGroupSearch'];
398
+        foreach($saKeys as $key) {
399
+            $val = $this->configuration->$key;
400
+            if(is_array($val) && count($val) === 1 && empty($val[0])) {
401
+                $this->configuration->$key = [];
402
+            }
403
+        }
404
+
405
+        if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
406
+            && $this->configuration->ldapTLS) {
407
+            $this->configuration->ldapTLS = false;
408
+            \OCP\Util::writeLog(
409
+                'user_ldap',
410
+                'LDAPS (already using secure connection) and TLS do not work together. Switched off TLS.',
411
+                ILogger::INFO
412
+            );
413
+        }
414
+    }
415
+
416
+    /**
417
+     * @return bool
418
+     */
419
+    private function doCriticalValidation() {
420
+        $configurationOK = true;
421
+        $errorStr = 'Configuration Error (prefix '.
422
+            (string)$this->configPrefix .'): ';
423
+
424
+        //options that shall not be empty
425
+        $options = ['ldapHost', 'ldapPort', 'ldapUserDisplayName',
426
+            'ldapGroupDisplayName', 'ldapLoginFilter'];
427
+        foreach($options as $key) {
428
+            $val = $this->configuration->$key;
429
+            if(empty($val)) {
430
+                switch($key) {
431
+                    case 'ldapHost':
432
+                        $subj = 'LDAP Host';
433
+                        break;
434
+                    case 'ldapPort':
435
+                        $subj = 'LDAP Port';
436
+                        break;
437
+                    case 'ldapUserDisplayName':
438
+                        $subj = 'LDAP User Display Name';
439
+                        break;
440
+                    case 'ldapGroupDisplayName':
441
+                        $subj = 'LDAP Group Display Name';
442
+                        break;
443
+                    case 'ldapLoginFilter':
444
+                        $subj = 'LDAP Login Filter';
445
+                        break;
446
+                    default:
447
+                        $subj = $key;
448
+                        break;
449
+                }
450
+                $configurationOK = false;
451
+                \OCP\Util::writeLog(
452
+                    'user_ldap',
453
+                    $errorStr.'No '.$subj.' given!',
454
+                    ILogger::WARN
455
+                );
456
+            }
457
+        }
458
+
459
+        //combinations
460
+        $agent = $this->configuration->ldapAgentName;
461
+        $pwd = $this->configuration->ldapAgentPassword;
462
+        if (
463
+            ($agent === ''  && $pwd !== '')
464
+            || ($agent !== '' && $pwd === '')
465
+        ) {
466
+            \OCP\Util::writeLog(
467
+                'user_ldap',
468
+                $errorStr.'either no password is given for the user ' .
469
+                    'agent or a password is given, but not an LDAP agent.',
470
+                ILogger::WARN);
471
+            $configurationOK = false;
472
+        }
473
+
474
+        $base = $this->configuration->ldapBase;
475
+        $baseUsers = $this->configuration->ldapBaseUsers;
476
+        $baseGroups = $this->configuration->ldapBaseGroups;
477
+
478
+        if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
479
+            \OCP\Util::writeLog(
480
+                'user_ldap',
481
+                $errorStr.'Not a single Base DN given.',
482
+                ILogger::WARN
483
+            );
484
+            $configurationOK = false;
485
+        }
486
+
487
+        if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
488
+            === false) {
489
+            \OCP\Util::writeLog(
490
+                'user_ldap',
491
+                $errorStr.'login filter does not contain %uid place holder.',
492
+                ILogger::WARN
493
+            );
494
+            $configurationOK = false;
495
+        }
496
+
497
+        return $configurationOK;
498
+    }
499
+
500
+    /**
501
+     * Validates the user specified configuration
502
+     * @return bool true if configuration seems OK, false otherwise
503
+     */
504
+    private function validateConfiguration() {
505
+
506
+        if($this->doNotValidate) {
507
+            //don't do a validation if it is a new configuration with pure
508
+            //default values. Will be allowed on changes via __set or
509
+            //setConfiguration
510
+            return false;
511
+        }
512
+
513
+        // first step: "soft" checks: settings that are not really
514
+        // necessary, but advisable. If left empty, give an info message
515
+        $this->doSoftValidation();
516
+
517
+        //second step: critical checks. If left empty or filled wrong, mark as
518
+        //not configured and give a warning.
519
+        return $this->doCriticalValidation();
520
+    }
521
+
522
+
523
+    /**
524
+     * Connects and Binds to LDAP
525
+     *
526
+     * @throws ServerNotAvailableException
527
+     */
528
+    private function establishConnection() {
529
+        if(!$this->configuration->ldapConfigurationActive) {
530
+            return null;
531
+        }
532
+        static $phpLDAPinstalled = true;
533
+        if(!$phpLDAPinstalled) {
534
+            return false;
535
+        }
536
+        if(!$this->ignoreValidation && !$this->configured) {
537
+            \OCP\Util::writeLog(
538
+                'user_ldap',
539
+                'Configuration is invalid, cannot connect',
540
+                ILogger::WARN
541
+            );
542
+            return false;
543
+        }
544
+        if(!$this->ldapConnectionRes) {
545
+            if(!$this->ldap->areLDAPFunctionsAvailable()) {
546
+                $phpLDAPinstalled = false;
547
+                \OCP\Util::writeLog(
548
+                    'user_ldap',
549
+                    'function ldap_connect is not available. Make sure that the PHP ldap module is installed.',
550
+                    ILogger::ERROR
551
+                );
552
+
553
+                return false;
554
+            }
555
+            if($this->configuration->turnOffCertCheck) {
556
+                if(putenv('LDAPTLS_REQCERT=never')) {
557
+                    \OCP\Util::writeLog('user_ldap',
558
+                        'Turned off SSL certificate validation successfully.',
559
+                        ILogger::DEBUG);
560
+                } else {
561
+                    \OCP\Util::writeLog(
562
+                        'user_ldap',
563
+                        'Could not turn off SSL certificate validation.',
564
+                        ILogger::WARN
565
+                    );
566
+                }
567
+            }
568
+
569
+            $isOverrideMainServer = ($this->configuration->ldapOverrideMainServer
570
+                || $this->getFromCache('overrideMainServer'));
571
+            $isBackupHost = (trim($this->configuration->ldapBackupHost) !== "");
572
+            $bindStatus = false;
573
+            try {
574
+                if (!$isOverrideMainServer) {
575
+                    $this->doConnect($this->configuration->ldapHost,
576
+                        $this->configuration->ldapPort);
577
+                    return $this->bind();
578
+                }
579
+            } catch (ServerNotAvailableException $e) {
580
+                if(!$isBackupHost) {
581
+                    throw $e;
582
+                }
583
+            }
584
+
585
+            //if LDAP server is not reachable, try the Backup (Replica!) Server
586
+            if($isBackupHost || $isOverrideMainServer) {
587
+                $this->doConnect($this->configuration->ldapBackupHost,
588
+                                    $this->configuration->ldapBackupPort);
589
+                $this->bindResult = [];
590
+                $bindStatus = $this->bind();
591
+                $error = $this->ldap->isResource($this->ldapConnectionRes) ?
592
+                    $this->ldap->errno($this->ldapConnectionRes) : -1;
593
+                if($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
594
+                    //when bind to backup server succeeded and failed to main server,
595
+                    //skip contacting him until next cache refresh
596
+                    $this->writeToCache('overrideMainServer', true);
597
+                }
598
+            }
599
+
600
+            return $bindStatus;
601
+        }
602
+        return null;
603
+    }
604
+
605
+    /**
606
+     * @param string $host
607
+     * @param string $port
608
+     * @return bool
609
+     * @throws \OC\ServerNotAvailableException
610
+     */
611
+    private function doConnect($host, $port) {
612
+        if ($host === '') {
613
+            return false;
614
+        }
615
+
616
+        $this->ldapConnectionRes = $this->ldap->connect($host, $port);
617
+
618
+        if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
619
+            throw new ServerNotAvailableException('Could not set required LDAP Protocol version.');
620
+        }
621
+
622
+        if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
623
+            throw new ServerNotAvailableException('Could not disable LDAP referrals.');
624
+        }
625
+
626
+        if($this->configuration->ldapTLS) {
627
+            if(!$this->ldap->startTls($this->ldapConnectionRes)) {
628
+                throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.');
629
+            }
630
+        }
631
+
632
+        return true;
633
+    }
634
+
635
+    /**
636
+     * Binds to LDAP
637
+     */
638
+    public function bind() {
639
+        if(!$this->configuration->ldapConfigurationActive) {
640
+            return false;
641
+        }
642
+        $cr = $this->ldapConnectionRes;
643
+        if(!$this->ldap->isResource($cr)) {
644
+            $cr = $this->getConnectionResource();
645
+        }
646
+
647
+        if(
648
+            count($this->bindResult) !== 0
649
+            && $this->bindResult['dn'] === $this->configuration->ldapAgentName
650
+            && \OC::$server->getHasher()->verify(
651
+                $this->configPrefix . $this->configuration->ldapAgentPassword,
652
+                $this->bindResult['hash']
653
+            )
654
+        ) {
655
+            // don't attempt to bind again with the same data as before
656
+            // bind might have been invoked via getConnectionResource(),
657
+            // but we need results specifically for e.g. user login
658
+            return $this->bindResult['result'];
659
+        }
660
+
661
+        $ldapLogin = @$this->ldap->bind($cr,
662
+                                        $this->configuration->ldapAgentName,
663
+                                        $this->configuration->ldapAgentPassword);
664
+
665
+        $this->bindResult = [
666
+            'dn' => $this->configuration->ldapAgentName,
667
+            'hash' => \OC::$server->getHasher()->hash($this->configPrefix . $this->configuration->ldapAgentPassword),
668
+            'result' => $ldapLogin,
669
+        ];
670
+
671
+        if(!$ldapLogin) {
672
+            $errno = $this->ldap->errno($cr);
673
+
674
+            \OCP\Util::writeLog('user_ldap',
675
+                'Bind failed: ' . $errno . ': ' . $this->ldap->error($cr),
676
+                ILogger::WARN);
677
+
678
+            // Set to failure mode, if LDAP error code is not LDAP_SUCCESS or LDAP_INVALID_CREDENTIALS
679
+            // or (needed for Apple Open Directory:) LDAP_INSUFFICIENT_ACCESS
680
+            if($errno !== 0 && $errno !== 49 && $errno !== 50) {
681
+                $this->ldapConnectionRes = null;
682
+            }
683
+
684
+            return false;
685
+        }
686
+        return true;
687
+    }
688 688
 
689 689
 }
Please login to merge, or discard this patch.
Spacing   +65 added lines, -65 removed lines patch added patch discarded remove patch
@@ -111,7 +111,7 @@  discard block
 block discarded – undo
111 111
 		$this->configuration = new Configuration($configPrefix,
112 112
 												 !is_null($configID));
113 113
 		$memcache = \OC::$server->getMemCacheFactory();
114
-		if($memcache->isAvailable()) {
114
+		if ($memcache->isAvailable()) {
115 115
 			$this->cache = $memcache->createDistributed();
116 116
 		}
117 117
 		$helper = new Helper(\OC::$server->getConfig());
@@ -120,7 +120,7 @@  discard block
 block discarded – undo
120 120
 	}
121 121
 
122 122
 	public function __destruct() {
123
-		if(!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
123
+		if (!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
124 124
 			@$this->ldap->unbind($this->ldapConnectionRes);
125 125
 			$this->bindResult = [];
126 126
 		}
@@ -132,7 +132,7 @@  discard block
 block discarded – undo
132 132
 	public function __clone() {
133 133
 		$this->configuration = new Configuration($this->configPrefix,
134 134
 												 !is_null($this->configID));
135
-		if(count($this->bindResult) !== 0 && $this->bindResult['result'] === true) {
135
+		if (count($this->bindResult) !== 0 && $this->bindResult['result'] === true) {
136 136
 			$this->bindResult = [];
137 137
 		}
138 138
 		$this->ldapConnectionRes = null;
@@ -144,7 +144,7 @@  discard block
 block discarded – undo
144 144
 	 * @return bool|mixed
145 145
 	 */
146 146
 	public function __get($name) {
147
-		if(!$this->configured) {
147
+		if (!$this->configured) {
148 148
 			$this->readConfiguration();
149 149
 		}
150 150
 
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
 		$before = $this->configuration->$name;
161 161
 		$this->configuration->$name = $value;
162 162
 		$after = $this->configuration->$name;
163
-		if($before !== $after) {
163
+		if ($before !== $after) {
164 164
 			if ($this->configID !== '' && $this->configID !== null) {
165 165
 				$this->configuration->saveConfiguration();
166 166
 			}
@@ -184,7 +184,7 @@  discard block
 block discarded – undo
184 184
 	 * @param bool $state
185 185
 	 */
186 186
 	public function setIgnoreValidation($state) {
187
-		$this->ignoreValidation = (bool)$state;
187
+		$this->ignoreValidation = (bool) $state;
188 188
 	}
189 189
 
190 190
 	/**
@@ -200,14 +200,14 @@  discard block
 block discarded – undo
200 200
 	 * Returns the LDAP handler
201 201
 	 */
202 202
 	public function getConnectionResource() {
203
-		if(!$this->ldapConnectionRes) {
203
+		if (!$this->ldapConnectionRes) {
204 204
 			$this->init();
205
-		} else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
205
+		} else if (!$this->ldap->isResource($this->ldapConnectionRes)) {
206 206
 			$this->ldapConnectionRes = null;
207 207
 			$this->establishConnection();
208 208
 		}
209
-		if(is_null($this->ldapConnectionRes)) {
210
-			\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, ILogger::ERROR);
209
+		if (is_null($this->ldapConnectionRes)) {
210
+			\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server '.$this->configuration->ldapHost, ILogger::ERROR);
211 211
 			throw new ServerNotAvailableException('Connection to LDAP server could not be established');
212 212
 		}
213 213
 		return $this->ldapConnectionRes;
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
 	 * resets the connection resource
218 218
 	 */
219 219
 	public function resetConnectionResource() {
220
-		if(!is_null($this->ldapConnectionRes)) {
220
+		if (!is_null($this->ldapConnectionRes)) {
221 221
 			@$this->ldap->unbind($this->ldapConnectionRes);
222 222
 			$this->ldapConnectionRes = null;
223 223
 			$this->bindResult = [];
@@ -230,7 +230,7 @@  discard block
 block discarded – undo
230 230
 	 */
231 231
 	private function getCacheKey($key) {
232 232
 		$prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
233
-		if(is_null($key)) {
233
+		if (is_null($key)) {
234 234
 			return $prefix;
235 235
 		}
236 236
 		return $prefix.hash('sha256', $key);
@@ -241,10 +241,10 @@  discard block
 block discarded – undo
241 241
 	 * @return mixed|null
242 242
 	 */
243 243
 	public function getFromCache($key) {
244
-		if(!$this->configured) {
244
+		if (!$this->configured) {
245 245
 			$this->readConfiguration();
246 246
 		}
247
-		if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
247
+		if (is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
248 248
 			return null;
249 249
 		}
250 250
 		$key = $this->getCacheKey($key);
@@ -259,10 +259,10 @@  discard block
 block discarded – undo
259 259
 	 * @return string
260 260
 	 */
261 261
 	public function writeToCache($key, $value) {
262
-		if(!$this->configured) {
262
+		if (!$this->configured) {
263 263
 			$this->readConfiguration();
264 264
 		}
265
-		if(is_null($this->cache)
265
+		if (is_null($this->cache)
266 266
 			|| !$this->configuration->ldapCacheTTL
267 267
 			|| !$this->configuration->ldapConfigurationActive) {
268 268
 			return null;
@@ -273,7 +273,7 @@  discard block
 block discarded – undo
273 273
 	}
274 274
 
275 275
 	public function clearCache() {
276
-		if(!is_null($this->cache)) {
276
+		if (!is_null($this->cache)) {
277 277
 			$this->cache->clear($this->getCacheKey(null));
278 278
 		}
279 279
 	}
@@ -285,7 +285,7 @@  discard block
 block discarded – undo
285 285
 	 * @return null
286 286
 	 */
287 287
 	private function readConfiguration($force = false) {
288
-		if((!$this->configured || $force) && !is_null($this->configID)) {
288
+		if ((!$this->configured || $force) && !is_null($this->configID)) {
289 289
 			$this->configuration->readConfiguration();
290 290
 			$this->configured = $this->validateConfiguration();
291 291
 		}
@@ -298,12 +298,12 @@  discard block
 block discarded – undo
298 298
 	 * @return boolean true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
299 299
 	 */
300 300
 	public function setConfiguration($config, &$setParameters = null) {
301
-		if(is_null($setParameters)) {
301
+		if (is_null($setParameters)) {
302 302
 			$setParameters = [];
303 303
 		}
304 304
 		$this->doNotValidate = false;
305 305
 		$this->configuration->setConfiguration($config, $setParameters);
306
-		if(count($setParameters) > 0) {
306
+		if (count($setParameters) > 0) {
307 307
 			$this->configured = $this->validateConfiguration();
308 308
 		}
309 309
 
@@ -330,10 +330,10 @@  discard block
 block discarded – undo
330 330
 		$config = $this->configuration->getConfiguration();
331 331
 		$cta = $this->configuration->getConfigTranslationArray();
332 332
 		$result = [];
333
-		foreach($cta as $dbkey => $configkey) {
334
-			switch($configkey) {
333
+		foreach ($cta as $dbkey => $configkey) {
334
+			switch ($configkey) {
335 335
 				case 'homeFolderNamingRule':
336
-					if(strpos($config[$configkey], 'attr:') === 0) {
336
+					if (strpos($config[$configkey], 'attr:') === 0) {
337 337
 						$result[$dbkey] = substr($config[$configkey], 5);
338 338
 					} else {
339 339
 						$result[$dbkey] = '';
@@ -344,7 +344,7 @@  discard block
 block discarded – undo
344 344
 				case 'ldapBaseGroups':
345 345
 				case 'ldapAttributesForUserSearch':
346 346
 				case 'ldapAttributesForGroupSearch':
347
-					if(is_array($config[$configkey])) {
347
+					if (is_array($config[$configkey])) {
348 348
 						$result[$dbkey] = implode("\n", $config[$configkey]);
349 349
 						break;
350 350
 					} //else follows default
@@ -357,23 +357,23 @@  discard block
 block discarded – undo
357 357
 
358 358
 	private function doSoftValidation() {
359 359
 		//if User or Group Base are not set, take over Base DN setting
360
-		foreach(['ldapBaseUsers', 'ldapBaseGroups'] as $keyBase) {
360
+		foreach (['ldapBaseUsers', 'ldapBaseGroups'] as $keyBase) {
361 361
 			$val = $this->configuration->$keyBase;
362
-			if(empty($val)) {
362
+			if (empty($val)) {
363 363
 				$this->configuration->$keyBase = $this->configuration->ldapBase;
364 364
 			}
365 365
 		}
366 366
 
367
-		foreach(['ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
367
+		foreach (['ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
368 368
 			'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute']
369 369
 				as $expertSetting => $effectiveSetting) {
370 370
 			$uuidOverride = $this->configuration->$expertSetting;
371
-			if(!empty($uuidOverride)) {
371
+			if (!empty($uuidOverride)) {
372 372
 				$this->configuration->$effectiveSetting = $uuidOverride;
373 373
 			} else {
374 374
 				$uuidAttributes = Access::UUID_ATTRIBUTES;
375 375
 				array_unshift($uuidAttributes, 'auto');
376
-				if(!in_array($this->configuration->$effectiveSetting,
376
+				if (!in_array($this->configuration->$effectiveSetting,
377 377
 							$uuidAttributes)
378 378
 					&& (!is_null($this->configID))) {
379 379
 					$this->configuration->$effectiveSetting = 'auto';
@@ -387,7 +387,7 @@  discard block
 block discarded – undo
387 387
 			}
388 388
 		}
389 389
 
390
-		$backupPort = (int)$this->configuration->ldapBackupPort;
390
+		$backupPort = (int) $this->configuration->ldapBackupPort;
391 391
 		if ($backupPort <= 0) {
392 392
 			$this->configuration->backupPort = $this->configuration->ldapPort;
393 393
 		}
@@ -395,14 +395,14 @@  discard block
 block discarded – undo
395 395
 		//make sure empty search attributes are saved as simple, empty array
396 396
 		$saKeys = ['ldapAttributesForUserSearch',
397 397
 			'ldapAttributesForGroupSearch'];
398
-		foreach($saKeys as $key) {
398
+		foreach ($saKeys as $key) {
399 399
 			$val = $this->configuration->$key;
400
-			if(is_array($val) && count($val) === 1 && empty($val[0])) {
400
+			if (is_array($val) && count($val) === 1 && empty($val[0])) {
401 401
 				$this->configuration->$key = [];
402 402
 			}
403 403
 		}
404 404
 
405
-		if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
405
+		if ((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
406 406
 			&& $this->configuration->ldapTLS) {
407 407
 			$this->configuration->ldapTLS = false;
408 408
 			\OCP\Util::writeLog(
@@ -419,15 +419,15 @@  discard block
 block discarded – undo
419 419
 	private function doCriticalValidation() {
420 420
 		$configurationOK = true;
421 421
 		$errorStr = 'Configuration Error (prefix '.
422
-			(string)$this->configPrefix .'): ';
422
+			(string) $this->configPrefix.'): ';
423 423
 
424 424
 		//options that shall not be empty
425 425
 		$options = ['ldapHost', 'ldapPort', 'ldapUserDisplayName',
426 426
 			'ldapGroupDisplayName', 'ldapLoginFilter'];
427
-		foreach($options as $key) {
427
+		foreach ($options as $key) {
428 428
 			$val = $this->configuration->$key;
429
-			if(empty($val)) {
430
-				switch($key) {
429
+			if (empty($val)) {
430
+				switch ($key) {
431 431
 					case 'ldapHost':
432 432
 						$subj = 'LDAP Host';
433 433
 						break;
@@ -460,12 +460,12 @@  discard block
 block discarded – undo
460 460
 		$agent = $this->configuration->ldapAgentName;
461 461
 		$pwd = $this->configuration->ldapAgentPassword;
462 462
 		if (
463
-			($agent === ''  && $pwd !== '')
463
+			($agent === '' && $pwd !== '')
464 464
 			|| ($agent !== '' && $pwd === '')
465 465
 		) {
466 466
 			\OCP\Util::writeLog(
467 467
 				'user_ldap',
468
-				$errorStr.'either no password is given for the user ' .
468
+				$errorStr.'either no password is given for the user '.
469 469
 					'agent or a password is given, but not an LDAP agent.',
470 470
 				ILogger::WARN);
471 471
 			$configurationOK = false;
@@ -475,7 +475,7 @@  discard block
 block discarded – undo
475 475
 		$baseUsers = $this->configuration->ldapBaseUsers;
476 476
 		$baseGroups = $this->configuration->ldapBaseGroups;
477 477
 
478
-		if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
478
+		if (empty($base) && empty($baseUsers) && empty($baseGroups)) {
479 479
 			\OCP\Util::writeLog(
480 480
 				'user_ldap',
481 481
 				$errorStr.'Not a single Base DN given.',
@@ -484,7 +484,7 @@  discard block
 block discarded – undo
484 484
 			$configurationOK = false;
485 485
 		}
486 486
 
487
-		if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
487
+		if (mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
488 488
 		   === false) {
489 489
 			\OCP\Util::writeLog(
490 490
 				'user_ldap',
@@ -503,7 +503,7 @@  discard block
 block discarded – undo
503 503
 	 */
504 504
 	private function validateConfiguration() {
505 505
 
506
-		if($this->doNotValidate) {
506
+		if ($this->doNotValidate) {
507 507
 			//don't do a validation if it is a new configuration with pure
508 508
 			//default values. Will be allowed on changes via __set or
509 509
 			//setConfiguration
@@ -526,14 +526,14 @@  discard block
 block discarded – undo
526 526
 	 * @throws ServerNotAvailableException
527 527
 	 */
528 528
 	private function establishConnection() {
529
-		if(!$this->configuration->ldapConfigurationActive) {
529
+		if (!$this->configuration->ldapConfigurationActive) {
530 530
 			return null;
531 531
 		}
532 532
 		static $phpLDAPinstalled = true;
533
-		if(!$phpLDAPinstalled) {
533
+		if (!$phpLDAPinstalled) {
534 534
 			return false;
535 535
 		}
536
-		if(!$this->ignoreValidation && !$this->configured) {
536
+		if (!$this->ignoreValidation && !$this->configured) {
537 537
 			\OCP\Util::writeLog(
538 538
 				'user_ldap',
539 539
 				'Configuration is invalid, cannot connect',
@@ -541,8 +541,8 @@  discard block
 block discarded – undo
541 541
 			);
542 542
 			return false;
543 543
 		}
544
-		if(!$this->ldapConnectionRes) {
545
-			if(!$this->ldap->areLDAPFunctionsAvailable()) {
544
+		if (!$this->ldapConnectionRes) {
545
+			if (!$this->ldap->areLDAPFunctionsAvailable()) {
546 546
 				$phpLDAPinstalled = false;
547 547
 				\OCP\Util::writeLog(
548 548
 					'user_ldap',
@@ -552,8 +552,8 @@  discard block
 block discarded – undo
552 552
 
553 553
 				return false;
554 554
 			}
555
-			if($this->configuration->turnOffCertCheck) {
556
-				if(putenv('LDAPTLS_REQCERT=never')) {
555
+			if ($this->configuration->turnOffCertCheck) {
556
+				if (putenv('LDAPTLS_REQCERT=never')) {
557 557
 					\OCP\Util::writeLog('user_ldap',
558 558
 						'Turned off SSL certificate validation successfully.',
559 559
 						ILogger::DEBUG);
@@ -577,20 +577,20 @@  discard block
 block discarded – undo
577 577
 					return $this->bind();
578 578
 				}
579 579
 			} catch (ServerNotAvailableException $e) {
580
-				if(!$isBackupHost) {
580
+				if (!$isBackupHost) {
581 581
 					throw $e;
582 582
 				}
583 583
 			}
584 584
 
585 585
 			//if LDAP server is not reachable, try the Backup (Replica!) Server
586
-			if($isBackupHost || $isOverrideMainServer) {
586
+			if ($isBackupHost || $isOverrideMainServer) {
587 587
 				$this->doConnect($this->configuration->ldapBackupHost,
588 588
 								 $this->configuration->ldapBackupPort);
589 589
 				$this->bindResult = [];
590 590
 				$bindStatus = $this->bind();
591 591
 				$error = $this->ldap->isResource($this->ldapConnectionRes) ?
592 592
 					$this->ldap->errno($this->ldapConnectionRes) : -1;
593
-				if($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
593
+				if ($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
594 594
 					//when bind to backup server succeeded and failed to main server,
595 595
 					//skip contacting him until next cache refresh
596 596
 					$this->writeToCache('overrideMainServer', true);
@@ -615,17 +615,17 @@  discard block
 block discarded – undo
615 615
 
616 616
 		$this->ldapConnectionRes = $this->ldap->connect($host, $port);
617 617
 
618
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
618
+		if (!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
619 619
 			throw new ServerNotAvailableException('Could not set required LDAP Protocol version.');
620 620
 		}
621 621
 
622
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
622
+		if (!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
623 623
 			throw new ServerNotAvailableException('Could not disable LDAP referrals.');
624 624
 		}
625 625
 
626
-		if($this->configuration->ldapTLS) {
627
-			if(!$this->ldap->startTls($this->ldapConnectionRes)) {
628
-				throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.');
626
+		if ($this->configuration->ldapTLS) {
627
+			if (!$this->ldap->startTls($this->ldapConnectionRes)) {
628
+				throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host '.$host.'.');
629 629
 			}
630 630
 		}
631 631
 
@@ -636,19 +636,19 @@  discard block
 block discarded – undo
636 636
 	 * Binds to LDAP
637 637
 	 */
638 638
 	public function bind() {
639
-		if(!$this->configuration->ldapConfigurationActive) {
639
+		if (!$this->configuration->ldapConfigurationActive) {
640 640
 			return false;
641 641
 		}
642 642
 		$cr = $this->ldapConnectionRes;
643
-		if(!$this->ldap->isResource($cr)) {
643
+		if (!$this->ldap->isResource($cr)) {
644 644
 			$cr = $this->getConnectionResource();
645 645
 		}
646 646
 
647
-		if(
647
+		if (
648 648
 			count($this->bindResult) !== 0
649 649
 			&& $this->bindResult['dn'] === $this->configuration->ldapAgentName
650 650
 			&& \OC::$server->getHasher()->verify(
651
-				$this->configPrefix . $this->configuration->ldapAgentPassword,
651
+				$this->configPrefix.$this->configuration->ldapAgentPassword,
652 652
 				$this->bindResult['hash']
653 653
 			)
654 654
 		) {
@@ -664,20 +664,20 @@  discard block
 block discarded – undo
664 664
 
665 665
 		$this->bindResult = [
666 666
 			'dn' => $this->configuration->ldapAgentName,
667
-			'hash' => \OC::$server->getHasher()->hash($this->configPrefix . $this->configuration->ldapAgentPassword),
667
+			'hash' => \OC::$server->getHasher()->hash($this->configPrefix.$this->configuration->ldapAgentPassword),
668 668
 			'result' => $ldapLogin,
669 669
 		];
670 670
 
671
-		if(!$ldapLogin) {
671
+		if (!$ldapLogin) {
672 672
 			$errno = $this->ldap->errno($cr);
673 673
 
674 674
 			\OCP\Util::writeLog('user_ldap',
675
-				'Bind failed: ' . $errno . ': ' . $this->ldap->error($cr),
675
+				'Bind failed: '.$errno.': '.$this->ldap->error($cr),
676 676
 				ILogger::WARN);
677 677
 
678 678
 			// Set to failure mode, if LDAP error code is not LDAP_SUCCESS or LDAP_INVALID_CREDENTIALS
679 679
 			// or (needed for Apple Open Directory:) LDAP_INSUFFICIENT_ACCESS
680
-			if($errno !== 0 && $errno !== 49 && $errno !== 50) {
680
+			if ($errno !== 0 && $errno !== 49 && $errno !== 50) {
681 681
 				$this->ldapConnectionRes = null;
682 682
 			}
683 683
 
Please login to merge, or discard this patch.