Completed
Pull Request — master (#42)
by Frederik
04:15 queued 01:07
created

AuthNegotiation::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 3
crap 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Genkgo\Mail\Protocol\Imap\Negotiation;
5
6
use Genkgo\Mail\Exception\ImapAuthenticationException;
7
use Genkgo\Mail\Protocol\Imap\Client;
8
use Genkgo\Mail\Protocol\Imap\NegotiationInterface;
9
use Genkgo\Mail\Protocol\Imap\Request\AuthPlainCommand;
10
use Genkgo\Mail\Protocol\Imap\Request\AuthPlainCredentialsRequest;
11
use Genkgo\Mail\Protocol\Imap\Request\CapabilityCommand;
12
use Genkgo\Mail\Protocol\Imap\Request\LoginCommand;
13
use Genkgo\Mail\Protocol\Imap\Response\Command\CapabilityCommandResponse;
14
use Genkgo\Mail\Protocol\Imap\Response\CompletionResult;
15
16
final class AuthNegotiation implements NegotiationInterface
17
{
18
    /**
19
     * @var int
20
     */
21
    private $method;
22
    /**
23
     * @var string
24
     */
25
    private $username;
26
    /**
27
     * @var string
28
     */
29
    private $password;
30
31
    /**
32
     * AuthNegotiation constructor.
33
     * @param int $method
34
     * @param string $username
35
     * @param string $password
36
     */
37 6
    public function __construct(int $method, string $username, string $password)
38
    {
39 6
        $this->method = $method;
40 6
        $this->username = $username;
41 6
        $this->password = $password;
42 6
    }
43
44
    /**
45
     * @param Client $client
46
     * @throws ImapAuthenticationException
47
     */
48 5
    public function negotiate(Client $client): void
49
    {
50 5
        $method = $this->method;
51 5
        if ($method === Client::AUTH_AUTO) {
52 4
            $responseList = $client->emit(new CapabilityCommand($client->newTag()));
53
54 4
            $capabilities = CapabilityCommandResponse::fromString($responseList->first()->getBody());
55
56
            $responseList
57 4
                ->last()
58 4
                ->assertCompletion(CompletionResult::ok())
59 4
                ->assertTagged();
60
61
            $options = [
62 4
                'AUTH=PLAIN' => Client::AUTH_PLAIN,
63
            ];
64
65 4
            foreach ($options as $capability => $auth) {
66 4
                if ($capabilities->isAdvertising($capability)) {
67 4
                    $method = $auth;
68
                }
69
            }
70
71 4
            if ($method === Client::AUTH_AUTO && !$capabilities->isAdvertising('LOGINDISABLED')) {
72 1
                $method = Client::AUTH_LOGIN;
73
            }
74
75 4
            if ($method === Client::AUTH_AUTO) {
76 1
                throw new ImapAuthenticationException(
77 1
                    'IMAP server does not advertise one the supported AUTH methods (AUTH PLAIN)'
78
                );
79
            }
80
        }
81
82
        switch ($method) {
83 4
            case Client::AUTH_PLAIN:
84 3
                $tag = $client->newTag();
85
                $client
86 3
                    ->emit(new AuthPlainCommand($tag))
87 3
                    ->first()
88 3
                    ->assertContinuation();
89
90
                $client
91 3
                    ->emit(
92 3
                        new AuthPlainCredentialsRequest(
93 3
                            $tag,
94 3
                            $this->username,
95 3
                            $this->password
96
                        )
97
                    )
98 3
                    ->last()
99 3
                    ->assertCompletion(CompletionResult::ok())
100 3
                    ->assertTagged();
101 3
                break;
102 1
            case Client::AUTH_LOGIN:
103 1
                $tag = $client->newTag();
104
                $client
105 1
                    ->emit(new LoginCommand($tag, $this->username, $this->password))
106 1
                    ->last()
107 1
                    ->assertTagged()
108 1
                    ->assertCompletion(CompletionResult::ok());
109 1
                break;
110
        }
111
    }
112
}