1 | <?php declare(strict_types=1); |
||||
2 | |||||
3 | |||||
4 | /** |
||||
5 | * Files_FromMail - Recover your email attachments from your cloud. |
||||
6 | * |
||||
7 | * This file is licensed under the Affero General Public License version 3 or |
||||
8 | * later. See the COPYING file. |
||||
9 | * |
||||
10 | * @author Maxence Lange <[email protected]> |
||||
11 | * @copyright 2017 |
||||
12 | * @license GNU AGPL version 3 or any later version |
||||
13 | * |
||||
14 | * This program is free software: you can redistribute it and/or modify |
||||
15 | * it under the terms of the GNU Affero General Public License as |
||||
16 | * published by the Free Software Foundation, either version 3 of the |
||||
17 | * License, or (at your option) any later version. |
||||
18 | * |
||||
19 | * This program is distributed in the hope that it will be useful, |
||||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
22 | * GNU Affero General Public License for more details. |
||||
23 | * |
||||
24 | * You should have received a copy of the GNU Affero General Public License |
||||
25 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
26 | * |
||||
27 | */ |
||||
28 | |||||
29 | |||||
30 | $config = [ |
||||
31 | 'nextcloud' => 'https://cloud.example.net/', |
||||
32 | 'username' => 'frommail', |
||||
33 | 'password' => 'Ledxc-jRFiR-wBMXD-jyyjt-Y87CZ', |
||||
34 | 'debug' => false |
||||
35 | ]; |
||||
36 | |||||
37 | |||||
38 | // --- do not edit below this line --- |
||||
39 | |||||
40 | class NextcloudMailCatcher { |
||||
41 | |||||
42 | |||||
43 | /** @var string */ |
||||
44 | private $content; |
||||
45 | |||||
46 | /** @var array */ |
||||
47 | private $config; |
||||
48 | |||||
49 | |||||
50 | /** |
||||
51 | * NextcloudMailCatcher constructor. |
||||
52 | * |
||||
53 | * @param array $config |
||||
54 | */ |
||||
55 | public function __construct(array $config) { |
||||
56 | $nextcloud = $config['nextcloud']; |
||||
57 | if (substr($nextcloud, -1) === '/') { |
||||
58 | $config['nextcloud'] = substr($nextcloud, 0, -1); |
||||
59 | } |
||||
60 | |||||
61 | $this->config = $config; |
||||
62 | } |
||||
63 | |||||
64 | |||||
65 | /** |
||||
66 | * @param $content |
||||
67 | * |
||||
68 | * @return $this |
||||
69 | */ |
||||
70 | public function setContent(string $content): self { |
||||
71 | $this->content = $content; |
||||
72 | |||||
73 | return $this; |
||||
74 | } |
||||
75 | |||||
76 | |||||
77 | /** |
||||
78 | * @return string |
||||
79 | */ |
||||
80 | public function getContent(): string { |
||||
81 | return $this->content; |
||||
82 | } |
||||
83 | |||||
84 | |||||
85 | /** |
||||
86 | * |
||||
87 | */ |
||||
88 | public function sendToNextcloud(): void { |
||||
89 | $content = rawurlencode(base64_encode($this->getContent())); |
||||
90 | |||||
91 | $curl = $this->generateAuthedCurl(); |
||||
92 | $this->fillCurlWithContent($curl, 'content=' . $content); |
||||
93 | |||||
94 | $result = curl_exec($curl); |
||||
95 | |||||
96 | $this->debugCurl($curl, $result); |
||||
97 | } |
||||
98 | |||||
99 | |||||
100 | /** |
||||
101 | * |
||||
102 | */ |
||||
103 | public function test(): void { |
||||
104 | $this->config['debug'] = true; |
||||
105 | $this->debug('testing!'); |
||||
106 | |||||
107 | $pwd = $this->config['password']; |
||||
108 | if (substr($pwd, 5, 1) !== '-') { |
||||
109 | $this->debug(''); |
||||
110 | $this->debug('Error: password have to be a generated token'); |
||||
111 | $this->debug( |
||||
112 | 'Generate a token on the webclient: Settings / Security / Devices & session' |
||||
113 | ); |
||||
114 | exit(); |
||||
0 ignored issues
–
show
|
|||||
115 | } |
||||
116 | |||||
117 | $curl = $this->generateAuthedCurl(); |
||||
118 | $this->fillCurlWithContent($curl, 'content=null'); |
||||
119 | |||||
120 | $result = curl_exec($curl); |
||||
121 | |||||
122 | $this->debugCurl($curl, $result); |
||||
123 | } |
||||
124 | |||||
125 | |||||
126 | /** |
||||
127 | * @param resource $curl |
||||
128 | * @param string|array $result |
||||
129 | */ |
||||
130 | private function debugCurl($curl, $result): void { |
||||
131 | if ($result === false) { |
||||
0 ignored issues
–
show
|
|||||
132 | $this->debug('Mail NOT forwarded: ' . curl_error($curl)); |
||||
133 | |||||
134 | return; |
||||
135 | } |
||||
136 | |||||
137 | try { |
||||
138 | $this->debugCurlResponseCode($curl); |
||||
139 | } catch (Exception $e) { |
||||
140 | $this->debug('Mail NOT forwarded: ' . $e->getMessage()); |
||||
141 | |||||
142 | return; |
||||
143 | } |
||||
144 | |||||
145 | $this->debug('Mail forwarded, result was ' . $result); |
||||
0 ignored issues
–
show
Are you sure
$result of type array|string can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
146 | } |
||||
147 | |||||
148 | |||||
149 | /** |
||||
150 | * @param $curl |
||||
151 | * |
||||
152 | * @throws Exception |
||||
153 | */ |
||||
154 | private function debugCurlResponseCode($curl) { |
||||
155 | |||||
156 | $code = curl_getinfo($curl, CURLINFO_HTTP_CODE); |
||||
157 | if ($code === 201) { |
||||
158 | return; |
||||
159 | } |
||||
160 | |||||
161 | if ($code === 401 || $code === 500) { |
||||
162 | throw new Exception('Unauthorized access'); |
||||
163 | } |
||||
164 | |||||
165 | if ($code === 404) { |
||||
166 | throw new Exception('404 Not Found'); |
||||
167 | } |
||||
168 | |||||
169 | if ($code === 503 || $code === 302) { |
||||
170 | throw new Exception('The \'files_frommail\' app does not seems enabled'); |
||||
171 | } |
||||
172 | |||||
173 | throw new Exception('Request returned code ' . $code); |
||||
174 | } |
||||
175 | |||||
176 | |||||
177 | /** |
||||
178 | * @return resource |
||||
179 | */ |
||||
180 | private function generateAuthedCurl() { |
||||
181 | |||||
182 | $url = $this->config['nextcloud'] . '/index.php/apps/files_frommail/remote'; |
||||
183 | $curl = curl_init($url); |
||||
184 | |||||
185 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); |
||||
0 ignored issues
–
show
It seems like
$curl can also be of type false ; however, parameter $ch of curl_setopt() does only seem to accept resource , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
186 | curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); |
||||
187 | curl_setopt( |
||||
188 | $curl, CURLOPT_USERPWD, |
||||
189 | $this->config['username'] . ':' . $this->config['password'] |
||||
190 | ); |
||||
191 | |||||
192 | $this->debug( |
||||
193 | 'Generate curl request to ' . $url . ' with username \'' . $this->config['username'] |
||||
194 | . '\'' |
||||
195 | ); |
||||
196 | |||||
197 | return $curl; |
||||
0 ignored issues
–
show
The expression
return $curl could also return false which is incompatible with the documented return type resource . Did you maybe forget to handle an error condition?
If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled. ![]() |
|||||
198 | } |
||||
199 | |||||
200 | |||||
201 | /** |
||||
202 | * @param resource $curl |
||||
203 | * @param string $put |
||||
204 | */ |
||||
205 | private function fillCurlWithContent(&$curl, string $put): void { |
||||
206 | |||||
207 | curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT'); |
||||
208 | curl_setopt($curl, CURLOPT_POSTFIELDS, $put); |
||||
209 | |||||
210 | $length = strlen($put); |
||||
211 | curl_setopt( |
||||
212 | $curl, CURLOPT_HTTPHEADER, |
||||
213 | [ |
||||
214 | 'Content-type: application/x-www-form-urlencoded', |
||||
215 | 'OCS-APIRequest: true', |
||||
216 | 'Content-Length: ' . $length |
||||
217 | ] |
||||
218 | ); |
||||
219 | |||||
220 | $this->debug('Content-Length: ' . $length . ' (' . round($length / 1024 / 1024, 1) . 'MB)'); |
||||
221 | } |
||||
222 | |||||
223 | |||||
224 | /** |
||||
225 | * @param string $string |
||||
226 | */ |
||||
227 | private function debug(string $string): void { |
||||
228 | if (!array_key_exists('debug', $this->config) || $this->config['debug'] !== true) { |
||||
229 | return; |
||||
230 | } |
||||
231 | |||||
232 | echo $string . "\n"; |
||||
233 | // $log = '/tmp/' . basename(__FILE__, '.php') . '.log'; |
||||
234 | // file_put_contents($log, date('Y-m-d H:i:s') . ' ' . $string . "\n", FILE_APPEND); |
||||
235 | } |
||||
236 | |||||
237 | } |
||||
238 | |||||
239 | |||||
240 | $mailCatcher = new NextcloudMailCatcher($config); |
||||
241 | |||||
242 | if (sizeof($argv) === 2 && $argv[1] === 'test') { |
||||
243 | $mailCatcher->test(); |
||||
244 | |||||
245 | return; |
||||
246 | } |
||||
247 | |||||
248 | echo 'Catching a new mail'; |
||||
249 | |||||
250 | $content = ''; |
||||
251 | $fd = fopen('php://stdin', 'r'); |
||||
252 | while (!feof($fd)) { |
||||
0 ignored issues
–
show
It seems like
$fd can also be of type false ; however, parameter $handle of feof() does only seem to accept resource , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
253 | $content .= fread($fd, 1024); |
||||
0 ignored issues
–
show
It seems like
$fd can also be of type false ; however, parameter $handle of fread() does only seem to accept resource , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
254 | } |
||||
255 | |||||
256 | $mailCatcher->setContent($content); |
||||
257 | $mailCatcher->sendToNextcloud(); |
||||
258 | |||||
259 | |||||
260 | |||||
261 | |||||
262 |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.