1
0

first commit

This commit is contained in:
Daniel Tartavel
2021-10-14 17:58:21 +02:00
parent e5fe464cbc
commit df07673a67
327 changed files with 44407 additions and 0 deletions

View File

@ -0,0 +1,75 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles CRAM-MD5 authentication.
*
* @author Chris Corbyn
*/
class Swift_Transport_Esmtp_Auth_CramMd5Authenticator implements Swift_Transport_Esmtp_Authenticator
{
/**
* Get the name of the AUTH mechanism this Authenticator handles.
*
* @return string
*/
public function getAuthKeyword()
{
return 'CRAM-MD5';
}
/**
* {@inheritdoc}
*/
public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password)
{
try {
$challenge = $agent->executeCommand("AUTH CRAM-MD5\r\n", [334]);
$challenge = base64_decode(substr($challenge, 4));
$message = base64_encode(
$username.' '.$this->getResponse($password, $challenge)
);
$agent->executeCommand(sprintf("%s\r\n", $message), [235]);
return true;
} catch (Swift_TransportException $e) {
$agent->executeCommand("RSET\r\n", [250]);
throw $e;
}
}
/**
* Generate a CRAM-MD5 response from a server challenge.
*
* @param string $secret
* @param string $challenge
*
* @return string
*/
private function getResponse($secret, $challenge)
{
if (\strlen($secret) > 64) {
$secret = pack('H32', md5($secret));
}
if (\strlen($secret) < 64) {
$secret = str_pad($secret, 64, \chr(0));
}
$k_ipad = substr($secret, 0, 64) ^ str_repeat(\chr(0x36), 64);
$k_opad = substr($secret, 0, 64) ^ str_repeat(\chr(0x5C), 64);
$inner = pack('H32', md5($k_ipad.$challenge));
$digest = md5($k_opad.$inner);
return $digest;
}
}

View File

@ -0,0 +1,45 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles LOGIN authentication.
*
* @author Chris Corbyn
*/
class Swift_Transport_Esmtp_Auth_LoginAuthenticator implements Swift_Transport_Esmtp_Authenticator
{
/**
* Get the name of the AUTH mechanism this Authenticator handles.
*
* @return string
*/
public function getAuthKeyword()
{
return 'LOGIN';
}
/**
* {@inheritdoc}
*/
public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password)
{
try {
$agent->executeCommand("AUTH LOGIN\r\n", [334]);
$agent->executeCommand(sprintf("%s\r\n", base64_encode($username)), [334]);
$agent->executeCommand(sprintf("%s\r\n", base64_encode($password)), [235]);
return true;
} catch (Swift_TransportException $e) {
$agent->executeCommand("RSET\r\n", [250]);
throw $e;
}
}
}

View File

