Webページ仕様

これのこと → https://sigcoww.org/

Sinatraで作ったWebサイト。 ページ配信、電子書籍配信とかやっている。

開発

機能の詳細を述べる前に、開発方法を述べておく。

こいつは、dokkuで動く(dokkuはlrksが個人的に借りているVPSで動いている)。 以下の設定を ~/.ssh/config に書けば $ git clone ssh://sigcoww.org/home/sigcoww/.repo/docs でソースコードが見える、masterブランチへのcommit/pushによって自動的にコンテナが立ち上がってなんちゃらやってくれる。

Host sigcoww.org
  #HostName sigcoww.org
  User sigcoww
  Port 25252
  IdentityFile (GitHubに登録してある鍵)

サーバ側では、GitHub Organizationを基にSIGCOWWメンバーの公開鍵を取ってきて、authorized_keysに入れている。 当然、GitHubに有効な鍵が登録されていなければサーバにアクセスできない。 また、取得はcron.dailyによる1日1回のみ。 そのためタイミング次第ではアクセスできないこともあるが、しばらく待つ。

環境変数には、「定期実行モノ」(後述)用にpixivやcircle.msの認証情報が含まれる。 たとえば、ENV['SLACK_TOKEN']は「売れさせば富さ」のIncoming Webhooks用URLである。 こういった感じの環境変数を外部に見せるようなコードは書かないでほしい。

ちなみにローカルでの開発はこんな感じになる。

$ bundle install --path vendor/bundle --without production
$ bundle exec rackup config.ru -o 0.0.0.0

機能詳細

ここから機能の詳細を述べる。

ページ配信

  • ./data/posts/HOGE.md/HOGE.html として配信
    • 一応、 ./data/posts/FUGA/PIYO.md/FUGA/PIYO.html として配信される…ようになっている…はず…だったかも…知れません。
  • 文章、というかコンテンツ部分のMarkdownをべた書きすれば、いい感じの位置に入る
    • 見出しのレベルは、h2から始める
    • titleは別途設定できるので
    • Markdown中のHTMLはそのまま出る
    • あと、vmg/redcarpetによるMarkdownなので、普段とは少し違うかもしれない。
  • Jekyll なんかで使われる YAML front matter に対応
    • titlebreadcrumb が設定設定できる

./data/posts/index.md./data/posts/docs.md./data/posts/link.md に実際の例あり。 ちなみに、この3つに関して app.rb には / /docs/ /link/ でも見えるように特別な処理が含まれますが、気にしなくて良いです。

電子書籍配信

  • ./data/book/HOGE/meta.yml の内容から、書籍一覧 /book/ と詳細ページ /book/HOGE/ を配信
  • /data/book/HOGE/version-FUGA/book.(pdf|epub|diff) のデータを利用
    • ./public/images/book/HOGE-cover.png の画像も利用する
  • ダウンロードの認証時、ダウンロード時にはログを取る
  • 感想フォームの受け取りもする
meta.ymlの書き方
title: "タイトル"
date: 2017-01-23              # 発行日
price: 500                    # 頒布価格
size: "B5"
ext: "jpg"                    # 表紙画像の拡張子。デフォルトは "png"
page: 40                      # 本文 + 4P
booth: "http://example.com/"  # リンクを貼る。省略可能。
zin: "http://example.com/"    # リンクを貼る。省略可能。
message: |
  なんかこういう書き方をすると、ヒアドキュメントになるそう。
  ここはMarkdownで書ける。ページ配信と同様に、HTMLタグは<strong>そのまま出力</strong>される。

files:
  - id: v1.0                  # ./data/book/HOGE/v1.0/book.(pdf|epub|diff) を見せる
    date: 2017-01-23          # 公開日
    message: "ここもHTMLにそのまま出力"
  - id: v1.1                  # files:は古い順。dateは見ない。ここではv1.0が古く、v1.1が新しい
    date: 2017-01-30
    message: "ここはMarkdown無効。HTMLは<strong>そのまま</strong>出る。"

keys:
  - "HASH:SALT"               # 詳細は後述
  - "HASH2:SALT2"

keysについては、こんな感じで作成します。

  1. I have a DOWNLOAD_CODE
  2. I have a SALT
  3. Ah...! DOWNLOAD_CODE + SALT
  4. これをSHA256でハッシュ
  5. もう一度SHA256でハッシュ
  6. 5.を22回繰り返す

