Completed
Pull Request — master (#4212)
by Individual IT
33:24
created
apps/dav/lib/DAV/SystemPrincipalBackend.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -132,7 +132,7 @@
 block discarded – undo
132 132
 	 * Returns the list of members for a group-principal
133 133
 	 *
134 134
 	 * @param string $principal
135
-	 * @return array
135
+	 * @return string[]
136 136
 	 */
137 137
 	function getGroupMemberSet($principal) {
138 138
 		// TODO: for now the group principal has only one member, the user itself
Please login to merge, or discard this patch.
Indentation   +161 added lines, -161 removed lines patch added patch discarded remove patch
@@ -27,165 +27,165 @@
 block discarded – undo
27 27
 
28 28
 class SystemPrincipalBackend extends AbstractBackend {
29 29
 
30
-	/**
31
-	 * Returns a list of principals based on a prefix.
32
-	 *
33
-	 * This prefix will often contain something like 'principals'. You are only
34
-	 * expected to return principals that are in this base path.
35
-	 *
36
-	 * You are expected to return at least a 'uri' for every user, you can
37
-	 * return any additional properties if you wish so. Common properties are:
38
-	 *   {DAV:}displayname
39
-	 *   {http://sabredav.org/ns}email-address - This is a custom SabreDAV
40
-	 *     field that's actually injected in a number of other properties. If
41
-	 *     you have an email address, use this property.
42
-	 *
43
-	 * @param string $prefixPath
44
-	 * @return array
45
-	 */
46
-	function getPrincipalsByPrefix($prefixPath) {
47
-		$principals = [];
48
-
49
-		if ($prefixPath === 'principals/system') {
50
-			$principals[] = [
51
-				'uri' => 'principals/system/system',
52
-				'{DAV:}displayname' => 'system',
53
-			];
54
-			$principals[] = [
55
-				'uri' => 'principals/system/public',
56
-				'{DAV:}displayname' => 'public',
57
-			];
58
-		}
59
-
60
-		return $principals;
61
-	}
62
-
63
-	/**
64
-	 * Returns a specific principal, specified by it's path.
65
-	 * The returned structure should be the exact same as from
66
-	 * getPrincipalsByPrefix.
67
-	 *
68
-	 * @param string $path
69
-	 * @return array
70
-	 */
71
-	function getPrincipalByPath($path) {
72
-
73
-		if ($path === 'principals/system/system') {
74
-			$principal = [
75
-				'uri' => 'principals/system/system',
76
-				'{DAV:}displayname' => 'system',
77
-			];
78
-			return $principal;
79
-		}
80
-		if ($path === 'principals/system/public') {
81
-			$principal = [
82
-				'uri' => 'principals/system/public',
83
-				'{DAV:}displayname' => 'public',
84
-			];
85
-			return $principal;
86
-		}
87
-
88
-		return null;
89
-	}
90
-
91
-	/**
92
-	 * Updates one ore more webdav properties on a principal.
93
-	 *
94
-	 * The list of mutations is stored in a Sabre\DAV\PropPatch object.
95
-	 * To do the actual updates, you must tell this object which properties
96
-	 * you're going to process with the handle() method.
97
-	 *
98
-	 * Calling the handle method is like telling the PropPatch object "I
99
-	 * promise I can handle updating this property".
100
-	 *
101
-	 * Read the PropPatch documentation for more info and examples.
102
-	 *
103
-	 * @param string $path
104
-	 * @param \Sabre\DAV\PropPatch $propPatch
105
-	 * @return void
106
-	 */
107
-	function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch) {
108
-	}
109
-
110
-	/**
111
-	 * This method is used to search for principals matching a set of
112
-	 * properties.
113
-	 *
114
-	 * This search is specifically used by RFC3744's principal-property-search
115
-	 * REPORT.
116
-	 *
117
-	 * The actual search should be a unicode-non-case-sensitive search. The
118
-	 * keys in searchProperties are the WebDAV property names, while the values
119
-	 * are the property values to search on.
120
-	 *
121
-	 * By default, if multiple properties are submitted to this method, the
122
-	 * various properties should be combined with 'AND'. If $test is set to
123
-	 * 'anyof', it should be combined using 'OR'.
124
-	 *
125
-	 * This method should simply return an array with full principal uri's.
126
-	 *
127
-	 * If somebody attempted to search on a property the backend does not
128
-	 * support, you should simply return 0 results.
129
-	 *
130
-	 * You can also just return 0 results if you choose to not support
131
-	 * searching at all, but keep in mind that this may stop certain features
132
-	 * from working.
133
-	 *
134
-	 * @param string $prefixPath
135
-	 * @param array $searchProperties
136
-	 * @param string $test
137
-	 * @return array
138
-	 */
139
-	function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
140
-		return [];
141
-	}
142
-
143
-	/**
144
-	 * Returns the list of members for a group-principal
145
-	 *
146
-	 * @param string $principal
147
-	 * @return array
148
-	 */
149
-	function getGroupMemberSet($principal) {
150
-		// TODO: for now the group principal has only one member, the user itself
151
-		$principal = $this->getPrincipalByPath($principal);
152
-		if (!$principal) {
153
-			throw new \Sabre\DAV\Exception('Principal not found');
154
-		}
155
-
156
-		return [$principal['uri']];
157
-	}
158
-
159
-	/**
160
-	 * Returns the list of groups a principal is a member of
161
-	 *
162
-	 * @param string $principal
163
-	 * @return array
164
-	 */
165
-	function getGroupMembership($principal) {
166
-		list($prefix, $name) = URLUtil::splitPath($principal);
167
-
168
-		if ($prefix === 'principals/system') {
169
-			$principal = $this->getPrincipalByPath($principal);
170
-			if (!$principal) {
171
-				throw new \Sabre\DAV\Exception('Principal not found');
172
-			}
173
-
174
-			return [];
175
-		}
176
-		return [];
177
-	}
178
-
179
-	/**
180
-	 * Updates the list of group members for a group principal.
181
-	 *
182
-	 * The principals should be passed as a list of uri's.
183
-	 *
184
-	 * @param string $principal
185
-	 * @param array $members
186
-	 * @return void
187
-	 */
188
-	function setGroupMemberSet($principal, array $members) {
189
-		throw new \Sabre\DAV\Exception('Setting members of the group is not supported yet');
190
-	}
30
+    /**
31
+     * Returns a list of principals based on a prefix.
32
+     *
33
+     * This prefix will often contain something like 'principals'. You are only
34
+     * expected to return principals that are in this base path.
35
+     *
36
+     * You are expected to return at least a 'uri' for every user, you can
37
+     * return any additional properties if you wish so. Common properties are:
38
+     *   {DAV:}displayname
39
+     *   {http://sabredav.org/ns}email-address - This is a custom SabreDAV
40
+     *     field that's actually injected in a number of other properties. If
41
+     *     you have an email address, use this property.
42
+     *
43
+     * @param string $prefixPath
44
+     * @return array
45
+     */
46
+    function getPrincipalsByPrefix($prefixPath) {
47
+        $principals = [];
48
+
49
+        if ($prefixPath === 'principals/system') {
50
+            $principals[] = [
51
+                'uri' => 'principals/system/system',
52
+                '{DAV:}displayname' => 'system',
53
+            ];
54
+            $principals[] = [
55
+                'uri' => 'principals/system/public',
56
+                '{DAV:}displayname' => 'public',
57
+            ];
58
+        }
59
+
60
+        return $principals;
61
+    }
62
+
63
+    /**
64
+     * Returns a specific principal, specified by it's path.
65
+     * The returned structure should be the exact same as from
66
+     * getPrincipalsByPrefix.
67
+     *
68
+     * @param string $path
69
+     * @return array
70
+     */
71
+    function getPrincipalByPath($path) {
72
+
73
+        if ($path === 'principals/system/system') {
74
+            $principal = [
75
+                'uri' => 'principals/system/system',
76
+                '{DAV:}displayname' => 'system',
77
+            ];
78
+            return $principal;
79
+        }
80
+        if ($path === 'principals/system/public') {
81
+            $principal = [
82
+                'uri' => 'principals/system/public',
83
+                '{DAV:}displayname' => 'public',
84
+            ];
85
+            return $principal;
86
+        }
87
+
88
+        return null;
89
+    }
90
+
91
+    /**
92
+     * Updates one ore more webdav properties on a principal.
93
+     *
94
+     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
95
+     * To do the actual updates, you must tell this object which properties
96
+     * you're going to process with the handle() method.
97
+     *
98
+     * Calling the handle method is like telling the PropPatch object "I
99
+     * promise I can handle updating this property".
100
+     *
101
+     * Read the PropPatch documentation for more info and examples.
102
+     *
103
+     * @param string $path
104
+     * @param \Sabre\DAV\PropPatch $propPatch
105
+     * @return void
106
+     */
107
+    function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch) {
108
+    }
109
+
110
+    /**
111
+     * This method is used to search for principals matching a set of
112
+     * properties.
113
+     *
114
+     * This search is specifically used by RFC3744's principal-property-search
115
+     * REPORT.
116
+     *
117
+     * The actual search should be a unicode-non-case-sensitive search. The
118
+     * keys in searchProperties are the WebDAV property names, while the values
119
+     * are the property values to search on.
120
+     *
121
+     * By default, if multiple properties are submitted to this method, the
122
+     * various properties should be combined with 'AND'. If $test is set to
123
+     * 'anyof', it should be combined using 'OR'.
124
+     *
125
+     * This method should simply return an array with full principal uri's.
126
+     *
127
+     * If somebody attempted to search on a property the backend does not
128
+     * support, you should simply return 0 results.
129
+     *
130
+     * You can also just return 0 results if you choose to not support
131
+     * searching at all, but keep in mind that this may stop certain features
132
+     * from working.
133
+     *
134
+     * @param string $prefixPath
135
+     * @param array $searchProperties
136
+     * @param string $test
137
+     * @return array
138
+     */
139
+    function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
140
+        return [];
141
+    }
142
+
143
+    /**
144
+     * Returns the list of members for a group-principal
145
+     *
146
+     * @param string $principal
147
+     * @return array
148
+     */
149
+    function getGroupMemberSet($principal) {
150
+        // TODO: for now the group principal has only one member, the user itself
151
+        $principal = $this->getPrincipalByPath($principal);
152
+        if (!$principal) {
153
+            throw new \Sabre\DAV\Exception('Principal not found');
154
+        }
155
+
156
+        return [$principal['uri']];
157
+    }
158
+
159
+    /**
160
+     * Returns the list of groups a principal is a member of
161
+     *
162
+     * @param string $principal
163
+     * @return array
164
+     */
165
+    function getGroupMembership($principal) {
166
+        list($prefix, $name) = URLUtil::splitPath($principal);
167
+
168
+        if ($prefix === 'principals/system') {
169
+            $principal = $this->getPrincipalByPath($principal);
170
+            if (!$principal) {
171
+                throw new \Sabre\DAV\Exception('Principal not found');
172
+            }
173
+
174
+            return [];
175
+        }
176
+        return [];
177
+    }
178
+
179
+    /**
180
+     * Updates the list of group members for a group principal.
181
+     *
182
+     * The principals should be passed as a list of uri's.
183
+     *
184
+     * @param string $principal
185
+     * @param array $members
186
+     * @return void
187
+     */
188
+    function setGroupMemberSet($principal, array $members) {
189
+        throw new \Sabre\DAV\Exception('Setting members of the group is not supported yet');
190
+    }
191 191
 }
Please login to merge, or discard this patch.
apps/dav/lib/SystemTag/SystemTagPlugin.php 3 patches
Unused Use Statements   -2 removed lines patch added patch discarded remove patch
@@ -29,9 +29,7 @@
 block discarded – undo
29 29
 use Sabre\DAV\Exception\BadRequest;
30 30
 use Sabre\DAV\Exception\Conflict;
31 31
 use Sabre\DAV\Exception\Forbidden;
32
-use Sabre\DAV\Exception\NotFound;
33 32
 use Sabre\DAV\Exception\UnsupportedMediaType;
34
-
35 33
 use OCP\SystemTag\ISystemTag;
36 34
 use OCP\SystemTag\ISystemTagManager;
37 35
 use OCP\SystemTag\TagAlreadyExistsException;
Please login to merge, or discard this patch.
Indentation   +276 added lines, -276 removed lines patch added patch discarded remove patch
@@ -49,280 +49,280 @@
 block discarded – undo
49 49
  */
50 50
 class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
51 51
 
52
-	// namespace
53
-	const NS_OWNCLOUD = 'http://owncloud.org/ns';
54
-	const ID_PROPERTYNAME = '{http://owncloud.org/ns}id';
55
-	const DISPLAYNAME_PROPERTYNAME = '{http://owncloud.org/ns}display-name';
56
-	const USERVISIBLE_PROPERTYNAME = '{http://owncloud.org/ns}user-visible';
57
-	const USERASSIGNABLE_PROPERTYNAME = '{http://owncloud.org/ns}user-assignable';
58
-	const GROUPS_PROPERTYNAME = '{http://owncloud.org/ns}groups';
59
-	const CANASSIGN_PROPERTYNAME = '{http://owncloud.org/ns}can-assign';
60
-
61
-	/**
62
-	 * @var \Sabre\DAV\Server $server
63
-	 */
64
-	private $server;
65
-
66
-	/**
67
-	 * @var ISystemTagManager
68
-	 */
69
-	protected $tagManager;
70
-
71
-	/**
72
-	 * @var IUserSession
73
-	 */
74
-	protected $userSession;
75
-
76
-	/**
77
-	 * @var IGroupManager
78
-	 */
79
-	protected $groupManager;
80
-
81
-	/**
82
-	 * @param ISystemTagManager $tagManager tag manager
83
-	 * @param IGroupManager $groupManager
84
-	 * @param IUserSession $userSession
85
-	 */
86
-	public function __construct(ISystemTagManager $tagManager,
87
-								IGroupManager $groupManager,
88
-								IUserSession $userSession) {
89
-		$this->tagManager = $tagManager;
90
-		$this->userSession = $userSession;
91
-		$this->groupManager = $groupManager;
92
-	}
93
-
94
-	/**
95
-	 * This initializes the plugin.
96
-	 *
97
-	 * This function is called by \Sabre\DAV\Server, after
98
-	 * addPlugin is called.
99
-	 *
100
-	 * This method should set up the required event subscriptions.
101
-	 *
102
-	 * @param \Sabre\DAV\Server $server
103
-	 * @return void
104
-	 */
105
-	public function initialize(\Sabre\DAV\Server $server) {
106
-
107
-		$server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
108
-
109
-		$server->protectedProperties[] = self::ID_PROPERTYNAME;
110
-
111
-		$server->on('propFind', array($this, 'handleGetProperties'));
112
-		$server->on('propPatch', array($this, 'handleUpdateProperties'));
113
-		$server->on('method:POST', [$this, 'httpPost']);
114
-
115
-		$this->server = $server;
116
-	}
117
-
118
-	/**
119
-	 * POST operation on system tag collections
120
-	 *
121
-	 * @param RequestInterface $request request object
122
-	 * @param ResponseInterface $response response object
123
-	 * @return null|false
124
-	 */
125
-	public function httpPost(RequestInterface $request, ResponseInterface $response) {
126
-		$path = $request->getPath();
127
-
128
-		// Making sure the node exists
129
-		$node = $this->server->tree->getNodeForPath($path);
130
-		if ($node instanceof SystemTagsByIdCollection || $node instanceof SystemTagsObjectMappingCollection) {
131
-			$data = $request->getBodyAsString();
132
-
133
-			$tag = $this->createTag($data, $request->getHeader('Content-Type'));
134
-
135
-			if ($node instanceof SystemTagsObjectMappingCollection) {
136
-				// also add to collection
137
-				$node->createFile($tag->getId());
138
-				$url = $request->getBaseUrl() . 'systemtags/';
139
-			} else {
140
-				$url = $request->getUrl();
141
-			}
142
-
143
-			if ($url[strlen($url) - 1] !== '/') {
144
-				$url .= '/';
145
-			}
146
-
147
-			$response->setHeader('Content-Location', $url . $tag->getId());
148
-
149
-			// created
150
-			$response->setStatus(201);
151
-			return false;
152
-		}
153
-	}
154
-
155
-	/**
156
-	 * Creates a new tag
157
-	 *
158
-	 * @param string $data JSON encoded string containing the properties of the tag to create
159
-	 * @param string $contentType content type of the data
160
-	 * @return ISystemTag newly created system tag
161
-	 *
162
-	 * @throws BadRequest if a field was missing
163
-	 * @throws Conflict if a tag with the same properties already exists
164
-	 * @throws UnsupportedMediaType if the content type is not supported
165
-	 */
166
-	private function createTag($data, $contentType = 'application/json') {
167
-		if (explode(';', $contentType)[0] === 'application/json') {
168
-			$data = json_decode($data, true);
169
-		} else {
170
-			throw new UnsupportedMediaType();
171
-		}
172
-
173
-		if (!isset($data['name'])) {
174
-			throw new BadRequest('Missing "name" attribute');
175
-		}
176
-
177
-		$tagName = $data['name'];
178
-		$userVisible = true;
179
-		$userAssignable = true;
180
-
181
-		if (isset($data['userVisible'])) {
182
-			$userVisible = (bool)$data['userVisible'];
183
-		}
184
-
185
-		if (isset($data['userAssignable'])) {
186
-			$userAssignable = (bool)$data['userAssignable'];
187
-		}
188
-
189
-		$groups = [];
190
-		if (isset($data['groups'])) {
191
-			$groups = $data['groups'];
192
-			if (is_string($groups)) {
193
-				$groups = explode('|', $groups);
194
-			}
195
-		}
196
-
197
-		if($userVisible === false || $userAssignable === false || !empty($groups)) {
198
-			if(!$this->userSession->isLoggedIn() || !$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) {
199
-				throw new BadRequest('Not sufficient permissions');
200
-			}
201
-		}
202
-
203
-		try {
204
-			$tag = $this->tagManager->createTag($tagName, $userVisible, $userAssignable);
205
-			if (!empty($groups)) {
206
-				$this->tagManager->setTagGroups($tag, $groups);
207
-			}
208
-			return $tag;
209
-		} catch (TagAlreadyExistsException $e) {
210
-			throw new Conflict('Tag already exists', 0, $e);
211
-		}
212
-	}
213
-
214
-
215
-	/**
216
-	 * Retrieves system tag properties
217
-	 *
218
-	 * @param PropFind $propFind
219
-	 * @param \Sabre\DAV\INode $node
220
-	 */
221
-	public function handleGetProperties(
222
-		PropFind $propFind,
223
-		\Sabre\DAV\INode $node
224
-	) {
225
-		if (!($node instanceof SystemTagNode) && !($node instanceof SystemTagMappingNode)) {
226
-			return;
227
-		}
228
-
229
-		$propFind->handle(self::ID_PROPERTYNAME, function() use ($node) {
230
-			return $node->getSystemTag()->getId();
231
-		});
232
-
233
-		$propFind->handle(self::DISPLAYNAME_PROPERTYNAME, function() use ($node) {
234
-			return $node->getSystemTag()->getName();
235
-		});
236
-
237
-		$propFind->handle(self::USERVISIBLE_PROPERTYNAME, function() use ($node) {
238
-			return $node->getSystemTag()->isUserVisible() ? 'true' : 'false';
239
-		});
240
-
241
-		$propFind->handle(self::USERASSIGNABLE_PROPERTYNAME, function() use ($node) {
242
-			// this is the tag's inherent property "is user assignable"
243
-			return $node->getSystemTag()->isUserAssignable() ? 'true' : 'false';
244
-		});
245
-
246
-		$propFind->handle(self::CANASSIGN_PROPERTYNAME, function() use ($node) {
247
-			// this is the effective permission for the current user
248
-			return $this->tagManager->canUserAssignTag($node->getSystemTag(), $this->userSession->getUser()) ? 'true' : 'false';
249
-		});
250
-
251
-		$propFind->handle(self::GROUPS_PROPERTYNAME, function() use ($node) {
252
-			if (!$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) {
253
-				// property only available for admins
254
-				throw new Forbidden();
255
-			}
256
-			$groups = [];
257
-			// no need to retrieve groups for namespaces that don't qualify
258
-			if ($node->getSystemTag()->isUserVisible() && !$node->getSystemTag()->isUserAssignable()) {
259
-				$groups = $this->tagManager->getTagGroups($node->getSystemTag());
260
-			}
261
-			return implode('|', $groups);
262
-		});
263
-	}
264
-
265
-	/**
266
-	 * Updates tag attributes
267
-	 *
268
-	 * @param string $path
269
-	 * @param PropPatch $propPatch
270
-	 *
271
-	 * @return void
272
-	 */
273
-	public function handleUpdateProperties($path, PropPatch $propPatch) {
274
-		$propPatch->handle([
275
-			self::DISPLAYNAME_PROPERTYNAME,
276
-			self::USERVISIBLE_PROPERTYNAME,
277
-			self::USERASSIGNABLE_PROPERTYNAME,
278
-			self::GROUPS_PROPERTYNAME,
279
-		], function($props) use ($path) {
280
-			$node = $this->server->tree->getNodeForPath($path);
281
-			if (!($node instanceof SystemTagNode)) {
282
-				return;
283
-			}
284
-
285
-			$tag = $node->getSystemTag();
286
-			$name = $tag->getName();
287
-			$userVisible = $tag->isUserVisible();
288
-			$userAssignable = $tag->isUserAssignable();
289
-
290
-			$updateTag = false;
291
-
292
-			if (isset($props[self::DISPLAYNAME_PROPERTYNAME])) {
293
-				$name = $props[self::DISPLAYNAME_PROPERTYNAME];
294
-				$updateTag = true;
295
-			}
296
-
297
-			if (isset($props[self::USERVISIBLE_PROPERTYNAME])) {
298
-				$propValue = $props[self::USERVISIBLE_PROPERTYNAME];
299
-				$userVisible = ($propValue !== 'false' && $propValue !== '0');
300
-				$updateTag = true;
301
-			}
302
-
303
-			if (isset($props[self::USERASSIGNABLE_PROPERTYNAME])) {
304
-				$propValue = $props[self::USERASSIGNABLE_PROPERTYNAME];
305
-				$userAssignable = ($propValue !== 'false' && $propValue !== '0');
306
-				$updateTag = true;
307
-			}
308
-
309
-			if (isset($props[self::GROUPS_PROPERTYNAME])) {
310
-				if (!$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) {
311
-					// property only available for admins
312
-					throw new Forbidden();
313
-				}
314
-
315
-				$propValue = $props[self::GROUPS_PROPERTYNAME];
316
-				$groupIds = explode('|', $propValue);
317
-				$this->tagManager->setTagGroups($tag, $groupIds);
318
-			}
319
-
320
-			if ($updateTag) {
321
-				$node->update($name, $userVisible, $userAssignable);
322
-			}
323
-
324
-			return true;
325
-		});
326
-
327
-	}
52
+    // namespace
53
+    const NS_OWNCLOUD = 'http://owncloud.org/ns';
54
+    const ID_PROPERTYNAME = '{http://owncloud.org/ns}id';
55
+    const DISPLAYNAME_PROPERTYNAME = '{http://owncloud.org/ns}display-name';
56
+    const USERVISIBLE_PROPERTYNAME = '{http://owncloud.org/ns}user-visible';
57
+    const USERASSIGNABLE_PROPERTYNAME = '{http://owncloud.org/ns}user-assignable';
58
+    const GROUPS_PROPERTYNAME = '{http://owncloud.org/ns}groups';
59
+    const CANASSIGN_PROPERTYNAME = '{http://owncloud.org/ns}can-assign';
60
+
61
+    /**
62
+     * @var \Sabre\DAV\Server $server
63
+     */
64
+    private $server;
65
+
66
+    /**
67
+     * @var ISystemTagManager
68
+     */
69
+    protected $tagManager;
70
+
71
+    /**
72
+     * @var IUserSession
73
+     */
74
+    protected $userSession;
75
+
76
+    /**
77
+     * @var IGroupManager
78
+     */
79
+    protected $groupManager;
80
+
81
+    /**
82
+     * @param ISystemTagManager $tagManager tag manager
83
+     * @param IGroupManager $groupManager
84
+     * @param IUserSession $userSession
85
+     */
86
+    public function __construct(ISystemTagManager $tagManager,
87
+                                IGroupManager $groupManager,
88
+                                IUserSession $userSession) {
89
+        $this->tagManager = $tagManager;
90
+        $this->userSession = $userSession;
91
+        $this->groupManager = $groupManager;
92
+    }
93
+
94
+    /**
95
+     * This initializes the plugin.
96
+     *
97
+     * This function is called by \Sabre\DAV\Server, after
98
+     * addPlugin is called.
99
+     *
100
+     * This method should set up the required event subscriptions.
101
+     *
102
+     * @param \Sabre\DAV\Server $server
103
+     * @return void
104
+     */
105
+    public function initialize(\Sabre\DAV\Server $server) {
106
+
107
+        $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
108
+
109
+        $server->protectedProperties[] = self::ID_PROPERTYNAME;
110
+
111
+        $server->on('propFind', array($this, 'handleGetProperties'));
112
+        $server->on('propPatch', array($this, 'handleUpdateProperties'));
113
+        $server->on('method:POST', [$this, 'httpPost']);
114
+
115
+        $this->server = $server;
116
+    }
117
+
118
+    /**
119
+     * POST operation on system tag collections
120
+     *
121
+     * @param RequestInterface $request request object
122
+     * @param ResponseInterface $response response object
123
+     * @return null|false
124
+     */
125
+    public function httpPost(RequestInterface $request, ResponseInterface $response) {
126
+        $path = $request->getPath();
127
+
128
+        // Making sure the node exists
129
+        $node = $this->server->tree->getNodeForPath($path);
130
+        if ($node instanceof SystemTagsByIdCollection || $node instanceof SystemTagsObjectMappingCollection) {
131
+            $data = $request->getBodyAsString();
132
+
133
+            $tag = $this->createTag($data, $request->getHeader('Content-Type'));
134
+
135
+            if ($node instanceof SystemTagsObjectMappingCollection) {
136
+                // also add to collection
137
+                $node->createFile($tag->getId());
138
+                $url = $request->getBaseUrl() . 'systemtags/';
139
+            } else {
140
+                $url = $request->getUrl();
141
+            }
142
+
143
+            if ($url[strlen($url) - 1] !== '/') {
144
+                $url .= '/';
145
+            }
146
+
147
+            $response->setHeader('Content-Location', $url . $tag->getId());
148
+
149
+            // created
150
+            $response->setStatus(201);
151
+            return false;
152
+        }
153
+    }
154
+
155
+    /**
156
+     * Creates a new tag
157
+     *
158
+     * @param string $data JSON encoded string containing the properties of the tag to create
159
+     * @param string $contentType content type of the data
160
+     * @return ISystemTag newly created system tag
161
+     *
162
+     * @throws BadRequest if a field was missing
163
+     * @throws Conflict if a tag with the same properties already exists
164
+     * @throws UnsupportedMediaType if the content type is not supported
165
+     */
166
+    private function createTag($data, $contentType = 'application/json') {
167
+        if (explode(';', $contentType)[0] === 'application/json') {
168
+            $data = json_decode($data, true);
169
+        } else {
170
+            throw new UnsupportedMediaType();
171
+        }
172
+
173
+        if (!isset($data['name'])) {
174
+            throw new BadRequest('Missing "name" attribute');
175
+        }
176
+
177
+        $tagName = $data['name'];
178
+        $userVisible = true;
179
+        $userAssignable = true;
180
+
181
+        if (isset($data['userVisible'])) {
182
+            $userVisible = (bool)$data['userVisible'];
183
+        }
184
+
185
+        if (isset($data['userAssignable'])) {
186
+            $userAssignable = (bool)$data['userAssignable'];
187
+        }
188
+
189
+        $groups = [];
190
+        if (isset($data['groups'])) {
191
+            $groups = $data['groups'];
192
+            if (is_string($groups)) {
193
+                $groups = explode('|', $groups);
194
+            }
195
+        }
196
+
197
+        if($userVisible === false || $userAssignable === false || !empty($groups)) {
198
+            if(!$this->userSession->isLoggedIn() || !$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) {
199
+                throw new BadRequest('Not sufficient permissions');
200
+            }
201
+        }
202
+
203
+        try {
204
+            $tag = $this->tagManager->createTag($tagName, $userVisible, $userAssignable);
205
+            if (!empty($groups)) {
206
+                $this->tagManager->setTagGroups($tag, $groups);
207
+            }
208
+            return $tag;
209
+        } catch (TagAlreadyExistsException $e) {
210
+            throw new Conflict('Tag already exists', 0, $e);
211
+        }
212
+    }
213
+
214
+
215
+    /**
216
+     * Retrieves system tag properties
217
+     *
218
+     * @param PropFind $propFind
219
+     * @param \Sabre\DAV\INode $node
220
+     */
221
+    public function handleGetProperties(
222
+        PropFind $propFind,
223
+        \Sabre\DAV\INode $node
224
+    ) {
225
+        if (!($node instanceof SystemTagNode) && !($node instanceof SystemTagMappingNode)) {
226
+            return;
227
+        }
228
+
229
+        $propFind->handle(self::ID_PROPERTYNAME, function() use ($node) {
230
+            return $node->getSystemTag()->getId();
231
+        });
232
+
233
+        $propFind->handle(self::DISPLAYNAME_PROPERTYNAME, function() use ($node) {
234
+            return $node->getSystemTag()->getName();
235
+        });
236
+
237
+        $propFind->handle(self::USERVISIBLE_PROPERTYNAME, function() use ($node) {
238
+            return $node->getSystemTag()->isUserVisible() ? 'true' : 'false';
239
+        });
240
+
241
+        $propFind->handle(self::USERASSIGNABLE_PROPERTYNAME, function() use ($node) {
242
+            // this is the tag's inherent property "is user assignable"
243
+            return $node->getSystemTag()->isUserAssignable() ? 'true' : 'false';
244
+        });
245
+
246
+        $propFind->handle(self::CANASSIGN_PROPERTYNAME, function() use ($node) {
247
+            // this is the effective permission for the current user
248
+            return $this->tagManager->canUserAssignTag($node->getSystemTag(), $this->userSession->getUser()) ? 'true' : 'false';
249
+        });
250
+
251
+        $propFind->handle(self::GROUPS_PROPERTYNAME, function() use ($node) {
252
+            if (!$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) {
253
+                // property only available for admins
254
+                throw new Forbidden();
255
+            }
256
+            $groups = [];
257
+            // no need to retrieve groups for namespaces that don't qualify
258
+            if ($node->getSystemTag()->isUserVisible() && !$node->getSystemTag()->isUserAssignable()) {
259
+                $groups = $this->tagManager->getTagGroups($node->getSystemTag());
260
+            }
261
+            return implode('|', $groups);
262
+        });
263
+    }
264
+
265
+    /**
266
+     * Updates tag attributes
267
+     *
268
+     * @param string $path
269
+     * @param PropPatch $propPatch
270
+     *
271
+     * @return void
272
+     */
273
+    public function handleUpdateProperties($path, PropPatch $propPatch) {
274
+        $propPatch->handle([
275
+            self::DISPLAYNAME_PROPERTYNAME,
276
+            self::USERVISIBLE_PROPERTYNAME,
277
+            self::USERASSIGNABLE_PROPERTYNAME,
278
+            self::GROUPS_PROPERTYNAME,
279
+        ], function($props) use ($path) {
280
+            $node = $this->server->tree->getNodeForPath($path);
281
+            if (!($node instanceof SystemTagNode)) {
282
+                return;
283
+            }
284
+
285
+            $tag = $node->getSystemTag();
286
+            $name = $tag->getName();
287
+            $userVisible = $tag->isUserVisible();
288
+            $userAssignable = $tag->isUserAssignable();
289
+
290
+            $updateTag = false;
291
+
292
+            if (isset($props[self::DISPLAYNAME_PROPERTYNAME])) {
293
+                $name = $props[self::DISPLAYNAME_PROPERTYNAME];
294
+                $updateTag = true;
295
+            }
296
+
297
+            if (isset($props[self::USERVISIBLE_PROPERTYNAME])) {
298
+                $propValue = $props[self::USERVISIBLE_PROPERTYNAME];
299
+                $userVisible = ($propValue !== 'false' && $propValue !== '0');
300
+                $updateTag = true;
301
+            }
302
+
303
+            if (isset($props[self::USERASSIGNABLE_PROPERTYNAME])) {
304
+                $propValue = $props[self::USERASSIGNABLE_PROPERTYNAME];
305
+                $userAssignable = ($propValue !== 'false' && $propValue !== '0');
306
+                $updateTag = true;
307
+            }
308
+
309
+            if (isset($props[self::GROUPS_PROPERTYNAME])) {
310
+                if (!$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) {
311
+                    // property only available for admins
312
+                    throw new Forbidden();
313
+                }
314
+
315
+                $propValue = $props[self::GROUPS_PROPERTYNAME];
316
+                $groupIds = explode('|', $propValue);
317
+                $this->tagManager->setTagGroups($tag, $groupIds);
318
+            }
319
+
320
+            if ($updateTag) {
321
+                $node->update($name, $userVisible, $userAssignable);
322
+            }
323
+
324
+            return true;
325
+        });
326
+
327
+    }
328 328
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -135,7 +135,7 @@  discard block
 block discarded – undo
