Passed
Push — master ( 37aad3...325143 )
by Zaahid
03:26
created

PrivacyHelper::getSignaturePart()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the ZBateson\MailMimeParser project.
4
 *
5
 * @license http://opensource.org/licenses/bsd-license.php BSD
6
 */
7
namespace ZBateson\MailMimeParser\Message\Helper;
8
9
use ZBateson\MailMimeParser\Message;
10
use ZBateson\MailMimeParser\Message\Part\Factory\MimePartFactory;
11
use ZBateson\MailMimeParser\Message\Part\Factory\PartBuilderFactory;
12
use ZBateson\MailMimeParser\Message\Part\Factory\UUEncodedPartFactory;
13
use ZBateson\MailMimeParser\Message\Part\ParentPart;
14
use ZBateson\MailMimeParser\Message\PartFilter;
15
16
/**
17
 * Provides routines to set or retrieve the signature part of a signed message.
18
 *
19
 * @author Zaahid Bateson
20
 */
21
class PrivacyHelper extends AbstractHelper
22
{
23
    /**
24
     * @var GenericHelper a GenericHelper instance
25
     */
26
    private $genericHelper;
27
28
    /**
29
     * @var MultipartHelper a MultipartHelper instance
30
     */
31
    private $multipartHelper;
32
33
    /**
34
     * @param MimePartFactory $mimePartFactory
35
     * @param UUEncodedPartFactory $uuEncodedPartFactory
36
     * @param PartBuilderFactory $partBuilderFactory
37
     * @param GenericHelper $genericHelper
38
     * @param MultipartHelper $multipartHelper
39
     */
40 7
    public function __construct(
41
        MimePartFactory $mimePartFactory,
42
        UUEncodedPartFactory $uuEncodedPartFactory,
43
        PartBuilderFactory $partBuilderFactory,
44
        GenericHelper $genericHelper,
45
        MultipartHelper $multipartHelper
46
    ) {
47 7
        parent::__construct($mimePartFactory, $uuEncodedPartFactory, $partBuilderFactory);
48 7
        $this->genericHelper = $genericHelper;
49 7
        $this->multipartHelper = $multipartHelper;
50 7
    }
51
52
    /**
53
     * The passed message is set as multipart/signed, and a new part is created
54
     * below it with content headers, content and children copied from the
55
     * message.
56
     *
57
     * @param Message $message
58
     * @param string $micalg
59
     * @param string $protocol
60
     */
61 1
    public function setMessageAsMultipartSigned(Message $message, $micalg, $protocol)
62
    {
63 1
        if (strcasecmp($message->getContentType(), 'multipart/signed') !== 0) {
64 1
            $this->multipartHelper->enforceMime($message);
65 1
            $messagePart = $this->partBuilderFactory->newPartBuilder($this->mimePartFactory)->createMessagePart();
66 1
            $this->genericHelper->movePartContentAndChildren($message, $messagePart);
67 1
            $message->addChild($messagePart);
68 1
            $boundary = $this->multipartHelper->getUniqueBoundary('multipart/signed');
69 1
            $message->setRawHeader(
70 1
                'Content-Type',
71 1
                "multipart/signed;\r\n\tboundary=\"$boundary\";\r\n\tmicalg=\"$micalg\"; protocol=\"$protocol\""
72
            );
73
        }
74 1
        $this->overwrite8bitContentEncoding($message);
75 1
        $this->ensureHtmlPartFirstForSignedMessage($message);
76 1
        $this->setSignature($message, 'Empty');
77 1
    }
78
79
    /**
80
     * Sets the signature of the message to $body, creating a signature part if
81
     * one doesn't exist.
82
     *
83
     * @param Message $message
84
     * @param string $body
85
     */
86 2
    public function setSignature(Message $message, $body)
87
    {
88 2
        $signedPart = $message->getSignaturePart();
89 2
        if ($signedPart === null) {
90 1
            $signedPart = $this->partBuilderFactory->newPartBuilder($this->mimePartFactory)->createMessagePart();
91 1
            $message->addChild($signedPart);
92
        }
93 2
        $signedPart->setRawHeader(
0 ignored issues
show
Bug introduced by
The method setRawHeader() does not exist on ZBateson\MailMimeParser\Message\Part\MessagePart. It seems like you code against a sub-type of ZBateson\MailMimeParser\Message\Part\MessagePart such as ZBateson\MailMimeParser\...e\Part\ParentHeaderPart. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

93
        $signedPart->/** @scrutinizer ignore-call */ 
94
                     setRawHeader(
Loading history...
94 2
            'Content-Type',
95 2
            $message->getHeaderParameter('Content-Type', 'protocol')
96
        );
97 2
        $signedPart->setContent($body);
98 2
    }
99
100
    /**
101
     * Loops over parts of the message and sets the content-transfer-encoding
102
     * header to quoted-printable for text/* mime parts, and to base64
103
     * otherwise for parts that are '8bit' encoded.
104
     *
105
     * Used for multipart/signed messages which doesn't support 8bit transfer
106
     * encodings.
107
     *
108
     * @param Message $message
109
     */
110 2
    public function overwrite8bitContentEncoding(Message $message)
111
    {
112 2
        $parts = $message->getAllParts(new PartFilter([
113 2
            'headers' => [ PartFilter::FILTER_INCLUDE => [
114
                'Content-Transfer-Encoding' => '8bit'
115
            ] ]
116
        ]));
117 2
        foreach ($parts as $part) {
118 1
            $contentType = strtolower($part->getContentType());
119 1
            if ($contentType === 'text/plain' || $contentType === 'text/html') {
120 1
                $part->setRawHeader('Content-Transfer-Encoding', 'quoted-printable');
121
            } else {
122 1
                $part->setRawHeader('Content-Transfer-Encoding', 'base64');
123
            }
124
        }
125 2
    }
126
127
    /**
128
     * Ensures a non-text part comes first in a signed multipart/alternative
129
     * message as some clients seem to prefer the first content part if the
130
     * client doesn't understand multipart/signed.
131
     *
132
     * @param Message $message
133
     */
134 2
    public function ensureHtmlPartFirstForSignedMessage(Message $message)
135
    {
136 2
        $alt = $message->getPartByMimeType('multipart/alternative');
137 2
        if ($alt !== null && $alt instanceof ParentPart) {
138 1
            $cont = $this->multipartHelper->getContentPartContainerFromAlternative('text/html', $alt);
139 1
            $children = $alt->getChildParts();
140 1
            $pos = array_search($cont, $children, true);
141 1
            if ($pos !== false && $pos !== 0) {
142 1
                $alt->removePart($children[0]);
143 1
                $alt->addChild($children[0]);
144
            }
145
        }
146 2
    }
147
148
    /**
149
     * Returns a stream that can be used to read the content part of a signed
150
     * message, which can be used to sign an email or verify a signature.
151
     *
152
     * The method simply returns the stream for the first child.  No
153
     * verification of whether the message is in fact a signed message is
154
     * performed.
155
     *
156
     * Note that unlike getSignedMessageAsString, getSignedMessageStream doesn't
157
     * replace new lines.
158
     *
159
     * @param Message $message
160
     * @return StreamInterface or null if the message doesn't have any children
0 ignored issues
show
Bug introduced by
The type ZBateson\MailMimeParser\...\Helper\StreamInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
161
     */
162 2
    public function getSignedMessageStream(Message $message)
163
    {
164 2
        $child = $message->getChild(0);
165 2
        if ($child !== null) {
166 2
            return $child->getStream();
167
        }
168 2
        return null;
169
    }
170
171
    /**
172
     * Returns a string containing the entire body (content) of a signed message
173
     * for verification or calculating a signature.
174
     *
175
     * Non-CRLF new lines are replaced to always be CRLF.
176
     *
177
     * @param Message $message
178
     * @return string or null if the message doesn't have any children
179
     */
180 1
    public function getSignedMessageAsString(Message $message)
181
    {
182 1
        $stream = $this->getSignedMessageStream($message);
183 1
        if ($stream !== null) {
184 1
            return preg_replace(
185 1
                '/\r\n|\r|\n/',
186 1
                "\r\n",
187 1
                $stream->getContents()
188
            );
189
        }
190 1
        return null;
191
    }
192
193
    /**
194
     * Returns the signature part of a multipart/signed message or null.
195
     *
196
     * The signature part is determined to always be the 2nd child of a
197
     * multipart/signed message, the first being the 'body'.
198
     *
199
     * Using the 'protocol' parameter of the Content-Type header is unreliable
200
     * in some instances (for instance a difference of x-pgp-signature versus
201
     * pgp-signature).
202
     *
203
     * @param Message $message
204
     * @return MimePart
0 ignored issues
show
Bug introduced by
The type ZBateson\MailMimeParser\Message\Helper\MimePart was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
205
     */
206 1
    public function getSignaturePart(Message $message)
207
    {
208 1
        if (strcasecmp($message->getContentType(), 'multipart/signed') === 0) {
209 1
            return $message->getChild(1);
210
        } else {
211 1
            return null;
212
        }
213
    }
214
}
215