未分類

概要

apache2.2で.htaccessしか使えない状況での設定で手間取りましたが、VALUE-SERVERでgitリポジトリを公開することが出来たので、その方法を記事にしました。本来こういう用向きはGitHubでいいのですが、やっぱりやってみたいでしょ?

なお、今回はgitコマンドで扱えるhttpsのリポジトリを作成するところまでで、WebUIの設定は次回予定です。

設定の検討

今回はGitのマニュアルをベースに設定を検討していきます。

Smart HTTPで公開

Git – Smart HTTP

Gitのリポジトリ公開方法は、2020年1月31日現在、gitプロトコル、ssh、httpの3種類で、httpはさらにdum/smartの2種類に分かれます。gitプロトコルはVALUE-SERVERでは使えないし、sshだと公開してもVALUE-SERVER上ではアカウント作れないので自分しか使えません。 今回はhttpのより洗練されたsmartで公開する、ということです。

Apache自体のインストール

マニュアルではここからやっているのですが、これはVALUE-SERVERでは出来ません。

$ sudo apt-get install apache2 apache2-utils
$ a2enmod cgi alias env rewrite

https://git-scm.com/book/ja/v2/Git%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC-Smart-HTTP

最初に行っているのはdebian系Linuxでのapache2とapache2-utilのインストールです。apache2相当は絶対にインストールされてます。apache2-utilは、恐らくhtpasswdコマンドをインストールするためだと思うので、これはVALUE-SERVERにも入っており、問題ありません。

次に行っているのは、mod_cgi、mod_alias、mod_env、mod_rewriteなどのモジュールの有効化です。これらもVALUE-SERVERで有効になってます。apachectl -Mで確認できるので、気になる人はやってみてください。

つまりApache自体のインストールについては、すでにやってあるので問題ないということです。

gitリポジトリの所有グループ変更

次にやってるのはリポジトリ内のファイル・ディレクトリの所有グループ変更です。

$ chgrp -R www-data /opt/git

https://git-scm.com/book/ja/v2/Git%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC-Smart-HTTP

