銀の弾丸

プログラミングに関して、いろいろ書き残していければと思っております。

GitHub の Security Alerts を 1 clickで解消する(Botが勝手にやってくれる)

f:id:takamints:20190714165555j:plain
photo credit: verchmarco Vintage-Haustürschlüssel liegt auf einem selbstgemalten Haus via photopin (license)



GitHubからSecurity Alertsのメールが来ていました。3日連続で合計12件。全部npmのリポジトリ。 未明から早朝にかけてメールを受信するので朝起きて即ウンザリしてました。

すべて 12件のうち11件は間接的に依存している lodash が「prototype汚染に対して脆弱」だとのことで、解消するにはバージョンを 4.17.13 以上に上げなさいと。残り1件は diff というモジュールでした。

この場合、各リポジトリpackage-lock.json を直接開いて、lodash の tgz や sha の情報を npm info lodash で表示される最新バージョンの情報に書き換える必要があります。 npm install で 監査(Audit)の警告が出た時に npm audit fix で解消するのとほぼ同じ対処ですね(多分)

しかし、この単純作業を12個のリポジトリでやっていくのが若干面倒だったので、1日知らないふりして放置していましたが、本日GitHubでセキュリティ警告の画面を見ると、以前は無かった「Create automated security fix」という緑色のボタンがあって「なんだこれは?」と。

f:id:takamints:20190714110011p:plain

どうなるのか少し不安でしたが、Gitなので大丈夫だろうと押してみると、Botが勝手にブランチ切って、上記対処を適用してくれ、プルリクエストまで投げられました。 さらにこのプルリクをマージすると、ブランチを削除してくれました。

※ npmのパッケージのバージョンは勝手に上げてくれないので、それは手作業で対処が必要。


MicrosoftGitHubを買って以降、いろいろ便利になっていますね。 npmの場合、他のリポジトリで使われている数がわかったりしてチョット上がる。 UIも結構変わっているけど気に障らないし戸惑わない。 マイクロソフトらしい妙な日本語が交じることも無く良い状態(笑)。

はてなブログをAsciiDocで書く方法

f:id:takamints:20190521164525j:plain
photo credit: InstructionalSolutions Keyboard and Blank Paper via photopin (license)

はてなブログをAsciiDocで書けないものかとやってみたらなんとかなった。

前回記事(「AsciiDocのテーブルで行のヘッダを指定する方法」)でコードブロックのAsciiDocをプレビューするため書き殴ったJavaScriptを整理してご紹介しております。

実際には、はてなブログだけじゃなくて他社のブログやウェブサイトでも使えるはずです。

続きを読む

AsciiDocのテーブルで行のヘッダを指定する

f:id:takamints:20190518074249j:plain
photo credit: Pittypomm 27.1.15 - Bicycle via photopin (license)

仕様書書いててAsciiDocのテーブルで行ヘッダ(=特定列をまるごとヘッダ)はどうするの?と疑問に思って調べました。小ネタです。 以下、AsciiDoc の文書と @asciidoctor/core を使って書き殴ったプレビューツールでお送りしてます。

続きを読む

AWSでランダムな画像を返すURLを作りました(Stravaのワークアウトのシェアのため)

f:id:takamints:20190524130539j:plain

HTMLのIMG要素のSRC属性に設定しておけば、ランダムに画像を表示するURLです。 複数の画像をAWS S3のバケットに置いておき、CloudFront - API Gateway - Lambda Function というルートで画像を返します。

続きを読む

AWS S3 の putObject API でメタデータを設定する

f:id:takamints:20190415215350j:plain

AWSによるサーバーレスアーキテクチャ
Peter Sbarski
翔泳社
売り上げランキング: 157,672

AWS S3 の putObject APIバケットにファイルをアップロードするときには、メタデータをきちんと指定しておきましょうという話です。

既にメタデータが設定されてるファイルに上書きする場合、putObject APIメタデータを指定しないと、既に設定されていたメタデータは失われます。

