OneTouch.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <?php
  2. /**
  3. * MageSpecialist
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to info@magespecialist.it so we can send you a copy immediately.
  14. *
  15. * @category MSP
  16. * @package MSP_NoSpam
  17. * @copyright Copyright (c) 2017 Skeeller srl (http://www.magespecialist.it)
  18. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  19. */
  20. namespace MSP\TwoFactorAuth\Model\Provider\Engine\Authy;
  21. use Magento\Framework\App\Config\ScopeConfigInterface;
  22. use Magento\Framework\Exception\LocalizedException;
  23. use Magento\Framework\HTTP\Client\CurlFactory;
  24. use Magento\Framework\Json\DecoderInterface;
  25. use Magento\Store\Model\StoreManagerInterface;
  26. use Magento\User\Api\Data\UserInterface;
  27. use MSP\TwoFactorAuth\Api\UserConfigManagerInterface;
  28. use MSP\TwoFactorAuth\Model\Provider\Engine\Authy;
  29. class OneTouch
  30. {
  31. const XML_PATH_ONETOUCH_MESSAGE = 'msp_securitysuite_twofactorauth/authy/onetouch_message';
  32. /**
  33. * @var CurlFactory
  34. */
  35. private $curlFactory;
  36. /**
  37. * @var UserConfigManagerInterface
  38. */
  39. private $userConfigManager;
  40. /**
  41. * @var StoreManagerInterface
  42. */
  43. private $storeManager;
  44. /**
  45. * @var Service
  46. */
  47. private $service;
  48. /**
  49. * @var DecoderInterface
  50. */
  51. private $decoder;
  52. /**
  53. * @var ScopeConfigInterface
  54. */
  55. private $scopeConfig;
  56. /**
  57. * OneTouch constructor.
  58. * @param CurlFactory $curlFactory
  59. * @param UserConfigManagerInterface $userConfigManager
  60. * @param DecoderInterface $decoder
  61. * @param Service $service
  62. * @param StoreManagerInterface $storeManager
  63. * @param ScopeConfigInterface $scopeConfig
  64. */
  65. public function __construct(
  66. CurlFactory $curlFactory,
  67. UserConfigManagerInterface $userConfigManager,
  68. DecoderInterface $decoder,
  69. Service $service,
  70. StoreManagerInterface $storeManager,
  71. ScopeConfigInterface $scopeConfig
  72. ) {
  73. $this->curlFactory = $curlFactory;
  74. $this->userConfigManager = $userConfigManager;
  75. $this->storeManager = $storeManager;
  76. $this->service = $service;
  77. $this->decoder = $decoder;
  78. $this->scopeConfig = $scopeConfig;
  79. }
  80. /**
  81. * Request one-touch
  82. * @param UserInterface $user
  83. * @return true
  84. * @throws LocalizedException
  85. */
  86. public function request(UserInterface $user)
  87. {
  88. $providerInfo = $this->userConfigManager->getProviderConfig($user->getId(), Authy::CODE);
  89. if (!isset($providerInfo['user'])) {
  90. throw new LocalizedException(__('Missing user information'));
  91. }
  92. $url = $this->service->getOneTouchApiEndpoint('users/' . $providerInfo['user'] . '/approval_requests');
  93. $curl = $this->curlFactory->create();
  94. $curl->addHeader('X-Authy-API-Key', $this->service->getApiKey());
  95. $curl->post($url, [
  96. 'message' => $this->scopeConfig->getValue(self::XML_PATH_ONETOUCH_MESSAGE),
  97. 'details[URL]' => $this->storeManager->getStore()->getBaseUrl(),
  98. 'details[User]' => $user->getUserName(),
  99. 'details[Email]' => $user->getEmail(),
  100. 'seconds_to_expire' => 300,
  101. ]);
  102. $response = $this->decoder->decode($curl->getBody());
  103. if ($errorMessage = $this->service->getErrorFromResponse($response)) {
  104. throw new LocalizedException(__($errorMessage));
  105. }
  106. $this->userConfigManager->addProviderConfig($user->getId(), Authy::CODE, [
  107. 'pending_approval' => $response['approval_request']['uuid'],
  108. ]);
  109. return true;
  110. }
  111. /**
  112. * Verify one-touch
  113. * @param UserInterface $user
  114. * @return string
  115. * @throws LocalizedException
  116. */
  117. public function verify(UserInterface $user)
  118. {
  119. $providerInfo = $this->userConfigManager->getProviderConfig($user->getId(), Authy::CODE);
  120. if (!isset($providerInfo['user'])) {
  121. throw new LocalizedException(__('Missing user information'));
  122. }
  123. if (!isset($providerInfo['pending_approval'])) {
  124. throw new LocalizedException(__('No approval requests for this user'));
  125. }
  126. $approvalCode = $providerInfo['pending_approval'];
  127. if (!preg_match('/^\w[\w\-]+\w$/', $approvalCode)) {
  128. throw new LocalizedException(__('Invalid approval code'));
  129. }
  130. $url = $this->service->getOneTouchApiEndpoint('approval_requests/' . $approvalCode);
  131. $times = 10;
  132. for ($i=0; $i<$times; $i++) {
  133. $curl = $this->curlFactory->create();
  134. $curl->addHeader('X-Authy-API-Key', $this->service->getApiKey());
  135. $curl->get($url);
  136. $response = $this->decoder->decode($curl->getBody());
  137. if ($errorMessage = $this->service->getErrorFromResponse($response)) {
  138. throw new LocalizedException(__($errorMessage));
  139. }
  140. $status = $response['approval_request']['status'];
  141. if ($status == 'pending') {
  142. // @codingStandardsIgnoreStart
  143. sleep(1); // I know... but it is the only option I have here
  144. // @codingStandardsIgnoreEnd
  145. continue;
  146. }
  147. if ($status == 'approved') {
  148. return $status;
  149. }
  150. return $status;
  151. }
  152. return 'retry';
  153. }
  154. }