memorandums

日々のメモです。

自分は自分。他人は他人。

今朝、風邪気味で出勤しながら、もやもや考えたことをツイートしました。Twitterは流れてどこかに消えてしまうので(消えないけど)、ちょっと自分のメモのためにここにまとめておきたいと思います。

成功:Digisparkのアップロードタイムアウト時間を短くした

今朝からDigisparkでいろいろやってました。

普通のArduinoとは異なり書き込み失敗することもよくあり、そのたびにタイムアウトまで1分待たされるのが面倒でした。

以下の対策をしてみようとしたものの。。。効果はなく。

memorandums.hatenablog.com

いろいろと調べてみた結果、Arduino IDEの「マイコンに書き込む」ボタンを押すと、以下の場所にある2つのプロセス(launcherとmicronucleus)が起動されることがわかりました。

~/Library/Arduino15/packages/digistump/tools/micronucleus/2.0a4

launcherはArduino IDEが起動するらしく、そのパラメタは以下のファイルのtimeoutを書き換えることで変更できました。でも、launcherはバイナリ転送プログラム?(micronucleus)を起動するコマンドらしく、launcherのtimeoutを変えてもタイムアウト時間は一向に変わりませんでした。

~/Arduino15/packages/digistump/hardware/avr/1.6.7/platform.txt

digistumpのgithubのリポジトリもみてみたのですが、それらしいコードがない。。。よくわかりませんが、ソースコードがどうしても見つけられません。

色々と試行錯誤した結果、もう、バイナリをいじるしかないなぁ。。。と。

0xEDというバイナリエディタをダウンロードして、①にtimeoutといれ、②の「36 30」を「31 20」にします。要はtimeoutを60から1にする感じです。

f:id:ke_takahashi:20181020184618p:plain

念のために、launchar本体をいじる前に、launchar.orgにコピーして原本を残して修正しましょう。

バイナリのサイズを見ているようで、timeoutを1にしただけでは1バイト短くなるためArduino IDEで書き込みボタンを押したときにエラーがでました。なのでとりあえず空白(0x20)を入れたらめでたく動いたわけです。

まぁ、こんなことやっていいのか、そもそもソースコードが入手できればこんなことしなくていいでしょうけど。

とりあえず。

失敗:DigisparkでArduino IDEから書き込み不能になったときにやってみたこと(USB Prober)

来週末のイベントに向けてArduinoのプログラムを作ってはDigisparkに書き込む作業を繰り返しています。

Digisparkはリセット回路が実装されていないためUSB抜き差しをしなければなりません。

で、たまーに、以下のメッセージを吐いて、抜き差ししてもどうにもこうにも書き込めなくなる状況があります。

f:id:ke_takahashi:20181020091413p:plain

そんなときには、とりあえず別のUSBポートに刺し直したり、Arduino IDEを再起動したり、あれこれしているうちに復旧するんですが。。。

来週のイベントでは20個のDigisparkに書き込む必要があり、イベント会場でも参加者の要望にあわせてLEDの点灯パターンを変えたいので、いちいち詰まっていては困ります。

で、何か方法を探しておこうとぐぐったわけです。

USBドライバを再起動すれば直せるんじゃないかと。技術的な仕組みを理解していないのであてずっぽです。

apple.stackexchange.com

USB Proberっていうアプリで再起動ができるらしい(アプリを起動するだけでリセットされるとか)。でも、インストールしてはダメよと書かれています。実際にハマった人もいるようで。。。せっかくの失敗報告を生かさないと行けません。

とりあえず入れてみました。以下、インスト手順です。

(1)https://developer.apple.com/download/more/:Appleの開発者サイトにログインし、以下のdmgをダウンロードします。

f:id:ke_takahashi:20181020092040p:plain

(2)dmgファイルをダブクリし、IOUSBFamily-683.4.0フォルダをダブクリし、IOUSBFamily-683.4.0.pkgを右クリックしてパッケージの内容を表示を選択し、Contentsをダブクリし、Archive.pax.gzをデスクトップにコピペします。

(3)あとはArchive.pax.gzを解凍してDevTools - Hardware と辿るとUSB Prober.appに出会えます。

(4)USB Prober.appをダブクリするとアプリを起動できます。


で、Arduino IDEが上記の現象になったときにこのアプリを起動してみたんですが。。。残念ながら回復しませんでした。仕組みが違うんでしょうね。

とりあえず、せっかくなので/Applicationフォルダにいれておこうと思います。

Arduino IDEを再起動すると時間かかるしな。。。なんかいい方法ないかしら?

Rails4のvalidates(confirmation)ではまった理由をメモしておきます