AWS-CLIでコンソールからアップロードする場合はContent-Type に適切なMIME Type を設定してくれるのですが、APIでは自分で指定しなければなりません。でないとすべて application/octet-stream に設定されてしまいます。こうなるとバケットをWEBで公開している場合(CloudFrontのDistribution経由でも)、すべてがバイナリファイルの扱いになって、なんでもかんでもダウンロードされてしまいます。

他にも、ブラウザキャッシュを禁止しておきたい場合があると思いますが、これも上書きのたびに失われます(AWS-CLIでは、--cache-control オプションに、no-cache を指定する必要があります)。

まあ、とにかくAPIでputObjectする場合には必要なメタデータを毎回設定するべきなんですね。

ということで、以下のコードは、APIでS3にファイルをアップロードする際、同時にメタデータを設定するNode.jsのコードです(AWSへの接続はAWS-CLIのプロファイル(~/.aws/ 以下の configcredentials)が正しくセットアップされている前提です)。 ここでは putObject のパラメータで、最低限設定しておきたい Content-Type と、おそらく必要になるであろう Cache-Control を指定しています。

"use strict";
const AWS = require("aws-sdk");
const mime = require("mime-types"); //拡張子からMIME Type
const fs = require("promise-fs"); //地獄に落ちないfsモジュール
const { promisify } = require("es6-promisify"); //callbackの非同期をPromise化
const s3 = new AWS.S3();
const promised = {
    s3: {
        putObject: promisify(s3.putObject.bind(s3))
    }
};

/**
 * ContentTypeとCacheControlを設定してS3のバケットへファイルを
 * アップロードする。
 * @async
 * @param {string} bucket バケット名
 * @param {string} key アップロード先のキー(バケット内のパス)
 * @param {string} pathname ローカルファイルのパス名
 * @returns {Promise<undefined>} アップロード完了で解決するPromise
 */
const uploadS3Bucket = async (bucket, key, pathname) => {
    try {
        const body = await fs.readFile(pathname);
        const contentType = mime.lookup(pathname);
        const params = {
            Body: contentType.match(/^text\//) ? body.toString() : body,
            Bucket: bucket,
            Key: key,
            CacheControl: "no-cache",
            ContentType: contentType,
        };
        console.log(`Uploading: ${pathname}`);
        console.log(`  [ContentType: ${params.ContentType}]`);
        console.log(`  ==> s3:${'//'}${params.Bucket}/${params.Key}`);
        await promised.s3.putObject(params);
    } catch(err) {
        console.warn(err.message);
    }
};

Content-Type の特定は npm mime-type が使えます

ファイル名(拡張子)からMIME Typeを得るために、 mime-types というnpmモジュールを使ってみました。 別の npm mime-dbに依存していますが、どちらも週に1500万回ほどダウンロードされていますから実用上の問題はないでしょう。

Cache-Control も設定したい

上のコードでは Cache-Control を no-cache に設定しています。 Webサイトとして公開している場合に、ブラウザキャッシュを無効にする設定です。 CloudFrontでInvalidationを作成してキャッシュを無効化しても、ブラウザキャッシュが効いているとページが更新されなくて「?」となることがありまして。

参考:S3のオブジェクトのメタデータ

下表は S3 Bucket のファイルに設定可能なメタデータです。 メタデータ列は S3 のWEBコンソールで表示される名称で、パラメータキーはputObjectのパラメータで指定する場合のキー名称です。

メタデータ パラメータキー 詳細
Cache-Control CacheControl ブラウザキャッシュの指定 (☞MDN)
Content-Disposition ContentDisposition ファイルの扱い方法を指定 (☞MDN)
Content-Encoding ContentEncoding 圧縮アルゴリズムを指定 (☞MDN)
Content-Language ContentLanguage 閲覧者の言語を指定 (☞MDN)
Content-Type ContentType ファイルのMIME Typeを指定 (☞MDN)
Website-Redirect-Location WebsiteRedirectLocation リダイレクト先 (☞DevelopersIO)
x-amz-meta-<key> Metadata.<key> ユーザー定義メタデータ (☞AWS)
有効期限 Expires 削除される日時(☞AWS)

※ ユーザー定義メタデータ以外は、APIであらかじめ定義されているシステムメタデータです。

リンク