Files
newwalls.pl/modules/ps_accounts/classes/Service/ShopLinkAccountService.php
2024-12-17 13:43:22 +01:00

389 lines
11 KiB
PHP

<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsAccounts\Service;
use Module;
use PrestaShop\Module\PsAccounts\Adapter\Link;
use PrestaShop\Module\PsAccounts\Api\Client\ServicesAccountsClient;
use PrestaShop\Module\PsAccounts\Configuration\ConfigOptionsResolver;
use PrestaShop\Module\PsAccounts\Configuration\Configurable;
use PrestaShop\Module\PsAccounts\Exception\HmacException;
use PrestaShop\Module\PsAccounts\Exception\OptionResolutionException;
use PrestaShop\Module\PsAccounts\Exception\QueryParamsException;
use PrestaShop\Module\PsAccounts\Exception\RsaSignedDataNotFoundException;
use PrestaShop\Module\PsAccounts\Exception\SshKeysNotFoundException;
use PrestaShop\Module\PsAccounts\Provider\ShopProvider;
use PrestaShop\Module\PsAccounts\Repository\ConfigurationRepository;
use Ps_accounts;
class ShopLinkAccountService implements Configurable
{
/**
* @var ShopKeysService
*/
private $shopKeysService;
/**
* @var ShopProvider
*/
private $shopProvider;
/**
* @var ShopTokenService
*/
private $shopTokenService;
/**
* @var ConfigurationRepository
*/
private $configuration;
/**
* @var Link
*/
private $link;
/**
* @var string
*/
private $accountsUiUrl;
/**
* ShopLinkAccountService constructor.
*
* @param array $config
* @param ShopProvider $shopProvider
* @param ShopKeysService $shopKeysService
* @param ShopTokenService $shopTokenService
* @param ConfigurationRepository $configuration
* @param Link $link
*
* @throws OptionResolutionException
*/
public function __construct(
array $config,
ShopProvider $shopProvider,
ShopKeysService $shopKeysService,
ShopTokenService $shopTokenService,
ConfigurationRepository $configuration,
Link $link
) {
$this->accountsUiUrl = $this->resolveConfig($config)['accounts_ui_url'];
$this->shopProvider = $shopProvider;
$this->shopKeysService = $shopKeysService;
$this->shopTokenService = $shopTokenService;
$this->configuration = $configuration;
$this->link = $link;
}
/**
* @return ServicesAccountsClient
*/
public function getServicesAccountsClient()
{
/** @var Ps_accounts $module */
$module = Module::getInstanceByName('ps_accounts');
return $module->getService(ServicesAccountsClient::class);
}
/**
* @param array $bodyHttp
* @param string $trigger
*
* @return mixed
*
* @throws \Exception
*/
public function updateShopUrl($bodyHttp, $trigger)
{
if (array_key_exists('shop_id', $bodyHttp)) {
// id for multishop
$this->configuration->setShopId($bodyHttp['shop_id']);
}
$sslEnabled = $this->shopProvider->getShopContext()->sslEnabled();
$protocol = $this->shopProvider->getShopContext()->getProtocol();
$domain = $sslEnabled ? $bodyHttp['domain_ssl'] : $bodyHttp['domain'];
$uuid = $this->configuration->getShopUuid();
$response = false;
$boUrl = $this->replaceScheme(
$this->link->getAdminLink('AdminModules', true),
$protocol . '://' . $domain
);
if ($uuid && strlen($uuid) > 0) {
$response = $this->getServicesAccountsClient()->updateShopUrl(
$uuid,
[
'protocol' => $protocol,
'domain' => $domain,
'boUrl' => $boUrl,
'trigger' => $trigger,
]
);
}
return $response;
}
/**
* @param string $psxName
*
* @return string
*
* @throws \PrestaShopException
*/
public function getLinkAccountUrl($psxName)
{
$callback = $this->replaceScheme(
$this->link->getAdminLink('AdminModules', true) . '&configure=' . $psxName
);
$protocol = $this->shopProvider->getShopContext()->getProtocol();
$currentShop = $this->shopProvider->getCurrentShop($psxName);
$domainName = $this->shopProvider->getShopContext()->sslEnabled() ? $currentShop['domainSsl'] : $currentShop['domain'];
$queryParams = [
'bo' => $callback,
'pubKey' => $this->shopKeysService->getPublicKey(),
'next' => $this->replaceScheme(
$this->link->getAdminLink('AdminConfigureHmacPsAccounts')
),
'name' => $currentShop['name'],
'lang' => $this->shopProvider->getShopContext()->getContext()->language->iso_code,
];
$queryParamsArray = [];
foreach ($queryParams as $key => $value) {
$queryParamsArray[] = $key . '=' . urlencode($value);
}
$strQueryParams = implode('&', $queryParamsArray);
return $this->accountsUiUrl . '/shop/account/link/' . $protocol . '/' . $domainName
. '/' . $protocol . '/' . $domainName . '/' . $psxName . '?' . $strQueryParams;
}
/**
* @param array $queryParams
* @param string $rootDir
*
* @return string
*
* @throws HmacException
* @throws QueryParamsException
* @throws RsaSignedDataNotFoundException
*/
public function getVerifyAccountUrl(array $queryParams, $rootDir)
{
foreach (
[
'hmac' => '/[a-zA-Z0-9]{8,64}/',
'uid' => '/[a-zA-Z0-9]{8,64}/',
'slug' => '/[-_a-zA-Z0-9]{8,255}/',
] as $key => $value
) {
if (!array_key_exists($key, $queryParams)) {
throw new QueryParamsException('Missing query params');
}
if (!preg_match($value, $queryParams[$key])) {
throw new QueryParamsException('Invalid query params');
}
}
$this->writeHmac($queryParams['hmac'], $queryParams['uid'], $rootDir . '/upload/');
if (empty($this->shopKeysService->getSignature())) {
throw new RsaSignedDataNotFoundException('RSA signature not found');
}
$url = $this->accountsUiUrl;
if ('/' === substr($url, -1)) {
$url = substr($url, 0, -1);
}
return $url . '/shop/account/verify/' . $queryParams['uid']
. '?shopKey=' . urlencode($this->shopKeysService->getSignature());
}
/**
* @return array
*
* @throws SshKeysNotFoundException
*/
public function unlinkShop()
{
$response = $this->getServicesAccountsClient()->deleteShop((string) $this->configuration->getShopUuid());
// Réponse: 200: Shop supprimé avec payload contenant un message de confirmation
// Réponse: 404: La shop n'existe pas (not found)
// Réponse: 401: L'utilisateur n'est pas autorisé à supprimer cette shop
if ($response['status'] && 200 === $response['httpCode']
|| 404 === $response['httpCode']) {
$this->resetOnboardingData();
// FIXME regenerate rsa keys
$this->shopKeysService->regenerateKeys();
}
return $response;
}
/**
* Empty onboarding configuration values
*
* @return void
*/
public function resetOnboardingData()
{
$this->configuration->updateAccountsRsaPrivateKey('');
$this->configuration->updateAccountsRsaPublicKey('');
$this->configuration->updateAccountsRsaSignData('');
$this->configuration->updateFirebaseIdAndRefreshTokens('', '');
$this->configuration->updateFirebaseEmail('');
$this->configuration->updateFirebaseEmailIsVerified(false);
$this->configuration->updateShopUuid('');
}
/**
* @param string $psxName
*
* @return void
*
* @throws SshKeysNotFoundException
* @throws \PrestaShopException
*/
public function manageOnboarding($psxName)
{
$this->shopKeysService->generateKeys();
$this->updateOnboardingData($psxName);
}
/**
* Only callable during onboarding
*
* Prepare onboarding data
*
* @param string $psxName
*
* @return void
*
* @throws \PrestaShopException
* @throws \Exception
*/
public function updateOnboardingData($psxName)
{
$email = \Tools::getValue('email');
$emailVerified = \Tools::getValue('emailVerified');
$customToken = \Tools::getValue('adminToken');
if (is_string($customToken)) {
if (false === $this->shopKeysService->hasKeys()) {
throw new \Exception('SSH keys were not found');
}
if (!$this->shopTokenService->exchangeCustomTokenForIdAndRefreshToken($customToken)) {
throw new \Exception('Unable to get Firebase token');
}
if (!empty($email)) {
$this->configuration->updateFirebaseEmail($email);
if (!empty($emailVerified)) {
$this->configuration->updateFirebaseEmailIsVerified('true' === $emailVerified);
}
// FIXME : quick and dirty fix
\Tools::redirectAdmin(
$this->link->getAdminLink('AdminModules', true, [], [
'configure' => $psxName,
])
);
}
}
}
/**
* @return bool
*/
public function isAccountLinked()
{
return $this->shopTokenService->getToken()
&& $this->configuration->getFirebaseEmail();
}
/**
* @param array $config
* @param array $defaults
*
* @return array|mixed
*
* @throws OptionResolutionException
*/
public function resolveConfig(array $config, array $defaults = [])
{
return (new ConfigOptionsResolver([
'accounts_ui_url',
]))->resolve($config, $defaults);
}
/**
* @param string $hmac
* @param string $uid
* @param string $path
*
* @return void
*
* @throws HmacException
*/
private function writeHmac($hmac, $uid, $path)
{
if (!is_dir($path)) {
mkdir($path);
}
if (!is_writable($path)) {
throw new HmacException('Directory isn\'t writable');
}
file_put_contents($path . $uid . '.txt', $hmac);
}
/**
* @param string $url
* @param string $replacement
*
* @return string
*/
private function replaceScheme($url, $replacement = '')
{
return preg_replace('/^https?:\/\/[^\/]+/', $replacement, $url);
}
}