これはapacheからリポジトリを読み書きするために必要なことなのですが、VALUE-SERVERの設定では、ユーザーが扱える$HOME/public_html/*のファイルを実行するときにユーザーのアカウントで実行されるため設定の必要がありません。逆に言うとWebから自分のアカウントで出来ることは何でも出来るということなのですが…そういうセキュリティのプランなのです。

Apache の設定

いよいよ本題に近付いてきました。マニュアルで次に記載があるのは、httpd.confとかapache2.confやその分散された設定ファイルの内容です。これはディストリビューションごとにファイル名やディレクトリ構成が違いますが、そもそも管理者権限のないレンタルサーバでは変更できない部分です。

SetEnv GIT_PROJECT_ROOT /opt/git
SetEnv GIT_HTTP_EXPORT_ALL
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/

https://git-scm.com/book/ja/v2/Git%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC-Smart-HTTP

これらは、ユーザーが唯一編集可能な設定ファイルである、.htaccessで記述する必要があります。内容とともに解説すると…

SetEnvは環境変数を設定するもの(ディレクティブ)です。ここではGIT_PROJECT_ROOT(リポジトリの場所)とGIT_HTTP_EXPORT_ALL( GIT_PROJECT_ROOT以下のリポジトリを全て公開する意思表示)を設定しています。これらは.htaccessに記載が可能であり、またVALUE-SERVERではOverrideが許可されている(つまり普通に使える)ので問題ありません。

ScriptAliasは、スクリプトの位置とURLの紐付けを行うもの(ディレクティブ)です。これは.htaccessには記載できないので、代替手段が必要になります。

ScriptAliasの代替

今回の設定は、URLパスとして/git/以下でアクセスされた場合に、/usr/lib/git-core/git-http-backendが処理をし、環境変数PATH_INFOに/git/をルートとしたパスが入るということを意味します。git-http-backendはgitパッケージに付属するコマンドで、VALUE-SERVERにも /usr/libexec/git-core/git-http-backend に入っています。ユーザーがWebから直接 git-http-backend を処理させる手段はありませんが、CGIスクリプトから呼び出すことは可能です。ということはつまり、$HOME/public_html/ドメイン/git ディレクトリの.htaccessに以下の記述を入れて、

AddHandler cgi-script .cgi

git-http-backend.cgiという名前で

#!/bin/sh
/usr/libexec/git-core/git-http-backend

とすれば、 URLパスとして/git/git-http-backend.cgi/以下でアクセスされた場合に、/usr/libexec/git-core/git-http-backendが処理をし、環境変数PATH_INFOに/git/git-http-backend.cgi/ をルートとしたパスが入る、を実現できます。

BASIC認証の設定

マニュアルで次に行っているのはBASIC認証の設定です。

RewriteEngine On
RewriteCond %{QUERY_STRING} service=git-receive-pack [OR]
RewriteCond %{REQUEST_URI} /git-receive-pack$
RewriteRule ^/git/ - [E=AUTHREQUIRED]

<Files "git-http-backend">
    AuthType Basic
    AuthName "Git Access"
    AuthUserFile /opt/git/.htpasswd
    Require valid-user
    Order deny,allow
    Deny from env=AUTHREQUIRED
    Satisfy any
</Files>

解説

  1. Rewriteを有効にします
  2. URLのクエリ文字列(?以降の部分)が"service=git-receive-pack"である場合、もしくは
  3. URLのパス文字列が"/git-receive-pack"で終わっている場合
  4. URLのパス文字列が"/git/"で始まっているなら環境変数AUTHREQUIREDを設定する
  5. ファイルシステム内のファイル名がgit-http-backendである場合
    1. 認証方式をBASIC認証とする
    2. realmを"Git Access"とする
    3. BASIC認証のパスワードを/opt/git/.htpasswdから読むものとする
    4. ユーザーの認証を「必要」とする
    5. 全てを許可した上で、Deny処理→Allow処理の順で処理する
    6. 環境変数 AUTHREQUIRED が設定されていたらDenyする
    7. Allowされているか、「必要」を満たせばアクセスを許可する

つまり git-http-backendで処理するケースでは、「URLのクエリ文字列(?以降の部分)が"service=git-receive-pack"である」か「URLのパス文字列が"/git-receive-pack"で終わっている」場合はBASIC認証を要求し、それ以外の場合は無条件にアクセスを許可するという設定。ようはgit cloneやpullなど読み取りは無条件アクセスで、git pushなど書き込みはBASIC認証を付けたいということ。

VALUE-SERVERでの対応検討

この部分は全て.htaccessに記述可能です。しかし、VALUE-SERVERのapache2.2では期待したとおりに機能しません。理由は以下の記事のとおりです。

ようは、適用順番のせいで「環境変数 AUTHREQUIRED が設定されていたらDenyする」が機能しないということなので、常に「無条件にアクセスを許可するという設定」になってしまいます。さすがに認証なしで無制限に書き込みが出来てしまったら何が起きるか分かりません(デフォルトでは無条件にアクセスしても書き込みはエラー(403)になりますが)。

RewriteでダメならSetEnvIfではどうか?

Rewriteは主にリダイレクトや、読み替え、つまりURLの書き換えに似た機能です。しかし、今回はURLの書き換えは行っておらず、HTTPリクエストのパラメータを解析してBASIC認証の必要判定を環境変数に入れたいだけです。であれば、SetEnvIfでも出来そうな気がしますが…しかしSetEnvIfではQUERY_STRINGパラメータを扱えません。今回の用件では使用できないということです。

じゃあQUERY_STRINGを使わない方法はないの?

ありました。

If you do not have mod_rewrite available to match against the query string, it is sufficient to just protect git-receive-pack itself, like:

https://git-scm.com/docs/git-http-backend
<LocationMatch "^/git/.*/git-receive-pack$">
 AuthType Basic
 AuthName "Git Access"
 Require group committers
 ...
</LocationMatch>

BASIC認証をするタイミングは遅れますが、これでもpushなど書き込みに制限付けられます。ただし、

In this mode, the server will not request authentication until the client actually starts the object negotiation phase of the push, rather than during the initial contact. For this reason, you must also enable the http.receivepack config option in any repositories that should accept a push. The default behavior, if http.receivepack is not set, is to reject any pushes by unauthenticated users; the initial request will therefore report 403 Forbidden to the client, without even giving an opportunity for authentication.

https://git-scm.com/docs/git-http-backend

遅れた分のアクセスはデフォルトだとエラーになるので、 git-http-backendには「認証してなくてもエラーにしない設定」(http.receivepack)にする必要があります。apacheが許可したらOKということです。

ただURLとのマッチングを行うLocationMatchセクションは.htaccessでは使用できません

解: LocationMatchをSetEnvIfで置き換える

こうしてしまえばいいのです。

SetEnvIf Request_URI "/git-receive-pack$" AUTHREQUIRED=yes
AuthType Basic
AuthName "Git Access"
Require group committers
...
Order deny,allow
Deny from env=AUTHREQUIRED
Satisfy any

これが今回使用した方法の骨子になります。

パスワードの設定

マニュアルの続きです。htpasswd -c パスワードファイル ユーザー名 して、パスワードファイルを作成して認証可能なユーザーを1人作ってるだけです。 htpasswdの使い方はそこら中にあるので各自で調べてください。

実際の設置方法

URIのベースとなるディレクトリを決めて作成

マニュアルだと/git/になっていた部分ですね。そのまま使うと悪戯されそうなので、ちょっと変えました。

