sqrl-2.0.0-rc1/src/Sqrl.php
src/Sqrl.php
<?php
namespace Drupal\sqrl;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\PageCache\ResponsePolicy\KillSwitch;
use Drupal\Core\Session\AccountProxy;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides SQRL services.
*/
class Sqrl {
use StringManipulation;
/**
* The configuration.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected ImmutableConfig $config;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountProxy
*/
protected AccountProxy $currentUser;
/**
* The nut service.
*
* @var \Drupal\sqrl\Nut|null
*/
protected ?Nut $nut = NULL;
/**
* The container.
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected ContainerInterface $container;
/**
* The log channel.
*
* @var \Drupal\sqrl\Log
*/
protected Log $log;
/**
* The nut domain.
*
* @var string
*/
protected string $nutDomain;
/**
* The nut base path.
*
* @var string
*/
protected string $nutBasePath = '/';
/**
* The assets service.
*
* @var \Drupal\sqrl\Assets
*/
protected Assets $assets;
/**
* The cache kill switch.
*
* @var \Drupal\Core\PageCache\ResponsePolicy\KillSwitch
*/
protected KillSwitch $killSwitch;
/**
* The list of modules.
*
* @var \Drupal\Core\Extension\ModuleExtensionList
*/
protected ModuleExtensionList $moduleExtensionList;
/**
* Constructs a FormAlter object.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Drupal\Core\Session\AccountProxy $current_user
* The current user.
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The container.
* @param \Drupal\Core\PageCache\ResponsePolicy\KillSwitch $kill_switch
* The cache kill switch.
* @param \Drupal\sqrl\Assets $assets
* The assets service.
* @param \Drupal\sqrl\Log $log
* The log channel.
* @param \Drupal\Core\Extension\ModuleExtensionList $moduleExtensionList
* The list of modules.
*/
public function __construct(ConfigFactoryInterface $config_factory, AccountProxy $current_user, ContainerInterface $container, KillSwitch $kill_switch, Assets $assets, Log $log, ModuleExtensionList $moduleExtensionList) {
$this->config = $config_factory->get('sqrl.settings');
$this->currentUser = $current_user;
$this->container = $container;
$this->log = $log;
$this->assets = $assets;
$this->killSwitch = $kill_switch;
$this->moduleExtensionList = $moduleExtensionList;
}
/**
* Sets the nut.
*
* @param \Drupal\sqrl\Nut $nut
* The nut.
*
* @return $this
* This sqrl service.
*/
public function setNut(Nut $nut): self {
$this->nut = $nut;
return $this;
}
/**
* Gets the nut.
*
* @return \Drupal\sqrl\Nut
* The nut.
*/
public function getNut(): Nut {
if ($this->nut === NULL) {
$this->nut = $this->getNewNut();
}
return $this->nut;
}
/**
* Creates and returns a new nut.
*
* @return \Drupal\sqrl\Nut
* The new nut.
*/
public function getNewNut(): Nut {
return Nut::create($this->container);
}
/**
* Get the nut as a url.
*
* @return string
* The nut url.
*/
public function getNutUrl(): string {
$protocols = UrlHelper::getAllowedProtocols();
$protocols[] = 'sqrl';
UrlHelper::setAllowedProtocols($protocols);
$url = $this->getPath('sqrl.client', [], TRUE, TRUE, TRUE);
$parts = parse_url($url);
$url = str_replace($parts['scheme'] . '://', 'sqrl://', $url);
if ($parts['path'] !== '/sqrl/client') {
// If the base_url contains a path component, then we have to append a
// single "|" and avoid the subsequent "/" to indicate the domain string.
$url = str_replace($parts['path'], str_replace('/sqrl', '|/sqrl', $parts['path']), $url);
$this->nutBasePath = substr($parts['path'], 0, strpos($parts['path'], '/sqrl'));
}
$this->nutDomain = $parts['host'];
if (isset($parts['port']) && $parts['port'] !== 80 && $parts['port'] !== 443) {
$this->nutDomain .= ':' . $parts['port'];
}
return $url;
}
/**
* Get the url for a route.
*
* @param string $route
* The route.
* @param array $parameters
* The route parameters.
* @param bool $include_nut
* TRUE, if the nut should be included.
* @param bool $absolute
* TRUE, if the url should be absolute.
* @param bool $include_can
* TRUE, if the "can" should be included.
*
* @return \Drupal\Core\Url
* The url.
*/
public function getUrl(string $route, array $parameters = [], bool $include_nut = TRUE, bool $absolute = TRUE, bool $include_can = FALSE): Url {
$query = [];
if ($include_nut) {
$query['nut'] = (string) $this->nut;
}
if ($include_can) {
$query['can'] = $this->base64Encode($this->getPath('sqrl.cps.url.cancel', ['token' => $this->getNut()->getCancelToken()]));
}
if (defined('SQRL_XDEBUG')) {
$query['XDEBUG_SESSION_START'] = 'IDEA';
}
return Url::fromRoute($route, $parameters, [
'absolute' => $absolute,
'https' => TRUE,
'query' => $query,
]);
}
/**
* Get the url for a route as a string.
*
* @param string $route
* The route.
* @param array $parameters
* The route parameters.
* @param bool $include_nut
* TRUE, if the nut should be included.
* @param bool $absolute
* TRUE, if the url should be absolute.
* @param bool $include_can
* TRUE, if the "can" should be included.
*
* @return string
* The url as a string.
*/
public function getPath(string $route, array $parameters = [], bool $include_nut = TRUE, bool $absolute = TRUE, bool $include_can = FALSE): string {
return $this->getUrl($route, $parameters, $include_nut, $absolute, $include_can)->toString();
}
/**
* Build the SQRL widget for an operation.
*
* @param string $op
* The operation.
*
* @return array
* The render array.
*/
public function buildMarkup(string $op): array {
$this->killSwitch->trigger();
$this->nut = $this->getNewNut();
$this->nut->setClientOperation($op);
$nuturl = $this->getNutUrl();
return [
'#theme' => 'sqrl_widget',
'#allowed_tags' => array_merge(Xss::getAdminTagList(), ['div', 'a', 'script', 'img']),
'#weight' => 999,
'#title' => $this->assets->getOperationTitle($op),
'#operation' => $op,
'#nuturl' => $nuturl,
'#encodednuturl' => $this->base64Encode($nuturl),
'#logourl' => Url::fromUserInput('/' . $this->moduleExtensionList->getPath('sqrl') . '/image/icon.png'),
'#qrcodeurl' => $this->getPath('sqrl.img'),
'#qrcodesize' => $this->config->get('qr_size'),
'#description' => $this->assets->getOperationDescription($op),
'#attached' => [
'drupalSettings' => [
'sqrl' => [
'authenticated' => FALSE,
'canceled' => FALSE,
'debug' => $this->config->get('debug'),
'destination' => FALSE,
'url' => [
'markup' => $this->getPath('sqrl.ajax', ['op' => 'markup'], FALSE),
'poll' => $this->getPath('sqrl.ajax', ['op' => 'poll']),
],
'pollIntervalInitial' => $this->config->get('poll_interval_initial') * 1000,
'pollInterval' => $this->config->get('poll_interval') * 1000,
],
],
'library' => [
'sqrl/sqrl',
],
],
];
}
/**
* Build the cacheable widget for a SQRL operation.
*
* @param string $op
* The operation.
*
* @return array
* The render array,
*/
public function buildCacheableMarkup(string $op): array {
return [
'#theme' => 'sqrl_widget_cached',
'#title' => $this->assets->getOperationTitle($op),
'#url' => $this->getPath('sqrl.view', ['op' => $op], FALSE),
'#logourl' => Url::fromUserInput('/' . $this->moduleExtensionList->getPath('sqrl') . '/image/icon.png'),
'#description' => $this->assets->getOtherDescription('click'),
'#attached' => [
'library' => [
'sqrl/sqrl',
],
],
];
}
}
