Okada Hiroshi の blog

typo が多いです

zeit の now で Basic 認証付きで Web ページをデプロイするサンプルを作成しました。

ZEIT (ツァイト) という会社の Now という Pass があって node.js 等で作った API や静的ファイルを簡単にデプロイできます。

jpn.now.sh

(僕は有料プランにしていますが、無料でもそれなりに使えます。)

まったく何の認証もないページだと、ほぼ何にも考えなくてもデプロイできるのですが、Basic 認証をかけるにはサーバー側のコードを書く必要があり、一手間かかるので express を使ったサンプルを作ってみました。


https://now-node-express-basic-auth-example.hiroshi-okada.now.sh

(Basic 認証の ユーザー名は myid パスワードは mypassword に設定してあります。)

コードは github に置きました。

GitHub - HiroshiOkada/now-node-express-basic-auth-example: @now/node express basic auth example

basic 認証ですので、クリティカルな用途には向きませんが、最低限の認証をつけて web ページで情報を共有するには便利だと思います。(よく行くページの一覧とか)

Twitter の自動更新ブックマークレット

今日は小ネタを

Twitter の自動更新 ブックマークレット (Bookmarklet) です。ツイッターの Web ページの 「新しいツイート○件を見る」 が表示されていたらクリックして、広告は非表示にします。

  • Twitter のページを開いて読み込みが終わってからブックマークをクリックしてください。
  • スクロールして過去のツイートを見ているときは自動更新しません。
  • ブックマークレットをクリックする毎に自動更新 ON/OFF が切り替わります。
  • 自動読み込み時にはタイトルに🔃が表示されます。
  • 広告は非表示にしているだけで、内部的には読み込んでいます。

同様の機能をもった機能拡張もありますが、機能拡張用よりはブックマークレットのほうが安全性は高いし、起動していないときの負荷も少ないです。

2019-06-11 修正

  • コードを少し修正しました。(リロード中であるのをタイトルに🔃つけることにより表示)
  • コードをこの blog 書くのでは無く CodePen へのリンクとしました。(管理上の理由)

https (ssl) サーバーのサンプル

ローカルネットで開発する時に使用するワイルドカード SSL 証明書の取得方法の記事を書いたので、いくつかの言語で簡単な https サーバープログラムを記述しようと思います。 最近の言語は標準ライブラリや定番のライブラリが充実しているので簡単に https サーバーを書くことができます。

コンテンツ

なお、折角 https サーバーで配信するのですから、加速度センサーを使うサンプルコンテンツにしようと思います。

以下のように Android からアクセスするとスマホを回転させても頭が上でありつづけます。

残念ながら iOSバイスでは動作しません。 PC では API は使えるようですが物理的に加速度センサーがほぼ付いていないので使えません。 Accelerometer | MDN

とりあえず簡単のために index.html に JavaScriptCSS も書いてしまいました。 ( index.htmlpublic という名前のフォルダーに入れました。 )

<!DOCTYPE html>
<html lang="ja">

<head>

<meta name="viewport" content="width=device-width,initial-scale=1">
<meta charset="UTF-8">
<title>Stick figure</title>

<style>
#stick-figure {
  width: 50%;
  margin: 0 auto;
  transform: rotate(0rad);
  transform-origin: center;
}
#message {
  color: red;
  font-size: 2rem;
}
</style>

</head>

<body>

<svg viewBox="0 0 200 200" id="stick-figure">
  <g stroke="green" fill="none" stroke-width="5">
    <circle cx="100" cy="30" r="20" />
    <line x1="100" y1="50" x2="100" y2="110" />
    <polyline points="80,190 100,110 120,190" />
    <polyline points="40,75 100,65 160,75" />
  </g>
</svg>

<p id="message"></p>

<script>
const main = () => {
  const stickFigure = document.getElementById('stick-figure');
  const message = document.getElementById('message');

  if (!('Accelerometer' in window)) {
    message.innerHTML = 'no Accelerometer';
    return;
  }
  navigator.permissions.query({ name: 'accelerometer' }).then(result => {
    if (result.state !== 'granted') {
      message.innerHTML = result.state;
      return;
    }
    const acc = new Accelerometer({ frequency: 60 });
    acc.addEventListener('reading', e => {
      const { x, y } = acc;
      const rad = -Math.atan2(y, x) + Math.PI / 2.0;
      stickFigure.style.transform = `rotate(${rad}rad)`;
    });
    acc.start();
  });
};

main();
</script>

</body>
</html>

Ruby

標準のモジュールだけで完結したかったので WEBrick を使いました。 WEBrick モジュールだけで完結するので、リファレンス等が分かりやすかったです。 ( この辺は大クラス主義のおかげかもしれません。 ) 証明書と中間認証局は別ファイルにしないといけないようです。

