Completed
Push — 5.x ( 5eecd4...c9dc5a )
by Lars
06:17
created

Swift_Signers_DKIMSigner::_getEncryptedHash()   C

Complexity

Conditions 7
Paths 24

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 8.1426

Importance

Changes 0
Metric Value
cc 7
eloc 20
nc 24
nop 0
dl 0
loc 30
ccs 15
cts 21
cp 0.7143
crap 8.1426
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of SwiftMailer.
5
 * (c) 2004-2009 Chris Corbyn
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
/**
12
 * DKIM Signer used to apply DKIM Signature to a message.
13
 *
14
 * @author Xavier De Cock <[email protected]>
15
 */
16
class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
17
{
18
    /**
19
     * PrivateKey.
20
     *
21
     * @var string
22
     */
23
    protected $_privateKey;
24
25
    /**
26
     * DomainName.
27
     *
28
     * @var string
29
     */
30
    protected $_domainName;
31
32
    /**
33
     * Selector.
34
     *
35
     * @var string
36
     */
37
    protected $_selector;
38
39
    /**
40
     * @var string
41
     */
42
    private $_passphrase = '';
43
44
    /**
45
     * Hash algorithm used.
46
     *
47
     * @see RFC6376 3.3: Signers MUST implement and SHOULD sign using rsa-sha256.
48
     *
49
     * @var string
50
     */
51
    protected $_hashAlgorithm = 'rsa-sha256';
52
53
    /**
54
     * Body canon method.
55
     *
56
     * @var string
57
     */
58
    protected $_bodyCanon = 'simple';
59
60
    /**
61
     * Header canon method.
62
     *
63
     * @var string
64
     */
65
    protected $_headerCanon = 'simple';
66
67
    /**
68
     * Headers not being signed.
69
     *
70
     * @var array
71
     */
72
    protected $_ignoredHeaders = array('return-path' => true);
73
74
    /**
75
     * Signer identity.
76
     *
77
     * @var string
78
     */
79
    protected $_signerIdentity;
80
81
    /**
82
     * BodyLength.
83
     *
84
     * @var int
85
     */
86
    protected $_bodyLen = 0;
87
88
    /**
89
     * Maximum signedLen.
90
     *
91
     * @var int
92
     */
93
    protected $_maxLen = PHP_INT_MAX;
94
95
    /**
96
     * Embbed bodyLen in signature.
97
     *
98
     * @var bool
99
     */
100
    protected $_showLen = false;
101
102
    /**
103
     * When the signature has been applied (true means time()), false means not embedded.
104
     *
105
     * @var mixed
106
     */
107
    protected $_signatureTimestamp = true;
108
109
    /**
110
     * When will the signature expires false means not embedded, if sigTimestamp is auto
111
     * Expiration is relative, otherwise it's absolute.
112
     *
113
     * @var int
114
     */
115
    protected $_signatureExpiration = false;
116
117
    /**
118
     * Must we embed signed headers?
119
     *
120
     * @var bool
121
     */
122
    protected $_debugHeaders = false;
123
124
    // work variables
125
    /**
126
     * Headers used to generate hash.
127
     *
128
     * @var array
129
     */
130
    protected $_signedHeaders = array();
131
132
    /**
133
     * If debugHeaders is set store debugData here.
134
     *
135
     * @var string
136
     */
137
    private $_debugHeadersData = '';
138
139
    /**
140
     * Stores the bodyHash.
141
     *
142
     * @var string
143
     */
144
    private $_bodyHash = '';
145
146
    /**
147
     * Stores the signature header.
148
     *
149
     * @var Swift_Mime_Headers_ParameterizedHeader
150
     */
151
    protected $_dkimHeader;
152
153
    /**
154
     * @var resource
155
     */
156
    private $_bodyHashHandler;
157
158
    /**
159
     * @var null
160
     *
161
     * no used?
162
     */
163
    private $_headerHash;
164
165
    /**
166
     * @var string
167
     */
168
    private $_headerCanonData = '';
169
170
    /**
171
     * @var int
172
     */
173
    private $_bodyCanonEmptyCounter = 0;
174
175
    /**
176
     * @var int
177
     */
178
    private $_bodyCanonIgnoreStart = 2;
179
180
    /**
181
     * @var bool
182
     */
183
    private $_bodyCanonSpace = false;
184
185
    /**
186
     * @var null|string
187
     */
188
    private $_bodyCanonLastChar = null;
189
190
    /**
191
     * @var string
192
     */
193
    private $_bodyCanonLine = '';
194
195
    /**
196
     * @var array
197
     */
198
    private $_bound = array();
199
200
    /**
201
     * Constructor.
202
     *
203
     * @param string $privateKey
204
     * @param string $domainName
205
     * @param string $selector
206
     * @param string $passphrase
207
     */
208 7
    public function __construct($privateKey, $domainName, $selector, $passphrase = '')
209
    {
210 7
        $this->_privateKey = $privateKey;
211 7
        $this->_domainName = $domainName;
212 7
        $this->_signerIdentity = '@' . $domainName;
213 7
        $this->_selector = $selector;
214 7
        $this->_passphrase = $passphrase;
215
216
        // keep fallback hash algorithm sha1 if php version is lower than 5.4.8
217 7
        if (PHP_VERSION_ID < 50408) {
218
            $this->_hashAlgorithm = 'rsa-sha1';
219
        }
220 7
    }
221
222
    /**
223
     * Instanciate DKIMSigner.
224
     *
225
     * @param string $privateKey
226
     * @param string $domainName
227
     * @param string $selector
228
     *
229
     * @return self
230
     */
231
    public static function newInstance($privateKey, $domainName, $selector)
232
    {
233
        return new static($privateKey, $domainName, $selector);
234
    }
235
236
    /**
237
     * Reset the Signer.
238
     *
239
     * @see Swift_Signer::reset()
240
     */
241 6
    public function reset()
242
    {
243 6
        $this->_headerHash = null;
244 6
        $this->_signedHeaders = array();
245 6
        $this->_bodyHash = null;
246 6
        $this->_bodyHashHandler = null;
247 6
        $this->_bodyCanonIgnoreStart = 2;
248 6
        $this->_bodyCanonEmptyCounter = 0;
249 6
        $this->_bodyCanonLastChar = null;
250 6
        $this->_bodyCanonSpace = false;
251 6
    }
252
253
    /**
254
     * Writes $bytes to the end of the stream.
255
     *
256
     * Writing may not happen immediately if the stream chooses to buffer. If
257
     * you want to write these bytes with immediate effect, call {@link commit()}
258
     * after calling write().
259
     *
260
     * This method returns the sequence ID of the write (i.e. 1 for first, 2 for
261
     * second, etc etc).
262
     *
263
     * @param string $bytes
264
     *
265
     * @throws Swift_IoException
266
     *
267
     * @return int
268
     */
269
    // TODO: fix return
270 6
    public function write($bytes)
271
    {
272 6
        $this->_canonicalizeBody($bytes);
273 6
        foreach ($this->_bound as $is) {
274
            $is->write($bytes);
275 6
        }
276 6
    }
277
278
    /**
279
     * For any bytes that are currently buffered inside the stream, force them
280
     * off the buffer.
281
     */
282
    public function commit()
283
    {
284
        // Nothing to do
285
        return;
286
    }
287
288
    /**
289
     * Attach $is to this stream.
290
     * The stream acts as an observer, receiving all data that is written.
291
     * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
292
     *
293
     * @param Swift_InputByteStream $is
294
     */
295
    public function bind(Swift_InputByteStream $is)
296
    {
297
        // Don't have to mirror anything
298
        $this->_bound[] = $is;
299
300
        return;
301
    }
302
303
    /**
304
     * Remove an already bound stream.
305
     * If $is is not bound, no errors will be raised.
306
     * If the stream currently has any buffered data it will be written to $is
307
     * before unbinding occurs.
308
     *
309
     * @param Swift_InputByteStream $is
310
     */
311 View Code Duplication
    public function unbind(Swift_InputByteStream $is)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
312
    {
313
        // Don't have to mirror anything
314
        foreach ($this->_bound as $k => $stream) {
315
            if ($stream === $is) {
316
                unset($this->_bound[$k]);
317
318
                return;
319
            }
320
        }
321
    }
322
323
    /**
324
     * Flush the contents of the stream (empty it) and set the internal pointer
325
     * to the beginning.
326
     *
327
     * @throws Swift_IoException
328
     */
329
    public function flushBuffers()
330
    {
331
        $this->reset();
332
    }
333
334
    /**
335
     * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1.
336
     *
337
     * @param string $hash 'rsa-sha1' or 'rsa-sha256'
338
     *
339
     * @throws Swift_SwiftException
340
     *
341
     * @return $this
342
     */
343 5
    public function setHashAlgorithm($hash)
344
    {
345
        switch ($hash) {
346 5
            case 'rsa-sha1':
347 1
                $this->_hashAlgorithm = 'rsa-sha1';
348 1
                break;
349 4
            case 'rsa-sha256':
350 4
                $this->_hashAlgorithm = 'rsa-sha256';
351 4
                if (!defined('OPENSSL_ALGO_SHA256')) {
352
                    throw new Swift_SwiftException('Unable to set sha256 as it is not supported by OpenSSL.');
353
                }
354 4
                break;
355
            default:
356
                throw new Swift_SwiftException('Unable to set the hash algorithm, must be one of rsa-sha1 or rsa-sha256 (%s given).', $hash);
357
        }
358
359 5
        return $this;
360
    }
361
362
    /**
363
     * Set the body canonicalization algorithm.
364
     *
365
     * @param string $canon
366
     *
367
     * @return $this
368
     */
369 2
    public function setBodyCanon($canon)
370
    {
371 2
        if ($canon === 'relaxed') {
372 2
            $this->_bodyCanon = 'relaxed';
373 2
        } else {
374
            $this->_bodyCanon = 'simple';
375
        }
376
377 2
        return $this;
378
    }
379
380
    /**
381
     * Set the header canonicalization algorithm.
382
     *
383
     * @param string $canon
384
     *
385
     * @return $this
386
     */
387 2
    public function setHeaderCanon($canon)
388
    {
389 2
        if ($canon === 'relaxed') {
390 2
            $this->_headerCanon = 'relaxed';
391 2
        } else {
392
            $this->_headerCanon = 'simple';
393
        }
394
395 2
        return $this;
396
    }
397
398
    /**
399
     * Set the signer identity.
400
     *
401
     * @param string $identity
402
     *
403
     * @return $this
404
     */
405
    public function setSignerIdentity($identity)
406
    {
407
        $this->_signerIdentity = $identity;
408
409
        return $this;
410
    }
411
412
    /**
413
     * Set the length of the body to sign.
414
     *
415
     * @param mixed $len (bool or int)
416
     *
417
     * @return $this
418
     */
419
    public function setBodySignedLen($len)
420
    {
421
        if ($len === true) {
422
            $this->_showLen = true;
423
            $this->_maxLen = PHP_INT_MAX;
424
        } elseif ($len === false) {
425
            $this->_showLen = false;
426
            $this->_maxLen = PHP_INT_MAX;
427
        } else {
428
            $this->_showLen = true;
429
            $this->_maxLen = (int) $len;
430
        }
431
432
        return $this;
433
    }
434
435
    /**
436
     * Set the signature timestamp.
437
     *
438
     * @param int $time A timestamp
439
     *
440
     * @return $this
441
     */
442 5
    public function setSignatureTimestamp($time)
443
    {
444 5
        $this->_signatureTimestamp = $time;
445
446 5
        return $this;
447
    }
448
449
    /**
450
     * Set the signature expiration timestamp.
451
     *
452
     * @param int $time A timestamp
453
     *
454
     * @return $this
455
     */
456
    public function setSignatureExpiration($time)
457
    {
458
        $this->_signatureExpiration = $time;
459
460
        return $this;
461
    }
462
463
    /**
464
     * Enable / disable the DebugHeaders.
465
     *
466
     * @param bool $debug
467
     *
468
     * @return Swift_Signers_DKIMSigner
469
     */
470
    public function setDebugHeaders($debug)
471
    {
472
        $this->_debugHeaders = (bool) $debug;
473
474
        return $this;
475
    }
476
477
    /**
478
     * Start Body.
479
     */
480 6
    public function startBody()
481
    {
482
        // Init
483 6
        switch ($this->_hashAlgorithm) {
484 6
            case 'rsa-sha256':
485 5
                $this->_bodyHashHandler = hash_init('sha256');
486 5
                break;
487 1
            case 'rsa-sha1':
488 1
                $this->_bodyHashHandler = hash_init('sha1');
489 1
                break;
490 6
        }
491 6
        $this->_bodyCanonLine = '';
492 6
    }
493
494
    /**
495
     * End Body.
496
     */
497 6
    public function endBody()
498
    {
499 6
        $this->_endOfBody();
500 6
    }
501
502
    /**
503
     * Returns the list of Headers Tampered by this plugin.
504
     *
505
     * @return string[]
506
     */
507 6
    public function getAlteredHeaders()
508
    {
509 6
        if ($this->_debugHeaders) {
510
            return array('DKIM-Signature', 'X-DebugHash');
511
        }
512
513 6
      return array('DKIM-Signature');
514
    }
515
516
    /**
517
     * Adds an ignored Header.
518
     *
519
     * @param string $header_name
520
     *
521
     * @return Swift_Signers_DKIMSigner
522
     */
523
    public function ignoreHeader($header_name)
524
    {
525
        $this->_ignoredHeaders[Swift::strtolowerWithStaticCache($header_name)] = true;
526
527
        return $this;
528
    }
529
530
    /**
531
     * Set the headers to sign.
532
     *
533
     * @param Swift_Mime_HeaderSet $headers
534
     *
535
     * @return Swift_Signers_DKIMSigner
536
     */
537 6
    public function setHeaders(Swift_Mime_HeaderSet $headers)
538
    {
539 6
        $this->_headerCanonData = '';
540
        // Loop through Headers
541 6
        $listHeaders = $headers->listAll();
542 6 View Code Duplication
        foreach ($listHeaders as $hName) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
543
            // Check if we need to ignore Header
544
            if (
545 1
                !isset($this->_ignoredHeaders[Swift::strtolowerWithStaticCache($hName)])
546 1
                &&
547 1
                $headers->has($hName)
548 1
            ) {
549 1
                $tmp = $headers->getAll($hName);
550 1
                foreach ($tmp as $header) {
551 1
                    if ($header->getFieldBody() != '') {
552 1
                        $this->_addHeader($header->toString());
553 1
                        $this->_signedHeaders[] = $header->getFieldName();
554 1
                    }
555 1
                }
556 1
            }
557 6
        }
558
559 6
        return $this;
560
    }
561
562
    /**
563
     * Add the signature to the given Headers.
564
     *
565
     * @param Swift_Mime_HeaderSet $headers
566
     *
567
     * @return Swift_Signers_DKIMSigner
568
     */
569 6
    public function addSignature(Swift_Mime_HeaderSet $headers)
570
    {
571
        // Prepare the DKIM-Signature
572
        $params = array(
573 6
            'v' => '1',
574 6
            'a' => $this->_hashAlgorithm,
575 6
            'bh' => base64_encode($this->_bodyHash),
576 6
            'd' => $this->_domainName,
577 6
            'h' => implode(': ', $this->_signedHeaders),
578 6
            'i' => $this->_signerIdentity,
579 6
            's' => $this->_selector
580 6
        );
581
582 6
        if ($this->_bodyCanon != 'simple') {
583 2
            $params['c'] = $this->_headerCanon . '/' . $this->_bodyCanon;
584 6
        } elseif ($this->_headerCanon != 'simple') {
585 1
            $params['c'] = $this->_headerCanon;
586 1
        }
587
588 6
        if ($this->_showLen) {
589
            $params['l'] = $this->_bodyLen;
590
        }
591
592 6
        if ($this->_signatureTimestamp === true) {
593
594 1
          $params['t'] = time();
595 1
            if ($this->_signatureExpiration !== false) {
596
                $params['x'] = $params['t'] + $this->_signatureExpiration;
597
            }
598
599 1
        } else {
600
601 5
            if ($this->_signatureTimestamp !== false) {
602 5
                $params['t'] = $this->_signatureTimestamp;
603 5
            }
604
605 5
            if ($this->_signatureExpiration !== false) {
606
                $params['x'] = $this->_signatureExpiration;
607
            }
608
609
        }
610
611 6
        if ($this->_debugHeaders) {
612
            $params['z'] = implode('|', $this->_debugHeadersData);
613
        }
614
615 6
        $string = '';
616 6
        foreach ($params as $k => $v) {
617 6
            $string .= $k . '=' . $v . '; ';
618 6
        }
619
620 6
        $string = trim($string);
621 6
        $headers->addTextHeader('DKIM-Signature', $string);
622
623
        // Add the last DKIM-Signature
624 6
        $tmp = $headers->getAll('DKIM-Signature');
625 6
        $this->_dkimHeader = end($tmp);
0 ignored issues
show
Documentation Bug introduced by
It seems like end($tmp) of type object<Swift_Mime_Headers_AbstractHeader> or false is incompatible with the declared type object<Swift_Mime_Headers_ParameterizedHeader> of property $_dkimHeader.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
626 6
        $this->_addHeader(trim($this->_dkimHeader->toString()) . "\r\n b=", true);
627 6
        $this->_endOfHeaders();
0 ignored issues
show
Deprecated Code introduced by
The method Swift_Signers_DKIMSigner::_endOfHeaders() has been deprecated with message: This method is currently useless in this class but it must be kept for BC reasons due to its "protected" scope. This method might be overridden by custom client code.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
628
629 6
        if ($this->_debugHeaders) {
630
            $headers->addTextHeader('X-DebugHash', base64_encode($this->_headerHash));
631
        }
632
633 6
        $this->_dkimHeader->setValue($string . ' b=' . trim(chunk_split(base64_encode($this->_getEncryptedHash()), 73, ' ')));
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Swift_Mime_Headers_AbstractHeader as the method setValue() does only exist in the following sub-classes of Swift_Mime_Headers_AbstractHeader: Swift_Mime_Headers_ParameterizedHeader, Swift_Mime_Headers_UnstructuredHeader. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
634
635 6
        return $this;
636
    }
