From 95cc8b829b2eecf906bc663640d6f946111508e3 Mon Sep 17 00:00:00 2001 From: Synchro Date: Tue, 4 Dec 2012 10:33:23 +0100 Subject: [PATCH] Add info & test case for CRAM-MD5 auth Fix validation test Fix misdocumented do_debug property in SMTP Code cleanup --- README.md | 4 ++-- class.phpmailer.php | 6 ++--- class.smtp.php | 52 ++++++++++++++++++++++-------------------- test/phpmailerTest.php | 39 +++++++++++++++++++++++-------- 4 files changed, 62 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index bb20e447..f7f6238b 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ - Multipart/alternative emails for mail clients that do not read HTML email - Support for 8bit, base64, binary, and quoted-printable encoding - Uses the same methods as the very popular AspEmail active server (COM) component -- SMTP authentication +- SMTP authentication with LOGIN, PLAIN, NTLM and CRAM-MD5 mechanisms - Native language support - Word wrap - Compatible with PHP 5.0 and later @@ -26,7 +26,7 @@ The PHP mail() function usually sends via a local mail server, typically fronted ## License -This software is licenced under the [LGPL](http://www.gnu.org/licenses/lgpl-2.1.html). Please read LICENSE for information on the +This software is licenced under the [LGPL 2.1](http://www.gnu.org/licenses/lgpl-2.1.html). Please read LICENSE for information on the software availability and distribution. ## Installation diff --git a/class.phpmailer.php b/class.phpmailer.php index e9f41755..af7df9d7 100644 --- a/class.phpmailer.php +++ b/class.phpmailer.php @@ -260,7 +260,7 @@ class PHPMailer { public $Password = ''; /** - * Sets SMTP auth type. Options are LOGIN | PLAIN | NTLM (default LOGIN) + * Sets SMTP auth type. Options are LOGIN | PLAIN | NTLM | CRAM-MD5 (default LOGIN) * @var string */ public $AuthType = ''; @@ -2069,8 +2069,8 @@ class PHPMailer { case 'comment': $pattern = '\(\)"'; - //note that we dont break here! - //for this reason we build the $pattern withoud including delimiters and [] + //note that we don't break here! + //for this reason we build the $pattern without including delimiters and [] case 'text': default: diff --git a/class.smtp.php b/class.smtp.php index ddb624a6..44f7ff1b 100644 --- a/class.smtp.php +++ b/class.smtp.php @@ -58,10 +58,10 @@ class SMTP { public $CRLF = "\r\n"; /** - * Sets whether debugging is turned on - * @var bool + * Sets debug output level; 0 for no output + * @var int */ - public $do_debug; // the level of debug to perform + public $do_debug = 0; /** * Sets the function/method to use for debugging output. @@ -432,11 +432,11 @@ class SMTP { return false; } - // Get the challenge - $challenge = base64_decode(substr($rply,4)); + // Get the challenge + $challenge = base64_decode(substr($rply,4)); - // Build the response - $response = $username . ' ' . $this->hmac($challenge, $password); + // Build the response + $response = $username . ' ' . $this->hmac($challenge, $password); // Send encoded credentials fputs($this->smtp_conn, base64_encode($response) . $this->CRLF); @@ -462,31 +462,33 @@ class SMTP { /** * Works like hash_hmac('md5', $data, $key) in case that function is not available * @access private + * @param string $data + * @param string $key * @return string */ private function hmac($data, $key) { - if (function_exists('hash_hmac')) { - return hash_hmac('md5', $data, $key); - } + if (function_exists('hash_hmac')) { + return hash_hmac('md5', $data, $key); + } - // The following borrowed from http://php.net/manual/en/function.mhash.php#27225 + // The following borrowed from http://php.net/manual/en/function.mhash.php#27225 - // RFC 2104 HMAC implementation for php. - // Creates an md5 HMAC. - // Eliminates the need to install mhash to compute a HMAC - // Hacked by Lance Rushing + // RFC 2104 HMAC implementation for php. + // Creates an md5 HMAC. + // Eliminates the need to install mhash to compute a HMAC + // Hacked by Lance Rushing - $b = 64; // byte length for md5 - if (strlen($key) > $b) { - $key = pack("H*",md5($key)); - } - $key = str_pad($key, $b, chr(0x00)); - $ipad = str_pad('', $b, chr(0x36)); - $opad = str_pad('', $b, chr(0x5c)); - $k_ipad = $key ^ $ipad ; - $k_opad = $key ^ $opad; + $b = 64; // byte length for md5 + if (strlen($key) > $b) { + $key = pack("H*",md5($key)); + } + $key = str_pad($key, $b, chr(0x00)); + $ipad = str_pad('', $b, chr(0x36)); + $opad = str_pad('', $b, chr(0x5c)); + $k_ipad = $key ^ $ipad ; + $k_opad = $key ^ $opad; - return md5($k_opad . pack("H*",md5($k_ipad . $data))); + return md5($k_opad . pack("H*",md5($k_ipad . $data))); } /** diff --git a/test/phpmailerTest.php b/test/phpmailerTest.php index 4536e35a..70c3cef5 100644 --- a/test/phpmailerTest.php +++ b/test/phpmailerTest.php @@ -9,7 +9,6 @@ * @author Andy Prevost * @author Marcus Bointon * @copyright 2004 - 2009 Andy Prevost - * @version $Id: phpmailerTest.php 444 2009-05-05 11:22:26Z coolbru $ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License */ @@ -285,6 +284,28 @@ class phpmailerTest extends PHPUnit_Framework_TestCase // UNIT TESTS ///////////////////////////////////////////////// + /** + * Test CRAM-MD5 authentication + * Needs a connection to a server that supports this auth mechanism, so commented out by default + */ + function testAuthCRAMMD5() + { + $this->Mail->Host = 'hostname'; + $this->Mail->Port = 587; + $this->Mail->SMTPAuth = true; + $this->Mail->SMTPSecure = 'tls'; + $this->Mail->AuthType = 'CRAM-MD5'; + $this->Mail->Username = 'username'; + $this->Mail->Password = 'password'; + $this->Mail->Body = 'Test body'; + $this->Mail->Subject .= ": Auth CRAM-MD5"; + $this->Mail->From = 'from@example.com'; + $this->Mail->Sender = 'from@example.com'; + $this->Mail->ClearAllRecipients(); + $this->Mail->AddAddress('user@example.com'); + //$this->assertTrue($this->Mail->Send(), $this->Mail->ErrorInfo); + } + /** * Test email address validation * Test addresses obtained from http://isemail.info @@ -575,14 +596,14 @@ class phpmailerTest extends PHPUnit_Framework_TestCase } $err = ''; if (count($goodfails) > 0) { - $err = "Good addreses that failed validation:\n"; + $err .= "Good addreses that failed validation:\n"; $err .= implode("\n", $goodfails); } if (count($badpasses) > 0) { if (!empty($err)) { $err .="\n\n"; } - $err = "Bad addreses that passed validation:\n"; + $err .= "Bad addreses that passed validation:\n"; $err .= implode("\n", $badpasses); } $this->assertEmpty($err, $err); @@ -951,7 +972,7 @@ class phpmailerTest extends PHPUnit_Framework_TestCase { $this->Mail->SetLanguage('en'); $definedStrings = $this->Mail->GetTranslations(); - $err = ''; + $err = ''; foreach (new DirectoryIterator('../language') as $fileInfo) { if ($fileInfo->isDot()) { continue; @@ -965,14 +986,14 @@ class phpmailerTest extends PHPUnit_Framework_TestCase $missing = array_diff(array_keys($definedStrings), array_keys($PHPMAILER_LANG)); $extra = array_diff(array_keys($PHPMAILER_LANG), array_keys($definedStrings)); if (!empty($missing)) { - $err .= "Missing translations in $lang: " . implode(', ', $missing)."\n"; + $err .= "Missing translations in $lang: " . implode(', ', $missing)."\n"; + } + if (!empty($extra)) { + $err .= "Extra translations in $lang: " . implode(', ', $extra)."\n"; } - if (!empty($extra)) { - $err .= "Extra translations in $lang: " . implode(', ', $extra)."\n"; - } } } - $this->assertEmpty($err, $err); + $this->assertEmpty($err, $err); } /**