$ cd $HOME/public_html/(ドメイン名)/
$ mkdir gitrepos

.htaccessの設置

$HOME/public_html/(ドメイン名)/gitrepos/に以下の.htaccessを置きました。

SetEnv GIT_PROJECT_ROOT (ホーム)/(リポジトリの設置場所)
SetEnv GIT_HTTP_EXPORT_ALL
AddHandler cgi-script .cgi

SetEnvIf Request_URI "/git-receive-pack$" AUTHREQUIRED=yes

Order Deny,Allow
Deny from env=AUTHREQUIRED
AuthType Basic
AuthName "Git Access"
AuthUserFile (ホーム)/(リポジトリの設置場所)/.htpasswd
AuthGroupFile /dev/null
Require valid-user
Satisfy Any

CGIスクリプトの設置

$HOME/public_html/(ドメイン名)/gitrepos/に以下のgit-http-backend.cgiを置きました。

#!/bin/sh
/usr/libexec/git-core/git-http-backend

実行可能属性を付けておきます。

$ cd $HOME/public_html/(ドメイン名)/gitrepos/
$ chmod u+x git-http-backend.cgi

gitリポジトリの作成

このディレクトリはセキュリティ上の理由から、$HOME/public_html/(ドメイン名)/ 配下には置きません。ここでは $HOME/(リポジトリの設置場所)/に複数のリポジトリを置くものとし、今回はsample1という名前のリポジトリを作成します。

$ mkdir -p $HOME/(リポジトリの設置場所)
$ cd $HOME/(リポジトリの設置場所)
$ mkdir sample1
$ cd sample1
$ git init --bare
$ git config http.receivepack true

最後のコマンドが、「認証してなくてもエラーにしない設定」をしています。今回の認証方式を使う場合は、公開リポジトリを作成する度に必要な操作になります。

パスワード認証ファイルの作成

$ cd $HOME/(リポジトリの設置場所)
$ htpasswd -c .htpasswd ユーザー名
$ chmod og-rwx .htpasswd

ユーザーは必要な数だけ作成してください。VALUE-SERVERでは、パスワード認証ファイルは自分以外読めない設定で十分です。

最後に

BASIC認証はパスワードが暗号化されません。必ずhttpsでアクセスするようにしてください。

公開リポジトリへの接続確認

早速リポジトリにアクセスしてみます。

$ git clone https://(ドメイン名)/gitrepos/git-http-backend.cgi/sample1
Cloning into 'sample1'...
warning: You appear to have cloned an empty repository.
$ 

取得成功したようです。それでは適当に何かcommitしてpushしてみます。

$ cd sample1
$ touch hoge
$ git add .
$ git commit -m "initial commit."
[master (root-commit) 23b1fde] initial commit.
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 hoge
$ git push origin master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 205 bytes | 205.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
Username for 'https://(ドメイン名)': (htpasswdで設定したユーザー名)
Password for 'https://(ユーザー名)@(ドメイン名)': (htpasswdで設定したパスワード)
To https://(ドメイン名)/gitrepos/git-http-backend.cgi/sample1
 * [new branch]      master -> master
$

pushの途中でちゃんとBASIC認証が入り、pushできました。

→成功


2021/6/15 追記

現在はVALUE SERVERからConoHa VPSに移行し、SmartGitによるhttpsでのリポジトリ公開はしておりません。代わりにGiteaで公開しています。

未分類

前回の Apache設定ファイルのSetEnv/SetEnvIf適用順番 と似たような記事です。

確認したいこと

VALUE-SERVERの現行Apache 2.2の.htaccessで、RewriteRuleとDenyの適用順番を確認したい

実験

まずはやってみる

.htaccess

RewriteCond REMOTE_ADDR .*
RewriteRule .* - [E=HOGE:deny]
Order Deny,Allow
Deny from env=HOGE

解説

  1. クライアントのIPアドレスが正規表現で.*であるかどうか?=全てに一致するので、常に条件を満たす
  2. .htaccessの置いてあるディレクトリ部分を除いたURLのパス指定部分が正規表現で.*である部分(つまり全て)を無変更とし、環境変数HOGEに値denyを設定する
  3. Orderはまず全てをAllowとした上で、Deny処理を適用後に、Allow処理を入れるという宣言
  4. 環境変数HOGEが設定されていたら全てDenyとする

つまり、記述された順番どおりに適用されるなら、全て403 Forbiddenにするという設定

結果

こちら(VALUE SERVER上なのでConoHaに移行した現在はない)に上記.htaccessを置いたが、200 OKで見えてしまっていた。RewriteRuleの適用順序がDenyよりも遅い可能性が高まった。

RewriteRuleで環境変数を設定できていることの確認

.htaccess

RewriteCond REMOTE_ADDR .*
RewriteRule .* - [E=HOGE:deny]
Header set X-Frame-Options %{HOGE}e env=HOGE

