Completed
Pull Request — master (#18)
by Frederik
03:05
created

HeaderV1Factory.php$0 ➔ getValue()   A

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
cc 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Genkgo\Mail\Dkim;
5
6
use Genkgo\Mail\Header\GenericHeader;
7
use Genkgo\Mail\Header\HeaderName;
8
use Genkgo\Mail\Header\HeaderValue;
9
use Genkgo\Mail\Header\HeaderValueParameter;
10
use Genkgo\Mail\HeaderInterface;
11
use Genkgo\Mail\MessageInterface;
12
13
final class HeaderV1Factory
14
{
15
    /**
16
     *
17
     */
18
    public CONST HEADER_NAME = 'DKIM-Signature';
19
    /**
20
     * @var array
21
     */
22
    private CONST HEADERS_IGNORED = [
23
        'return-path' => true,
24
        'received' => true,
25
        'comments' => true,
26
        'keywords' => true,
27
        'bcc' => true,
28
        'resent-bcc' => true,
29
    ];
30
    /**
31
     * @var SignInterface
32
     */
33
    private $sign;
34
    /**
35
     * @var CanonicalizeHeaderInterface
36
     */
37
    private $canonicalizeHeader;
38
    /**
39
     * @var CanonicalizeBodyInterface
40
     */
41
    private $canonicalizeBody;
42
43
    /**
44
     * SignedTransport constructor.
45
     * @param SignInterface $sign
46
     * @param CanonicalizeHeaderInterface $canonicalizeHeader
47
     * @param CanonicalizeBodyInterface $canonicalizeBody
48
     */
49
    public function __construct(
50
        SignInterface $sign,
51
        CanonicalizeHeaderInterface $canonicalizeHeader,
52
        CanonicalizeBodyInterface $canonicalizeBody
53
    ) {
54
        $this->sign = $sign;
55
        $this->canonicalizeHeader = $canonicalizeHeader;
56
        $this->canonicalizeBody = $canonicalizeBody;
57
    }
58
59
    /**
60
     * @param MessageInterface $message
61
     * @param string $domain
62
     * @param string $selector
63
     * @param array $parameters
64
     * @return HeaderInterface
65
     */
66
    public function factory(
67
        MessageInterface $message,
68
        string $domain,
69
        string $selector,
70
        array $parameters = []
71
    ): HeaderInterface
72
    {
73
        $bodyHash = $this->sign->hashBody(
74
            $this->canonicalizeBody->canonicalize($message->getBody())
75
        );
76
77
        $headerCanonicalized = [];
78
        $headerNames = [];
79
        foreach ($message->getHeaders() as $headers) {
80
            /** @var HeaderInterface $header */
81
            foreach ($headers as $header) {
82
                $headerName = strtolower((string)$header->getName());
83
                if (isset(self::HEADERS_IGNORED[$headerName])) {
84
                    break;
85
                }
86
87
                // make sure we sign only the last header in the list
88
                $headerCanonicalized[$headerName] = $this->canonicalizeHeader->canonicalize($header);
89
                $headerNames[$headerName] = (string)$header->getName();
90
            }
91
        }
92
93
        $canonicalization = [$this->canonicalizeHeader->name(), $this->canonicalizeBody->name()];
94
95
        $headerValue = (new HeaderValue('v=1'))
96
            ->withParameter(new HeaderValueParameter('a', $this->sign->name()))
97
            ->withParameter(new HeaderValueParameter('b', '', true))
98
            ->withParameter(new HeaderValueParameter('bh', $bodyHash, true))
99
            ->withParameter(new HeaderValueParameter('c', implode('/', $canonicalization)))
100
            ->withParameter(new HeaderValueParameter('d', $domain, true))
101
            ->withParameter(new HeaderValueParameter('h', implode(' : ', $headerNames), true))
102
            ->withParameter(new HeaderValueParameter('q', 'dns/txt'))
103
            ->withParameter(new HeaderValueParameter('s', $selector));
104
105
        foreach ($parameters as $key => $value) {
106
            $headerValue = $headerValue->withParameter(new HeaderValueParameter($key, $value));
107
        }
108
109
        $headerCanonicalized[strtolower(self::HEADER_NAME)] = $this->canonicalizeHeader->canonicalize(
110
            new GenericHeader(self::HEADER_NAME, (string) $headerValue)
111
        );
112
113
        $signature = base64_encode($this->sign->signHeaders(implode('', $headerCanonicalized)));
114
        $headerValue = $headerValue->withParameter(new HeaderValueParameter('b', trim($signature), true));
115
116
        return new class ($headerValue) implements HeaderInterface
117
        {
118
            /**
119
             * @var HeaderValue
120
             */
121
            private $headerValue;
122
123
            /**
124
             * DkimSignature constructor.
125
             * @param HeaderValue $headerValue
126
             */
127
            public function __construct(HeaderValue $headerValue)
128
            {
129
                $this->headerValue = $headerValue;
130
            }
131
132
            /**
133
             * @return HeaderName
134
             */
135
            public function getName(): HeaderName
136
            {
137
                return new HeaderName(HeaderV1Factory::HEADER_NAME);
138
            }
139
140
            /**
141
             * @return HeaderValue
142
             */
143
            public function getValue(): HeaderValue
144
            {
145
                return $this->headerValue;
146
            }
147
        };
148
    }
149
150
}