1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @copyright Copyright (c) 2016 Joas Schilling <[email protected]> |
4
|
|
|
* |
5
|
|
|
* @license GNU AGPL version 3 or any later version |
6
|
|
|
* |
7
|
|
|
* This program is free software: you can redistribute it and/or modify |
8
|
|
|
* it under the terms of the GNU Affero General Public License as |
9
|
|
|
* published by the Free Software Foundation, either version 3 of the |
10
|
|
|
* License, or (at your option) any later version. |
11
|
|
|
* |
12
|
|
|
* This program is distributed in the hope that it will be useful, |
13
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15
|
|
|
* GNU Affero General Public License for more details. |
16
|
|
|
* |
17
|
|
|
* You should have received a copy of the GNU Affero General Public License |
18
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
19
|
|
|
* |
20
|
|
|
*/ |
21
|
|
|
|
22
|
|
|
namespace OCA\WorkflowEngine\Check; |
23
|
|
|
|
24
|
|
|
|
25
|
|
|
use OCA\WorkflowEngine\Entity\File; |
26
|
|
|
use OCP\Files\IMimeTypeDetector; |
27
|
|
|
use OCP\Files\Storage\IStorage; |
28
|
|
|
use OCP\IL10N; |
29
|
|
|
use OCP\IRequest; |
30
|
|
|
use OCP\WorkflowEngine\IFileCheck; |
31
|
|
|
|
32
|
|
|
class FileMimeType extends AbstractStringCheck implements IFileCheck { |
33
|
|
|
use TFileCheck { |
34
|
|
|
setFileInfo as _setFileInfo; |
35
|
|
|
} |
36
|
|
|
|
37
|
|
|
/** @var array */ |
38
|
|
|
protected $mimeType; |
39
|
|
|
|
40
|
|
|
/** @var IRequest */ |
41
|
|
|
protected $request; |
42
|
|
|
|
43
|
|
|
/** @var IMimeTypeDetector */ |
44
|
|
|
protected $mimeTypeDetector; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @param IL10N $l |
48
|
|
|
* @param IRequest $request |
49
|
|
|
* @param IMimeTypeDetector $mimeTypeDetector |
50
|
|
|
*/ |
51
|
|
|
public function __construct(IL10N $l, IRequest $request, IMimeTypeDetector $mimeTypeDetector) { |
52
|
|
|
parent::__construct($l); |
53
|
|
|
$this->request = $request; |
54
|
|
|
$this->mimeTypeDetector = $mimeTypeDetector; |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* @param IStorage $storage |
59
|
|
|
* @param string $path |
60
|
|
|
*/ |
61
|
|
|
public function setFileInfo(IStorage $storage, string $path) { |
62
|
|
|
$this->_setFileInfo($storage, $path); |
63
|
|
|
if (!isset($this->mimeType[$this->storage->getId()][$this->path]) |
64
|
|
|
|| $this->mimeType[$this->storage->getId()][$this->path] === '') { |
65
|
|
|
$this->mimeType[$this->storage->getId()][$this->path] = null; |
66
|
|
|
} |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* The mimetype is only cached if the file exists. Otherwise files access |
71
|
|
|
* control will cache "application/octet-stream" for all the target node on: |
72
|
|
|
* rename, move, copy and all other methods which create a new item |
73
|
|
|
* |
74
|
|
|
* To check this: |
75
|
|
|
* 1. Add an automated tagging rule which tags on mimetype NOT "httpd/unix-directory" |
76
|
|
|
* 2. Add an access control rule which checks for any mimetype |
77
|
|
|
* 3. Create a folder and rename it, the folder should not be tagged, but it is |
78
|
|
|
* |
79
|
|
|
* @param string $storageId |
80
|
|
|
* @param string|null $path |
81
|
|
|
* @param string $mimeType |
82
|
|
|
* @return string |
83
|
|
|
*/ |
84
|
|
|
protected function cacheAndReturnMimeType(string $storageId, ?string $path, string $mimeType): string { |
85
|
|
|
if ($path !== null && $this->storage->file_exists($path)) { |
86
|
|
|
$this->mimeType[$storageId][$path] = $mimeType; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
return $mimeType; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* @return string |
94
|
|
|
*/ |
95
|
|
|
protected function getActualValue() { |
96
|
|
|
if ($this->mimeType[$this->storage->getId()][$this->path] !== null) { |
97
|
|
|
return $this->mimeType[$this->storage->getId()][$this->path]; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
if ($this->storage->is_dir($this->path)) { |
101
|
|
|
return $this->cacheAndReturnMimeType($this->storage->getId(), $this->path, 'httpd/unix-directory'); |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
if ($this->isWebDAVRequest()) { |
105
|
|
|
// Creating a folder |
106
|
|
|
if ($this->request->getMethod() === 'MKCOL') { |
107
|
|
|
return $this->cacheAndReturnMimeType($this->storage->getId(), $this->path, 'httpd/unix-directory'); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
if ($this->request->getMethod() === 'PUT' || $this->request->getMethod() === 'MOVE') { |
111
|
|
|
if ($this->request->getMethod() === 'MOVE') { |
112
|
|
|
$mimeType = $this->mimeTypeDetector->detectPath($this->path); |
113
|
|
|
} else { |
114
|
|
|
$path = $this->request->getPathInfo(); |
115
|
|
|
$mimeType = $this->mimeTypeDetector->detectPath($path); |
116
|
|
|
} |
117
|
|
|
return $this->cacheAndReturnMimeType($this->storage->getId(), $this->path, $mimeType); |
118
|
|
|
} |
119
|
|
|
} else if ($this->isPublicWebDAVRequest()) { |
120
|
|
|
if ($this->request->getMethod() === 'PUT') { |
121
|
|
|
$path = $this->request->getPathInfo(); |
122
|
|
|
if (strpos($path, '/webdav/') === 0) { |
123
|
|
|
$path = substr($path, strlen('/webdav')); |
124
|
|
|
} |
125
|
|
|
$path = $this->path . $path; |
|
|
|
|
126
|
|
|
$mimeType = $this->mimeTypeDetector->detectPath($path); |
127
|
|
|
return $this->cacheAndReturnMimeType($this->storage->getId(), $path, $mimeType); |
128
|
|
|
} |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
if (in_array($this->request->getMethod(), ['POST', 'PUT'])) { |
132
|
|
|
$files = $this->request->getUploadedFile('files'); |
133
|
|
|
if (isset($files['type'][0])) { |
134
|
|
|
$mimeType = $files['type'][0]; |
135
|
|
|
if ($mimeType === 'application/octet-stream') { |
136
|
|
|
// Maybe not... |
137
|
|
|
$mimeTypeTest = $this->mimeTypeDetector->detectPath($files['name'][0]); |
138
|
|
|
if ($mimeTypeTest !== 'application/octet-stream' && $mimeTypeTest !== false) { |
139
|
|
|
$mimeType = $mimeTypeTest; |
140
|
|
|
} else { |
141
|
|
|
$mimeTypeTest = $this->mimeTypeDetector->detect($files['tmp_name'][0]); |
142
|
|
|
if ($mimeTypeTest !== 'application/octet-stream' && $mimeTypeTest !== false) { |
143
|
|
|
$mimeType = $mimeTypeTest; |
144
|
|
|
} |
145
|
|
|
} |
146
|
|
|
} |
147
|
|
|
return $this->cacheAndReturnMimeType($this->storage->getId(), $this->path, $mimeType); |
148
|
|
|
} |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
$mimeType = $this->storage->getMimeType($this->path); |
152
|
|
|
if ($mimeType === 'application/octet-stream') { |
153
|
|
|
$mimeType = $this->detectMimetypeFromPath(); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
return $this->cacheAndReturnMimeType($this->storage->getId(), $this->path, $mimeType); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* @return string |
161
|
|
|
*/ |
162
|
|
|
protected function detectMimetypeFromPath() { |
163
|
|
|
$mimeType = $this->mimeTypeDetector->detectPath($this->path); |
164
|
|
|
if ($mimeType !== 'application/octet-stream' && $mimeType !== false) { |
165
|
|
|
return $mimeType; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
if ($this->storage->instanceOfStorage('\OC\Files\Storage\Local') |
169
|
|
|
|| $this->storage->instanceOfStorage('\OC\Files\Storage\Home') |
170
|
|
|
|| $this->storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')) { |
171
|
|
|
$localFile = $this->storage->getLocalFile($this->path); |
172
|
|
|
if ($localFile !== false) { |
173
|
|
|
$mimeType = $this->mimeTypeDetector->detect($localFile); |
174
|
|
|
if ($mimeType !== false) { |
|
|
|
|
175
|
|
|
return $mimeType; |
176
|
|
|
} |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
return 'application/octet-stream'; |
180
|
|
|
} else { |
181
|
|
|
$handle = $this->storage->fopen($this->path, 'r'); |
182
|
|
|
$data = fread($handle, 8024); |
183
|
|
|
fclose($handle); |
184
|
|
|
$mimeType = $this->mimeTypeDetector->detectString($data); |
185
|
|
|
if ($mimeType !== false) { |
|
|
|
|
186
|
|
|
return $mimeType; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
return 'application/octet-stream'; |
190
|
|
|
} |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* @return bool |
195
|
|
|
*/ |
196
|
|
|
protected function isWebDAVRequest() { |
197
|
|
|
return substr($this->request->getScriptName(), 0 - strlen('/remote.php')) === '/remote.php' && ( |
198
|
|
|
$this->request->getPathInfo() === '/webdav' || |
199
|
|
|
strpos($this->request->getPathInfo(), '/webdav/') === 0 || |
200
|
|
|
$this->request->getPathInfo() === '/dav/files' || |
201
|
|
|
strpos($this->request->getPathInfo(), '/dav/files/') === 0 || |
202
|
|
|
$this->request->getPathInfo() === '/dav/uploads' || |
203
|
|
|
strpos($this->request->getPathInfo(), '/dav/uploads/') === 0 |
204
|
|
|
); |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* @return bool |
209
|
|
|
*/ |
210
|
|
|
protected function isPublicWebDAVRequest() { |
211
|
|
|
return substr($this->request->getScriptName(), 0 - strlen('/public.php')) === '/public.php' && ( |
212
|
|
|
$this->request->getPathInfo() === '/webdav' || |
213
|
|
|
strpos($this->request->getPathInfo(), '/webdav/') === 0 |
214
|
|
|
); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
public function supportedEntities(): array { |
218
|
|
|
return [ File::class ]; |
219
|
|
|
} |
220
|
|
|
} |
221
|
|
|
|