Skip to content

Commit

Permalink
RFC違反のメールアドレスに送信できるよう修正
Browse files Browse the repository at this point in the history
携帯キャリアのメールアドレスの一部に存在するメールアドレスに対応

- user.@example.com - @ の前に . が存在する
- user..name@example.com - . が2つ連続する
  • Loading branch information
nanasess committed Sep 28, 2016
1 parent d8324b8 commit 5a646b1
Show file tree
Hide file tree
Showing 13 changed files with 250 additions and 14 deletions.
6 changes: 6 additions & 0 deletions src/Eccube/Application.php
Expand Up @@ -385,6 +385,12 @@ public function initMailer()
});
}
}
// RFC違反のメールを送信できるよう独自の Grammer に置き換える
\Swift::init(function () {
\Swift_DependencyContainer::getInstance()
->register('mime.grammar')
->asSharedInstanceOf(\Eccube\Swift\Mime\Grammar::class);
});

$this->register(new \Silex\Provider\SwiftmailerServiceProvider());
$this['swiftmailer.options'] = $this['config']['mail'];
Expand Down
2 changes: 1 addition & 1 deletion src/Eccube/Form/Type/Admin/CustomerType.php
Expand Up @@ -77,7 +77,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
'constraints' => array(
new Assert\NotBlank(),
// configでこの辺りは変えられる方が良さそう
new Assert\Email(array('strict' => true)),
new Assert\Email(array('strict' => false)),
new Assert\Regex(array(
'pattern' => '/^[[:graph:][:space:]]+$/i',
'message' => 'form.type.graph.invalid',
Expand Down
4 changes: 2 additions & 2 deletions src/Eccube/Form/Type/Admin/OrderType.php
Expand Up @@ -117,7 +117,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
'label' => 'メールアドレス',
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email(array('strict' => true)),
new Assert\Email(array('strict' => false)),
),
))
->add('tel', 'tel', array(
Expand Down Expand Up @@ -301,4 +301,4 @@ public function getName()
{
return 'order';
}
}
}
8 changes: 4 additions & 4 deletions src/Eccube/Form/Type/Admin/ShopMasterType.php
Expand Up @@ -127,31 +127,31 @@ public function buildForm(FormBuilderInterface $builder, array $options)
'required' => false,
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email(array('strict' => true)),
new Assert\Email(array('strict' => false)),
),
))
->add('email02', 'email', array(
'label' => '問い合わせ受付メールアドレス(From, ReplyTo)',
'required' => false,
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email(array('strict' => true)),
new Assert\Email(array('strict' => false)),
),
))
->add('email03', 'email', array(
'label' => '返信受付メールアドレス(ReplyTo)',
'required' => false,
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email(array('strict' => true)),
new Assert\Email(array('strict' => false)),
),
))
->add('email04', 'email', array(
'label' => '送信エラー受付メールアドレス(ReturnPath)',
'required' => false,
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email(array('strict' => true)),
new Assert\Email(array('strict' => false)),
),
))
->add('good_traded', 'textarea', array(
Expand Down
2 changes: 1 addition & 1 deletion src/Eccube/Form/Type/Admin/TradelawType.php
Expand Up @@ -78,7 +78,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
'required' => true,
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email(array('strict' => true)),
new Assert\Email(array('strict' => false)),
new Assert\Regex(array(
'pattern' => '/^[[:graph:][:space:]]+$/i',
'message' => 'form.type.graph.invalid',
Expand Down
2 changes: 1 addition & 1 deletion src/Eccube/Form/Type/CustomerType.php
Expand Up @@ -96,7 +96,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
->add('email', 'email', array(
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email(array('strict' => true)),
new Assert\Email(array('strict' => false)),
)
))
->add('sex', 'sex', array(
Expand Down
2 changes: 1 addition & 1 deletion src/Eccube/Form/Type/Front/ContactType.php
Expand Up @@ -62,7 +62,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
'required' => true,
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email(array('strict' => true)),
new Assert\Email(array('strict' => false)),
),
))
->add('contents', 'textarea', array(
Expand Down
2 changes: 1 addition & 1 deletion src/Eccube/Form/Type/Front/CustomerLoginType.php
Expand Up @@ -50,7 +50,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
),
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email(array('strict' => true)),
new Assert\Email(array('strict' => false)),
),
'data' => $this->session->get('_security.last_username'),
));
Expand Down
2 changes: 1 addition & 1 deletion src/Eccube/Form/Type/Front/ForgotType.php
Expand Up @@ -42,7 +42,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
),
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email(array('strict' => true)),
new Assert\Email(array('strict' => false)),
),
));
}
Expand Down
2 changes: 1 addition & 1 deletion src/Eccube/Form/Type/Install/Step3Type.php
Expand Up @@ -60,7 +60,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
'label' => 'メールアドレス(受注メールなどの宛先になります)',
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email(array('strict' => true)),
new Assert\Email(array('strict' => false)),
),
))
->add('login_id', 'text', array(
Expand Down
2 changes: 1 addition & 1 deletion src/Eccube/Form/Type/RepeatedEmailType.php
Expand Up @@ -42,7 +42,7 @@ public function configureOptions(OptionsResolver $resolver)
'options' => array(
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email(array('strict' => true)),
new Assert\Email(array('strict' => false)),
new Assert\Regex(array(
'pattern' => '/^[[:graph:][:space:]]+$/i',
'message' => 'form.type.graph.invalid',
Expand Down
194 changes: 194 additions & 0 deletions src/Eccube/Swift/Mime/Grammar.php
@@ -0,0 +1,194 @@
<?php

namespace Eccube\Swift\Mime;

/*
* 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.
*/

/**
* Defines the grammar to use for validation, implements the RFC 2822 (and friends) ABNF grammar definitions.
*
* Original \Swift_Mime_Grammer
*
* @author Fabien Potencier
* @author Chris Corbyn
* @author Kentaro Ohkouchi
*/
class Grammar extends \Swift_Mime_Grammar
{
/**
* Special characters used in the syntax which need to be escaped.
*
* @var string[]
*/
private static $_specials = array();

/**
* Tokens defined in RFC 2822 (and some related RFCs).
*
* @var string[]
*/
private static $_grammar = array();

/**
* Initialize some RFC 2822 (and friends) ABNF grammar definitions.
*/
public function __construct()
{
$this->init();
}

public function __wakeup()
{
$this->init();
}

protected function init()
{
if (count(self::$_specials) > 0) {
return;
}

self::$_specials = array(
'(', ')', '<', '>', '[', ']',
':', ';', '@', ',', '.', '"',
);

/*** Refer to RFC 2822 for ABNF grammar ***/

// All basic building blocks
self::$_grammar['NO-WS-CTL'] = '[\x01-\x08\x0B\x0C\x0E-\x19\x7F]';
self::$_grammar['WSP'] = '[ \t]';
self::$_grammar['CRLF'] = '(?:\r\n)';
self::$_grammar['FWS'] = '(?:(?:'.self::$_grammar['WSP'].'*'.
self::$_grammar['CRLF'].')?'.self::$_grammar['WSP'].')';
self::$_grammar['text'] = '[\x00-\x08\x0B\x0C\x0E-\x7F]';
self::$_grammar['quoted-pair'] = '(?:\\\\'.self::$_grammar['text'].')';
self::$_grammar['ctext'] = '(?:'.self::$_grammar['NO-WS-CTL'].
'|[\x21-\x27\x2A-\x5B\x5D-\x7E])';
// Uses recursive PCRE (?1) -- could be a weak point??
self::$_grammar['ccontent'] = '(?:'.self::$_grammar['ctext'].'|'.
self::$_grammar['quoted-pair'].'|(?1))';
self::$_grammar['comment'] = '(\((?:'.self::$_grammar['FWS'].'|'.
self::$_grammar['ccontent'].')*'.self::$_grammar['FWS'].'?\))';
self::$_grammar['CFWS'] = '(?:(?:'.self::$_grammar['FWS'].'?'.
self::$_grammar['comment'].')*(?:(?:'.self::$_grammar['FWS'].'?'.
self::$_grammar['comment'].')|'.self::$_grammar['FWS'].'))';
self::$_grammar['qtext'] = '(?:'.self::$_grammar['NO-WS-CTL'].
'|[\x21\x23-\x5B\x5D-\x7E])';
self::$_grammar['qcontent'] = '(?:'.self::$_grammar['qtext'].'|'.
self::$_grammar['quoted-pair'].')';
self::$_grammar['quoted-string'] = '(?:'.self::$_grammar['CFWS'].'?"'.
'('.self::$_grammar['FWS'].'?'.self::$_grammar['qcontent'].')*'.
self::$_grammar['FWS'].'?"'.self::$_grammar['CFWS'].'?)';
self::$_grammar['atext'] = '[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]';
self::$_grammar['atom'] = '(?:'.self::$_grammar['CFWS'].'?'.
self::$_grammar['atext'].'+'.self::$_grammar['CFWS'].'?)';

self::$_grammar['loose-dot-atom-text'] = '(?:'.self::$_grammar['atext'].'|\.)+';
self::$_grammar['loose-dot-atom'] = '(?:'.self::$_grammar['CFWS'].'?'.
self::$_grammar['loose-dot-atom-text'].'+'.self::$_grammar['CFWS'].'?)';

// self::$_grammar['dot-atom-text'] = '(?:'.self::$_grammar['atext'].'+'.
// '(\.'.self::$_grammar['atext'].'+)*)';
// self::$_grammar['dot-atom'] = '(?:'.self::$_grammar['CFWS'].'?'.
// self::$_grammar['dot-atom-text'].'+'.self::$_grammar['CFWS'].'?)';

self::$_grammar['word'] = '(?:'.self::$_grammar['atom'].'|'.
self::$_grammar['quoted-string'].')';
self::$_grammar['phrase'] = '(?:'.self::$_grammar['word'].'+?)';
self::$_grammar['no-fold-quote'] = '(?:"(?:'.self::$_grammar['qtext'].
'|'.self::$_grammar['quoted-pair'].')*")';
self::$_grammar['dtext'] = '(?:'.self::$_grammar['NO-WS-CTL'].
'|[\x21-\x5A\x5E-\x7E])';
self::$_grammar['no-fold-literal'] = '(?:\[(?:'.self::$_grammar['dtext'].
'|'.self::$_grammar['quoted-pair'].')*\])';

// Message IDs
self::$_grammar['id-left'] = '(?:'.self::$_grammar['loose-dot-atom-text'].'|'.
self::$_grammar['no-fold-quote'].')';
self::$_grammar['id-right'] = '(?:'.self::$_grammar['loose-dot-atom-text'].'|'.
self::$_grammar['no-fold-literal'].')';

// self::$_grammar['id-left'] = '(?:'.self::$_grammar['dot-atom-text'].'|'.
// self::$_grammar['no-fold-quote'].')';
// self::$_grammar['id-right'] = '(?:'.self::$_grammar['dot-atom-text'].'|'.
// self::$_grammar['no-fold-literal'].')';

// Addresses, mailboxes and paths
self::$_grammar['local-part'] = '(?:'.self::$_grammar['loose-dot-atom'].'|'.
self::$_grammar['quoted-string'].')';
// self::$_grammar['local-part'] = '(?:'.self::$_grammar['dot-atom'].'|'.
// self::$_grammar['quoted-string'].')';
self::$_grammar['dcontent'] = '(?:'.self::$_grammar['dtext'].'|'.
self::$_grammar['quoted-pair'].')';
self::$_grammar['domain-literal'] = '(?:'.self::$_grammar['CFWS'].'?\[('.
self::$_grammar['FWS'].'?'.self::$_grammar['dcontent'].')*?'.
self::$_grammar['FWS'].'?\]'.self::$_grammar['CFWS'].'?)';
self::$_grammar['domain'] = '(?:'.self::$_grammar['loose-dot-atom'].'|'.
self::$_grammar['domain-literal'].')';
self::$_grammar['addr-spec'] = '(?:'.self::$_grammar['local-part'].'@'.
self::$_grammar['domain'].')';
}

/**
* Get the grammar defined for $name token.
*
* @param string $name exactly as written in the RFC
*
* @return string
*/
public function getDefinition($name)
{
if (array_key_exists($name, self::$_grammar)) {
return self::$_grammar[$name];
}

throw new Swift_RfcComplianceException(
"No such grammar '".$name."' defined."
);
}

/**
* Returns the tokens defined in RFC 2822 (and some related RFCs).
*
* @return array
*/
public function getGrammarDefinitions()
{
return self::$_grammar;
}

/**
* Returns the current special characters used in the syntax which need to be escaped.
*
* @return array
*/
public function getSpecials()
{
return self::$_specials;
}

/**
* Escape special characters in a string (convert to quoted-pairs).
*
* @param string $token
* @param string[] $include additional chars to escape
* @param string[] $exclude chars from escaping
*
* @return string
*/
public function escapeSpecials($token, $include = array(), $exclude = array())
{
foreach (array_merge(array('\\'), array_diff(self::$_specials, $exclude), $include) as $char) {
$token = str_replace($char, '\\'.$char, $token);
}

return $token;
}
}
36 changes: 36 additions & 0 deletions tests/Eccube/Tests/Web/ContactControllerTest.php
Expand Up @@ -190,4 +190,40 @@ public function testRoutingComplete()
$client->request('GET', $this->app->path('contact_complete'));
$this->assertTrue($client->getResponse()->isSuccessful());
}

public function testInvalidRfcEmail()
{
$emails = array(
// RFC違反のメールアドレス
'aaaa......aaaa@example.com',
'aaaa..aaaa@example.com',
'aaaa.@example.com'
);

foreach ($emails as $email) {
$client = $this->createClient();

$formData = $this->createFormData();
$formData['email'] = $email;
$crawler = $client->request(
'POST',
$this->app->path('contact'),
array('contact' => $formData,
'mode' => 'complete')
);
$this->assertTrue($client->getResponse()->isRedirect($this->app->url('contact_complete')));

$BaseInfo = $this->app['eccube.repository.base_info']->get();
$Messages = $this->getMailCatcherMessages();
$Message = $this->getMailCatcherMessage($Messages[0]->id);

$this->expected = '[' . $BaseInfo->getShopName() . '] お問い合わせを受け付けました。';
$this->actual = $Message->subject;
$this->verify();

$body = $this->parseMailCatcherSource($Message);
$this->assertRegexp('/'.$formData['email'].'/', $body, $formData['email'].' でも送信可能');
$this->cleanUpMailCatcherMessages();
}
}
}

0 comments on commit 5a646b1

Please sign in to comment.