chromeのHSTSキャッシュを削除する

http のリクエストが勝手にhttps にリダイレクトされる事案が発生しました。

状況としては↓な状況

beniyama.hatenablog.jp

サーバ側は設定を変更・再起動でよいけど ブラウザに残ったHSTS キャッシュが消えないかぎり、https にリダイレクトされ続けます。

キャッシュ消えるまで待つとかつらすぎるので、chromeのHSTSキャッシュを削除します

chromeのHSTSキャッシュを削除する方法

  • chrome://net-internals/#hsts をchrome のURLに入力し、移動する。
  • Delete domain の箇所に削除したいドメインを入力します。
  • Delete ボタンをクリックします。

gyazo.com

vpn 接続時に SSH2_MSG_KEXINIT でハングするときの対処

  • pritunl v1.18.902.26
  • Tunnelblick 3.5.7 (vpn client)

pritunl をつかってVPN環境が構築した。

モバイル回線だと特に不便なくVPN接続できていたのだが、有線にしたところssh が繋がらない状態になった。

% ssh app-001.cameong.local
:
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.2
debug1: Remote protocol version 2.0, remote software version OpenSSH_6.6.1
debug1: match: OpenSSH_6.6.1 pat OpenSSH*
debug1: SSH2_MSG_KEXINIT sent

どうやらMTUの設定値関係してそう。

MTU = 1454

この PPPoE では Ethernet の MTU = 1500 の世界の中に、 RFC2516 的には 6 バイトの PPPoE へッダと 2 バイトの ppp へッダを加える。このため、 1500 - ( 6 + 2 ) = 1492 バイトまでのパケットしか通れないことになる。つまり MTU = 1492 にする。 しかし NTT 東日本の場合、更に内部のネットワークの事情で 「MTU = 1454 にしておけば、必ずどこでも通る」ということになっているらしい。 これらの数字は、 通常の Ethernet の通信に使われる 1500より小さくなるので、問題が起きる。と言える。

MTU @ki.nu

たしかに mtu 1500 になっている。

// ifconfig
:
utun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
        inet 10.0.5.2 --> 10.0.5.2 netmask 0xffffff00

tunnelblick の設定にMTUの変更( link-mtu) を加える

   verb 2
   mute 3 
   push-peer-info
   ping 10
   ping-restart 60
   hand-window 70
   server-poll-timeout 4
   reneg-sec 2592000
   sndbuf 100000
   rcvbuf 100000
   remote-cert-tls server
+ link-mtu 1454
   comp-lzo no
   auth-user-pass
   key-direction 1

確認

% ifconfig 
:
utun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1384
        inet 10.0.5.2 --> 10.0.5.2 netmask 0xffffff00

mtu 1454より小さくなってるけど。

この設定で、ssh 接続可能になりました。

気になる謎

  • VPN接続なしの場合、en0 から接続してるのだが、en0 のmtu が1500 でも繋がるのなぜ。
  • link-mtu 1545 なのに実際は1384 になってるのなぜ。

詳しい方、教えてください!

追記

  • mtu 1454 だと時間がたったら、再度sshできなくなる。
  • mtu 1400 でトライ

AWS RDS mysql 5.7.10だと360日でアカウント強制無効化されるとか聞いてないよ

  • 日時: 2016/03/03

mysql 5.7 がAWS RDS で使えるということで、使ってみました。

そうすると、気になる記事を発見

アカウントの自動失効

MySQL 5.7で新しく追加された機能の1つに,アカウントの自動失効機能があります。これは最後にパスワードを変更した時間からデフォルトで360日が経過すると,そのアカウントをEXPIRE(無効化)しその後のログインを許可しないという強烈なオプションです。テストのために都度ビルドして利用するようなケースで問題になることは少ないかと思いますが,作成したイメージをそのまま長期間利用する(あるいは,ビルド時にユーザを作成し,その後アカウントが追加されることはあってもパスワードが変更されることはないようなケース)場合はこの機能をOFFにしておいた方がいいでしょう。

引用元

http://gihyo.jp/dev/serial/01/mysql-road-construction-news/0010