ソルトを振ってストレッチング、です。bashで作る場合はこうです。

# 手入力を想定し l I q 9 O 0 Q は抜いておく
CODE=`dd if=/dev/urandom count=10 bs=512 2>/dev/null | tr -dc "12345678abcdefghijkmnoprstuvwxyzABCDEFGHJKLMNPRSTUVWXYZ" | cut -c -8`
SALT=C91`dd if=/dev/urandom count=10 bs=512 2>/dev/null | tr -dc "[:alnum:]" | cut -c -32`

A=`echo -n ${CODE}${SALT} | sha256sum | cut -d' ' -f1`
for i in `seq 1 22`; do A=`echo -n $A | sha256sum | cut -d' ' -f1`; done

echo "Download code ..." $CODE
echo "KEY ..." "${A}:${SALT}"

このとき、KEYは8文字以上、SALTは32文字以上が良いと思いました。

ファイルの配置
  • 表紙画像を置く
    • ./public/images/book/HOGE-cover.ext
    • 特にこだわりがなければ、640px * 903px 程度で
    • アスペクト比は構わない
    • tinypng/mozjpeg とかその辺で最適化しておくと嬉しい
  • 電子書籍ファイルを置く
    • /data/book/HOGE/version-FUGA/book.pdfbook.epub
    • 最低どちらか1つ。もちろん、両方あっても良い。
  • 前バージョンとのdiffファイルを置く
    • /data/book/HOGE/version-FUGA/book.diff
    • 別に無くてもOK
    • 執筆リポジトリにて git diff v1.0 v1.1 --ignore-blank-lines -w --relative=src --diff-filter=MAD --no-color みたいな感じで取る
ログ取り
  • ログを取る
    • リレーショナルなDBにそのまま突っ込む
    • もともとHerokuで使いたかったためにこうした
    • syslogとかにしようと思ったけど、定期実行モノで読むときにSQLが使えると便利…なので残した
  • 取得内容
    • DLコード入力時のログ
    • 本のID ... ./data/book/HOGE/HOGE
    • リモートホストのIPアドレス
    • 認証成功 or 失敗フラグ
    • 認証に使われたキーのソルト or 認証失敗なら入力値そのまま
    • ダウンロード時のログ
    • 本のID
    • リモートホストのIPアドレス
    • バージョン ... ./data/book/HOGE/version-FUGA/version-FUGA
    • ファイル名 ... ./data/book/HOGE/version-FUGA/book.pdfbook.pdf
    • 認証に利用したキーや、リモートホストの情報を取っているのは不正防止のため
    • 異常なアクセスがあった場合にあとで検証する
感想フォーム
  • 感想フォームを置いている
  • 内容はSlackの#ciに通知する
    • 心臓に悪い内容が来たら困るので、Base64でエンコードする
  • 内容には以下も含む
    • リモートホストのIPアドレス
    • 認証済みか否か
その他
  • meta.ymlfiles: とか書いていなくても見れる
    • 認証が成功していて、ファイルが存在している場合に限る
    • book.(pdf|epub|diff) 以外のファイル名でも可能
    • ただし、リンクは貼られない
    • 貼りたければ、message とかで頑張る
    • *.diff は、整形され、HTMLとして配布される
    • ただし、ページタイトルは常に version-FUGA での変更点 となる

定期実行モノ

tasksディレクトリにある何か

report.rb

  • 日報
  • 昨日の出来事を Slack #ci チャネルへ通知
    • 「コミケWebカタログ」と「技術書典」のお気に入り登録数
    • BOOTH売上金額
    • ウェブサイトでの電子書籍ダウンロード数・認証数の統計
    • sigcoww@sigcoww.org に届いたメール
  • dokkuのcrontabによって0:00に実行される
    • dokkuがdockerを実行する際、cronでは-itを付けない、それ以外では付けるというhas_ttyのチェックが謎
    • cronで実行しても-itが付いて、TTYがないと言われる
    • なので、dokku runコマンドを改変して、has_ttyチェックをすっ飛ばした

mail.rb

  • メール(後述)が来たらSlackに流す
  • 1日1回起動して、IMAP(+IDLE)で読む
    • 運が悪いと、1日以上遅延する

メール

これ → sigcoww@sigcoww.org

さくらのメールボックスで運用されている。 ドメイン20個まで料金が同じなので、個人的なメールアドレスと同居させている。