Completed
Push — master ( bd2b4b...e19a0a )
by Frederik
03:38 queued 01:06
created

TryTlsUpgradeNegotiation   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 77
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 7
lcom 1
cbo 7
dl 0
loc 77
c 0
b 0
f 0
ccs 24
cts 24
cp 1
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
B negotiate() 0 40 6
1
<?php
2
declare(strict_types=1);
3
4
namespace Genkgo\Mail\Protocol\Smtp\Negotiation;
5
6
use Genkgo\Mail\Exception\AssertionFailedException;
7
use Genkgo\Mail\Exception\ConnectionInsecureException;
8
use Genkgo\Mail\Exception\SecureConnectionUpgradeException;
9
use Genkgo\Mail\Protocol\ConnectionInterface;
10
use Genkgo\Mail\Protocol\Smtp\Client;
11
use Genkgo\Mail\Protocol\Smtp\NegotiationInterface;
12
use Genkgo\Mail\Protocol\Smtp\Request\EhloCommand;
13
use Genkgo\Mail\Protocol\Smtp\Request\HeloCommand;
14
use Genkgo\Mail\Protocol\Smtp\Request\StartTlsCommand;
15
use Genkgo\Mail\Protocol\Smtp\Response\EhloResponse;
16
17
final class TryTlsUpgradeNegotiation implements NegotiationInterface
18
{
19
    /**
20
     * @var ConnectionInterface
21
     */
22
    private $connection;
23
24
    /**
25
     * @var string
26
     */
27
    private $ehlo;
28
29
    /**
30
     * @var int
31
     */
32
    private $crypto;
33
34
    /**
35
     * @param ConnectionInterface $connection
36
     * @param string $ehlo
37
     * @param int $crypto
38
     */
39 6
    public function __construct(
40
        ConnectionInterface $connection,
41
        string $ehlo,
42
        int $crypto
43
    ) {
44 6
        $this->connection = $connection;
45 6
        $this->ehlo = $ehlo;
46 6
        $this->crypto = $crypto;
47 6
    }
48
49
    /**
50
     * @param Client $client
51
     * @throws ConnectionInsecureException
52
     */
53 5
    public function negotiate(Client $client): void
54
    {
55 5
        if (!empty($this->connection->getMetaData(['crypto']))) {
56 1
            return;
57
        }
58
59 4
        $reply = $client->request(new EhloCommand($this->ehlo));
60
61 4
        if ($reply->isCommandNotImplemented()) {
62
            // since EHLO is not implemented, let's try HELO and then STARTTLS
63 2
            $reply = $client->request(new HeloCommand($this->ehlo));
64 2
            $reply->assertCompleted();
65
66
            try {
67
                $client
68 2
                    ->request(new StartTlsCommand())
69 2
                    ->assertCompleted();
70
71 1
                $this->connection->upgrade($this->crypto);
72 1
            } catch (AssertionFailedException $e) {
73
                // apparently HELO OR STARTTLS command is also not implemented
74
                // but failure of STARTTLS is allowed
75 2
            } catch (SecureConnectionUpgradeException $e) {
76
                // apparently STARTTLS command is implemented
77
                // but failed to start a secure connection
78
            }
79
        } else {
80 2
            $reply->assertCompleted();
81
82 2
            $ehloResponse = new EhloResponse($reply);
83
84 2
            if ($ehloResponse->isAdvertising('STARTTLS')) {
85
                $client
86 1
                    ->request(new StartTlsCommand())
87 1
                    ->assertCompleted();
88
89 1
                $this->connection->upgrade($this->crypto);
90
            }
91
        }
92 4
    }
93
}
94