BLOGサブスレッドの日常

2016.05.31

メアドのドメイン

tama

邪神の封印に失敗したへっぽこ魔女です。どうも。
髪は死んだ。

週末のデスマ対応でDjangoのバリデーションを見ていて「へー!」と思ったことがあったので共有します。

「メールアドレスのドメイン部に全角文字が入力できます」

みたいなチケットをいただきました。
あれれ?それってDjangoさんの django.core.validators.EmailValidator をそのまま使ってるはず…?

というわけでさくっとソース探索。IDEがあると Go To Declaration がショートカット一発で楽だからいいよねー。

domain_regex = _lazy_re_compile(
    # max length for domain name labels is 63 characters per RFC 1034
    r'((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+)(?:[A-Z0-9-]{2,63}(?<!-))\Z',
    re.IGNORECASE)

見るからにASCII文字のアルファベット・数字・ハイフン(-)とドメイン区切りのピリオド(.)しか許可してない…

と思いきや。

    if (domain_part not in self.domain_whitelist and
            not self.validate_domain_part(domain_part)):
        # Try for possible IDN domain-part
        try:
            domain_part = domain_part.encode('idna').decode('ascii')
            if self.validate_domain_part(domain_part):
                return
        except UnicodeError:
            pass
        raise ValidationError(self.message, code=self.code)

あー、IDNA(RFC3490)対応。
全角英数字をASCII(半角英数字)に置き換えてバリデーション判定してるのね、なるほど。
じゃあこれRFC的には正しいのだろうけど、うちのシステムからCSVで出力して連携する先のシステムは
あくまで半角英数のメアドを求めてはるのよね…

既存のバリデータをフル活用しつつ俺々バリデータ

django.core.validators.EmailValidator のメアドバリデーションはそのまま活かしつつ
全角文字の入力だけ拒否したいので。
こんな俺々バリデータを作ってみました。

from django.core import validators
import re

class MyEmailValidator(validators.EmailValidator):
    def __call__(self, value):
        # validators.EmailValidator のバリデート前に全角文字を弾く ※IDNA対応で全角英数字が通ってしまうので
        if re.search(r'[^\x00-\x7E]', value):
            raise validators.ValidationError(self.message, code=self.code)
        return super(MyEmailValidator, self).__call__(value)

全角文字を自動的に半角文字に変換してあげればいいじゃんってのは真理なんだけど。
一箇所やると「ほかも全部」という話になるし(半角→全角とか)、試験項目的にも納期的にもお客さんが納得しないので
なんか悔しいけどエラーで跳ねる対応でひとまず。

まとめ。

  • Djangoさんの django.core.validators.EmailValidator はIDNA対応で全角ドメインを受け付ける
  • 全角拒否するためにバリデータを実装し直すのはやめたいよね

でした。
デスマまだ終わってなくて薄いブログでごめんなさいねー(いつもと変わらない説

この記事を書いた人

tama