Skip to content
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

[!!!][TASK] Allow to disable siteHash check by setting query.allowedSites to * #929

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
129 changes: 129 additions & 0 deletions Classes/Domain/Site/SiteHashService.php
@@ -0,0 +1,129 @@
<?php

namespace ApacheSolrForTypo3\Solr\Domain\Site;

/***************************************************************
* Copyright notice
*
* (c) 2017- Timo Hund <timo.hund@dkd.de>
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script 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 General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/

use ApacheSolrForTypo3\Solr\Site;

/**
* SiteHashService
*
* Responsible to provide sitehash related service methods.
*
* @author Timo Hund <timo.hund@dkd.de>
*/
class SiteHashService
{

/**
* Resolves magic keywords in allowed sites configuration.
* Supported keywords:
* __solr_current_site - The domain of the site the query has been started from
* __current_site - Same as __solr_current_site
* __all - Adds all domains as allowed sites
* * - Means all sites are allowed, same as no siteHash
*
* @param integer $pageId A page ID that is then resolved to the site it belongs to
* @param string $allowedSitesConfiguration TypoScript setting for allowed sites
* @return string List of allowed sites/domains, magic keywords resolved
*/
public function getAllowedSitesForPageIdAndAllowedSitesConfiguration($pageId, $allowedSitesConfiguration)
{
if ($allowedSitesConfiguration === '__all') {
return $this->getDomainListOfAllSites();
} elseif ($allowedSitesConfiguration === '*') {
return '*';
} else {
return $this->getDomainByPageIdAndReplaceMarkers($pageId, $allowedSitesConfiguration);
}
}

/**
* Gets the site hash for a domain
*
* @param string $domain Domain to calculate the site hash for.
* @return string site hash for $domain
*/
public function getSiteHashForDomain($domain)
{
static $siteHashes = [];
if (isset($siteHashes[$domain])) {
return $siteHashes[$domain];
}

$siteHashes[$domain] = sha1($domain . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] . 'tx_solr');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just moved, the hash should be the same as before

return $siteHashes[$domain];
}


/**
* Returns a comma separated list of all domains from all sites.
*
* @return string
*/
protected function getDomainListOfAllSites()
{
$sites = $this->getAvailableSites();
$domains = [];
foreach ($sites as $site) {
$domains[] = $site->getDomain();
}

$allowedSites = implode(',', $domains);
return $allowedSites;
}

/**
* Retrieves the domain of the site that belongs to the passed pageId and replaces their markers __solr_current_site
* and __current_site.
*
* @param integer $pageId
* @param string $allowedSitesConfiguration
* @return string
*/
protected function getDomainByPageIdAndReplaceMarkers($pageId, $allowedSitesConfiguration)
{
$domainOfPage = $this->getSiteByPageId($pageId)->getDomain();
$allowedSites = str_replace(['__solr_current_site', '__current_site'], $domainOfPage, $allowedSitesConfiguration);
return (string)$allowedSites;
}

/**
* @return Site[]
*/
protected function getAvailableSites()
{
return Site::getAvailableSites();
}

/**
* @param $pageId
* @return Site
*/
protected function getSiteByPageId($pageId)
{
return Site::getSiteByPageId($pageId);
}
}
99 changes: 99 additions & 0 deletions Classes/Domain/Variants/IdBuilder.php
@@ -0,0 +1,99 @@
<?php

namespace ApacheSolrForTypo3\Solr\Domain\Variants;

/***************************************************************
* Copyright notice
*
* (c) 2017- Timo Hund <timo.hund@dkd.de>
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script 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 General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/

use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
* The variantId can be used to group documents by a variantId. This variantId is by default unique per system,
* and has the following syntax:
*
* <SystemHash>/type/uid
*
* A file from one system will get the same variantId, which could be useful for de-duplication.
* @author Timo Hund <timo.hund@dkd.de>
*/
class IdBuilder
{

/**
* This method is used to build a variantId.
*
* By default the variantId is used
* @param string $type
* @param integer $uid
* @return string
*/
public function buildFromTypeAndUid($type, $uid)
{
$systemHash = $this->getSystemHash();
$variantId = $systemHash . '/' . $type . '/' . $uid;

$variantId = $this->applyHook($variantId, $systemHash, $type, $uid);
return $variantId;
}

/**
* Applies configured postProcessing hooks to build a custom variantId.
*
* @param string $variantId
* @param string $systemHash
* @param string $type
* @param integer $uid
* @return string
*/
protected function applyHook($variantId, $systemHash, $type, $uid)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would be better to use the new Signal concept in TYPO3? - I think hooks are only kept for compatibility

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

signals don't work for every scenario. If you want to change data, you still need hooks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think signals and slots are more like "events" and the intension is normally a one way direction. It is possible to return data, but only by passing a variable by reference (what is not optimal i would say). I think with hooks you can directly return a value, what is needed in this case (Add btw. in the changes of the core also new hooks are added).

{
if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['modifyVariantId'])) {
return $variantId;
}

foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['modifyVariantId'] as $classReference) {
$variantIdModifier = GeneralUtility::getUserObj($classReference);
if ($variantIdModifier instanceof IdModifier) {
$variantId = $variantIdModifier->modifyVariantId($variantId, $systemHash, $type, $uid);
}
}

