Completed
Push — stable8.2 ( 696ee3...54f8ec )
by Roeland
70:33
created

Storage::getShareInfo()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 25
ccs 0
cts 14
cp 0
rs 8.439
c 1
b 0
f 0
cc 5
eloc 15
nc 4
nop 0
crap 30
1
<?php
2
/**
3
 * @author Lukas Reschke <[email protected]>
4
 * @author Morris Jobke <[email protected]>
5
 * @author Robin Appelman <[email protected]>
6
 * @author Thomas Müller <[email protected]>
7
 * @author Vincent Petry <[email protected]>
8
 *
9
 * @copyright Copyright (c) 2015, ownCloud, Inc.
10
 * @license AGPL-3.0
11
 *
12
 * This code is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License, version 3,
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License, version 3,
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
23
 *
24
 */
25
26
namespace OCA\Files_Sharing\External;
27
28
use OC\Files\Storage\DAV;
29
use OC\ForbiddenException;
30
use OCA\Files_Sharing\ISharedStorage;
31
use OCP\Files\NotFoundException;
32
use OCP\Files\StorageInvalidException;
33
use OCP\Files\StorageNotAvailableException;
34
35
class Storage extends DAV implements ISharedStorage {
36
	/**
37
	 * @var string
38
	 */
39
	private $remoteUser;
40
41
	/**
42
	 * @var string
43
	 */
44
	private $remote;
45
46
	/**
47
	 * @var string
48
	 */
49
	private $mountPoint;
50
51
	/**
52
	 * @var string
53
	 */
54
	private $token;
55
56
	/**
57
	 * @var \OCP\ICertificateManager
58
	 */
59
	private $certificateManager;
60
61
	private $updateChecked = false;
62
63
	/**
64
	 * @var \OCA\Files_Sharing\External\Manager
65
	 */
66
	private $manager;
67
68 7
	public function __construct($options) {
69 7
		$this->manager = $options['manager'];
70 7
		$this->certificateManager = $options['certificateManager'];
71 7
		$this->remote = $options['remote'];
72 7
		$this->remoteUser = $options['owner'];
73 7
		list($protocol, $remote) = explode('://', $this->remote);
74 7
		if (strpos($remote, '/')) {
75 6
			list($host, $root) = explode('/', $remote, 2);
76 6
		} else {
77 1
			$host = $remote;
78 1
			$root = '';
79
		}
80 7
		$secure = $protocol === 'https';
81 7
		$root = rtrim($root, '/') . '/public.php/webdav';
82 7
		$this->mountPoint = $options['mountpoint'];
83 7
		$this->token = $options['token'];
84 7
		parent::__construct(array(
85 7
			'secure' => $secure,
86 7
			'host' => $host,
87 7
			'root' => $root,
88 7
			'user' => $options['token'],
89 7
			'password' => (string)$options['password']
90 7
		));
91
92 7
		$this->getWatcher()->setPolicy(\OC\Files\Cache\Watcher::CHECK_ONCE);
93 7
	}
94
95
	public function getRemoteUser() {
96
		return $this->remoteUser;
97
	}
98
99
	public function getRemote() {
100
		return $this->remote;
101
	}
102
103
	public function getMountPoint() {
104
		return $this->mountPoint;
105
	}
106
107
	public function getToken() {
108
		return $this->token;
109
	}
110
111
	public function getPassword() {
112
		return $this->password;
113
	}
114
115
	/**
116
	 * @brief get id of the mount point
117
	 * @return string
118
	 */
119 7
	public function getId() {
120 7
		return 'shared::' . md5($this->token . '@' . $this->remote);
121
	}
122
123 7
	public function getCache($path = '', $storage = null) {
124 7
		if (is_null($this->cache)) {
125 7
			$this->cache = new Cache($this, $this->remote, $this->remoteUser);
126 7
		}
127 7
		return $this->cache;
128
	}
129
130
	/**
131
	 * @param string $path
132
	 * @param \OC\Files\Storage\Storage $storage
133
	 * @return \OCA\Files_Sharing\External\Scanner
134
	 */
135 7 View Code Duplication
	public function getScanner($path = '', $storage = null) {
136 7
		if (!$storage) {
137 7
			$storage = $this;
138 7
		}
139 7
		if (!isset($this->scanner)) {
140 7
			$this->scanner = new Scanner($storage);
141 7
		}
142 7
		return $this->scanner;
143
	}
144
145
	/**
146
	 * check if a file or folder has been updated since $time
147
	 *
148
	 * @param string $path
149
	 * @param int $time
150
	 * @throws \OCP\Files\StorageNotAvailableException
151
	 * @throws \OCP\Files\StorageInvalidException
152
	 * @return bool
153
	 */
154
	public function hasUpdated($path, $time) {
155
		// since for owncloud webdav servers we can rely on etag propagation we only need to check the root of the storage
156
		// because of that we only do one check for the entire storage per request
157
		if ($this->updateChecked) {
158
			return false;
159
		}
160
		$this->updateChecked = true;
161
		try {
162
			return parent::hasUpdated('', $time);
163
		} catch (StorageInvalidException $e) {
164
			// check if it needs to be removed
165
			$this->checkStorageAvailability();
166
			throw $e;
167
		} catch (StorageNotAvailableException $e) {
168
			// check if it needs to be removed or just temp unavailable
169
			$this->checkStorageAvailability();
170
			throw $e;
171
		}
172
	}
173
174
	/**
175
	 * Check whether this storage is permanently or temporarily
176
	 * unavailable
177
	 *
178
	 * @throws \OCP\Files\StorageNotAvailableException
179
	 * @throws \OCP\Files\StorageInvalidException
180
	 */
181
	public function checkStorageAvailability() {
182
		// see if we can find out why the share is unavailable
183
		try {
184
			$this->getShareInfo();
185
		} catch (NotFoundException $e) {
186
			// a 404 can either mean that the share no longer exists or there is no ownCloud on the remote
187
			if ($this->testRemote()) {
188
				// valid ownCloud instance means that the public share no longer exists
189
				// since this is permanent (re-sharing the file will create a new token)
190
				// we remove the invalid storage
191
				$this->manager->removeShare($this->mountPoint);
192
				$this->manager->getMountManager()->removeMount($this->mountPoint);
193
				throw new StorageInvalidException();
194
			} else {
195
				// ownCloud instance is gone, likely to be a temporary server configuration error
196
				throw new StorageNotAvailableException();
197
			}
198
		} catch (ForbiddenException $e) {
199
			// auth error, remove share for now (provide a dialog in the future)
200
			$this->manager->removeShare($this->mountPoint);
201
			$this->manager->getMountManager()->removeMount($this->mountPoint);
202
			throw new StorageInvalidException();
203
		} catch (\GuzzleHttp\Exception\ConnectException $e) {
0 ignored issues
show
Bug introduced by
The class GuzzleHttp\Exception\ConnectException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
204
			throw new StorageNotAvailableException();
205
		} catch (\GuzzleHttp\Exception\RequestException $e) {
0 ignored issues
show
Bug introduced by
The class GuzzleHttp\Exception\RequestException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
206
			throw new StorageNotAvailableException();
207
		} catch (\Exception $e) {
208
			throw $e;
209
		}
210
	}
211
212
	public function file_exists($path) {
213
		if ($path === '') {
214
			return true;
215
		} else {
216
			return parent::file_exists($path);
217
		}
218
	}
219
220
	/**
221
	 * check if the configured remote is a valid ownCloud instance
222
	 *
223
	 * @return bool
224
	 */
225
	protected function testRemote() {
226
		try {
227
			$result = file_get_contents($this->remote . '/status.php');
228
			$data = json_decode($result);
229
			return is_object($data) and !empty($data->version);
230
		} catch (\Exception $e) {
231
			return false;
232
		}
233
	}
234
235
	/**
236
	 * @return mixed
237
	 * @throws ForbiddenException
238
	 * @throws NotFoundException
239
	 * @throws \Exception
240
	 */
241
	public function getShareInfo() {
242
		$remote = $this->getRemote();
243
		$token = $this->getToken();
244
		$password = $this->getPassword();
245
		$url = rtrim($remote, '/') . '/index.php/apps/files_sharing/shareinfo?t=' . $token;
246
247
		// TODO: DI
248
		$client = \OC::$server->getHTTPClientService()->newClient();
249
		try {
250
			$response = $client->post($url, ['body' => ['password' => $password]]);
251
		} catch (\GuzzleHttp\Exception\RequestException $e) {
0 ignored issues
show
Bug introduced by
The class GuzzleHttp\Exception\RequestException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
252
			if ($e->getCode() === 401 || $e->getCode() === 403) {
253
					throw new ForbiddenException();
254
			}
255
			if ($e->getCode() === 404) {
256
				throw new NotFoundException();
257
			}
258
			// throw this to be on the safe side: the share will still be visible
259
			// in the UI in case the failure is intermittent, and the user will
260
			// be able to decide whether to remove it if it's really gone
261
			throw new StorageNotAvailableException();
262
		}
263
264
		return json_decode($response->getBody(), true);
265
	}
266
267
	public function isSharable($path) {
268
		if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) {
269
			return false;
270
		}
271
		return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE);
272
	}
273
}
274