以下の書籍でログイン機能を作ってたとき、2時間くらいハマりました。。。あとで「何だっけ?」となったときに思い出せるようにメモしておきます。

ちなみに、このやり方は古いようで、最近は暗号化も含めて簡単に記述(has_secure_password)できるようなので、Rails勉強中の方にとってはノイズになりますので、この記事はくれぐれも無視してください。

改訂3版基礎 Ruby on Rails (KS IMPRESS KISO SERIES)

改訂3版基礎 Ruby on Rails (KS IMPRESS KISO SERIES)

ログインするユーザを登録するときに、パスワードの入力誤りを防止するために2回入力させることがよくありますが、それを実装します。

Userモデル(name:string、hashed_password:string)に基本情報をいれます。テーブルにはハッシュ後のパスワードをいれるため、モデルにない項目を入力フォームで扱う必要があります。これはこれで勉強になります。

モデルに項目を追加するため、普通のRuby同様に、attr_accessorで定義します。あと、passwordのセッターを定義しておいて、passwordに代入された文字列を横取りして、テーブルに入れるパスワードを暗号化するメソッドを追加します。いたって普通です。

attr_accessor :password, :password_confirmation

  def password=(val)
    if val.present?
      self.hashed_password = BCrypt::Password.create(val)
    end
    @password = val
  end

さらに、Userモデルに以下のvalidatesを追加します。

  validates :name, presence: true, uniqueness: true
  validates :password, presence: true, length: {minimum: 4}, confirmation: true

さらに、コントローラのcreateアクションを以下のようにしました。

  def create
    @user = User.new(name: params[:user][:name], password: params[:user][:password])
    if @user.save
      redirect_to users_path
    else

で、この状態でユーザ登録すると、なぜかパスワードが確認用のパスと一致していなくても通過しちゃうんですね。。。ここから調べること2時間。。。もったいない。ほんと。

原因はコントローラの書き方でした。

上記の書籍ではストロングパラメタを使っているので私のようなことは起きません。私は学習を用意にするため、記述は面倒ですが、ストロングパラメタを使わず、1つずつビューから渡す記述をしていたんですね。。。

本来であれば、以下のように書くべきなんですね。めちゃくちゃ長くなってどうにもこうにもッテ感じがしますが、バリデーションする元ネタであるpassword_confirmationをUserモデルにセットしていなかった。。。ここがミスでした。

  def create
    @user = User.new(name: params[:user][:name], password: params[:user][:password], password_confirmation: params[:user][:password_confirmation])
    if @user.save
      redirect_to users_path
    else

それでも、validatesを記述しているんだから不一致のチェックくらいしてくれたら。。。と思うのですが、「password_confirmationがnilの場合は同一性のチェックは行わない」という仕様なんだそうです。確かにドキュメントに書いてあったような気がします。読み飛ばしてしまいましたが。。。そのため気づくのが遅れてしまったわけです。

password_confirmationが空かどうかもバリデーションすべきってことです。それで気づけたのかもしれません。Userモデルにその記述を追加すると以下のようになります。

  validates :name, presence: true, uniqueness: true
  validates :password, presence: true, length: {minimum: 4}, confirmation: true
  validates :password_confirmation, presence: true

2時間返して。。。

嬉しいこと

個人的なメモを1つ。

本日、福岡県の教員採用試験の合格発表日でした。

大学に通う娘が無事、合格してくれました。

よかったぁ。。。😁

思い起こせば。4年前。

センター試験前日に私がインフルにかかってしまい。。。娘が試験だっていうのに親父がインフルでは洒落になりませんでした。ホント。以下には書いていませんが、自宅にはいれず博多駅前のホテルに3,4日間くらい過ごしました。私自身も試験監督だったので。。。もう苦い思い出です。

インフルエンザA型 - memorandums

でも、それもちゃんと結果を出してくれました。

普段、だらしないところがありますがやるときはやる、そんな子でした。

本当におめでとう🎉

これからが大変でしょうけど「先生」として、たくさんの人を支えたり支えられたりしながら成長していって欲しいと思います。

1つ役目が終わったような気がします。

まだ2人残っているので。。。まだまだ頑張らないといけません😁

bcrypt-rubyについて調べたメモ

Railsでログイン機能を実装するときに、パスワードを暗号化するのに表記のライブラリを利用するのが普通らしいです。

授業のネタ本にしている以下の書籍の361ページに以下の図で説明がありました。

改訂3版基礎 Ruby on Rails (KS IMPRESS KISO SERIES)

改訂3版基礎 Ruby on Rails (KS IMPRESS KISO SERIES)

f:id:ke_takahashi:20181011231355p:plain

暗号強度を高めるため生パスワードにソルトと呼ばれるランダムな文字列を付加してハッシュ化してDBに保存しておきます。なるほどなるほど。

ログインするときに、入力されたパスワードにソルトを加えてハッシュ化して暗号同士が等しいか比較する。。。という流れです。これもわかります。

で、僕がよくわからないな。。。と思ったのはこの「ソルト」。

パスワードをDBに登録するときにランダムで生成される文字列と、ログインするときまたまたランダムで生成される文字列が同じになるわけないじゃん。。。と思ったわけです。少なくともそう読み取ってしまいました。

で、調べたんですね。

でも、「rails bcrypt」で検索しても出てくるのは使い方だけ。

中にはこういうのもありましたが、やはり異なるタイミングで生成されるはずの(←この時点でのも僕の理解はそうだった)ソルトが同じになる仕組みがわからない。。。

帰りの電車であちこちのサイトを探しましたが詳しいアルゴリズムに関する説明がどこにもない。

結局、bcrypt-rubyのレポジトリを見るしかない。。。と行き着き、最初にREADME.mdを読みましたが、まだわからない。。。

一応、以下のような仕組みの説明もしてくれているんです。。。でも肝心のソルトがどこからくるのかわからない。。。「ソルトはハッシュと一緒にDBに保存するぜ」ってどこだよ。。。

f:id:ke_takahashi:20181011232527p:plain

結局、ソースを読みました。構成ファイルも2,3個しかなく、ソースコードは短く読みやすいものでした。

ソースコードを読んでやっとわかりました。

ちょっと例を使って説明します。簡略化するため実際のbcrypt-rubyの文字数とは異なりますのでご了承ください。また、もし、理解が間違っていたら教えてください。

パスワードをハッシュ化するときの入力情報が以下とします。

パスワード:a
ソルト:A

このソルトとパスワードを連結してハッシュ関数に渡します。すると結果として"A123"が返ってきます。ハッシュ関数の答えは本来は"123"なのですが、ハッシュ関数に入力したソルトがわかるように"123"の前にソルトの文字列をつけて"A123"という文字列が返ってくるという寸法です。ここで僕の疑問は晴れました。

hash("A"+"a")  =>  "A123"

あとは、ログインするときに暗号化されたパスワード "A123" からソルト"A" を取り出し、入力されたパスワードが"a"だったら、ハッシュ化後のパスワードは"A123"になるので合致する。。。という感じです。

実装上はもっと込み入っているようです。bcrypt-rubyのドキュメントの例を使って説明してみます。

以下を実行すると、pに暗号化後のデータが入ったBCrypt::Passwordのインスタンスが生成されます。

p = BCrypt::Password.create("my password")

具体的には暗号文は以下のようになります(createメソッドを実行するたびにソルトが変わるので同じ文字列になることはありませんので、当然ですが。。。)。

$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

$が区切り記号で、2aがバージョン番号、10がコスト、ソルトは先頭から左から29番目の文字列(ピリオド)までの文字列のようです。コードによると。ただ「$2a$10$」は固定の文字列ですから本来の意味のソルトは29−7=22文字ということになります。残りはチェックサムと書かれていました。

で、このあと、上記の暗号文を入力として、ユーザが入力したパスワードと照合するのが以下のコードになります。

p2 = BCrypt::Password.new("$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa")

このnew(つまりinitializeメソッド)は以下のように書かれています。

@version, @cost, @salt, @checksum = split_hash(self)

そして、split_hashメソッドは以下。つまり、new()に与えられた引数の文字列からソルト(@salt)を取り出してセットしている感じですね。

    def split_hash(h)
      _, v, c, mash = h.split('$')
      return v.to_str, c.to_i, h[0, 29].to_str, mash[-31, 31].to_str
    end

このあと、ユーザが入力したパスワード(平文)と照合します。ユーザとしては以下のように書きます。

if  p2 ==  "my_password"
    照合成功!
end

これは文字列の照合をしているわけではなく、BCrypt::Passwordクラスに定義された == メソッドが実行されています。

    def ==(secret)
      super(BCrypt::Engine.hash_secret(secret, @salt))
    end

ここではsecretには==の右辺であるsecretに"my_password"が入りますので、"my_password"と上記の暗号文から取り出したソルト("$2a$10$vI8aWBnW3fID.ZQ4/zo1G.")の2つの引数をもとにハッシュ関数で計算した結果が返ってくるという感じです。

なるほど。。。ですね。

