0
0

More than 1 year has passed since last update.

webpushのVAPIDでつかうapplicationServerKeyをrubyで作る

Posted at

概要

rubyにはwebpush用のgemが作られているので、webpushを使いたい人はそちらを使うことをお勧めします。
https://github.com/zaru/webpush
以下はあくまで趣味として作った内容を記載しています。

Webpushを行う際の、PushManager.subscribeに渡すapplicationServerKey。これを自分で作ってみたいなと思いました。
ここで生成してくれますが、やっぱどう作られてるかって気になりますし。

applicationServerKeyに渡す値は?

https://developer.mozilla.org/ja/docs/Web/API/PushManager/subscribe
プッシュサーバーがアプリケーションサーバーを認証するために使用する 楕円曲線 DSA P-256 公開鍵を含む、Base64 でエンコードされた DOMString または ArrayBuffer。指定した場合は、アプリケーションサーバーから発するすべてのメッセージで VAPID 認証スキームを使用しなければならず、また対応する秘密鍵で署名した JWT を含めなければなりません。この鍵は、データを暗号化するために使用する ECDH 鍵と同じではありません。詳しくは "Using VAPID with WebPush" をご覧ください。

Base64 でエンコードされた DOMStringとはURL SafeなBase64のことみたいです(それでうまくいったので)。

作成手順

まず楕円曲線暗号DSA P-256の鍵とのことなので、鍵を生成します。P-256とprime256v1は同じものの様です[参考]。

ec = OpenSSL::PKey::EC.new('prime256v1')
ec.generate_key

公開鍵は以下のように取り出せます。

public_key = ec.public_key

ここから先が困ったのですが、rubyのBase64.urlsafe_encode64に渡すためにbinaryにしなければなりません(なんとなくそのまんま渡したら怒られました)。
なんとなくpuckしたら行けるかなと思ったのですが、この公開鍵がとても大きな整数でした。

ec.public_key.to_bn.to_i
=> 60261393456883804897223332611535112895220851064492348957771298788553930859852980720330767505752023124297821596288685360429179926033825531665063484302731885

64bit符号なし整数とかでも全然足りなません。しょうがないので2進数表現経由で.pack('B*')で変換しました(もっといい方法がきっとある...)。

bitstring = ec.public_key.to_bn.to_i.to_s(2)
# => "10001111110100101111000111000110101001001110001100110100100110010101111001010010001000010001110110110110110001100111101001101100110110101001101111001110100010000011101000111100110000011001011001001101000001011000010011111100101111111101010110100111010011001000100000011101111000010000110000101111110110100001000001001101111101001110000001001101111101111001100101100100010001100100000010101010101001110011110110010110000101111000110001011001110111101100101101111000001000101011000001101110101111111101010101001101101"
# .pack('B*')は1byte毎に処理するので足りない分0を先頭に足す
bitstring = ('0' * (8 - (bitstring.length % 8))) + bitstring
# => "0000010001111110100101111000111000110101001001110001100110100100110010101111001010010001000010001110110110110110001100111101001101100110110101001101111001110100010000011101000111100110000011001011001001101000001011000010011111100101111111101010110100111010011001000100000011101111000010000110000101111110110100001000001001101111101001110000001001101111101111001100101100100010001100100000010101010101001110011110110010110000101111000110001011001110111101100101101111000001000101011000001101110101111111101010101001101101"
binary = [bitstring].pack('B*')
# => "\x04~\x97\x8E5'\x19\xA4\xCA\xF2\x91\b\xED\xB63\xD3f\xD4\xDEtA\xD1\xE6\f\xB2h,'\xE5\xFE\xAD:d@\xEF\ba~\xD0\x82o\xA7\x02o\xBC\xCB\"2\x05U9\xEC\xB0\xBCb\xCE\xF6[\xC1\x15\x83u\xFE\xAAm"
Base64.urlsafe_encode64(binary, padding: false)
# => "BH6XjjUnGaTK8pEI7bYz02bU3nRB0eYMsmgsJ-X-rTpkQO8IYX7Qgm-nAm-8yyIyBVU57LC8Ys72W8EVg3X-qm0"

上記で作成した文字列をapplicationServerKeyに渡すと無事エンドポイント情報などが帰ってきたので、たぶん成功だと思います。実際にpush通知を送るところまではまだ確認していません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0