135 135
 			if ($node instanceof SystemTagsObjectMappingCollection) {
136 136
 				// also add to collection
137 137
 				$node->createFile($tag->getId());
138
-				$url = $request->getBaseUrl() . 'systemtags/';
138
+				$url = $request->getBaseUrl().'systemtags/';
139 139
 			} else {
140 140
 				$url = $request->getUrl();
141 141
 			}
@@ -144,7 +144,7 @@  discard block
 block discarded – undo
144 144
 				$url .= '/';
145 145
 			}
146 146
 
147
-			$response->setHeader('Content-Location', $url . $tag->getId());
147
+			$response->setHeader('Content-Location', $url.$tag->getId());
148 148
 
149 149
 			// created
150 150
 			$response->setStatus(201);
@@ -179,11 +179,11 @@  discard block
 block discarded – undo
179 179
 		$userAssignable = true;
180 180
 
181 181
 		if (isset($data['userVisible'])) {
182
-			$userVisible = (bool)$data['userVisible'];
182
+			$userVisible = (bool) $data['userVisible'];
183 183
 		}
184 184
 
185 185
 		if (isset($data['userAssignable'])) {
186
-			$userAssignable = (bool)$data['userAssignable'];
186
+			$userAssignable = (bool) $data['userAssignable'];
187 187
 		}
188 188
 
189 189
 		$groups = [];
@@ -194,8 +194,8 @@  discard block
 block discarded – undo
194 194
 			}
195 195
 		}
196 196
 
197
-		if($userVisible === false || $userAssignable === false || !empty($groups)) {
198
-			if(!$this->userSession->isLoggedIn() || !$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) {
197
+		if ($userVisible === false || $userAssignable === false || !empty($groups)) {
198
+			if (!$this->userSession->isLoggedIn() || !$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) {
199 199
 				throw new BadRequest('Not sufficient permissions');
200 200
 			}
201 201
 		}
Please login to merge, or discard this patch.
apps/dav/lib/SystemTag/SystemTagsByIdCollection.php 3 patches
Unused Use Statements   -2 removed lines patch added patch discarded remove patch
@@ -26,13 +26,11 @@
 block discarded – undo
26 26
 use Sabre\DAV\Exception\NotFound;
27 27
 use Sabre\DAV\Exception\BadRequest;
28 28
 use Sabre\DAV\ICollection;
29
-
30 29
 use OCP\SystemTag\ISystemTagManager;
31 30
 use OCP\SystemTag\ISystemTag;
32 31
 use OCP\SystemTag\TagNotFoundException;
33 32
 use OCP\IGroupManager;
34 33
 use OCP\IUserSession;
35
-use OC\User\NoUserException;
36 34
 
37 35
 class SystemTagsByIdCollection implements ICollection {
38 36
 
Please login to merge, or discard this patch.
Indentation   +140 added lines, -140 removed lines patch added patch discarded remove patch
@@ -37,144 +37,144 @@
 block discarded – undo
37 37
 
38 38
 class SystemTagsByIdCollection implements ICollection {
39 39
 
40
-	/**
41
-	 * @var ISystemTagManager
42
-	 */
43
-	private $tagManager;
44
-
45
-	/**
46
-	 * @var IGroupManager
47
-	 */
48
-	private $groupManager;
49
-
50
-	/**
51
-	 * @var IUserSession
52
-	 */
53
-	private $userSession;
54
-
55
-	/**
56
-	 * SystemTagsByIdCollection constructor.
57
-	 *
58
-	 * @param ISystemTagManager $tagManager
59
-	 * @param IUserSession $userSession
60
-	 * @param IGroupManager $groupManager
61
-	 */
62
-	public function __construct(
63
-		ISystemTagManager $tagManager,
64
-		IUserSession $userSession,
65
-		IGroupManager $groupManager
66
-	) {
67
-		$this->tagManager = $tagManager;
68
-		$this->userSession = $userSession;
69
-		$this->groupManager = $groupManager;
70
-	}
71
-
72
-	/**
73
-	 * Returns whether the currently logged in user is an administrator
74
-	 *
75
-	 * @return bool true if the user is an admin
76
-	 */
77
-	private function isAdmin() {
78
-		$user = $this->userSession->getUser();
79
-		if ($user !== null) {
80
-			return $this->groupManager->isAdmin($user->getUID());
81
-		}
82
-		return false;
83
-	}
84
-
85
-	/**
86
-	 * @param string $name
87
-	 * @param resource|string $data Initial payload
88
-	 * @throws Forbidden
89
-	 */
90
-	function createFile($name, $data = null) {
91
-		throw new Forbidden('Cannot create tags by id');
92
-	}
93
-
94
-	/**
95
-	 * @param string $name
96
-	 */
97
-	function createDirectory($name) {
98
-		throw new Forbidden('Permission denied to create collections');
99
-	}
100
-
101
-	/**
102
-	 * @param string $name
103
-	 */
104
-	function getChild($name) {
105
-		try {
106
-			$tag = $this->tagManager->getTagsByIds([$name]);
107
-			$tag = current($tag);
108
-			if (!$this->tagManager->canUserSeeTag($tag, $this->userSession->getUser())) {
109
-				throw new NotFound('Tag with id ' . $name . ' not found');
110
-			}
111
-			return $this->makeNode($tag);
112
-		} catch (\InvalidArgumentException $e) {
113
-			throw new BadRequest('Invalid tag id', 0, $e);
114
-		} catch (TagNotFoundException $e) {
115
-			throw new NotFound('Tag with id ' . $name . ' not found', 0, $e);
116
-		}
117
-	}
118
-
119
-	function getChildren() {
120
-		$visibilityFilter = true;
121
-		if ($this->isAdmin()) {
122
-			$visibilityFilter = null;
123
-		}
124
-
125
-		$tags = $this->tagManager->getAllTags($visibilityFilter);
126
-		return array_map(function($tag) {
127
-			return $this->makeNode($tag);
128
-		}, $tags);
129
-	}
130
-
131
-	/**
132
-	 * @param string $name
133
-	 */
134
-	function childExists($name) {
135
-		try {
136
-			$tag = $this->tagManager->getTagsByIds([$name]);
137
-			$tag = current($tag);
138
-			if (!$this->tagManager->canUserSeeTag($tag, $this->userSession->getUser())) {
139
-				return false;
140
-			}
141
-			return true;
142
-		} catch (\InvalidArgumentException $e) {
143
-			throw new BadRequest('Invalid tag id', 0, $e);
144
-		} catch (TagNotFoundException $e) {
145
-			return false;
146
-		}
147
-	}
148
-
149
-	function delete() {
150
-		throw new Forbidden('Permission denied to delete this collection');
151
-	}
152
-
153
-	function getName() {
154
-		return 'systemtags';
155
-	}
156
-
157
-	function setName($name) {
158
-		throw new Forbidden('Permission denied to rename this collection');
159
-	}
160
-
161
-	/**
162
-	 * Returns the last modification time, as a unix timestamp
163
-	 *
164
-	 * @return int
165
-	 */
166
-	function getLastModified() {
167
-		return null;
168
-	}
169
-
170
-	/**
171
-	 * Create a sabre node for the given system tag
172
-	 *
173
-	 * @param ISystemTag $tag
174
-	 *
175
-	 * @return SystemTagNode
176
-	 */
177
-	private function makeNode(ISystemTag $tag) {
178
-		return new SystemTagNode($tag, $this->userSession->getUser(), $this->isAdmin(), $this->tagManager);
179
-	}
40
+    /**
41
+     * @var ISystemTagManager
42
+     */
43
+    private $tagManager;
44
+
45
+    /**
46
+     * @var IGroupManager
47
+     */
48
+    private $groupManager;
49
+
50
+    /**
51
+     * @var IUserSession
52
+     */
53
+    private $userSession;
54
+
55
+    /**
56
+     * SystemTagsByIdCollection constructor.
57
+     *
58
+     * @param ISystemTagManager $tagManager
59
+     * @param IUserSession $userSession
60
+     * @param IGroupManager $groupManager
61
+     */
62
+    public function __construct(
63
+        ISystemTagManager $tagManager,
64
+        IUserSession $userSession,
65
+        IGroupManager $groupManager
66
+    ) {
67
+        $this->tagManager = $tagManager;
68
+        $this->userSession = $userSession;
69
+        $this->groupManager = $groupManager;
70
+    }
71
+
72
+    /**
73
+     * Returns whether the currently logged in user is an administrator
74
+     *
75
+     * @return bool true if the user is an admin
76
+     */
77
+    private function isAdmin() {
78
+        $user = $this->userSession->getUser();
79
+        if ($user !== null) {
80
+            return $this->groupManager->isAdmin($user->getUID());
81
+        }
82
+        return false;
83
+    }
84
+
85
+    /**
86
+     * @param string $name
87
+     * @param resource|string $data Initial payload
88
+     * @throws Forbidden
89
+     */
90
+    function createFile($name, $data = null) {
91
+        throw new Forbidden('Cannot create tags by id');
92
+    }
93
+
94
+    /**
95
+     * @param string $name
96
+     */
97
+    function createDirectory($name) {
98
+        throw new Forbidden('Permission denied to create collections');
99
+    }
100
+
101
+    /**
102
+     * @param string $name
103
+     */
104
+    function getChild($name) {
105
+        try {
106
+            $tag = $this->tagManager->getTagsByIds([$name]);
107
+            $tag = current($tag);
108
+            if (!$this->tagManager->canUserSeeTag($tag, $this->userSession->getUser())) {
109
+                throw new NotFound('Tag with id ' . $name . ' not found');
110
+            }
111
+            return $this->makeNode($tag);
112
+        } catch (\InvalidArgumentException $e) {
113
+            throw new BadRequest('Invalid tag id', 0, $e);
114
+        } catch (TagNotFoundException $e) {
115
+            throw new NotFound('Tag with id ' . $name . ' not found', 0, $e);
116
+        }
117
+    }
118
+
119
+    function getChildren() {
120
+        $visibilityFilter = true;
121
+        if ($this->isAdmin()) {
122
+            $visibilityFilter = null;
123
+        }
124
+
125
+        $tags = $this->tagManager->getAllTags($visibilityFilter);
126
+        return array_map(function($tag) {
127
+            return $this->makeNode($tag);
128
+        }, $tags);
129
+    }
130
+
131
+    /**
132
+     * @param string $name
133
+     */
134
+    function childExists($name) {
135
+        try {
136
+            $tag = $this->tagManager->getTagsByIds([$name]);
137
+            $tag = current($tag);
138
+            if (!$this->tagManager->canUserSeeTag($tag, $this->userSession->getUser())) {
139
+                return false;
140
+            }
141
+            return true;
142
+        } catch (\InvalidArgumentException $e) {
143
+            throw new BadRequest('Invalid tag id', 0, $e);
144
+        } catch (TagNotFoundException $e) {
145
+            return false;
146
+        }
147
+    }
148
+
149
+    function delete() {
150
+        throw new Forbidden('Permission denied to delete this collection');
151
+    }
152
+
153
+    function getName() {
154
+        return 'systemtags';
155
+    }
156
+
157
+    function setName($name) {
158
+        throw new Forbidden('Permission denied to rename this collection');
159
+    }
160
+
161
+    /**
162
+     * Returns the last modification time, as a unix timestamp
163
+     *
164
+     * @return int
165
+     */
166
+    function getLastModified() {
167
+        return null;
168
+    }
169
+
170
+    /**
171
+     * Create a sabre node for the given system tag
172
+     *
173
+     * @param ISystemTag $tag
174
+     *
175
+     * @return SystemTagNode
176
+     */
177
+    private function makeNode(ISystemTag $tag) {
178
+        return new SystemTagNode($tag, $this->userSession->getUser(), $this->isAdmin(), $this->tagManager);
179
+    }
180 180
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -106,13 +106,13 @@
 block discarded – undo
106 106
 			$tag = $this->tagManager->getTagsByIds([$name]);
107 107
 			$tag = current($tag);
108 108
 			if (!$this->tagManager->canUserSeeTag($tag, $this->userSession->getUser())) {
109
-				throw new NotFound('Tag with id ' . $name . ' not found');
109
+				throw new NotFound('Tag with id '.$name.' not found');
110 110
 			}
111 111
 			return $this->makeNode($tag);
112 112
 		} catch (\InvalidArgumentException $e) {
113 113
 			throw new BadRequest('Invalid tag id', 0, $e);
114 114
 		} catch (TagNotFoundException $e) {
115
-			throw new NotFound('Tag with id ' . $name . ' not found', 0, $e);
115
+			throw new NotFound('Tag with id '.$name.' not found', 0, $e);
116 116
 		}
117 117
 	}
118 118
 
Please login to merge, or discard this patch.
apps/dav/lib/SystemTag/SystemTagsObjectMappingCollection.php 4 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -26,7 +26,6 @@
 block discarded – undo
26 26
 use Sabre\DAV\Exception\BadRequest;
27 27
 use Sabre\DAV\Exception\PreconditionFailed;
28 28
 use Sabre\DAV\ICollection;
29
-
30 29
 use OCP\SystemTag\ISystemTagManager;
31 30
 use OCP\SystemTag\ISystemTagObjectMapper;
32 31
 use OCP\SystemTag\ISystemTag;
Please login to merge, or discard this patch.
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -89,6 +89,9 @@
 block discarded – undo
89 89
 		$this->user = $user;
90 90
 	}
91 91
 
92
+	/**
93
+	 * @param string $tagId
94
+	 */
92 95
 	function createFile($tagId, $data = null) {
93 96
 		try {
94 97
 			$tags = $this->tagManager->getTagsByIds([$tagId]);
Please login to merge, or discard this patch.
Indentation   +165 added lines, -165 removed lines patch added patch discarded remove patch
@@ -39,169 +39,169 @@
 block discarded – undo
39 39
  */
40 40
 class SystemTagsObjectMappingCollection implements ICollection {
41 41
 
42
-	/**
43
-	 * @var string
44
-	 */
45
-	private $objectId;
46
-
47
-	/**
48
-	 * @var string
49
-	 */
50
-	private $objectType;
51
-
52
-	/**
53
-	 * @var ISystemTagManager
54
-	 */
55
-	private $tagManager;
56
-
57
-	/**
58
-	 * @var ISystemTagObjectMapper
59
-	 */
60
-	private $tagMapper;
61
-
62
-	/**
63
-	 * User
64
-	 *
65
-	 * @var IUser
66
-	 */
67
-	private $user;
68
-
69
-
70
-	/**
71
-	 * Constructor
72
-	 *
73
-	 * @param string $objectId object id
74
-	 * @param string $objectType object type
75
-	 * @param IUser $user user
76
-	 * @param ISystemTagManager $tagManager tag manager
77
-	 * @param ISystemTagObjectMapper $tagMapper tag mapper
78
-	 */
79
-	public function __construct(
80
-		$objectId,
81
-		$objectType,
82
-		IUser $user,
83
-		ISystemTagManager $tagManager,
84
-		ISystemTagObjectMapper $tagMapper
85
-	) {
86
-		$this->tagManager = $tagManager;
87
-		$this->tagMapper = $tagMapper;
88
-		$this->objectId = $objectId;
89
-		$this->objectType = $objectType;
90
-		$this->user = $user;
91
-	}
92
-
93
-	function createFile($tagId, $data = null) {
94
-		try {
95
-			$tags = $this->tagManager->getTagsByIds([$tagId]);
96
-			$tag = current($tags);
97
-			if (!$this->tagManager->canUserSeeTag($tag, $this->user)) {
98
-				throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
99
-			}
100
-			if (!$this->tagManager->canUserAssignTag($tag, $this->user)) {
101
-				throw new Forbidden('No permission to assign tag ' . $tagId);
102
-			}
103
-
104
-			$this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId);
105
-		} catch (TagNotFoundException $e) {
106
-			throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
107
-		}
108
-	}
109
-
110
-	function createDirectory($name) {
111
-		throw new Forbidden('Permission denied to create collections');
112
-	}
113
-
114
-	function getChild($tagId) {
115
-		try {
116
-			if ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)) {
117
-				$tag = $this->tagManager->getTagsByIds([$tagId]);
118
-				$tag = current($tag);
119
-				if ($this->tagManager->canUserSeeTag($tag, $this->user)) {
120
-					return $this->makeNode($tag);
121
-				}
122
-			}
123
-			throw new NotFound('Tag with id ' . $tagId . ' not present for object ' . $this->objectId);
124
-		} catch (\InvalidArgumentException $e) {
125
-			throw new BadRequest('Invalid tag id', 0, $e);
126
-		} catch (TagNotFoundException $e) {
127
-			throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e);
128
-		}
129
-	}
130
-
131
-	function getChildren() {
132
-		$tagIds = current($this->tagMapper->getTagIdsForObjects([$this->objectId], $this->objectType));
133
-		if (empty($tagIds)) {
134
-			return [];
135
-		}
136
-		$tags = $this->tagManager->getTagsByIds($tagIds);
137
-
138
-		// filter out non-visible tags
139
-		$tags = array_filter($tags, function($tag) {
140
-			return $this->tagManager->canUserSeeTag($tag, $this->user);
141
-		});
142
-
143
-		return array_values(array_map(function($tag) {
144
-			return $this->makeNode($tag);
145
-		}, $tags));
146
-	}
147
-
148
-	function childExists($tagId) {
149
-		try {
150
-			$result = ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true));
151
-
152
-			if ($result) {
153
-				$tags = $this->tagManager->getTagsByIds([$tagId]);
154
-				$tag = current($tags);
155
-				if (!$this->tagManager->canUserSeeTag($tag, $this->user)) {
156
-					return false;
157
-				}
158
-			}
159
-
160
-			return $result;
161
-		} catch (\InvalidArgumentException $e) {
162
-			throw new BadRequest('Invalid tag id', 0, $e);
163
-		} catch (TagNotFoundException $e) {
164
-			return false;
165
-		}
166
-	}
167
-
168
-	function delete() {
169
-		throw new Forbidden('Permission denied to delete this collection');
170
-	}
171
-
172
-	function getName() {
173
-		return $this->objectId;
174
-	}
175
-
176
-	function setName($name) {
177
-		throw new Forbidden('Permission denied to rename this collection');
178
-	}
179
-
180
-	/**
181
-	 * Returns the last modification time, as a unix timestamp
182
-	 *
183
-	 * @return int
184
-	 */
185
-	function getLastModified() {
186
-		return null;
187
-	}
188
-
189
-	/**
190
-	 * Create a sabre node for the mapping of the 
191
-	 * given system tag to the collection's object
192
-	 *
193
-	 * @param ISystemTag $tag
194
-	 *
195
-	 * @return SystemTagMappingNode
196
-	 */
197
-	private function makeNode(ISystemTag $tag) {
198
-		return new SystemTagMappingNode(
199
-			$tag,
200
-			$this->objectId,
201
-			$this->objectType,
202
-			$this->user,
203
-			$this->tagManager,
204
-			$this->tagMapper
205
-		);
206
-	}
42
+    /**
43
+     * @var string
44
+     */
45
+    private $objectId;
46
+
47
+    /**
48
+     * @var string
49
+     */
50
+    private $objectType;
51
+
52
+    /**
53
+     * @var ISystemTagManager
54
+     */
55
+    private $tagManager;
56
+
57
+    /**
58
+     * @var ISystemTagObjectMapper
59
+     */
60
+    private $tagMapper;
61
+
62
+    /**
63
+     * User
64
+     *
65
+     * @var IUser
66
+     */
67
+    private $user;
68
+
69
+
70
+    /**
71
+     * Constructor
72
+     *
73
+     * @param string $objectId object id
74
+     * @param string $objectType object type
75
+     * @param IUser $user user
76
+     * @param ISystemTagManager $tagManager tag manager
77
+     * @param ISystemTagObjectMapper $tagMapper tag mapper
78
+     */
79
+    public function __construct(
80
+        $objectId,
81
+        $objectType,
82
+        IUser $user,
83
+        ISystemTagManager $tagManager,
84
+        ISystemTagObjectMapper $tagMapper
85
+    ) {
86
+        $this->tagManager = $tagManager;
87
+        $this->tagMapper = $tagMapper;
88
+        $this->objectId = $objectId;
89
+        $this->objectType = $objectType;
90
+        $this->user = $user;
91
+    }
92
+
93
+    function createFile($tagId, $data = null) {
94
+        try {
95
+            $tags = $this->tagManager->getTagsByIds([$tagId]);
96
+            $tag = current($tags);
97
+            if (!$this->tagManager->canUserSeeTag($tag, $this->user)) {
98
+                throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
99
+            }
100
+            if (!$this->tagManager->canUserAssignTag($tag, $this->user)) {
101
+                throw new Forbidden('No permission to assign tag ' . $tagId);
102
+            }
103
+
104
+            $this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId);
105
+        } catch (TagNotFoundException $e) {
106
+            throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
107
+        }
108
+    }
109
+
110
+    function createDirectory($name) {
111
+        throw new Forbidden('Permission denied to create collections');
112
+    }
113
+
114
+    function getChild($tagId) {
115
+        try {
116
+            if ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)) {
117
+                $tag = $this->tagManager->getTagsByIds([$tagId]);
118
+                $tag = current($tag);
119
+                if ($this->tagManager->canUserSeeTag($tag, $this->user)) {
120
+                    return $this->makeNode($tag);
121
+                }
122
+            }
123
+            throw new NotFound('Tag with id ' . $tagId . ' not present for object ' . $this->objectId);
124
+        } catch (\InvalidArgumentException $e) {
125
+            throw new BadRequest('Invalid tag id', 0, $e);
126
+        } catch (TagNotFoundException $e) {
127
+            throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e);
128
+        }
129
+    }
130
+
131
+    function getChildren() {
132
+        $tagIds = current($this->tagMapper->getTagIdsForObjects([$this->objectId], $this->objectType));
133
+        if (empty($tagIds)) {
134
+            return [];
135
+        }
136
+        $tags = $this->tagManager->getTagsByIds($tagIds);
137
+
138
+        // filter out non-visible tags
139
+        $tags = array_filter($tags, function($tag) {
140
+            return $this->tagManager->canUserSeeTag($tag, $this->user);
141
+        });
142
+
143
+        return array_values(array_map(function($tag) {
144
+            return $this->makeNode($tag);
145
+        }, $tags));
146
+    }
147
+
148
+    function childExists($tagId) {
149
+        try {
150
+            $result = ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true));
151
+
152
+            if ($result) {
153
+                $tags = $this->tagManager->getTagsByIds([$tagId]);
154
+                $tag = current($tags);
155
+                if (!$this->tagManager->canUserSeeTag($tag, $this->user)) {
156
+                    return false;
157
+                }
158
+            }
159
+
160
+            return $result;
161
+        } catch (\InvalidArgumentException $e) {
162
+            throw new BadRequest('Invalid tag id', 0, $e);
163
+        } catch (TagNotFoundException $e) {
164
+            return false;
165
+        }
166
+    }
167
+
168
+    function delete() {
169
+        throw new Forbidden('Permission denied to delete this collection');
170
+    }
171
+
172
+    function getName() {
173
+        return $this->objectId;
174
+    }
175
+
176
+    function setName($name) {
177
+        throw new Forbidden('Permission denied to rename this collection');
178
+    }
179
+
180
+    /**
181
+     * Returns the last modification time, as a unix timestamp
182
+     *
183
+     * @return int
184
+     */
185
+    function getLastModified() {
186
+        return null;
187
+    }
188
+
189
+    /**
190
+     * Create a sabre node for the mapping of the 
191
+     * given system tag to the collection's object
192
+     *
193
+     * @param ISystemTag $tag
194
+     *
195
+     * @return SystemTagMappingNode
196
+     */
197
+    private function makeNode(ISystemTag $tag) {
198
+        return new SystemTagMappingNode(
199
+            $tag,
200
+            $this->objectId,
201
+            $this->objectType,
202
+            $this->user,
203
+            $this->tagManager,
204
+            $this->tagMapper
205
+        );
206
+    }
207 207
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -95,15 +95,15 @@  discard block
 block discarded – undo
95 95
 			$tags = $this->tagManager->getTagsByIds([$tagId]);
96 96
 			$tag = current($tags);
97 97
 			if (!$this->tagManager->canUserSeeTag($tag, $this->user)) {
98
-				throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
98
+				throw new PreconditionFailed('Tag with id '.$tagId.' does not exist, cannot assign');
99 99
 			}
100 100
 			if (!$this->tagManager->canUserAssignTag($tag, $this->user)) {
101
-				throw new Forbidden('No permission to assign tag ' . $tagId);
101
+				throw new Forbidden('No permission to assign tag '.$tagId);
102 102
 			}
103 103
 
104 104
 			$this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId);
105 105
 		} catch (TagNotFoundException $e) {
106
-			throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
106
+			throw new PreconditionFailed('Tag with id '.$tagId.' does not exist, cannot assign');
107 107
 		}
108 108
 	}
109 109
 
@@ -120,11 +120,11 @@  discard block
 block discarded – undo
120 120
 					return $this->makeNode($tag);
121 121
 				}
122 122
 			}
123
-			throw new NotFound('Tag with id ' . $tagId . ' not present for object ' . $this->objectId);
123
+			throw new NotFound('Tag with id '.$tagId.' not present for object '.$this->objectId);
124 124
 		} catch (\InvalidArgumentException $e) {
125 125
 			throw new BadRequest('Invalid tag id', 0, $e);
126 126
 		} catch (TagNotFoundException $e) {
127
-			throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e);
127
+			throw new NotFound('Tag with id '.$tagId.' not found', 0, $e);
128 128
 		}
129 129
 	}
130 130
 
Please login to merge, or discard this patch.
apps/dav/lib/SystemTag/SystemTagsObjectTypeCollection.php 3 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -26,7 +26,6 @@
 block discarded – undo
26 26
 use Sabre\DAV\Exception\MethodNotAllowed;
27 27
 use Sabre\DAV\Exception\NotFound;
28 28
 use Sabre\DAV\ICollection;
29
-
30 29
 use OCP\SystemTag\ISystemTagManager;
31 30
 use OCP\SystemTag\ISystemTagObjectMapper;
32 31
 use OCP\IUserSession;
Please login to merge, or discard this patch.
Indentation   +132 added lines, -132 removed lines patch added patch discarded remove patch
@@ -39,136 +39,136 @@
 block discarded – undo
39 39
  */
