• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tomasnorre / crawler / 11237471329

08 Oct 2024 02:20PM UTC coverage: 68.586% (-1.3%) from 69.862%
11237471329

push

github

web-flow
ci: Update coveralls workflow (#1109)

1834 of 2674 relevant lines covered (68.59%)

3.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.58
/Classes/Middleware/FrontendUserAuthenticator.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace AOE\Crawler\Middleware;
6

7
/*
8
 * (c) 2021 Tomas Norre Mikkelsen <tomasnorre@gmail.com>
9
 *
10
 * This file is part of the TYPO3 Crawler Extension.
11
 *
12
 * It is free software; you can redistribute it and/or modify it under
13
 * the terms of the GNU General Public License, either version 2
14
 * of the License, or any later version.
15
 *
16
 * For the full copyright and license information, please read the
17
 * LICENSE.txt file that was distributed with this source code.
18
 *
19
 * The TYPO3 project - inspiring people to share!
20
 */
21
use AOE\Crawler\Converter\JsonCompatibilityConverter;
22
use AOE\Crawler\Domain\Repository\QueueRepository;
23
use Psr\Http\Message\ResponseInterface;
24
use Psr\Http\Message\ServerRequestInterface;
25
use Psr\Http\Server\MiddlewareInterface;
26
use Psr\Http\Server\RequestHandlerInterface;
27
use TYPO3\CMS\Core\Context\Context;
28
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
29
use TYPO3\CMS\Core\Context\UserAspect;
30
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
31
use TYPO3\CMS\Core\Error\Http\ServiceUnavailableException;
32
use TYPO3\CMS\Core\Utility\GeneralUtility;
33
use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
34
use TYPO3\CMS\Frontend\Controller\ErrorController;
35

36
/**
37
 * Evaluates HTTP headers and checks if Crawler should register itself.
38
 *
39
 * @internal since v12.0.0
40
 */
41
class FrontendUserAuthenticator implements MiddlewareInterface
42
{
43
    protected string $headerName = 'X-T3CRAWLER';
44
    protected Context $context;
45

46
    public function __construct(
47
        private readonly QueryBuilder $queryBuilder,
48
        ?Context $context = null
49
    ) {
50
        $this->context = $context ?? GeneralUtility::makeInstance(Context::class);
2✔
51
    }
52

53
    /**
54
     * @throws AspectNotFoundException
55
     * @throws ServiceUnavailableException
56
     */
57
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
58
    {
59
        /** @var JsonCompatibilityConverter $jsonCompatibilityConverter */
60
        $jsonCompatibilityConverter = GeneralUtility::makeInstance(JsonCompatibilityConverter::class);
3✔
61

62
        $crawlerInformation = $request->getHeaderLine($this->headerName);
3✔
63
        if (empty($crawlerInformation)) {
3✔
64
            return $handler->handle($request);
1✔
65
        }
66

67
        // Authenticate crawler request:
68
        //@todo: ask service to exclude current call for special reasons: for example no relevance because the language version is not affected
69
        [$queueId, $hash] = explode(':', $crawlerInformation);
2✔
70
        $queueRec = $this->findByQueueId($queueId);
2✔
71

72
        // If a crawler record was found and hash was matching, set it up
73
        if (!$this->isRequestHashMatchingQueueRecord($queueRec, $hash)) {
2✔
74
            return GeneralUtility::makeInstance(ErrorController::class)->unavailableAction(
×
75
                $request,
×
76
                'No crawler entry found'
×
77
            );
×
78
        }
79

80
        $queueParameters = $jsonCompatibilityConverter->convert($queueRec['parameters']);
2✔
81
        $request = $request->withAttribute('tx_crawler', $queueParameters);
2✔
82

83
        // Now ensure to set the proper user groups
84
        if (is_array($queueParameters)) {
2✔
85
            $grList = $queueParameters['feUserGroupList'] ?? '';
2✔
86
            if ($grList) {
2✔
87
                $frontendUser = $this->getFrontendUser($grList, $request);
2✔
88

89
                // we have to set the fe user group to the user aspect since indexed_search only reads the user aspect
90
                // to get the groups. otherwise groups are ignored during indexing.
91
                // we need to add the groups 0, and -2 too, like the getGroupIds getter does.
92
                $this->context->setAspect(
2✔
93
                    'frontend.user',
2✔
94
                    GeneralUtility::makeInstance(UserAspect::class, $frontendUser, explode(',', '0,-2,' . $grList))
2✔
95
                );
2✔
96
            }
97
        }
98

99
        return $handler->handle($request);
2✔
100
    }
101

102
    public function getContext(): Context
103
    {
104
        return $this->context;
2✔
105
    }
106

107
    private function isRequestHashMatchingQueueRecord(?array $queueRec, string $hash): bool
108
    {
109
        if ($queueRec === null || !array_key_exists('qid', $queueRec) || !array_key_exists('set_id', $queueRec)) {
2✔
110
            return false;
×
111
        }
112

113
        return is_array($queueRec) && hash_equals(
2✔
114
            $hash,
2✔
115
            md5(
2✔
116
                $queueRec['qid'] . '|' . $queueRec['set_id'] . '|' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']
2✔
117
            )
2✔
118
        );
2✔
119
    }
120

121
    /**
122
     * @return mixed|string|FrontendUserAuthentication
123
     */
124
    private function getFrontendUser(string $grList, ServerRequestInterface $request)
125
    {
126
        /** @var FrontendUserAuthentication $frontendUser */
127
        $frontendUser = $request->getAttribute('frontend.user');
2✔
128
        $frontendUser->user[$frontendUser->usergroup_column] = '0,-2,' . $grList;
2✔
129
        $frontendUser->user[$frontendUser->userid_column] = 0;
2✔
130
        $frontendUser->user[$frontendUser->username_column] = '';
2✔
131
        $frontendUser->fetchGroupData($request);
2✔
132
        $frontendUser->user['uid'] = PHP_INT_MAX;
2✔
133
        return $frontendUser;
2✔
134
    }
135

136
    private function findByQueueId(string $queueId): array
137
    {
138
        $queueRec = $this->queryBuilder
2✔
139
            ->select('*')
2✔
140
            ->from(QueueRepository::TABLE_NAME)->where(
2✔
141
                $this->queryBuilder->expr()->eq('qid', $this->queryBuilder->createNamedParameter($queueId))
2✔
142
            )->executeQuery()
2✔
143
            ->fetchAssociative();
2✔
144

145
        // Todo: This should be changes, as we don't want logic only present to please tests.
146
        // This is a tweak as the CSV Data contains invalid json for testing, to ensure that json is double-quoted instead of single-quoted.
147
        if (isset($queueRec['parameters'])) {
2✔
148
            $queueRec['parameters'] = str_replace("'", '"', (string) $queueRec['parameters']);
2✔
149
        }
150

151
        return is_array($queueRec) ? $queueRec : [];
2✔
152
    }
153
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc