Passed
Pull Request — master (#236)
by
unknown
12:39 queued 09:46
created

ForceSecureConnection   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 51
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 24
c 2
b 1
f 0
dl 0
loc 51
rs 10
wmc 8

4 Methods

Rating   Name   Duplication   Size   Complexity  
A process() 0 11 2
A __construct() 0 3 1
A addSTS() 0 6 3
A addCSP() 0 5 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Web\Middleware;
6
7
use Psr\Http\Message\ResponseFactoryInterface;
8
use Psr\Http\Message\ResponseInterface;
9
use Psr\Http\Message\ServerRequestInterface;
10
use Psr\Http\Server\MiddlewareInterface;
11
use Psr\Http\Server\RequestHandlerInterface;
12
use Yiisoft\Http\Status;
13
14
/**
15
 * Redirects from HTTP to HTTPS and adds CSP and HSTS headers
16
 */
17
class ForceSecureConnection implements MiddlewareInterface
18
{
19
    protected int $statusCode = Status::MOVED_PERMANENTLY;
20
    protected ?int $port = null;
21
22
    protected bool $addCSP = true;
23
    protected string $cspDirective = 'upgrade-insecure-requests';
24
25
    protected bool $addSTS = true;
26
    protected int $stsMaxAge = 31_536_000; // 12 months
0 ignored issues
show
Bug introduced by
The constant Yiisoft\Yii\Web\Middleware\31_536_000 was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
27
    protected bool $stsSubDomains = false;
28
29
    private ResponseFactoryInterface $responseFactory;
30
31
    public function __construct(ResponseFactoryInterface $responseFactory)
32
    {
33
        $this->responseFactory = $responseFactory;
34
    }
35
36
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
37
    {
38
        if ($request->getUri()->getScheme() === 'http') {
39
            $url = (string)$request->getUri()->withScheme('https')->withPort($this->port);
40
            return $this->addCSP(
41
                $this->responseFactory
42
                    ->createResponse($this->statusCode)
43
                    ->withHeader('Location', $url)
44
            );
45
        }
46
        return $this->addSTS($this->addCSP($handler->handle($request)));
47
    }
48
49
    /**
50
     * Add Content-Security-Policy header
51
     */
52
    private function addCSP(ResponseInterface $response): ResponseInterface
53
    {
54
        return $this->addCSP
55
            ? $response->withHeader('Content-Security-Policy', $this->cspDirective)
56
            : $response;
57
    }
58
59
    /**
60
     * Add Strict-Transport-Security header
61
     */
62
    private function addSTS(ResponseInterface $response): ResponseInterface
63
    {
64
        $subDomains = $this->stsSubDomains ? 'includeSubDomains' : '';
65
        return $this->addSTS
66
            ? $response->withHeader('Strict-Transport-Security', "max-age={$this->stsMaxAge}; {$subDomains}")
67
            : $response;
68
    }
69
}
70