MySQL 5.7.11でdefault_password_lifetimeのデフォルトは0に変更になりました!

引用元 http://yoku0825.blogspot.jp/2015/06/mysql-574defaultpasswordlifetime.html

とのことで

  • mysql 5.7.0 ~ 5.7.10 は 360日経過するとデフォルトでアカウントが無効化される
  • mysql 5.7.11 以降 デフォルトでアカウント無効化しない.
  • AWS のRDS mysqlは 5.7.10

AWS が気を利かせてデフォルト値を変更しててくれてないかなと期待して見てみると

mysql> select @@default_password_lifetime;
+-----------------------------+
| @@default_password_lifetime |
+-----------------------------+
|                         360 |
+-----------------------------+
1 row in set (0.01 sec)

はい、360日で無効化されてしまいますね。

AWSコンソールから default_password_lifetime を 0にするように変更します。

利用中のパラメーターグループを選択し、default_password_lifetime の値を0に変更します。

gyazo.com

変更後

mysql> select @@default_password_lifetime;
+-----------------------------+
| @@default_password_lifetime |
+-----------------------------+
|                           0 |
+-----------------------------+
1 row in set (0.00 sec)

無停止で変更できました。

これで強制無効化はなくなった。よかった。

django 1.8 のmodelformを使って、画像を登録・更新する

環境

  • django 1.8
  • python 2.7

目的

ユーザが自分自身の画像を登録できるようにする。

formで画像を登録するときの動きはほかのmodel でも利用可能です。

modelform を利用します。

変更に必要なファイルは次の通り。

  • original_auth/models.py
  • original_auth/urls.py
  • original_auth/views.py
  • original_auth/forms.py
  • original_auth/templates/original_auth/original_user_update.html

一つずつ見ていきましょう。

original_auth/models.py

original_auth/models.py をみます。

主な初期値からの変更点は次の通り

  • カスタムユーザを作成
  • ログイン名をusernameからemail に変更

なお、2つとも画像登録に関係ない変更です。

どんなフィールドを使用しているか見てもらえればいいかなと。

// original_auth/models.py
#-*- coding: utf-8 -*-
from django.db import models
from django.contrib.auth.models import AbstractUser,AbstractBaseUser,PermissionsMixin,UserManager
from django.core.urlresolvers import reverse
from django.dispatch import receiver
from django.db.models.signals import post_save
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser, _user_has_perm, _user_has_module_perms
)
from django.core import validators
from django.core.mail import send_mail

class OriginalUser(AbstractBaseUser,PermissionsMixin):
    """User """
    image = models.ImageField(_('image URL'),upload_to='user/images/%Y/%m/%d/', blank=True)
    username    = models.CharField(_('username'),
                                   max_length=30,
                                   blank=True,
                                   help_text=_('Required. 30 characters or fewer. Letters, numbers and '
                                   '@/./+/-/_ characters'))
    first_name  = models.CharField(_('first name'), max_length=30, blank=True)
    last_name   = models.CharField(_('last name'), max_length=30, blank=True)
    email       = models.EmailField(verbose_name=_('email address'), max_length=255, unique=True)
    is_active   = models.BooleanField(default=False)
    is_staff    = models.BooleanField(default=False)
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)

    objects = UserManager()

    USERNAME_FIELD  = 'email'
    REQUIRED_FIELDS = ['username']

    def __str__(self):
        return self.username
    
    def get_full_name(self):
        """
        Returns the first_name plus the last_name, with a space in between.
        """
        full_name = '%s %s' % (self.first_name, self.last_name)
        return full_name.strip()

    def get_short_name(self):
        "Returns the short name for the user."
        return self.first_name

    def email_user(self, subject, message, from_email=None, **kwargs):
        """
        Sends an email to this User.
        """
        send_mail(subject, message, from_email, [self.email], **kwargs)

    def get_absolute_url(self):
        return "/user/%i/" % self.id

original_auth/urls.py

つぎ original_auth/urls.py

from django.conf.urls import patterns, url
from original_auth.views import user_update

urlpatterns = patterns('',
                 url(r'^(?P<pk>\d+)/update$',
                 user_update,
                 name='original_user_update'
                ),
)

