Completed
Push — 5.x ( 158fb7...5eecd4 )
by Lars
06:12
created

Swift_Signers_DKIMSigner::addSignature()   D

Complexity

Conditions 11
Paths 288

Size

Total Lines 68
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 0
Metric Value
cc 11
eloc 39
nc 288
nop 1
dl 0
loc 68
ccs 0
cts 47
cp 0
crap 132
rs 4.2857
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
    public function __construct($privateKey, $domainName, $selector, $passphrase)
209
    {
210
        $this->_privateKey = $privateKey;
211
        $this->_domainName = $domainName;
212
        $this->_signerIdentity = '@' . $domainName;
213
        $this->_selector = $selector;
214
        $this->_passphrase = $passphrase;
215
216
        // keep fallback hash algorithm sha1 if php version is lower than 5.4.8
217
        if (PHP_VERSION_ID < 50408) {
218
            $this->_hashAlgorithm = 'rsa-sha1';
219
        }
220
    }
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);
0 ignored issues
show
Bug introduced by
The call to Swift_Signers_DKIMSigner::__construct() misses a required argument $passphrase.

This check looks for function calls that miss required arguments.

Loading history...
234
    }
235
236
    /**
237
     * Reset the Signer.
238
     *
239
     * @see Swift_Signer::reset()
240
     */
241
    public function reset()
242
    {
243
        $this->_headerHash = null;
244
        $this->_signedHeaders = array();
245
        $this->_bodyHash = null;
246
        $this->_bodyHashHandler = null;
247
        $this->_bodyCanonIgnoreStart = 2;
248
        $this->_bodyCanonEmptyCounter = 0;
249
        $this->_bodyCanonLastChar = null;
250
        $this->_bodyCanonSpace = false;
251
    }
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
    public function write($bytes)
271
    {
272
        $this->_canonicalizeBody($bytes);
273
        foreach ($this->_bound as $is) {
274
            $is->write($bytes);
275
        }
276
    }
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
    public function setHashAlgorithm($hash)
