addAuthorizationHeader()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 0
cts 7
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://github.com/flipboxfactory/patron-hubspot/blob/master/LICENSE
6
 * @link       https://github.com/flipboxfactory/patron-hubspot/
7
 */
8
9
namespace flipbox\patron\hubspot\connections;
10
11
use craft\helpers\ArrayHelper;
12
use craft\helpers\StringHelper;
13
use flipbox\patron\records\Token;
14
use Flipbox\Skeleton\Helpers\JsonHelper;
15
use League\OAuth2\Client\Token\AccessTokenInterface;
16
use Psr\Http\Message\RequestInterface;
17
use Psr\Http\Message\ResponseInterface;
18
19
/**
20
 * @author Flipbox Factory <[email protected]>
21
 * @since 1.0.0
22
 */
23
trait AccessTokenAuthorizationTrait
24
{
25
    use AccessTokenTrait;
26
27
    /**
28
     * @param RequestInterface $request
29
     * @return RequestInterface
30
     * @throws \yii\base\InvalidConfigException
31
     */
32
    public function prepareAuthorizationRequest(
33
        RequestInterface $request
34
    ): RequestInterface {
35
36
        foreach ($this->getProvider()->getHeaders() as $key => $value) {
37
            $request = $request->withAddedHeader($key, $value);
38
        }
39
40
        return $this->addAuthorizationHeader($request);
41
    }
42
43
    /**
44
     * @param RequestInterface $request
45
     * @return RequestInterface
46
     * @throws \yii\base\InvalidConfigException
47
     */
48
    protected function addAuthorizationHeader(RequestInterface $request): RequestInterface
49
    {
50
        return $request->withHeader(
51
            'Authorization',
52
            'Bearer ' . (string)$this->getAccessToken()
53
        );
54
    }
55
56
    /**
57
     * @param ResponseInterface $response
58
     * @param RequestInterface $request
59
     * @param callable $runner
60
     * @return ResponseInterface
61
     * @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException
62
     * @throws \flipbox\craft\ember\exceptions\RecordNotFoundException
63
     * @throws \yii\base\InvalidConfigException
64
     */
65
    public function handleAuthorizationResponse(
66
        ResponseInterface $response,
67
        RequestInterface $request,
68
        callable $runner
69
    ): ResponseInterface {
70
71
        if ($this->responseIsExpiredToken($response)) {
72
            $response = $this->refreshAndRetry(
73
                $request,
74
                $response,
75
                $runner
76
            );
77
        }
78
79
        return $response;
80
    }
81
82
    /**
83
     * @param ResponseInterface $response
84
     * @return bool
85
     */
86
    protected function responseIsExpiredToken(ResponseInterface $response): bool
87
    {
88
        if ($response->getStatusCode() !== 401) {
89
            return false;
90
        }
91
92
        $data = JsonHelper::decodeIfJson(
93
            $response->getBody()->getContents()
94
        );
95
96
        return $this->hasSessionExpired($data);
97
    }
98
99
    /**
100
     * @param RequestInterface $request
101
     * @param ResponseInterface $response
102
     * @param callable|null $next
103
     * @return mixed
104
     * @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException
105
     * @throws \flipbox\craft\ember\exceptions\RecordNotFoundException
106
     * @throws \yii\base\InvalidConfigException
107
     */
108
    protected function refreshAndRetry(RequestInterface $request, ResponseInterface $response, callable $next = null)
109
    {
110
        $refreshToken = $this->getProvider()->getAccessToken('refresh_token', [
111
            'refresh_token' => $this->getAccessToken()->getRefreshToken()
112
        ]);
113
114
        $this->saveRefreshToken(
115
            $this->getAccessToken(),
116
            $refreshToken
117
        );
118
119
        $this->setAccessToken($refreshToken);
120
121
        return $next(
122
            $this->addAuthorizationHeader($request),
123
            $response
124
        );
125
    }
126
127
    /**
128
     * @param AccessTokenInterface $accessToken
129
     * @param AccessTokenInterface $refreshToken
130
     * @return bool
131
     * @throws \flipbox\craft\ember\exceptions\RecordNotFoundException
132
     */
133
    protected function saveRefreshToken(AccessTokenInterface $accessToken, AccessTokenInterface $refreshToken): bool
134
    {
135
        $record = Token::getOne([
136
            'accessToken' => $accessToken->getToken()
137
        ]);
138
        $record->accessToken = $refreshToken->getToken();
139
        return $record->save();
140
    }
141
142
    /**
143
     * @param array $error
144
     *
145
     * This is an example of the error
146
     * [
147
     * 'status' => 'error',
148
     * 'message' => 'This oauth-token (TOKEN_STRING) is expired! expiresAt: 1530045454360, now: 1530114086081',
149
     * 'correlationId' => '1a45b07b-e8ba-41d5-8a85-508f1fdd3246',
150
     * 'requestId' => '302880bcbf2c8727850c536b70254015'
151
     * ]
152
     *
153
     * @return bool
154
     */
155
    private function hasSessionExpired(array $error): bool
156
    {
157
        $message = $error['message'] ?? '';
158
        // Look for these parts in the message
159
        $messageParts = [
160
            'This oauth-token',
161
            'is expired'
162
        ];
163
        if (ArrayHelper::getValue($error, 'status') === 'error' &&
164
            StringHelper::containsAll($message, $messageParts)
165
        ) {
166
            return true;
167
        }
168
        return false;
169
    }
170
}
171