Passed
Push — master ( 5b3951...bde9e6 )
by Peter
03:16
created

Security::getEnvironmentData()   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
nc 2
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
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
25
    /** @var ICacheBridge */
26
    protected $cacheBridge;
27
28
    /** @var string */
29
    protected $environment;
30
31
    /** @var string[] */
32
    protected $environmentData;
33
34
    /** @var string[] */
35
    protected $settings;
36
37
    /**
38
     * Security constructor.
39
     *
40
     * @param ICacheBridge $cacheBridge
41
     */
42
    public function __construct(ICacheBridge $cacheBridge)
43
    {
44
        $this->cacheBridge = $cacheBridge;
45
    }
46
47
    /**
48
     * @return string
49
     */
50
    public function getEnvironment(): string
51
    {
52
        if (null === $this->environment) {
53
            $this->environment = getenv(Env::ENV_NAME);
54
        }
55
56
        return $this->environment;
57
    }
58
59
    /**
60
     * @param string $environment
61
     */
62
    public function setEnvironment(string $environment): void
63
    {
64
        $this->environment = $environment;
65
    }
66
67
    /**
68
     * @param string $key
69
     *
70
     * @return string
71
     */
72
    public function getEnvironmentData(string $key): string
73
    {
74
        if (!isset($this->environmentData[$key])) {
75
            return (string)getenv($key);
76
        }
77
78
        return (string)$this->environmentData[$key];
79
    }
80
81
    /**
82
     * @param array $environmentData
83
     *
84
     * @return $this
85
     */
86
    public function setEnvironmentData(array $environmentData): Security
87
    {
88
        $this->environmentData = $environmentData;
89
90
        return $this;
91
    }
92
93
    /**
94
     * @param string $key
95
     *
96
     * @return string
97
     */
98
    public function getSetting(string $key): string
99
    {
100
        if (!isset($this->settings[$key])) {
101
            return (string)getenv($key);
102
        }
103
104
        return (string)$this->settings[$key];
105
    }
106
107
    /**
108
     * @param array $settings
109
     *
110
     * @return Security
111
     */
112
    public function setSettings(array $settings): Security
113
    {
114
        $this->settings = $settings;
115
116
        return $this;
117
    }
118
119
    // $next consists of the next middleware in the pipeline
120
    public function handle(Request $request, Closure $next): Response
121
    {
122
        if ($this->getEnvironment() !== Environment::PRODUCTION) {
123
            return $next($request);
124
        }
125
126
        // phpcs:disable Generic.CodeAnalysis.EmptyStatement
127
        try {
128
            if ($this->cacheBridge->get(static::KEY)) {
129
                return $next($request);
130
            }
131
        } catch (\Exception $e) {
132
            // It's always safe to check potential security risks, only makes the response slightly slower
133
        }
134
        // phpcs:enable Generic.CodeAnalysis.EmptyStatement
135
136
        $this->checkSecrets();
137
        $this->checkPhpSettings();
138
139
        $this->cacheBridge->set(static::KEY, true, PHP_INT_MAX);
140
141
        return $next($request);
142
    }
143
144
    private function checkSecrets()
145
    {
146
        if ($this->getEnvironmentData(Env::DB_PASSWORD) === static::TEST_DB_PASSWORD) {
147
            throw new SecurityException('Invalid DB_PASSWORD environment variable.');
148
        }
149
150
        if ($this->getEnvironmentData(Env::ENCRYPTION_KEY) === static::TEST_ENCRYPTION_KEY) {
151
            throw new SecurityException('Invalid ENCRYPTION_KEY environment variable.');
152
        }
153
154
        if ($this->getEnvironmentData(Env::CRYPTO_FRONTEND_SALT) === static::TEST_CRYPTO_FRONTEND_SALT) {
155
            throw new SecurityException('Invalid CRYPTO_FRONTEND_SALT environment variable.');
156
        }
157
158
        if ($this->getEnvironmentData(Env::CRYPTO_ENCRYPTION_PEPPER) === static::TEST_CRYPTO_ENCRYPTION_PEPPER) {
159
            throw new SecurityException('Invalid CRYPTO_ENCRYPTION_PEPPER environment variable.');
160
        }
161
    }
162
163
    private function checkPhpSettings()
164
    {
165
        if ($this->getSetting('display_errors')) {
166
            throw new SecurityException('Unacceptable `display_errors` value for production.');
167
        }
168
    }
169
}
170