@ -0,0 +1,681 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* This authentication is for Exchange servers. We support version 1 & 2.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles NTLM authentication.
*
* @author Ward Peeters <ward@coding-tech.com>
*/
class Swift_Transport_Esmtp_Auth_NTLMAuthenticator implements Swift_Transport_Esmtp_Authenticator
{
const NTLMSIG = "NTLMSSP\x00";
const DESCONST = 'KGS!@#$%';
/**
* Get the name of the AUTH mechanism this Authenticator handles.
*
* @return string
*/
public function getAuthKeyword()
{
return 'NTLM';
}
/**
* {@inheritdoc}
*
* @throws \LogicException
*/
public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password)
{
if (!\function_exists('openssl_encrypt')) {
throw new LogicException('The OpenSSL extension must be enabled to use the NTLM authenticator.');
}
if (!\function_exists('bcmul')) {
throw new LogicException('The BCMath functions must be enabled to use the NTLM authenticator.');
}
try {
// execute AUTH command and filter out the code at the beginning
// AUTH NTLM xxxx
$response = base64_decode(substr(trim($this->sendMessage1($agent)), 4));
// extra parameters for our unit cases
$timestamp = \func_num_args() > 3 ? func_get_arg(3) : $this->getCorrectTimestamp(bcmul(microtime(true), '1000'));
$client = \func_num_args() > 4 ? func_get_arg(4) : random_bytes(8);
// Message 3 response
$this->sendMessage3($response, $username, $password, $timestamp, $client, $agent);
return true;
} catch (Swift_TransportException $e) {
$agent->executeCommand("RSET\r\n", [250]);
throw $e;
}
}
protected function si2bin($si, $bits = 32)
{
$bin = null;
if ($si >= -2 ** ($bits - 1) && ($si <= 2 ** ($bits - 1))) {
// positive or zero
if ($si >= 0) {
$bin = base_convert($si, 10, 2);
// pad to $bits bit
$bin_length = \strlen($bin);
if ($bin_length < $bits) {
$bin = str_repeat('0', $bits - $bin_length).$bin;
}
} else {
// negative
$si = -$si - 2 ** $bits;
$bin = base_convert($si, 10, 2);
$bin_length = \strlen($bin);
if ($bin_length > $bits) {
$bin = str_repeat('1', $bits - $bin_length).$bin;
}
}
}
return $bin;
}
/**
* Send our auth message and returns the response.
*
* @return string SMTP Response
*/
protected function sendMessage1(Swift_Transport_SmtpAgent $agent)
{
$message = $this->createMessage1();
return $agent->executeCommand(sprintf("AUTH %s %s\r\n", $this->getAuthKeyword(), base64_encode($message)), [334]);
}
/**
* Fetch all details of our response (message 2).
*
* @param string $response
*
* @return array our response parsed
*/
protected function parseMessage2($response)
{
$responseHex = bin2hex($response);
$length = floor(hexdec(substr($responseHex, 28, 4)) / 256) * 2;
$offset = floor(hexdec(substr($responseHex, 32, 4)) / 256) * 2;
$challenge = hex2bin(substr($responseHex, 48, 16));
$context = hex2bin(substr($responseHex, 64, 16));
$targetInfoH = hex2bin(substr($responseHex, 80, 16));
$targetName = hex2bin(substr($responseHex, $offset, $length));
$offset = floor(hexdec(substr($responseHex, 88, 4)) / 256) * 2;
$targetInfoBlock = substr($responseHex, $offset);
list($domainName, $serverName, $DNSDomainName, $DNSServerName, $terminatorByte) = $this->readSubBlock($targetInfoBlock);
return [
$challenge,
$context,
$targetInfoH,
$targetName,
$domainName,
$serverName,
$DNSDomainName,
$DNSServerName,
hex2bin($targetInfoBlock),
$terminatorByte,
];
}
/**
* Read the blob information in from message2.
*
* @return array
*/
protected function readSubBlock($block)
{
// remove terminatorByte cause it's always the same
$block = substr($block, 0, -8);
$length = \strlen($block);
$offset = 0;
$data = [];
while ($offset < $length) {
$blockLength = hexdec(substr(substr($block, $offset, 8), -4)) / 256;
$offset += 8;
$data[] = hex2bin(substr($block, $offset, $blockLength * 2));
$offset += $blockLength * 2;
}
if (3 == \count($data)) {
$data[] = $data[2];
$data[2] = '';
}
$data[] = $this->createByte('00');
return $data;
}
/**
* Send our final message with all our data.
*
* @param string $response Message 1 response (message 2)
* @param string $username
* @param string $password
* @param string $timestamp
* @param string $client
* @param bool $v2 Use version2 of the protocol
*
* @return string
*/
protected function sendMessage3($response, $username, $password, $timestamp, $client, Swift_Transport_SmtpAgent $agent, $v2 = true)
{
list($domain, $username) = $this->getDomainAndUsername($username);
//$challenge, $context, $targetInfoH, $targetName, $domainName, $workstation, $DNSDomainName, $DNSServerName, $blob, $ter
list($challenge, , , , , $workstation, , , $blob) = $this->parseMessage2($response);
if (!$v2) {
// LMv1
$lmResponse = $this->createLMPassword($password, $challenge);
// NTLMv1
$ntlmResponse = $this->createNTLMPassword($password, $challenge);
} else {
// LMv2
$lmResponse = $this->createLMv2Password($password, $username, $domain, $challenge, $client);
// NTLMv2
$ntlmResponse = $this->createNTLMv2Hash($password, $username, $domain, $challenge, $blob, $timestamp, $client);
}
$message = $this->createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse);
return $agent->executeCommand(sprintf("%s\r\n", base64_encode($message)), [235]);
}
/**
* Create our message 1.
*
* @return string
*/
protected function createMessage1()
{
return self::NTLMSIG
.$this->createByte('01') // Message 1
.$this->createByte('0702'); // Flags
}
/**
* Create our message 3.
*
* @param string $domain
* @param string $username
* @param string $workstation
* @param string $lmResponse
* @param string $ntlmResponse
*
* @return string
*/
protected function createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse)
{
// Create security buffers
$domainSec = $this->createSecurityBuffer($domain, 64);
$domainInfo = $this->readSecurityBuffer(bin2hex($domainSec));
$userSec = $this->createSecurityBuffer($username, ($domainInfo[0] + $domainInfo[1]) / 2);
$userInfo = $this->readSecurityBuffer(bin2hex($userSec));
$workSec = $this->createSecurityBuffer($workstation, ($userInfo[0] + $userInfo[1]) / 2);
$workInfo = $this->readSecurityBuffer(bin2hex($workSec));
$lmSec = $this->createSecurityBuffer($lmResponse, ($workInfo[0] + $workInfo[1]) / 2, true);
$lmInfo = $this->readSecurityBuffer(bin2hex($lmSec));
$ntlmSec = $this->createSecurityBuffer($ntlmResponse, ($lmInfo[0] + $lmInfo[1]) / 2, true);
return self::NTLMSIG
.$this->createByte('03') // TYPE 3 message
.$lmSec // LM response header
.$ntlmSec // NTLM response header
.$domainSec // Domain header
.$userSec // User header
.$workSec // Workstation header
.$this->createByte('000000009a', 8) // session key header (empty)
.$this->createByte('01020000') // FLAGS
.$this->convertTo16bit($domain) // domain name
.$this->convertTo16bit($username) // username
.$this->convertTo16bit($workstation) // workstation
.$lmResponse
.$ntlmResponse;
}
/**
* @param string $timestamp Epoch timestamp in microseconds
* @param string $client Random bytes
* @param string $targetInfo
*
* @return string
*/
protected function createBlob($timestamp, $client, $targetInfo)
{
return $this->createByte('0101')
.$this->createByte('00')
.$timestamp
.$client
.$this->createByte('00')
.$targetInfo
.$this->createByte('00');
}
/**
* Get domain and username from our username.
*
* @example DOMAIN\username
*
* @param string $name
*
* @return array
*/
protected function getDomainAndUsername($name)
{
if (false !== strpos($name, '\\')) {
return explode('\\', $name);
}
if (false !== strpos($name, '@')) {
list($user, $domain) = explode('@', $name);
return [$domain, $user];
}
// no domain passed
return ['', $name];
}
/**
* Create LMv1 response.
*
* @param string $password
* @param string $challenge
*
* @return string
*/
protected function createLMPassword($password, $challenge)
{
// FIRST PART
$password = $this->createByte(strtoupper($password), 14, false);
list($key1, $key2) = str_split($password, 7);
$desKey1 = $this->createDesKey($key1);
$desKey2 = $this->createDesKey($key2);
$constantDecrypt = $this->createByte($this->desEncrypt(self::DESCONST, $desKey1).$this->desEncrypt(self::DESCONST, $desKey2), 21, false);
// SECOND PART
list($key1, $key2, $key3) = str_split($constantDecrypt, 7);
$desKey1 = $this->createDesKey($key1);
$desKey2 = $this->createDesKey($key2);
$desKey3 = $this->createDesKey($key3);
return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3);
}
/**
* Create NTLMv1 response.
*
* @param string $password
* @param string $challenge
*
* @return string
*/
protected function createNTLMPassword($password, $challenge)
{
// FIRST PART
$ntlmHash = $this->createByte($this->md4Encrypt($password), 21, false);
list($key1, $key2, $key3) = str_split($ntlmHash, 7);
$desKey1 = $this->createDesKey($key1);
$desKey2 = $this->createDesKey($key2);
$desKey3 = $this->createDesKey($key3);
return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3);
}
/**
* Convert a normal timestamp to a tenth of a microtime epoch time.
*
* @param string $time
*
* @return string
*/
protected function getCorrectTimestamp($time)
{
// Get our timestamp (tricky!)
$time = number_format($time, 0, '.', ''); // save microtime to string
$time = bcadd($time, '11644473600000', 0); // add epoch time
$time = bcmul($time, 10000, 0); // tenths of a microsecond.
$binary = $this->si2bin($time, 64); // create 64 bit binary string
$timestamp = '';
for ($i = 0; $i < 8; ++$i) {
$timestamp .= \chr(bindec(substr($binary, -(($i + 1) * 8), 8)));
}
return $timestamp;
}
/**
* Create LMv2 response.
*
* @param string $password
* @param string $username
* @param string $domain
* @param string $challenge NTLM Challenge
* @param string $client Random string
*
* @return string
*/
protected function createLMv2Password($password, $username, $domain, $challenge, $client)
{
$lmPass = '00'; // by default 00
// if $password > 15 than we can't use this method
if (\strlen($password) <= 15) {
$ntlmHash = $this->md4Encrypt($password);
$ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain));
$lmPass = bin2hex($this->md5Encrypt($ntml2Hash, $challenge.$client).$client);
}
return $this->createByte($lmPass, 24);
}
/**
* Create NTLMv2 response.
*
* @param string $password
* @param string $username
* @param string $domain
* @param string $challenge Hex values
* @param string $targetInfo Hex values
* @param string $timestamp
* @param string $client Random bytes
*
* @return string
*
* @see http://davenport.sourceforge.net/ntlm.html#theNtlmResponse
*/
protected function createNTLMv2Hash($password, $username, $domain, $challenge, $targetInfo, $timestamp, $client)
{
$ntlmHash = $this->md4Encrypt($password);
$ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain));
// create blob
$blob = $this->createBlob($timestamp, $client, $targetInfo);
$ntlmv2Response = $this->md5Encrypt($ntml2Hash, $challenge.$blob);
return $ntlmv2Response.$blob;
}
protected function createDesKey($key)
{
$material = [bin2hex($key[0])];
$len = \strlen($key);
for ($i = 1; $i < $len; ++$i) {
list($high, $low) = str_split(bin2hex($key[$i]));
$v = $this->castToByte(\ord($key[$i - 1]) << (7 + 1 - $i) | $this->uRShift(hexdec(dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xf)), $i));
$material[] = str_pad(substr(dechex($v), -2), 2, '0', STR_PAD_LEFT); // cast to byte
}
$material[] = str_pad(substr(dechex($this->castToByte(\ord($key[6]) << 1)), -2), 2, '0');
// odd parity
foreach ($material as $k => $v) {
$b = $this->castToByte(hexdec($v));
$needsParity = 0 == (($this->uRShift($b, 7) ^ $this->uRShift($b, 6) ^ $this->uRShift($b, 5)
^ $this->uRShift($b, 4) ^ $this->uRShift($b, 3) ^ $this->uRShift($b, 2)
^ $this->uRShift($b, 1)) & 0x01);
list($high, $low) = str_split($v);
if ($needsParity) {
$material[$k] = dechex(hexdec($high) | 0x0).dechex(hexdec($low) | 0x1);
} else {
$material[$k] = dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xe);
}
}
return hex2bin(implode('', $material));
}
/** HELPER FUNCTIONS */
/**
* Create our security buffer depending on length and offset.
*
* @param string $value Value we want to put in
* @param int $offset start of value
* @param bool $is16 Do we 16bit string or not?
*
* @return string
*/
protected function createSecurityBuffer($value, $offset, $is16 = false)
{
$length = \strlen(bin2hex($value));
$length = $is16 ? $length / 2 : $length;
$length = $this->createByte(str_pad(dechex($length), 2, '0', STR_PAD_LEFT), 2);
return $length.$length.$this->createByte(dechex($offset), 4);
}
/**
* Read our security buffer to fetch length and offset of our value.
*
* @param string $value Securitybuffer in hex
*
* @return array array with length and offset
*/
protected function readSecurityBuffer($value)
{
$length = floor(hexdec(substr($value, 0, 4)) / 256) * 2;
$offset = floor(hexdec(substr($value, 8, 4)) / 256) * 2;
return [$length, $offset];
}
/**
* Cast to byte java equivalent to (byte).
*
* @param int $v
*
* @return int
*/
protected function castToByte($v)
{
return (($v + 128) % 256) - 128;
}
/**
* Java unsigned right bitwise
* $a >>> $b.
*
* @param int $a
* @param int $b
*
* @return int
*/
protected function uRShift($a, $b)
{
if (0 == $b) {
return $a;
}
return ($a >> $b) & ~(1 << (8 * PHP_INT_SIZE - 1) >> ($b - 1));
}
/**
* Right padding with 0 to certain length.
*
* @param string $input
* @param int $bytes Length of bytes
* @param bool $isHex Did we provided hex value
*
* @return string
*/
protected function createByte($input, $bytes = 4, $isHex = true)
{
if ($isHex) {
$byte = hex2bin(str_pad($input, $bytes * 2, '00'));
} else {
$byte = str_pad($input, $bytes, "\x00");
}
return $byte;
}
/** ENCRYPTION ALGORITHMS */
/**
* DES Encryption.
*
* @param string $value An 8-byte string
* @param string $key
*
* @return string
*/
protected function desEncrypt($value, $key)
{
return substr(openssl_encrypt($value, 'DES-ECB', $key, \OPENSSL_RAW_DATA), 0, 8);
}
/**
* MD5 Encryption.
*
* @param string $key Encryption key
* @param string $msg Message to encrypt
*
* @return string
*/
protected function md5Encrypt($key, $msg)
{
$blocksize = 64;
if (\strlen($key) > $blocksize) {
$key = pack('H*', md5($key));
}
$key = str_pad($key, $blocksize, "\0");
$ipadk = $key ^ str_repeat("\x36", $blocksize);
$opadk = $key ^ str_repeat("\x5c", $blocksize);
return pack('H*', md5($opadk.pack('H*', md5($ipadk.$msg))));
}
/**
* MD4 Encryption.
*
* @param string $input
*
* @return string
*
* @see https://secure.php.net/manual/en/ref.hash.php
*/
protected function md4Encrypt($input)
{
$input = $this->convertTo16bit($input);
return \function_exists('hash') ? hex2bin(hash('md4', $input)) : mhash(MHASH_MD4, $input);
}
/**
* Convert UTF-8 to UTF-16.
*
* @param string $input
*
* @return string
*/
protected function convertTo16bit($input)
{
return iconv('UTF-8', 'UTF-16LE', $input);
}
/**
* @param string $message
*/
protected function debug($message)
{
$message = bin2hex($message);
$messageId = substr($message, 16, 8);
echo substr($message, 0, 16)." NTLMSSP Signature<br />\n";
echo $messageId." Type Indicator<br />\n";
if ('02000000' == $messageId) {
$map = [
'Challenge',
'Context',
'Target Information Security Buffer',
'Target Name Data',
'NetBIOS Domain Name',
'NetBIOS Server Name',
'DNS Domain Name',
'DNS Server Name',
'BLOB',
'Target Information Terminator',
];
$data = $this->parseMessage2(hex2bin($message));
foreach ($map as $key => $value) {
echo bin2hex($data[$key]).' - '.$data[$key].' ||| '.$value."<br />\n";
}
} elseif ('03000000' == $messageId) {
$i = 0;
$data[$i++] = substr($message, 24, 16);
list($lmLength, $lmOffset) = $this->readSecurityBuffer($data[$i - 1]);
$data[$i++] = substr($message, 40, 16);
list($ntmlLength, $ntmlOffset) = $this->readSecurityBuffer($data[$i - 1]);
$data[$i++] = substr($message, 56, 16);
list($targetLength, $targetOffset) = $this->readSecurityBuffer($data[$i - 1]);
$data[$i++] = substr($message, 72, 16);
list($userLength, $userOffset) = $this->readSecurityBuffer($data[$i - 1]);
$data[$i++] = substr($message, 88, 16);
list($workLength, $workOffset) = $this->readSecurityBuffer($data[$i - 1]);
$data[$i++] = substr($message, 104, 16);
$data[$i++] = substr($message, 120, 8);
$data[$i++] = substr($message, $targetOffset, $targetLength);
$data[$i++] = substr($message, $userOffset, $userLength);
$data[$i++] = substr($message, $workOffset, $workLength);
$data[$i++] = substr($message, $lmOffset, $lmLength);
$data[$i] = substr($message, $ntmlOffset, $ntmlLength);
$map = [
'LM Response Security Buffer',
'NTLM Response Security Buffer',
'Target Name Security Buffer',
'User Name Security Buffer',
'Workstation Name Security Buffer',
'Session Key Security Buffer',
'Flags',
'Target Name Data',
'User Name Data',
'Workstation Name Data',
'LM Response Data',
'NTLM Response Data',
];
foreach ($map as $key => $value) {
echo $data[$key].' - '.hex2bin($data[$key]).' ||| '.$value."<br />\n";
}
}
echo '<br /><br />';
}
}