original_auth/views.py

つぎ、original_auth/views.py をみます。

  • ログインユーザと違うユーザが変更画面にアクセスしたら表示させない
  • 新規画像ファイルがなかったら、user情報を更新。
  • 新規画像ファイルがあったら、あたらしくinstance を作成し、user情報を上書き。

もっといい方法があればしりたい。

// original_auth/views.py
from django.http import HttpResponseRedirect
from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import login_required
from original_auth.models import OriginalUser
from original_auth.forms import OriginalUserUpdateForm
@login_required
def user_update(request, pk):
        '''
        :pk: unicode
        :request.user.pk: integer
        ''''
        request.user.pk == int(pk):
        u = OriginalUser.objects.get(id=pk)
        form = OriginalUserUpdateForm(request.POST or None,  request.FILES or None,instance=u)
        args = {}
        if form.is_valid():
            if request.FILES:
                instance            = OriginalUser(image = request.FILES['image'])
            else:
                instance                = u
            instance.id                = u.id
            instance.email           = u.email
            instance.password    = u.password
            instance.username  = form.cleaned_data['username']
            instance.first_name  = form.cleaned_data['first_name']
            instance.last_name   = form.cleaned_data['last_name']
            instance.is_active     = u.is_active
            instance.is_staff        = u.is_staff
            instance.date_joined = u.date_joined

            instance.save()

            return HttpResponseRedirect("/user/%s" % (pk))
        else:
            form = OriginalUserUpdateForm(request.POST or None, instance=u)
        args['form'] = form
        return render(request, 'original_auth/original_user_update.html', args)
    else:
        raise PermissionDenied

original_auth/forms.py

つぎ、 original_auth/forms.py をみます。

fields = '__all__'にしてしまうと、(暗号化された)パスワードも見えるので、パスワード変更は別フォームで行ったほうが楽です。

変更したいフィールドだけ指定するようにします。

#-*- coding: utf-8 -*-
from django import forms
from original_auth.models import OriginalUser

class OriginalUserUpdateForm(forms.ModelForm):
    image          =  forms.ImageField(required=False)
    class Meta:
        model = OriginalUser
        #fields = '__all__'
        fields = ['username','image','first_name','last_name']

original_auth/templates/original_auth/original_user_update.html

最後、templates です。

  • enctype="multipart/form-data" を忘れずに。これがないと画像を扱えません。
  • 当然のことですが、{% csrf_token %} つけましょう
{% extends "base.html" %}
{% block content %}
                        <div>
                           {% if form.has_errors %}
                               {% for field in form.fields %}
                                  {% if field.error %}
                                     {{ field.error }}
                                  {% endif %}
                               {% endfor %}
                           {% endif %}
                            <form method="POST" class="post-form" enctype="multipart/form-data">{% csrf_token %}
                                {% csrf_token %}
                                {{ form.as_p }}
                                <input type="submit" value="{% trans 'Submit' %}" />
                            </form>
                        </div>
{% endblock %}

以上です。

.gitignore をお手軽に作成する

いちから.gitignoreを作成するのは大変なので github/gitignore を利用します.

  • ライセンス: MIT
% mkdir repo_dir
% cd repo_dir
% wget https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore -O - >> .gitignore
% wget https://raw.githubusercontent.com/github/gitignore/master/Global/Vim.gitignore -O - >> .gitignore
% git init

django メールの送信テストを行う

django でメール送信するテストを行う。

settings.py の設定

// project/settings.py

EMAIL_HOST = 'smtp.yourdomain.com'
EMAIL_HOST_USER = 'your-username@yourdomain.com'
EMAIL_HOST_PASSWORD = 'your-password'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"

django < 1.4 未満の場合

python manage.py shell
>>> from django.core.mail import send_mail
>>> send_mail('test email', 'hello world', to=['test@example.com'])

django 1.4 以上の場合

python manage.py shell
>>> from django.core.mail import send_mail
>>> send_mail('test email', 'hello world', 'your@email.com', ['test@email.com'])

http://stackoverflow.com/questions/6914687/django-sending-email