WebコンテンツのDark Modeについて

WebコンテンツのDark Modeの情報が全然ない。まぁ、まだ仕様策定中で実装してるのがmac版のsafariだけなので仕方ないのだが。

Safari以外の状況は以下のような感じ。

ChromeはWork In Progress。FirefoxはNightlyバージョンで一部実装済み。

supported-color-schemes / color-schemeプロパティ

利用するカラースキームの設定。darkを設定しておくとDark Mode時にはDark Mode用のデフォルトスタイルシートが適用されるようになる。

フォームのボタンやプルダウン等もDark Mode用のものに切り替わるのが地味にありがたい。

macsafari 12.1ではsupported-color-schemesという名前で実装されているが、次のバージョンでcolor-schemeに改名される予定。Firefox Nightly (68.0) では未対応

:root {
  supported-color-schemes: light dark;
  color-scheme: light darkl;
}

当初はmeta tagとして実装される予定だったらしいが、CSSプロパティとして実装されるようだ。

https://github.com/whatwg/html/issues/4504

prefers-color-scheme メディアクエリ

今dark mode対応についてググると出てくるのは大体これに関する情報。Dark Mode時に適用されるスタイルを指定できる。

現状macsafari 12.1とFirefox Nightly 68.0以降で動作する

@media (prefers-color-scheme: dark) {
  html {
    color: #fff;
    background-color: #000;
  }
}

@media (prefers-color-scheme: light) {
  html {
    color: #000;
    background-color: #fff;
  }
}

メディアクエリなのでlinkタグにも設定可能

Node v12でTLS v1.3を試す

先日リリースされたNode v12はTLS v1.3に対応しているらしい。というわけで早速試してみた。

サーバ証明書の作成

まずテスト用に自己署名サーバ証明書を作成する。ここでは楕円曲線secp521r1*1のecdsaの秘密鍵を作成した。鍵を作成できるサブコマンドは何種類かあるようだが、今は genpkey サブコマンドが推奨されているらしい。

openssl genpkey -algorithm EC -out server.key -pkeyopt ec_paramgen_curve:secp521r1

次に作成した秘密鍵からCSRを作成する。各種パラメータの入力を求められるが、Common Name を localhost として、それ以外は適当に入力しておく。

openssl req -new -key server.key -out server.csr

CSRに自己署名する。自己署名の場合 -signkey で秘密鍵を指定するらしい。

openssl x509 -req -signkey server.key -days 30 -sha256 -in server.csr -out server.pem 

server.pemが証明書、server.keyが秘密鍵

テストサーバ実装

Node.jsでTLS v1.3対応のhttpsサーバを書く。ドキュメントのサンプルコード通りで問題ないが多少手を加えている。

const https = require("https");
const fs = require('fs');

const options = {
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.pem'),
  maxVersion: 'TLSv1.3',
  minVersion: 'TLSv1.3',
  ciphers: 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256'
};

https.createServer(options, (req, res) => {
  res.writeHead(200, {"Content-Type": "text/html"});
  res.end('<html>Hello TLS 1.3</html>\n');
}).listen(8443, (err) => {
  if (err) {
    console.log(err);
    process.exit(1);
  }
  console.log("listen 8443")
});

optionsのkeyに先ほど作成した秘密鍵、certにサーバ証明書を指定する。TLSv1.3のみで接続するため、maxVersionとminVersionにTLSv1.3を指定する。minVersionのデフォルトはTLSv1.2、maxVersionはTLSv1.3らしい。ciphersには以下の3つの暗号スイートを指定した。TLS v1.3で使用できるのはこの3つしかない。

  • TLS_AES_256_GCM_SHA384
  • TLS_CHACHA20_POLY1305_SHA256
  • TLS_AES_128_GCM_SHA256

CHACHA20_POLY1305という暗号はあまり聞きなれないが、暗号界隈のスーパーヒーロー、ダニエル・バーンスタインが開発し、Googleが一押ししているストリーム暗号である。

接続

最新のFirefoxChromeSafariで使えない楕円曲線で証明書を作ってしまったのでFirefoxのみ・・・)であればTLS v1.3で接続できるが、ブラウザで見ても違いがわからないのでopensslコマンドで接続

openssl s_client -connect localhost:8443 -tls1_3

以下のような出力があり、TLSv1.3で接続できているらしいことが確認できる

Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384

上記コマンドはTLSハンドシェイクしか行わず、HTTPリクエストは送られていない。入力待ちになっているのでGET / とタイプし、改行を2回打ってHTTPリクエストを送ろう。

GET /

HTTP/1.1 200 OK
Content-Type: text/html
Date: Sun, 28 Apr 2019 16:55:36 GMT
Connection: close

<html>Hello TLS 1.3</html>
closed

HTTPレスポンスが得られました。

*1:ChromeSafariはsecp521r1をサポートしていないためエラーになります。prime256v1, secp384r1で作成すると接続できます