CsrfMiddleware::getCsrfSettings()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 1
cts 1
cp 1
rs 9.9
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php declare(strict_types=1);
2
3
namespace Limoncello\Application\Packages\Csrf;
4
5
/**
6
 * Copyright 2015-2020 [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 Closure;
22
use Limoncello\Application\Contracts\Csrf\CsrfTokenStorageInterface;
23
use Limoncello\Contracts\Application\MiddlewareInterface;
24
use Limoncello\Contracts\Settings\SettingsProviderInterface;
25
use Psr\Container\ContainerInterface;
26
use Psr\Http\Message\ResponseInterface;
27
use Psr\Http\Message\ServerRequestInterface;
28
use Zend\Diactoros\Response\EmptyResponse;
29
use function array_key_exists;
30
use function assert;
31
use function call_user_func;
32
use function is_array;
33
use function is_string;
34
use function strtoupper;
35
36
/**
37
 * @package Limoncello\Application
38
 */
39
class CsrfMiddleware implements MiddlewareInterface
40
{
41
    /** Middleware handler */
42 2
    const CALLABLE_HANDLER = [self::class, self::MIDDLEWARE_METHOD_NAME];
43
44
    /** @var string Default error response factory on invalid/absent CSRF token */
45
    const DEFAULT_ERROR_RESPONSE_METHOD = 'defaultErrorResponse';
46
47 2
    /**
48 2
     * @inheritdoc
49
     */
50 2
    public static function handle(
51 2
        ServerRequestInterface $request,
52 2
        Closure $next,
53 1
        ContainerInterface $container
54 1
    ): ResponseInterface {
55
        $settings = static::getCsrfSettings($container);
0 ignored issues
show
Bug introduced by
Since getCsrfSettings() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of getCsrfSettings() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
56 1
        $methods  = $settings[CsrfSettings::INTERNAL_HTTP_METHODS_TO_CHECK_AS_UC_KEYS];
57
58
        if (array_key_exists(strtoupper($request->getMethod()), $methods) === true) {
59
            $token = static::readToken($request, $settings[CsrfSettings::HTTP_REQUEST_CSRF_TOKEN_KEY]);
0 ignored issues
show
Bug introduced by
Since readToken() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of readToken() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
60 1
            if (is_string($token) === false || static::getTokenStorage($container)->check($token) === false) {
0 ignored issues
show
Bug introduced by
Since getTokenStorage() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of getTokenStorage() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
61
                $errResponseMethod = $settings[CsrfSettings::CREATE_ERROR_RESPONSE_METHOD];
62
                $errResponse       = call_user_func($errResponseMethod, $container, $request);
63
64
                return $errResponse;
65
            }
66
        }
67
68
        return $next($request);
69 1
    }
70
71
    /**
72
     * @param ContainerInterface     $container
73 1
     * @param ServerRequestInterface $request
74
     *
75
     * @return ResponseInterface
76 1
     */
77
    public static function defaultErrorResponse(
78
        ContainerInterface $container,
79
        ServerRequestInterface $request
80
    ): ResponseInterface {
81
        assert($container !== null && $request !== null);
82
83
        // forbid if no valid CSRF token
84
        return new EmptyResponse(403);
85 2
    }
86
87 2
    /**
88
     * @param ServerRequestInterface $request
89 2
     * @param string                 $tokenKey
90
     *
91
     * @return null|string
92
     */
93
    private static function readToken(ServerRequestInterface $request, string $tokenKey): ?string
94
    {
95
        $token = is_array($form = $request->getParsedBody()) === true ? ($form[$tokenKey] ?? null) : null;
96
97 2
        return $token;
98
    }
99 2
100
    /**
101 2
     * @param ContainerInterface $container
102
     *
103 2
     * @return CsrfTokenStorageInterface
104
     */
105
    private static function getTokenStorage(ContainerInterface $container): CsrfTokenStorageInterface
106
    {
107
        assert($container->has(CsrfTokenStorageInterface::class) === true);
108
        /** @var CsrfTokenStorageInterface $csrfStorage */
109
        $csrfStorage = $container->get(CsrfTokenStorageInterface::class);
110
111 2
        return $csrfStorage;
112
    }
113
114 2
    /**
115 2
     * @param ContainerInterface $container
116
     *
117 2
     * @return array
118 2
     */
119
    private static function getCsrfSettings(ContainerInterface $container): array
120 2
    {
121
        /** @var SettingsProviderInterface $provider */
122
        assert($container->has(SettingsProviderInterface::class) === true);
123
        $provider = $container->get(SettingsProviderInterface::class);
124
125
        assert($provider->has(CsrfSettings::class));
126
        $settings = $provider->get(CsrfSettings::class);
127
128
        return $settings;
129
    }
130
}
131