Completed
Push — master ( 7be6c6...dd953d )
by Christoph
03:24 queued 10s
created

Ovh::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @author Jordan Bieder <[email protected]>
7
 *
8
 * Nextcloud - Two-factor Gateway for Ovh
9
 *
10
 * This code is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License, version 3,
12
 * as published by the Free Software Foundation.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License, version 3,
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
21
 *
22
 */
23
24
namespace OCA\TwoFactorGateway\Service\Gateway\SMS\Provider;
25
26
use Exception;
27
use OCA\TwoFactorGateway\Exception\SmsTransmissionException;
28
use OCA\TwoFactorGateway\Exception\InvalidSmsProviderException;
29
use OCP\Http\Client\IClient;
30
use OCP\Http\Client\IClientService;
31
32
class Ovh implements IProvider {
33
34
	const PROVIDER_ID = 'ovh';
35
36
	/** @var IClient */
37
	private $client;
38
39
	/** @var OvhConfig */
40
	private $config;
41
42
	/**
43
	 * Url to communicate with Ovh API
44
	 *
45
	 * @var array
46
	 */
47
	private $endpoints = [
48
		'ovh-eu'        => 'https://api.ovh.com/1.0',
49
		'ovh-us'        => 'https://api.us.ovhcloud.com/1.0',
50
		'ovh-ca'        => 'https://ca.api.ovh.com/1.0',
51
		'kimsufi-eu'    => 'https://eu.api.kimsufi.com/1.0',
52
		'kimsufi-ca'    => 'https://ca.api.kimsufi.com/1.0',
53
		'soyoustart-eu' => 'https://eu.api.soyoustart.com/1.0',
54
		'soyoustart-ca' => 'https://ca.api.soyoustart.com/1.0',
55
		'runabove-ca'   => 'https://api.runabove.com/1.0',
56
	];
57
58
	/**
59
	 * Array of the 4 needed parameters to connect to the API
60
	 * @var array
61
	 */
62
	private $attrs = [ 
63
		'AK' => null, 
64
		'AS' => null,
65
		'CK' => null,
66
		'endpoint' => null,
67
		'timedelta' => null
68
	];
69
70
71
	public function __construct(IClientService $clientService,
72
                                OvhConfig $config) {
73
		$this->client = $clientService->newClient();
74
		$this->config = $config;
75
	}
76
77
	/**
78
	 * @param string $identifier
79
	 * @param string $message
80
	 *
81
	 * @throws SmsTransmissionException
82
	 */
83
	public function send(string $identifier, string $message) {
84
		$config = $this->getConfig();
85
		$endpoint = $config->getEndpoint();
86
		$sender = $config->getSender();
87
		$smsAccount = $config->getAccount();
88
89
		$this->attrs['AK'] = $config->getApplicationKey();
90
		$this->attrs['AS'] = $config->getApplicationSecret();
91
		$this->attrs['CK'] = $config->getConsumerKey();
92
		if (!isset($this->endpoints[$endpoint]))
93
			throw new InvalidSmsProviderException("Endpoint $endpoint not found");
94
		$this->attrs['endpoint'] = $this->endpoints[$endpoint];
95
96
		$this->getTimeDelta();
97
98
		$header = $this->getHeader('GET',$this->attrs['endpoint'].'/sms');
99
		$response = $this->client->get($this->attrs['endpoint'].'/sms',[
100
			'headers' => $header,
101
		]);
102
		$smsServices = json_decode($response->getBody(),true);
0 ignored issues
show
Bug introduced by
It seems like $response->getBody() can also be of type resource; however, parameter $json of json_decode() does only seem to accept string, 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

102
		$smsServices = json_decode(/** @scrutinizer ignore-type */ $response->getBody(),true);
Loading history...
103
104
		$smsAccountFound = false;
105
		foreach ($smsServices as $smsService) {
106
			if ($smsService === $smsAccount) {
107
				$smsAccountFound = true;
108
				break;
109
			}
110
		}
111
		if ($smsAccountFound === false) {
112
			throw new InvalidSmsProviderException("SMS account $smsAccount not found");
113
		}
114
		$content = [
115
			"charset"=> "UTF-8",
116
			"message"=> $message,
117
			"noStopClause"=> true,
118
			"priority"=> "high",
119
			"receivers"=> [ $identifier ],
120
			"senderForResponse"=> false,
121
			"sender"=> $sender,
122
			"validityPeriod"=> 3600
123
		];
124
		$body = json_encode($content);
125
126
		$header = $this->getHeader('POST',$this->attrs['endpoint']."/sms/$smsAccount/jobs",$body);
127
		$response = $this->client->post($this->attrs['endpoint']."/sms/$smsAccount/jobs",[
128
			'headers' => $header,
129
			'json' => $content,
130
		]);
131
		$resultPostJob = json_decode($response->getBody(),true);
132
133
		if (count($resultPostJob["validReceivers"]) === 0) {
134
			throw new SmsTransmissionException("Bad receiver $identifier");
135
		}
136
	}
137
138
	/**
139
	 * @return OvhConfig
140
	 */
141
	public function getConfig(): IProviderConfig {
142
		return $this->config;
143
	}
144
145
	/**
146
	 * Compute time delta between this server and OVH endpoint
147
	 * @throws InvalidSmsProviderException
148
	 */
149
	private function getTimeDelta() {
150
		if (!isset($this->attrs['timedelta'])) {
151
			if (!isset($this->attrs['endpoint']))
152
				throw new InvalidSmsProviderException('Need to set the endpoint');
153
			try {
154
				$response         = $this->client->get($this->attrs['endpoint'].'/auth/time');
155
				$serverTimestamp  = (int)$response->getBody();
156
				$this->attrs['timedelta'] = $serverTimestamp - time();
157
			}
158
			catch (Exception $ex) {
159
				throw new InvalidSmsProviderException('Unable to calculate time delta:'.$ex->getMessage());
160
			}
161
		}
162
	}
163
164
	/**
165
	 * Make header for Ovh
166
	 * @param string $method The methode use for the query : GET, POST, PUT, DELETE
167
	 * @param string $query The fulle URI for the query: https://eu.api.ovh.com/1.0/......
168
	 * @param string $body JSON encoded body content for the POST request
169
	 * @return array $header Contains the data for the request need by OVH
170
	 */
171
	private function getHeader($method,$query,$body='') {
172
		$timestamp = time() + $this->attrs['timedelta'];
173
		$prehash = $this->attrs['AS'].'+'.$this->attrs['CK'].'+'.$method.'+'.$query.'+'.$body.'+'.$timestamp;
174
		$header = [
175
			'Content-Type'      => 'application/json; charset=utf-8',
176
			'X-Ovh-Application' => $this->attrs['AK'],
177
			'X-Ovh-Timestamp'   => $timestamp,
178
			'X-Ovh-Signature'   => '$1$'.sha1($prehash),
179
			'X-Ovh-Consumer'    => $this->attrs['CK'],
180
		];
181
		return $header;
182
	}
183
184
185
}
186