View File

@ -0,0 +1,44 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles PLAIN authentication.
*
* @author Chris Corbyn
*/
class Swift_Transport_Esmtp_Auth_PlainAuthenticator implements Swift_Transport_Esmtp_Authenticator
{
/**
* Get the name of the AUTH mechanism this Authenticator handles.
*
* @return string
*/
public function getAuthKeyword()
{
return 'PLAIN';
}
/**
* {@inheritdoc}
*/
public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password)
{
try {
$message = base64_encode($username.\chr(0).$username.\chr(0).$password);
$agent->executeCommand(sprintf("AUTH PLAIN %s\r\n", $message), [235]);
return true;
} catch (Swift_TransportException $e) {
$agent->executeCommand("RSET\r\n", [250]);
throw $e;
}
}
}

View File

@ -0,0 +1,64 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles XOAUTH2 authentication.
*
* Example:
* <code>
* $transport = (new Swift_SmtpTransport('smtp.gmail.com', 587, 'tls'))
* ->setAuthMode('XOAUTH2')
* ->setUsername('YOUR_EMAIL_ADDRESS')
* ->setPassword('YOUR_ACCESS_TOKEN');
* </code>
*
* @author xu.li<AthenaLightenedMyPath@gmail.com>
*
* @see https://developers.google.com/google-apps/gmail/xoauth2_protocol
*/
class Swift_Transport_Esmtp_Auth_XOAuth2Authenticator implements Swift_Transport_Esmtp_Authenticator
{
/**
* Get the name of the AUTH mechanism this Authenticator handles.
*
* @return string
*/
public function getAuthKeyword()
{
return 'XOAUTH2';
}
/**
* {@inheritdoc}
*/
public function authenticate(Swift_Transport_SmtpAgent $agent, $email, $token)
{
try {
$param = $this->constructXOAuth2Params($email, $token);
$agent->executeCommand('AUTH XOAUTH2 '.$param."\r\n", [235]);
return true;
} catch (Swift_TransportException $e) {
$agent->executeCommand("RSET\r\n", [250]);
throw $e;
}
}
/**
* Construct the auth parameter.
*
* @see https://developers.google.com/google-apps/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism
*/
protected function constructXOAuth2Params($email, $token)
{
return base64_encode("user=$email\1auth=Bearer $token\1\1");
}
}

