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

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

Webpushを行う際の、[PushManager.subscribe](https://developer.mozilla.org/ja/docs/Web/API/PushManager/subscribe)に渡す`applicationServerKey`。これを自分で作ってみたいなと思いました。
[ここ](https://web-push-codelab.glitch.me/)で生成してくれますが、やっぱどう作られてるかって気になりますし。

# 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は同じものの様です[[参考](https://adiary.adiary.jp/0391#webpush%e3%82%92%e5%ae%9f%e8%a3%85%e3%81%99%e3%82%8b%e3%81%9f%e3%82%81%e3%81%ae%e6%89%8b%e9%a0%86)]。

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

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

```ruby
public_key = ec.public_key
```

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

```ruby
ec.public_key.to_bn.to_i
=> 60261393456883804897223332611535112895220851064492348957771298788553930859852980720330767505752023124297821596288685360429179926033825531665063484302731885
```

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

```ruby
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通知を送るところまではまだ確認していません。