Issues (197)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

Http/ThrowableHandlers/FluteThrowableHandler.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php declare (strict_types = 1);
2
3
namespace Limoncello\Flute\Http\ThrowableHandlers;
4
5
/**
6
 * Copyright 2015-2019 [email protected]
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 * http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
use Exception;
22
use Limoncello\Common\Reflection\ClassIsTrait;
23
use Limoncello\Contracts\Exceptions\ThrowableHandlerInterface;
24
use Limoncello\Contracts\Http\ThrowableResponseInterface;
25
use Limoncello\Flute\Contracts\Encoder\EncoderInterface;
26
use Limoncello\Flute\Contracts\Exceptions\JsonApiThrowableConverterInterface as ConverterInterface;
27
use Limoncello\Flute\Http\JsonApiResponse;
28
use Neomerx\JsonApi\Exceptions\JsonApiException;
29
use Neomerx\JsonApi\Schema\Error;
30
use Neomerx\JsonApi\Schema\ErrorCollection;
31
use Psr\Container\ContainerInterface;
32
use Psr\Log\LoggerAwareTrait;
33
use Throwable;
34
use function array_key_exists;
35
use function assert;
36
use function get_class;
37
38
/**
39
 * @package Limoncello\Flute
40
 *
41
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
42
 */
43
class FluteThrowableHandler implements ThrowableHandlerInterface
44
{
45
    use LoggerAwareTrait, ClassIsTrait;
46
47
    /**
48
     * Those classes will not be logged. Note that classes are expected to be keys but not values.
49
     *
50
     * @var array
51
     */
52
    private $doNotLogClassesAsKeys;
53
54
    /**
55
     * @var int
56
     */
57
    private $httpCodeForUnexpected;
58
59
    /**
60
     * @var bool
61
     */
62
    private $isDebug;
63
64
    /**
65
     * @var EncoderInterface
66
     */
67
    private $encoder;
68
69
    /**
70
     * @var string|null
71
     */
72
    private $throwableConverter;
73
74
    /**
75
     * @param EncoderInterface $encoder
76
     * @param array            $noLogClassesAsKeys
77 6
     * @param int              $codeForUnexpected
78
     * @param bool             $isDebug
79
     * @param null|string      $converterClass
80
     */
81
    public function __construct(
82
        EncoderInterface $encoder,
83
        array $noLogClassesAsKeys,
84 6
        int $codeForUnexpected,
85 6
        bool $isDebug,
86 6
        ?string $converterClass
87
    ) {
88
        assert(
89 6
            $converterClass === null ||
90 6
            static::classImplements($converterClass, ConverterInterface::class)
91 6
        );
92 6
93 6
        $this->doNotLogClassesAsKeys = $noLogClassesAsKeys;
94
        $this->httpCodeForUnexpected = $codeForUnexpected;
95
        $this->isDebug               = $isDebug;
96
        $this->encoder               = $encoder;
97
        $this->throwableConverter    = $converterClass;
98
    }
99
100
    /**
101 5
     * @inheritdoc
102
     *
103 5
     * @SuppressWarnings(PHPMD.ElseExpression)
104
     */
105 5
    public function createResponse(Throwable $throwable, ContainerInterface $container): ThrowableResponseInterface
106 5
    {
107
        unset($container);
108 5
109
        $message            = 'Internal Server Error';
110
        $isJsonApiException = $throwable instanceof JsonApiException;
111 5
112
        $this->logError($throwable, $message);
113
114 2
        // if exception converter is specified it will be used to convert throwable to JsonApiException
115 2
        if ($isJsonApiException === false && $this->throwableConverter !== null) {
116 1
            try {
117 1
                /** @var ConverterInterface $converterClass */
118 1
                $converterClass = $this->throwableConverter;
119
                if (($converted = $converterClass::convert($throwable)) !== null) {
120 1
                    assert($converted instanceof JsonApiException);
121
                    $throwable          = $converted;
122
                    $isJsonApiException = true;
123
                }
124
            } catch (Throwable $ignored) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
125 5
            }
126
        }
127 2
128 2
        // compose JSON API Error with appropriate level of details
129
        if ($isJsonApiException === true) {
130 3
            /** @var JsonApiException $throwable */
131 3
            $errors   = $throwable->getErrors();
132 3
            $httpCode = $throwable->getHttpCode();
133 3
        } else {
134 3
            $errors   = new ErrorCollection();
135 3
            $httpCode = $this->getHttpCodeForUnexpectedThrowable();
136
            $details  = null;
137 3
            if ($this->isDebug === true) {
138
                $message = $throwable->getMessage();
139
                $details = (string)$throwable;
140
            }
141 5
            $errors->add(new Error(null, null, null, (string)$httpCode, null, $message, $details));
142
        }
143 5
144
        // encode the error and send to client
145
        $content = $this->encoder->encodeErrors($errors);
0 ignored issues
show
$errors is of type object<Neomerx\JsonApi\Schema\ErrorCollection>, but the function expects a object<Neomerx\JsonApi\C...racts\Encoder\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
146
147
        return $this->createThrowableJsonApiResponse($throwable, $content, $httpCode);
148
    }
149
150
    /**
151
     * @param Throwable $throwable
152 5
     * @param string    $message
153
     *
154 5
     * @return void
155
     */
156
    private function logError(Throwable $throwable, string $message): void
157 5
    {
158 1
        if ($this->logger !== null && $this->shouldBeLogged($throwable) === true) {
159
            // on error (e.g. no permission to write on disk or etc) ignore
160
            try {
161
                $this->logger->error($message, ['error' => $throwable]);
162
            } catch (Exception $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
163
            }
164
        }
165
    }
166 3
167
    /**
168 3
     * @return int
169
     */
170
    private function getHttpCodeForUnexpectedThrowable(): int
171
    {
172
        return $this->httpCodeForUnexpected;
173
    }
174
175
    /**
176 5
     * @param Throwable $throwable
177
     *
178 5
     * @return bool
179
     */
180 5
    private function shouldBeLogged(Throwable $throwable): bool
181
    {
182
        $result = array_key_exists(get_class($throwable), $this->doNotLogClassesAsKeys) === false;
183
184
        return $result;
185
    }
186
187
    /**
188
     * @param Throwable $throwable
189
     * @param string    $content
190
     * @param int       $status
191
     *
192
     * @return ThrowableResponseInterface
193
     */
194
    private function createThrowableJsonApiResponse(
195
        Throwable $throwable,
196
        string $content,
197
        int $status
198
    ): ThrowableResponseInterface {
199
        return new class ($throwable, $content, $status) extends JsonApiResponse implements ThrowableResponseInterface
200
        {
201
            /**
202
             * @var Throwable
203
             */
204
            private $throwable;
205
206
            /**
207 5
             * @param Throwable $throwable
208
             * @param string    $content
209 5
             * @param int       $status
210 5
             */
211
            public function __construct(Throwable $throwable, string $content, int $status)
212
            {
213
                parent::__construct($content, $status);
214
                $this->throwable = $throwable;
215
            }
216 5
217
            /**
218 5
             * @return Throwable
219
             */
220
            public function getThrowable(): Throwable
221
            {
222
                return $this->throwable;
223
            }
224
        };
225
    }
226
}
227