View File

@ -0,0 +1,268 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An ESMTP handler for AUTH support (RFC 5248).
*
* @author Chris Corbyn
*/
class Swift_Transport_Esmtp_AuthHandler implements Swift_Transport_EsmtpHandler
{
/**
* Authenticators available to process the request.
*
* @var Swift_Transport_Esmtp_Authenticator[]
*/
private $authenticators = [];
/**
* The username for authentication.
*
* @var string
*/
private $username;
/**
* The password for authentication.
*
* @var string
*/
private $password;
/**
* The auth mode for authentication.
*
* @var string
*/
private $auth_mode;
/**
* The ESMTP AUTH parameters available.
*
* @var string[]
*/
private $esmtpParams = [];
/**
* Create a new AuthHandler with $authenticators for support.
*
* @param Swift_Transport_Esmtp_Authenticator[] $authenticators
*/
public function __construct(array $authenticators)
{
$this->setAuthenticators($authenticators);
}
/**
* Set the Authenticators which can process a login request.
*
* @param Swift_Transport_Esmtp_Authenticator[] $authenticators
*/
public function setAuthenticators(array $authenticators)
{
$this->authenticators = $authenticators;
}
/**
* Get the Authenticators which can process a login request.
*
* @return Swift_Transport_Esmtp_Authenticator[]
*/
public function getAuthenticators()
{
return $this->authenticators;
}
/**
* Set the username to authenticate with.
*
* @param string $username
*/
public function setUsername($username)
{
$this->username = $username;
}
/**
* Get the username to authenticate with.
*
* @return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Set the password to authenticate with.
*
* @param string $password
*/
public function setPassword($password)
{
$this->password = $password;
}
/**
* Get the password to authenticate with.
*
* @return string
*/
public function getPassword()
{
return $this->password;
}
/**
* Set the auth mode to use to authenticate.
*
* @param string $mode
*/
public function setAuthMode($mode)
{
$this->auth_mode = $mode;
}
/**
* Get the auth mode to use to authenticate.
*
* @return string
*/
public function getAuthMode()
{
return $this->auth_mode;
}
/**
* Get the name of the ESMTP extension this handles.
*
* @return string
*/
public function getHandledKeyword()
{
return 'AUTH';
}
/**
* Set the parameters which the EHLO greeting indicated.
*
* @param string[] $parameters
*/
public function setKeywordParams(array $parameters)
{
$this->esmtpParams = $parameters;
}
/**
* Runs immediately after a EHLO has been issued.
*
* @param Swift_Transport_SmtpAgent $agent to read/write
*/
public function afterEhlo(Swift_Transport_SmtpAgent $agent)
{
if ($this->username) {
$count = 0;
$errors = [];
foreach ($this->getAuthenticatorsForAgent() as $authenticator) {
if (\in_array(strtolower($authenticator->getAuthKeyword()), array_map('strtolower', $this->esmtpParams))) {
++$count;
try {
if ($authenticator->authenticate($agent, $this->username, $this->password)) {
return;
}
} catch (Swift_TransportException $e) {
// keep the error message, but tries the other authenticators
$errors[] = [$authenticator->getAuthKeyword(), $e->getMessage()];
}
}
}
$message = 'Failed to authenticate on SMTP server with username "'.$this->username.'" using '.$count.' possible authenticators.';
foreach ($errors as $error) {
$message .= ' Authenticator '.$error[0].' returned '.$error[1].'.';
}
throw new Swift_TransportException($message);
}
}
/**
* Not used.
*/
public function getMailParams()
{
return [];
}
/**
* Not used.
*/
public function getRcptParams()
{
return [];
}
/**
* Not used.
*/
public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false)
{
}
/**
* Returns +1, -1 or 0 according to the rules for usort().
*
* This method is called to ensure extensions can be execute in an appropriate order.
*
* @param string $esmtpKeyword to compare with
*
* @return int
*/
public function getPriorityOver($esmtpKeyword)
{
return 0;
}
/**
* Returns an array of method names which are exposed to the Esmtp class.
*
* @return string[]
*/
public function exposeMixinMethods()
{
return ['setUsername', 'getUsername', 'setPassword', 'getPassword', 'setAuthMode', 'getAuthMode'];
}
/**
* Not used.
*/
public function resetState()
{
}
/**
* Returns the authenticator list for the given agent.
*
* @return array
*/
protected function getAuthenticatorsForAgent()
{
if (!$mode = strtolower($this->auth_mode)) {
return $this->authenticators;
}
foreach ($this->authenticators as $authenticator) {
if (strtolower($authenticator->getAuthKeyword()) == $mode) {
return [$authenticator];
}
}
throw new Swift_TransportException('Auth mode '.$mode.' is invalid');
}
}

