-
Notifications
You must be signed in to change notification settings - Fork 62
Add CustomSMS a generic provider #473
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,6 +30,8 @@ | |
| use OCA\TwoFactorGateway\Service\Gateway\SMS\GatewayConfig as SMSConfig; | ||
| use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\ClickSendConfig; | ||
| use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\ClockworkSMSConfig; | ||
| use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\CustomSMS; | ||
| use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\CustomSMSConfig; | ||
| use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\EcallSMSConfig; | ||
| use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\PlaySMSConfig; | ||
| use OCA\TwoFactorGateway\Service\Gateway\SMS\Provider\Sms77IoConfig; | ||
|
|
@@ -110,12 +112,101 @@ private function configureSignal(InputInterface $input, OutputInterface $output) | |
| 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, voipbuster, huawei_e3531, spryng, sms77io, ovh, clickatellcentral, clicksend): ', 'websms'); | ||
| $providerQuestion = new Question('Please choose a SMS provider (customsms, websms, playsms, clockworksms, puzzelsms, ecallsms, voipms, voipbuster, huawei_e3531, spryng, sms77io, ovh, clickatellcentral, clicksend): ', 'customsms'); | ||
| $provider = $helper->ask($input, $output, $providerQuestion); | ||
|
|
||
| /** @var SMSConfig $config */ | ||
| $config = $this->smsGateway->getConfig(); | ||
| switch ($provider) { | ||
| case 'customsms': | ||
| $config->setProvider($provider); | ||
| /** @var CustomSMSConfig $providerConfig */ | ||
| $providerConfig = $config->getProvider()->getConfig(); | ||
|
|
||
| ReTypeUrl: | ||
| $urlQuestion = new Question('Please enter the web service URL: '); | ||
| $url = $helper->ask($input, $output, $urlQuestion); | ||
|
|
||
| if(!filter_var($url, FILTER_VALIDATE_URL)) | ||
| { | ||
| $output->writeln('Invalid URL '.$url); | ||
| goto ReTypeUrl; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| } | ||
|
|
||
| ReTypeMethod: | ||
| $methodQuestion = new Question('Please enter the web service method (GET or POST): '); | ||
| $method = (string)$helper->ask($input, $output, $methodQuestion); | ||
|
|
||
| if(strtolower($method) != 'get' && strtolower($method) != 'post') | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is a good practice use |
||
| { | ||
| $output->writeln('Invalid method '.$method); | ||
| goto ReTypeMethod; | ||
| } | ||
|
|
||
| ReTypeIdentifier: | ||
| $identifierQuestion = new Question('Please enter the identifier parameter for mobile number (Eg. mobile or number): '); | ||
| $identifier = $helper->ask($input, $output, $identifierQuestion); | ||
|
|
||
| if(empty($identifier)) | ||
| { | ||
| $output->writeln('Mobile number parameter cannot be empty'); | ||
| goto ReTypeIdentifier; | ||
| } | ||
|
|
||
| ReTypeMessage: | ||
| $messageQuestion = new Question('Please enter the message parameter (Eg. msg, sms, message): '); | ||
| $message = $helper->ask($input, $output, $messageQuestion); | ||
|
|
||
| if(empty($message)) | ||
| { | ||
| $output->writeln('Message parameter cannot be empty'); | ||
| goto ReTypeMessage; | ||
| } | ||
|
|
||
| ReTypeHeaders: | ||
| $headersQuestion = new Question('Please enter any http headers (Eg. x-api-key=123456789&x-api-token=ABCD12345 etc.): '); | ||
| $headers = $helper->ask($input, $output, $headersQuestion); | ||
|
|
||
| if(!empty($headers)) | ||
| { | ||
| parse_str($headers, $headers_array); | ||
| if(!is_array($headers_array)) | ||
| { | ||
| $output->writeln('headers is invalid'); | ||
| goto ReTypeHeaders; | ||
| } | ||
| } | ||
| else | ||
| { | ||
| $headers=''; | ||
| } | ||
|
|
||
| ReTypeParameters: | ||
| $parametersQuestion = new Question('Please enter any extra parameters (Eg. sender=nextcloud&username=nextcloud&password=1234 etc.): '); | ||
| $parameters = $helper->ask($input, $output, $parametersQuestion); | ||
|
|
||
| if(!empty($parameters)) | ||
| { | ||
| parse_str($parameters, $parameters_array); | ||
| if(!is_array($parameters_array)) | ||
| { | ||
| $output->writeln('Extra parameters is invalid'); | ||
| goto ReTypeParameters; | ||
| } | ||
| } | ||
| else | ||
| { | ||
| $parameters=''; | ||
| } | ||
|
|
||
| $providerConfig->setUrl($url); | ||
| $providerConfig->setMethod($method); | ||
| $providerConfig->setIdentifier($identifier); | ||
| $providerConfig->setMessage($message); | ||
| $providerConfig->setHeaders($headers); | ||
| $providerConfig->setParameters($parameters); | ||
|
|
||
| break; | ||
| case 'websms': | ||
| $config->setProvider($provider); | ||
| /** @var WebSmsConfig $providerConfig */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| /** | ||
| * @author Daif Alazmi <[email protected]> | ||
| * | ||
| * Nextcloud - Two-factor Gateway | ||
| * | ||
| * 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 OCP\Http\Client\IClient; | ||
| use OCP\Http\Client\IClientService; | ||
|
|
||
| class CustomSMS implements IProvider { | ||
| public const PROVIDER_ID = 'customsms'; | ||
|
|
||
| /** @var IClient */ | ||
| private $client; | ||
|
|
||
| /** @var CustomSMSConfig */ | ||
| private $config; | ||
|
|
||
| public function __construct(IClientService $clientService, | ||
| CustomSMSConfig $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(); | ||
|
|
||
| try { | ||
|
|
||
| if(strtolower($config->getMethod()) == 'get') | ||
| { | ||
| $options = [ | ||
| 'query'=> [ | ||
| $config->getIdentifier()=>$identifier, | ||
| $config->getMessage()=>$message, | ||
| ] | ||
| ]; | ||
| parse_str($config->getHeaders(), $headers); | ||
| if(!empty($headers)) | ||
| { | ||
| $options['headers'] = $headers; | ||
| } | ||
| parse_str($config->getParameters(), $parameters); | ||
| if(!empty($parameters)) | ||
| { | ||
| $options['query'] = $options['query'] + $parameters; | ||
| } | ||
| $response = $this->client->get($config->getUrl(),$options); | ||
| } | ||
|
|
||
| if(strtolower($config->getMethod()) == 'post') | ||
| { | ||
| $options = [ | ||
| 'body'=> [ | ||
| $config->getIdentifier()=>$identifier, | ||
| $config->getMessage()=>$message, | ||
| ] | ||
| ]; | ||
| parse_str($config->getHeaders(), $headers); | ||
| if(!empty($headers)) | ||
| { | ||
| $options['headers'] = $headers; | ||
| } | ||
| parse_str($config->getParameters(), $parameters); | ||
| if(!empty($parameters)) | ||
| { | ||
| $options['body'] = $options['body'] + $parameters; | ||
| } | ||
| $this->client->post($config->getUrl(),$options); | ||
| } | ||
|
|
||
| } catch (Exception $ex) { | ||
| throw new SmsTransmissionException(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @return CustomSMSConfig | ||
| */ | ||
| public function getConfig(): IProviderConfig { | ||
| return $this->config; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| /** | ||
| * @author Daif Alazmi <[email protected]> | ||
| * | ||
| * Nextcloud - Two-factor Gateway | ||
| * | ||
| * 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 CustomSMSConfig implements IProviderConfig { | ||
|
|
||
| const expected = [ | ||
| 'customsms_url', | ||
| 'customsms_method', | ||
| 'customsms_identifier', | ||
| 'customsms_message', | ||
| 'customsms_headers', | ||
| 'customsms_parameters', | ||
| ]; | ||
|
|
||
| /** @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 getUrl(): string { | ||
| return $this->getOrFail('customsms_url'); | ||
| } | ||
|
|
||
| public function setUrl(string $url) { | ||
| $this->config->setAppValue(Application::APP_NAME, 'customsms_url', $url); | ||
| } | ||
|
|
||
| public function getMethod(): string { | ||
| return $this->getOrFail('customsms_method'); | ||
| } | ||
|
|
||
| public function setMethod(string $method) { | ||
| $this->config->setAppValue(Application::APP_NAME, 'customsms_method', $method); | ||
| } | ||
|
|
||
| public function getIdentifier(): string { | ||
| return $this->getOrFail('customsms_identifier'); | ||
| } | ||
|
|
||
| public function setIdentifier(string $identifier) { | ||
| $this->config->setAppValue(Application::APP_NAME, 'customsms_identifier', $identifier); | ||
| } | ||
|
|
||
| public function getMessage(): string { | ||
| return $this->getOrFail('customsms_message'); | ||
| } | ||
|
|
||
| public function setMessage(string $message) { | ||
| $this->config->setAppValue(Application::APP_NAME, 'customsms_message', $message); | ||
| } | ||
|
|
||
| public function getHeaders(): string { | ||
| return $this->getOrFail('customsms_headers'); | ||
| } | ||
|
|
||
| public function setHeaders(string $headers) { | ||
| $this->config->setAppValue(Application::APP_NAME, 'customsms_headers', $headers); | ||
| } | ||
|
|
||
| public function getParameters(): string { | ||
| return $this->getOrFail('customsms_parameters'); | ||
| } | ||
|
|
||
| public function setParameters(string $parameters) { | ||
| $this->config->setAppValue(Application::APP_NAME, 'customsms_parameters', $parameters); | ||
| } | ||
|
|
||
| public function isComplete(): bool { | ||
| $set = $this->config->getAppKeys(Application::APP_NAME); | ||
| return count(array_intersect($set, self::expected)) === count(self::expected); | ||
| } | ||
|
|
||
| public function remove() { | ||
| foreach(self::expected as $key) { | ||
| $this->config->deleteAppValue(Application::APP_NAME, $key); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that will be good implement examples of supported API payload with GET and POST.
For example:
Provider with GET:
Need accept URL on this format:
<base_url_provider>?<mobile_number_parameter>=<number> ....Provider with POST:
...
Mandatory parameters: