WindowsとCertbotとSSL証明書と。

備忘録的エントリになります。

レンタルサーバーとかだと、LetsEncryptの Certbot で運用・・・なんてできませんよね。
LetsEcryptに対応している(コンパネとかで)レンタルサーバーだといいんですが、対応していない場合、なんとかして LetsEncrypt のフリーのSSL証明書をゲットしなければなりません。

探し方が悪いのかググっても情報がバラバラで何がどうなってんのかさっぱり分からない。かなり試行錯誤しながら、SSL証明書の取得および更新を半自動化するスクリプトを組むことができました。

まずはCertbotのインストール

私は ガチガチのWindows ユーザーなので、まず最初に WSL1(Ubuntu 20.04)でやろうとしましたが、Certbotの公式サイト(https://certbot.eff.org/)に載ってる説明されている方法だと、snapdをインストールして・・・と書かれているのですが、WSL1ではsnapdは非対応でした。

WSL2とsystemd稼働環境だといけるみたいですが、WSL2はあまり使いたくありません。で、残る選択肢は Windowsで動作するCertbotをインストールするしかありません。

Windows版のcertbotのインストールはWinGetを使うと超絶カンタンです。
コマンドプロンプトから、下記のようにコマンドを叩くだけ。途中権限昇格がポップアップされますが、大丈夫でしょう。

 >> winget install certbot

通常、C:\Program Files\Certbot\binに実行ファイルが格納されていますので、環境変数 PATH に追加しておくといいでせう。

Linuxとかだと、関連するファイルは、/etc/letsencrypt/ に配置されてるようですが、Windowsだと、C:\Certbotに関連するファイルが作成されるようです。

一つ注意点として、certbotを実行する際、管理者権限が必要です。まず管理者権限のコマンドプロンプトで実行しないと、エラーになります。

SSL証明書の取得

インストールが完了したらほぼ作業は終わり。あとは、下記のようなCMDファイル(batファイルでもいいけど)を書いた方がいいです。
インストールして初回実行時だけ、メールアドレスの登録プロセスが出ますが、特別な理由がない限り、メールアドレスは登録しておいた方がいいでしょう。SSL証明書の期限切れ前に、メールで知らせてくれます^^;

今回は証明書の取得をウェブサーバー上で行うのではなく、自分のPCで証明書を取得しますので、Manualプラグインを使用します。ドメインの認証方法は、通常と同じくデフォルトのhttp認証でドメインの認証を行います。

要するに、自分がそのドメインのオーナーかどうかは、レンタルサーバー上へ FTPなどで認証ファイルを置くことで認証を行います。
認証ファイルをレンタルサーバーへ転送するには、cURL を使います。Windows10から curl.exe が標準でバンドルされるようになってるはずです。

読めば大体分かりますが・・・、
(1) –manual で Manualプラグインを使用します。
(2) -d でSSL証明書を取得したいドメイン名を指定。
(3) –key-type で rsa を指定。レンタルサーバーがRSAしか対応していない場合は指定する。
(4) –agree-tos, –manual-public-ip-logging-ok は指定しないと途中で聞いてくるので初めからYes。
(5) –manual-auth-hook,–manual-auth-cleanup は、後述。

最後の(5)で、–manual-auth-hookと–manual-auth-cleanupは、認証情報をセットアップ、クリーンアップするスクリプトを指定します。
これは下記のように、certbotを実行中、http認証する前、後にコールされ実行されます。

※この2つのフックについては、公式?のドキュメント、Pre and Post Validation Hooks 参照のこと。

具体的には、スクリプトが実行されるとき、ドメイン名や、認証テキストなどが環境変数を通して渡されますので、環境変数から渡されたパラメータを使用して、レンタルサーバーへcURLを使って放り込みます。具体的には、以下のようなスクリプトを用意します。

上記ファイルにも書きましたが、FTPサーバーへのアカウントを直書きしているので、そのままコピペはダメです。あくまでサンプルですので、暗号化・復号化は自分で実装してください。

※ また、FTP以外のSCPとか使ってレンタルサーバーにアップしている人・・・cURLのほかにも SCPもWindows10以降はバンドルされているので、その辺はテキトーに書き換え必要。

正常に認証が通れば、SSL証明書が、C:\Certbot\live\ドメイン名 ディレクトリに証明書が生成されているはずです。
実際には、シンボリックリンクになってますが。これらのファイルをレンタルサーバーのコンパネで設定してください。

SSL証明書の更新

LetsEncryptは3か月(90日)しか使えません。自前のサーバーでは、crondなりで更新スクリプトを回せばいいのですが、 レンタルサーバーだと全部手動になります。
少しでも楽するため、SSL証明書の更新処理だけは自動化したいですよね。

更新の際も認証が必要になりますので、上記で使った certbot-preauth.cmd,certbot-postauth.cmdを使いまわします。。。

certbot renew する際の注意点として、複数のドメインの証明書をcertbotで管理する際、特定のドメインを指定して更新、というのは現状できないみたいで、renewするときはすべてのドメインを一括して更新されてしまいます。

-d でドメインを指定しても、エラーになり、いずれドメインを指定できるようにする、という旨のメッセージが出ます。まぁ、バージョンが上がれば、そのうちドメインを指定して更新処理(certbot renew)することができるようになるでせう。

と、まぁ、http認証をmanualプラグイン(手動)で運用できるようになりました。888888。

・・・ですが、ワイルドカードSSL認証の場合は、デフォルトのhttp認証ではなく、dns認証をするしかありません。
やり方は上記とほぼ同じですが、–preferred-challenges dns を付け足し、-d で アスタリスクをつけたドメイン名を指定するだけ。
ただし、自動化するには、–manual-auth-hookでDNSのTXTレコードを設定する処理が必要です。
DNSの設定をAPI経由などでできないと無理っぽそう。

ブラウザでPDFファイルの画像化

持病の影響で急性腎不全を患い、少しばかり入院していました。はぁ~、健康って大事ですよねぇ。。。
というのは、さておき。

コーディング・メモです。

PDFファイルの画像を生成するため、アップロードしたPDFファイルをサーバーで(具体的には ImageMagickで)処理していました。
周知のとおり、ImageMagickでPDFファイルを処理するとセキュリティー云々があってごく限られた場合に使用するようにしていました。
ImageMagickはいいですね、もう画像関連の処理は全部コイツに任せたいぐらいですが、4~5年前に脆弱性に関する情報がいっぱい出て使うのをためらっています。2022年末になってもまだ同じ状況なのでしょうか?よく分かりません。

というわけ・・・でもないのですが、サーバーサイドでImageMagickに頼らず、ということになるとImageMagickの代替を探すか、自作するしかありませんが、画像のアルゴリズム他に関する知見はほとんどないので自前でなんとか、というのはできない。となると、クライアントでどうにかするしかありません。

幸いにも、最近のウェブ環境ではJavaScriptでどうとでもなります。
PDFフォーマットの解析・表示には、MozillaさんがPDF.js を公開してくれてます。今更ですが。

A general-purpose, web standards-based platform for parsing and rendering PDFs.
PDF.js

これを使うと、File,Blobなどで取得したPDFデータを HTMLに書いたcanvas要素にレンダリングしてくれます。
canvas要素にレンダリングしてくれたら、あとは canvas要素の画像を取得して Blob に変換してあげて、サーバーにPDFとともに生成した画像を送信してやれば、サーバー側で重い処理を走らせずに済みます。

上記サイトにサンプルがあるので、チョチョっといじれば、簡単に実装できる、いい時代です。
最初、ダウンロードしたファイルのどれが必要なのかよく分かんなかったですが・・・、最終的に、以下のように buildディレクトリとcmapsディレクトリさえあれば、事足りるみたい。

.
└── pdfjs
    ├── build
    │   ├── pdf.min.js
    │   ├── pdf.sandbox.min.js
    │   ├── pdf.worker.entry.js
    │   └── pdf.worker.min.js
    └── cmaps/*

とりあえず動作デモ
ソースを見れば大体何をやってるかは分かると思います。チョーカンタン。

input[type=file]要素でファイルを読み込んで、それをそのまま渡すと変換した画像のFileオブジェクトを返してくれるような関数を書いてみました。再利用しやすいようにとりあえずモジュールとして書いた。

これを、下記のようにコール。

ものすごく、簡単。

上記のデモはこっち。

JAPAN/MARCデータって何ですか?

最近、図書を管理するシステムを嫌々作らされているのですが💦、図書関連の用語がもうムズカシイ。
知らない単語のオンパレードで、知らないワードが出てくると、ググるか、WIKIペディアで調べてます。
んー、めんどくさい。

で、作っている途中で、JAPAN/MARCデータ、というものがあるらしい、そのファイルを取り込んで本のデータとしてデータベースに格納する、という一見簡単なタスクだなぁ、と高を括ってたんですが、この MARCデータの形式(MARC形式というらしい)の仕様書をダウンロードして、サラッと流し読み・・・そっとファイルを閉じました・・・。

このMARCデータから本の情報を切り出すプログラム、誰か書いてないかなー、とググるもキーワードが悪いのかコレ!っていうものが見つからず・・・。
そうだよな、わざわざ JAPAN/MARCなんて使わなくても Google BooksやopenBDで書誌データをAPIで取れるようにしてれくれてるからなぁ。。。

そうはいっても・・・途中で放り出すわけにもいかないので・・・必要なデータを取ることだけに集中して、データを読み出す処理をJavaScriptで起こすことにした。画面はとりあえずhtmlで組んでプロトタイプを作って、あとでC#とかにポーティングすればいいや。
ってわけで、通常業務の空いた時間にシコシコシコ書いてみました。

変換したデータは、indexedDB APIでブラウザに保存するようにして、その際、Dexie.js というライブラリを使う。
Dexie.js
https://github.com/dexie/Dexie.jshttps://dexie.org/

デモ実装した画面はこちら。(クライアントブラウザのみで動作)

肝心のMARC形式のファイルを読み込むスクリプト本体は・・・今見ても何でこんな実装にしたんだ?っていうほどヒドく、初心者丸出しでお恥ずかしい。
実際に業務で使う予定のものは、もうちょっと改良したバージョンですが・・・それのプロトタイプとなった殴り書きバージョン。

正直なんでMARC形式ってこんなメンドクサイ形式なんだーーーー、と書きながら思いました。。。偉い人がつくるフォーマットは、凡人には理解できん。。。

どこかに、完全な実装例ないのかなぁ。。。教えて!エロい人!

ブラウザでCSV(CP932)⇔XLSXの相互変換

極力サーバーサイドでExcelファイルを処理させたくなくて、(なんちゃって)フロントエンド開発をワチャワチャやっております。

データベースからデータを抜き出すのも、Excelファイルだし、データベースにインポートするデータもExcelファイルです。 もうエクセルを見るのも嫌になってます。

サーバーサイドのプログラムを組む時、データをJSONもしくはCSV形式で扱うと、書くのがラクになります。そこで、ブラウザ上で、CSVとXLSXを相互変換できれば便利だな、と思ったのがきっかけ。

例によって、node.jsモジュールを browserify でワンパッケージにして利用します。(バンドラーって呼ぶみたいです。よく分からん)今回は npmコマンドで exceljs・encoding.js・file-saver の三つのモジュールを取得して、browserify で一つのファイルにパックします。

exceljs は、Excel(xlsx)ファイルを扱うモジュール。ExcelファイルをJavaScriptで扱うライブラリは SheetJS が有名で xlsxだけじゃなくて旧型式のxlsファイルも読むことができて非常に便利なのですが、Pro版じゃないと制限が多いので、最近では ExcelJSの方を使っています。

encoding.js は JavaScript でUTF-8,ShiftJIS(CP932),UTF16などを相互に変換できるライブラリです。ShiftJISのCSVファイルを扱う時に使用します。

file-saverは・・・説明要らないですよね💦 ダウンロードできるようにするヤツです。


動作デモはこちら


手順はいつもどおり。
まずは、package.json 。

今回は 3つのモジュールを一つのファイル(bundle.min.js)にまとめて、実際に使用するときは、そのファイル内(bundle.min.js)に定義されているrequire関数でロードするようにします。

上記package.jsonを適当なディレクトリにおいて下記を実行して、bundle.min.js を生成しておきます。

>> npm install
>> npm run bundle

この bundle.min.js を下記のサンプルのHTMLファイルのように、scriptタグでロードしておきます。

そして・・・肝心の 変換コードは下記のようになります。

特筆すべき点はありませんが・・・encoding-japaneseモジュールで、ShiftJISに変換した後、ShiftJISに変換したものを保存するとき、単純 string型でBlobのコンストラクタに渡すと、再変換されて文字化けを起こしてしまいハマってしまいました。
イマイチあんまり分かってません。

CSVの行区切り、本来は・・・CRLF(0x0D0A)・・・ですよね・・・。workbookからCSVにするとき、worksheetを行毎にループして変換したあと、自前で join(‘\r\n’)とかすればいいんでしょうけど・・・。
workbook.csv.writeBuffer()する際、formatterOptionでrowDelimiterで改行コードを指定すればいいみたい。

フロントエンド、メンドクサイし、ムズカシイし、あんまりやりたくない。。。


動作デモはこちら


TABLE要素にtoJSON()をつけちゃえ

2022/02/19 配列を返すのに toPlainObject というのは、名前としてはおかしいので toArray に修正。もろもろ修正。


業務で使うために作ったけど、すぐ忘れそうなのでメモ書きです。

テーブル要素、たとえば下記のようなものから、データベースの行配列のようなオブジェクトを作りたい、と唐突に思ったわけです。

カラム1 カラム2 カラム3 カラム4 カラム5
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3

で、table2json みたいなキーワードでググってみると、いくつか githubとかで見つかります。
・・・が、公開されているのは、すごく汎用性が高くバグも少ないけれど、イヤイヤイヤ、そんな機能要らんねん、とか、こういう事ができたらなぁ・・・とか、いろいろあるわけです。要は、帯に短し、襷に長し、というケースがいろいろ出てきます。

じゃあ、仕方ない、テーブル要素からJSONを組み立てるぐらいなら、数十行のコードだな・・・と思い、書き始めると、時間がかかるわけです。
単純なテーブルなら、すぐ書けたんです。30分ぐらいでしょうか。でも・・・「あ、セルが縦横に合体してるテーブルだと、使えんな・・・」と。

まぁ、ブログの肥やし💦

デモはこちら

下記のようなテーブルから、JSONデータ(正確には オブジェクトかな。)を組み立てる。
要は、theadにキー名の列を、tbodyに実際の行があるような、よく見かける表です。

これを下記のようなスクリプトで、オブジェクトに変換します。
単純な関数を1個つくればいいと思ったですが・・・HTMLTableElementにtoJSON,toArrayメソッドを強引に付け足してやりました。

実際の本体は、↓のような感じ。(エラー処理は一切してないので、無いとは思いますが、コピペ使用は危険です)

まぁ、使い方は、テーブル要素のオブジェクトを取得して、toArray()メソッドをコールすると、運が良ければオブジェクトが返ってきます。
toJSONメソッドは、toArrayメソッドの返り値を JSON.stringify しただけ。
fn 引数を指定すると、セルのテキストを加工できます。

デモはこちら
稚拙だなぁ・・・。