レインボーテーブルってのもついでに勉強しました。文字列に対するハッシュ値を予め計算しておいてテーブルにすると。でも、ソルトがあると、このソルトの文字列の組み合わせ数分だけテーブルが必要になり、膨大な大きさになる。。。ユーザが入力したパスワードが8文字だったとしてもソルト(上記の例では22文字も!!)分だけ長くすることができるので、レインボーテーブルも巨大になるっていうことですね。わかります。

ちなみに、このbcrypt-rubyの==メソッドをみて思ったんですが、平文(secret)は必ず右辺に来ないとダメですよね。。。

試しに左辺に持ってきて実行してみました。やはり結果はアウト(false)でした。

if   "my_password"  ==  p2
    照合成功!
end

Rails4ではこうした記述を自分で書かなければならなかったようですが、Rails5では==部分などの細かい実装は書かなくてもハッシュパスワードを利用できるようになっているようです。

わかっている人にとっては効率的だけどなぁ。。。初学者にとっては、なんか知らないけど「こう書けばいい感じにRailsがパスワードを暗号化してくれるんだぜ」っていう世界が広がっていって。。。益々教えにくいな。。。と思ったりしました。

ちょっと後半、オネムの時間になったので説明が粗くなりましたが。。。あとで読んで思い出せる程度の情報は残した感じで。。。

おしまい。ねよ。

傘とイヤホンは消耗品です。私にとって。

徒歩+電車+バス通勤なので、傘は必須です。

特に九州の(北海道ではないという意味)日差しは強いので男子ですが日傘も必須。

雨風を凌ぐのにイイ傘欲しいな、と以下みたいな傘を使っていたこともありましたが、半年くらいで壊れて。。。

兼用傘としてのSENZ - memorandums

で、以下の格安な傘で日傘男子デビュー?をしました。安かったですが、意外と持ちましたね。。。

さすがに裏地がひび割れてそろそろ交換だな。。。と思いながら、なんとかひと夏を越しました。

そして最近の台風。突然の雨もあるでしょう。

ということで傘をアプデ。いろいろ迷いましたが、以下にしました。ちょっと丈夫なやつがいいなと。あと雨に濡れないためにサイズも大きめのがいいな。。。と。

本日、到着したのですが、予想外に大きい。そして重い。小型のリュックにいれるには。。。しかたがありません。使ってみます。

ただ、自動開閉は面白いですね。でも、すぐコワレソウ。。。半年持てばいいな。

動画探したんですが。。。なかったので撮りました。YouTuberではありませんので。。。

youtu.be

で、もう1つ。

イヤホンです。

電車通勤には必須アイテムの1つですね。

3万円くらいのイヤホンを使っていたこともあるのですが、これも消耗品だと思いますし、音源がスマホですし聞く音楽もAmazon Musicくらいですのでそれほどこだわりがありません。

直近で使っていたのが以下で、分離型のイヤホンを初めて使ってみたやつでした。

これが最近、ブツブツ音が切れるようになり。。。ついに半分しか聞こえなくなり。。。買い換えないとなぁ。。。と。

Totemoi S2-01を購入直後にペアリングときにはまったので動画作った - memorandums

迷いに迷って以下にしました。これも今日届きました。

とりあえず5000円以下。消耗品としては許容範囲です。

早速、聞いてみようとスマホAndroid)に接続しようとしたら。。。認識しない。

あれ?これってケースから取り出したら自動的にペアリングされるってのがウリじゃなかったっけ?

この商品はBluetooth5.0、そしてスマホはまだまだ使っていますZenfone3です。スペックを見るとBluetooth4.2。

やっちまったか。。。?と思いましたが、とりあえずMacbookBluetoothで検索すると見れる?あれ?このMacbookも相当古いのに見つけられるってことは。。。下位互換なんだな。。。でもAndroidではダメ。

Android側でBluetoothを切り入りを繰り返しているうちに表示されました。

メデタシメデタシ。

意外と耳にフィットしていい感じです。少なくともTotemoi S2-01よりは断然いい。ちなみにTotemoi S2-01は付属のパッドが合わず、100均の耳栓でイヤピースを自作したり、最近は以下を使っていました。

https://www.yodobashi.com/product/100000001001467573/?gad1=&gad2=g&gad3=&gad4=56278881131&gad5=15623952785040755045&gad6=1o1&gclid=CjwKCAjwo_HdBRBjEiwAiPPXpAqPZSRiQs07BAgmbdeedc8CqIavJvT8Aq2PixUL94vHH7vSnVXJJRoCiWwQAvD_BwE&xfr=pla

でも、このイヤホンはイヤピースを別買いしなくてもいい感じです。僕にはフィットしています。

これを選択したのはスマホ充電器としても使用できるってところですね。

今回もベゾスさんに貢献しました😁