Issues (3)

src/Service/ProofValidator.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * For the full copyright and license information, please view
5
 * the LICENSE file that was distributed with this source code.
6
 */
7
8
declare(strict_types=1);
9
10
namespace ChampsLibres\WopiLib\Service;
11
12
use ChampsLibres\WopiLib\Contract\Service\Clock\ClockInterface;
13
use ChampsLibres\WopiLib\Contract\Service\Discovery\DiscoveryInterface;
14
use ChampsLibres\WopiLib\Contract\Service\ProofValidatorInterface;
15
use ChampsLibres\WopiLib\Contract\Service\Utils\DotNetTimeConverterInterface;
16
use ChampsLibres\WopiLib\Contract\Service\WopiInterface;
17
use phpseclib3\Crypt\PublicKeyLoader;
18
use phpseclib3\Crypt\RSA;
19
use Psr\Http\Message\RequestInterface;
20
use Throwable;
21
22
use function strlen;
23
24
final class ProofValidator implements ProofValidatorInterface
25
{
26
    private ClockInterface $clock;
27
28
    private DiscoveryInterface $discovery;
29
30
    private DotNetTimeConverterInterface $dotNetTimeConverter;
31
32 3
    public function __construct(
33
        DiscoveryInterface $discovery,
34
        ClockInterface $clock,
35
        DotNetTimeConverterInterface $dotNetTimeConverter
36
    ) {
37 3
        $this->clock = $clock;
38 3
        $this->discovery = $discovery;
39 3
        $this->dotNetTimeConverter = $dotNetTimeConverter;
40
    }
41
42 2
    public function isValid(RequestInterface $request): bool
43
    {
44 2
        $timestamp = $request->getHeaderLine(WopiInterface::HEADER_TIMESTAMP);
45 2
        $date = $this->dotNetTimeConverter->toDatetime($timestamp);
46
47 2
        if (20 * 60 < ($this->clock->now()->getTimestamp() - $date->getTimestamp())) {
48 1
            return false;
49
        }
50
51 1
        $params = [];
52 1
        parse_str($request->getUri()->getQuery(), $params);
53 1
        $url = (string) $request->getUri();
54
55 1
        $expected = sprintf(
56 1
            '%s%s%s%s%s%s',
57 1
            pack('N', strlen($params['access_token'])),
58 1
            $params['access_token'],
59 1
            pack('N', strlen($url)),
60 1
            strtoupper($url),
61 1
            pack('N', 8),
62 1
            pack('J', $timestamp)
63 1
        );
64
65 1
        $key = $this->discovery->getPublicKey();
66 1
        $keyOld = $this->discovery->getPublicKeyOld();
67 1
        $xWopiProof = $request->getHeaderLine(WopiInterface::HEADER_PROOF);
68 1
        $xWopiProofOld = $request->getHeaderLine(WopiInterface::HEADER_PROOF_OLD);
69
70 1
        return $this->verify($expected, $xWopiProof, $key)
71 1
            || $this->verify($expected, $xWopiProofOld, $key)
72 1
            || $this->verify($expected, $xWopiProof, $keyOld);
73
    }
74
75
    /**
76
     * @param string $key The key in MSBLOB format
77
     */
78 1
    private function verify(string $expected, string $proof, string $key): bool
79
    {
80
        try {
81
            /** @var RSA $key */
82 1
            $key = PublicKeyLoader::loadPublicKey($key);
83
        } catch (Throwable $e) {
84
            return false;
85
        }
86
87 1
        return $key
88 1
            ->withHash('sha256')
89 1
            ->withPadding(RSA::SIGNATURE_RELAXED_PKCS1)
90 1
            ->verify($expected, (string) base64_decode($proof, true));
0 ignored issues
show
The method verify() does not exist on phpseclib3\Crypt\RSA. It seems like you code against a sub-type of phpseclib3\Crypt\RSA such as phpseclib3\Crypt\RSA\PublicKey. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

90
            ->/** @scrutinizer ignore-call */ verify($expected, (string) base64_decode($proof, true));
Loading history...
91
    }
92
}
93