Issues (51)

src/Request/Request.php (1 issue)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace MaxBeckers\AmazonAlexa\Request;
6
7
use MaxBeckers\AmazonAlexa\Exception\MissingRequestDataException;
8
use MaxBeckers\AmazonAlexa\Exception\MissingRequiredHeaderException;
9
use MaxBeckers\AmazonAlexa\Helper\PropertyHelper;
10
use MaxBeckers\AmazonAlexa\Request\Request\AbstractRequest;
11
use MaxBeckers\AmazonAlexa\Request\Request\AlexaSkillEvent\SkillAccountLinkedRequest;
12
use MaxBeckers\AmazonAlexa\Request\Request\AlexaSkillEvent\SkillDisabledRequest;
13
use MaxBeckers\AmazonAlexa\Request\Request\AlexaSkillEvent\SkillEnabledRequest;
14
use MaxBeckers\AmazonAlexa\Request\Request\AlexaSkillEvent\SkillPermissionAcceptedRequest;
15
use MaxBeckers\AmazonAlexa\Request\Request\AlexaSkillEvent\SkillPermissionChangedRequest;
16
use MaxBeckers\AmazonAlexa\Request\Request\APL\LoadIndexListDataRequest;
17
use MaxBeckers\AmazonAlexa\Request\Request\APL\LoadTokenListDataRequest;
18
use MaxBeckers\AmazonAlexa\Request\Request\APL\RuntimeErrorRequest;
19
use MaxBeckers\AmazonAlexa\Request\Request\APL\UserEventRequest;
20
use MaxBeckers\AmazonAlexa\Request\Request\AudioPlayer\PlaybackFailedRequest;
21
use MaxBeckers\AmazonAlexa\Request\Request\AudioPlayer\PlaybackFinishedRequest;
22
use MaxBeckers\AmazonAlexa\Request\Request\AudioPlayer\PlaybackNearlyFinishedRequest;
23
use MaxBeckers\AmazonAlexa\Request\Request\AudioPlayer\PlaybackStartedRequest;
24
use MaxBeckers\AmazonAlexa\Request\Request\AudioPlayer\PlaybackStoppedRequest;
25
use MaxBeckers\AmazonAlexa\Request\Request\CanFulfill\CanFulfillIntentRequest;
26
use MaxBeckers\AmazonAlexa\Request\Request\Display\ElementSelectedRequest;
27
use MaxBeckers\AmazonAlexa\Request\Request\GameEngine\InputHandlerEvent;
28
use MaxBeckers\AmazonAlexa\Request\Request\PlaybackController\NextCommandIssued;
29
use MaxBeckers\AmazonAlexa\Request\Request\PlaybackController\PauseCommandIssued;
30
use MaxBeckers\AmazonAlexa\Request\Request\PlaybackController\PlayCommandIssued;
31
use MaxBeckers\AmazonAlexa\Request\Request\PlaybackController\PreviousCommandIssued;
32
use MaxBeckers\AmazonAlexa\Request\Request\Standard\IntentRequest;
33
use MaxBeckers\AmazonAlexa\Request\Request\Standard\LaunchRequest;
34
use MaxBeckers\AmazonAlexa\Request\Request\Standard\SessionEndedRequest;
35
use MaxBeckers\AmazonAlexa\Request\Request\System\ConnectionsResponseRequest;
36
use MaxBeckers\AmazonAlexa\Request\Request\System\ExceptionEncounteredRequest;
37
38
class Request
39
{
40
    /**
41
     * List of all supported amazon request types.
42
     */
43
    public const REQUEST_TYPES = [
44
        // Standard types
45
        IntentRequest::TYPE => IntentRequest::class,
46
        LaunchRequest::TYPE => LaunchRequest::class,
47
        SessionEndedRequest::TYPE => SessionEndedRequest::class,
48
        // AudioPlayer types
49
        PlaybackStartedRequest::TYPE => PlaybackStartedRequest::class,
50
        PlaybackNearlyFinishedRequest::TYPE => PlaybackNearlyFinishedRequest::class,
51
        PlaybackFinishedRequest::TYPE => PlaybackFinishedRequest::class,
52
        PlaybackStoppedRequest::TYPE => PlaybackStoppedRequest::class,
53
        PlaybackFailedRequest::TYPE => PlaybackFailedRequest::class,
54
        // PlaybackController types
55
        NextCommandIssued::TYPE => NextCommandIssued::class,
56
        PauseCommandIssued::TYPE => PauseCommandIssued::class,
57
        PlayCommandIssued::TYPE => PlayCommandIssued::class,
58
        PreviousCommandIssued::TYPE => PreviousCommandIssued::class,
59
        // System types
60
        ExceptionEncounteredRequest::TYPE => ExceptionEncounteredRequest::class,
61
        // Display types
62
        ElementSelectedRequest::TYPE => ElementSelectedRequest::class,
63
        // Game engine types
64
        InputHandlerEvent::TYPE => InputHandlerEvent::class,
65
        // can fulfill intent
66
        CanFulfillIntentRequest::TYPE => CanFulfillIntentRequest::class,
67
        // Connections Response Request
68
        ConnectionsResponseRequest::TYPE => ConnectionsResponseRequest::class,
69
        // Skill event types
70
        SkillAccountLinkedRequest::TYPE => SkillAccountLinkedRequest::class,
71
        SkillEnabledRequest::TYPE => SkillEnabledRequest::class,
72
        SkillDisabledRequest::TYPE => SkillDisabledRequest::class,
73
        SkillPermissionAcceptedRequest::TYPE => SkillPermissionAcceptedRequest::class,
74
        SkillPermissionChangedRequest::TYPE => SkillPermissionChangedRequest::class,
75
        // APL request types
76
        LoadIndexListDataRequest::TYPE => LoadIndexListDataRequest::class,
77
        LoadTokenListDataRequest::TYPE => LoadTokenListDataRequest::class,
78
        RuntimeErrorRequest::TYPE => RuntimeErrorRequest::class,
79
        UserEventRequest::TYPE => UserEventRequest::class,
80
    ];
81
82
    /**
83
     * @param string|null $version Request version
84
     * @param Session|null $session Session information
85
     * @param Context|null $context Context information
86
     * @param AbstractRequest|null $request The actual request object
87
     * @param string $amazonRequestBody Raw Amazon request body
88
     * @param string $signatureCertChainUrl Signature certificate chain URL
89
     * @param string $signature Request signature
90
     */
91 73
    public function __construct(
92
        public ?string $version = null,
93
        public ?Session $session = null,
94
        public ?Context $context = null,
95
        public ?AbstractRequest $request = null,
96
        public string $amazonRequestBody = '',
97
        public string $signatureCertChainUrl = '',
98
        public string $signature = '',
99
    ) {
100 73
    }
101
102
    /**
103
     * @throws MissingRequiredHeaderException
104
     * @throws MissingRequestDataException
105
     */
106 52
    public static function fromAmazonRequest(string $amazonRequestBody, string $signatureCertChainUrl, string $signature): self
107
    {
108 52
        $amazonRequest = (array) json_decode($amazonRequestBody, true);
109
110 52
        $request = new self(
111 52
            version: PropertyHelper::checkNullValueString($amazonRequest, 'version'),
112 52
            session: isset($amazonRequest['session']) ? Session::fromAmazonRequest($amazonRequest['session']) : null,
113 52
            context: isset($amazonRequest['context']) ? Context::fromAmazonRequest($amazonRequest['context']) : null,
114 52
            amazonRequestBody: $amazonRequestBody,
115 52
            signatureCertChainUrl: $signatureCertChainUrl,
116 52
            signature: $signature,
117 52
        );
118
119 52
        $request->setRequest($amazonRequest);
120 51
        $request->checkSignature();
121
122 50
        return $request;
123
    }
124
125 3
    public function getApplicationId(): ?string
126
    {
127
        // workaround for developer console
128 3
        if ($this->session && $this->session->application) {
129 3
            return $this->session->application->applicationId;
130
        } elseif ($this->context && ($system = $this->context->system) && $system->application) {
131
            return $system->application->applicationId;
132
        }
133
134
        return null;
135
    }
136
137
    /**
138
     * @throws MissingRequestDataException
139
     */
140 52
    private function setRequest(array $amazonRequest): void
141
    {
142 52
        if (!isset($amazonRequest['request']['type']) || !isset(self::REQUEST_TYPES[$amazonRequest['request']['type']])) {
143 1
            throw new MissingRequestDataException();
144
        }
145 51
        $this->request = (self::REQUEST_TYPES[$amazonRequest['request']['type']])::fromAmazonRequest($amazonRequest['request']);
146
    }
147
148
    /**
149
     * @throws MissingRequiredHeaderException
150
     */
151 51
    private function checkSignature(): void
152
    {
153 51
        if ($this->request->validateSignature() && (!$this->signatureCertChainUrl || !$this->signature)) {
0 ignored issues
show
The method validateSignature() does not exist on null. ( Ignorable by Annotation )

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

153
        if ($this->request->/** @scrutinizer ignore-call */ validateSignature() && (!$this->signatureCertChainUrl || !$this->signature)) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
154 1
            throw new MissingRequiredHeaderException();
155
        }
156
    }
157
}
158