Completed
Push — master ( 8024bc...f8f0d2 )
by Vitor
14s
created

Ovh::send()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 55
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
eloc 41
dl 0
loc 55
ccs 0
cts 44
cp 0
rs 8.6417
c 0
b 0
f 0
cc 6
nc 10
nop 2
crap 42

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * SPDX-FileCopyrightText: 2024 Jordan Bieder <[email protected]>
7
 * SPDX-License-Identifier: AGPL-3.0-or-later
8
 */
9
10
namespace OCA\TwoFactorGateway\Provider\Channel\SMS\Provider\Drivers;
11
12
use Exception;
13
use OCA\TwoFactorGateway\Exception\InvalidProviderException;
14
use OCA\TwoFactorGateway\Exception\MessageTransmissionException;
15
use OCA\TwoFactorGateway\Provider\Channel\SMS\Provider\AProvider;
16
use OCA\TwoFactorGateway\Provider\FieldDefinition;
17
use OCA\TwoFactorGateway\Provider\Settings;
18
use OCP\Http\Client\IClient;
19
use OCP\Http\Client\IClientService;
20
21
/**
22
 * @method string getApplicationKey()
23
 * @method static setApplicationKey(string $applicationKey)
24
 * @method string getApplicationSecret()
25
 * @method static setApplicationSecret(string $applicationSecret)
26
 * @method string getConsumerKey()
27
 * @method static setConsumerKey(string $consumerKey)
28
 * @method string getEndpoint()
29
 * @method static setEndpoint(string $endpoint)
30
 * @method string getAccount()
31
 * @method static setAccount(string $account)
32
 * @method string getSender()
33
 * @method static setSender(string $sender)
34
 */
