Completed
Push — master ( ac1fa0...9301b0 )
by Neomerx
02:58
created

CsrfSettings::get()   C

Complexity

Conditions 8
Paths 2

Size

Total Lines 42
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 8

Importance

Changes 0
Metric Value
dl 0
loc 42
ccs 25
cts 25
cp 1
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 26
nc 2
nop 1
crap 8
1
<?php namespace Limoncello\Application\Packages\Csrf;
2
3
/**
4
 * Copyright 2015-2018 [email protected]
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
use Limoncello\Contracts\Settings\SettingsInterface;
20
use Limoncello\Core\Reflection\CheckCallableTrait;
21
use Psr\Container\ContainerInterface;
22
use Psr\Http\Message\ResponseInterface;
23
use Psr\Http\Message\ServerRequestInterface;
24
25
/**
26
 * @package Limoncello\Application
27
 */
28
class CsrfSettings implements SettingsInterface
29
{
30
    use CheckCallableTrait;
31
32
    /** @var string Default form field for storing CSRF value */
33
    public const DEFAULT_HTTP_REQUEST_CSRF_TOKEN_KEY = '_token';
34
35
    /** @var int Settings key */
36
    public const HTTP_METHODS_TO_CHECK = 0;
37
38
    /** @var int Settings key */
39
    public const HTTP_REQUEST_CSRF_TOKEN_KEY = self::HTTP_METHODS_TO_CHECK + 1;
40
41
    /** @var int Settings key */
42
    public const TOKEN_STORAGE_KEY_IN_SESSION = self::HTTP_REQUEST_CSRF_TOKEN_KEY + 1;
43
44
    /** @var int Settings key */
45
    public const MAX_TOKENS = self::TOKEN_STORAGE_KEY_IN_SESSION + 1;
46
47
    /** @var int Settings key */
48
    public const MAX_TOKENS_THRESHOLD = self::MAX_TOKENS + 1;
49
50
    /** @var int Settings key */
51
    public const CREATE_ERROR_RESPONSE_METHOD = self::MAX_TOKENS_THRESHOLD + 1;
52
53
    /** @var int Settings key */
54
    public const INTERNAL_HTTP_METHODS_TO_CHECK_AS_UC_KEYS = self::CREATE_ERROR_RESPONSE_METHOD + 1;
55
56
    /** @var int Settings key */
57
    public const KEY_LAST = self::INTERNAL_HTTP_METHODS_TO_CHECK_AS_UC_KEYS + 1;
58
59
    /**
60
     * @inheritdoc
61
     */
62 5
    final public function get(array $appConfig): array
63
    {
64 5
        $settings = $this->getSettings();
65
66
        // check and transform HTTP methods
67 5
        $methods = $settings[static::HTTP_METHODS_TO_CHECK] ?? [];
68 5
        assert(empty($methods) === false);
69 5
        $upperCaseMethods = [];
70 5
        foreach ($methods as $method) {
71 5
            assert(is_string($method) === true && empty($method) === false);
72 5
            $upperCaseMethods[strtoupper($method)] = true;
73
        }
74 5
        $settings[static::INTERNAL_HTTP_METHODS_TO_CHECK_AS_UC_KEYS] = $upperCaseMethods;
75 5
        unset($settings[static::HTTP_METHODS_TO_CHECK]);
76
77
        // check token key
78 5
        $tokenKey = $settings[static::HTTP_REQUEST_CSRF_TOKEN_KEY];
79 5
        assert(is_string($tokenKey) === true && empty($tokenKey) === false);
80
81
        // check storage key
82 5
        $storageKey = $settings[static::TOKEN_STORAGE_KEY_IN_SESSION];
83 5
        assert(is_string($storageKey) === true && empty($storageKey) === false);
84
85
        // check max tokens
86 5
        $maxTokens = $settings[static::MAX_TOKENS];
87 5
        assert(is_null($maxTokens) === true || (is_int($maxTokens) === true && $maxTokens > 0));
88
89
        // check max tokens
90 5
        $maxTokensThreshold = $settings[static::MAX_TOKENS];
91 5
        assert(is_int($maxTokensThreshold) === true && $maxTokensThreshold >= 0);
92
93 5
        $errorResponseMethod = $settings[static::CREATE_ERROR_RESPONSE_METHOD] ?? null;
94 5
        $expectedArgs        = [ContainerInterface::class, ServerRequestInterface::class];
95 5
        $expectedRet         = ResponseInterface::class;
96 5
        assert(
97 5
            $this->checkPublicStaticCallable($errorResponseMethod, $expectedArgs, $expectedRet) === true,
98
            'CSRF error response method should have signature ' .
99 5
            '(ContainerInterface, ServerRequestInterface): ResponseInterface.'
100
        );
101
102 5
        return $settings;
103
    }
104
105
    /**
106
     * @return array
107
     */
108 5
    protected function getSettings(): array
109
    {
110
        // defaults
111 5
        $errorResponseMethod = [CsrfMiddleware::class, CsrfMiddleware::DEFAULT_ERROR_RESPONSE_METHOD];
112
113
        return [
114 5
            static::HTTP_METHODS_TO_CHECK        => ['POST', 'PUT', 'DELETE', 'PATCH'],
115 5
            static::HTTP_REQUEST_CSRF_TOKEN_KEY  => static::DEFAULT_HTTP_REQUEST_CSRF_TOKEN_KEY,
116 5
            static::TOKEN_STORAGE_KEY_IN_SESSION => 'csrf_tokens',
117 5
            static::MAX_TOKENS                   => 20,
118 5
            static::MAX_TOKENS_THRESHOLD         => 5,
119 5
            static::CREATE_ERROR_RESPONSE_METHOD => $errorResponseMethod,
120
        ];
121
    }
122
}
123