Node.jsを使ってWebブラウザからS3に直接アップロードするサンプルアプリを作った

s3-uploaderを作りました。ブラウザから直接ファイルをS3にアップロードできます。詳しくはREADMEを読んで下さい。

使い方

S3のバケットを作成

公開アクセスを許可するのを忘れないでください。

Bucket Policyの作成

Bucket Policyを作成してください。
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    "AWS": "*"
                },
                "Action": [
                    "s3:PutObject",
                    "s3:PutObjectAcl"
                ],
                "Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*"
            }
        ]
     }

server.jsを編集

PROFILE_NAMEを~/.aws/credentialsのプロファイル名, BUCKET_NAMEを先程作成したバケット名に書き換えてください。

アプリを実行

以下のコマンドでアプリを実行してください。

npm install
npm run app
npm run server
open index.html

Certbotを使ってHTTPSに対応する

SSL/TLS サーバ証明書の取得・更新作業を簡単に行えるCertbotを使用してHTTPSに対応したのでその手順をメモ。OSはalpinelinux,WebサーバにはNginxを使用しています。

Certbotをインストール

Certbotと諸々のパッケージをインストールします。
apk add  --no-cache --update  \
  python python-dev py-pip git wget vim \
  gcc musl-dev linux-headers \
  augeas-dev openssl-dev libffi-dev ca-certificates dialog \
  && rm -rf /var/cache/apk/*

nginxの設定ファイルを編集

今回はwebrootプラグインを使用して証明書の作成、更新を行うので ドメイン名/.well-knwon/acme-challengeのリクエストを受け取ったときに証明書のディレクトリを返すようにします。
http {

	
	server {
	  listen 80;
          location /.well-known/acme-challenge {
              default_type "text/plain";
              root   /etc/letsencrypt;
          }

	      location / {
	        proxy_pass YOUR_SERVER;
	        proxy_http_version 1.1;
	        proxy_set_header Upgrade $http_upgrade;
	        proxy_set_header Connection 'upgrade';
	        proxy_set_header Host $host;
	        proxy_cache_bypass $http_upgrade;
	      }
	}

     server {
        listen 443 ssl;
        server_name ドメイン名;
        ssl_certificate /etc/letsencrypt/live/ドメイン名/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/ドメイン名/privkey.pem;
        location / {
	        proxy_pass YOUR_SERVER;
        }
    }
}

SSL/TLS サーバ証明書の取得

certbotを使用すると秘密鍵・公開鍵・署名リクエスト(CSR)を手動で生成する必要はありません。これらの作業は、Certbot クライアントが自動的に行います。
certbot certonly  --webroot -w /etc/letsencrypt \
  -d ドメイン名 -m メールアドレス --agree-tos -n

証明書の更新を自動で行う

証明書の有効期限は90日なのでそれまでに更新する必要があるのでcronを使って定期的に更新を行います。

$ crontab e
# 毎日午前2時に更新を行う
# min hour day month weekday command
  0   2    *  *     *        certbot renew

NullをReturnするのが適切な場合について調べた

どんな場合のときだとNullを返したほうがいいか、深く考えたことがないなと思ったのでいろいろ調べてみた。 Is it better to return NULL or empty values from functions/methods where the return value is not present?にとても有意義な情報がちりばめられていた。その中でも一番上の回答をしているJW8さんが下の内容を投稿していてとても参考になった。

Returning null is usually the best idea if you intend to indicate that no data is available. An empty object implies data has been returned, whereas returning null clearly indicates that nothing has been returned. Additionally, returning a null will result in a null exception if you attempt to access members in the object, which can be useful for highlighting buggy code – attempting to access a member of nothing makes no sense. Accessing members of an empty object will not fail meaning bugs can go undiscovered

要約

データを取得しようとして、データが存在しない場合にnullを返すのは意味があるので適切だけど、存在しないはずのプロパティにアクセスしようとしたりして予期しないエラーのときにnullを返すのはバグを隠蔽しているために不適切。
と書かれてあってとてもしっくりきた。

【Node.js】cryptoを使って暗号化をする

ユーザーのメールアドレスやパスワードをDBに格納する場合はセキュリティ上の観点から、暗号化させる必要があったのでメモ。

メールアドレスは復元が可能な可逆方式、パスワードは復元が不可能な不可逆方式で暗号化させる必要があるかと思います。

以下はメールアドレスは aes-256-ctr で、パスワードは hash 方式で暗号化させるサンプルコードになります。

メールアドレス

const crypto = require('crypto');
const key = ‘abc’;
// 暗号化
const encrypt = (text) => {
    let cipher = crypto.createCipher(‘aes-256-ctr’ ,key)
    let crypted = cipher.update(text,'utf8','hex')
    crypted += cipher.final('hex');
    return crypted;
}

// 復元
const decrypt = (text) => {
    let decipher = crypto.createDecipher(‘aes-256-ctr’,key);
    let dec = decipher.update(text,'hex','utf8')
    dec += decipher.final('utf8');
    return dec;
};

// 例
const val = encrypt('apple');
// e15690645d
decrypt(val);
// apple

パスワード

// 暗号化
const hashed = (password) => {
   let hash = crypto.createHmac('sha512', password)
   hash.update(password)
   let value = hash.digest('hex')
   return value;
}

// 例
hashed(‘apple’)
e8244ca53f71dc5be93bc074286828f466eca7cdd46ef47438d83d02f250be9a53825d133c5ef5cd99dadb5b957f39d2f9bbd0dbc20eec350768bcdda56a73bb

使っていないDockerのimageを削除するワンライナー

以下のコマンドで使用していないDockerのimageを削除できます。

    $ docker rmi $(docker images | grep "^" | awk "{print $3}")

ビルドしていたらいつのまにかDockerのimageが作成されまくるので定期的にクリーンアップする必要があるので便利。