40 40
 class SystemTagsObjectTypeCollection implements ICollection {
41 41
 
42
-	/**
43
-	 * @var string
44
-	 */
45
-	private $objectType;
46
-
47
-	/**
48
-	 * @var ISystemTagManager
49
-	 */
50
-	private $tagManager;
51
-
52
-	/**
53
-	 * @var ISystemTagObjectMapper
54
-	 */
55
-	private $tagMapper;
56
-
57
-	/**
58
-	 * @var IGroupManager
59
-	 */
60
-	private $groupManager;
61
-
62
-	/**
63
-	 * @var IUserSession
64
-	 */
65
-	private $userSession;
66
-
67
-	/**
68
-	 * @var \Closure
69
-	 **/
70
-	protected $childExistsFunction;
71
-
72
-	/**
73
-	 * Constructor
74
-	 *
75
-	 * @param string $objectType object type
76
-	 * @param ISystemTagManager $tagManager
77
-	 * @param ISystemTagObjectMapper $tagMapper
78
-	 * @param IUserSession $userSession
79
-	 * @param IGroupManager $groupManager
80
-	 * @param \Closure $childExistsFunction
81
-	 */
82
-	public function __construct(
83
-		$objectType, 
84
-		ISystemTagManager $tagManager,
85
-		ISystemTagObjectMapper $tagMapper,
86
-		IUserSession $userSession,
87
-		IGroupManager $groupManager,
88
-		\Closure $childExistsFunction
89
-	) {
90
-		$this->tagManager = $tagManager;
91
-		$this->tagMapper = $tagMapper;
92
-		$this->objectType = $objectType;
93
-		$this->userSession = $userSession;
94
-		$this->groupManager = $groupManager;
95
-		$this->childExistsFunction = $childExistsFunction;
96
-	}
97
-
98
-	/**
99
-	 * @param string $name
100
-	 * @param resource|string $data Initial payload
101
-	 * @return null|string
102
-	 * @throws Forbidden
103
-	 */
104
-	function createFile($name, $data = null) {
105
-		throw new Forbidden('Permission denied to create nodes');
106
-	}
107
-
108
-	/**
109
-	 * @param string $name
110
-	 * @throws Forbidden
111
-	 */
112
-	function createDirectory($name) {
113
-		throw new Forbidden('Permission denied to create collections');
114
-	}
115
-
116
-	/**
117
-	 * @param string $objectId
118
-	 * @return SystemTagsObjectMappingCollection
119
-	 * @throws NotFound
120
-	 */
121
-	function getChild($objectId) {
122
-		// make sure the object exists and is reachable
123
-		if(!$this->childExists($objectId)) {
124
-			throw new NotFound('Entity does not exist or is not available');
125
-		}
126
-		return new SystemTagsObjectMappingCollection(
127
-			$objectId,
128
-			$this->objectType,
129
-			$this->userSession->getUser(),
130
-			$this->tagManager,
131
-			$this->tagMapper
132
-		);
133
-	}
134
-
135
-	function getChildren() {
136
-		// do not list object ids
137
-		throw new MethodNotAllowed();
138
-	}
139
-
140
-	/**
141
-	 * Checks if a child-node with the specified name exists
142
-	 *
143
-	 * @param string $name
144
-	 * @return bool
145
-	 */
146
-	function childExists($name) {
147
-		return call_user_func($this->childExistsFunction, $name);
148
-	}
149
-
150
-	function delete() {
151
-		throw new Forbidden('Permission denied to delete this collection');
152
-	}
153
-
154
-	function getName() {
155
-		return $this->objectType;
156
-	}
157
-
158
-	/**
159
-	 * @param string $name
160
-	 * @throws Forbidden
161
-	 */
162
-	function setName($name) {
163
-		throw new Forbidden('Permission denied to rename this collection');
164
-	}
165
-
166
-	/**
167
-	 * Returns the last modification time, as a unix timestamp
168
-	 *
169
-	 * @return int
170
-	 */
171
-	function getLastModified() {
172
-		return null;
173
-	}
42
+    /**
43
+     * @var string
44
+     */
45
+    private $objectType;
46
+
47
+    /**
48
+     * @var ISystemTagManager
49
+     */
50
+    private $tagManager;
51
+
52
+    /**
53
+     * @var ISystemTagObjectMapper
54
+     */
55
+    private $tagMapper;
56
+
57
+    /**
58
+     * @var IGroupManager
59
+     */
60
+    private $groupManager;
61
+
62
+    /**
63
+     * @var IUserSession
64
+     */
65
+    private $userSession;
66
+
67
+    /**
68
+     * @var \Closure
69
+     **/
70
+    protected $childExistsFunction;
71
+
72
+    /**
73
+     * Constructor
74
+     *
75
+     * @param string $objectType object type
76
+     * @param ISystemTagManager $tagManager
77
+     * @param ISystemTagObjectMapper $tagMapper
78
+     * @param IUserSession $userSession
79
+     * @param IGroupManager $groupManager
80
+     * @param \Closure $childExistsFunction
81
+     */
82
+    public function __construct(
83
+        $objectType, 
84
+        ISystemTagManager $tagManager,
85
+        ISystemTagObjectMapper $tagMapper,
86
+        IUserSession $userSession,
87
+        IGroupManager $groupManager,
88
+        \Closure $childExistsFunction
89
+    ) {
90
+        $this->tagManager = $tagManager;
91
+        $this->tagMapper = $tagMapper;
92
+        $this->objectType = $objectType;
93
+        $this->userSession = $userSession;
94
+        $this->groupManager = $groupManager;
95
+        $this->childExistsFunction = $childExistsFunction;
96
+    }
97
+
98
+    /**
99
+     * @param string $name
100
+     * @param resource|string $data Initial payload
101
+     * @return null|string
102
+     * @throws Forbidden
103
+     */
104
+    function createFile($name, $data = null) {
105
+        throw new Forbidden('Permission denied to create nodes');
106
+    }
107
+
108
+    /**
109
+     * @param string $name
110
+     * @throws Forbidden
111
+     */
112
+    function createDirectory($name) {
113
+        throw new Forbidden('Permission denied to create collections');
114
+    }
115
+
116
+    /**
117
+     * @param string $objectId
118
+     * @return SystemTagsObjectMappingCollection
119
+     * @throws NotFound
120
+     */
121
+    function getChild($objectId) {
122
+        // make sure the object exists and is reachable
123
+        if(!$this->childExists($objectId)) {
124
+            throw new NotFound('Entity does not exist or is not available');
125
+        }
126
+        return new SystemTagsObjectMappingCollection(
127
+            $objectId,
128
+            $this->objectType,
129
+            $this->userSession->getUser(),
130
+            $this->tagManager,
131
+            $this->tagMapper
132
+        );
133
+    }
134
+
135
+    function getChildren() {
136
+        // do not list object ids
137
+        throw new MethodNotAllowed();
138
+    }
139
+
140
+    /**
141
+     * Checks if a child-node with the specified name exists
142
+     *
143
+     * @param string $name
144
+     * @return bool
145
+     */
146
+    function childExists($name) {
147
+        return call_user_func($this->childExistsFunction, $name);
148
+    }
149
+
150
+    function delete() {
151
+        throw new Forbidden('Permission denied to delete this collection');
152
+    }
153
+
154
+    function getName() {
155
+        return $this->objectType;
156
+    }
157
+
158
+    /**
159
+     * @param string $name
160
+     * @throws Forbidden
161
+     */
162
+    function setName($name) {
163
+        throw new Forbidden('Permission denied to rename this collection');
164
+    }
165
+
166
+    /**
167
+     * Returns the last modification time, as a unix timestamp
168
+     *
169
+     * @return int
170
+     */
171
+    function getLastModified() {
172
+        return null;
173
+    }
174 174
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -120,7 +120,7 @@
 block discarded – undo
120 120
 	 */
121 121
 	function getChild($objectId) {
122 122
 		// make sure the object exists and is reachable
123
-		if(!$this->childExists($objectId)) {
123
+		if (!$this->childExists($objectId)) {
124 124
 			throw new NotFound('Entity does not exist or is not available');
125 125
 		}
126 126
 		return new SystemTagsObjectMappingCollection(
Please login to merge, or discard this patch.
apps/dav/lib/Upload/AssemblyStream.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -118,7 +118,7 @@  discard block
 block discarded – undo
118 118
 
119 119
 	/**
120 120
 	 * @param string $data
121
-	 * @return int
121
+	 * @return boolean
122 122
 	 */
123 123
 	public function stream_write($data) {
124 124
 		return false;
@@ -224,7 +224,7 @@  discard block
 block discarded – undo
224 224
 	}
225 225
 
226 226
 	/**
227
-	 * @param $pos
227
+	 * @param integer $pos
228 228
 	 * @return IFile | null
229 229
 	 */
230 230
 	private function getNodeForPosition($pos) {
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -74,7 +74,7 @@  discard block
 block discarded – undo
74 74
 		// build additional information
75 75
 		$this->sortedNodes = [];
76 76
 		$start = 0;
77
-		foreach($this->nodes as $node) {
77
+		foreach ($this->nodes as $node) {
78 78
 			$size = $node->getSize();
79 79
 			$name = $node->getName();
80 80
 			$this->sortedNodes[$name] = ['node' => $node, 'start' => $start, 'end' => $start + $size];
@@ -216,7 +216,7 @@  discard block
 block discarded – undo
216 216
 		if (isset($context[$name])) {
217 217
 			$context = $context[$name];
218 218
 		} else {
219
-			throw new \BadMethodCallException('Invalid context, "' . $name . '" options not set');
219
+			throw new \BadMethodCallException('Invalid context, "'.$name.'" options not set');
220 220
 		}
221 221
 		if (isset($context['nodes']) and is_array($context['nodes'])) {
222 222
 			$this->nodes = $context['nodes'];
@@ -253,7 +253,7 @@  discard block
 block discarded – undo
253 253
 	 * @return IFile | null
254 254
 	 */
255 255
 	private function getNodeForPosition($pos) {
256
-		foreach($this->sortedNodes as $node) {
256
+		foreach ($this->sortedNodes as $node) {
257 257
 			if ($pos >= $node['start'] && $pos < $node['end']) {
258 258
 				return [$node['node'], $pos - $node['start']];
259 259
 			}
@@ -271,7 +271,7 @@  discard block
 block discarded – undo
271 271
 			return $data;
272 272
 		}
273 273
 
274
-		return fopen('data://text/plain,' . $data,'r');
274
+		return fopen('data://text/plain,'.$data, 'r');
275 275
 	}
276 276
 
277 277
 }
Please login to merge, or discard this patch.
Indentation   +238 added lines, -238 removed lines patch added patch discarded remove patch
@@ -35,243 +35,243 @@
 block discarded – undo
35 35
  */
36 36
 class AssemblyStream implements \Icewind\Streams\File {
37 37
 
38
-	/** @var resource */
39
-	private $context;
40
-
41
-	/** @var IFile[] */
42
-	private $nodes;
43
-
44
-	/** @var int */
45
-	private $pos = 0;
46
-
47
-	/** @var array */
48
-	private $sortedNodes;
49
-
50
-	/** @var int */
51
-	private $size;
52
-
53
-	/** @var resource */
54
-	private $currentStream = null;
55
-
56
-	/**
57
-	 * @param string $path
58
-	 * @param string $mode
59
-	 * @param int $options
60
-	 * @param string &$opened_path
61
-	 * @return bool
62
-	 */
63
-	public function stream_open($path, $mode, $options, &$opened_path) {
64
-		$this->loadContext('assembly');
65
-
66
-		// sort the nodes
67
-		$nodes = $this->nodes;
68
-		// http://stackoverflow.com/a/10985500
69
-		@usort($nodes, function(IFile $a, IFile $b) {
70
-			return strnatcmp($a->getName(), $b->getName());
71
-		});
72
-		$this->nodes = $nodes;
73
-
74
-		// build additional information
75
-		$this->sortedNodes = [];
76
-		$start = 0;
77
-		foreach($this->nodes as $node) {
78
-			$size = $node->getSize();
79
-			$name = $node->getName();
80
-			$this->sortedNodes[$name] = ['node' => $node, 'start' => $start, 'end' => $start + $size];
81
-			$start += $size;
82
-			$this->size = $start;
83
-		}
84
-		return true;
85
-	}
86
-
87
-	/**
88
-	 * @param string $offset
89
-	 * @param int $whence
90
-	 * @return bool
91
-	 */
92
-	public function stream_seek($offset, $whence = SEEK_SET) {
93
-		return false;
94
-	}
95
-
96
-	/**
97
-	 * @return int
98
-	 */
99
-	public function stream_tell() {
100
-		return $this->pos;
101
-	}
102
-
103
-	/**
104
-	 * @param int $count
105
-	 * @return string
106
-	 */
107
-	public function stream_read($count) {
108
-		do {
109
-			if ($this->currentStream === null) {
110
-				list($node, $posInNode) = $this->getNodeForPosition($this->pos);
111
-				if (is_null($node)) {
112
-					// reached last node, no more data
113
-					return '';
114
-				}
115
-				$this->currentStream = $this->getStream($node);
116
-				fseek($this->currentStream, $posInNode);
117
-			}
118
-
119
-			$data = fread($this->currentStream, $count);
120
-			// isset is faster than strlen
121
-			if (isset($data[$count - 1])) {
122
-				// we read the full count
123
-				$read = $count;
124
-			} else {
125
-				// reaching end of stream, which happens less often so strlen is ok
126
-				$read = strlen($data);
127
-			}
128
-
129
-			if (feof($this->currentStream)) {
130
-				fclose($this->currentStream);
131
-				$this->currentNode = null;
132
-				$this->currentStream = null;
133
-			}
134
-			// if no data read, try again with the next node because
135
-			// returning empty data can make the caller think there is no more
136
-			// data left to read
137
-		} while ($read === 0);
138
-
139
-		// update position
140
-		$this->pos += $read;
141
-		return $data;
142
-	}
143
-
144
-	/**
145
-	 * @param string $data
146
-	 * @return int
147
-	 */
148
-	public function stream_write($data) {
149
-		return false;
150
-	}
151
-
152
-	/**
153
-	 * @param int $option
154
-	 * @param int $arg1
155
-	 * @param int $arg2
156
-	 * @return bool
157
-	 */
158
-	public function stream_set_option($option, $arg1, $arg2) {
159
-		return false;
160
-	}
161
-
162
-	/**
163
-	 * @param int $size
164
-	 * @return bool
165
-	 */
166
-	public function stream_truncate($size) {
167
-		return false;
168
-	}
169
-
170
-	/**
171
-	 * @return array
172
-	 */
173
-	public function stream_stat() {
174
-		return [];
175
-	}
176
-
177
-	/**
178
-	 * @param int $operation
179
-	 * @return bool
180
-	 */
181
-	public function stream_lock($operation) {
182
-		return false;
183
-	}
184
-
185
-	/**
186
-	 * @return bool
187
-	 */
188
-	public function stream_flush() {
189
-		return false;
190
-	}
191
-
192
-	/**
193
-	 * @return bool
194
-	 */
195
-	public function stream_eof() {
196
-		return $this->pos >= $this->size;
197
-	}
198
-
199
-	/**
200
-	 * @return bool
201
-	 */
202
-	public function stream_close() {
203
-		return true;
204
-	}
205
-
206
-
207
-	/**
208
-	 * Load the source from the stream context and return the context options
209
-	 *
210
-	 * @param string $name
211
-	 * @return array
212
-	 * @throws \Exception
213
-	 */
214
-	protected function loadContext($name) {
215
-		$context = stream_context_get_options($this->context);
216
-		if (isset($context[$name])) {
217
-			$context = $context[$name];
218
-		} else {
219
-			throw new \BadMethodCallException('Invalid context, "' . $name . '" options not set');
220
-		}
221
-		if (isset($context['nodes']) and is_array($context['nodes'])) {
222
-			$this->nodes = $context['nodes'];
223
-		} else {
224
-			throw new \BadMethodCallException('Invalid context, nodes not set');
225
-		}
226
-		return $context;
227
-	}
228
-
229
-	/**
230
-	 * @param IFile[] $nodes
231
-	 * @return resource
232
-	 *
233
-	 * @throws \BadMethodCallException
234
-	 */
235
-	public static function wrap(array $nodes) {
236
-		$context = stream_context_create([
237
-			'assembly' => [
238
-				'nodes' => $nodes]
239
-		]);
240
-		stream_wrapper_register('assembly', '\OCA\DAV\Upload\AssemblyStream');
241
-		try {
242
-			$wrapped = fopen('assembly://', 'r', null, $context);
243
-		} catch (\BadMethodCallException $e) {
244
-			stream_wrapper_unregister('assembly');
245
-			throw $e;
246
-		}
247
-		stream_wrapper_unregister('assembly');
248
-		return $wrapped;
249
-	}
250
-
251
-	/**
252
-	 * @param $pos
253
-	 * @return IFile | null
254
-	 */
255
-	private function getNodeForPosition($pos) {
256
-		foreach($this->sortedNodes as $node) {
257
-			if ($pos >= $node['start'] && $pos < $node['end']) {
258
-				return [$node['node'], $pos - $node['start']];
259
-			}
260
-		}
261
-		return null;
262
-	}
263
-
264
-	/**
265
-	 * @param IFile $node
266
-	 * @return resource
267
-	 */
268
-	private function getStream(IFile $node) {
269
-		$data = $node->get();
270
-		if (is_resource($data)) {
271
-			return $data;
272
-		}
273
-
274
-		return fopen('data://text/plain,' . $data,'r');
275
-	}
38
+    /** @var resource */
39
+    private $context;
40
+
41
+    /** @var IFile[] */
42
+    private $nodes;
43
+
44
+    /** @var int */
45
+    private $pos = 0;
46
+
47
+    /** @var array */
48
+    private $sortedNodes;
49
+
50
+    /** @var int */
51
+    private $size;
52
+
53
+    /** @var resource */
54
+    private $currentStream = null;
55
+
56
+    /**
57
+     * @param string $path
58
+     * @param string $mode
59
+     * @param int $options
60
+     * @param string &$opened_path
61
+     * @return bool
62
+     */
63
+    public function stream_open($path, $mode, $options, &$opened_path) {
64
+        $this->loadContext('assembly');
65
+
66
+        // sort the nodes
67
+        $nodes = $this->nodes;
68
+        // http://stackoverflow.com/a/10985500
69
+        @usort($nodes, function(IFile $a, IFile $b) {
70
+            return strnatcmp($a->getName(), $b->getName());
71
+        });
72
+        $this->nodes = $nodes;
73
+
74
+        // build additional information
75
+        $this->sortedNodes = [];
76
+        $start = 0;
77
+        foreach($this->nodes as $node) {
78
+            $size = $node->getSize();
79
+            $name = $node->getName();
80
+            $this->sortedNodes[$name] = ['node' => $node, 'start' => $start, 'end' => $start + $size];
81
+            $start += $size;
82
+            $this->size = $start;
83
+        }
84
+        return true;
85
+    }
86
+
87
+    /**
88
+     * @param string $offset
89
+     * @param int $whence
90
+     * @return bool
91
+     */
92
+    public function stream_seek($offset, $whence = SEEK_SET) {
93
+        return false;
94
+    }
95
+
96
+    /**
97
+     * @return int
98
+     */
99
+    public function stream_tell() {
100
+        return $this->pos;
101
+    }
102
+
103
+    /**
104
+     * @param int $count
105
+     * @return string
106
+     */
107
+    public function stream_read($count) {
108
+        do {
109
+            if ($this->currentStream === null) {
110
+                list($node, $posInNode) = $this->getNodeForPosition($this->pos);
111
+                if (is_null($node)) {
112
+                    // reached last node, no more data
113
+                    return '';
114
+                }
115
+                $this->currentStream = $this->getStream($node);
116
+                fseek($this->currentStream, $posInNode);
117
+            }
118
+
119
+            $data = fread($this->currentStream, $count);
120
+            // isset is faster than strlen
121
+            if (isset($data[$count - 1])) {
122
+                // we read the full count
123
+                $read = $count;
124
+            } else {
125
+                // reaching end of stream, which happens less often so strlen is ok
126
+                $read = strlen($data);
127
+            }
128
+
129
+            if (feof($this->currentStream)) {
130
+                fclose($this->currentStream);
131
+                $this->currentNode = null;
132
+                $this->currentStream = null;
133
+            }
134
+            // if no data read, try again with the next node because
135
+            // returning empty data can make the caller think there is no more
136
+            // data left to read
137
+        } while ($read === 0);
138
+
139
+        // update position
140
+        $this->pos += $read;
141
+        return $data;
142
+    }
143
+
144
+    /**
145
+     * @param string $data
146
+     * @return int
147
+     */
148
+    public function stream_write($data) {
149
+        return false;
150
+    }
151
+
152
+    /**
153
+     * @param int $option
154
+     * @param int $arg1
155
+     * @param int $arg2
156
+     * @return bool
157
+     */
158
+    public function stream_set_option($option, $arg1, $arg2) {
159
+        return false;
160
+    }
161
+
162
+    /**
163
+     * @param int $size
164
+     * @return bool
165
+     */
166
+    public function stream_truncate($size) {
167
+        return false;
168
+    }
169
+
170
+    /**
171
+     * @return array
172
+     */
173
+    public function stream_stat() {
174
+        return [];
175
+    }
176
+
177
+    /**
178
+     * @param int $operation
179
+     * @return bool
180
+     */
181
+    public function stream_lock($operation) {
182
+        return false;
183
+    }
184
+
185
+    /**
186
+     * @return bool
187
+     */
188
+    public function stream_flush() {
189
+        return false;
190
+    }
191
+
192
+    /**
193
+     * @return bool
194
+     */
195
+    public function stream_eof() {
196
+        return $this->pos >= $this->size;
197
+    }
198
+
199
+    /**
200
+     * @return bool
201
+     */
202
+    public function stream_close() {
203
+        return true;
204
+    }
205
+
206
+
207
+    /**
208
+     * Load the source from the stream context and return the context options
209
+     *
210
+     * @param string $name
211
+     * @return array
212
+     * @throws \Exception
213
+     */
214
+    protected function loadContext($name) {
215
+        $context = stream_context_get_options($this->context);
216
+        if (isset($context[$name])) {
217
+            $context = $context[$name];
218
+        } else {
219
+            throw new \BadMethodCallException('Invalid context, "' . $name . '" options not set');
220
+        }
221
+        if (isset($context['nodes']) and is_array($context['nodes'])) {
222
+            $this->nodes = $context['nodes'];
223
+        } else {
224
+            throw new \BadMethodCallException('Invalid context, nodes not set');
225
+        }
226
+        return $context;
227
+    }
228
+
229
+    /**
230
+     * @param IFile[] $nodes
231
+     * @return resource
232
+     *
233
+     * @throws \BadMethodCallException
234
+     */
235
+    public static function wrap(array $nodes) {
236
+        $context = stream_context_create([
237
+            'assembly' => [
238
+                'nodes' => $nodes]
239
+        ]);
240
+        stream_wrapper_register('assembly', '\OCA\DAV\Upload\AssemblyStream');
241
+        try {
242
+            $wrapped = fopen('assembly://', 'r', null, $context);
243
+        } catch (\BadMethodCallException $e) {
244
+            stream_wrapper_unregister('assembly');
245
+            throw $e;
246
+        }
247
+        stream_wrapper_unregister('assembly');
248
+        return $wrapped;
249
+    }
250
+
251
+    /**
252
+     * @param $pos
253
+     * @return IFile | null
254
+     */
255
+    private function getNodeForPosition($pos) {
256
+        foreach($this->sortedNodes as $node) {
257
+            if ($pos >= $node['start'] && $pos < $node['end']) {
258
+                return [$node['node'], $pos - $node['start']];
259
+            }
260
+        }
261
+        return null;
262
+    }
263
+
264
+    /**
265
+     * @param IFile $node
266
+     * @return resource
267
+     */
268
+    private function getStream(IFile $node) {
269
+        $data = $node->get();
270
+        if (is_resource($data)) {
271
+            return $data;
272
+        }
273
+
274
+        return fopen('data://text/plain,' . $data,'r');
275
+    }
276 276
 
277 277
 }
Please login to merge, or discard this patch.
apps/encryption/lib/Crypto/Encryption.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -369,7 +369,7 @@
 block discarded – undo
369 369
 	 * @param string $path path to the file which should be updated
370 370
 	 * @param string $uid of the user who performs the operation
371 371
 	 * @param array $accessList who has access to the file contains the key 'users' and 'public'
372
-	 * @return boolean
372
+	 * @return null|boolean
373 373
 	 */
374 374
 	public function update($path, $uid, array $accessList) {
375 375
 
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -177,7 +177,7 @@  discard block
 block discarded – undo
177 177
 		$this->isWriteOperation = false;
178 178
 		$this->writeCache = '';
179 179
 
180
-		if($this->session->isReady() === false) {
180
+		if ($this->session->isReady() === false) {
181 181
 			// if the master key is enabled we can initialize encryption
182 182
 			// with a empty password and user name
183 183
 			if ($this->util->isMasterKeyEnabled()) {
@@ -198,7 +198,7 @@  discard block
 block discarded – undo
198 198
 		// always use the version from the original file, also part files
199 199
 		// need to have a correct version number if they get moved over to the
200 200
 		// final location
201
-		$this->version = (int)$this->keyManager->getVersion($this->stripPartFileExtension($path), new View());
201
+		$this->version = (int) $this->keyManager->getVersion($this->stripPartFileExtension($path), new View());
202 202
 
203 203
 		if (
204 204
 			$mode === 'w'
@@ -214,7 +214,7 @@  discard block
 block discarded – undo
214 214
 			// if we read a part file we need to increase the version by 1
215 215
 			// because the version number was also increased by writing
216 216
 			// the part file
217
-			if(Scanner::isPartialFile($path)) {
217
+			if (Scanner::isPartialFile($path)) {
218 218
 				$this->version = $this->version + 1;
219 219
 			}
220 220
 		}
@@ -300,7 +300,7 @@  discard block
 block discarded – undo
300 300
 		if ($this->writeCache) {
301 301
 
302 302
 			// Concat writeCache to start of $data
303
-			$data = $this->writeCache . $data;
303
+			$data = $this->writeCache.$data;
304 304
 
305 305
 			// Clear the write cache, ready for reuse - it has been
306 306
 			// flushed and its old contents processed
@@ -402,7 +402,7 @@  discard block
 block discarded – undo
402 402
 					try {
403 403
 						$publicKeys[$user] = $this->keyManager->getPublicKey($user);
404 404
 					} catch (PublicKeyMissingException $e) {
405
-						$this->logger->warning('Could not encrypt file for ' . $user . ': ' . $e->getMessage());
405
+						$this->logger->warning('Could not encrypt file for '.$user.': '.$e->getMessage());
406 406
 					}
407 407
 				}
408 408
 			}
@@ -489,8 +489,8 @@  discard block
 block discarded – undo
489 489
 				// error message because in this case it means that the file was
490 490
 				// shared with the user at a point where the user didn't had a
491 491
 				// valid private/public key
492
-				$msg = 'Encryption module "' . $this->getDisplayName() .
493
-					'" is not able to read ' . $path;
492
+				$msg = 'Encryption module "'.$this->getDisplayName().
493
+					'" is not able to read '.$path;
494 494
 				$hint = $this->l->t('Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
495 495
 				$this->logger->warning($msg);
496 496
 				throw new DecryptionFailedException($msg, $hint);
@@ -532,7 +532,7 @@  discard block
 block discarded – undo
532 532
 		$realPath = $path;
533 533
 		$parts = explode('/', $path);
534 534
 		if ($parts[2] === 'files_versions') {
535
-			$realPath = '/' . $parts[1] . '/files/' . implode('/', array_slice($parts, 3));
535
+			$realPath = '/'.$parts[1].'/files/'.implode('/', array_slice($parts, 3));
536 536
 			$length = strrpos($realPath, '.');
537 537
 			$realPath = substr($realPath, 0, $length);
538 538
 		}
Please login to merge, or discard this patch.
Indentation   +526 added lines, -526 removed lines patch added patch discarded remove patch
@@ -43,530 +43,530 @@
 block discarded – undo
43 43
 
44 44
 class Encryption implements IEncryptionModule {
45 45
 
46
-	const ID = 'OC_DEFAULT_MODULE';
47
-	const DISPLAY_NAME = 'Default encryption module';
48
-
49
-	/**
50
-	 * @var Crypt
51
-	 */
52
-	private $crypt;
53
-
54
-	/** @var string */
55
-	private $cipher;
56
-
57
-	/** @var string */
58
-	private $path;
59
-
60
-	/** @var string */
61
-	private $user;
62
-
63
-	/** @var string */
64
-	private $fileKey;
65
-
66
-	/** @var string */
67
-	private $writeCache;
68
-
69
-	/** @var KeyManager */
70
-	private $keyManager;
71
-
72
-	/** @var array */
73
-	private $accessList;
74
-
75
-	/** @var boolean */
76
-	private $isWriteOperation;
77
-
78
-	/** @var Util */
79
-	private $util;
80
-
81
-	/** @var  Session */
82
-	private $session;
83
-
84
-	/** @var  ILogger */
85
-	private $logger;
86
-
87
-	/** @var IL10N */
88
-	private $l;
89
-
90
-	/** @var EncryptAll */
91
-	private $encryptAll;
92
-
93
-	/** @var  bool */
94
-	private $useMasterPassword;
95
-
96
-	/** @var DecryptAll  */
97
-	private $decryptAll;
98
-
99
-	/** @var int unencrypted block size if block contains signature */
100
-	private $unencryptedBlockSizeSigned = 6072;
101
-
102
-	/** @var int unencrypted block size */
103
-	private $unencryptedBlockSize = 6126;
104
-
105
-	/** @var int Current version of the file */
106
-	private $version = 0;
107
-
108
-	/** @var array remember encryption signature version */
109
-	private static $rememberVersion = [];
110
-
111
-
112
-	/**
113
-	 *
114
-	 * @param Crypt $crypt
115
-	 * @param KeyManager $keyManager
116
-	 * @param Util $util
117
-	 * @param Session $session
118
-	 * @param EncryptAll $encryptAll
119
-	 * @param DecryptAll $decryptAll
120
-	 * @param ILogger $logger
121
-	 * @param IL10N $il10n
122
-	 */
123
-	public function __construct(Crypt $crypt,
124
-								KeyManager $keyManager,
125
-								Util $util,
126
-								Session $session,
127
-								EncryptAll $encryptAll,
128
-								DecryptAll $decryptAll,
129
-								ILogger $logger,
130
-								IL10N $il10n) {
131
-		$this->crypt = $crypt;
132
-		$this->keyManager = $keyManager;
133
-		$this->util = $util;
134
-		$this->session = $session;
135
-		$this->encryptAll = $encryptAll;
136
-		$this->decryptAll = $decryptAll;
137
-		$this->logger = $logger;
138
-		$this->l = $il10n;
139
-		$this->useMasterPassword = $util->isMasterKeyEnabled();
140
-	}
141
-
142
-	/**
143
-	 * @return string defining the technical unique id
144
-	 */
145
-	public function getId() {
146
-		return self::ID;
147
-	}
148
-
149
-	/**
150
-	 * In comparison to getKey() this function returns a human readable (maybe translated) name
151
-	 *
152
-	 * @return string
153
-	 */
154
-	public function getDisplayName() {
155
-		return self::DISPLAY_NAME;
156
-	}
157
-
158
-	/**
159
-	 * start receiving chunks from a file. This is the place where you can
160
-	 * perform some initial step before starting encrypting/decrypting the
161
-	 * chunks
162
-	 *
163
-	 * @param string $path to the file
164
-	 * @param string $user who read/write the file
165
-	 * @param string $mode php stream open mode
166
-	 * @param array $header contains the header data read from the file
167
-	 * @param array $accessList who has access to the file contains the key 'users' and 'public'
168
-	 *
169
-	 * @return array $header contain data as key-value pairs which should be
170
-	 *                       written to the header, in case of a write operation
171
-	 *                       or if no additional data is needed return a empty array
172
-	 */
173
-	public function begin($path, $user, $mode, array $header, array $accessList) {
174
-		$this->path = $this->getPathToRealFile($path);
175
-		$this->accessList = $accessList;
176
-		$this->user = $user;
177
-		$this->isWriteOperation = false;
178
-		$this->writeCache = '';
179
-
180
-		if($this->session->isReady() === false) {
181
-			// if the master key is enabled we can initialize encryption
182
-			// with a empty password and user name
183
-			if ($this->util->isMasterKeyEnabled()) {
184
-				$this->keyManager->init('', '');
185
-			}
186
-		}
187
-
188
-		if ($this->session->decryptAllModeActivated()) {
189
-			$encryptedFileKey = $this->keyManager->getEncryptedFileKey($this->path);
190
-			$shareKey = $this->keyManager->getShareKey($this->path, $this->session->getDecryptAllUid());
191
-			$this->fileKey = $this->crypt->multiKeyDecrypt($encryptedFileKey,
192
-				$shareKey,
193
-				$this->session->getDecryptAllKey());
194
-		} else {
195
-			$this->fileKey = $this->keyManager->getFileKey($this->path, $this->user);
196
-		}
197
-
198
-		// always use the version from the original file, also part files
199
-		// need to have a correct version number if they get moved over to the
200
-		// final location
201
-		$this->version = (int)$this->keyManager->getVersion($this->stripPartFileExtension($path), new View());
202
-
203
-		if (
204
-			$mode === 'w'
205
-			|| $mode === 'w+'
206
-			|| $mode === 'wb'
207
-			|| $mode === 'wb+'
208
-		) {
209
-			$this->isWriteOperation = true;
210
-			if (empty($this->fileKey)) {
211
-				$this->fileKey = $this->crypt->generateFileKey();
212
-			}
213
-		} else {
214
-			// if we read a part file we need to increase the version by 1
215
-			// because the version number was also increased by writing
216
-			// the part file
217
-			if(Scanner::isPartialFile($path)) {
218
-				$this->version = $this->version + 1;
219
-			}
220
-		}
221
-
222
-		if ($this->isWriteOperation) {
223
-			$this->cipher = $this->crypt->getCipher();
224
-		} elseif (isset($header['cipher'])) {
225
-			$this->cipher = $header['cipher'];
226
-		} else {
227
-			// if we read a file without a header we fall-back to the legacy cipher
228
-			// which was used in <=oC6
229
-			$this->cipher = $this->crypt->getLegacyCipher();
230
-		}
231
-
232
-		return array('cipher' => $this->cipher, 'signed' => 'true');
233
-	}
234
-
235
-	/**
236
-	 * last chunk received. This is the place where you can perform some final
237
-	 * operation and return some remaining data if something is left in your
238
-	 * buffer.
239
-	 *
240
-	 * @param string $path to the file
241
-	 * @param int $position
242
-	 * @return string remained data which should be written to the file in case
243
-	 *                of a write operation
244
-	 * @throws PublicKeyMissingException
245
-	 * @throws \Exception
246
-	 * @throws \OCA\Encryption\Exceptions\MultiKeyEncryptException
247
-	 */
248
-	public function end($path, $position = 0) {
249
-		$result = '';
250
-		if ($this->isWriteOperation) {
251
-			$this->keyManager->setVersion($path, $this->version + 1, new View());
252
-			// in case of a part file we remember the new signature versions
253
-			// the version will be set later on update.
254
-			// This way we make sure that other apps listening to the pre-hooks
255
-			// still get the old version which should be the correct value for them
256
-			if (Scanner::isPartialFile($path)) {
257
-				self::$rememberVersion[$this->stripPartFileExtension($path)] = $this->version + 1;
258
-			}
259
-			if (!empty($this->writeCache)) {
260
-				$result = $this->crypt->symmetricEncryptFileContent($this->writeCache, $this->fileKey, $this->version + 1, $position);
261
-				$this->writeCache = '';
262
-			}
263
-			$publicKeys = array();
264
-			if ($this->useMasterPassword === true) {
265
-				$publicKeys[$this->keyManager->getMasterKeyId()] = $this->keyManager->getPublicMasterKey();
266
-			} else {
267
-				foreach ($this->accessList['users'] as $uid) {
268
-					try {
269
-						$publicKeys[$uid] = $this->keyManager->getPublicKey($uid);
270
-					} catch (PublicKeyMissingException $e) {
271
-						$this->logger->warning(
272
-							'no public key found for user "{uid}", user will not be able to read the file',
273
-							['app' => 'encryption', 'uid' => $uid]
274
-						);
275
-						// if the public key of the owner is missing we should fail
276
-						if ($uid === $this->user) {
277
-							throw $e;
278
-						}
279
-					}
280
-				}
281
-			}
282
-
283
-			$publicKeys = $this->keyManager->addSystemKeys($this->accessList, $publicKeys, $this->user);
284
-			$encryptedKeyfiles = $this->crypt->multiKeyEncrypt($this->fileKey, $publicKeys);
285
-			$this->keyManager->setAllFileKeys($this->path, $encryptedKeyfiles);
286
-		}
287
-		return $result;
288
-	}
289
-
290
-	/**
291
-	 * encrypt data
292
-	 *
293
-	 * @param string $data you want to encrypt
294
-	 * @param int $position
295
-	 * @return string encrypted data
296
-	 */
297
-	public function encrypt($data, $position = 0) {
298
-		// If extra data is left over from the last round, make sure it
299
-		// is integrated into the next block
300
-		if ($this->writeCache) {
301
-
302
-			// Concat writeCache to start of $data
303
-			$data = $this->writeCache . $data;
304
-
305
-			// Clear the write cache, ready for reuse - it has been
306
-			// flushed and its old contents processed
307
-			$this->writeCache = '';
308
-
309
-		}
310
-
311
-		$encrypted = '';
312
-		// While there still remains some data to be processed & written
313
-		while (strlen($data) > 0) {
314
-
315
-			// Remaining length for this iteration, not of the
316
-			// entire file (may be greater than 8192 bytes)
317
-			$remainingLength = strlen($data);
318
-
319
-			// If data remaining to be written is less than the
320
-			// size of 1 6126 byte block
321
-			if ($remainingLength < $this->unencryptedBlockSizeSigned) {
322
-
323
-				// Set writeCache to contents of $data
324
-				// The writeCache will be carried over to the
325
-				// next write round, and added to the start of
326
-				// $data to ensure that written blocks are
327
-				// always the correct length. If there is still
328
-				// data in writeCache after the writing round
329
-				// has finished, then the data will be written
330
-				// to disk by $this->flush().
331
-				$this->writeCache = $data;
332
-
333
-				// Clear $data ready for next round
334
-				$data = '';
335
-
336
-			} else {
337
-
338
-				// Read the chunk from the start of $data
339
-				$chunk = substr($data, 0, $this->unencryptedBlockSizeSigned);
340
-
341
-				$encrypted .= $this->crypt->symmetricEncryptFileContent($chunk, $this->fileKey, $this->version + 1, $position);
342
-
343
-				// Remove the chunk we just processed from
344
-				// $data, leaving only unprocessed data in $data
345
-				// var, for handling on the next round
346
-				$data = substr($data, $this->unencryptedBlockSizeSigned);
347
-
348
-			}
349
-
350
-		}
351
-
352
-		return $encrypted;
353
-	}
354
-
355
-	/**
356
-	 * decrypt data
357
-	 *
358
-	 * @param string $data you want to decrypt
359
-	 * @param int $position
360
-	 * @return string decrypted data
361
-	 * @throws DecryptionFailedException
362
-	 */
363
-	public function decrypt($data, $position = 0) {
364
-		if (empty($this->fileKey)) {
365
-			$msg = 'Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.';
366
-			$hint = $this->l->t('Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
367
-			$this->logger->error($msg);
368
-
369
-			throw new DecryptionFailedException($msg, $hint);
370
-		}
371
-
372
-		return $this->crypt->symmetricDecryptFileContent($data, $this->fileKey, $this->cipher, $this->version, $position);
373
-	}
374
-
375
-	/**
376
-	 * update encrypted file, e.g. give additional users access to the file
377
-	 *
378
-	 * @param string $path path to the file which should be updated
379
-	 * @param string $uid of the user who performs the operation
380
-	 * @param array $accessList who has access to the file contains the key 'users' and 'public'
381
-	 * @return boolean
382
-	 */
383
-	public function update($path, $uid, array $accessList) {
384
-
385
-		if (empty($accessList)) {
386
-			if (isset(self::$rememberVersion[$path])) {
387
-				$this->keyManager->setVersion($path, self::$rememberVersion[$path], new View());
388
-				unset(self::$rememberVersion[$path]);
389
-			}
390
-			return;
391
-		}
392
-
393
-		$fileKey = $this->keyManager->getFileKey($path, $uid);
394
-
395
-		if (!empty($fileKey)) {
396
-
397
-			$publicKeys = array();
398
-			if ($this->useMasterPassword === true) {
399
-				$publicKeys[$this->keyManager->getMasterKeyId()] = $this->keyManager->getPublicMasterKey();
400
-			} else {
401
-				foreach ($accessList['users'] as $user) {
402
-					try {
403
-						$publicKeys[$user] = $this->keyManager->getPublicKey($user);
404
-					} catch (PublicKeyMissingException $e) {
405
-						$this->logger->warning('Could not encrypt file for ' . $user . ': ' . $e->getMessage());
406
-					}
407
-				}
408
-			}
409
-
410
-			$publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $uid);
411
-
412
-			$encryptedFileKey = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
413
-
414
-			$this->keyManager->deleteAllFileKeys($path);
415
-
416
-			$this->keyManager->setAllFileKeys($path, $encryptedFileKey);
417
-
418
-		} else {
419
-			$this->logger->debug('no file key found, we assume that the file "{file}" is not encrypted',
420
-				array('file' => $path, 'app' => 'encryption'));
421
-
422
-			return false;
423
-		}
424
-
425
-		return true;
426
-	}
427
-
428
-	/**
429
-	 * should the file be encrypted or not
430
-	 *
431
-	 * @param string $path
432
-	 * @return boolean
433
-	 */
434
-	public function shouldEncrypt($path) {
435
-		if ($this->util->shouldEncryptHomeStorage() === false) {
436
-			$storage = $this->util->getStorage($path);
437
-			if ($storage->instanceOfStorage('\OCP\Files\IHomeStorage')) {
438
-				return false;
439
-			}
440
-		}
441
-		$parts = explode('/', $path);
442
-		if (count($parts) < 4) {
443
-			return false;
444
-		}
445
-
446
-		if ($parts[2] == 'files') {
447
-			return true;
448
-		}
449
-		if ($parts[2] == 'files_versions') {
450
-			return true;
451
-		}
452
-		if ($parts[2] == 'files_trashbin') {
453
-			return true;
454
-		}
455
-
456
-		return false;
457
-	}
458
-
459
-	/**
460
-	 * get size of the unencrypted payload per block.
461
-	 * Nextcloud read/write files with a block size of 8192 byte
462
-	 *
463
-	 * @param bool $signed
464
-	 * @return int
465
-	 */
466
-	public function getUnencryptedBlockSize($signed = false) {
467
-		if ($signed === false) {
468
-			return $this->unencryptedBlockSize;
469
-		}
470
-
471
-		return $this->unencryptedBlockSizeSigned;
472
-	}
473
-
474
-	/**
475
-	 * check if the encryption module is able to read the file,
476
-	 * e.g. if all encryption keys exists
477
-	 *
478
-	 * @param string $path
479
-	 * @param string $uid user for whom we want to check if he can read the file
480
-	 * @return bool
481
-	 * @throws DecryptionFailedException
482
-	 */
483
-	public function isReadable($path, $uid) {
484
-		$fileKey = $this->keyManager->getFileKey($path, $uid);
485
-		if (empty($fileKey)) {
486
-			$owner = $this->util->getOwner($path);
487
-			if ($owner !== $uid) {
488
-				// if it is a shared file we throw a exception with a useful
489
-				// error message because in this case it means that the file was
490
-				// shared with the user at a point where the user didn't had a
491
-				// valid private/public key
492
-				$msg = 'Encryption module "' . $this->getDisplayName() .
493
-					'" is not able to read ' . $path;
494
-				$hint = $this->l->t('Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
495
-				$this->logger->warning($msg);
496
-				throw new DecryptionFailedException($msg, $hint);
497
-			}
498
-			return false;
499
-		}
500
-
501
-		return true;
502
-	}
503
-
504
-	/**
505
-	 * Initial encryption of all files
506
-	 *
507
-	 * @param InputInterface $input
508
-	 * @param OutputInterface $output write some status information to the terminal during encryption
509
-	 */
510
-	public function encryptAll(InputInterface $input, OutputInterface $output) {
511
-		$this->encryptAll->encryptAll($input, $output);
512
-	}
513
-
514
-	/**
515
-	 * prepare module to perform decrypt all operation
516
-	 *
517
-	 * @param InputInterface $input
518
-	 * @param OutputInterface $output
519
-	 * @param string $user
520
-	 * @return bool
521
-	 */
522
-	public function prepareDecryptAll(InputInterface $input, OutputInterface $output, $user = '') {
523
-		return $this->decryptAll->prepare($input, $output, $user);
524
-	}
525
-
526
-
527
-	/**
528
-	 * @param string $path
529
-	 * @return string
530
-	 */
531
-	protected function getPathToRealFile($path) {
532
-		$realPath = $path;
533
-		$parts = explode('/', $path);
534
-		if ($parts[2] === 'files_versions') {
535
-			$realPath = '/' . $parts[1] . '/files/' . implode('/', array_slice($parts, 3));
536
-			$length = strrpos($realPath, '.');
537
-			$realPath = substr($realPath, 0, $length);
538
-		}
539
-
540
-		return $realPath;
541
-	}
542
-
543
-	/**
544
-	 * remove .part file extension and the ocTransferId from the file to get the
545
-	 * original file name
546
-	 *
547
-	 * @param string $path
548
-	 * @return string
549
-	 */
550
-	protected function stripPartFileExtension($path) {
551
-		if (pathinfo($path, PATHINFO_EXTENSION) === 'part') {
552
-			$pos = strrpos($path, '.', -6);
553
-			$path = substr($path, 0, $pos);
554
-		}
555
-
556
-		return $path;
557
-	}
558
-
559
-	/**
560
-	 * Check if the module is ready to be used by that specific user.
561
-	 * In case a module is not ready - because e.g. key pairs have not been generated
562
-	 * upon login this method can return false before any operation starts and might
563
-	 * cause issues during operations.
564
-	 *
565
-	 * @param string $user
566
-	 * @return boolean
567
-	 * @since 9.1.0
568
-	 */
569
-	public function isReadyForUser($user) {
570
-		return $this->keyManager->userHasKeys($user);
571
-	}
46
+    const ID = 'OC_DEFAULT_MODULE';
47
+    const DISPLAY_NAME = 'Default encryption module';
48
+
49
+    /**
50
+     * @var Crypt
51
+     */
52
+    private $crypt;
53
+
54
+    /** @var string */
55
+    private $cipher;
56
+
57
+    /** @var string */
58
+    private $path;
59
+
60
+    /** @var string */
61
+    private $user;
62
+
63
+    /** @var string */
64
+    private $fileKey;
65
+
66
+    /** @var string */
67
+    private $writeCache;
68
+
69
+    /** @var KeyManager */
70
+    private $keyManager;
71
+
72
+    /** @var array */
73
+    private $accessList;
74
+
75
+    /** @var boolean */
76
+    private $isWriteOperation;
77
+
78
+    /** @var Util */
79
+    private $util;
80
+
81
+    /** @var  Session */
82
+    private $session;
83
+
84
+    /** @var  ILogger */
85
+    private $logger;
86
+
87
+    /** @var IL10N */
88
+    private $l;
89
+
90
+    /** @var EncryptAll */
91
+    private $encryptAll;
92
+
93
+    /** @var  bool */
94
+    private $useMasterPassword;
95
+
96
+    /** @var DecryptAll  */
97
+    private $decryptAll;
98
+
99
+    /** @var int unencrypted block size if block contains signature */
100
+    private $unencryptedBlockSizeSigned = 6072;
101
+
102
+    /** @var int unencrypted block size */
103
+    private $unencryptedBlockSize = 6126;
104
+
105
+    /** @var int Current version of the file */
106
+    private $version = 0;
107
+
108
+    /** @var array remember encryption signature version */
109
+    private static $rememberVersion = [];
110
+
111
+
112
+    /**
113
+     *
114
+     * @param Crypt $crypt
115
+     * @param KeyManager $keyManager
116
+     * @param Util $util
117
+     * @param Session $session
118
+     * @param EncryptAll $encryptAll
119
+     * @param DecryptAll $decryptAll
120
+     * @param ILogger $logger
121
+     * @param IL10N $il10n
122
+     */
123
+    public function __construct(Crypt $crypt,
124
+                                KeyManager $keyManager,
125
+                                Util $util,
126
+                                Session $session,
127
+                                EncryptAll $encryptAll,
128
+                                DecryptAll $decryptAll,
129
+                                ILogger $logger,
130
+                                IL10N $il10n) {
131
+        $this->crypt = $crypt;
132
+        $this->keyManager = $keyManager;
133
+        $this->util = $util;
134
+        $this->session = $session;
135
+        $this->encryptAll = $encryptAll;
136
+        $this->decryptAll = $decryptAll;
137
+        $this->logger = $logger;
138
+        $this->l = $il10n;
139
+        $this->useMasterPassword = $util->isMasterKeyEnabled();
140
+    }
141
+
142
+    /**
143
+     * @return string defining the technical unique id
144
+     */
145
+    public function getId() {
146
+        return self::ID;
147
+    }
148
+
149
+    /**
150
+     * In comparison to getKey() this function returns a human readable (maybe translated) name
151
+     *
152
+     * @return string
153
+     */
154
+    public function getDisplayName() {
155
+        return self::DISPLAY_NAME;
156
+    }
157
+
158
+    /**
159
+     * start receiving chunks from a file. This is the place where you can
160
+     * perform some initial step before starting encrypting/decrypting the
161
+     * chunks
162
+     *
163
+     * @param string $path to the file
164
+     * @param string $user who read/write the file
165
+     * @param string $mode php stream open mode
166
+     * @param array $header contains the header data read from the file
167
+     * @param array $accessList who has access to the file contains the key 'users' and 'public'
168
+     *
169
+     * @return array $header contain data as key-value pairs which should be
170
+     *                       written to the header, in case of a write operation
171
+     *                       or if no additional data is needed return a empty array
172
+     */
173
+    public function begin($path, $user, $mode, array $header, array $accessList) {
174
+        $this->path = $this->getPathToRealFile($path);
175
+        $this->accessList = $accessList;
176
+        $this->user = $user;
177
+        $this->isWriteOperation = false;
178
+        $this->writeCache = '';
179
+
180
+        if($this->session->isReady() === false) {
181
+            // if the master key is enabled we can initialize encryption
182
+            // with a empty password and user name
183
+            if ($this->util->isMasterKeyEnabled()) {
184
+                $this->keyManager->init('', '');
185
+            }
186
+        }
187
+
188
+        if ($this->session->decryptAllModeActivated()) {
189
+            $encryptedFileKey = $this->keyManager->getEncryptedFileKey($this->path);
190
+            $shareKey = $this->keyManager->getShareKey($this->path, $this->session->getDecryptAllUid());
191
+            $this->fileKey = $this->crypt->multiKeyDecrypt($encryptedFileKey,
192
+                $shareKey,
193
+                $this->session->getDecryptAllKey());
194
+        } else {
195
+            $this->fileKey = $this->keyManager->getFileKey($this->path, $this->user);
196
+        }
197
+
198
+        // always use the version from the original file, also part files
199
+        // need to have a correct version number if they get moved over to the
200
+        // final location
201
+        $this->version = (int)$this->keyManager->getVersion($this->stripPartFileExtension($path), new View());
202
+
203
+        if (
204
+            $mode === 'w'
205
+            || $mode === 'w+'
206
+            || $mode === 'wb'
207
+            || $mode === 'wb+'
208
+        ) {
209
+            $this->isWriteOperation = true;
210
+            if (empty($this->fileKey)) {
211
+                $this->fileKey = $this->crypt->generateFileKey();
212
+            }
213
+        } else {
214
+            // if we read a part file we need to increase the version by 1
215
+            // because the version number was also increased by writing
216
+            // the part file
217
+            if(Scanner::isPartialFile($path)) {
218
+                $this->version = $this->version + 1;
219
+            }
220
+        }
221
+
222
+        if ($this->isWriteOperation) {
223
+            $this->cipher = $this->crypt->getCipher();
224
+        } elseif (isset($header['cipher'])) {
225
+            $this->cipher = $header['cipher'];
226
+        } else {
227
+            // if we read a file without a header we fall-back to the legacy cipher
228
+            // which was used in <=oC6
229
+            $this->cipher = $this->crypt->getLegacyCipher();
230
+        }
231
+
232
+        return array('cipher' => $this->cipher, 'signed' => 'true');
233
+    }
234
+
235
+    /**
236
+     * last chunk received. This is the place where you can perform some final
237
+     * operation and return some remaining data if something is left in your
238
+     * buffer.
239
+     *
240
+     * @param string $path to the file
241
+     * @param int $position
242
+     * @return string remained data which should be written to the file in case
243
+     *                of a write operation
244
+     * @throws PublicKeyMissingException
245
+     * @throws \Exception
246
+     * @throws \OCA\Encryption\Exceptions\MultiKeyEncryptException
247
+     */
248
+    public function end($path, $position = 0) {
249
+        $result = '';
250
+        if ($this->isWriteOperation) {
251
+            $this->keyManager->setVersion($path, $this->version + 1, new View());
252
+            // in case of a part file we remember the new signature versions
253
+            // the version will be set later on update.
254
+            // This way we make sure that other apps listening to the pre-hooks
255
+            // still get the old version which should be the correct value for them
256
+            if (Scanner::isPartialFile($path)) {
257
+                self::$rememberVersion[$this->stripPartFileExtension($path)] = $this->version + 1;
258
+            }
259
+            if (!empty($this->writeCache)) {
260
+                $result = $this->crypt->symmetricEncryptFileContent($this->writeCache, $this->fileKey, $this->version + 1, $position);
261
+                $this->writeCache = '';
262
+            }
263
+            $publicKeys = array();
264
+            if ($this->useMasterPassword === true) {
265
+                $publicKeys[$this->keyManager->getMasterKeyId()] = $this->keyManager->getPublicMasterKey();
266
+            } else {
267
+                foreach ($this->accessList['users'] as $uid) {
268
+                    try {
269
+                        $publicKeys[$uid] = $this->keyManager->getPublicKey($uid);
270
+                    } catch (PublicKeyMissingException $e) {
271
+                        $this->logger->warning(
272
+                            'no public key found for user "{uid}", user will not be able to read the file',
273
+                            ['app' => 'encryption', 'uid' => $uid]
274
+                        );
275
+                        // if the public key of the owner is missing we should fail
276
+                        if ($uid === $this->user) {
277
+                            throw $e;
278
+                        }
279
+                    }
280
+                }
281
+            }
282
+
283
+            $publicKeys = $this->keyManager->addSystemKeys($this->accessList, $publicKeys, $this->user);
284
+            $encryptedKeyfiles = $this->crypt->multiKeyEncrypt($this->fileKey, $publicKeys);
285
+            $this->keyManager->setAllFileKeys($this->path, $encryptedKeyfiles);
286
+        }
287
+        return $result;
288
+    }
289
+
290
+    /**
291
+     * encrypt data
292
+     *
293
+     * @param string $data you want to encrypt
294
+     * @param int $position
295
+     * @return string encrypted data
296
+     */
297
+    public function encrypt($data, $position = 0) {
298
+        // If extra data is left over from the last round, make sure it
299
+        // is integrated into the next block
300
+        if ($this->writeCache) {
301
+
302
+            // Concat writeCache to start of $data
303
+            $data = $this->writeCache . $data;
304
+
305
+            // Clear the write cache, ready for reuse - it has been
306
+            // flushed and its old contents processed
307
+            $this->writeCache = '';
308
+
309
+        }
310
+
311
+        $encrypted = '';
312
+        // While there still remains some data to be processed & written
313
+        while (strlen($data) > 0) {
314
+
315
+            // Remaining length for this iteration, not of the
316
+            // entire file (may be greater than 8192 bytes)
317
+            $remainingLength = strlen($data);
318
+
319
+            // If data remaining to be written is less than the
320
+            // size of 1 6126 byte block
321
+            if ($remainingLength < $this->unencryptedBlockSizeSigned) {
322
+
323
+                // Set writeCache to contents of $data
324
+                // The writeCache will be carried over to the
325
+                // next write round, and added to the start of
326
+                // $data to ensure that written blocks are
327
+                // always the correct length. If there is still
328
+                // data in writeCache after the writing round
329
+                // has finished, then the data will be written
330
+                // to disk by $this->flush().
331
+                $this->writeCache = $data;
332
+
333
+                // Clear $data ready for next round
334
+                $data = '';
335
+
336
+            } else {
337
+
338
+                // Read the chunk from the start of $data
339
+                $chunk = substr($data, 0, $this->unencryptedBlockSizeSigned);
340
+
341
+                $encrypted .= $this->crypt->symmetricEncryptFileContent($chunk, $this->fileKey, $this->version + 1, $position);
342
+
343
+                // Remove the chunk we just processed from
344
+                // $data, leaving only unprocessed data in $data
345
+                // var, for handling on the next round
346
+                $data = substr($data, $this->unencryptedBlockSizeSigned);
347
+
348
+            }
349
+
350
+        }
351
+
352
+        return $encrypted;
353
+    }
354
+
355
+    /**
356
+     * decrypt data
357
+     *
358
+     * @param string $data you want to decrypt
359
+     * @param int $position
360
+     * @return string decrypted data
361
+     * @throws DecryptionFailedException
362
+     */
363
+    public function decrypt($data, $position = 0) {
364
+        if (empty($this->fileKey)) {
365
+            $msg = 'Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.';
366
+            $hint = $this->l->t('Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
367
+            $this->logger->error($msg);
368
+
369
+            throw new DecryptionFailedException($msg, $hint);
370
+        }
371
+
372
+        return $this->crypt->symmetricDecryptFileContent($data, $this->fileKey, $this->cipher, $this->version, $position);
373
+    }
374
+
375
+    /**
376
+     * update encrypted file, e.g. give additional users access to the file
377
+     *
378
+     * @param string $path path to the file which should be updated
379
+     * @param string $uid of the user who performs the operation
380
+     * @param array $accessList who has access to the file contains the key 'users' and 'public'
381
+     * @return boolean
382
+     */
383
+    public function update($path, $uid, array $accessList) {
384
+
385
+        if (empty($accessList)) {
386
+            if (isset(self::$rememberVersion[$path])) {
387
+                $this->keyManager->setVersion($path, self::$rememberVersion[$path], new View());
388
+                unset(self::$rememberVersion[$path]);
389
+            }
390
+            return;
391
+        }
392
+
393
+        $fileKey = $this->keyManager->getFileKey($path, $uid);
394
+
395
+        if (!empty($fileKey)) {
396
+
397
+            $publicKeys = array();
398
+            if ($this->useMasterPassword === true) {
399
+                $publicKeys[$this->keyManager->getMasterKeyId()] = $this->keyManager->getPublicMasterKey();
400
+            } else {
401
+                foreach ($accessList['users'] as $user) {
402
+                    try {
403
+                        $publicKeys[$user] = $this->keyManager->getPublicKey($user);
404
+                    } catch (PublicKeyMissingException $e) {
405
+                        $this->logger->warning('Could not encrypt file for ' . $user . ': ' . $e->getMessage());
406
+                    }
407
+                }
408
+            }
409
+
410
+            $publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $uid);
411
+
412
+            $encryptedFileKey = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
413
+
414
+            $this->keyManager->deleteAllFileKeys($path);
415
+
416
+            $this->keyManager->setAllFileKeys($path, $encryptedFileKey);
417
+
418
+        } else {
419
+            $this->logger->debug('no file key found, we assume that the file "{file}" is not encrypted',
420
+                array('file' => $path, 'app' => 'encryption'));
421
+
422
+            return false;
423
+        }
424
+
425
+        return true;
426
+    }
427
+
428
+    /**
429
+     * should the file be encrypted or not
430
+     *
431
+     * @param string $path
432
+     * @return boolean
433
+     */
434
+    public function shouldEncrypt($path) {
435
+        if ($this->util->shouldEncryptHomeStorage() === false) {
436
+            $storage = $this->util->getStorage($path);
437
+            if ($storage->instanceOfStorage('\OCP\Files\IHomeStorage')) {
438
+                return false;
439
+            }
440
+        }
441
+        $parts = explode('/', $path);
442
+        if (count($parts) < 4) {
443
+            return false;
444
+        }
445
+
446
+        if ($parts[2] == 'files') {
447
+            return true;
448
+        }
449
+        if ($parts[2] == 'files_versions') {
450
+            return true;
451
+        }
452
+        if ($parts[2] == 'files_trashbin') {
453
+            return true;
454
+        }
455
+
456
+        return false;
457
+    }
458
+
459
+    /**
460
+     * get size of the unencrypted payload per block.
461
+     * Nextcloud read/write files with a block size of 8192 byte
462
+     *
463
+     * @param bool $signed
464
+     * @return int
465
+     */
466
+    public function getUnencryptedBlockSize($signed = false) {
467
+        if ($signed === false) {
468
+            return $this->unencryptedBlockSize;
469
+        }
470
+
471
+        return $this->unencryptedBlockSizeSigned;
472
+    }
473
+
474
+    /**
475
+     * check if the encryption module is able to read the file,
476
+     * e.g. if all encryption keys exists
477
+     *
478
+     * @param string $path
479
+     * @param string $uid user for whom we want to check if he can read the file
480
+     * @return bool
481
+     * @throws DecryptionFailedException
482
+     */
483
+    public function isReadable($path, $uid) {
484
+        $fileKey = $this->keyManager->getFileKey($path, $uid);
485
+        if (empty($fileKey)) {
486
+            $owner = $this->util->getOwner($path);
487
+            if ($owner !== $uid) {
488
+                // if it is a shared file we throw a exception with a useful
489
+                // error message because in this case it means that the file was
490
+                // shared with the user at a point where the user didn't had a
491
+                // valid private/public key
492
+                $msg = 'Encryption module "' . $this->getDisplayName() .
493
+                    '" is not able to read ' . $path;
494
+                $hint = $this->l->t('Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
495
+                $this->logger->warning($msg);
496
+                throw new DecryptionFailedException($msg, $hint);
497
+            }
498
+            return false;
499
+        }
500
+
501
+        return true;
502
+    }
503
+
504
+    /**
505
+     * Initial encryption of all files
506
+     *
507
+     * @param InputInterface $input
508
+     * @param OutputInterface $output write some status information to the terminal during encryption
509
+     */
510
+    public function encryptAll(InputInterface $input, OutputInterface $output) {
511
+        $this->encryptAll->encryptAll($input, $output);
512
+    }
513
+
514
+    /**
515
+     * prepare module to perform decrypt all operation
516
+     *
517
+     * @param InputInterface $input
518
+     * @param OutputInterface $output
519
+     * @param string $user
520
+     * @return bool
521
+     */
522
+    public function prepareDecryptAll(InputInterface $input, OutputInterface $output, $user = '') {
523
+        return $this->decryptAll->prepare($input, $output, $user);
524
+    }
525
+
526
+
527
+    /**
528
+     * @param string $path
529
+     * @return string
530
+     */
531
+    protected function getPathToRealFile($path) {
532
+        $realPath = $path;
533
+        $parts = explode('/', $path);
534
+        if ($parts[2] === 'files_versions') {
535
+            $realPath = '/' . $parts[1] . '/files/' . implode('/', array_slice($parts, 3));
536
+            $length = strrpos($realPath, '.');
537
+            $realPath = substr($realPath, 0, $length);
538
+        }
539
+
540
+        return $realPath;
541
+    }
542
+
543
+    /**
544
+     * remove .part file extension and the ocTransferId from the file to get the
545
+     * original file name
546
+     *
547
+     * @param string $path
548
+     * @return string
549
+     */
550
+    protected function stripPartFileExtension($path) {
551
+        if (pathinfo($path, PATHINFO_EXTENSION) === 'part') {
552
+            $pos = strrpos($path, '.', -6);
553
+            $path = substr($path, 0, $pos);
554
+        }
555
+
556
+        return $path;
557
+    }
558
+
559
+    /**
560
+     * Check if the module is ready to be used by that specific user.
561
+     * In case a module is not ready - because e.g. key pairs have not been generated
562
+     * upon login this method can return false before any operation starts and might
563
+     * cause issues during operations.
564
+     *
565
+     * @param string $user
566
+     * @return boolean
567
+     * @since 9.1.0
568
+     */
569
+    public function isReadyForUser($user) {
570
+        return $this->keyManager->userHasKeys($user);
571
+    }
572 572
 }
Please login to merge, or discard this patch.
apps/encryption/lib/KeyManager.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -488,7 +488,7 @@
 block discarded – undo
488 488
 
489 489
 
490 490
 	/**
491
-	 * @param $path
491
+	 * @param string $path
492 492
 	 * @param $uid
493 493
 	 * @return mixed
494 494
 	 */
Please login to merge, or discard this patch.
Indentation   +672 added lines, -672 removed lines patch added patch discarded remove patch
@@ -38,676 +38,676 @@
 block discarded – undo
38 38
 
39 39
 class KeyManager {
40 40
 
41
-	/**
42
-	 * @var Session
43
-	 */
44
-	protected $session;
45
-	/**
46
-	 * @var IStorage
47
-	 */
48
-	private $keyStorage;
49
-	/**
50
-	 * @var Crypt
51
-	 */
52
-	private $crypt;
53
-	/**
54
-	 * @var string
55
-	 */
56
-	private $recoveryKeyId;
57
-	/**
58
-	 * @var string
59
-	 */
60
-	private $publicShareKeyId;
61
-	/**
62
-	 * @var string
63
-	 */
64
-	private $masterKeyId;
65
-	/**
66
-	 * @var string UserID
67
-	 */
68
-	private $keyId;
69
-	/**
70
-	 * @var string
71
-	 */
72
-	private $publicKeyId = 'publicKey';
73
-	/**
74
-	 * @var string
75
-	 */
76
-	private $privateKeyId = 'privateKey';
77
-
78
-	/**
79
-	 * @var string
80
-	 */
81
-	private $shareKeyId = 'shareKey';
82
-
83
-	/**
84
-	 * @var string
85
-	 */
86
-	private $fileKeyId = 'fileKey';
87
-	/**
88
-	 * @var IConfig
89
-	 */
90
-	private $config;
91
-	/**
92
-	 * @var ILogger
93
-	 */
94
-	private $log;
95
-	/**
96
-	 * @var Util
97
-	 */
98
-	private $util;
99
-
100
-	/**
101
-	 * @param IStorage $keyStorage
102
-	 * @param Crypt $crypt
103
-	 * @param IConfig $config
104
-	 * @param IUserSession $userSession
105
-	 * @param Session $session
106
-	 * @param ILogger $log
107
-	 * @param Util $util
108
-	 */
109
-	public function __construct(
110
-		IStorage $keyStorage,
111
-		Crypt $crypt,
112
-		IConfig $config,
113
-		IUserSession $userSession,
114
-		Session $session,
115
-		ILogger $log,
116
-		Util $util
117
-	) {
118
-
119
-		$this->util = $util;
120
-		$this->session = $session;
121
-		$this->keyStorage = $keyStorage;
122
-		$this->crypt = $crypt;
123
-		$this->config = $config;
124
-		$this->log = $log;
125
-
126
-		$this->recoveryKeyId = $this->config->getAppValue('encryption',
127
-			'recoveryKeyId');
128
-		if (empty($this->recoveryKeyId)) {
129
-			$this->recoveryKeyId = 'recoveryKey_' . substr(md5(time()), 0, 8);
130
-			$this->config->setAppValue('encryption',
131
-				'recoveryKeyId',
132
-				$this->recoveryKeyId);
133
-		}
134
-
135
-		$this->publicShareKeyId = $this->config->getAppValue('encryption',
136
-			'publicShareKeyId');
137
-		if (empty($this->publicShareKeyId)) {
138
-			$this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
139
-			$this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
140
-		}
141
-
142
-		$this->masterKeyId = $this->config->getAppValue('encryption',
143
-			'masterKeyId');
144
-		if (empty($this->masterKeyId)) {
145
-			$this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
146
-			$this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
147
-		}
148
-
149
-		$this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false;
150
-		$this->log = $log;
151
-	}
152
-
153
-	/**
154
-	 * check if key pair for public link shares exists, if not we create one
155
-	 */
156
-	public function validateShareKey() {
157
-		$shareKey = $this->getPublicShareKey();
158
-		if (empty($shareKey)) {
159
-			$keyPair = $this->crypt->createKeyPair();
160
-
161
-			// Save public key
162
-			$this->keyStorage->setSystemUserKey(
163
-				$this->publicShareKeyId . '.publicKey', $keyPair['publicKey'],
164
-				Encryption::ID);
165
-
166
-			// Encrypt private key empty passphrase
167
-			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], '');
168
-			$header = $this->crypt->generateHeader();
169
-			$this->setSystemPrivateKey($this->publicShareKeyId, $header . $encryptedKey);
170
-		}
171
-	}
172
-
173
-	/**
174
-	 * check if a key pair for the master key exists, if not we create one
175
-	 */
176
-	public function validateMasterKey() {
177
-
178
-		if ($this->util->isMasterKeyEnabled() === false) {
179
-			return;
180
-		}
181
-
182
-		$masterKey = $this->getPublicMasterKey();
183
-		if (empty($masterKey)) {
184
-			$keyPair = $this->crypt->createKeyPair();
185
-
186
-			// Save public key
187
-			$this->keyStorage->setSystemUserKey(
188
-				$this->masterKeyId . '.publicKey', $keyPair['publicKey'],
189
-				Encryption::ID);
190
-
191
-			// Encrypt private key with system password
192
-			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $this->getMasterKeyPassword(), $this->masterKeyId);
193
-			$header = $this->crypt->generateHeader();
194
-			$this->setSystemPrivateKey($this->masterKeyId, $header . $encryptedKey);
195
-		}
196
-	}
197
-
198
-	/**
199
-	 * @return bool
200
-	 */
201
-	public function recoveryKeyExists() {
202
-		$key = $this->getRecoveryKey();
203
-		return (!empty($key));
204
-	}
205
-
206
-	/**
207
-	 * get recovery key
208
-	 *
209
-	 * @return string
210
-	 */
211
-	public function getRecoveryKey() {
212
-		return $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey', Encryption::ID);
213
-	}
214
-
215
-	/**
216
-	 * get recovery key ID
217
-	 *
218
-	 * @return string
219
-	 */
220
-	public function getRecoveryKeyId() {
221
-		return $this->recoveryKeyId;
222
-	}
223
-
224
-	/**
225
-	 * @param string $password
226
-	 * @return bool
227
-	 */
228
-	public function checkRecoveryPassword($password) {
229
-		$recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.privateKey', Encryption::ID);
230
-		$decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password);
231
-
232
-		if ($decryptedRecoveryKey) {
233
-			return true;
234
-		}
235
-		return false;
236
-	}
237
-
238
-	/**
239
-	 * @param string $uid
240
-	 * @param string $password
241
-	 * @param string $keyPair
242
-	 * @return bool
243
-	 */
244
-	public function storeKeyPair($uid, $password, $keyPair) {
245
-		// Save Public Key
246
-		$this->setPublicKey($uid, $keyPair['publicKey']);
247
-
248
-		$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password, $uid);
249
-
250
-		$header = $this->crypt->generateHeader();
251
-
252
-		if ($encryptedKey) {
253
-			$this->setPrivateKey($uid, $header . $encryptedKey);
254
-			return true;
255
-		}
256
-		return false;
257
-	}
258
-
259
-	/**
260
-	 * @param string $password
261
-	 * @param array $keyPair
262
-	 * @return bool
263
-	 */
264
-	public function setRecoveryKey($password, $keyPair) {
265
-		// Save Public Key
266
-		$this->keyStorage->setSystemUserKey($this->getRecoveryKeyId().
267
-			'.publicKey',
268
-			$keyPair['publicKey'],
269
-			Encryption::ID);
270
-
271
-		$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password);
272
-		$header = $this->crypt->generateHeader();
273
-
274
-		if ($encryptedKey) {
275
-			$this->setSystemPrivateKey($this->getRecoveryKeyId(), $header . $encryptedKey);
276
-			return true;
277
-		}
278
-		return false;
279
-	}
280
-
281
-	/**
282
-	 * @param $userId
283
-	 * @param $key
284
-	 * @return bool
285
-	 */
286
-	public function setPublicKey($userId, $key) {
287
-		return $this->keyStorage->setUserKey($userId, $this->publicKeyId, $key, Encryption::ID);
288
-	}
289
-
290
-	/**
291
-	 * @param $userId
292
-	 * @param string $key
293
-	 * @return bool
294
-	 */
295
-	public function setPrivateKey($userId, $key) {
296
-		return $this->keyStorage->setUserKey($userId,
297
-			$this->privateKeyId,
298
-			$key,
299
-			Encryption::ID);
300
-	}
301
-
302
-	/**
303
-	 * write file key to key storage
304
-	 *
305
-	 * @param string $path
306
-	 * @param string $key
307
-	 * @return boolean
308
-	 */
309
-	public function setFileKey($path, $key) {
310
-		return $this->keyStorage->setFileKey($path, $this->fileKeyId, $key, Encryption::ID);
311
-	}
312
-
313
-	/**
314
-	 * set all file keys (the file key and the corresponding share keys)
315
-	 *
316
-	 * @param string $path
317
-	 * @param array $keys
318
-	 */
319
-	public function setAllFileKeys($path, $keys) {
320
-		$this->setFileKey($path, $keys['data']);
321
-		foreach ($keys['keys'] as $uid => $keyFile) {
322
-			$this->setShareKey($path, $uid, $keyFile);
323
-		}
324
-	}
325
-
326
-	/**
327
-	 * write share key to the key storage
328
-	 *
329
-	 * @param string $path
330
-	 * @param string $uid
331
-	 * @param string $key
332
-	 * @return boolean
333
-	 */
334
-	public function setShareKey($path, $uid, $key) {
335
-		$keyId = $uid . '.' . $this->shareKeyId;
336
-		return $this->keyStorage->setFileKey($path, $keyId, $key, Encryption::ID);
337
-	}
338
-
339
-	/**
340
-	 * Decrypt private key and store it
341
-	 *
342
-	 * @param string $uid user id
343
-	 * @param string $passPhrase users password
344
-	 * @return boolean
345
-	 */
346
-	public function init($uid, $passPhrase) {
347
-
348
-		$this->session->setStatus(Session::INIT_EXECUTED);
349
-
350
-		try {
351
-			if($this->util->isMasterKeyEnabled()) {
352
-				$uid = $this->getMasterKeyId();
353
-				$passPhrase = $this->getMasterKeyPassword();
354
-				$privateKey = $this->getSystemPrivateKey($uid);
355
-			} else {
356
-				$privateKey = $this->getPrivateKey($uid);
357
-			}
358
-			$privateKey = $this->crypt->decryptPrivateKey($privateKey, $passPhrase, $uid);
359
-		} catch (PrivateKeyMissingException $e) {
360
-			return false;
361
-		} catch (DecryptionFailedException $e) {
362
-			return false;
363
-		} catch (\Exception $e) {
364
-			$this->log->warning(
365
-				'Could not decrypt the private key from user "' . $uid . '"" during login. ' .
366
-				'Assume password change on the user back-end. Error message: '
367
-				. $e->getMessage()
368
-			);
369
-			return false;
370
-		}
371
-
372
-		if ($privateKey) {
373
-			$this->session->setPrivateKey($privateKey);
374
-			$this->session->setStatus(Session::INIT_SUCCESSFUL);
375
-			return true;
376
-		}
377
-
378
-		return false;
379
-	}
380
-
381
-	/**
382
-	 * @param $userId
383
-	 * @return string
384
-	 * @throws PrivateKeyMissingException
385
-	 */
386
-	public function getPrivateKey($userId) {
387
-		$privateKey = $this->keyStorage->getUserKey($userId,
388
-			$this->privateKeyId, Encryption::ID);
389
-
390
-		if (strlen($privateKey) !== 0) {
391
-			return $privateKey;
392
-		}
393
-		throw new PrivateKeyMissingException($userId);
394
-	}
395
-
396
-	/**
397
-	 * @param string $path
398
-	 * @param $uid
399
-	 * @return string
400
-	 */
401
-	public function getFileKey($path, $uid) {
402
-		if ($uid === '') {
403
-			$uid = null;
404
-		}
405
-		$publicAccess = is_null($uid);
406
-		$encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
407
-
408
-		if (empty($encryptedFileKey)) {
409
-			return '';
410
-		}
411
-
412
-		if ($this->util->isMasterKeyEnabled()) {
413
-			$uid = $this->getMasterKeyId();
414
-			$shareKey = $this->getShareKey($path, $uid);
415
-			if ($publicAccess) {
416
-				$privateKey = $this->getSystemPrivateKey($uid);
417
-				$privateKey = $this->crypt->decryptPrivateKey($privateKey, $this->getMasterKeyPassword(), $uid);
418
-			} else {
419
-				// when logged in, the master key is already decrypted in the session
420
-				$privateKey = $this->session->getPrivateKey();
421
-			}
422
-		} else if ($publicAccess) {
423
-			// use public share key for public links
424
-			$uid = $this->getPublicShareKeyId();
425
-			$shareKey = $this->getShareKey($path, $uid);
426
-			$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
427
-			$privateKey = $this->crypt->decryptPrivateKey($privateKey);
428
-		} else {
429
-			$shareKey = $this->getShareKey($path, $uid);
430
-			$privateKey = $this->session->getPrivateKey();
431
-		}
432
-
433
-		if ($encryptedFileKey && $shareKey && $privateKey) {
434
-			return $this->crypt->multiKeyDecrypt($encryptedFileKey,
435
-				$shareKey,
436
-				$privateKey);
437
-		}
438
-
439
-		return '';
440
-	}
441
-
442
-	/**
443
-	 * Get the current version of a file
444
-	 *
445
-	 * @param string $path
446
-	 * @param View $view
447
-	 * @return int
448
-	 */
449
-	public function getVersion($path, View $view) {
450
-		$fileInfo = $view->getFileInfo($path);
451
-		if($fileInfo === false) {
452
-			return 0;
453
-		}
454
-		return $fileInfo->getEncryptedVersion();
455
-	}
456
-
457
-	/**
458
-	 * Set the current version of a file
459
-	 *
460
-	 * @param string $path
461
-	 * @param int $version
462
-	 * @param View $view
463
-	 */
464
-	public function setVersion($path, $version, View $view) {
465
-		$fileInfo= $view->getFileInfo($path);
466
-
467
-		if($fileInfo !== false) {
468
-			$cache = $fileInfo->getStorage()->getCache();
469
-			$cache->update($fileInfo->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]);
470
-		}
471
-	}
472
-
473
-	/**
474
-	 * get the encrypted file key
475
-	 *
476
-	 * @param string $path
477
-	 * @return string
478
-	 */
479
-	public function getEncryptedFileKey($path) {
480
-		$encryptedFileKey = $this->keyStorage->getFileKey($path,
481
-			$this->fileKeyId, Encryption::ID);
482
-
483
-		return $encryptedFileKey;
484
-	}
485
-
486
-	/**
487
-	 * delete share key
488
-	 *
489
-	 * @param string $path
490
-	 * @param string $keyId
491
-	 * @return boolean
492
-	 */
493
-	public function deleteShareKey($path, $keyId) {
494
-		return $this->keyStorage->deleteFileKey(
495
-			$path,
496
-			$keyId . '.' . $this->shareKeyId,
497
-			Encryption::ID);
498
-	}
499
-
500
-
501
-	/**
502
-	 * @param $path
503
-	 * @param $uid
504
-	 * @return mixed
505
-	 */
506
-	public function getShareKey($path, $uid) {
507
-		$keyId = $uid . '.' . $this->shareKeyId;
508
-		return $this->keyStorage->getFileKey($path, $keyId, Encryption::ID);
509
-	}
510
-
511
-	/**
512
-	 * check if user has a private and a public key
513
-	 *
514
-	 * @param string $userId
515
-	 * @return bool
516
-	 * @throws PrivateKeyMissingException
517
-	 * @throws PublicKeyMissingException
518
-	 */
519
-	public function userHasKeys($userId) {
520
-		$privateKey = $publicKey = true;
521
-		$exception = null;
522
-
523
-		try {
524
-			$this->getPrivateKey($userId);
525
-		} catch (PrivateKeyMissingException $e) {
526
-			$privateKey = false;
527
-			$exception = $e;
528
-		}
529
-		try {
530
-			$this->getPublicKey($userId);
531
-		} catch (PublicKeyMissingException $e) {
532
-			$publicKey = false;
533
-			$exception = $e;
534
-		}
535
-
536
-		if ($privateKey && $publicKey) {
537
-			return true;
538
-		} elseif (!$privateKey && !$publicKey) {
539
-			return false;
540
-		} else {
541
-			throw $exception;
542
-		}
543
-	}
544
-
545
-	/**
546
-	 * @param $userId
547
-	 * @return mixed
548
-	 * @throws PublicKeyMissingException
549
-	 */
550
-	public function getPublicKey($userId) {
551
-		$publicKey = $this->keyStorage->getUserKey($userId, $this->publicKeyId, Encryption::ID);
552
-
553
-		if (strlen($publicKey) !== 0) {
554
-			return $publicKey;
555
-		}
556
-		throw new PublicKeyMissingException($userId);
557
-	}
558
-
559
-	public function getPublicShareKeyId() {
560
-		return $this->publicShareKeyId;
561
-	}
562
-
563
-	/**
564
-	 * get public key for public link shares
565
-	 *
566
-	 * @return string
567
-	 */
568
-	public function getPublicShareKey() {
569
-		return $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.publicKey', Encryption::ID);
570
-	}
571
-
572
-	/**
573
-	 * @param string $purpose
574
-	 * @param string $uid
575
-	 */
576
-	public function backupUserKeys($purpose, $uid) {
577
-		$this->keyStorage->backupUserKeys(Encryption::ID, $purpose, $uid);
578
-	}
579
-
580
-	/**
581
-	 * creat a backup of the users private and public key and then  delete it
582
-	 *
583
-	 * @param string $uid
584
-	 */
585
-	public function deleteUserKeys($uid) {
586
-		$this->deletePublicKey($uid);
587
-		$this->deletePrivateKey($uid);
588
-	}
589
-
590
-	/**
591
-	 * @param $uid
592
-	 * @return bool
593
-	 */
594
-	public function deletePublicKey($uid) {
595
-		return $this->keyStorage->deleteUserKey($uid, $this->publicKeyId, Encryption::ID);
596
-	}
597
-
598
-	/**
599
-	 * @param string $uid
600
-	 * @return bool
601
-	 */
602
-	private function deletePrivateKey($uid) {
603
-		return $this->keyStorage->deleteUserKey($uid, $this->privateKeyId, Encryption::ID);
604
-	}
605
-
606
-	/**
607
-	 * @param string $path
608
-	 * @return bool
609
-	 */
610
-	public function deleteAllFileKeys($path) {
611
-		return $this->keyStorage->deleteAllFileKeys($path);
612
-	}
613
-
614
-	/**
615
-	 * @param array $userIds
616
-	 * @return array
617
-	 * @throws PublicKeyMissingException
618
-	 */
619
-	public function getPublicKeys(array $userIds) {
620
-		$keys = [];
621
-
622
-		foreach ($userIds as $userId) {
623
-			try {
624
-				$keys[$userId] = $this->getPublicKey($userId);
625
-			} catch (PublicKeyMissingException $e) {
626
-				continue;
627
-			}
628
-		}
629
-
630
-		return $keys;
631
-
632
-	}
633
-
634
-	/**
635
-	 * @param string $keyId
636
-	 * @return string returns openssl key
637
-	 */
638
-	public function getSystemPrivateKey($keyId) {
639
-		return $this->keyStorage->getSystemUserKey($keyId . '.' . $this->privateKeyId, Encryption::ID);
640
-	}
641
-
642
-	/**
643
-	 * @param string $keyId
644
-	 * @param string $key
645
-	 * @return string returns openssl key
646
-	 */
647
-	public function setSystemPrivateKey($keyId, $key) {
648
-		return $this->keyStorage->setSystemUserKey(
649
-			$keyId . '.' . $this->privateKeyId,
650
-			$key,
651
-			Encryption::ID);
652
-	}
653
-
654
-	/**
655
-	 * add system keys such as the public share key and the recovery key
656
-	 *
657
-	 * @param array $accessList
658
-	 * @param array $publicKeys
659
-	 * @param string $uid
660
-	 * @return array
661
-	 * @throws PublicKeyMissingException
662
-	 */
663
-	public function addSystemKeys(array $accessList, array $publicKeys, $uid) {
664
-		if (!empty($accessList['public'])) {
665
-			$publicShareKey = $this->getPublicShareKey();
666
-			if (empty($publicShareKey)) {
667
-				throw new PublicKeyMissingException($this->getPublicShareKeyId());
668
-			}
669
-			$publicKeys[$this->getPublicShareKeyId()] = $publicShareKey;
670
-		}
671
-
672
-		if ($this->recoveryKeyExists() &&
673
-			$this->util->isRecoveryEnabledForUser($uid)) {
674
-
675
-			$publicKeys[$this->getRecoveryKeyId()] = $this->getRecoveryKey();
676
-		}
677
-
678
-		return $publicKeys;
679
-	}
680
-
681
-	/**
682
-	 * get master key password
683
-	 *
684
-	 * @return string
685
-	 * @throws \Exception
686
-	 */
687
-	public function getMasterKeyPassword() {
688
-		$password = $this->config->getSystemValue('secret');
689
-		if (empty($password)){
690
-			throw new \Exception('Can not get secret from Nextcloud instance');
691
-		}
692
-
693
-		return $password;
694
-	}
695
-
696
-	/**
697
-	 * return master key id
698
-	 *
699
-	 * @return string
700
-	 */
701
-	public function getMasterKeyId() {
702
-		return $this->masterKeyId;
703
-	}
704
-
705
-	/**
706
-	 * get public master key
707
-	 *
708
-	 * @return string
709
-	 */
710
-	public function getPublicMasterKey() {
711
-		return $this->keyStorage->getSystemUserKey($this->masterKeyId . '.publicKey', Encryption::ID);
712
-	}
41
+    /**
42
+     * @var Session
43
+     */
44
+    protected $session;
45
+    /**
46
+     * @var IStorage
47
+     */
48
+    private $keyStorage;
49
+    /**
50
+     * @var Crypt
51
+     */
52
+    private $crypt;
53
+    /**
54
+     * @var string
55
+     */
56
+    private $recoveryKeyId;
57
+    /**
58
+     * @var string
59
+     */
60
+    private $publicShareKeyId;
61
+    /**
62
+     * @var string
63
+     */
64
+    private $masterKeyId;
65
+    /**
66
+     * @var string UserID
67
+     */
68
+    private $keyId;
69
+    /**
70
+     * @var string
71
+     */
72
+    private $publicKeyId = 'publicKey';
73
+    /**
74
+     * @var string
75
+     */
76
+    private $privateKeyId = 'privateKey';
77
+
78
+    /**
79
+     * @var string
80
+     */
81
+    private $shareKeyId = 'shareKey';
82
+
83
+    /**
84
+     * @var string
85
+     */
86
+    private $fileKeyId = 'fileKey';
87
+    /**
88
+     * @var IConfig
89
+     */
90
+    private $config;
91
+    /**
92
+     * @var ILogger
93
+     */
94
+    private $log;
95
+    /**
96
+     * @var Util
97
+     */
98
+    private $util;
99
+
100
+    /**
101
+     * @param IStorage $keyStorage
102
+     * @param Crypt $crypt
103
+     * @param IConfig $config
104
+     * @param IUserSession $userSession
105
+     * @param Session $session
106
+     * @param ILogger $log
107
+     * @param Util $util
108
+     */
109
+    public function __construct(
110
+        IStorage $keyStorage,
111
+        Crypt $crypt,
112
+        IConfig $config,
113
+        IUserSession $userSession,
114
+        Session $session,
115
+        ILogger $log,
116
+        Util $util
117
+    ) {
118
+
119
+        $this->util = $util;
120
+        $this->session = $session;
121
+        $this->keyStorage = $keyStorage;
122
+        $this->crypt = $crypt;
123
+        $this->config = $config;
124
+        $this->log = $log;
125
+
126
+        $this->recoveryKeyId = $this->config->getAppValue('encryption',
127
+            'recoveryKeyId');
128
+        if (empty($this->recoveryKeyId)) {
129
+            $this->recoveryKeyId = 'recoveryKey_' . substr(md5(time()), 0, 8);
130
+            $this->config->setAppValue('encryption',
131
+                'recoveryKeyId',
132
+                $this->recoveryKeyId);
133
+        }
134
+
135
+        $this->publicShareKeyId = $this->config->getAppValue('encryption',
136
+            'publicShareKeyId');
137
+        if (empty($this->publicShareKeyId)) {
138
+            $this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
139
+            $this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
140
+        }
141
+
142
+        $this->masterKeyId = $this->config->getAppValue('encryption',
143
+            'masterKeyId');
144
+        if (empty($this->masterKeyId)) {
145
+            $this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
146
+            $this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
147
+        }
148
+
149
+        $this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false;
150
+        $this->log = $log;
151
+    }
152
+
153
+    /**
154
+     * check if key pair for public link shares exists, if not we create one
155
+     */
156
+    public function validateShareKey() {
157
+        $shareKey = $this->getPublicShareKey();
158
+        if (empty($shareKey)) {
159
+            $keyPair = $this->crypt->createKeyPair();
160
+
161
+            // Save public key
162
+            $this->keyStorage->setSystemUserKey(
163
+                $this->publicShareKeyId . '.publicKey', $keyPair['publicKey'],
164
+                Encryption::ID);
165
+
166
+            // Encrypt private key empty passphrase
167
+            $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], '');
168
+            $header = $this->crypt->generateHeader();
169
+            $this->setSystemPrivateKey($this->publicShareKeyId, $header . $encryptedKey);
170
+        }
171
+    }
172
+
173
+    /**
174
+     * check if a key pair for the master key exists, if not we create one
175
+     */
176
+    public function validateMasterKey() {
177
+
178
+        if ($this->util->isMasterKeyEnabled() === false) {
179
+            return;
180
+        }
181
+
182
+        $masterKey = $this->getPublicMasterKey();
183
+        if (empty($masterKey)) {
184
+            $keyPair = $this->crypt->createKeyPair();
185
+
186
+            // Save public key
187
+            $this->keyStorage->setSystemUserKey(
188
+                $this->masterKeyId . '.publicKey', $keyPair['publicKey'],
189
+                Encryption::ID);
190
+
191
+            // Encrypt private key with system password
192
+            $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $this->getMasterKeyPassword(), $this->masterKeyId);
193
+            $header = $this->crypt->generateHeader();
194
+            $this->setSystemPrivateKey($this->masterKeyId, $header . $encryptedKey);
195
+        }
196
+    }
197
+
198
+    /**
199
+     * @return bool
200
+     */
201
+    public function recoveryKeyExists() {
202
+        $key = $this->getRecoveryKey();
203
+        return (!empty($key));
204
+    }
205
+
206
+    /**
207
+     * get recovery key
208
+     *
209
+     * @return string
210
+     */
211
+    public function getRecoveryKey() {
212
+        return $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey', Encryption::ID);
213
+    }
214
+
215
+    /**
216
+     * get recovery key ID
217
+     *
218
+     * @return string
219
+     */
220
+    public function getRecoveryKeyId() {
221
+        return $this->recoveryKeyId;
222
+    }
223
+
224
+    /**
225
+     * @param string $password
226
+     * @return bool
227
+     */
228
+    public function checkRecoveryPassword($password) {
229
+        $recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.privateKey', Encryption::ID);
230
+        $decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password);
231
+
232
+        if ($decryptedRecoveryKey) {
233
+            return true;
234
+        }
235
+        return false;
236
+    }
237
+
238
+    /**
239
+     * @param string $uid
240
+     * @param string $password
241
+     * @param string $keyPair
242
+     * @return bool
243
+     */
244
+    public function storeKeyPair($uid, $password, $keyPair) {
245
+        // Save Public Key
246
+        $this->setPublicKey($uid, $keyPair['publicKey']);
247
+
248
+        $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password, $uid);
249
+
250
+        $header = $this->crypt->generateHeader();
251
+
252
+        if ($encryptedKey) {
253
+            $this->setPrivateKey($uid, $header . $encryptedKey);
254
+            return true;
255
+        }
256
+        return false;
257
+    }
258
+
259
+    /**
260
+     * @param string $password
261
+     * @param array $keyPair
262
+     * @return bool
263
+     */
264
+    public function setRecoveryKey($password, $keyPair) {
265
+        // Save Public Key
266
+        $this->keyStorage->setSystemUserKey($this->getRecoveryKeyId().
267
+            '.publicKey',
268
+            $keyPair['publicKey'],
269
+            Encryption::ID);
270
+
271
+        $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password);
272
+        $header = $this->crypt->generateHeader();
273
+
274
+        if ($encryptedKey) {
275
+            $this->setSystemPrivateKey($this->getRecoveryKeyId(), $header . $encryptedKey);
276
+            return true;
277
+        }
278
+        return false;
279
+    }
280
+
281
+    /**
282
+     * @param $userId
283
+     * @param $key
284
+     * @return bool
285
+     */
286
+    public function setPublicKey($userId, $key) {
287
+        return $this->keyStorage->setUserKey($userId, $this->publicKeyId, $key, Encryption::ID);
288
+    }
289
+
290
+    /**
291
+     * @param $userId
292
+     * @param string $key
293
+     * @return bool
294
+     */
295
+    public function setPrivateKey($userId, $key) {
296
+        return $this->keyStorage->setUserKey($userId,
297
+            $this->privateKeyId,
298
+            $key,
299
+            Encryption::ID);
300
+    }
301
+
302
+    /**
303
+     * write file key to key storage
304
+     *
305
+     * @param string $path
306
+     * @param string $key
307
+     * @return boolean
308
+     */
309
+    public function setFileKey($path, $key) {
310
+        return $this->keyStorage->setFileKey($path, $this->fileKeyId, $key, Encryption::ID);
311
+    }
312
+
313
+    /**
314
+     * set all file keys (the file key and the corresponding share keys)
315
+     *
316
+     * @param string $path
317
+     * @param array $keys
318
+     */
319
+    public function setAllFileKeys($path, $keys) {
320
+        $this->setFileKey($path, $keys['data']);
321
+        foreach ($keys['keys'] as $uid => $keyFile) {
322
+            $this->setShareKey($path, $uid, $keyFile);
323
+        }
324
+    }
325
+
326
+    /**
327
+     * write share key to the key storage
328
+     *
329
+     * @param string $path
330
+     * @param string $uid
331
+     * @param string $key
332
+     * @return boolean
333
+     */
334
+    public function setShareKey($path, $uid, $key) {
335
+        $keyId = $uid . '.' . $this->shareKeyId;
336
+        return $this->keyStorage->setFileKey($path, $keyId, $key, Encryption::ID);
337
+    }
338
+
339
+    /**
340
+     * Decrypt private key and store it
341
+     *
342
+     * @param string $uid user id
343
+     * @param string $passPhrase users password
344
+     * @return boolean
345
+     */
346
+    public function init($uid, $passPhrase) {
347
+
348
+        $this->session->setStatus(Session::INIT_EXECUTED);
349
+
350
+        try {
351
+            if($this->util->isMasterKeyEnabled()) {
352
+                $uid = $this->getMasterKeyId();
353
+                $passPhrase = $this->getMasterKeyPassword();
354
+                $privateKey = $this->getSystemPrivateKey($uid);
355
+            } else {
356
+                $privateKey = $this->getPrivateKey($uid);
357
+            }
358
+            $privateKey = $this->crypt->decryptPrivateKey($privateKey, $passPhrase, $uid);
359
+        } catch (PrivateKeyMissingException $e) {
360
+            return false;
361
+        } catch (DecryptionFailedException $e) {
362
+            return false;
363
+        } catch (\Exception $e) {
364
+            $this->log->warning(
365
+                'Could not decrypt the private key from user "' . $uid . '"" during login. ' .
366
+                'Assume password change on the user back-end. Error message: '
367
+                . $e->getMessage()
368
+            );
369
+            return false;
370
+        }
371
+
372
+        if ($privateKey) {
373
+            $this->session->setPrivateKey($privateKey);
374
+            $this->session->setStatus(Session::INIT_SUCCESSFUL);
375
+            return true;
376
+        }
377
+
378
+        return false;
379
+    }
380
+
381
+    /**
382
+     * @param $userId
383
+     * @return string
384
+     * @throws PrivateKeyMissingException
385
+     */
386
+    public function getPrivateKey($userId) {
387
+        $privateKey = $this->keyStorage->getUserKey($userId,
388
+            $this->privateKeyId, Encryption::ID);
389
+
390
+        if (strlen($privateKey) !== 0) {
391
+            return $privateKey;
392
+        }
393
+        throw new PrivateKeyMissingException($userId);
394
+    }
395
+
396
+    /**
397
+     * @param string $path
398
+     * @param $uid
399
+     * @return string
400
+     */
401
+    public function getFileKey($path, $uid) {
402
+        if ($uid === '') {
403
+            $uid = null;
404
+        }
405
+        $publicAccess = is_null($uid);
406
+        $encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
407
+
408
+        if (empty($encryptedFileKey)) {
409
+            return '';
410
+        }
411
+
412
+        if ($this->util->isMasterKeyEnabled()) {
413
+            $uid = $this->getMasterKeyId();
414
+            $shareKey = $this->getShareKey($path, $uid);
415
+            if ($publicAccess) {
416
+                $privateKey = $this->getSystemPrivateKey($uid);
417
+                $privateKey = $this->crypt->decryptPrivateKey($privateKey, $this->getMasterKeyPassword(), $uid);
418
+            } else {
419
+                // when logged in, the master key is already decrypted in the session
420
+                $privateKey = $this->session->getPrivateKey();
421
+            }
422
+        } else if ($publicAccess) {
423
+            // use public share key for public links
424
+            $uid = $this->getPublicShareKeyId();
425
+            $shareKey = $this->getShareKey($path, $uid);
426
+            $privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
427
+            $privateKey = $this->crypt->decryptPrivateKey($privateKey);
428
+        } else {
429
+            $shareKey = $this->getShareKey($path, $uid);
430
+            $privateKey = $this->session->getPrivateKey();
431
+        }
432
+
433
+        if ($encryptedFileKey && $shareKey && $privateKey) {
434
+            return $this->crypt->multiKeyDecrypt($encryptedFileKey,
435
+                $shareKey,
436
+                $privateKey);
437
+        }
438
+
439
+        return '';
440
+    }
441
+
442
+    /**
443
+     * Get the current version of a file
444
+     *
445
+     * @param string $path
446
+     * @param View $view
447
+     * @return int
448
+     */
449
+    public function getVersion($path, View $view) {
450
+        $fileInfo = $view->getFileInfo($path);
451
+        if($fileInfo === false) {
452
+            return 0;
453
+        }
454
+        return $fileInfo->getEncryptedVersion();
455
+    }
456
+
457
+    /**
458
+     * Set the current version of a file
459
+     *
460
+     * @param string $path
461
+     * @param int $version
462
+     * @param View $view
463
+     */
464
+    public function setVersion($path, $version, View $view) {
465
+        $fileInfo= $view->getFileInfo($path);
466
+
467
+        if($fileInfo !== false) {
468
+            $cache = $fileInfo->getStorage()->getCache();
469
+            $cache->update($fileInfo->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]);
470
+        }
471
+    }
472
+
473
+    /**
474
+     * get the encrypted file key
475
+     *
476
+     * @param string $path
477
+     * @return string
478
+     */
479
+    public function getEncryptedFileKey($path) {
480
+        $encryptedFileKey = $this->keyStorage->getFileKey($path,
481
+            $this->fileKeyId, Encryption::ID);
482
+
483
+        return $encryptedFileKey;
484
+    }
485
+
486
+    /**
487
+     * delete share key
488
+     *
489
+     * @param string $path
490
+     * @param string $keyId
491
+     * @return boolean
492
+     */
493
+    public function deleteShareKey($path, $keyId) {
494
+        return $this->keyStorage->deleteFileKey(
495
+            $path,
496
+            $keyId . '.' . $this->shareKeyId,
497
+            Encryption::ID);
498
+    }
499
+
500
+
501
+    /**
502
+     * @param $path
503
+     * @param $uid
504
+     * @return mixed
505
+     */
506
+    public function getShareKey($path, $uid) {
507
+        $keyId = $uid . '.' . $this->shareKeyId;
508
+        return $this->keyStorage->getFileKey($path, $keyId, Encryption::ID);
509
+    }
510
+
511
+    /**
512
+     * check if user has a private and a public key
513
+     *
514
+     * @param string $userId
515
+     * @return bool
516
+     * @throws PrivateKeyMissingException
517
+     * @throws PublicKeyMissingException
518
+     */
519
+    public function userHasKeys($userId) {
520
+        $privateKey = $publicKey = true;
521
+        $exception = null;
522
+
523
+        try {
524
+            $this->getPrivateKey($userId);
525
+        } catch (PrivateKeyMissingException $e) {
526
+            $privateKey = false;
527
+            $exception = $e;
528
+        }
529
+        try {
530
+            $this->getPublicKey($userId);
531
+        } catch (PublicKeyMissingException $e) {
532
+            $publicKey = false;
533
+            $exception = $e;
534
+        }
535
+
536
+        if ($privateKey && $publicKey) {
537
+            return true;
538
+        } elseif (!$privateKey && !$publicKey) {
539
+            return false;
540
+        } else {
541
+            throw $exception;
542
+        }
543
+    }
544
+
545
+    /**
546
+     * @param $userId
547
+     * @return mixed
548
+     * @throws PublicKeyMissingException
549
+     */
550
+    public function getPublicKey($userId) {
551
+        $publicKey = $this->keyStorage->getUserKey($userId, $this->publicKeyId, Encryption::ID);
552
+
553
+        if (strlen($publicKey) !== 0) {
554
+            return $publicKey;
555
+        }
556
+        throw new PublicKeyMissingException($userId);
557
+    }
558
+
559
+    public function getPublicShareKeyId() {
560
+        return $this->publicShareKeyId;
561
+    }
562
+
563
+    /**
564
+     * get public key for public link shares
565
+     *
566
+     * @return string
567
+     */
568
+    public function getPublicShareKey() {
569
+        return $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.publicKey', Encryption::ID);
570
+    }
571
+
572
+    /**
573
+     * @param string $purpose
574
+     * @param string $uid
575
+     */
576
+    public function backupUserKeys($purpose, $uid) {
577
+        $this->keyStorage->backupUserKeys(Encryption::ID, $purpose, $uid);
578
+    }
579
+
580
+    /**
581
+     * creat a backup of the users private and public key and then  delete it
582
+     *
583
+     * @param string $uid
584
+     */
585
+    public function deleteUserKeys($uid) {
586
+        $this->deletePublicKey($uid);
587
+        $this->deletePrivateKey($uid);
588
+    }
589
+
590
+    /**
591
+     * @param $uid
592
+     * @return bool
593
+     */
594
+    public function deletePublicKey($uid) {
595
+        return $this->keyStorage->deleteUserKey($uid, $this->publicKeyId, Encryption::ID);
596
+    }
597
+
598
+    /**
599
+     * @param string $uid
600
+     * @return bool
601
+     */
602
+    private function deletePrivateKey($uid) {
603
+        return $this->keyStorage->deleteUserKey($uid, $this->privateKeyId, Encryption::ID);
604
+    }
605
+
606
+    /**
607
+     * @param string $path
608
+     * @return bool
609
+     */
610
+    public function deleteAllFileKeys($path) {
611
+        return $this->keyStorage->deleteAllFileKeys($path);
612
+    }
613
+
614
+    /**
615
+     * @param array $userIds
616
+     * @return array
617
+     * @throws PublicKeyMissingException
618
+     */
619
+    public function getPublicKeys(array $userIds) {
620
+        $keys = [];
621
+
622
+        foreach ($userIds as $userId) {
623
+            try {
624
+                $keys[$userId] = $this->getPublicKey($userId);
625
+            } catch (PublicKeyMissingException $e) {
626
+                continue;
627
+            }
628
+        }
629
+
630
+        return $keys;
631
+
632
+    }
633
+
634
+    /**
635
+     * @param string $keyId
636
+     * @return string returns openssl key
637
+     */
638
+    public function getSystemPrivateKey($keyId) {
639
+        return $this->keyStorage->getSystemUserKey($keyId . '.' . $this->privateKeyId, Encryption::ID);
640
+    }
641
+
642
+    /**
643
+     * @param string $keyId
644
+     * @param string $key
645
+     * @return string returns openssl key
646
+     */
647
+    public function setSystemPrivateKey($keyId, $key) {
648
+        return $this->keyStorage->setSystemUserKey(
649
+            $keyId . '.' . $this->privateKeyId,
650
+            $key,
651
+            Encryption::ID);
652
+    }
653
+
654
+    /**
655
+     * add system keys such as the public share key and the recovery key
656
+     *
657
+     * @param array $accessList
658
+     * @param array $publicKeys
659
+     * @param string $uid
660
+     * @return array
661
+     * @throws PublicKeyMissingException
662
+     */
663
+    public function addSystemKeys(array $accessList, array $publicKeys, $uid) {
664
+        if (!empty($accessList['public'])) {
665
+            $publicShareKey = $this->getPublicShareKey();
666
+            if (empty($publicShareKey)) {
667
+                throw new PublicKeyMissingException($this->getPublicShareKeyId());
668
+            }
669
+            $publicKeys[$this->getPublicShareKeyId()] = $publicShareKey;
670
+        }
671
+
672
+        if ($this->recoveryKeyExists() &&
673
+            $this->util->isRecoveryEnabledForUser($uid)) {
674
+
675
+            $publicKeys[$this->getRecoveryKeyId()] = $this->getRecoveryKey();
676
+        }
677
+
678
+        return $publicKeys;
679
+    }
680
+
681
+    /**
682
+     * get master key password
683
+     *
684
+     * @return string
685
+     * @throws \Exception
686
+     */
687
+    public function getMasterKeyPassword() {
688
+        $password = $this->config->getSystemValue('secret');
689
+        if (empty($password)){
690
+            throw new \Exception('Can not get secret from Nextcloud instance');
691
+        }
692
+
693
+        return $password;
694
+    }
695
+
696
+    /**
697
+     * return master key id
698
+     *
699
+     * @return string
700
+     */
701
+    public function getMasterKeyId() {
702
+        return $this->masterKeyId;
703
+    }
704
+
705
+    /**
706
+     * get public master key
707
+     *
708
+     * @return string
709
+     */
710
+    public function getPublicMasterKey() {
711
+        return $this->keyStorage->getSystemUserKey($this->masterKeyId . '.publicKey', Encryption::ID);
712
+    }
713 713
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -126,7 +126,7 @@  discard block
 block discarded – undo
126 126
 		$this->recoveryKeyId = $this->config->getAppValue('encryption',
127 127
 			'recoveryKeyId');
128 128
 		if (empty($this->recoveryKeyId)) {
129
-			$this->recoveryKeyId = 'recoveryKey_' . substr(md5(time()), 0, 8);
129
+			$this->recoveryKeyId = 'recoveryKey_'.substr(md5(time()), 0, 8);
130 130
 			$this->config->setAppValue('encryption',
131 131
 				'recoveryKeyId',
132 132
 				$this->recoveryKeyId);
@@ -135,14 +135,14 @@  discard block
 block discarded – undo
135 135
 		$this->publicShareKeyId = $this->config->getAppValue('encryption',
136 136
 			'publicShareKeyId');
137 137
 		if (empty($this->publicShareKeyId)) {
138
-			$this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
138
+			$this->publicShareKeyId = 'pubShare_'.substr(md5(time()), 0, 8);
139 139
 			$this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
140 140
 		}
141 141
 
142 142
 		$this->masterKeyId = $this->config->getAppValue('encryption',
143 143
 			'masterKeyId');
144 144
 		if (empty($this->masterKeyId)) {
145
-			$this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
145
+			$this->masterKeyId = 'master_'.substr(md5(time()), 0, 8);
146 146
 			$this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
147 147
 		}
148 148
 
@@ -160,13 +160,13 @@  discard block
 block discarded – undo
160 160
 
161 161
 			// Save public key
162 162
 			$this->keyStorage->setSystemUserKey(
163
-				$this->publicShareKeyId . '.publicKey', $keyPair['publicKey'],
163
+				$this->publicShareKeyId.'.publicKey', $keyPair['publicKey'],
164 164
 				Encryption::ID);
165 165
 
166 166
 			// Encrypt private key empty passphrase
167 167
 			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], '');
168 168
 			$header = $this->crypt->generateHeader();
169
-			$this->setSystemPrivateKey($this->publicShareKeyId, $header . $encryptedKey);
169
+			$this->setSystemPrivateKey($this->publicShareKeyId, $header.$encryptedKey);
170 170
 		}
