Passed
Pull Request — master (#640)
by Vitor
03:36
created

Ovh::send()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 55
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 41
dl 0
loc 55
rs 8.6417
c 0
b 0
f 0
cc 6
nc 10
nop 2

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