View File

@ -0,0 +1,36 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An Authentication mechanism.
*
* @author Chris Corbyn
*/
interface Swift_Transport_Esmtp_Authenticator
{
/**
* Get the name of the AUTH mechanism this Authenticator handles.
*
* @return string
*/
public function getAuthKeyword();
/**
* Try to authenticate the user with $username and $password.
*
* @param string $username
* @param string $password
*
* @return bool true if authentication worked (returning false is deprecated, throw a Swift_TransportException instead)
*
* @throws Swift_TransportException Allows the message to bubble up when authentication was not successful
*/
public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password);
}

View File

@ -0,0 +1,113 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2018 Christian Schmidt
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An ESMTP handler for 8BITMIME support (RFC 6152).
*
* 8BITMIME is required when sending 8-bit content to over SMTP, e.g. when using
* Swift_Mime_ContentEncoder_PlainContentEncoder in "8bit" mode.
*
* 8BITMIME mode is enabled unconditionally, even when sending ASCII-only
* messages, so it should only be used with an outbound SMTP server that will
* convert the message to 7-bit MIME if the next hop does not support 8BITMIME.
*
* @author Christian Schmidt
*/
class Swift_Transport_Esmtp_EightBitMimeHandler implements Swift_Transport_EsmtpHandler
{
protected $encoding;
/**
* @param string $encoding The parameter so send with the MAIL FROM command;
* either "8BITMIME" or "7BIT"
*/
public function __construct(string $encoding = '8BITMIME')
{
$this->encoding = $encoding;
}
/**
* Get the name of the ESMTP extension this handles.
*
* @return string
*/
public function getHandledKeyword()
{
return '8BITMIME';
}
/**
* Not used.
*/
public function setKeywordParams(array $parameters)
{
}
/**
* Not used.
*/
public function afterEhlo(Swift_Transport_SmtpAgent $agent)
{
}
/**
* Get params which are appended to MAIL FROM:<>.
*
* @return string[]
*/
public function getMailParams()
{
return ['BODY='.$this->encoding];
}
/**
* Not used.
*/
public function getRcptParams()
{
return [];
}
/**
* Not used.
*/
public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false)
{
}
/**
* Returns +1, -1 or 0 according to the rules for usort().
*
* This method is called to ensure extensions can be execute in an appropriate order.
*
* @param string $esmtpKeyword to compare with
*
* @return int
*/
public function getPriorityOver($esmtpKeyword)
{
return 0;
}
/**
* Not used.
*/
public function exposeMixinMethods()
{
return [];
}
/**
* Not used.
*/
public function resetState()
{
}
}