解説

前回記事とあわせて全て説明されているので詳細は省略。環境変数経由でHTTPレスポンスヘッダX-Frame-Optionsにdenyを設定している。

結果

こちら(VALUE SERVER上なのでConoHaに移行した現在はない)に上記.htaccessを置いたが、Chromeの開発者ツールのネットワークで、以下のレスポンスが確認できた。

HTTP/1.1 200 OK
...
X-Frame-Options: deny
...

つまり、RewriteRuleの記述に問題はない→最初の実験の設定では、RewriteRuleより先にDenyが評価されている。

DenyをFilesMatchセクションに置いたら、評価が遅くならないか確認

.htaccessで置けるセクションとしてはFileかFilesMatchだと思うので、その条件で最初の実験を再確認する。

.htaccess

RewriteCond REMOTE_ADDR .*
RewriteRule .* - [E=HOGE:deny]
<FilesMatch ".*">
Order Deny,Allow
Deny from env=HOGE
</FilesMatch>

解説

FilesMatchは、ファイルシステムベースでのファイル名でマッチングをかけるセクション。このケースではどんなファイル名でも該当する。なので最初の実験と内容は同じ。

結果

こちら(VALUE SERVER上なのでConoHaに移行した現在はない)に上記.htaccessを置いたが、最初の実験同様見えてしまっている。こう書いてもRewriteRuleの適用順序がDenyよりも遅い 。

結論

VALUE-SERVERの現行Apache 2.2の.htaccessでは、Deny→RewriteRuleの順で適用される。

※Apacheが2.4だったり、server configに記載された場合などは確認していない

未分類

2020年1月30日現在、ココVALUE-SERVERで使用されているapache2.2(古い)で.htaccessを使っていろいろな設定が出来る。出来るけど、その設定には適用順番があるって話(2.4でも同様)。

事の発端

SetEnv HOGE "deny"
Order Deny,Allow
Deny from env=HOGE

この.htaccessが置かれたディレクトリが見えてしまう。論より証拠がこちら(VALUE SERVER上なのでConoHaに移行した現在はない)。

参考リンクに置いたapacheのドキュメントに従って解説を入れると、

  1. SetEnvは環境変数HOGEに値denyを設定している
  2. Orderはまず全てをAllowとした上で、Deny処理を適用後に、Allow処理を入れるという宣言
  3. Denyは環境変数HOGEが設定されていたら、全部Denyとするという意味

つまり、書かれた順番どおりに処理されたなら、この.htaccessが置かれたディレクトリでは全て403 Forbiddenになるはず」ということ。しかし200 OKで見えてしまっているわけです。

いろいろ疑い調べましたが、日本語の2.2のマニュアルには記載がありませんが、英語の2.2以降のマニュアルと、日本語の2.4以降のマニュアルに、

SetEnv はリクエスト処理の 段階の中でも遅くに実行されます。つまり SetEnvIf や RewriteCond などからは、変数がそこで設定されていることがわかりません。

https://httpd.apache.org/docs/2.4/ja/env.html#setting

という、よ~く読み漁らないと見つからない記述を見つけました。2.2の日本語版ではどれだけ読み漁っても見つかりませんけど…。

で、「それ本当なの?」「本当ならどう書けばいいの?」というのを読み解くのが今回のミッションです。

実験

そもそもSetEnv出来てるの?

SetEnvの成功例が必要です。確認できたのが、こちらの.htaccessになります。

SetEnv HOGE "deny"
Header set X-Frame-Options %{HOGE}e env=HOGE

解説

  1. 環境変数HOGEに値denyを設定する
  2. 環境変数HOGEが設定されていたら、HTTPレスポンスヘッダのX-Frame-Optionsに環境変数HOGEの内容を設定する

結果

こちらのリンク先(VALUE SERVER上なのでConoHaに移行した現在はない)のディレクトリに当該.htaccessを置いています。Chromeなどの開発者ツールでNetworkモニタリングしつつ、リンク先を読み込めば、HTTPプロトコルのレスポンスヘッダを見ることで分かります。

HTTP/1.1 200 OK
...
X-Frame-Options: deny
...

SetEnv自体は出来てますね。成功です。つまり処理順序の問題であるという可能性が高まりました。

じゃあDeny fromは出来てるの?

次はDeny fromの成功例が必要です。環境変数パターンは試せてませんが、.htaccessでAllow/Deny設定を上書き可能かどうかはApacheの設定次第なので、確認が必要ということです。確認用の.htaccessが以下です。

Order Deny,Allow
Deny from All

解説

  1. Orderはまず全てをAllowとした上で、Deny処理を適用後に、Allow処理を入れるという宣言
  2. 全てをDenyする

つまり、「この.htaccessを含むディレクトリ以下は全て403 Forbiddenになる」という設定です。

結果