171 171
 	}
172 172
 
@@ -185,13 +185,13 @@  discard block
 block discarded – undo
185 185
 
186 186
 			// Save public key
187 187
 			$this->keyStorage->setSystemUserKey(
188
-				$this->masterKeyId . '.publicKey', $keyPair['publicKey'],
188
+				$this->masterKeyId.'.publicKey', $keyPair['publicKey'],
189 189
 				Encryption::ID);
190 190
 
191 191
 			// Encrypt private key with system password
192 192
 			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $this->getMasterKeyPassword(), $this->masterKeyId);
193 193
 			$header = $this->crypt->generateHeader();
194
-			$this->setSystemPrivateKey($this->masterKeyId, $header . $encryptedKey);
194
+			$this->setSystemPrivateKey($this->masterKeyId, $header.$encryptedKey);
195 195
 		}
196 196
 	}
197 197
 
@@ -209,7 +209,7 @@  discard block
 block discarded – undo
209 209
 	 * @return string
210 210
 	 */
211 211
 	public function getRecoveryKey() {
212
-		return $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey', Encryption::ID);
212
+		return $this->keyStorage->getSystemUserKey($this->recoveryKeyId.'.publicKey', Encryption::ID);
213 213
 	}
214 214
 
215 215
 	/**
@@ -226,7 +226,7 @@  discard block
 block discarded – undo
226 226
 	 * @return bool
227 227
 	 */
