Passed
Push — fix-170 ( a0a20a )
by Zaahid
05:36
created

ensureHtmlPartFirstForSignedMessage()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 8
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 10
ccs 9
cts 9
cp 1
crap 5
rs 9.6111
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
     * Constructor
35
     *
36
     * @param MimePartFactory $mimePartFactory
37
     * @param UUEncodedPartFactory $uuEncodedPartFactory
38
     * @param PartBuilderFactory $partBuilderFactory
39
     * @param GenericHelper $genericHelper
40
     * @param MultipartHelper $multipartHelper
41
     */
42 7
    public function __construct(
43
        MimePartFactory $mimePartFactory,
44
        UUEncodedPartFactory $uuEncodedPartFactory,
45
        PartBuilderFactory $partBuilderFactory,
46
        GenericHelper $genericHelper,
47
        MultipartHelper $multipartHelper
48
    ) {
49 7
        parent::__construct($mimePartFactory, $uuEncodedPartFactory, $partBuilderFactory);
50 7
        $this->genericHelper = $genericHelper;
51 7
        $this->multipartHelper = $multipartHelper;
52 7
    }
53
54
    /**
55
     * The passed message is set as multipart/signed, and a new part is created
56
     * below it with content headers, content and children copied from the
57
     * message.
58
     *
59
     * @param Message $message
60
     * @param string $micalg
61
     * @param string $protocol
62
     */
63 9
    public function setMessageAsMultipartSigned(Message $message, $micalg, $protocol)
64
    {
65 9
        if (strcasecmp($message->getContentType(), 'multipart/signed') !== 0) {
66 9
            $this->multipartHelper->enforceMime($message);
67 9
            $messagePart = $this->partBuilderFactory->newPartBuilder($this->mimePartFactory)->createMessagePart();
68 9
            $this->genericHelper->movePartContentAndChildren($message, $messagePart);
69 9
            $message->addChild($messagePart);
70 9
            $boundary = $this->multipartHelper->getUniqueBoundary('multipart/signed');
71 9
            $message->setRawHeader(
72 9
                'Content-Type',
73 9
                "multipart/signed;\r\n\tboundary=\"$boundary\";\r\n\tmicalg=\"$micalg\"; protocol=\"$protocol\""
74
            );
75
        }
76 9
        $this->overwrite8bitContentEncoding($message);
77 9
        $this->setSignature($message, 'Empty');
78 9
    }
79
80
    /**
81
     * Sets the signature of the message to $body, creating a signature part if
82
     * one doesn't exist.
83
     *
84
     * @param Message $message
85
     * @param string $body
86
     */
87 10
    public function setSignature(Message $message, $body)
88
    {
89 10
        $signedPart = $message->getSignaturePart();
90 10
        if ($signedPart === null) {
91 9
            $signedPart = $this->partBuilderFactory->newPartBuilder($this->mimePartFactory)->createMessagePart();
92 9
            $message->addChild($signedPart);
93
        }
94 10
        $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

94
        $signedPart->/** @scrutinizer ignore-call */ 
95
                     setRawHeader(
Loading history...
95 10
            'Content-Type',
96 10
            $message->getHeaderParameter('Content-Type', 'protocol')
97
        );
98 10
        $signedPart->setContent($body);
99 10
    }
100
101
    /**
102
     * Loops over parts of the message and sets the content-transfer-encoding
103
     * header to quoted-printable for text/* mime parts, and to base64
104
     * otherwise for parts that are '8bit' encoded.
105
     *
106
     * Used for multipart/signed messages which doesn't support 8bit transfer
107
     * encodings.
108
     *
109
     * @param Message $message
110
     */
111 10
    public function overwrite8bitContentEncoding(Message $message)
112
    {
113 10
        $parts = $message->getAllParts(new PartFilter([
114 10
            'headers' => [ PartFilter::FILTER_INCLUDE => [
115
                'Content-Transfer-Encoding' => '8bit'
116
            ] ]
117
        ]));
118 10
        foreach ($parts as $part) {
119 2
            $contentType = strtolower($part->getContentType());
120 2
            if ($contentType === 'text/plain' || $contentType === 'text/html') {
121 2
                $part->setRawHeader('Content-Transfer-Encoding', 'quoted-printable');
122
            } else {
123 2
                $part->setRawHeader('Content-Transfer-Encoding', 'base64');
124
            }
125
        }
126 10
    }
127
128
    /**
129
     * Returns a stream that can be used to read the content part of a signed
130
     * message, which can be used to sign an email or verify a signature.
131
     *
132
     * The method simply returns the stream for the first child.  No
133
     * verification of whether the message is in fact a signed message is
134
     * performed.
135
     *
136
     * Note that unlike getSignedMessageAsString, getSignedMessageStream doesn't
137
     * replace new lines.
138
     *
139
     * @param Message $message
140
     * @return \Psr\Http\Message\StreamInterface or null if the message doesn't
141
     *         have any children
142
     */
143 15
    public function getSignedMessageStream(Message $message)
144
    {
145 15
        $child = $message->getChild(0);
146 15
        if ($child !== null) {
147 15
            return $child->getStream();
148
        }
149 2
        return null;
150
    }
151
152
    /**
153
     * Returns a string containing the entire body (content) of a signed message
154
     * for verification or calculating a signature.
155
     *
156
     * Non-CRLF new lines are replaced to always be CRLF.
157
     *
158
     * @param Message $message
159
     * @return string or null if the message doesn't have any children
160
     */
161 14
    public function getSignedMessageAsString(Message $message)
162
    {
163 14
        $stream = $this->getSignedMessageStream($message);
164 14
        if ($stream !== null) {
165 14
            return preg_replace(
166 14
                '/\r\n|\r|\n/',
167 14
                "\r\n",
168 14
                $stream->getContents()
169
            );
170
        }
171 1
        return null;
172
    }
173
174
    /**
175
     * Returns the signature part of a multipart/signed message or null.
176
     *
177
     * The signature part is determined to always be the 2nd child of a
178
     * multipart/signed message, the first being the 'body'.
179
     *
180
     * Using the 'protocol' parameter of the Content-Type header is unreliable
181
     * in some instances (for instance a difference of x-pgp-signature versus
182
     * pgp-signature).
183
     *
184
     * @param Message $message
185
     * @return \ZBateson\MailMimeParser\Message\Part\MimePart
186
     */
187 19
    public function getSignaturePart(Message $message)
188
    {
189 19
        if (strcasecmp($message->getContentType(), 'multipart/signed') === 0) {
190 19
            return $message->getChild(1);
191
        } else {
192 1
            return null;
193
        }
194
    }
195
}
196