1 | <?php |
||||
2 | /** |
||||
3 | * |
||||
4 | * (c) Copyright Ascensio System SIA 2021 |
||||
5 | * |
||||
6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
||||
7 | * you may not use this file except in compliance with the License. |
||||
8 | * You may obtain a copy of the License at |
||||
9 | * |
||||
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
||||
11 | * |
||||
12 | * Unless required by applicable law or agreed to in writing, software |
||||
13 | * distributed under the License is distributed on an "AS IS" BASIS, |
||||
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
15 | * See the License for the specific language governing permissions and |
||||
16 | * limitations under the License. |
||||
17 | * |
||||
18 | */ |
||||
19 | |||||
20 | require_once __DIR__.'/../../main/inc/global.inc.php'; |
||||
21 | |||||
22 | use ChamiloSession as Session; |
||||
23 | |||||
24 | /** |
||||
25 | * Status of the document |
||||
26 | */ |
||||
27 | const TrackerStatus_Editing = 1; |
||||
28 | const TrackerStatus_MustSave = 2; |
||||
29 | const TrackerStatus_Corrupted = 3; |
||||
30 | const TrackerStatus_Closed = 4; |
||||
31 | const TrackerStatus_ForceSave = 6; |
||||
32 | const TrackerStatus_CorruptedForceSave = 7; |
||||
33 | |||||
34 | $plugin = OnlyofficePlugin::create(); |
||||
35 | |||||
36 | if (isset($_GET["hash"]) && !empty($_GET["hash"])) { |
||||
37 | $callbackResponseArray = []; |
||||
38 | @header( 'Content-Type: application/json; charset==utf-8'); |
||||
0 ignored issues
–
show
|
|||||
39 | @header( 'X-Robots-Tag: noindex' ); |
||||
40 | @header( 'X-Content-Type-Options: nosniff' ); |
||||
41 | |||||
42 | list ($hashData, $error) = Crypt::ReadHash($_GET["hash"]); |
||||
43 | if ($hashData === null) { |
||||
44 | $callbackResponseArray["status"] = "error"; |
||||
45 | $callbackResponseArray["error"] = $error; |
||||
46 | die(json_encode($callbackResponseArray)); |
||||
47 | } |
||||
48 | |||||
49 | $type = $hashData->type; |
||||
50 | $courseId = $hashData->courseId; |
||||
51 | $userId = $hashData->userId; |
||||
52 | $docId = $hashData->docId; |
||||
53 | $groupId = $hashData->groupId; |
||||
54 | $sessionId = $hashData->sessionId; |
||||
55 | |||||
56 | $courseInfo = api_get_course_info_by_id($courseId); |
||||
57 | $courseCode = $courseInfo["code"]; |
||||
58 | |||||
59 | if (!empty($userId)) { |
||||
60 | $userInfo = api_get_user_info($userId); |
||||
61 | } else { |
||||
62 | $result["error"] = "User not found"; |
||||
63 | die (json_encode($result)); |
||||
64 | } |
||||
65 | |||||
66 | if (api_is_anonymous()) { |
||||
67 | $loggedUser = [ |
||||
68 | "user_id" => $userInfo["id"], |
||||
69 | "status" => $userInfo["status"], |
||||
70 | "uidReset" => true, |
||||
71 | ]; |
||||
72 | |||||
73 | Session::write("_user", $loggedUser); |
||||
74 | Login::init_user($loggedUser["user_id"], true); |
||||
75 | } else { |
||||
76 | $userId = api_get_user_id(); |
||||
77 | } |
||||
78 | |||||
79 | switch($type) { |
||||
80 | case "track": |
||||
81 | $callbackResponseArray = track(); |
||||
82 | die (json_encode($callbackResponseArray)); |
||||
83 | case "download": |
||||
84 | $callbackResponseArray = download(); |
||||
85 | die (json_encode($callbackResponseArray)); |
||||
86 | default: |
||||
87 | $callbackResponseArray["status"] = "error"; |
||||
88 | $callbackResponseArray["error"] = "404 Method not found"; |
||||
89 | die(json_encode($callbackResponseArray)); |
||||
90 | } |
||||
91 | } |
||||
92 | |||||
93 | /** |
||||
94 | * Handle request from the document server with the document status information |
||||
95 | */ |
||||
96 | function track(): array |
||||
97 | { |
||||
98 | $result = []; |
||||
99 | |||||
100 | global $plugin; |
||||
101 | global $courseCode; |
||||
102 | global $userId; |
||||
103 | global $docId; |
||||
104 | global $groupId; |
||||
105 | global $sessionId; |
||||
106 | global $courseInfo; |
||||
107 | |||||
108 | if (($body_stream = file_get_contents("php://input")) === false) { |
||||
109 | $result["error"] = "Bad Request"; |
||||
110 | return $result; |
||||
111 | } |
||||
112 | |||||
113 | $data = json_decode($body_stream, true); |
||||
114 | |||||
115 | if ($data === null) { |
||||
116 | $result["error"] = "Bad Response"; |
||||
117 | return $result; |
||||
118 | } |
||||
119 | |||||
120 | if (!empty($plugin->get("jwt_secret"))) { |
||||
121 | |||||
122 | if (!empty($data["token"])) { |
||||
123 | try { |
||||
124 | $payload = \Firebase\JWT\JWT::decode($data["token"], $plugin->get("jwt_secret"), array("HS256")); |
||||
125 | } catch (\UnexpectedValueException $e) { |
||||
126 | $result["status"] = "error"; |
||||
127 | $result["error"] = "403 Access denied"; |
||||
128 | return $result; |
||||
129 | } |
||||
130 | } else { |
||||
131 | $token = substr($_SERVER[AppConfig::JwtHeader()], strlen("Bearer ")); |
||||
132 | try { |
||||
133 | $decodeToken = \Firebase\JWT\JWT::decode($token, $plugin->get("jwt_secret"), array("HS256")); |
||||
134 | $payload = $decodeToken->payload; |
||||
135 | } catch (\UnexpectedValueException $e) { |
||||
136 | $result["status"] = "error"; |
||||
137 | $result["error"] = "403 Access denied"; |
||||
138 | return $result; |
||||
139 | } |
||||
140 | } |
||||
141 | |||||
142 | $data["url"] = isset($payload->url) ? $payload->url : null; |
||||
143 | $data["status"] = $payload->status; |
||||
144 | } |
||||
145 | |||||
146 | $status = $data["status"]; |
||||
147 | |||||
148 | $track_result = 1; |
||||
149 | switch ($status) { |
||||
150 | case TrackerStatus_MustSave: |
||||
151 | case TrackerStatus_Corrupted: |
||||
152 | |||||
153 | $downloadUri = $data["url"]; |
||||
154 | |||||
155 | if (!empty($docId) && !empty($courseCode)) { |
||||
156 | $docInfo = DocumentManager::get_document_data_by_id($docId, $courseCode, false, $sessionId); |
||||
157 | |||||
158 | if ($docInfo === false) { |
||||
159 | $result["error"] = "File not found"; |
||||
160 | return $result; |
||||
161 | } |
||||
162 | |||||
163 | $filePath = $docInfo["absolute_path"]; |
||||
164 | } else { |
||||
165 | $result["error"] = "Bad Request"; |
||||
166 | return $result; |
||||
167 | } |
||||
168 | |||||
169 | list ($isAllowToEdit, $isMyDir, $isGroupAccess, $isReadonly) = getPermissions($docInfo, $userId, $courseCode, $groupId, $sessionId); |
||||
170 | |||||
171 | if ($isReadonly) { |
||||
172 | break; |
||||
173 | } |
||||
174 | |||||
175 | if (($new_data = file_get_contents($downloadUri)) === false) { |
||||
176 | break; |
||||
177 | } |
||||
178 | |||||
179 | if ($isAllowToEdit || $isMyDir || $isGroupAccess) { |
||||
180 | $groupInfo = GroupManager::get_group_properties($groupId); |
||||
181 | |||||
182 | if ($fp = @fopen($filePath, "w")) { |
||||
183 | fputs($fp, $new_data); |
||||
184 | fclose($fp); |
||||
185 | api_item_property_update($courseInfo, |
||||
186 | TOOL_DOCUMENT, |
||||
187 | $docId, |
||||
188 | "DocumentUpdated", |
||||
189 | $userId, |
||||
190 | $groupInfo, |
||||
191 | null, |
||||
192 | null, |
||||
193 | null, |
||||
194 | $sessionId); |
||||
195 | update_existing_document($courseInfo, |
||||
196 | $docId, |
||||
197 | filesize($filePath), |
||||
198 | false); |
||||
199 | $track_result = 0; |
||||
200 | break; |
||||
201 | } |
||||
202 | } |
||||
203 | |||||
204 | case TrackerStatus_Editing: |
||||
205 | case TrackerStatus_Closed: |
||||
206 | |||||
207 | $track_result = 0; |
||||
208 | break; |
||||
209 | } |
||||
210 | |||||
211 | $result["error"] = $track_result; |
||||
212 | return $result; |
||||
213 | } |
||||
214 | |||||
215 | /** |
||||
216 | * Downloading file by the document service |
||||
217 | */ |
||||
218 | function download() |
||||
219 | { |
||||
220 | global $plugin; |
||||
221 | global $courseCode; |
||||
222 | global $userId; |
||||
223 | global $docId; |
||||
224 | global $groupId; |
||||
225 | global $sessionId; |
||||
226 | global $courseInfo; |
||||
227 | |||||
228 | if (!empty($plugin->get("jwt_secret"))) { |
||||
229 | $token = substr($_SERVER[AppConfig::JwtHeader()], strlen("Bearer ")); |
||||
230 | try { |
||||
231 | $payload = \Firebase\JWT\JWT::decode($token, $plugin->get("jwt_secret"), array("HS256")); |
||||
232 | |||||
233 | } catch (\UnexpectedValueException $e) { |
||||
234 | $result["status"] = "error"; |
||||
235 | $result["error"] = "403 Access denied"; |
||||
236 | return $result; |
||||
237 | } |
||||
238 | } |
||||
239 | |||||
240 | if (!empty($docId) && !empty($courseCode)) { |
||||
241 | $docInfo = DocumentManager::get_document_data_by_id($docId, $courseCode, false, $sessionId); |
||||
242 | |||||
243 | if ($docInfo === false) { |
||||
244 | $result["error"] = "File not found"; |
||||
245 | return $result; |
||||
246 | } |
||||
247 | |||||
248 | $filePath = $docInfo["absolute_path"]; |
||||
249 | } else { |
||||
250 | $result["error"] = "File not found"; |
||||
251 | return $result; |
||||
252 | } |
||||
253 | |||||
254 | @header("Content-Type: application/octet-stream"); |
||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
header() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||||
255 | @header("Content-Disposition: attachment; filename=" . $docInfo["title"]); |
||||
256 | |||||
257 | readfile($filePath); |
||||
258 | } |
||||
259 | |||||
260 | /** |
||||
261 | * Method checks access rights to document and returns permissions |
||||
262 | */ |
||||
263 | function getPermissions(array $docInfo, int $userId, string $courseCode, int $groupId = null, int $sessionId = null): array |
||||
264 | { |
||||
265 | $isAllowToEdit = api_is_allowed_to_edit(true, true); |
||||
266 | $isMyDir = DocumentManager::is_my_shared_folder($userId, $docInfo["absolute_parent_path"], $sessionId); |
||||
267 | |||||
268 | $isGroupAccess = false; |
||||
269 | if (!empty($groupId)) { |
||||
270 | $courseInfo = api_get_course_info($courseCode); |
||||
271 | Session::write("_real_cid", $courseInfo["real_id"]); |
||||
272 | $groupProperties = GroupManager::get_group_properties($groupId); |
||||
273 | $docInfoGroup = api_get_item_property_info($courseInfo["real_id"], "document", $docInfo["id"], $sessionId); |
||||
274 | $isGroupAccess = GroupManager::allowUploadEditDocument($userId, $courseCode, $groupProperties, $docInfoGroup); |
||||
275 | } |
||||
276 | |||||
277 | $isReadonly = $docInfo["readonly"]; |
||||
278 | |||||
279 | return [$isAllowToEdit, $isMyDir, $isGroupAccess, $isReadonly]; |
||||
280 | } |
||||
281 |
If you suppress an error, we recommend checking for the error condition explicitly: