PrivacyHelper   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 136
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 13
eloc 48
c 2
b 0
f 0
dl 0
loc 136
ccs 56
cts 56
cp 1
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getSignedMessageAsString() 0 11 2
A overwrite8bitContentEncoding() 0 15 4
A getSignedMessageStream() 0 7 2
A setSignature() 0 13 2
A __construct() 0 9 1
A setMessageAsMultipartSigned() 0 16 2
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
8
namespace ZBateson\MailMimeParser\Message\Helper;
9
10
use Psr\Http\Message\StreamInterface;
11
use ZBateson\MailMimeParser\Header\HeaderConsts;
12
use ZBateson\MailMimeParser\IMessage;
13
use ZBateson\MailMimeParser\Message\Factory\IMimePartFactory;
14
use ZBateson\MailMimeParser\Message\Factory\IUUEncodedPartFactory;
15
use ZBateson\MailMimeParser\Message\IMessagePart;
16
17
/**
18
 * Provides routines to set or retrieve the signature part of a signed message.
19
 *
20
 * @author Zaahid Bateson
21
 */
22
class PrivacyHelper extends AbstractHelper
23
{
24
    /**
25
     * @var GenericHelper a GenericHelper instance
26
     */
27
    private GenericHelper $genericHelper;
28
29
    /**
30
     * @var MultipartHelper a MultipartHelper instance
31
     */
32
    private MultipartHelper $multipartHelper;
33
34 7
    public function __construct(
35
        IMimePartFactory $mimePartFactory,
36
        IUUEncodedPartFactory $uuEncodedPartFactory,
37
        GenericHelper $genericHelper,
38
        MultipartHelper $multipartHelper
39
    ) {
40 7
        parent::__construct($mimePartFactory, $uuEncodedPartFactory);
41 7
        $this->genericHelper = $genericHelper;
42 7
        $this->multipartHelper = $multipartHelper;
43
    }
44
45
    /**
46
     * The passed message is set as multipart/signed, and a new part is created
47
     * below it with content headers, content and children copied from the
48
     * message.
49
     *
50
     * @param string $micalg
51
     * @param string $protocol
52
     */
53 10
    public function setMessageAsMultipartSigned(IMessage $message, $micalg, $protocol) : static
54
    {
55 10
        if (\strcasecmp($message->getContentType(), 'multipart/signed') !== 0) {
0 ignored issues
show
Bug introduced by
It seems like $message->getContentType() can also be of type null; however, parameter $string1 of strcasecmp() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

55
        if (\strcasecmp(/** @scrutinizer ignore-type */ $message->getContentType(), 'multipart/signed') !== 0) {
Loading history...
56 10
            $this->multipartHelper->enforceMime($message);
57 10
            $messagePart = $this->mimePartFactory->newInstance();
58 10
            $this->genericHelper->movePartContentAndChildren($message, $messagePart);
59 10
            $message->addChild($messagePart);
60 10
            $boundary = $this->multipartHelper->getUniqueBoundary('multipart/signed');
61 10
            $message->setRawHeader(
62 10
                HeaderConsts::CONTENT_TYPE,
63 10
                "multipart/signed;\r\n\tboundary=\"$boundary\";\r\n\tmicalg=\"$micalg\"; protocol=\"$protocol\""
64 10
            );
65
        }
66 10
        $this->overwrite8bitContentEncoding($message);
67 10
        $this->setSignature($message, 'Empty');
68 10
        return $this;
69
    }
70
71
    /**
72
     * Sets the signature of the message to $body, creating a signature part if
73
     * one doesn't exist.
74
     *
75
     * @param string $body
76
     */
77 11
    public function setSignature(IMessage $message, $body) : static
78
    {
79 11
        $signedPart = $message->getSignaturePart();
80 11
        if ($signedPart === null) {
81 10
            $signedPart = $this->mimePartFactory->newInstance();
82 10
            $message->addChild($signedPart);
83
        }
84 11
        $signedPart->setRawHeader(
0 ignored issues
show
Bug introduced by
The method setRawHeader() does not exist on ZBateson\MailMimeParser\Message\IMessagePart. It seems like you code against a sub-type of ZBateson\MailMimeParser\Message\IMessagePart such as ZBateson\MailMimeParser\Message\MimePart or ZBateson\MailMimeParser\Message\IMimePart or ZBateson\MailMimeParser\Message\MimePart. ( Ignorable by Annotation )

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

84
        $signedPart->/** @scrutinizer ignore-call */ 
85
                     setRawHeader(
Loading history...
85 11
            HeaderConsts::CONTENT_TYPE,
86 11
            $message->getHeaderParameter(HeaderConsts::CONTENT_TYPE, 'protocol')
87 11
        );
88 11
        $signedPart->setContent($body);
89 11
        return $this;
90
    }
91
92
    /**
93
     * Loops over parts of the message and sets the content-transfer-encoding
94
     * header to quoted-printable for text/* mime parts, and to base64
95
     * otherwise for parts that are '8bit' encoded.
96
     *
97
     * Used for multipart/signed messages which doesn't support 8bit transfer
98
     * encodings.
99
     */
100 11
    public function overwrite8bitContentEncoding(IMessage $message) : static
101
    {
102 11
        $parts = $message->getAllParts(function(IMessagePart $part) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
103 9
            return \strcasecmp($part->getContentTransferEncoding(), '8bit') === 0;
0 ignored issues
show
Bug introduced by
It seems like $part->getContentTransferEncoding() can also be of type null; however, parameter $string1 of strcasecmp() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

103
            return \strcasecmp(/** @scrutinizer ignore-type */ $part->getContentTransferEncoding(), '8bit') === 0;
Loading history...
104 11
        });
105 11
        foreach ($parts as $part) {
106 3
            $contentType = \strtolower($part->getContentType());
0 ignored issues
show
Bug introduced by
It seems like $part->getContentType() can also be of type null; however, parameter $string of strtolower() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

106
            $contentType = \strtolower(/** @scrutinizer ignore-type */ $part->getContentType());
Loading history...
107 3
            $part->setRawHeader(
108 3
                HeaderConsts::CONTENT_TRANSFER_ENCODING,
109 3
                ($contentType === 'text/plain' || $contentType === 'text/html') ?
110 2
                'quoted-printable' :
111 3
                'base64'
112 3
            );
113
        }
114 11
        return $this;
115
    }
116
117
    /**
118
     * Returns a stream that can be used to read the content part of a signed
119
     * message, which can be used to sign an email or verify a signature.
120
     *
121
     * The method simply returns the stream for the first child.  No
122
     * verification of whether the message is in fact a signed message is
123
     * performed.
124
     *
125
     * Note that unlike getSignedMessageAsString, getSignedMessageStream doesn't
126
     * replace new lines.
127
     *
128
     * @return ?StreamInterface null if the message doesn't have any children
129
     */
130 16
    public function getSignedMessageStream(IMessage $message) : ?StreamInterface
131
    {
132 16
        $child = $message->getChild(0);
133 16
        if ($child !== null) {
134 16
            return $child->getStream();
135
        }
136 2
        return null;
137
    }
138
139
    /**
140
     * Returns a string containing the entire body (content) of a signed message
141
     * for verification or calculating a signature.
142
     *
143
     * Non-CRLF new lines are replaced to always be CRLF.
144
     *
145
     * @return ?string null if the message doesn't have any children
146
     */
147 15
    public function getSignedMessageAsString(IMessage $message) : ?string
148
    {
149 15
        $stream = $this->getSignedMessageStream($message);
150 15
        if ($stream !== null) {
151 15
            return \preg_replace(
152 15
                '/\r\n|\r|\n/',
153 15
                "\r\n",
154 15
                $stream->getContents()
155 15
            );
156
        }
157 1
        return null;
158
    }
159
}
160