35
class Ovh extends AProvider {
36
	private IClient $client;
37
38
	/**
39
	 * Url to communicate with Ovh API
40
	 */
41
	private array $endpoints = [
42
		'ovh-eu' => 'https://api.ovh.com/1.0',
43
		'ovh-us' => 'https://api.us.ovhcloud.com/1.0',
44
		'ovh-ca' => 'https://ca.api.ovh.com/1.0',
45
		'kimsufi-eu' => 'https://eu.api.kimsufi.com/1.0',
46
		'kimsufi-ca' => 'https://ca.api.kimsufi.com/1.0',
47
		'soyoustart-eu' => 'https://eu.api.soyoustart.com/1.0',
48
		'soyoustart-ca' => 'https://ca.api.soyoustart.com/1.0',
49
		'runabove-ca' => 'https://api.runabove.com/1.0',
50
	];
51
52
	/**
53
	 * Array of the 4 needed parameters to connect to the API
54
	 */
55
	private array $attrs = [
56
		'AK' => null,
57
		'AS' => null,
58
		'CK' => null,
59
		'endpoint' => null,
60
		'timedelta' => null
61
	];
62
63
64 1
	public function __construct(
65
		IClientService $clientService,
66
	) {
67 1
		$this->client = $clientService->newClient();
68
	}
69
70 1
	public function createSettings(): Settings {
71 1
		return new Settings(
72 1
			id: 'ovh',
73 1
			name: 'OVH',
74 1
			fields: [
75 1
				new FieldDefinition(
76 1
					field: 'endpoint',
77 1
					prompt: 'Please enter the endpoint (ovh-eu, ovh-us, ovh-ca, soyoustart-eu, soyoustart-ca, kimsufi-eu, kimsufi-ca, runabove-ca):',
78 1
				),
79 1
				new FieldDefinition(
80 1
					field: 'application_key',
81 1
					prompt: 'Please enter your application key:',
82 1
				),
83 1
				new FieldDefinition(
84 1
					field: 'application_secret',
85 1
					prompt: 'Please enter your application secret:',
86 1
				),
87 1
				new FieldDefinition(
88 1
					field: 'consumer_key',
89 1
					prompt: 'Please enter your consumer key:',
90 1
				),
91 1
				new FieldDefinition(
92 1
					field: 'account',
93 1
					prompt: 'Please enter your account (sms-*****):',
94 1
				),
95 1
				new FieldDefinition(
96 1
					field: 'sender',
97 1
					prompt: 'Please enter your sender:',
98 1
				),
99 1
			]
100 1
		);
101
	}
102
103
	#[\Override]
104
	public function send(string $identifier, string $message) {
105
		$endpoint = $this->getEndpoint();
106
		$sender = $this->getSender();
107
		$smsAccount = $this->getAccount();
108
109
		$this->attrs['AK'] = $this->getApplicationKey();
110
		$this->attrs['AS'] = $this->getApplicationSecret();
111
		$this->attrs['CK'] = $this->getConsumerKey();
112
		if (!isset($this->endpoints[$endpoint])) {
113
			throw new InvalidProviderException("Endpoint $endpoint not found");
114
		}
115
		$this->attrs['endpoint'] = $this->endpoints[$endpoint];
116
117
		$this->getTimeDelta();
118
119
		$header = $this->getHeader('GET', $this->attrs['endpoint'] . '/sms');
120
		$response = $this->client->get($this->attrs['endpoint'] . '/sms', [
121
			'headers' => $header,
122
		]);
123
		$body = (string)$response->getBody();
124
		$smsServices = json_decode($body, true);
125
126
		$smsAccountFound = false;
127
		foreach ($smsServices as $smsService) {
128
			if ($smsService === $smsAccount) {
129
				$smsAccountFound = true;
130
				break;
131
			}
132
		}
133
		if ($smsAccountFound === false) {
134
			throw new InvalidProviderException("SMS account $smsAccount not found");
135
		}
136
		$content = [
137
			'charset' => 'UTF-8',
138
			'message' => $message,
139
			'noStopClause' => true,
140
			'priority' => 'high',
141
			'receivers' => [ $identifier ],
142
			'senderForResponse' => false,
143
			'sender' => $sender,
144
			'validityPeriod' => 3600
145
		];
146
		$body = json_encode($content);
147
148
		$header = $this->getHeader('POST', $this->attrs['endpoint'] . "/sms/$smsAccount/jobs", $body);
149
		$response = $this->client->post($this->attrs['endpoint'] . "/sms/$smsAccount/jobs", [
150
			'headers' => $header,
151
			'json' => $content,
152
		]);
153
		$body = (string)$response->getBody();
154
		$resultPostJob = json_decode($body, true);
155
156
		if (count($resultPostJob['validReceivers']) === 0) {
157
			throw new MessageTransmissionException("Bad receiver $identifier");
158
		}
159
	}
160
161
	/**
162
	 * Compute time delta between this server and OVH endpoint
163
	 *
164
	 * @throws InvalidProviderException
165
	 */
166
	private function getTimeDelta(): void {
167
		if (!isset($this->attrs['timedelta'])) {
168
			if (!isset($this->attrs['endpoint'])) {
169
				throw new InvalidProviderException('Need to set the endpoint');
170
			}
171
			try {
172
				$response = $this->client->get($this->attrs['endpoint'] . '/auth/time');
173
				$serverTimestamp = (int)$response->getBody();
174
				$this->attrs['timedelta'] = $serverTimestamp - time();
175
			} catch (Exception $ex) {
176
				throw new InvalidProviderException('Unable to calculate time delta:' . $ex->getMessage());
177
			}
178
		}
179
	}
180
181
	/**
182
	 * Make header for Ovh
183
	 * @param string $method The methode use for the query : GET, POST, PUT, DELETE
184
	 * @param string $query The fulle URI for the query: https://eu.api.ovh.com/1.0/......
185
	 * @param string $body JSON encoded body content for the POST request
186
	 * @return array $header Contains the data for the request need by OVH
187
	 */
188
	private function getHeader($method, $query, $body = '') {
189
		$timestamp = time() + $this->attrs['timedelta'];
190
		$prehash = $this->attrs['AS'] . '+' . $this->attrs['CK'] . '+' . $method . '+' . $query . '+' . $body . '+' . $timestamp;
191
		$header = [
192
			'Content-Type' => 'application/json; charset=utf-8',
193
			'X-Ovh-Application' => $this->attrs['AK'],
194
			'X-Ovh-Timestamp' => $timestamp,
195
			'X-Ovh-Signature' => '$1$' . sha1($prehash),
196
			'X-Ovh-Consumer' => $this->attrs['CK'],
197
		];
198
		return $header;
199
	}
200
}
201