Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/Authentication.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace DirectoryTree\ImapEngine;

use DirectoryTree\ImapEngine\Connection\ConnectionInterface;
use DirectoryTree\ImapEngine\Connection\Responses\TaggedResponse;
use Throwable;

class Authentication
{
/**
* Constructor.
*/
public function __construct(
protected ConnectionInterface $connection,
protected AuthenticatorInterface $authenticator,
) {}

/**
* Authenticate the connection.
*/
public function authenticate(bool $initial = false): TaggedResponse
{
$response = $this->authenticator->initial();
$sent = $initial && $response !== null;

$exchange = $this->connection->authenticate(
$this->authenticator->mechanism(),
$sent ? $response : null,
);

foreach ($exchange as $challenge) {
try {
if (! $sent && $response !== null) {
$answer = $response;
$sent = true;
} else {
$answer = $this->authenticator->respond($challenge);
}
} catch (Throwable $e) {
$this->connection->disconnect();

throw $e;
}

$this->connection->respond($answer);
}

return $exchange->getReturn();
}
}
40 changes: 40 additions & 0 deletions src/Authentication/XOAuth2.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace DirectoryTree\ImapEngine\Authentication;

use DirectoryTree\ImapEngine\AuthenticatorInterface;

class XOAuth2 implements AuthenticatorInterface
{
/**
* Constructor.
*/
public function __construct(
protected string $user,
protected string $token,
) {}

/**
* {@inheritDoc}
*/
public function mechanism(): string
{
return 'XOAUTH2';
}

/**
* {@inheritDoc}
*/
public function initial(): string
{
return "user=$this->user\1auth=Bearer $this->token\1\1";
}

/**
* {@inheritDoc}
*/
public function respond(string $challenge): string
{
return '';
}
}
21 changes: 21 additions & 0 deletions src/AuthenticatorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace DirectoryTree\ImapEngine;

interface AuthenticatorInterface
{
/**
* Get the SASL mechanism name.
*/
public function mechanism(): string;

/**
* Get the unencoded initial data, or null to await a challenge.
*/
public function initial(): ?string;

/**
* Respond to a decoded challenge. Return null to cancel authentication.
*/
public function respond(string $challenge): ?string;
}
77 changes: 77 additions & 0 deletions src/Capabilities.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

namespace DirectoryTree\ImapEngine;

class Capabilities
{
/**
* The capabilities.
*
* @var array<string, Capability>
*/
protected array $items = [];

/**
* Create a capability collection from the given values.
*/
public static function from(iterable $capabilities): static
{
$instance = new static;

foreach ($capabilities as $capability) {
$item = new Capability($capability);

$instance->items[$item->name()] = $item;
}

return $instance;
}

/**
* Get all supported capabilities.
*/
public function all(): array
{
return array_keys($this->items);
}

/**
* Determine if the capability is supported.
*/
public function supports(string $capability): bool
{
return (bool) $this->find($capability);
}

/**
* Determine if the capability is enabled.
*/
public function enabled(string $capability): bool
{
return ($this->items[strtoupper($capability)] ?? null)?->enabled() ?? false;
}

/**
* Mark the given capabilities as enabled.
*/
public function enable(string ...$capabilities): void
{
foreach ($capabilities as $capability) {
($this->items[strtoupper($capability)] ?? null)?->enable();
}
}

/**
* Find a supported capability.
*/
protected function find(string $capability): ?Capability
{
foreach ($this->items as $item) {
if ($item->matches($capability)) {
return $item;
}
}

return null;
}
}
53 changes: 53 additions & 0 deletions src/Capability.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace DirectoryTree\ImapEngine;

class Capability
{
/**
* Constructor.
*/
public function __construct(
protected string $name,
protected bool $enabled = false,
) {
$this->name = strtoupper($name);
}

/**
* Get the capability name.
*/
public function name(): string
{
return $this->name;
}

/**
* Determine if the capability matches the given name.
*/
public function matches(string $capability): bool
{
$capability = strtoupper($capability);

return $this->name === $capability
|| str_starts_with($this->name, "{$capability}=");
}

/**
* Determine if the capability is enabled.
*/
public function enabled(): bool
{
return $this->enabled;
}

/**
* Enable the capability.
*/
public function enable(): static
{
$this->enabled = true;

return $this;
}
}
Loading