637
638
    /**
639
     * @param string $header
640
     * @param bool   $is_sig
641
     */
642 6 View Code Duplication
    protected function _addHeader($header, $is_sig = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
643
    {
644 6
        switch ($this->_headerCanon) {
645 6
            case 'relaxed':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
646
                // Prepare Header and cascade
647 2
                $exploded = explode(':', $header, 2);
648 2
                $name = Swift::strtolowerWithStaticCache(trim($exploded[0]));
649 2
                $value = str_replace("\r\n", '', $exploded[1]);
650 2
                $value = preg_replace("/[ \t][ \t]+/", ' ', $value);
651 2
                $header = $name . ':' . trim($value) . ($is_sig ? '' : "\r\n");
652 6
            case 'simple':
653
                // Nothing to do
654 6
        }
655 6
        $this->_addToHeaderHash($header);
656 6
    }
657
658
    /**
659
     * @deprecated This method is currently useless in this class but it must be
660
     *             kept for BC reasons due to its "protected" scope. This method
661
     *             might be overridden by custom client code.
662
     */
663
    protected function _endOfHeaders()
664
    {
665
    }
666
667
    /**
668
     * @param string $string
669
     */
670 6
    protected function _canonicalizeBody($string)
671
    {
672 6
        $len = strlen($string);
673 6
        $canon = '';
674 6
        $method = ($this->_bodyCanon === 'relaxed');
675 6
        for ($i = 0; $i < $len; ++$i) {
676 6
            if ($this->_bodyCanonIgnoreStart > 0) {
677 6
                --$this->_bodyCanonIgnoreStart;
678 6
                continue;
679
            }
680 6
            switch ($string[$i]) {
681 6
                case "\r":
682
                    $this->_bodyCanonLastChar = "\r";
683
                    break;
684 6 View Code Duplication
                case "\n":
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
685
                    if ($this->_bodyCanonLastChar === "\r") {
686
                        if ($method) {
687
                            $this->_bodyCanonSpace = false;
688
                        }
689
690
                        if ($this->_bodyCanonLine === '') {
691
                            ++$this->_bodyCanonEmptyCounter;
692
                        } else {
693
                            $this->_bodyCanonLine = '';
694
                            $canon .= "\r\n";
695
                        }
696
697
                    } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
698
                        // Wooops Error
699
                        // TODO: handle it but should never happen
700
                    }
701
                    break;
702 6
                case ' ':
703 6
                case "\t":
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
704 6
                    if ($method) {
705 2
                        $this->_bodyCanonSpace = true;
706 2
                        break;
707
                    }
708 6
                default:
709 6 View Code Duplication
                    if ($this->_bodyCanonEmptyCounter > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
710
                        $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter);
711
                        $this->_bodyCanonEmptyCounter = 0;
712
                    }
713 6
                    if ($this->_bodyCanonSpace) {
714 2
                        $this->_bodyCanonLine .= ' ';
715 2
                        $canon .= ' ';
716 2
                        $this->_bodyCanonSpace = false;
717 2
                    }
718 6
                    $this->_bodyCanonLine .= $string[$i];
719 6
                    $canon .= $string[$i];
720 6
            }
721 6
        }