#!/usr/bin/env ruby

require 'webrick'
require 'webrick/https'

port = (ENV['PORT'] || 8443).to_i

puts "port=#{port}"

httpd = WEBrick::HTTPServer.new({
  DocumentRoot: './public',
  BindAddress: '0.0.0.0',
  Port: port,
  Logger: WEBrick::Log.new(nil, level=WEBrick::BasicLog::WARN),
  SSLEnable: true,
  SSLCertificate: OpenSSL::X509::Certificate.new(File.open('./certs/cert.pem').read),
  SSLExtraChainCert: [OpenSSL::X509::Certificate.new(File.open('./certs/chain.pem').read)],
  SSLPrivateKey: OpenSSL::PKey::RSA.new(File.open('./certs/privkey.pem').read)
})

Signal.trap('INT') {
  httpd.shutdown
}

httpd.start()

Python

ssl.wrap_socket というのは Python 3.2 以上では非推奨で Python 3.7 からは禁止だそうです。 まずはじめに ssl context というのを作らなくてはいけないのですが、ドキュメントではクライアント側とサーバー側両方の解説があるので初心者にはわかりにくかったです。 しかもサーバー側を作る時に ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) とするのはチョッとした罠です。

あと、SimpleHTTPRequestHandler がカレントディレクトリからコンテンツを配信すること前提のようなので chdir するという汚いサンプルになってしまいました。

#!/usr/bin/env python3

from http import server
import ssl
import os

if __name__ == '__main__':
    address = ('0.0.0.0', 8443)

    context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    context.load_cert_chain('certs/fullchain.pem', 'certs/privkey.pem')

    os.chdir('public')
    httpd = server.HTTPServer(address, server.SimpleHTTPRequestHandler)
    httpd.socket = context.wrap_socket(httpd.socket)

    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        pass

    httpd.server_close()

Node.js

手抜きして express を使ってしましました。そのおかげで少ない行数で済んでいます。

#!/usr/bin/env node

const fs = require('fs')
const express = require('express')
const https = require('https')
const app = express()

const port = Number(process.env.PORT || 8443)

const options = {
  cert: fs.readFileSync('./certs/fullchain.pem'),
  key: fs.readFileSync('./certs/privkey.pem')
}

app.use(express.static('public'))

server = https
  .createServer(options, app)
  .listen(port, () => console.log(`start port=${port}`))

Docker (alpine + lighttpd)

プログラム言語ではありませんが、 Docker (alpine + lighttpd) でもやってみました。 lighttpd では鍵ファイルと証明書ファイルを連結する必要があるので起動時にやっています。

Dockerfile

FROM alpine:3.8

