少し前、従来のパスワードつきのZIP圧縮(Traditional PKWARE encryption)をNode.js (Lambda)で使いたかったが、ちょうどよいものが見当たらなかったので node-archiver-zip-encryptable というものを作成したので記録しておく。
これは node-archiver をベースにして、拡張機能的に付加することで利用する。
この archiver とその依存ライブラリが変わらない限りは、100% ピュア JavaScript の実装である。
今回の実装をするにあたり、そもそも普通に Windows で展開できるような(セキュリティ的には弱い)パスワードつきの圧縮というものに名前がついているのを知らず、調査に手間取った。
Golang での ZIP 圧縮ライブラリ alexmullins/zip にパスワード付与を実装している yeka/zip と、こちらの仕様を参考に実装。
https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
archiver は汎用的なアーカイブ作成のライブラリになっており、プラグインのような仕組みとして拡張子とその処理を登録することができる。これを利用して、以下のように archiver を読み込み、追加の拡張子として パスワードつき ZIP を登録する構成としている。
var fs = require('fs');
var archiver = require('archiver');
archiver.registerFormat('zip-encryptable', require('archiver-zip-encryptable'));
あとは、archiver の API 仕様に沿って利用すれば良い (パスワードのオプションは追加で必要だが)。
var output = fs.createWriteStream(__dirname + '/example.zip');
var archive = archiver('zip-encryptable', {
zlib: { level: 9 },
forceLocalTime: true,
password: 'test'
});
archive.pipe(output);
archive.append(Buffer.from('Hello World'), { name: 'test.txt' });
archive.append(Buffer.from('Good Bye'), { name: 'test2.txt' });
archive.finalize();
実装するにあたり、実はほとんどが archiver に含まれる ZIP の実装と同じなのだが、それ自体は拡張されることを意図した構成にはなっていなかったため、既存のクラスを継承して必要な function をオーバーライドするようにした。
ZIP 形式そのものの理解ができていなかったため、実行してはバイナリエディタでバイナリの中身を確認し、仕様通りになっているかの確認を繰り返すようなデバッグをした。
ファイルの仕様を理解していくのもなかなか面白いというか、今さらではあるが以下のような気付きがあった。
その他の気づき、感想。