228 228
 	public function checkRecoveryPassword($password) {
229
-		$recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.privateKey', Encryption::ID);
229
+		$recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId.'.privateKey', Encryption::ID);
230 230
 		$decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password);
231 231
 
232 232
 		if ($decryptedRecoveryKey) {
@@ -250,7 +250,7 @@  discard block
 block discarded – undo
250 250
 		$header = $this->crypt->generateHeader();
251 251
 
252 252
 		if ($encryptedKey) {
253
-			$this->setPrivateKey($uid, $header . $encryptedKey);
253
+			$this->setPrivateKey($uid, $header.$encryptedKey);
254 254
 			return true;
255 255
 		}
256 256
 		return false;
@@ -272,7 +272,7 @@  discard block
 block discarded – undo
272 272
 		$header = $this->crypt->generateHeader();
273 273
 
274 274
 		if ($encryptedKey) {
275
-			$this->setSystemPrivateKey($this->getRecoveryKeyId(), $header . $encryptedKey);
275
+			$this->setSystemPrivateKey($this->getRecoveryKeyId(), $header.$encryptedKey);
276 276
 			return true;
277 277
 		}
278 278
 		return false;
@@ -332,7 +332,7 @@  discard block
 block discarded – undo
332 332
 	 * @return boolean
333 333
 	 */
334 334
 	public function setShareKey($path, $uid, $key) {
335
-		$keyId = $uid . '.' . $this->shareKeyId;
335
+		$keyId = $uid.'.'.$this->shareKeyId;
336 336
 		return $this->keyStorage->setFileKey($path, $keyId, $key, Encryption::ID);
337 337
 	}
338 338
 
@@ -348,7 +348,7 @@  discard block
 block discarded – undo
348 348
 		$this->session->setStatus(Session::INIT_EXECUTED);
349 349
 
350 350
 		try {
351
-			if($this->util->isMasterKeyEnabled()) {
351
+			if ($this->util->isMasterKeyEnabled()) {
352 352
 				$uid = $this->getMasterKeyId();
353 353
 				$passPhrase = $this->getMasterKeyPassword();
354 354
 				$privateKey = $this->getSystemPrivateKey($uid);
@@ -362,7 +362,7 @@  discard block
 block discarded – undo
362 362
 			return false;
363 363
 		} catch (\Exception $e) {
364 364
 			$this->log->warning(
365
-				'Could not decrypt the private key from user "' . $uid . '"" during login. ' .
365
+				'Could not decrypt the private key from user "'.$uid.'"" during login. '.
366 366
 				'Assume password change on the user back-end. Error message: '
367 367
 				. $e->getMessage()
368 368
 			);
@@ -423,7 +423,7 @@  discard block
 block discarded – undo
423 423
 			// use public share key for public links
424 424
 			$uid = $this->getPublicShareKeyId();
425 425
 			$shareKey = $this->getShareKey($path, $uid);
426
-			$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
426
+			$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId.'.privateKey', Encryption::ID);
427 427
 			$privateKey = $this->crypt->decryptPrivateKey($privateKey);
428 428
 		} else {
429 429
 			$shareKey = $this->getShareKey($path, $uid);
@@ -448,7 +448,7 @@  discard block
 block discarded – undo
448 448
 	 */
449 449
 	public function getVersion($path, View $view) {
450 450
 		$fileInfo = $view->getFileInfo($path);
451
-		if($fileInfo === false) {
451
+		if ($fileInfo === false) {
452 452
 			return 0;
453 453
 		}
454 454
 		return $fileInfo->getEncryptedVersion();
@@ -462,9 +462,9 @@  discard block
 block discarded – undo
462 462
 	 * @param View $view
463 463
 	 */
464 464
 	public function setVersion($path, $version, View $view) {
465
-		$fileInfo= $view->getFileInfo($path);
465
+		$fileInfo = $view->getFileInfo($path);
466 466
 
467
-		if($fileInfo !== false) {
467
+		if ($fileInfo !== false) {
468 468
 			$cache = $fileInfo->getStorage()->getCache();
469 469
 			$cache->update($fileInfo->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]);
470 470
 		}
@@ -493,7 +493,7 @@  discard block
 block discarded – undo
493 493
 	public function deleteShareKey($path, $keyId) {
494 494
 		return $this->keyStorage->deleteFileKey(
495 495
 			$path,
496
-			$keyId . '.' . $this->shareKeyId,
496
+			$keyId.'.'.$this->shareKeyId,
497 497
 			Encryption::ID);
498 498
 	}
499 499
 
@@ -504,7 +504,7 @@  discard block
 block discarded – undo
504 504
 	 * @return mixed
505 505
 	 */
506 506
 	public function getShareKey($path, $uid) {
507
-		$keyId = $uid . '.' . $this->shareKeyId;
507
+		$keyId = $uid.'.'.$this->shareKeyId;
508 508
 		return $this->keyStorage->getFileKey($path, $keyId, Encryption::ID);
509 509
 	}
510 510
 
@@ -566,7 +566,7 @@  discard block
 block discarded – undo
566 566
 	 * @return string
567 567
 	 */
568 568
 	public function getPublicShareKey() {
569
-		return $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.publicKey', Encryption::ID);
569
+		return $this->keyStorage->getSystemUserKey($this->publicShareKeyId.'.publicKey', Encryption::ID);
570 570
 	}
571 571
 
572 572
 	/**
@@ -636,7 +636,7 @@  discard block
 block discarded – undo
636 636
 	 * @return string returns openssl key
637 637
 	 */
638 638
 	public function getSystemPrivateKey($keyId) {
639
-		return $this->keyStorage->getSystemUserKey($keyId . '.' . $this->privateKeyId, Encryption::ID);
639
+		return $this->keyStorage->getSystemUserKey($keyId.'.'.$this->privateKeyId, Encryption::ID);
640 640
 	}
641 641
 
642 642
 	/**
@@ -646,7 +646,7 @@  discard block
 block discarded – undo
646 646
 	 */
647 647
 	public function setSystemPrivateKey($keyId, $key) {
648 648
 		return $this->keyStorage->setSystemUserKey(
649
-			$keyId . '.' . $this->privateKeyId,
649
+			$keyId.'.'.$this->privateKeyId,
650 650
 			$key,
651 651
 			Encryption::ID);
652 652
 	}
@@ -686,7 +686,7 @@  discard block
 block discarded – undo
686 686
 	 */
687 687
 	public function getMasterKeyPassword() {
688 688
 		$password = $this->config->getSystemValue('secret');
689
-		if (empty($password)){
689
+		if (empty($password)) {
690 690
 			throw new \Exception('Can not get secret from Nextcloud instance');
691 691
 		}
692 692
 
@@ -708,6 +708,6 @@  discard block
 block discarded – undo
708 708
 	 * @return string
709 709
 	 */
710 710
 	public function getPublicMasterKey() {
711
-		return $this->keyStorage->getSystemUserKey($this->masterKeyId . '.publicKey', Encryption::ID);
711
+		return $this->keyStorage->getSystemUserKey($this->masterKeyId.'.publicKey', Encryption::ID);
712 712
 	}
713 713
 }
Please login to merge, or discard this patch.
apps/federatedfilesharing/lib/FederatedShareProvider.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -391,7 +391,7 @@  discard block
 block discarded – undo
391 391
 	/**
392 392
 	 * store remote ID in federated reShare table
393 393
 	 *
394
-	 * @param $shareId
394
+	 * @param integer $shareId
395 395
 	 * @param $remoteId
396 396
 	 */
397 397
 	public function storeRemoteId($shareId, $remoteId) {
@@ -729,7 +729,7 @@  discard block
 block discarded – undo
729 729
 	/**
730 730
 	 * get database row of a give share
731 731
 	 *
732
-	 * @param $id
732
+	 * @param integer $id
733 733
 	 * @return array
734 734
 	 * @throws ShareNotFound
735 735
 	 */
Please login to merge, or discard this patch.
Spacing   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -182,7 +182,7 @@  discard block
 block discarded – undo
182 182
 		if ($remoteShare) {
183 183
 			try {
184 184
 				$ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
185
-				$shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time());
185
+				$shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_'.time());
186 186
 				$share->setId($shareId);
187 187
 				list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId);
188 188
 				// remote share was create successfully if we get a valid token as return
@@ -254,11 +254,11 @@  discard block
 block discarded – undo
254 254
 				$failure = true;
255 255
 			}
256 256
 		} catch (\Exception $e) {
257
-			$this->logger->error('Failed to notify remote server of federated share, removing share (' . $e->getMessage() . ')');
257
+			$this->logger->error('Failed to notify remote server of federated share, removing share ('.$e->getMessage().')');
258 258
 			$failure = true;
259 259
 		}
260 260
 
261
-		if($failure) {
261
+		if ($failure) {
262 262
 			$this->removeShareFromTableById($shareId);
263 263
 			$message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable or uses a self-signed certificate.',
264 264
 				[$share->getNode()->getName(), $share->getSharedWith()]);
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
 			->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget())));
310 310
 		$result = $query->execute()->fetchAll();
311 311
 
312
-		if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
312
+		if (isset($result[0]) && (int) $result[0]['remote_id'] > 0) {
313 313
 			return $result[0];
314 314
 		}
315 315
 
@@ -351,7 +351,7 @@  discard block
 block discarded – undo
351 351
 		$qb->execute();
352 352
 		$id = $qb->getLastInsertId();
353 353
 
354
-		return (int)$id;
354
+		return (int) $id;
355 355
 	}
356 356
 
357 357
 	/**
@@ -441,14 +441,14 @@  discard block
 block discarded – undo
441 441
 	public function getRemoteId(IShare $share) {
442 442
 		$query = $this->dbConnection->getQueryBuilder();
443 443
 		$query->select('remote_id')->from('federated_reshares')
444
-			->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
444
+			->where($query->expr()->eq('share_id', $query->createNamedParameter((int) $share->getId())));
445 445
 		$data = $query->execute()->fetch();
446 446
 
447 447
 		if (!is_array($data) || !isset($data['remote_id'])) {
448 448
 			throw new ShareNotFound();
449 449
 		}
450 450
 
451
-		return (int)$data['remote_id'];
451
+		return (int) $data['remote_id'];
452 452
 	}
453 453
 
454 454
 	/**
@@ -479,7 +479,7 @@  discard block
 block discarded – undo
479 479
 			->orderBy('id');
480 480
 
481 481
 		$cursor = $qb->execute();
482
-		while($data = $cursor->fetch()) {
482
+		while ($data = $cursor->fetch()) {
483 483
 			$children[] = $this->createShareObject($data);
484 484
 		}
485 485
 		$cursor->closeCursor();
@@ -608,7 +608,7 @@  discard block
 block discarded – undo
608 608
 			);
609 609
 		}
610 610
 
611
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
611
+		$qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
612 612
 		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
613 613
 
614 614
 		$qb->orderBy('id');
@@ -671,7 +671,7 @@  discard block
 block discarded – undo
671 671
 
672 672
 		$cursor = $qb->execute();
673 673
 		$shares = [];
674
-		while($data = $cursor->fetch()) {
674
+		while ($data = $cursor->fetch()) {
675 675
 			$shares[] = $this->createShareObject($data);
676 676
 		}
677 677
 		$cursor->closeCursor();
@@ -723,7 +723,7 @@  discard block
 block discarded – undo
723 723
 			->execute();
724 724
 
725 725
 		$shares = [];
726
-		while($data = $cursor->fetch()) {
726
+		while ($data = $cursor->fetch()) {
727 727
 			$shares[] = $this->createShareObject($data);
728 728
 		}
729 729
 		$cursor->closeCursor();
@@ -762,7 +762,7 @@  discard block
 block discarded – undo
762 762
 
763 763
 		$cursor = $qb->execute();
764 764
 
765
-		while($data = $cursor->fetch()) {
765
+		while ($data = $cursor->fetch()) {
766 766
 			$shares[] = $this->createShareObject($data);
767 767
 		}
768 768
 		$cursor->closeCursor();
@@ -839,15 +839,15 @@  discard block
 block discarded – undo
839 839
 	private function createShareObject($data) {
840 840
 
841 841
 		$share = new Share($this->rootFolder, $this->userManager);
842
-		$share->setId((int)$data['id'])
843
-			->setShareType((int)$data['share_type'])
844
-			->setPermissions((int)$data['permissions'])
842
+		$share->setId((int) $data['id'])
843
+			->setShareType((int) $data['share_type'])
844
+			->setPermissions((int) $data['permissions'])
845 845
 			->setTarget($data['file_target'])
846
-			->setMailSend((bool)$data['mail_send'])
846
+			->setMailSend((bool) $data['mail_send'])
847 847
 			->setToken($data['token']);
848 848
 
849 849
 		$shareTime = new \DateTime();
850
-		$shareTime->setTimestamp((int)$data['stime']);
850
+		$shareTime->setTimestamp((int) $data['stime']);
851 851
 		$share->setShareTime($shareTime);
852 852
 		$share->setSharedWith($data['share_with']);
853 853
 
@@ -857,13 +857,13 @@  discard block
 block discarded – undo
857 857
 		} else {
858 858
 			//OLD SHARE
859 859
 			$share->setSharedBy($data['uid_owner']);
860
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
860
+			$path = $this->getNode($share->getSharedBy(), (int) $data['file_source']);
861 861
 
862 862
 			$owner = $path->getOwner();
863 863
 			$share->setShareOwner($owner->getUID());
864 864
 		}
865 865
 
866
-		$share->setNodeId((int)$data['file_source']);
866
+		$share->setNodeId((int) $data['file_source']);
867 867
 		$share->setNodeType($data['item_type']);
868 868
 
869 869
 		$share->setProviderId($this->identifier());
Please login to merge, or discard this patch.
Indentation   +954 added lines, -954 removed lines patch added patch discarded remove patch
@@ -50,968 +50,968 @@
 block discarded – undo
50 50
  */
51 51
 class FederatedShareProvider implements IShareProvider {
52 52
 
53
-	const SHARE_TYPE_REMOTE = 6;
54
-
55
-	/** @var IDBConnection */
56
-	private $dbConnection;
57
-
58
-	/** @var AddressHandler */
59
-	private $addressHandler;
60
-
61
-	/** @var Notifications */
62
-	private $notifications;
63
-
64
-	/** @var TokenHandler */
65
-	private $tokenHandler;
66
-
67
-	/** @var IL10N */
68
-	private $l;
69
-
70
-	/** @var ILogger */
71
-	private $logger;
72
-
73
-	/** @var IRootFolder */
74
-	private $rootFolder;
75
-
76
-	/** @var IConfig */
77
-	private $config;
78
-
79
-	/** @var string */
80
-	private $externalShareTable = 'share_external';
81
-
82
-	/** @var IUserManager */
83
-	private $userManager;
84
-
85
-	/** @var ICloudIdManager */
86
-	private $cloudIdManager;
87
-
88
-	/**
89
-	 * DefaultShareProvider constructor.
90
-	 *
91
-	 * @param IDBConnection $connection
92
-	 * @param AddressHandler $addressHandler
93
-	 * @param Notifications $notifications
94
-	 * @param TokenHandler $tokenHandler
95
-	 * @param IL10N $l10n
96
-	 * @param ILogger $logger
97
-	 * @param IRootFolder $rootFolder
98
-	 * @param IConfig $config
99
-	 * @param IUserManager $userManager
100
-	 * @param ICloudIdManager $cloudIdManager
101
-	 */
102
-	public function __construct(
103
-			IDBConnection $connection,
104
-			AddressHandler $addressHandler,
105
-			Notifications $notifications,
106
-			TokenHandler $tokenHandler,
107
-			IL10N $l10n,
108
-			ILogger $logger,
109
-			IRootFolder $rootFolder,
110
-			IConfig $config,
111
-			IUserManager $userManager,
112
-			ICloudIdManager $cloudIdManager
113
-	) {
114
-		$this->dbConnection = $connection;
115
-		$this->addressHandler = $addressHandler;
116
-		$this->notifications = $notifications;
117
-		$this->tokenHandler = $tokenHandler;
118
-		$this->l = $l10n;
119
-		$this->logger = $logger;
120
-		$this->rootFolder = $rootFolder;
121
-		$this->config = $config;
122
-		$this->userManager = $userManager;
123
-		$this->cloudIdManager = $cloudIdManager;
124
-	}
125
-
126
-	/**
127
-	 * Return the identifier of this provider.
128
-	 *
129
-	 * @return string Containing only [a-zA-Z0-9]
130
-	 */
131
-	public function identifier() {
132
-		return 'ocFederatedSharing';
133
-	}
134
-
135
-	/**
136
-	 * Share a path
137
-	 *
138
-	 * @param IShare $share
139
-	 * @return IShare The share object
140
-	 * @throws ShareNotFound
141
-	 * @throws \Exception
142
-	 */
143
-	public function create(IShare $share) {
144
-
145
-		$shareWith = $share->getSharedWith();
146
-		$itemSource = $share->getNodeId();
147
-		$itemType = $share->getNodeType();
148
-		$permissions = $share->getPermissions();
149
-		$sharedBy = $share->getSharedBy();
150
-
151
-		/*
53
+    const SHARE_TYPE_REMOTE = 6;
54
+
55
+    /** @var IDBConnection */
56
+    private $dbConnection;
57
+
58
+    /** @var AddressHandler */
59
+    private $addressHandler;
60
+
61
+    /** @var Notifications */
62
+    private $notifications;
63
+
64
+    /** @var TokenHandler */
65
+    private $tokenHandler;
66
+
67
+    /** @var IL10N */
68
+    private $l;
69
+
70
+    /** @var ILogger */
71
+    private $logger;
72
+
73
+    /** @var IRootFolder */
74
+    private $rootFolder;
75
+
76
+    /** @var IConfig */
77
+    private $config;
78
+
79
+    /** @var string */
80
+    private $externalShareTable = 'share_external';
81
+
82
+    /** @var IUserManager */
83
+    private $userManager;
84
+
85
+    /** @var ICloudIdManager */
86
+    private $cloudIdManager;
87
+
88
+    /**
89
+     * DefaultShareProvider constructor.
90
+     *
91
+     * @param IDBConnection $connection
92
+     * @param AddressHandler $addressHandler
93
+     * @param Notifications $notifications
94
+     * @param TokenHandler $tokenHandler
95
+     * @param IL10N $l10n
96
+     * @param ILogger $logger
97
+     * @param IRootFolder $rootFolder
98
+     * @param IConfig $config
99
+     * @param IUserManager $userManager
100
+     * @param ICloudIdManager $cloudIdManager
101
+     */
102
+    public function __construct(
103
+            IDBConnection $connection,
104
+            AddressHandler $addressHandler,
105
+            Notifications $notifications,
106
+            TokenHandler $tokenHandler,
107
+            IL10N $l10n,
108
+            ILogger $logger,
109
+            IRootFolder $rootFolder,
110
+            IConfig $config,
111
+            IUserManager $userManager,
112
+            ICloudIdManager $cloudIdManager
113
+    ) {
114
+        $this->dbConnection = $connection;
115
+        $this->addressHandler = $addressHandler;
116
+        $this->notifications = $notifications;
117
+        $this->tokenHandler = $tokenHandler;
118
+        $this->l = $l10n;
119
+        $this->logger = $logger;
120
+        $this->rootFolder = $rootFolder;
121
+        $this->config = $config;
122
+        $this->userManager = $userManager;
123
+        $this->cloudIdManager = $cloudIdManager;
124
+    }
125
+
126
+    /**
127
+     * Return the identifier of this provider.
128
+     *
129
+     * @return string Containing only [a-zA-Z0-9]
130
+     */
131
+    public function identifier() {
132
+        return 'ocFederatedSharing';
133
+    }
134
+
135
+    /**
136
+     * Share a path
137
+     *
138
+     * @param IShare $share
139
+     * @return IShare The share object
140
+     * @throws ShareNotFound
141
+     * @throws \Exception
142
+     */
143
+    public function create(IShare $share) {
144
+
145
+        $shareWith = $share->getSharedWith();
146
+        $itemSource = $share->getNodeId();
147
+        $itemType = $share->getNodeType();
148
+        $permissions = $share->getPermissions();
149
+        $sharedBy = $share->getSharedBy();
150
+
151
+        /*
152 152
 		 * Check if file is not already shared with the remote user
153 153
 		 */
154
-		$alreadyShared = $this->getSharedWith($shareWith, self::SHARE_TYPE_REMOTE, $share->getNode(), 1, 0);
155
-		if (!empty($alreadyShared)) {
156
-			$message = 'Sharing %s failed, because this item is already shared with %s';
157
-			$message_t = $this->l->t('Sharing %s failed, because this item is already shared with %s', array($share->getNode()->getName(), $shareWith));
158
-			$this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
159
-			throw new \Exception($message_t);
160
-		}
161
-
162
-
163
-		// don't allow federated shares if source and target server are the same
164
-		$cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
165
-		$currentServer = $this->addressHandler->generateRemoteURL();
166
-		$currentUser = $sharedBy;
167
-		if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) {
168
-			$message = 'Not allowed to create a federated share with the same user.';
169
-			$message_t = $this->l->t('Not allowed to create a federated share with the same user');
170
-			$this->logger->debug($message, ['app' => 'Federated File Sharing']);
171
-			throw new \Exception($message_t);
172
-		}
173
-
174
-
175
-		$share->setSharedWith($cloudId->getId());
176
-
177
-		try {
178
-			$remoteShare = $this->getShareFromExternalShareTable($share);
179
-		} catch (ShareNotFound $e) {
180
-			$remoteShare = null;
181
-		}
182
-
183
-		if ($remoteShare) {
184
-			try {
185
-				$ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
186
-				$shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time());
187
-				$share->setId($shareId);
188
-				list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId);
189
-				// remote share was create successfully if we get a valid token as return
190
-				$send = is_string($token) && $token !== '';
191
-			} catch (\Exception $e) {
192
-				// fall back to old re-share behavior if the remote server
193
-				// doesn't support flat re-shares (was introduced with Nextcloud 9.1)
194
-				$this->removeShareFromTable($share);
195
-				$shareId = $this->createFederatedShare($share);
196
-			}
197
-			if ($send) {
198
-				$this->updateSuccessfulReshare($shareId, $token);
199
-				$this->storeRemoteId($shareId, $remoteId);
200
-			} else {
201
-				$this->removeShareFromTable($share);
202
-				$message_t = $this->l->t('File is already shared with %s', [$shareWith]);
203
-				throw new \Exception($message_t);
204
-			}
205
-
206
-		} else {
207
-			$shareId = $this->createFederatedShare($share);
208
-		}
209
-
210
-		$data = $this->getRawShare($shareId);
211
-		return $this->createShareObject($data);
212
-	}
213
-
214
-	/**
215
-	 * create federated share and inform the recipient
216
-	 *
217
-	 * @param IShare $share
218
-	 * @return int
219
-	 * @throws ShareNotFound
220
-	 * @throws \Exception
221
-	 */
222
-	protected function createFederatedShare(IShare $share) {
223
-		$token = $this->tokenHandler->generateToken();
224
-		$shareId = $this->addShareToDB(
225
-			$share->getNodeId(),
226
-			$share->getNodeType(),
227
-			$share->getSharedWith(),
228
-			$share->getSharedBy(),
229
-			$share->getShareOwner(),
230
-			$share->getPermissions(),
231
-			$token
232
-		);
233
-
234
-		$failure = false;
235
-
236
-		try {
237
-			$sharedByFederatedId = $share->getSharedBy();
238
-			if ($this->userManager->userExists($sharedByFederatedId)) {
239
-				$cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL());
240
-				$sharedByFederatedId = $cloudId->getId();
241
-			}
242
-			$ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL());
243
-			$send = $this->notifications->sendRemoteShare(
244
-				$token,
245
-				$share->getSharedWith(),
246
-				$share->getNode()->getName(),
247
-				$shareId,
248
-				$share->getShareOwner(),
249
-				$ownerCloudId->getId(),
250
-				$share->getSharedBy(),
251
-				$sharedByFederatedId
252
-			);
253
-
254
-			if ($send === false) {
255
-				$failure = true;
256
-			}
257
-		} catch (\Exception $e) {
258
-			$this->logger->error('Failed to notify remote server of federated share, removing share (' . $e->getMessage() . ')');
259
-			$failure = true;
260
-		}
261
-
262
-		if($failure) {
263
-			$this->removeShareFromTableById($shareId);
264
-			$message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable or uses a self-signed certificate.',
265
-				[$share->getNode()->getName(), $share->getSharedWith()]);
266
-			throw new \Exception($message_t);
267
-		}
268
-
269
-		return $shareId;
270
-
271
-	}
272
-
273
-	/**
274
-	 * @param string $shareWith
275
-	 * @param IShare $share
276
-	 * @param string $shareId internal share Id
277
-	 * @return array
278
-	 * @throws \Exception
279
-	 */
280
-	protected function askOwnerToReShare($shareWith, IShare $share, $shareId) {
281
-
282
-		$remoteShare = $this->getShareFromExternalShareTable($share);
283
-		$token = $remoteShare['share_token'];
284
-		$remoteId = $remoteShare['remote_id'];
285
-		$remote = $remoteShare['remote'];
286
-
287
-		list($token, $remoteId) = $this->notifications->requestReShare(
288
-			$token,
289
-			$remoteId,
290
-			$shareId,
291
-			$remote,
292
-			$shareWith,
293
-			$share->getPermissions()
294
-		);
295
-
296
-		return [$token, $remoteId];
297
-	}
298
-
299
-	/**
300
-	 * get federated share from the share_external table but exclude mounted link shares
301
-	 *
302
-	 * @param IShare $share
303
-	 * @return array
304
-	 * @throws ShareNotFound
305
-	 */
306
-	protected function getShareFromExternalShareTable(IShare $share) {
307
-		$query = $this->dbConnection->getQueryBuilder();
308
-		$query->select('*')->from($this->externalShareTable)
309
-			->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner())))
310
-			->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget())));
311
-		$result = $query->execute()->fetchAll();
312
-
313
-		if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
314
-			return $result[0];
315
-		}
316
-
317
-		throw new ShareNotFound('share not found in share_external table');
318
-	}
319
-
320
-	/**
321
-	 * add share to the database and return the ID
322
-	 *
323
-	 * @param int $itemSource
324
-	 * @param string $itemType
325
-	 * @param string $shareWith
326
-	 * @param string $sharedBy
327
-	 * @param string $uidOwner
328
-	 * @param int $permissions
329
-	 * @param string $token
330
-	 * @return int
331
-	 */
332
-	private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token) {
333
-		$qb = $this->dbConnection->getQueryBuilder();
334
-		$qb->insert('share')
335
-			->setValue('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE))
336
-			->setValue('item_type', $qb->createNamedParameter($itemType))
337
-			->setValue('item_source', $qb->createNamedParameter($itemSource))
338
-			->setValue('file_source', $qb->createNamedParameter($itemSource))
339
-			->setValue('share_with', $qb->createNamedParameter($shareWith))
340
-			->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
341
-			->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
342
-			->setValue('permissions', $qb->createNamedParameter($permissions))
343
-			->setValue('token', $qb->createNamedParameter($token))
344
-			->setValue('stime', $qb->createNamedParameter(time()));
345
-
346
-		/*
154
+        $alreadyShared = $this->getSharedWith($shareWith, self::SHARE_TYPE_REMOTE, $share->getNode(), 1, 0);
155
+        if (!empty($alreadyShared)) {
156
+            $message = 'Sharing %s failed, because this item is already shared with %s';
157
+            $message_t = $this->l->t('Sharing %s failed, because this item is already shared with %s', array($share->getNode()->getName(), $shareWith));
158
+            $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
159
+            throw new \Exception($message_t);
160
+        }
161
+
162
+
163
+        // don't allow federated shares if source and target server are the same
164
+        $cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
165
+        $currentServer = $this->addressHandler->generateRemoteURL();
166
+        $currentUser = $sharedBy;
167
+        if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) {
168
+            $message = 'Not allowed to create a federated share with the same user.';
169
+            $message_t = $this->l->t('Not allowed to create a federated share with the same user');
170
+            $this->logger->debug($message, ['app' => 'Federated File Sharing']);
171
+            throw new \Exception($message_t);
172
+        }
173
+
174
+
175
+        $share->setSharedWith($cloudId->getId());
176
+
177
+        try {
178
+            $remoteShare = $this->getShareFromExternalShareTable($share);
179
+        } catch (ShareNotFound $e) {
180
+            $remoteShare = null;
181
+        }
182
+
183
+        if ($remoteShare) {
184
+            try {
185
+                $ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
186
+                $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time());
187
+                $share->setId($shareId);
188
+                list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId);
189
+                // remote share was create successfully if we get a valid token as return
190
+                $send = is_string($token) && $token !== '';
191
+            } catch (\Exception $e) {
192
+                // fall back to old re-share behavior if the remote server
193
+                // doesn't support flat re-shares (was introduced with Nextcloud 9.1)
194
+                $this->removeShareFromTable($share);
195
+                $shareId = $this->createFederatedShare($share);
196
+            }
197
+            if ($send) {
198
+                $this->updateSuccessfulReshare($shareId, $token);
199
+                $this->storeRemoteId($shareId, $remoteId);
200
+            } else {
201
+                $this->removeShareFromTable($share);
202
+                $message_t = $this->l->t('File is already shared with %s', [$shareWith]);
203
+                throw new \Exception($message_t);
204
+            }
205
+
206
+        } else {
207
+            $shareId = $this->createFederatedShare($share);
208
+        }
209
+
210
+        $data = $this->getRawShare($shareId);
211
+        return $this->createShareObject($data);
212
+    }
213
+
214
+    /**
215
+     * create federated share and inform the recipient
216
+     *
217
+     * @param IShare $share
218
+     * @return int
219
+     * @throws ShareNotFound
220
+     * @throws \Exception
221
+     */
222
+    protected function createFederatedShare(IShare $share) {
223
+        $token = $this->tokenHandler->generateToken();
224
+        $shareId = $this->addShareToDB(
225
+            $share->getNodeId(),
226
+            $share->getNodeType(),
227
+            $share->getSharedWith(),
228
+            $share->getSharedBy(),
229
+            $share->getShareOwner(),
230
+            $share->getPermissions(),
231
+            $token
232
+        );
233
+
234
+        $failure = false;
235
+
236
+        try {
237
+            $sharedByFederatedId = $share->getSharedBy();
238
+            if ($this->userManager->userExists($sharedByFederatedId)) {
239
+                $cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL());
240
+                $sharedByFederatedId = $cloudId->getId();
241
+            }
242
+            $ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL());
243
+            $send = $this->notifications->sendRemoteShare(
244
+                $token,
245
+                $share->getSharedWith(),
246
+                $share->getNode()->getName(),
247
+                $shareId,
248
+                $share->getShareOwner(),
249
+                $ownerCloudId->getId(),
250
+                $share->getSharedBy(),
251
+                $sharedByFederatedId
252
+            );
253
+
254
+            if ($send === false) {
255
+                $failure = true;
256
+            }
257
+        } catch (\Exception $e) {
258
+            $this->logger->error('Failed to notify remote server of federated share, removing share (' . $e->getMessage() . ')');
259
+            $failure = true;
260
+        }
261
+
262
+        if($failure) {
263
+            $this->removeShareFromTableById($shareId);
264
+            $message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable or uses a self-signed certificate.',
265
+                [$share->getNode()->getName(), $share->getSharedWith()]);
266
+            throw new \Exception($message_t);
267
+        }
268
+
269
+        return $shareId;
270
+
271
+    }
272
+
273
+    /**
274
+     * @param string $shareWith
275
+     * @param IShare $share
276
+     * @param string $shareId internal share Id
277
+     * @return array
278
+     * @throws \Exception
279
+     */
280
+    protected function askOwnerToReShare($shareWith, IShare $share, $shareId) {
281
+
282
+        $remoteShare = $this->getShareFromExternalShareTable($share);
283
+        $token = $remoteShare['share_token'];
284
+        $remoteId = $remoteShare['remote_id'];
285
+        $remote = $remoteShare['remote'];
286
+
287
+        list($token, $remoteId) = $this->notifications->requestReShare(
288
+            $token,
289
+            $remoteId,
290
+            $shareId,
291
+            $remote,
292
+            $shareWith,
293
+            $share->getPermissions()
294
+        );
295
+
296
+        return [$token, $remoteId];
297
+    }
298
+
299
+    /**
300
+     * get federated share from the share_external table but exclude mounted link shares
301
+     *
302
+     * @param IShare $share
303
+     * @return array
304
+     * @throws ShareNotFound
305
+     */
306
+    protected function getShareFromExternalShareTable(IShare $share) {
307
+        $query = $this->dbConnection->getQueryBuilder();
308
+        $query->select('*')->from($this->externalShareTable)
309
+            ->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner())))
310
+            ->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget())));
311
+        $result = $query->execute()->fetchAll();
312
+
313
+        if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
314
+            return $result[0];
315
+        }
316
+
317
+        throw new ShareNotFound('share not found in share_external table');
318
+    }
319
+
320
+    /**
321
+     * add share to the database and return the ID
322
+     *
323
+     * @param int $itemSource
324
+     * @param string $itemType
325
+     * @param string $shareWith
326
+     * @param string $sharedBy
327
+     * @param string $uidOwner
328
+     * @param int $permissions
329
+     * @param string $token
330
+     * @return int
331
+     */
332
+    private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token) {
333
+        $qb = $this->dbConnection->getQueryBuilder();
334
+        $qb->insert('share')
335
+            ->setValue('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE))
336
+            ->setValue('item_type', $qb->createNamedParameter($itemType))
337
+            ->setValue('item_source', $qb->createNamedParameter($itemSource))
338
+            ->setValue('file_source', $qb->createNamedParameter($itemSource))
339
+            ->setValue('share_with', $qb->createNamedParameter($shareWith))
340
+            ->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
341
+            ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
342
+            ->setValue('permissions', $qb->createNamedParameter($permissions))
343
+            ->setValue('token', $qb->createNamedParameter($token))
344
+            ->setValue('stime', $qb->createNamedParameter(time()));
345
+
346
+        /*
347 347
 		 * Added to fix https://github.com/owncloud/core/issues/22215
348 348
 		 * Can be removed once we get rid of ajax/share.php
349 349
 		 */
350
-		$qb->setValue('file_target', $qb->createNamedParameter(''));
351
-
352
-		$qb->execute();
353
-		$id = $qb->getLastInsertId();
354
-
355
-		return (int)$id;
356
-	}
357
-
358
-	/**
359
-	 * Update a share
360
-	 *
361
-	 * @param IShare $share
362
-	 * @return IShare The share object
363
-	 */
364
-	public function update(IShare $share) {
365
-		/*
350
+        $qb->setValue('file_target', $qb->createNamedParameter(''));
351
+
352
+        $qb->execute();
353
+        $id = $qb->getLastInsertId();
354
+
355
+        return (int)$id;
356
+    }
357
+
358
+    /**
359
+     * Update a share
360
+     *
361
+     * @param IShare $share
362
+     * @return IShare The share object
363
+     */
364
+    public function update(IShare $share) {
365
+        /*
366 366
 		 * We allow updating the permissions of federated shares
367 367
 		 */
368
-		$qb = $this->dbConnection->getQueryBuilder();
369
-			$qb->update('share')
370
-				->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
371
-				->set('permissions', $qb->createNamedParameter($share->getPermissions()))
372
-				->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
373
-				->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
374
-				->execute();
375
-
376
-		// send the updated permission to the owner/initiator, if they are not the same
377
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
378
-			$this->sendPermissionUpdate($share);
379
-		}
380
-
381
-		return $share;
382
-	}
383
-
384
-	/**
385
-	 * send the updated permission to the owner/initiator, if they are not the same
386
-	 *
387
-	 * @param IShare $share
388
-	 * @throws ShareNotFound
389
-	 * @throws \OC\HintException
390
-	 */
391
-	protected function sendPermissionUpdate(IShare $share) {
392
-		$remoteId = $this->getRemoteId($share);
393
-		// if the local user is the owner we send the permission change to the initiator
394
-		if ($this->userManager->userExists($share->getShareOwner())) {
395
-			list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
396
-		} else { // ... if not we send the permission change to the owner
397
-			list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
398
-		}
399
-		$this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions());
400
-	}
401
-
402
-
403
-	/**
404
-	 * update successful reShare with the correct token
405
-	 *
406
-	 * @param int $shareId
407
-	 * @param string $token
408
-	 */
409
-	protected function updateSuccessfulReShare($shareId, $token) {
410
-		$query = $this->dbConnection->getQueryBuilder();
411
-		$query->update('share')
412
-			->where($query->expr()->eq('id', $query->createNamedParameter($shareId)))
413
-			->set('token', $query->createNamedParameter($token))
414
-			->execute();
415
-	}
416
-
417
-	/**
418
-	 * store remote ID in federated reShare table
419
-	 *
420
-	 * @param $shareId
421
-	 * @param $remoteId
422
-	 */
423
-	public function storeRemoteId($shareId, $remoteId) {
424
-		$query = $this->dbConnection->getQueryBuilder();
425
-		$query->insert('federated_reshares')
426
-			->values(
427
-				[
428
-					'share_id' =>  $query->createNamedParameter($shareId),
429
-					'remote_id' => $query->createNamedParameter($remoteId),
430
-				]
431
-			);
432
-		$query->execute();
433
-	}
434
-
435
-	/**
436
-	 * get share ID on remote server for federated re-shares
437
-	 *
438
-	 * @param IShare $share
439
-	 * @return int
440
-	 * @throws ShareNotFound
441
-	 */
442
-	public function getRemoteId(IShare $share) {
443
-		$query = $this->dbConnection->getQueryBuilder();
444
-		$query->select('remote_id')->from('federated_reshares')
445
-			->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
446
-		$data = $query->execute()->fetch();
447
-
448
-		if (!is_array($data) || !isset($data['remote_id'])) {
449
-			throw new ShareNotFound();
450
-		}
451
-
452
-		return (int)$data['remote_id'];
453
-	}
454
-
455
-	/**
456
-	 * @inheritdoc
457
-	 */
458
-	public function move(IShare $share, $recipient) {
459
-		/*
368
+        $qb = $this->dbConnection->getQueryBuilder();
369
+            $qb->update('share')
370
+                ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
371
+                ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
372
+                ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
373
+                ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
374
+                ->execute();
375
+
376
+        // send the updated permission to the owner/initiator, if they are not the same
377
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
378
+            $this->sendPermissionUpdate($share);
379
+        }
380
+
381
+        return $share;
382
+    }
383
+
384
+    /**
385
+     * send the updated permission to the owner/initiator, if they are not the same
386
+     *
387
+     * @param IShare $share
388
+     * @throws ShareNotFound
389
+     * @throws \OC\HintException
390
+     */
391
+    protected function sendPermissionUpdate(IShare $share) {
392
+        $remoteId = $this->getRemoteId($share);
393
+        // if the local user is the owner we send the permission change to the initiator
394
+        if ($this->userManager->userExists($share->getShareOwner())) {
395
+            list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
396
+        } else { // ... if not we send the permission change to the owner
397
+            list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
398
+        }
399
+        $this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions());
400
+    }
401
+
402
+
403
+    /**
404
+     * update successful reShare with the correct token
405
+     *
406
+     * @param int $shareId
407
+     * @param string $token
408
+     */
409
+    protected function updateSuccessfulReShare($shareId, $token) {
410
+        $query = $this->dbConnection->getQueryBuilder();
411
+        $query->update('share')
412
+            ->where($query->expr()->eq('id', $query->createNamedParameter($shareId)))
413
+            ->set('token', $query->createNamedParameter($token))
414
+            ->execute();
415
+    }
416
+
417
+    /**
418
+     * store remote ID in federated reShare table
419
+     *
420
+     * @param $shareId
421
+     * @param $remoteId
422
+     */
423
+    public function storeRemoteId($shareId, $remoteId) {
424
+        $query = $this->dbConnection->getQueryBuilder();
425
+        $query->insert('federated_reshares')
426
+            ->values(
427
+                [
428
+                    'share_id' =>  $query->createNamedParameter($shareId),
429
+                    'remote_id' => $query->createNamedParameter($remoteId),
430
+                ]
431
+            );
432
+        $query->execute();
433
+    }
434
+
435
+    /**
436
+     * get share ID on remote server for federated re-shares
437
+     *
438
+     * @param IShare $share
439
+     * @return int
440
+     * @throws ShareNotFound
441
+     */
442
+    public function getRemoteId(IShare $share) {
443
+        $query = $this->dbConnection->getQueryBuilder();
444
+        $query->select('remote_id')->from('federated_reshares')
445
+            ->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
446
+        $data = $query->execute()->fetch();
447
+
448
+        if (!is_array($data) || !isset($data['remote_id'])) {
449
+            throw new ShareNotFound();
450
+        }
451
+
452
+        return (int)$data['remote_id'];
453
+    }
454
+
455
+    /**
456
+     * @inheritdoc
457
+     */
458
+    public function move(IShare $share, $recipient) {
459
+        /*
460 460
 		 * This function does nothing yet as it is just for outgoing
461 461
 		 * federated shares.
462 462
 		 */
463
-		return $share;
464
-	}
465
-
466
-	/**
467
-	 * Get all children of this share
468
-	 *
469
-	 * @param IShare $parent
470
-	 * @return IShare[]
471
-	 */
472
-	public function getChildren(IShare $parent) {
473
-		$children = [];
474
-
475
-		$qb = $this->dbConnection->getQueryBuilder();
476
-		$qb->select('*')
477
-			->from('share')
478
-			->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
479
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)))
480
-			->orderBy('id');
481
-
482
-		$cursor = $qb->execute();
483
-		while($data = $cursor->fetch()) {
484
-			$children[] = $this->createShareObject($data);
485
-		}
486
-		$cursor->closeCursor();
487
-
488
-		return $children;
489
-	}
490
-
491
-	/**
492
-	 * Delete a share (owner unShares the file)
493
-	 *
494
-	 * @param IShare $share
495
-	 */
496
-	public function delete(IShare $share) {
497
-
498
-		list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith());
499
-
500
-		$isOwner = false;
501
-
502
-		$this->removeShareFromTable($share);
503
-
504
-		// if the local user is the owner we can send the unShare request directly...
505
-		if ($this->userManager->userExists($share->getShareOwner())) {
506
-			$this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken());
507
-			$this->revokeShare($share, true);
508
-			$isOwner = true;
509
-		} else { // ... if not we need to correct ID for the unShare request
510
-			$remoteId = $this->getRemoteId($share);
511
-			$this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken());
512
-			$this->revokeShare($share, false);
513
-		}
514
-
515
-		// send revoke notification to the other user, if initiator and owner are not the same user
516
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
517
-			$remoteId = $this->getRemoteId($share);
518
-			if ($isOwner) {
519
-				list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
520
-			} else {
521
-				list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
522
-			}
523
-			$this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
524
-		}
525
-	}
526
-
527
-	/**
528
-	 * in case of a re-share we need to send the other use (initiator or owner)
529
-	 * a message that the file was unshared
530
-	 *
531
-	 * @param IShare $share
532
-	 * @param bool $isOwner the user can either be the owner or the user who re-sahred it
533
-	 * @throws ShareNotFound
534
-	 * @throws \OC\HintException
535
-	 */
536
-	protected function revokeShare($share, $isOwner) {
537
-		// also send a unShare request to the initiator, if this is a different user than the owner
538
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
539
-			if ($isOwner) {
540
-				list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
541
-			} else {
542
-				list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
543
-			}
544
-			$remoteId = $this->getRemoteId($share);
545
-			$this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
546
-		}
547
-	}
548
-
549
-	/**
550
-	 * remove share from table
551
-	 *
552
-	 * @param IShare $share
553
-	 */
554
-	public function removeShareFromTable(IShare $share) {
555
-		$this->removeShareFromTableById($share->getId());
556
-	}
557
-
558
-	/**
559
-	 * remove share from table
560
-	 *
561
-	 * @param string $shareId
562
-	 */
563
-	private function removeShareFromTableById($shareId) {
564
-		$qb = $this->dbConnection->getQueryBuilder();
565
-		$qb->delete('share')
566
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
567
-		$qb->execute();
568
-
569
-		$qb->delete('federated_reshares')
570
-			->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId)));
571
-		$qb->execute();
572
-	}
573
-
574
-	/**
575
-	 * @inheritdoc
576
-	 */
577
-	public function deleteFromSelf(IShare $share, $recipient) {
578
-		// nothing to do here. Technically deleteFromSelf in the context of federated
579
-		// shares is a umount of a external storage. This is handled here
580
-		// apps/files_sharing/lib/external/manager.php
581
-		// TODO move this code over to this app
582
-		return;
583
-	}
584
-
585
-
586
-	public function getSharesInFolder($userId, Folder $node, $reshares) {
587
-		$qb = $this->dbConnection->getQueryBuilder();
588
-		$qb->select('*')
589
-			->from('share', 's')
590
-			->andWhere($qb->expr()->orX(
591
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
592
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
593
-			))
594
-			->andWhere(
595
-				$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE))
596
-			);
597
-
598
-		/**
599
-		 * Reshares for this user are shares where they are the owner.
600
-		 */
601
-		if ($reshares === false) {
602
-			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
603
-		} else {
604
-			$qb->andWhere(
605
-				$qb->expr()->orX(
606
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
607
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
608
-				)
609
-			);
610
-		}
611
-
612
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
613
-		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
614
-
615
-		$qb->orderBy('id');
616
-
617
-		$cursor = $qb->execute();
618
-		$shares = [];
619
-		while ($data = $cursor->fetch()) {
620
-			$shares[$data['fileid']][] = $this->createShareObject($data);
621
-		}
622
-		$cursor->closeCursor();
623
-
624
-		return $shares;
625
-	}
626
-
627
-	/**
628
-	 * @inheritdoc
629
-	 */
630
-	public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
631
-		$qb = $this->dbConnection->getQueryBuilder();
632
-		$qb->select('*')
633
-			->from('share');
634
-
635
-		$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
636
-
637
-		/**
638
-		 * Reshares for this user are shares where they are the owner.
639
-		 */
640
-		if ($reshares === false) {
641
-			//Special case for old shares created via the web UI
642
-			$or1 = $qb->expr()->andX(
643
-				$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
644
-				$qb->expr()->isNull('uid_initiator')
645
-			);
646
-
647
-			$qb->andWhere(
648
-				$qb->expr()->orX(
649
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
650
-					$or1
651
-				)
652
-			);
653
-		} else {
654
-			$qb->andWhere(
655
-				$qb->expr()->orX(
656
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
657
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
658
-				)
659
-			);
660
-		}
661
-
662
-		if ($node !== null) {
663
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
664
-		}
665
-
666
-		if ($limit !== -1) {
667
-			$qb->setMaxResults($limit);
668
-		}
669
-
670
-		$qb->setFirstResult($offset);
671
-		$qb->orderBy('id');
672
-
673
-		$cursor = $qb->execute();
674
-		$shares = [];
675
-		while($data = $cursor->fetch()) {
676
-			$shares[] = $this->createShareObject($data);
677
-		}
678
-		$cursor->closeCursor();
679
-
680
-		return $shares;
681
-	}
682
-
683
-	/**
684
-	 * @inheritdoc
685
-	 */
686
-	public function getShareById($id, $recipientId = null) {
687
-		$qb = $this->dbConnection->getQueryBuilder();
688
-
689
-		$qb->select('*')
690
-			->from('share')
691
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
692
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
693
-
694
-		$cursor = $qb->execute();
695
-		$data = $cursor->fetch();
696
-		$cursor->closeCursor();
697
-
698
-		if ($data === false) {
699
-			throw new ShareNotFound();
700
-		}
701
-
702
-		try {
703
-			$share = $this->createShareObject($data);
704
-		} catch (InvalidShare $e) {
705
-			throw new ShareNotFound();
706
-		}
707
-
708
-		return $share;
709
-	}
710
-
711
-	/**
712
-	 * Get shares for a given path
713
-	 *
714
-	 * @param \OCP\Files\Node $path
715
-	 * @return IShare[]
716
-	 */
717
-	public function getSharesByPath(Node $path) {
718
-		$qb = $this->dbConnection->getQueryBuilder();
719
-
720
-		$cursor = $qb->select('*')
721
-			->from('share')
722
-			->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
723
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)))
724
-			->execute();
725
-
726
-		$shares = [];
727
-		while($data = $cursor->fetch()) {
728
-			$shares[] = $this->createShareObject($data);
729
-		}
730
-		$cursor->closeCursor();
731
-
732
-		return $shares;
733
-	}
734
-
735
-	/**
736
-	 * @inheritdoc
737
-	 */
738
-	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
739
-		/** @var IShare[] $shares */
740
-		$shares = [];
741
-
742
-		//Get shares directly with this user
743
-		$qb = $this->dbConnection->getQueryBuilder();
744
-		$qb->select('*')
745
-			->from('share');
746
-
747
-		// Order by id
748
-		$qb->orderBy('id');
749
-
750
-		// Set limit and offset
751
-		if ($limit !== -1) {
752
-			$qb->setMaxResults($limit);
753
-		}
754
-		$qb->setFirstResult($offset);
755
-
756
-		$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
757
-		$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
758
-
759
-		// Filter by node if provided
760
-		if ($node !== null) {
761
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
762
-		}
763
-
764
-		$cursor = $qb->execute();
765
-
766
-		while($data = $cursor->fetch()) {
767
-			$shares[] = $this->createShareObject($data);
768
-		}
769
-		$cursor->closeCursor();
770
-
771
-
772
-		return $shares;
773
-	}
774
-
775
-	/**
776
-	 * Get a share by token
777
-	 *
778
-	 * @param string $token
779
-	 * @return IShare
780
-	 * @throws ShareNotFound
781
-	 */
782
-	public function getShareByToken($token) {
783
-		$qb = $this->dbConnection->getQueryBuilder();
784
-
785
-		$cursor = $qb->select('*')
786
-			->from('share')
787
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)))
788
-			->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
789
-			->execute();
790
-
791
-		$data = $cursor->fetch();
792
-
793
-		if ($data === false) {
794
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
795
-		}
796
-
797
-		try {
798
-			$share = $this->createShareObject($data);
799
-		} catch (InvalidShare $e) {
800
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
801
-		}
802
-
803
-		return $share;
804
-	}
805
-
806
-	/**
807
-	 * get database row of a give share
808
-	 *
809
-	 * @param $id
810
-	 * @return array
811
-	 * @throws ShareNotFound
812
-	 */
813
-	private function getRawShare($id) {
814
-
815
-		// Now fetch the inserted share and create a complete share object
816
-		$qb = $this->dbConnection->getQueryBuilder();
817
-		$qb->select('*')
818
-			->from('share')
819
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
820
-
821
-		$cursor = $qb->execute();
822
-		$data = $cursor->fetch();
823
-		$cursor->closeCursor();
824
-
825
-		if ($data === false) {
826
-			throw new ShareNotFound;
827
-		}
828
-
829
-		return $data;
830
-	}
831
-
832
-	/**
833
-	 * Create a share object from an database row
834
-	 *
835
-	 * @param array $data
836
-	 * @return IShare
837
-	 * @throws InvalidShare
838
-	 * @throws ShareNotFound
839
-	 */
840
-	private function createShareObject($data) {
841
-
842
-		$share = new Share($this->rootFolder, $this->userManager);
843
-		$share->setId((int)$data['id'])
844
-			->setShareType((int)$data['share_type'])
845
-			->setPermissions((int)$data['permissions'])
846
-			->setTarget($data['file_target'])
847
-			->setMailSend((bool)$data['mail_send'])
848
-			->setToken($data['token']);
849
-
850
-		$shareTime = new \DateTime();
851
-		$shareTime->setTimestamp((int)$data['stime']);
852
-		$share->setShareTime($shareTime);
853
-		$share->setSharedWith($data['share_with']);
854
-
855
-		if ($data['uid_initiator'] !== null) {
856
-			$share->setShareOwner($data['uid_owner']);
857
-			$share->setSharedBy($data['uid_initiator']);
858
-		} else {
859
-			//OLD SHARE
860
-			$share->setSharedBy($data['uid_owner']);
861
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
862
-
863
-			$owner = $path->getOwner();
864
-			$share->setShareOwner($owner->getUID());
865
-		}
866
-
867
-		$share->setNodeId((int)$data['file_source']);
868
-		$share->setNodeType($data['item_type']);
869
-
870
-		$share->setProviderId($this->identifier());
871
-
872
-		return $share;
873
-	}
874
-
875
-	/**
876
-	 * Get the node with file $id for $user
877
-	 *
878
-	 * @param string $userId
879
-	 * @param int $id
880
-	 * @return \OCP\Files\File|\OCP\Files\Folder
881
-	 * @throws InvalidShare
882
-	 */
883
-	private function getNode($userId, $id) {
884
-		try {
885
-			$userFolder = $this->rootFolder->getUserFolder($userId);
886
-		} catch (NotFoundException $e) {
887
-			throw new InvalidShare();
888
-		}
889
-
890
-		$nodes = $userFolder->getById($id);
891
-
892
-		if (empty($nodes)) {
893
-			throw new InvalidShare();
894
-		}
895
-
896
-		return $nodes[0];
897
-	}
898
-
899
-	/**
900
-	 * A user is deleted from the system
901
-	 * So clean up the relevant shares.
902
-	 *
903
-	 * @param string $uid
904
-	 * @param int $shareType
905
-	 */
906
-	public function userDeleted($uid, $shareType) {
907
-		//TODO: probabaly a good idea to send unshare info to remote servers
908
-
909
-		$qb = $this->dbConnection->getQueryBuilder();
910
-
911
-		$qb->delete('share')
912
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
913
-			->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
914
-			->execute();
915
-	}
916
-
917
-	/**
918
-	 * This provider does not handle groups
919
-	 *
920
-	 * @param string $gid
921
-	 */
922
-	public function groupDeleted($gid) {
923
-		// We don't handle groups here
924
-		return;
925
-	}
926
-
927
-	/**
928
-	 * This provider does not handle groups
929
-	 *
930
-	 * @param string $uid
931
-	 * @param string $gid
932
-	 */
933
-	public function userDeletedFromGroup($uid, $gid) {
934
-		// We don't handle groups here
935
-		return;
936
-	}
937
-
938
-	/**
939
-	 * check if users from other Nextcloud instances are allowed to mount public links share by this instance
940
-	 *
941
-	 * @return bool
942
-	 */
943
-	public function isOutgoingServer2serverShareEnabled() {
944
-		$result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes');
945
-		return ($result === 'yes');
946
-	}
947
-
948
-	/**
949
-	 * check if users are allowed to mount public links from other Nextclouds
950
-	 *
951
-	 * @return bool
952
-	 */
953
-	public function isIncomingServer2serverShareEnabled() {
954
-		$result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes');
955
-		return ($result === 'yes');
956
-	}
957
-
958
-	/**
959
-	 * Check if querying sharees on the lookup server is enabled
960
-	 *
961
-	 * @return bool
962
-	 */
963
-	public function isLookupServerQueriesEnabled() {
964
-		$result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no');
965
-		return ($result === 'yes');
966
-	}
967
-
968
-
969
-	/**
970
-	 * Check if it is allowed to publish user specific data to the lookup server
971
-	 *
972
-	 * @return bool
973
-	 */
974
-	public function isLookupServerUploadEnabled() {
975
-		$result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes');
976
-		return ($result === 'yes');
977
-	}
978
-
979
-	/**
980
-	 * @inheritdoc
981
-	 */
982
-	public function getAccessList($nodes, $currentAccess) {
983
-		$ids = [];
984
-		foreach ($nodes as $node) {
985
-			$ids[] = $node->getId();
986
-		}
987
-
988
-		$qb = $this->dbConnection->getQueryBuilder();
989
-		$qb->select('share_with', 'token', 'file_source')
990
-			->from('share')
991
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
992
-			->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
993
-			->andWhere($qb->expr()->orX(
994
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
995
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
996
-			));
997
-		$cursor = $qb->execute();
998
-
999
-		if ($currentAccess === false) {
1000
-			$remote = $cursor->fetch() !== false;
1001
-			$cursor->closeCursor();
1002
-
1003
-			return ['remote' => $remote];
1004
-		}
1005
-
1006
-		$remote = [];
1007
-		while ($row = $cursor->fetch()) {
1008
-			$remote[$row['share_with']] = [
1009
-				'node_id' => $row['file_source'],
1010
-				'token' => $row['token'],
1011
-			];
1012
-		}
1013
-		$cursor->closeCursor();
1014
-
1015
-		return ['remote' => $remote];
1016
-	}
463
+        return $share;
464
+    }
465
+
466
+    /**
467
+     * Get all children of this share
468
+     *
469
+     * @param IShare $parent
470
+     * @return IShare[]
471
+     */
472
+    public function getChildren(IShare $parent) {
473
+        $children = [];
474
+
475
+        $qb = $this->dbConnection->getQueryBuilder();
476
+        $qb->select('*')
477
+            ->from('share')
478
+            ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
479
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)))
480
+            ->orderBy('id');
481
+
482
+        $cursor = $qb->execute();
483
+        while($data = $cursor->fetch()) {
484
+            $children[] = $this->createShareObject($data);
485
+        }
486
+        $cursor->closeCursor();
487
+
488
+        return $children;
489
+    }
490
+
491
+    /**
492
+     * Delete a share (owner unShares the file)
493
+     *
494
+     * @param IShare $share
495
+     */
496
+    public function delete(IShare $share) {
497
+
498
+        list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith());
499
+
500
+        $isOwner = false;
501
+
502
+        $this->removeShareFromTable($share);
503
+
504
+        // if the local user is the owner we can send the unShare request directly...
505
+        if ($this->userManager->userExists($share->getShareOwner())) {
506
+            $this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken());
507
+            $this->revokeShare($share, true);
508
+            $isOwner = true;
509
+        } else { // ... if not we need to correct ID for the unShare request
510
+            $remoteId = $this->getRemoteId($share);
511
+            $this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken());
512
+            $this->revokeShare($share, false);
513
+        }
514
+
515
+        // send revoke notification to the other user, if initiator and owner are not the same user
516
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
517
+            $remoteId = $this->getRemoteId($share);
518
+            if ($isOwner) {
519
+                list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
520
+            } else {
521
+                list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
522
+            }
523
+            $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
524
+        }
525
+    }
526
+
527
+    /**
528
+     * in case of a re-share we need to send the other use (initiator or owner)
529
+     * a message that the file was unshared
530
+     *
531
+     * @param IShare $share
532
+     * @param bool $isOwner the user can either be the owner or the user who re-sahred it
533
+     * @throws ShareNotFound
534
+     * @throws \OC\HintException
535
+     */
536
+    protected function revokeShare($share, $isOwner) {
537
+        // also send a unShare request to the initiator, if this is a different user than the owner
538
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
539
+            if ($isOwner) {
540
+                list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
541
+            } else {
542
+                list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
543
+            }
544
+            $remoteId = $this->getRemoteId($share);
545
+            $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
546
+        }
547
+    }
548
+
549
+    /**
550
+     * remove share from table
551
+     *
552
+     * @param IShare $share
553
+     */
554
+    public function removeShareFromTable(IShare $share) {
555
+        $this->removeShareFromTableById($share->getId());
556
+    }
557
+
558
+    /**
559
+     * remove share from table
560
+     *
561
+     * @param string $shareId
562
+     */
563
+    private function removeShareFromTableById($shareId) {
564
+        $qb = $this->dbConnection->getQueryBuilder();
565
+        $qb->delete('share')
566
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
567
+        $qb->execute();
568
+
569
+        $qb->delete('federated_reshares')
570
+            ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId)));
571
+        $qb->execute();
572
+    }
573
+
574
+    /**
575
+     * @inheritdoc
576
+     */
577
+    public function deleteFromSelf(IShare $share, $recipient) {
578
+        // nothing to do here. Technically deleteFromSelf in the context of federated
579
+        // shares is a umount of a external storage. This is handled here
580
+        // apps/files_sharing/lib/external/manager.php
581
+        // TODO move this code over to this app
582
+        return;
583
+    }
584
+
585
+
586
+    public function getSharesInFolder($userId, Folder $node, $reshares) {
587
+        $qb = $this->dbConnection->getQueryBuilder();
588
+        $qb->select('*')
589
+            ->from('share', 's')
590
+            ->andWhere($qb->expr()->orX(
591
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
592
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
593
+            ))
594
+            ->andWhere(
595
+                $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE))
596
+            );
597
+
598
+        /**
599
+         * Reshares for this user are shares where they are the owner.
600
+         */
601
+        if ($reshares === false) {
602
+            $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
603
+        } else {
604
+            $qb->andWhere(
605
+                $qb->expr()->orX(
606
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
607
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
608
+                )
609
+            );
610
+        }
611
+
612
+        $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
613
+        $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
614
+
615
+        $qb->orderBy('id');
616
+
617
+        $cursor = $qb->execute();
618
+        $shares = [];
619
+        while ($data = $cursor->fetch()) {
620
+            $shares[$data['fileid']][] = $this->createShareObject($data);
621
+        }
622
+        $cursor->closeCursor();
623
+
624
+        return $shares;
625
+    }
626
+
627
+    /**
628
+     * @inheritdoc
629
+     */
630
+    public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
631
+        $qb = $this->dbConnection->getQueryBuilder();
632
+        $qb->select('*')
633
+            ->from('share');
634
+
635
+        $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
636
+
637
+        /**
638
+         * Reshares for this user are shares where they are the owner.
639
+         */
640
+        if ($reshares === false) {
641
+            //Special case for old shares created via the web UI
642
+            $or1 = $qb->expr()->andX(
643
+                $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
644
+                $qb->expr()->isNull('uid_initiator')
645
+            );
646
+
647
+            $qb->andWhere(
648
+                $qb->expr()->orX(
649
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
650
+                    $or1
651
+                )
652
+            );
653
+        } else {
654
+            $qb->andWhere(
655
+                $qb->expr()->orX(
656
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
657
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
658
+                )
659
+            );
660
+        }
661
+
662
+        if ($node !== null) {
663
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
664
+        }
665
+
666
+        if ($limit !== -1) {
667
+            $qb->setMaxResults($limit);
668
+        }
669
+
670
+        $qb->setFirstResult($offset);
671
+        $qb->orderBy('id');
672
+
673
+        $cursor = $qb->execute();
674
+        $shares = [];
675
+        while($data = $cursor->fetch()) {
676
+            $shares[] = $this->createShareObject($data);
677
+        }
678
+        $cursor->closeCursor();
679
+
680
+        return $shares;
681
+    }
682
+
683
+    /**
684
+     * @inheritdoc
685
+     */
686
+    public function getShareById($id, $recipientId = null) {
687
+        $qb = $this->dbConnection->getQueryBuilder();
688
+
689
+        $qb->select('*')
690
+            ->from('share')
691
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
692
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
693
+
694
+        $cursor = $qb->execute();
695
+        $data = $cursor->fetch();
696
+        $cursor->closeCursor();
697
+
698
+        if ($data === false) {
699
+            throw new ShareNotFound();
700
+        }
701
+
702
+        try {
703
+            $share = $this->createShareObject($data);
704
+        } catch (InvalidShare $e) {
705
+            throw new ShareNotFound();
706
+        }
707
+
708
+        return $share;
709
+    }
710
+
711
+    /**
712
+     * Get shares for a given path
713
+     *
714
+     * @param \OCP\Files\Node $path
715
+     * @return IShare[]
716
+     */
717
+    public function getSharesByPath(Node $path) {
718
+        $qb = $this->dbConnection->getQueryBuilder();
719
+
720
+        $cursor = $qb->select('*')
721
+            ->from('share')
722
+            ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
723
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)))
724
+            ->execute();
725
+
726
+        $shares = [];
727
+        while($data = $cursor->fetch()) {
728
+            $shares[] = $this->createShareObject($data);
729
+        }
730
+        $cursor->closeCursor();
731
+
732
+        return $shares;
733
+    }
734
+
735
+    /**
736
+     * @inheritdoc
737
+     */
738
+    public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
739
+        /** @var IShare[] $shares */
740
+        $shares = [];
741
+
742
+        //Get shares directly with this user
743
+        $qb = $this->dbConnection->getQueryBuilder();
744
+        $qb->select('*')
745
+            ->from('share');
746
+
747
+        // Order by id
748
+        $qb->orderBy('id');
749
+
750
+        // Set limit and offset
751
+        if ($limit !== -1) {
752
+            $qb->setMaxResults($limit);
753
+        }
754
+        $qb->setFirstResult($offset);
755
+
756
+        $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
757
+        $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
758
+
759
+        // Filter by node if provided
760
+        if ($node !== null) {
761
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
762
+        }
763
+
764
+        $cursor = $qb->execute();
765
+
766
+        while($data = $cursor->fetch()) {
767
+            $shares[] = $this->createShareObject($data);
768
+        }
769
+        $cursor->closeCursor();
770
+
771
+
772
+        return $shares;
773
+    }
774
+
775
+    /**
776
+     * Get a share by token
777
+     *
778
+     * @param string $token
779
+     * @return IShare
780
+     * @throws ShareNotFound
781
+     */
782
+    public function getShareByToken($token) {
783
+        $qb = $this->dbConnection->getQueryBuilder();
784
+
785
+        $cursor = $qb->select('*')
786
+            ->from('share')
787
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)))
788
+            ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
789
+            ->execute();
790
+
791
+        $data = $cursor->fetch();
792
+
793
+        if ($data === false) {
794
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
795
+        }
796
+
797
+        try {
798
+            $share = $this->createShareObject($data);
799
+        } catch (InvalidShare $e) {
800
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
801
+        }
802
+
803
+        return $share;
804
+    }
805
+
806
+    /**
807
+     * get database row of a give share
808
+     *
809
+     * @param $id
810
+     * @return array
811
+     * @throws ShareNotFound
812
+     */
813
+    private function getRawShare($id) {
814
+
815
+        // Now fetch the inserted share and create a complete share object
816
+        $qb = $this->dbConnection->getQueryBuilder();
817
+        $qb->select('*')
818
+            ->from('share')
819
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
820
+
821
+        $cursor = $qb->execute();
822
+        $data = $cursor->fetch();
823
+        $cursor->closeCursor();
824
+
825
+        if ($data === false) {
826
+            throw new ShareNotFound;
827
+        }
828
+
829
+        return $data;
830
+    }
831
+
832
+    /**
833
+     * Create a share object from an database row
834
+     *
835
+     * @param array $data
836
+     * @return IShare
837
+     * @throws InvalidShare
838
+     * @throws ShareNotFound
839
+     */
840
+    private function createShareObject($data) {
841
+
842
+        $share = new Share($this->rootFolder, $this->userManager);
843
+        $share->setId((int)$data['id'])
844
+            ->setShareType((int)$data['share_type'])
845
+            ->setPermissions((int)$data['permissions'])
846
+            ->setTarget($data['file_target'])
847
+            ->setMailSend((bool)$data['mail_send'])
848
+            ->setToken($data['token']);
849
+
850
+        $shareTime = new \DateTime();
851
+        $shareTime->setTimestamp((int)$data['stime']);
852
+        $share->setShareTime($shareTime);
853
+        $share->setSharedWith($data['share_with']);
854
+
855
+        if ($data['uid_initiator'] !== null) {
856
+            $share->setShareOwner($data['uid_owner']);
857
+            $share->setSharedBy($data['uid_initiator']);
858
+        } else {
859
+            //OLD SHARE
860
+            $share->setSharedBy($data['uid_owner']);
861
+            $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
862
+
863
+            $owner = $path->getOwner();
864
+            $share->setShareOwner($owner->getUID());
865
+        }
866
+
867
+        $share->setNodeId((int)$data['file_source']);
868
+        $share->setNodeType($data['item_type']);
869
+
870
+        $share->setProviderId($this->identifier());
871
+
872
+        return $share;
873
+    }
874
+
875
+    /**
876
+     * Get the node with file $id for $user
877
+     *
878
+     * @param string $userId
879
+     * @param int $id
880
+     * @return \OCP\Files\File|\OCP\Files\Folder
881
+     * @throws InvalidShare
882
+     */
883
+    private function getNode($userId, $id) {
884
+        try {
885
+            $userFolder = $this->rootFolder->getUserFolder($userId);
886
+        } catch (NotFoundException $e) {
887
+            throw new InvalidShare();
888
+        }
889
+
890
+        $nodes = $userFolder->getById($id);
891
+
892
+        if (empty($nodes)) {
893
+            throw new InvalidShare();
894
+        }
895
+
896
+        return $nodes[0];
897
+    }
898
+
899
+    /**
900
+     * A user is deleted from the system
901
+     * So clean up the relevant shares.
902
+     *
903
+     * @param string $uid
904
+     * @param int $shareType
905
+     */
906
+    public function userDeleted($uid, $shareType) {
907
+        //TODO: probabaly a good idea to send unshare info to remote servers
908
+
909
+        $qb = $this->dbConnection->getQueryBuilder();
910
+
911
+        $qb->delete('share')
912
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
913
+            ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
914
+            ->execute();
915
+    }
916
+
917
+    /**
918
+     * This provider does not handle groups
919
+     *
920
+     * @param string $gid
921
+     */
922
+    public function groupDeleted($gid) {
923
+        // We don't handle groups here
924
+        return;
925
+    }
926
+
927
+    /**
928
+     * This provider does not handle groups
929
+     *
930
+     * @param string $uid
931
+     * @param string $gid
932
+     */
933
+    public function userDeletedFromGroup($uid, $gid) {
934
+        // We don't handle groups here
935
+        return;
936
+    }
937
+
938
+    /**
939
+     * check if users from other Nextcloud instances are allowed to mount public links share by this instance
940
+     *
941
+     * @return bool
942
+     */
943
+    public function isOutgoingServer2serverShareEnabled() {
944
+        $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes');
945
+        return ($result === 'yes');
946
+    }
947
+
948
+    /**
949
+     * check if users are allowed to mount public links from other Nextclouds
950
+     *
951
+     * @return bool
952
+     */
953
+    public function isIncomingServer2serverShareEnabled() {
954
+        $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes');
955
+        return ($result === 'yes');
956
+    }
957
+
958
+    /**
959
+     * Check if querying sharees on the lookup server is enabled
960
+     *
961
+     * @return bool
962
+     */
963
+    public function isLookupServerQueriesEnabled() {
964
+        $result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no');
965
+        return ($result === 'yes');
966
+    }
967
+
968
+
969
+    /**
970
+     * Check if it is allowed to publish user specific data to the lookup server
971
+     *
972
+     * @return bool
973
+     */
974
+    public function isLookupServerUploadEnabled() {
975
+        $result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes');
976
+        return ($result === 'yes');
977
+    }
978
+
979
+    /**
980
+     * @inheritdoc
981
+     */
982
+    public function getAccessList($nodes, $currentAccess) {
983
+        $ids = [];
984
+        foreach ($nodes as $node) {
985
+            $ids[] = $node->getId();
986
+        }
987
+
988
+        $qb = $this->dbConnection->getQueryBuilder();
989
+        $qb->select('share_with', 'token', 'file_source')
990
+            ->from('share')
991
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
992
+            ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
993
+            ->andWhere($qb->expr()->orX(
994
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
995
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
996
+            ));
997
+        $cursor = $qb->execute();
998
+
999
+        if ($currentAccess === false) {
1000
+            $remote = $cursor->fetch() !== false;
1001
+            $cursor->closeCursor();
1002
+
1003
+            return ['remote' => $remote];
1004
+        }
1005
+
1006
+        $remote = [];
1007
+        while ($row = $cursor->fetch()) {
1008
+            $remote[$row['share_with']] = [
1009
+                'node_id' => $row['file_source'],
1010
+                'token' => $row['token'],
1011
+            ];
1012
+        }
1013
+        $cursor->closeCursor();
1014
+
1015
+        return ['remote' => $remote];
1016
+    }
1017 1017
 }
Please login to merge, or discard this patch.