View File

@ -0,0 +1,107 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2018 Christian Schmidt
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An ESMTP handler for SMTPUTF8 support (RFC 6531).
*
* SMTPUTF8 is required when sending to email addresses containing non-ASCII
* characters in local-part (the substring before @). This handler should be
* used together with Swift_AddressEncoder_Utf8AddressEncoder.
*
* SMTPUTF8 mode is enabled unconditionally, even when sending to ASCII-only
* addresses, so it should only be used with an outbound SMTP server that will
* deliver ASCII-only messages even if the next hop does not support SMTPUTF8.
*
* @author Christian Schmidt
*/
class Swift_Transport_Esmtp_SmtpUtf8Handler implements Swift_Transport_EsmtpHandler
{
public function __construct()
{
}
/**
* Get the name of the ESMTP extension this handles.
*
* @return string
*/
public function getHandledKeyword()
{
return 'SMTPUTF8';
}
/**
* Not used.
*/
public function setKeywordParams(array $parameters)
{
}
/**
* Not used.
*/
public function afterEhlo(Swift_Transport_SmtpAgent $agent)
{
}
/**
* Get params which are appended to MAIL FROM:<>.
*
* @return string[]
*/
public function getMailParams()
{
return ['SMTPUTF8'];
}
/**
* Not used.
*/
public function getRcptParams()
{
return [];
}
/**
* Not used.
*/
public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false)
{
}
/**
* Returns +1, -1 or 0 according to the rules for usort().
*
* This method is called to ensure extensions can be execute in an appropriate order.
*
* @param string $esmtpKeyword to compare with
*
* @return int
*/
public function getPriorityOver($esmtpKeyword)
{
return 0;
}
/**
* Not used.
*/
public function exposeMixinMethods()
{
return [];
}
/**
* Not used.
*/
public function resetState()
{
}
}