return $variantId;
}

/**
* Returns a system unique hash.
*
* @return string
*/
protected function getSystemHash()
{
if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'])) {
throw new \InvalidArgumentException("No sitename set in TYPO3_CONF_VARS|SYS|sitename");
}

$siteName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
$systemKey = 'tx_solr' . $siteName;
return GeneralUtility::hmac($systemKey);
}
}
45 changes: 45 additions & 0 deletions Classes/Domain/Variants/IdModifier.php
@@ -0,0 +1,45 @@
<?php

namespace ApacheSolrForTypo3\Solr\Domain\Variants;

/***************************************************************
* Copyright notice
*
* (c) 2017- Timo Hund <timo.hund@dkd.de>
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script 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 General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/


/**
* An implementation of this class can be used to modify the variantId.
*
* @author Timo Hund <timo.hund@dkd.de>
*/
interface IdModifier
{

/**
* @param string $variantId
* @param string $systemHash
* @param string $type
* @param integer $uid
* @return string
*/
public function modifyVariantId($variantId, $systemHash, $type, $uid);
}
5 changes: 4 additions & 1 deletion Classes/Eid/SiteHash.php
Expand Up @@ -32,6 +32,7 @@
*/

use ApacheSolrForTypo3\Solr\Domain\Site\SiteHashService;
use ApacheSolrForTypo3\Solr\Util;
use TYPO3\CMS\Core\Utility\HttpUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
Expand All @@ -40,7 +41,9 @@
$returnData = '';

if (!empty($domain)) {
$siteHash = Util::getSiteHashForDomain($domain);
/** @var $siteHashService SiteHashService */
$siteHashService = GeneralUtility::makeInstance(SiteHashService::class);
$siteHash = $siteHashService->getSiteHashForDomain($domain);
$returnData = json_encode(['sitehash' => $siteHash]);
} else {
header(HttpUtility::HTTP_STATUS_400);
Expand Down
7 changes: 3 additions & 4 deletions Classes/Eid/Suggest.php
Expand Up @@ -23,6 +23,7 @@
***************************************************************/

use ApacheSolrForTypo3\Solr\ConnectionManager;
use ApacheSolrForTypo3\Solr\Domain\Site\SiteHashService;
use ApacheSolrForTypo3\Solr\Search;
use ApacheSolrForTypo3\Solr\SuggestQuery;
use ApacheSolrForTypo3\Solr\Util;
Expand Down Expand Up @@ -69,10 +70,8 @@
$q = GeneralUtility::_GET('q');
}
$allowedSitesConfig = $solrConfiguration->getObjectByPathOrDefault('plugin.tx_solr.search.query.', []);
$allowedSites = Util::resolveSiteHashAllowedSites(
$pageId,
$allowedSitesConfig['allowedSites']
);
$siteService = GeneralUtility::makeInstance(SiteHashService::class);
$allowedSites = $siteService->getAllowedSitesForPageIdAndAllowedSitesConfiguration($pageId, $allowedSitesConfig['allowedSites']);

$suggestQuery = GeneralUtility::makeInstance(SuggestQuery::class, $q);
$suggestQuery->setUserAccessGroups(explode(',', $GLOBALS['TSFE']->gr_list));
Expand Down
13 changes: 11 additions & 2 deletions Classes/IndexQueue/Indexer.php
Expand Up @@ -27,6 +27,7 @@
use Apache_Solr_Document;
use Apache_Solr_Response;
use ApacheSolrForTypo3\Solr\ConnectionManager;
use ApacheSolrForTypo3\Solr\Domain\Variants\IdBuilder;
use ApacheSolrForTypo3\Solr\FieldProcessor\Service;
use ApacheSolrForTypo3\Solr\NoSolrConnectionFoundException;
use ApacheSolrForTypo3\Solr\Site;
Expand Down Expand Up @@ -76,6 +77,11 @@ class Indexer extends AbstractIndexer
*/
protected $loggingEnabled = false;

/**
* @var IdBuilder
*/
protected $variantIdBuilder;

/**
* Cache of the sys_language_overlay information
*
Expand All @@ -87,11 +93,13 @@ class Indexer extends AbstractIndexer
* Constructor
*
* @param array $options array of indexer options
* @param IdBuilder $idBuilder
*/
public function __construct(array $options = [])
public function __construct(array $options = [], IdBuilder $idBuilder = null)
{
$this->options = $options;
$this->connectionManager = GeneralUtility::makeInstance(ConnectionManager::class);
$this->variantIdBuilder = is_null($idBuilder) ? GeneralUtility::makeInstance(IdBuilder::class) : $idBuilder;
}

/**
Expand Down Expand Up @@ -337,7 +345,8 @@ protected function getBaseDocument(Item $item, array $itemRecord)
$document->setField('pid', $itemRecord['pid']);

// variantId
$document->setField('variantId', $item->getType() . '/' . $itemRecord['uid']);
$variantId = $this->variantIdBuilder->buildFromTypeAndUid($item->getType(), $itemRecord['uid']);
$document->setField('variantId', $variantId);

// created, changed
if (!empty($GLOBALS['TCA'][$item->getType()]['ctrl']['crdate'])) {
Expand Down