Transaction   A
last analyzed

Complexity

Total Complexity 7

Size/Duplication

Total Lines 107
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 7
dl 0
loc 107
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A isTesting() 0 3 1
A process() 0 17 2
A requireHeader() 0 10 2
A __construct() 0 16 2
1
<?php
2
3
/**
4
 * This file is part of the Mediapart LaPresseLibre Library.
5
 *
6
 * CC BY-NC-SA <https://github.com/mediapart/lapresselibre>
7
 *
8
 * For the full license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Mediapart\LaPresseLibre;
13
14
use Psr\Log\LoggerAwareInterface;
15
use Psr\Log\NullLogger;
16
use Psr\Http\Message\RequestInterface as Request;
17
use Mediapart\LaPresseLibre\Security\Identity;
18
use Mediapart\LaPresseLibre\Security\Encryption;
19
20
/**
21
 * @see https://github.com/NextINpact/LaPresseLibreSDK/wiki/Fonctionnement-des-web-services#g%C3%A9n%C3%A9ralit%C3%A9s
22
 */
23
class Transaction implements LoggerAwareInterface
24
{
25
    use \Psr\Log\LoggerAwareTrait;
26
27
    /**
28
     * @var Request
29
     */
30
    private $request;
31
32
    /**
33
     * @var Encryption
34
     */
35
    private $encryption;
36
37
    /**
38
     * Initiate a new transaction.
39
     *
40
     * @param int        $secret
41
     * @param Encryption $encryption
42
     * @param Request    $request
43
     *
44
     * To initiate a transaction, Request should have the following headers :
45
     *
46
     * - X-PART (int32): partner identifier code
47
     * - X-TS (timestamp): sending transaction datetime
48
     * - X-LPL (string): hashed signature
49
     *
50
     * @throws \InvalidArgumentException if one of these headers are missing
51
     * @throws \UnexpectedValueException if one of these headers has invalid value
52
     */
53
    public function __construct(Identity $identity, Encryption $encryption, Request $request)
54
    {
55
        $this->request = $request;
56
        $this->encryption = $encryption;
57
        $this->logger = new NullLogger();
58
59
        $signature = $identity->sign(
60
            $this->requireHeader('X-PART'),
61
            $this->requireHeader('X-TS')
0 ignored issues
show
Bug introduced by
$this->requireHeader('X-TS') of type string is incompatible with the type integer expected by parameter $timestamp of Mediapart\LaPresseLibre\Security\Identity::sign(). ( Ignorable by Annotation )

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

61
            /** @scrutinizer ignore-type */ $this->requireHeader('X-TS')
Loading history...
62
        );
63
64
        if ($signature != $this->requireHeader('X-LPL')) {
65
            throw new \UnexpectedValueException(sprintf(
66
                'Request signed by %s but expected %s',
67
                $request->getHeaderLine('X-LPL'),
68
                $signature
69
            ));
70
        }
71
    }
72
73
    /**
74
     * @param string $name
75
     *
76
     * @throws InvalidArgumentException
77
     *
78
     * @return mixed
79
     */
80
    private function requireHeader($name)
81
    {
82
        if (!$this->request->hasHeader($name)) {
83
            throw new \InvalidArgumentException(sprintf(
84
                'Missing header %s',
85
                $name
86
            ));
87
        }
88
89
        return $this->request->getHeaderLine($name);
90
    }
91
92
    /**
93
     * Returns if the transaction is in testing mode.
94
     *
95
     * If true, the endpoint should returns valid response but without applying
96
     * its effetcs on database.
97
     * Based on the X-CTX HTTP request header.
98
     *
99
     * @return bool returns true if testing mode is active, false otherwise
100
     */
101
    public function isTesting()
102
    {
103
        return (bool) $this->request->hasHeader('X-CTX');
104
    }
105
106
    /**
107
     * Execute an endpoint and returns his result encrypted.
108
     *
109
     * @param Endpoint $endpoint
110
     *
111
     * @return string
112
     */
113
    public function process(Endpoint $endpoint)
114
    {
115
        if (in_array($this->request->getMethod(), ['PUT', 'POST'])) {
116
            $input = $this->request->getBody();
117
        } else {
118
            parse_str($this->request->getUri()->getQuery(), $query);
119
            $input = $query['crd'];
120
        }
121
122
        $data = $this->encryption->decrypt($input);
123
        $this->logger->debug('receive data', [$input, $data]);
124
        $result = $endpoint->execute($data, $this->isTesting());
0 ignored issues
show
Bug introduced by
$data of type string is incompatible with the type array expected by parameter $data of Mediapart\LaPresseLibre\Endpoint::execute(). ( Ignorable by Annotation )

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

124
        $result = $endpoint->execute(/** @scrutinizer ignore-type */ $data, $this->isTesting());
Loading history...
125
126
        $noPaddingOption = OPENSSL_RAW_DATA & OPENSSL_NO_PADDING;
127
        $encryptedResult = $this->encryption->encrypt($result, $noPaddingOption);
0 ignored issues
show
Bug introduced by
$result of type array is incompatible with the type string expected by parameter $message of Mediapart\LaPresseLibre\...y\Encryption::encrypt(). ( Ignorable by Annotation )

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

127
        $encryptedResult = $this->encryption->encrypt(/** @scrutinizer ignore-type */ $result, $noPaddingOption);
Loading history...
128
129
        return $encryptedResult;
130
    }
131
}
132