722 6
        $this->_addToBodyHash($canon);
723 6
    }
724
725 6
    protected function _endOfBody()
726
    {
727
        // Add trailing Line return if last line is non empty
728 6
        if ($this->_bodyCanonLine !== '') {
729 6
            $this->_addToBodyHash("\r\n");
730 6
        }
731
732 6
        $this->_bodyHash = hash_final($this->_bodyHashHandler, true);
733 6
    }
734
735
    /**
736
     * @param string $string
737
     */
738 6
    private function _addToBodyHash($string)
739
    {
740 6
        $len = strlen($string);
741 6
        if ($len > ($new_len = ($this->_maxLen - $this->_bodyLen))) {
742
          /** @noinspection CallableParameterUseCaseInTypeContextInspection */
743
          $string = substr($string, 0, $new_len);
744
            $len = $new_len;
745
        }
746 6
        hash_update($this->_bodyHashHandler, $string);
747 6
        $this->_bodyLen += $len;
748 6
    }
749
750
    /**
751
     * @param string $header
752
     */
753 6
    private function _addToHeaderHash($header)
754
    {
755 6
        if ($this->_debugHeaders) {
756
            $this->_debugHeadersData[] = trim($header);
757
        }
758 6
        $this->_headerCanonData .= $header;
759 6
    }