344
    {
345
        switch ($hash) {
346
            case 'rsa-sha1':
347
                $this->_hashAlgorithm = 'rsa-sha1';
348
                break;
349
            case 'rsa-sha256':
350
                $this->_hashAlgorithm = 'rsa-sha256';
351
                if (!defined('OPENSSL_ALGO_SHA256')) {
352
                    throw new Swift_SwiftException('Unable to set sha256 as it is not supported by OpenSSL.');
353
                }
354
                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
        return $this;
360
    }
361
362
    /**
363
     * Set the body canonicalization algorithm.
364
     *
365
     * @param string $canon
366
     *
367
     * @return $this
368
     */
369
    public function setBodyCanon($canon)
370
    {
371
        if ($canon === 'relaxed') {
372
            $this->_bodyCanon = 'relaxed';
373
        } else {
374
            $this->_bodyCanon = 'simple';
375
        }
376
377
        return $this;
378
    }
379
380
    /**
381
     * Set the header canonicalization algorithm.
382
     *
383
     * @param string $canon
384
     *
385
     * @return $this
386
     */
387
    public function setHeaderCanon($canon)
388
    {
389
        if ($canon === 'relaxed') {
390
            $this->_headerCanon = 'relaxed';
391
        } else {
392
            $this->_headerCanon = 'simple';
393
        }
394
395
        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
    public function setSignatureTimestamp($time)
443
    {
444
        $this->_signatureTimestamp = $time;
445
446
        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
    public function startBody()
481
    {
482
        // Init
483
        switch ($this->_hashAlgorithm) {
484
            case 'rsa-sha256':
485
                $this->_bodyHashHandler = hash_init('sha256');
486
                break;
487
            case 'rsa-sha1':
488
                $this->_bodyHashHandler = hash_init('sha1');
489
                break;
490
        }
491
        $this->_bodyCanonLine = '';
492
    }
493
494
    /**
495
     * End Body.
496
     */
497
    public function endBody()
498
    {
499
        $this->_endOfBody();
500
    }
501
502
    /**
503
     * Returns the list of Headers Tampered by this plugin.
504
     *
505
     * @return string[]
506
     */
507
    public function getAlteredHeaders()
508
    {
509
        if ($this->_debugHeaders) {
510
            return array('DKIM-Signature', 'X-DebugHash');
511
        }
512
513
      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
    public function setHeaders(Swift_Mime_HeaderSet $headers)
538
    {
539
        $this->_headerCanonData = '';
540
        // Loop through Headers
541
        $listHeaders = $headers->listAll();
542 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
                !isset($this->_ignoredHeaders[Swift::strtolowerWithStaticCache($hName)])
546
                &&
547
                $headers->has($hName)
548
            ) {
549
                $tmp = $headers->getAll($hName);
550
                foreach ($tmp as $header) {
551
                    if ($header->getFieldBody() != '') {
552
                        $this->_addHeader($header->toString());
553
                        $this->_signedHeaders[] = $header->getFieldName();
554
                    }
555
                }
556
            }
557
        }
558
559
        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
    public function addSignature(Swift_Mime_HeaderSet $headers)
570
    {
571
        // Prepare the DKIM-Signature
572
        $params = array(
573
            'v' => '1',
574
            'a' => $this->_hashAlgorithm,
575
            'bh' => base64_encode($this->_bodyHash),
576
            'd' => $this->_domainName,
577
            'h' => implode(': ', $this->_signedHeaders),
578
            'i' => $this->_signerIdentity,
579
            's' => $this->_selector
580
        );
581
582
        if ($this->_bodyCanon != 'simple') {
583
            $params['c'] = $this->_headerCanon . '/' . $this->_bodyCanon;
584
        } elseif ($this->_headerCanon != 'simple') {
585
            $params['c'] = $this->_headerCanon;
586
        }
587
588
        if ($this->_showLen) {
589
            $params['l'] = $this->_bodyLen;
590
        }
591
592
        if ($this->_signatureTimestamp === true) {
593
594
          $params['t'] = time();
595
            if ($this->_signatureExpiration !== false) {
596
                $params['x'] = $params['t'] + $this->_signatureExpiration;
597
            }
598
599
        } else {
600
601
            if ($this->_signatureTimestamp !== false) {
602
                $params['t'] = $this->_signatureTimestamp;
603
            }
604
605
            if ($this->_signatureExpiration !== false) {
606
                $params['x'] = $this->_signatureExpiration;
607
            }
608
609
        }
610
611
        if ($this->_debugHeaders) {
612
            $params['z'] = implode('|', $this->_debugHeadersData);
613
        }
614
615
        $string = '';
616
        foreach ($params as $k => $v) {
617
            $string .= $k . '=' . $v . '; ';
618
        }
619
620
        $string = trim($string);
621
        $headers->addTextHeader('DKIM-Signature', $string);
622
623
        // Add the last DKIM-Signature
624
        $tmp = $headers->getAll('DKIM-Signature');
625
        $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
        $this->_addHeader(trim($this->_dkimHeader->toString()) . "\r\n b=", true);
627
        $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
        if ($this->_debugHeaders) {
630
            $headers->addTextHeader('X-DebugHash', base64_encode($this->_headerHash));
631
        }
632
633
        $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
        return $this;
636
    }
637
638
    /**
639
     * @param string $header
640
     * @param bool   $is_sig
641
     */
642 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
        switch ($this->_headerCanon) {
645
            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
                $exploded = explode(':', $header, 2);
648
                $name = Swift::strtolowerWithStaticCache(trim($exploded[0]));
649
                $value = str_replace("\r\n", '', $exploded[1]);
650
                $value = preg_replace("/[ \t][ \t]+/", ' ', $value);
651
                $header = $name . ':' . trim($value) . ($is_sig ? '' : "\r\n");
652
            case 'simple':
653
                // Nothing to do
654
        }
655
        $this->_addToHeaderHash($header);
656
    }
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
    protected function _canonicalizeBody($string)
671
    {
672
        $len = strlen($string);
673
        $canon = '';
674
        $method = ($this->_bodyCanon === 'relaxed');
675
        for ($i = 0; $i < $len; ++$i) {
676
            if ($this->_bodyCanonIgnoreStart > 0) {
677
                --$this->_bodyCanonIgnoreStart;
678
                continue;
679
            }
680
            switch ($string[$i]) {
681
                case "\r":
682
                    $this->_bodyCanonLastChar = "\r";
683
                    break;
684 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
                case ' ':
703
                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
                    if ($method) {
705
                        $this->_bodyCanonSpace = true;
706
                        break;
707
                    }
708
                default:
709 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
                    if ($this->_bodyCanonSpace) {
714
                        $this->_bodyCanonLine .= ' ';
715
                        $canon .= ' ';
716
                        $this->_bodyCanonSpace = false;
717
                    }
718
                    $this->_bodyCanonLine .= $string[$i];
719
                    $canon .= $string[$i];
720
            }
721
        }
722
        $this->_addToBodyHash($canon);
723
    }
724
725
    protected function _endOfBody()
726
    {
727
        // Add trailing Line return if last line is non empty
728
        if ($this->_bodyCanonLine !== '') {
729
            $this->_addToBodyHash("\r\n");
730
        }
731
732
        $this->_bodyHash = hash_final($this->_bodyHashHandler, true);
733
    }
734
735
    /**
736
     * @param string $string
737
     */
738
    private function _addToBodyHash($string)
739
    {
740
        $len = strlen($string);
741
        if ($len > ($new_len = ($this->_maxLen - $this->_bodyLen))) {
742
          /** @noinspection CallableParameterUseCaseInTypeContextInspection */
743
          $string = substr($string, 0, $new_len);
744
            $len = $new_len;
745
        }
746
        hash_update($this->_bodyHashHandler, $string);
747
        $this->_bodyLen += $len;
748
    }
749
750
    /**
751
     * @param string $header
752
     */
753
    private function _addToHeaderHash($header)
754
    {
755
        if ($this->_debugHeaders) {
756
            $this->_debugHeadersData[] = trim($header);
757
        }
758
        $this->_headerCanonData .= $header;
759
    }
760
761
    /**
762
     * @throws Swift_SwiftException
763
     *
764
     * @return string
765
     */
766
    private function _getEncryptedHash()
767
    {
768
        $signature = '';
769
770
        switch ($this->_hashAlgorithm) {
771
            case 'rsa-sha1':
772
                $algorithm = OPENSSL_ALGO_SHA1;
773
                break;
774
            case 'rsa-sha256':
775
                $algorithm = OPENSSL_ALGO_SHA256;
776
                break;
777
            default:
778
                $algorithm = PHP_VERSION_ID < 50408 ? OPENSSL_ALGO_SHA1 : OPENSSL_ALGO_SHA256;
779
        }
780
781
        $pkeyId = openssl_get_privatekey($this->_privateKey, $this->_passphrase);
782
        if (!$pkeyId) {
783
            throw new Swift_SwiftException('Unable to load DKIM Private Key [' . openssl_error_string() . ']');
784
        }
785
786
        if (openssl_sign($this->_headerCanonData, $signature, $pkeyId, $algorithm)) {
787
            return $signature;
788
        }
789
790
        throw new Swift_SwiftException('Unable to sign DKIM Hash [' . openssl_error_string() . ']');
791
    }
792
}
793