RUN apk --update add lighttpd && rm -rf /var/cache/apk/*

COPY ./public /var/www/localhost/htdocs

RUN cd /etc/lighttpd &&\
    sed -e '/^server.modules = (/a"mod_openssl",' \
        -e '/^# server\.port/aserver.port = 443' \
        -e '/^# ssl.engine/assl.engine = "enable"' \
        -e '/^# ssl.pemfile/assl.pemfile = "/etc/ssl/certs/server.pem"' \
        -e '/^# ssl.pemfile/assl.ca-file = "/etc/ssl/certs/chain.pem"'\
        --in-place \
        lighttpd.conf &&\
        echo -e '#/bin/sh\n'\
                'cat /certs/privkey.pem /certs/cert.pem > /etc/ssl/certs/server.pem\n'\
                'cat /certs/chain.pem >/etc/ssl/certs/chain.pem\n'\
                'chmod 600 /etc/ssl/certs/*.pem\n'\
                'lighttpd -f /etc/lighttpd/lighttpd.conf\n'\
                'sleep 1\n'\
                'tail -f /var/log/lighttpd/error.log -f /var/log/lighttpd/access.log\n' > /start.sh &&\
        chmod +x /start.sh

EXPOSE 443

CMD "/start.sh"

起動

$ docker build . -t <タグ名>
$ docker run --rm -it -p 443:443 -v "$(pwd)/certs:/certs:ro" --name <コンテナ名> <タグ名>

リポジトリ

なお、以上のスクリプトHiroshiOkada/https-example: https 静的サーバーサンプル に置きました。

今更ながらブックマークレット作成

ちょっとブックマークレットを作たくなったので、今更ながら作成ツールを作りました。

オンラインにはもっと高機能なものも溢れていますが、個人的にはほぼ ChromeFirefox しか使わないので、入力、出力される JavaScript 両方とも新しめな物にしたかったのと、自分のブログに貼っておれば後で探さなくても済むので、作成しました。

自動リロード

静的なサイトでも開発中には自動リロードして欲しいこともあるので、自動リロードするスクリプトを書いてみました。

poor man's autoreload

以下のスニペットを HTML 文書の head や body の内側に挿入すると 800ミリ秒ごとにHTML文書を(内部的に読み込んで)変化があったらリロードします。

<script src="https://cdn.rawgit.com/HiroshiOkada/6344f094955f3fc31deeffeec2718ff6/raw/4578f0948fa86cff08302a43aea1d913798ce23f/poor-mans-autoreload.js"></script>

追記

10分間変化がなかったらチェックを停止するようにしました。

追記 (2018-10-14)

使っていた RawGit というサービスが終了するので、gist でなく github page を使うことにしました。上記の代わりに以下を使ってください。

 <script src="https://hiroshiokada.github.io/shortcodes/poor-mans-autoreload.js"></script>

RawGit が終了するそうです。 - Okada Hiroshi の blog

markdown-it のプラグインを書いてみました

nodejs の有名な Markdown パーサの markdown-it で 出力される html のエレメントタイプごとに class 属性を追加したかたので

www.npmjs.com

というプラグインを書いてみました。

markdown-it の内部構造はよくわかっていないので、他のプラグインのコードを参考に書きましたが、パフォーマンス等は悪いと思います。

$ npm install markdown-it @toycode/markdown-it-class --save-dev

みたいにインストールして

const MarkdownIt = require('markdown-it')
const markdownItClass = require('@toycode/markdown-it-class')
 
const mdText = '# テスト文書\n## サブタイトル\n今日は良い*天気*です'
const mapping = { h1: ['title', 'is-4'], h2: 'subtitle', em: 'tag' }
const md = MarkdownIt().use(markdownItClass, mapping)
console.log(md.render(mdText))

<h1 class="title is-4">テスト文書</h1>
<h2 class="subtitle">サブタイトル</h2>
<p>今日は良い<em class="tag">天気</em>です</p>

のようにクラスが付加できます。

EDINET から有価証券報告書・取引報告書をダウンロードしてくる CLI ツールを(node.jsで)作成しました。

株式投資をしていると、有価証券報告書を読んで分析する必要があります。

日本の会社の有価証券報告書は、EDINET という所からダウンロードできるようになっているのですが、 SSL 証明書が 政府認証基盤(GPKI) なので、ブラウザーによっては認証局を追加しないと警告がでたりして面倒です。

そのそも Webサイトをブラウザーで開いて、検索して、ダウンロードボタンを押してと、結構手間がかかって面倒くさいです。

もちろん探すと、いつくつかそれを簡単にできるようにしてあるサイトやサービスがあるのですが、どれも本格的すぎて今ひとつ僕の要求とは一致しませんでした。

そこで node.js でコマンドライン証券コード又は EDINET で指定しただけで、簡単にダウンロードできる CLI コマンドを作りました。

EDINETでは、平成31年3月下旬からEDINETに提出された書類を取得するAPI(EDINET API)の提供を予定しています。

ということで、それ以降だと、簡単に API を呼び出して書類を取得できそうですが、今はまだできないので

github.com

を利用して、ごりごり スクレイピング をすることにしました。

一応 npm として公開してあるのでもしよろしけば使ってみて下さい。

インストール方法

  • Node.js は 8.11 以上のものをインストールしてください

開発は、 ubuntu デスクトップ上で、10.8.0 Current で開発しています。

動作確認は Windows Server 2016 と macOS High Sierra でも行っています。

  • コマンドをインストールします。

グローバルではなくて適当なディレクトリを作ってそこに入れた方が良いでしょう。

$ mkdir 適当なディレクトリ
$ cd 適当なディレクトリ
$ npm i @toycode/getufo

使い方の例

$ npx getufo はてな
E32141, 39300, 株式会社はてな, カブシキガイシャハテナ, Hatena Co., Ltd
$ npx getufo E02144
$ npx getufo 7832
  • 引数を何も与えないとヘルプを表示します。
$ npx getufo

  Usage: getufo [options] <codes>

  Download financial statements from EDINET.

  Options:

    -v, --version          output the version number
    -f, --folder [folder]  Set download folder (default: current working directory)
    -n, --numpdf [num]     How many pdf files to download (default: 4)
    -h, --help             output usage information


    Codes are either security codes, EDINET codes or fund codes.

  Extra:
    Enter a part of the company name instead of the code to display
    a list of codes. (In this case, nothing is downloaded.)

リンク

www.npmjs.com

GitHub - HiroshiOkada/getufo: Download securities reports from EDINET

以上です。