diff options
author | Jordan Bieder <jordan.bieder@uliege.be> | 2020-01-16 18:37:07 +0300 |
---|---|---|
committer | Jordan Bieder <jordan.bieder@geduld.fr> | 2020-01-22 00:34:16 +0300 |
commit | e2942b1549d5129574f1633642aba85e0bc9dcb3 (patch) | |
tree | 4116f54768187c2a530b4fa51a3c3b8799e0dece /lib | |
parent | 2772cbeee7edee3f147b61077e22010518b065d6 (diff) |
Ovh SMS gateway integration
- Add configuration class
- Add Provider class
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Integrate Ovh gateway
- add php API with composer
- install the new dependencies
- Add configuration for ovh
- Update ProviderFactory for ovh
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Debug Ovh sms gateway.
Has been tested with the test function
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Improve documentation since it seems not that easy
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Update Admin Documentation.md
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Update Admin Documentation.md
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Update Admin Documentation.md
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Fix php syntax
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Bump css-loader from 3.4.1 to 3.4.2
Bumps [css-loader](https://github.com/webpack-contrib/css-loader) from 3.4.1 to 3.4.2.
- [Release notes](https://github.com/webpack-contrib/css-loader/releases)
- [Changelog](https://github.com/webpack-contrib/css-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/css-loader/compare/v3.4.1...v3.4.2)
Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
[tx-robot] updated from transifex
[tx-robot] updated from transifex
Add sms77 to help and fix case selection string
Signed-off-by: Olav Seyfarth <nursoda@users.noreply.github.com>
Update OVH sms provider to remove ovh/ovh dependency
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Update OVH sms provider to remove ovh/ovh dependency
Update ovh endpoints
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Fix typos
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Fix typos bis
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Fix POST request
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Remove ovh/ovh with composer
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Stupid commit to get the DCO ?!
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Add requested corrections
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Fix indentation
Signed-off-by: Jordan Bieder <jordan.bieder@geduld.fr>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Command/Configure.php | 38 | ||||
-rw-r--r-- | lib/Service/Gateway/SMS/Provider/Ovh.php | 185 | ||||
-rw-r--r-- | lib/Service/Gateway/SMS/Provider/OvhConfig.php | 109 | ||||
-rw-r--r-- | lib/Service/Gateway/SMS/Provider/ProviderFactory.php | 2 |
4 files changed, 332 insertions, 2 deletions
diff --git a/lib/Command/Configure.php b/lib/Command/Configure.php index 8808cf2..10c5787 100644 --- a/lib/Command/Configure.php +++ b/lib/Command/Configure.php @@ -32,6 +32,7 @@ use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\ClockworkSMSConfig; use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\EcallSMSConfig; use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\PlaySMSConfig; use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\Sms77IoConfig; +use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\OvhConfig; use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\WebSmsConfig; use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\PuzzelSMSConfig; use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\HuaweiE3531Config; @@ -105,7 +106,7 @@ class Configure extends Command { private function configureSms(InputInterface $input, OutputInterface $output) { $helper = $this->getHelper('question'); - $providerQuestion = new Question('Please choose a SMS provider (websms, playsms, clockworksms, puzzelsms, ecallsms, voipms, huawei_e3531, spryng): ', 'websms'); + $providerQuestion = new Question('Please choose a SMS provider (websms, playsms, clockworksms, puzzelsms, ecallsms, voipms, huawei_e3531, spryng, sms77io, 'ovh'): ', 'websms'); $provider = $helper->ask($input, $output, $providerQuestion); /** @var SMSConfig $config */ @@ -236,7 +237,7 @@ class Configure extends Command { break; - case 'sms77': + case 'sms77io': $config->setProvider($provider); /** @var Sms77IoConfig $providerConfig */ $providerConfig = $config->getProvider()->getConfig(); @@ -247,6 +248,39 @@ class Configure extends Command { $providerConfig->setApiKey($apiKey); break; + case 'ovh': + $config->setProvider($provider); + + /** @var OvhConfig $providerConfig */ + $providerConfig = $config->getProvider()->getConfig(); + + $endpointQ = new Question('Please enter the endpoint to use (ovh-eu, ovh-us, ovh-ca, soyoustart-eu, soyoustart-ca, kimsufi-eu, kimsufi-ca, runabove-ca): '); + $endpoint = $helper->ask($input, $output, $endpointQ); + + $appKeyQ = new Question('Please enter your application key: '); + $appKey = $helper->ask($input, $output, $appKeyQ); + + $appSecretQ = new Question('Please enter your application secret: '); + $appSecret = $helper->ask($input, $output, $appSecretQ); + + $consumerKeyQ = new Question('Please enter your consumer key: '); + $consumerKey = $helper->ask($input, $output, $consumerKeyQ); + + $accountQ = new Question('Please enter your account (sms-*****): '); + $account = $helper->ask($input, $output, $accountQ); + + $senderQ = new Question('Please enter your sender: '); + $sender = $helper->ask($input, $output, $senderQ); + + $providerConfig->setApplicationKey($appKey); + $providerConfig->setApplicationSecret($appSecret); + $providerConfig->setConsumerKey($consumerKey); + $providerConfig->setEndpoint($endpoint); + $providerConfig->setAccount($account); + $providerConfig->setSender($sender); + break; + + default: $output->writeln("Invalid provider $provider"); break; diff --git a/lib/Service/Gateway/SMS/Provider/Ovh.php b/lib/Service/Gateway/SMS/Provider/Ovh.php new file mode 100644 index 0000000..6aec22a --- /dev/null +++ b/lib/Service/Gateway/SMS/Provider/Ovh.php @@ -0,0 +1,185 @@ +<?php + +declare(strict_types=1); + +/** + * @author Jordan Bieder <jordan.bieder@geduld.fr> + * + * Nextcloud - Two-factor Gateway for Ovh + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCA\TwoFactorGateway\Service\Gateway\SMS\Provider; + +use Exception; +use OCA\TwoFactorGateway\Exception\SmsTransmissionException; +use OCA\TwoFactorGateway\Exception\InvalidSmsProviderException; +use OCP\Http\Client\IClient; +use OCP\Http\Client\IClientService; + +class Ovh implements IProvider { + + const PROVIDER_ID = 'ovh'; + + /** @var IClient */ + private $client; + + /** @var OvhConfig */ + private $config; + + /** + * Url to communicate with Ovh API + * + * @var array + */ + private $endpoints = [ + 'ovh-eu' => 'https://api.ovh.com/1.0', + 'ovh-us' => 'https://api.us.ovhcloud.com/1.0', + 'ovh-ca' => 'https://ca.api.ovh.com/1.0', + 'kimsufi-eu' => 'https://eu.api.kimsufi.com/1.0', + 'kimsufi-ca' => 'https://ca.api.kimsufi.com/1.0', + 'soyoustart-eu' => 'https://eu.api.soyoustart.com/1.0', + 'soyoustart-ca' => 'https://ca.api.soyoustart.com/1.0', + 'runabove-ca' => 'https://api.runabove.com/1.0', + ]; + + /** + * Array of the 4 needed parameters to connect to the API + * @var array + */ + private $attrs = [ + 'AK' => null, + 'AS' => null, + 'CK' => null, + 'endpoint' => null, + 'timedelta' => null + ]; + + + public function __construct(IClientService $clientService, + OvhConfig $config) { + $this->client = $clientService->newClient(); + $this->config = $config; + } + + /** + * @param string $identifier + * @param string $message + * + * @throws SmsTransmissionException + */ + public function send(string $identifier, string $message) { + $config = $this->getConfig(); + $endpoint = $config->getEndpoint(); + $sender = $config->getSender(); + $smsAccount = $config->getAccount(); + + $this->attrs['AK'] = $config->getApplicationKey(); + $this->attrs['AS'] = $config->getApplicationSecret(); + $this->attrs['CK'] = $config->getConsumerKey(); + if (!isset($this->endpoints[$endpoint])) + throw new InvalidSmsProviderException("Endpoint $endpoint not found"); + $this->attrs['endpoint'] = $this->endpoints[$endpoint]; + + $this->getTimeDelta(); + + $header = $this->getHeader('GET',$this->attrs['endpoint'].'/sms'); + $response = $this->client->get($this->attrs['endpoint'].'/sms',[ + 'headers' => $header, + ]); + $smsServices = json_decode($response->getBody(),true); + + $smsAccountFound = false; + foreach ($smsServices as $smsService) { + if ($smsService === $smsAccount) { + $smsAccountFound = true; + break; + } + } + if ($smsAccountFound === false) { + throw new InvalidSmsProviderException("SMS account $smsAccount not found"); + } + $content = [ + "charset"=> "UTF-8", + "message"=> $message, + "noStopClause"=> true, + "priority"=> "high", + "receivers"=> [ $identifier ], + "senderForResponse"=> false, + "sender"=> $sender, + "validityPeriod"=> 3600 + ]; + $body = json_encode($content); + + $header = $this->getHeader('POST',$this->attrs['endpoint']."/sms/$smsAccount/jobs",$body); + $response = $this->client->post($this->attrs['endpoint']."/sms/$smsAccount/jobs",[ + 'headers' => $header, + 'json' => $content, + ]); + $resultPostJob = json_decode($response->getBody(),true); + + if (count($resultPostJob["validReceivers"]) === 0) { + throw new SmsTransmissionException("Bad receiver $identifier"); + } + } + + /** + * @return OvhConfig + */ + public function getConfig(): IProviderConfig { + return $this->config; + } + + /** + * Compute time delta between this server and OVH endpoint + * @throws InvalidSmsProviderException + */ + private function getTimeDelta() { + if (!isset($this->attrs['timedelta'])) { + if (!isset($this->attrs['endpoint'])) + throw new InvalidSmsProviderException('Need to set the endpoint'); + try { + $response = $this->client->get($this->attrs['endpoint'].'/auth/time'); + $serverTimestamp = (int)$response->getBody(); + $this->attrs['timedelta'] = $serverTimestamp - time(); + } + catch (Exception $ex) { + throw new InvalidSmsProviderException('Unable to calculate time delta:'.$ex->getMessage()); + } + } + } + + /** + * Make header for Ovh + * @param string $method The methode use for the query : GET, POST, PUT, DELETE + * @param string $query The fulle URI for the query: https://eu.api.ovh.com/1.0/...... + * @param string $body JSON encoded body content for the POST request + * @return array $header Contains the data for the request need by OVH + */ + private function getHeader($method,$query,$body='') { + $timestamp = time() + $this->attrs['timedelta']; + $prehash = $this->attrs['AS'].'+'.$this->attrs['CK'].'+'.$method.'+'.$query.'+'.$body.'+'.$timestamp; + $header = [ + 'Content-Type' => 'application/json; charset=utf-8', + 'X-Ovh-Application' => $this->attrs['AK'], + 'X-Ovh-Timestamp' => $timestamp, + 'X-Ovh-Signature' => '$1$'.sha1($prehash), + 'X-Ovh-Consumer' => $this->attrs['CK'], + ]; + return $header; + } + + +} diff --git a/lib/Service/Gateway/SMS/Provider/OvhConfig.php b/lib/Service/Gateway/SMS/Provider/OvhConfig.php new file mode 100644 index 0000000..4703bbd --- /dev/null +++ b/lib/Service/Gateway/SMS/Provider/OvhConfig.php @@ -0,0 +1,109 @@ +<?php + +declare(strict_types=1); + +/** + * @author Jordan Bieder <jordan.bieder@geduld.fr> + * + * Nextcloud - Two-factor Gateway for Ovh + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCA\TwoFactorGateway\Service\Gateway\SMS\Provider; + +use function array_intersect; +use OCA\TwoFactorGateway\AppInfo\Application; +use OCA\TwoFactorGateway\Exception\ConfigurationException; +use OCP\IConfig; + +class OvhConfig implements IProviderConfig { + + /** @var IConfig */ + private $config; + + public function __construct(IConfig $config) { + $this->config = $config; + } + + private function getOrFail(string $key): string { + $val = $this->config->getAppValue(Application::APP_NAME, $key, null); + if (is_null($val)) { + throw new ConfigurationException(); + } + return $val; + } + + public function getApplicationKey(): string { + return $this->getOrFail('ovh_application_key'); + } + + public function getApplicationSecret(): string { + return $this->getOrFail('ovh_application_secret'); + } + + public function getConsumerKey(): string { + return $this->getOrFail('ovh_consumer_key'); + } + + public function getEndpoint(): string { + return $this->getOrFail('ovh_endpoint'); + } + + public function getAccount(): string { + return $this->getOrFail('ovh_account'); + } + + public function getSender(): string { + return $this->getOrFail('ovh_sender'); + } + + public function setApplicationKey(string $appKey){ + $this->config->setAppValue(Application::APP_NAME, 'ovh_application_key', $appKey); + } + + public function setApplicationSecret(string $appSecret){ + $this->config->setAppValue(Application::APP_NAME, 'ovh_application_secret', $appSecret); + } + + public function setConsumerKey(string $consumerKey){ + $this->config->setAppValue(Application::APP_NAME, 'ovh_consumer_key', $consumerKey); + } + + public function setEndpoint(string $endpoint){ + $this->config->setAppValue(Application::APP_NAME, 'ovh_endpoint', $endpoint); + } + + public function setAccount($account){ + $this->config->setAppValue(Application::APP_NAME, 'ovh_account', $account); + } + + public function setSender($sender){ + $this->config->setAppValue(Application::APP_NAME, 'ovh_sender', $sender); + } + + public function isComplete(): bool { + $set = $this->config->getAppKeys(Application::APP_NAME); + $expected = [ + 'ovh_application_key', + 'ovh_application_secret', + 'ovh_consumer_key', + 'ovh_endpoint', + 'ovh_account', + 'ovh_sender' + ]; + return count(array_intersect($set, $expected)) === count($expected); + } + +} diff --git a/lib/Service/Gateway/SMS/Provider/ProviderFactory.php b/lib/Service/Gateway/SMS/Provider/ProviderFactory.php index b27c341..d3f3614 100644 --- a/lib/Service/Gateway/SMS/Provider/ProviderFactory.php +++ b/lib/Service/Gateway/SMS/Provider/ProviderFactory.php @@ -53,6 +53,8 @@ class ProviderFactory { return $this->container->query(HuaweiE3531::class); case Sms77Io::PROVIDER_ID: return $this->container->query(Sms77Io::class); + case Ovh::PROVIDER_ID: + return $this->container->query(Ovh::class); case SpryngSMS::PROVIDER_ID: return $this->container->query(SpryngSMS::class); default: |