Passed
Pull Request — master (#640)
by Vitor
14:24
created

Ovh::send()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 53
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 39
dl 0
loc 53
rs 8.6737
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
		$smsServices = json_decode($response->getBody(), true);
0 ignored issues
show
Bug introduced by
It seems like $response->getBody() can also be of type null and 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

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