760
761
    /**
762
     * @throws Swift_SwiftException
763
     *
764
     * @return string
765
     */
766 6
    private function _getEncryptedHash()
767
    {
768 6
        $signature = '';
769
770 6
        switch ($this->_hashAlgorithm) {
771 6
            case 'rsa-sha1':
772 1
                $algorithm = OPENSSL_ALGO_SHA1;
773 1
                break;
774 5
            case 'rsa-sha256':
775 5
                $algorithm = OPENSSL_ALGO_SHA256;
776 5
                break;
777
            default:
778
                $algorithm = PHP_VERSION_ID < 50408 ? OPENSSL_ALGO_SHA1 : OPENSSL_ALGO_SHA256;
779 6
        }
780
781 6
        if ($this->_passphrase) {
782
          $pkeyId = openssl_get_privatekey($this->_privateKey, $this->_passphrase);
783
        } else {
784 6
          $pkeyId = openssl_get_privatekey($this->_privateKey);
785
        }
786 6
        if (!$pkeyId) {
787
            throw new Swift_SwiftException('Unable to load DKIM Private Key [' . openssl_error_string() . ']');
788
        }
789
790 6
        if (openssl_sign($this->_headerCanonData, $signature, $pkeyId, $algorithm)) {
791 6
            return $signature;
792
        }
793
794
        throw new Swift_SwiftException('Unable to sign DKIM Hash [' . openssl_error_string() . ']');
795
    }
796
}
797