Passed
Push — master ( e77583...ce02ca )
by Maxence
01:53
created

NextcloudMailCatcher::test()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
c 0
b 0
f 0
dl 0
loc 20
rs 9.8333
cc 2
nc 2
nop 0
1
<?php
2
/**
3
 * Files_FromMail - Recover your email attachments from your cloud.
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Maxence Lange <[email protected]>
9
 * @copyright 2017
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 *  You should have received a copy of the GNU Affero General Public License
23
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
28
$config = [
29
	'nextcloud' => 'https://cloud.example.net/',
30
	'username'  => 'frommail',
31
	'password'  => 'Ledxc-jRFiR-wBMXD-jyyjt-Y87CZ',
32
	'debug'     => false
33
];
34
35
36
// --- do not edit below this line ---
37
38
class NextcloudMailCatcher {
39
40
41
	/** @var string */
42
	private $content;
43
44
	/** @var array */
45
	private $config;
46
47
48
	/**
49
	 * RemoteMailCatcher constructor.
50
	 *
51
	 * @param array $config
52
	 */
53
	public function __construct($config) {
54
		$nextcloud = $config['nextcloud'];
55
		if (substr($nextcloud, -1) === '/') {
56
			$config['nextcloud'] = substr($nextcloud, 0, -1);
57
		}
58
59
		$this->config = $config;
60
	}
61
62
63
	/**
64
	 * @param $content
65
	 *
66
	 * @return $this
67
	 */
68
	public function setContent($content) {
69
		$this->content = $content;
70
71
		return $this;
72
	}
73
74
75
	/**
76
	 * @return string
77
	 */
78
	public function getContent() {
79
		return $this->content;
80
	}
81
82
83
	/**
84
	 *
85
	 */
86
	public function sendToNextcloud() {
87
88
		$content = rawurlencode(base64_encode($this->getContent()));
89
90
		$curl = $this->generateAuthedCurl();
91
		$this->fillCurlWithContent($curl, 'content=' . $content);
92
93
		$result = curl_exec($curl);
94
95
		$this->debugCurl($curl, $result);
96
	}
97
98
99
	/**
100
	 *
101
	 */
102
	public function test() {
103
		$this->config['debug'] = true;
104
		$this->debug('testing!');
105
106
		$pwd = $this->config['password'];
107
		if (substr($pwd, 5, 1) !== '-') {
108
			$this->debug('');
109
			$this->debug('Error: password have to be a generated token');
110
			$this->debug(
111
				'Generate a token on the webclient: Settings / Security / Devices & session'
112
			);
113
			exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
114
		}
115
116
		$curl = $this->generateAuthedCurl();
117
		$this->fillCurlWithContent($curl, 'content=null');
118
119
		$result = curl_exec($curl);
120
121
		$this->debugCurl($curl, $result);
122
	}
123
124
125
	/**
126
	 * @param resource $curl
127
	 * @param string|array $result
128
	 */
129
	private function debugCurl($curl, $result) {
130
		if ($result === false) {
0 ignored issues
show
introduced by
The condition $result === false is always false.
Loading history...
131
			$this->debug('Mail NOT forwarded: ' . curl_error($curl));
132
133
			return;
134
		}
135
136
		try {
137
			$this->debugCurlResponseCode($curl);
138
		} catch (Exception $e) {
139
			$this->debug('Mail NOT forwarded: ' . $e->getMessage());
140
141
			return;
142
		}
143
144
		$this->debug('Mail forwarded, result was ' . $result);
0 ignored issues
show
Bug introduced by
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 ignore-type  annotation

144
		$this->debug('Mail forwarded, result was ' . /** @scrutinizer ignore-type */ $result);
Loading history...
145
	}
146
147
148
	/**
149
	 * @param $curl
150
	 *
151
	 * @throws Exception
152
	 */
153
	private function debugCurlResponseCode($curl) {
154
155
		$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
156
		if ($code === 201) {
157
			return;
158
		}
159
160
		if ($code === 401 || $code === 500) {
161
			throw new Exception('Unauthorized access');
162
		}
163
164
		if ($code === 404) {
165
			throw new Exception('404 Not Found');
166
		}
167
168
		if ($code === 503 || $code === 302) {
169
			throw new Exception('The \'files_frommail\' app does not seems enabled');
170
		}
171
172
		throw new Exception('Request returned code ' . $code);
173
	}
174
175
176
	/**
177
	 * @return resource
178
	 */
179
	private function generateAuthedCurl() {
180
181
		$url = $this->config['nextcloud'] . '/index.php/apps/files_frommail/remote';
182
		$curl = curl_init($url);
183
184
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
0 ignored issues
show
Bug introduced by
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 ignore-type  annotation

184
		curl_setopt(/** @scrutinizer ignore-type */ $curl, CURLOPT_RETURNTRANSFER, true);
Loading history...
185
		curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
186
		curl_setopt(
187
			$curl, CURLOPT_USERPWD,
188
			$this->config['username'] . ':' . $this->config['password']
189
		);
190
191
		$this->debug(
192
			'Generate curl request to ' . $url . ' with username \'' . $this->config['username']
193
			. '\''
194
		);
195
196
		return $curl;
0 ignored issues
show
Bug Best Practice introduced by
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.

Loading history...
197
	}
198
199
200
	/**
201
	 * @param resource $curl
202
	 * @param string $put
203
	 */
204
	private function fillCurlWithContent(&$curl, $put) {
205
206
		curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
207
		curl_setopt($curl, CURLOPT_POSTFIELDS, $put);
208
209
		$length = strlen($put);
210
		curl_setopt(
211
			$curl, CURLOPT_HTTPHEADER,
212
			[
213
				'Content-type: application/x-www-form-urlencoded',
214
				'OCS-APIRequest: true',
215
				'Content-Length: ' . $length
216
			]
217
		);
218
219
		$this->debug('Content-Length: ' . $length . ' (' . round($length / 1024 / 1024, 1) . 'MB)');
220
	}
221
222
223
	/**
224
	 * @param string $string
225
	 */
226
	private function debug($string) {
227
		if (!array_key_exists('debug', $this->config) || $this->config['debug'] !== true) {
228
			return;
229
		}
230
231
		echo $string . "\n";
232
//		$log = '/tmp/' . basename(__FILE__, '.php') . '.log';
233
//		file_put_contents($log, date('Y-m-d H:i:s') . ' ' . $string . "\n", FILE_APPEND);
234
	}
235
236
}
237
238
239
$mailCatcher = new NextcloudMailCatcher($config);
240
241
if (sizeof($argv) === 2 && $argv[1] === 'test') {
242
	$mailCatcher->test();
243
244
	return;
245
}
246
247
echo 'Catching a new mail';
248
249
$content = '';
250
$fd = fopen('php://stdin', 'r');
251
while (!feof($fd)) {
0 ignored issues
show
Bug introduced by
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 ignore-type  annotation

251
while (!feof(/** @scrutinizer ignore-type */ $fd)) {
Loading history...
252
	$content .= fread($fd, 1024);
0 ignored issues
show
Bug introduced by
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 ignore-type  annotation

252
	$content .= fread(/** @scrutinizer ignore-type */ $fd, 1024);
Loading history...
253
}
254
255
$mailCatcher->setContent($content);
256
$mailCatcher->sendToNextcloud();
257
258
259
260
261