Passed
Push — master ( 8362e5...10440f )
by Pol
01:54
created

WopiProofValidator   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 66
Duplicated Lines 0 %

Test Coverage

Coverage 71.79%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 38
c 2
b 0
f 0
dl 0
loc 66
ccs 28
cts 39
cp 0.7179
rs 10
wmc 7

4 Methods

Rating   Name   Duplication   Size   Complexity  
A isValid() 0 26 3
A __construct() 0 3 1
A __constructX() 0 10 1
A verify() 0 13 2
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\Discovery\WopiDiscoveryInterface;
13
use ChampsLibres\WopiLib\Service\Contract\WopiProofValidatorInterface;
14
use phpseclib3\Crypt\PublicKeyLoader;
15
use Psr\Http\Message\RequestInterface;
16
use Throwable;
17
18
use function strlen;
19
20
use const OPENSSL_ALGO_SHA256;
21
22
final class WopiProofValidator implements WopiProofValidatorInterface
23
{
24
    private WopiDiscoveryInterface $wopiDiscovery;
25
26 2
    public function __construct(WopiDiscoveryInterface $wopiDiscovery)
27
    {
28 2
        $this->wopiDiscovery = $wopiDiscovery;
29 2
    }
30
31
    public function __constructX(string $accessToken, string $url, string $timestamp)
32
    {
33
        $this->expected = sprintf(
0 ignored issues
show
Bug Best Practice introduced by
The property expected does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
34
            '%s%s%s%s%s%s',
35
            pack('N', strlen($accessToken)),
36
            $accessToken,
37
            pack('N', strlen($url)),
38
            strtoupper($url),
39
            pack('N', 8),
40
            pack('J', $timestamp)
41
        );
42
    }
43
44 1
    public function isValid(RequestInterface $request): bool
45
    {
46 1
        $xWopiProof = $request->getHeaderLine('X-WOPI-Proof');
47 1
        $xWopiProofOld = $request->getHeaderLine('X-WOPI-ProofOld');
48 1
        $timestamp = $request->getHeaderLine('X-WOPI-Timestamp');
49
50 1
        $key = $this->wopiDiscovery->getPublicKey();
51 1
        $keyOld = $this->wopiDiscovery->getPublicKeyOld();
52
53 1
        $url = (string) $request->getUri();
54 1
        $params = [];
55 1
        parse_str($request->getUri()->getQuery(), $params);
56
57 1
        $expected = sprintf(
58 1
            '%s%s%s%s%s%s',
59 1
            pack('N', strlen($params['access_token'])),
60 1
            $params['access_token'],
61 1
            pack('N', strlen($url)),
62 1
            strtoupper($url),
63 1
            pack('N', 8),
64 1
            pack('J', $timestamp)
65
        );
66
67 1
        return $this->verify($expected, $xWopiProof, $key)
68 1
            || $this->verify($expected, $xWopiProofOld, $key)
69 1
            || $this->verify($expected, $xWopiProof, $keyOld);
70
    }
71
72
    /**
73
     * @param string $key The key in MSBLOB format
74
     */
75 1
    private function verify(string $expected, string $proof, string $key): bool
76
    {
77
        try {
78 1
            $key = PublicKeyLoader::loadPublicKey($key);
79
        } catch (Throwable $e) {
80
            return false;
81
        }
82
83 1
        return 1 === openssl_verify(
84
            $expected,
85 1
            base64_decode($proof, true),
86
            $key,
87 1
            OPENSSL_ALGO_SHA256
88
        );
89
    }
90
}
91