Passed
Push — master ( a13ecb...04451c )
by Peter
02:15
created

Security::getVar()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 7
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AbterPhp\Framework\Http\Middleware;
6
7
use AbterPhp\Framework\Constant\Env;
8
use AbterPhp\Framework\Security\SecurityException;
9
use Closure;
10
use Opulence\Cache\ICacheBridge;
11
use Opulence\Environments\Environment;
12
use Opulence\Http\Requests\Request;
13
use Opulence\Http\Responses\Response;
14
use Opulence\Routing\Middleware\IMiddleware;
15
16
class Security implements IMiddleware
17
{
18
    const KEY = 'abterphp:security';
19
20
    const TEST_DB_PASSWORD                 = '28T3pqyvKG3tEgsjE8Rj';
21
    const TEST_ENCRYPTION_KEY              = 'b8fbb40c129ad0e426e19b7d28f42e517ce639282e55ba7a98bd2b698fda7daa';
22
    const TEST_CRYPTO_FRONTEND_SALT        = 'R6n9gNH9ND6USc6D';
23
    const TEST_CRYPTO_ENCRYPTION_PEPPER    = 'h9fyyWr36vBnky9G';
24
    const TEST_OAUTH2_PRIVATE_KEY_PATH     = '/website/tests/resources/private.key';
25
    const TEST_OAUTH2_PRIVATE_KEY_PASSWORD = '8a!J2SZ9%WBII#9Z';
26
    const TEST_OAUTH2_PUBLIC_KEY_PATH      = '/website/tests/resources/public.key';
27
    const TEST_OAUTH2_ENCRYPTION_KEY       = 'def00000cea4c75b84279f43b56dd90851609717c5d29c215fd2c67f9b1acb0c3b1c5ff8528dbeecf0c1f368baa33284aa36d00b24994872970933e8881802287553ff7d'; // nolint
28
29
    /** @var ICacheBridge */
30
    protected $cacheBridge;
31
32
    /** @var string */
33
    protected $environment;
34
35
    /** @var string[] */
36
    protected $environmentData;
37
38
    /** @var string[] */
39
    protected $settings;
40
41
    /**
42
     * Security constructor.
43
     *
44
     * @param ICacheBridge $cacheBridge
45
     * @param string       $environment
46
     */
47
    public function __construct(ICacheBridge $cacheBridge, string $environment)
48
    {
49
        $this->cacheBridge = $cacheBridge;
50
        $this->environment = $environment;
51
    }
52
53
    /**
54
     * @param string $key
55
     *
56
     * @return string
57
     */
58
    public function getVar(string $key): string
59
    {
60
        if (!isset($this->environmentData[$key])) {
61
            return (string)Environment::getVar($key);
62
        }
63
64
        return (string)$this->environmentData[$key];
65
    }
66
67
    /**
68
     * @param array $environmentData
69
     *
70
     * @return $this
71
     */
72
    public function setVar(array $environmentData): Security
73
    {
74
        $this->environmentData = $environmentData;
75
76
        return $this;
77
    }
78
79
    /**
80
     * @param string $key
81
     *
82
     * @return string
83
     */
84
    public function getSetting(string $key): string
85
    {
86
        if (!isset($this->settings[$key])) {
87
            return (string)ini_get($key);
88
        }
89
90
        return (string)$this->settings[$key];
91
    }
92
93
    /**
94
     * @param array $settings
95
     *
96
     * @return Security
97
     */
98
    public function setSettings(array $settings): Security
99
    {
100
        $this->settings = $settings;
101
102
        return $this;
103
    }
104
105
    // $next consists of the next middleware in the pipeline
106
    public function handle(Request $request, Closure $next): Response
107
    {
108
        if ($this->environment !== Environment::PRODUCTION) {
109
            return $next($request);
110
        }
111
112
        // phpcs:disable Generic.CodeAnalysis.EmptyStatement
113
        try {
114
            if ($this->cacheBridge->get(static::KEY)) {
115
                return $next($request);
116
            }
117
        } catch (\Exception $e) {
118
            // It's always safe to check potential security risks, only makes the response slightly slower
119
        }
120
        // phpcs:enable Generic.CodeAnalysis.EmptyStatement
121
122
        $this->checkSecrets();
123
        $this->checkPhpSettings();
124
125
        $this->cacheBridge->set(static::KEY, true, PHP_INT_MAX);
126
127
        return $next($request);
128
    }
129
130
    private function checkSecrets()
131
    {
132
        if ($this->getVar(Env::DB_PASSWORD) === static::TEST_DB_PASSWORD) {
133
            throw new SecurityException('Invalid DB_PASSWORD environment variable.');
134
        }
135
136
        if ($this->getVar(Env::ENCRYPTION_KEY) === static::TEST_ENCRYPTION_KEY) {
137
            throw new SecurityException('Invalid ENCRYPTION_KEY environment variable.');
138
        }
139
140
        if ($this->getVar(Env::CRYPTO_FRONTEND_SALT) === static::TEST_CRYPTO_FRONTEND_SALT) {
141
            throw new SecurityException('Invalid CRYPTO_FRONTEND_SALT environment variable.');
142
        }
143
144
        if ($this->getVar(Env::CRYPTO_ENCRYPTION_PEPPER) === static::TEST_CRYPTO_ENCRYPTION_PEPPER) {
145
            throw new SecurityException('Invalid CRYPTO_ENCRYPTION_PEPPER environment variable.');
146
        }
147
148
        if ($this->getVar(Env::OAUTH2_PRIVATE_KEY_PATH) === static::TEST_OAUTH2_PRIVATE_KEY_PATH) {
149
            throw new SecurityException('Invalid OAUTH2_PRIVATE_KEY_PATH environment variable.');
150
        }
151
152
        if ($this->getVar(Env::OAUTH2_PRIVATE_KEY_PASSWORD) === static::TEST_OAUTH2_PRIVATE_KEY_PASSWORD) {
153
            throw new SecurityException('Invalid OAUTH2_PRIVATE_KEY_PASSWORD environment variable.');
154
        }
155
156
        if ($this->getVar(Env::OAUTH2_PUBLIC_KEY_PATH) === static::TEST_OAUTH2_PUBLIC_KEY_PATH) {
157
            throw new SecurityException('Invalid OAUTH2_PUBLIC_KEY_PATH environment variable.');
158
        }
159
160
        if ($this->getVar(Env::OAUTH2_ENCRYPTION_KEY) === static::TEST_OAUTH2_ENCRYPTION_KEY) {
161
            throw new SecurityException('Invalid OAUTH2_ENCRYPTION_KEY environment variable.');
162
        }
163
    }
164
165
    private function checkPhpSettings()
166
    {
167
        if ($this->getSetting('display_errors')) {
168
            throw new SecurityException('Unacceptable `display_errors` value for production.');
169
        }
170
    }
171
}
172