こちらのリンク先(VALUE SERVER上なのでConoHaに移行した現在はない)のディレクトリに当該.htaccessを置いています。 辿れば分かりますが、403になります。置かれてるファイルはいつものsample.htmlです。

SetEnvIfとSetEnvの処理順序確認

記述内容の確認になります。SetEnvIfからSetEnvの結果を参照して本当にうまく動作しないかどうかを見ます。確認用.htaccessが以下になります。

SetEnv HOGE "deny"
SetEnvIf HOGE "deny" HOGECHILD=deny
Header set X-Frame-Options %{HOGECHILD}e env=HOGECHILD

解説

  1. 環境変数HOGEに値denyを設定する
  2. 環境変数HOGEの値がdenyだったら、環境変数HOGECHILDに値denyを設定する
  3. 環境変数HOGECHILDが設定されていたら、HTTPレスポンスヘッダX-Frame-Optionsに環境変数HOGECHILDの値を設定する

結果

こちらのリンク先(VALUE SERVER上なのでConoHaに移行した現在はない)のディレクトリに当該.htaccessを置いています。Chromeなどの開発者ツールでNetworkモニタリングしつつ、リンク先を読み込めば、HTTPプロトコルのレスポンスヘッダを見ることで分かります。

HTTP/1.1 200 OK
Date: Wed, 29 Jan 2020 23:38:37 GMT
Server: Apache
Last-Modified: Wed, 29 Jan 2020 21:28:41 GMT
ETag: "1581901-31-59d4e063ccc5b"
Accept-Ranges: bytes
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Content-Length: 61
Connection: close
Content-Type: text/html

X-Frame-Optionsヘッダの出力がありません。確かにうまく動作しておらず、SetEnvIfがSetEnvより処理が早い可能性が高まります。

SetEnvIfは単体なら動くの?

単体で機能するなら、処理順序で確定します。確認用.htaccessが以下になります。

SetEnvIf Remote_Addr ".*" HOGE=deny
Header set X-Frame-Options %{HOGE}e env=HOGE

解説

  1. クライアントIPアドレスRemote_Addrの値が正規表現で".*"にマッチしたら、環境変数HOGEに値denyを設定する(何でもマッチするので、必ず設定される)
  2. 環境変数HOGEが設定されていたら、HTTPレスポンスヘッダX-Frame-Optionsに環境変数HOGEの値を設定する

結果

こちらのリンク先(VALUE SERVER上なのでConoHaに移行した現在はない)のディレクトリに当該.htaccessを置いています。Chromeなどの開発者ツールでNetworkモニタリングしつつ、リンク先を読み込めば、HTTPプロトコルのレスポンスヘッダを見ることで分かります。

HTTP/1.1 200 OK
...
X-Frame-Options: deny
...

X-Frame-Optionsヘッダの出力されています。単体なら確かにうまく動作しており、SetEnvIfがSetEnvより処理が早いことが確定しました。

SetEnvの代わりにSetEnvIfにしてみる

最後にどうすればいいの?の回答です。.htaccessが以下になります。

SetEnvIf Remote_Addr .* HOGE=deny
Order Deny,Allow
Deny from env=HOGE

新しい要素がないので解説は省略

結果

こちらのリンク先(VALUE SERVER上なのでConoHaに移行した現在はない)のディレクトリに当該.htaccessを置いています。 辿れば分かりますが、403になります。置かれてるファイルはいつものsample.htmlです。

参考リンク

未分類

前回HTML内でJavaScriptを書いてみたらハイライトされなくて、おかしいな〜と調べてたら3件不具合を見つけた。

不具合

HTML内のJavaScriptなどをハイライトできない場合がある

現象

記事内にシンタックスハイライターを単独で置き、HTML内にJavaScriptを記述した上で言語をHTML/XHTMLにしておくと、JavaScriptがハイライトされない。

原因

HTMLのハイライトを行う(prism-)markup.jsとJavaScriptのハイライトを行う(prism-)javascript.jsの読み込み順序が逆であるため。依存されているjsが後に読み込まれる必要がある。

JavaScriptなのにJava用のハイライタまで読み込まれる

現象

読み込みがごくごく僅かに遅くなるだけだが、わざわざ言語別に必要ハイライタだけ読み込んでるからもったいない

原因

言語指定の先頭4文字がjavaかで判断しているため、javascriptまでjavaと勘違いされた

JavaScriptのハイライタが2回読み込まれる場合がある

現象

読み込みがごくごく僅かに遅くなるだけだが、わざわざ言語別に必要ハイライタだけ読み込んでるからもったいない

原因

JavaScript単体で言語指定された場合と、依存言語として他の言語指定から読み込まれる場合に、別の言語指定文字列が使われているため(highlight-javascriptとjavascript)、重複して読み込まれる

対策

パッチを作成した。

diff --git a/inc/load-inline.php b/inc/load-inline.php
index cc707c5..3374c70 100644
--- a/inc/load-inline.php
+++ b/inc/load-inline.php
@@ -51,10 +51,14 @@ function thk_highlighter_load( $loads, $list, $active ) {
 
 		// Javascript
 		foreach( $list as $key => $val ) {
-			if( strpos( $post->post_content, '<code class="language-' . str_replace( 'highlight_', '', $key ) ) !== false ) {
+			if( strpos( $post->post_content, '<code class="language-' . str_replace( 'highlight_', '', $key ) . '"' ) !== false ) {
 				$lang = str_replace( 'highlight_', '', $key );
 
-				if( !isset( $loads[1][$key] ) ) {
+				if( !isset( $loads[1][$lang] ) ) {
+					// 言語ごとの読み込み
+					$loads[0] .= thk_fgc( $jsdir . $lang . '.js' );
+					$loads[1][$lang] = true;
+
 					/*
 					 * 他言語の依存チェック
 					*/
@@ -114,10 +118,6 @@ function thk_highlighter_load( $loads, $list, $active ) {
 						$loads[0] .= thk_fgc( $jsdir . 'sql.js' );
 						$loads[1]['sql'] = true;
 					}
-
-					// 言語ごとの読み込み
-					$loads[0] .= thk_fgc( $jsdir . $lang . '.js' );
-					$loads[1][$key] = true;
 				}
 			}
 		}

保管場所は以下。


Luxeritas作者様に報告させて頂きました。次バージョンで対応して頂けるとのお話なので、個々にパッチを当てる必要はないと思います。


2020年2月2日にリリースされたLuxeritas3.7.8本体で、対応されたことを確認しました。なので以降本件のパッチリリースはありません。


2020年2月3日本パッチには、ほとんどの言語でハイライトできなくなるという重大な不具合が発見されました?。
同日にリリースされたLuxeritas3.7.8.2で作者様が対応してくれております。詳細は↓で。

未分類

UI系JavaScriptの記事なら動かせてもいいなぁと思って実験してみました。

カスタムHTMLブロックを使う

以下のVueのサンプルコードを動かしてみる。

<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app-5">
  <p>{{ message }}</p>
  <button v-on:click="reverseMessage">Reverse Message</button>
</div>
<script type="text/javascript">
var app5 = new Vue({
  el: '#app-5',
  data: {
    message: 'Hello Vue.js!'
  },
  methods: {
    reverseMessage: function () {
      this.message = this.message.split('').reverse().join('')
    }
  }
})
</script>

これをカスタムHTMLブロックに貼り付けた結果が以下。

{{ message }}

結果

動いてるみたい。

未分類

ここでは、本サイトで実施しているDBのみの手作業移行について解説します。簡単で、用途もデバッグ用なので、方法も適当です。

目的

DBのデータを運用しているサイトからlocalデバッグ環境に移行する

方針

ファイルはgitで管理されているので、DB内のデータのみ移行したいということです。プラグインを使うと、ファイルまで一緒についてきたり、サーバに余計なプラグインを設置しないといけなくなります。ローカルでサーバと同じデータを使ってデバッグ/テストしたいという目的であれば、DBの内容だけ適当にコピーできれば良く、できればコマンド一発で簡単にやりたいというわけです。

mysqlのデータをVALUE SERVER上でファイルに落とす

VALUE SERVER上で以下のスクリプト($HOME/bin/hoge.sh)を使うと、標準出力に、圧縮したWordPress関連のテーブルデータを全て出力できます。

#!/bin/sh
TABLES="wp_commentmeta wp_comments wp_links wp_options wp_postmeta wp_posts wp_term_relationships wp_term_taxonomy wp_termmeta wp_terms wp_usermeta wp_users"
mysqldump --user=$USER -p $USER $TABLES | gzip

実行すると、MySQLのパスワードが聞かれます。このファイルには実行可能属性を付けておきます。

$ chmod u+x $HOME/bin/hoge.sh

なお、使用しているコマンドのmysqldumpはあまり早くない汎用性の高いコマンドです。大量のデータがあって、いつまで経っても終わらない場合は別の方法にすべきです。このサイトは2020年1月23日現在圧縮して1MBに満たないサイズです。

ローカル環境から直接ファイルに落とす

上のスクリプトと、前回整えたsshの公開鍵認証を使って、ローカル環境から直にVALUE SERVER上のMySQLデータをファイルに落とすことができます。以下がそのコマンドです。

$ echo (MySQLパスワード) | ssh xxxxxxxx@xx.valueserver.jp ./bin/hoge.sh > mysqldat.gz

リダイレクトを使うことで、暗号化された経路でコマンドに履歴を残したり、一時ファイルを作成することなく、綺麗にデータを落とすことができています。さらに、VALUE SERVER上のhoge.shすら使用しないローカルスクリプト(export_db.sh)も書いてみました。

#!/bin/sh
SSH_USER="xxxxxxxx"
SSH_SERVER="xx.valueserver.jp"
MYSQL_PASSWD="yyyyyyyyy"
TABLES="wp_commentmeta wp_comments wp_links wp_options wp_postmeta wp_posts wp_term_relationships wp_term_taxonomy wp_termmeta wp_terms wp_usermeta wp_users"
OUTFILE=mysql.dat.gz
echo $MYSQL_PASSWD \
    | ssh $SSH_USER@$SSH_SERVER "mysqldump --user=$SSH_USER -p $SSH_USER $TABLES | gzip" > $OUTFILE

完成したタイミングでVALUE SERVER上のhoge.shは削除しました。sshは痕跡をあまり残さず何でも出来て便利だけど、ここが乗っ取られたら大変なことになることがよく分かります。

落としたファイルをローカルDBに流し込む

今回流し込むローカルDBは以前書いた記事のものを使います。

まずはdockerを起動して

$ docker-compose up

その後、以下のスクリプト(import_db.sh)で取り込みます。

#!/bin/sh
MYSQL_DB="exampledb"
MYSQL_USER="exampleuser"
MYSQL_PASSWD="examplepass"
CONTAINER="docker_db_1"
OUTFILE="mysql.dat.gz"
gzip -dc $OUTFILE | docker exec -i $CONTAINER mysql --default-character-set=utf8 -D $MYSQL_DB -u $MYSQL_USER --password=$MYSQL_PASSWD
docker exec -i $CONTAINER mysql --default-character-set=utf8 -D $MYSQL_DB -u $MYSQL_USER --password=$MYSQL_PASSWD <<EOF
update wp_options set option_value='http://localhost' where option_name in ('siteurl', 'home');
commit;
EOF

実行時にパスワードが引数で渡されることに警告が出ますが、デバッグ用の環境で固有名詞は適当なので、気にしないことにします。

また、取り込んだ後にSQLのUpdate文でWP_OPTIONテーブルを修正していたりもします。しかしその部分も最低限で、リンクなどの修正やその他の細かい変更もしていません。これらは運用サイトの状態をなるべく変えないことを意図しています。

まとめ

dockerが起動していれば、ローカルでexport_db.shとimport_db.shを実行するだけでVALUE SERVERのデータを取り込むことが出来た。

未分類

どこでも腐るほど解説はされてると思うし、VALUE SERVERで特別なこともないとは思いますが、念の為記事にしておきました。

対称鍵の作成

VALUE SERVERではなく今ログインしている端末(Linuxを想定)で、公開鍵認証で使用する公開鍵とその対象鍵である秘密鍵を同時に作成します。

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ユーザー名/.ssh/id_rsa): 

作成した鍵を格納するファイルパスを聞かれるのでそのままEnterを押しておきます。

Enter passphrase (empty for no passphrase):

次にパスフレーズを聞かれます。これは秘密鍵に掛けるパスワードのようなものです。秘密鍵を単独で盗まれてもそこに鍵がまだかかっているような形になります。セキュリティ的にはあるべきですが、理由があればなくても構いません。

Enter same passphrase again:

再度聞かれるので、同じものを入力します。すると、最終的に

  • $HOME/.ssh/id_rsaに秘密鍵
  • $HOME/.ssh/id_rsa.pubに公開鍵

が作られます。

VALUE SERVERに公開鍵を設置

ssh-copy-idというコマンドを使うのが簡単です。下で、xxxxxxxx@xxx.valueserver.jpは、VALUE SERVERのユーザ名とホスト名を@で繋いだ文字列です。

$ ssh-copy-id xxxxxxxx@xxx.valueserver.jp
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/ユーザー名/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
xxxxxxxx@xxx.valueserver.jp's password: 

VALUE-SERVERのパスワードを聞かれるので、従来どおりに入れてください。正しいパスワードで認証されれば、公開鍵をVALUE SERVERに設置してくれます。

VALUE SERVERに公開鍵認証でログイン

いつもどおりログインするだけです。パスワードの代わりにパスフレーズを使うだけ。パスフレーズを設定していなければ、何も聞かれずにログインできます。

user@user-pc:~$ ssh xxxxxxxx@xxx.valueserver.jp
Last login: Wed Jan 22 00:00:00 2020 from somedomain.net

xxxxxxxx@xxx:~$

参考までに公開鍵は、VALUE SERVERの、$HOME/.ssh/authorized_keys に保存されています。

参考

How to Use SSH Public Key Authentication – ServerPilot

未分類

Google検索向けにサイトマップを置きました。検索エンジンさんにこのサイトの構成などを説明するファイルです。

やったことは、Google XML Sitemapsというプラグインを追加して、

設定リンクを押して、

こんな感じのURL(画像のドメイン部分は自分のドメインに読み替えてください)をコピーして、Google Search Consoleでサイトマップの追加をしただけ。

このサイトに人が来ることがあるのかは分かりませんが、少なくとも表札を立てて住んでますっていう張り紙をしたという話でした。

未分類

今回当サイトにLuxeritasのパッチを置いたら、Chromeなどでダウンロードしたときに警告が出てしまいました。

サイトを作ったことがある人は知っているもののようですが、個人サイトなどでダウンロードできるようにすると、「誰が作った何なのか分からない」ので危険物扱いされてしまうようです。リンク先のサイトの管理人さんは、普通にウィルスチェックして、Googleに再チェックを依頼して事なきを得たそうですが、毎回そんなことするの大変です。

Google Search Consoleで問題指摘された際の詳細を見て、その基準を追ってみると…望ましくないソフトウェアのポリシー | Google – Google というページが見つかります。2020/1/22現在そこには以下のような記述があります(他にも項目があります)。

プログラムには、サイト運営者の検証可能な情報を提示する、コードサイニング機関から発行された有効な検証済みのコード署名が必要です。

ソフトウェアのダウンロードは、ユーザーがラベルで明示されたダウンロード ボタンをクリックしてダウンロードに同意した上で開始される必要があります。

望ましくないソフトウェアのポリシー | Google – Google

多分この辺が問題だと判断されたのかなと思います。ようは直リンクで署名されてないアーカイブを検出した場合に所定の手順でチェックが入るのかと推測しています。信頼された検証済みコードは難しいけど、署名=「誰が」の部分を明確にすることは出来そうです。今回は、Googleのチェックということもあり、GoogleDriveに置くことで、発信元を少なくともGoogleが(他の人もですが…)識別できるようにしてみました。

こうすることで、少なくともChromeなどでダウンロードする際に、危険物扱いをされずに済むようです。

未分類

背景

最近Dockerを使った記事を書くにあたり、シンタックスハイライターの対応言語が足りてないことに気付きました。シンタックスハイライターを実装しているのは、WordPressテーマのLuxeritasなのですが、このシンタックスハイライターに使われているprism.jsではもっと大量の言語に対応しています。そこで、今回必要になった、YAMLファイル(docker-compose.yml)、Dockerfile、 iniファイル(php.iniで欲しくなる)の3つの言語に簡単に対応してみました。

Luxeritasのコード解析

簡単とはいえ、説明書があるわけではないので、Luxeritasのコード解析をしないと、どこを修正していいか分かりません。調べてみたところ、大まかにいかの流れでシンタックスハイライターが動いています。

  1. シンタックスハイライターが扱える言語とその言語を表す文字列のリスト(wpfunc.php)を元にシンタックスハイライターの言語選択画面でリストアップする
  2. 記事のDB保存時にユーザーが選んだ言語を表す文字列を個々のコードブロックに紐づけて保存する
  3. 記事の表示時は、シンタックスハイライターを以下のように表示する
    1. コードブロックに紐付けられた言語を表す文字列と、先のリスト (wpfunc.php) を照合して、言語を確認(loadinline.php)
    2. その言語が複数の言語で構成されていればそれらを追加し、記事内で必要な言語のリストを作る(loadinline.php)
    3. 必要な言語のリストを元に、必要なprism.jsのファイルを特定し、最小限の組み合わせでJavaScriptファイルを合成(minify)してクライアントに返す
    4. クライアント側ではprism.jsの機能により、自動的に各言語はparseされてハイライトされていく

言語の追加

今回追加する言語は、複数の言語で構成される言語ではないので(例えばHTMLの中にJavaScriptが入るとか)、 シンタックスハイライターが扱える言語とその言語を表す文字列のリストに必要な言語を追加し、その言語に必要なprism.jsの部品を追加すれば完成です。

シンタックスハイライターが扱える言語の追加

wpfunc.php

diff --git a/inc/wpfunc.php b/inc/wpfunc.php
index fac76e8..7039e66 100644
--- a/inc/wpfunc.php
+++ b/inc/wpfunc.php
@@ -1970,6 +1970,9 @@ function thk_syntax_highlighter_list() {
                'highlight_sql'         => 'SQL',
                'highlight_vbnet'       => 'VB.NET',
                'highlight_vim'         => 'Vim',
+               'highlight_yaml'        => 'YAML',
+               'highlight_docker'      => 'Docker',
+               'highlight_ini'         => 'Ini',
        );
 }
 endif;

必要なprism.jsの部品を追加

今回は現在の最新リリースである、prism.js v1.16.0を取得し、その中からcomponents/prism-言語名.min.jsとなっているファイルを抽出し、必要な言語をLuxeritasパッケージ内にjs/prism/言語名.jsというファイルで配置しました。

パッチ

以下にまとめてあります。