Node.js
Express
twilio

簡単なPost用serverを作る

Twilioのcallback statusを保存するために必要になったのでサクッと作る

Twilio
status-callbacks

Node/Expressを使用するので、"ベスト・プラクティス: セキュリティー"を考慮する

Express
security

1.構成

Node : v0.10.48
Express : 4.15.4
OS : CentOS release 6.8
Port   : 8443

2. 準備

HTTPS化するので事前に証明書を用意
今回は"letsencrypt"を使用

letsencrypt

logディレクトリを作成

#mkdir -p /var/log/access

Postされたデータを保存するためredisを用意

#rpm -Uvh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
#rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
#yum --enablerepo=remi,remi-test install redis
#/etc/init.d/redis start

iptablesを許可

-A INPUT -m state --state NEW -m tcp -p tcp --dport 8443 -j ACCEPT

Node/Express/foreverなどpackegeをinstallする

2. Node script

app.js
// set modules
const basicAuth = require('basic-auth-connect');
const bodyParser = require('body-parser');
const express = require('express');
const fs = require('fs');
const helmet = require('helmet');
const https = require('https');
const morgan = require('morgan');
const client = require('redis').createClient();

// init express
const app = express();

// set cert and key
var options = {
  key: fs.readFileSync( '/etc/letsencrypt/hoge/privkey.pem' ),
  cert: fs.readFileSync( '/etc/letsencrypt/hoge/fullchain.pem' )
};

// post param parser
app.use(bodyParser.urlencoded({
    extended: true
}));
app.use(bodyParser.json());

// set basic auth
app.use(basicAuth('user_name', 'password'));

// set logging
var stream = fs.createWriteStream('/var/log/access/access.log', { flags: 'a' });
app.use(morgan({ stream: stream }));

// check header
app.use(helmet());

// set route
app.post('/', function(req, res) {
    // save redis
    var key = req.body.To;
    var value = req.body.CallStatus;
    client.set(key, value, function(){
    });
    // return mesg
    res.send('POST request to the example.api.jp');
})

app.get('/CallStatus/:num?', function(req, res) {
    // restrict source ip
    var ip = req.connection.remoteAddress || req.socket.remoteAddress;
    var key = req.params.num
    if (ip.match(/xx\.xx\.xx\.xx/)){;
      client.get(key, function(err, val){
        if (err) return console.log(err);
        res.send(val);
      });
    }else{
      res.send('403 Forbidden', 403)};
});

// define server
var server = https.createServer(options,app);
server.listen(8443);

// console debug
console.log('Server start!');

3.起動

forever start app.js

3.Twilio設定

call.py
call = client.calls.create(
to = "+81XXXXXXXXX",
from_ = "+81XXXXXXXXX",
timeout = "15",
url = "https://example.api.ppsys.jp/message",
status_callback = "https://user_name:password@example.api.ppsys.jp:8443",
status_callback_method = "POST",
tatus_callback_event = ["completed"]
)

5.確認

今回は

callback statusの"To"を"key", "callstatus"を"value"とする

var key = req.body.To;  // call number
var value = req.body.CallStatus; // completed|no-answer など

PostはソースIP制限なし、GetはソースIP制限あり
Basic認証はGet/Post両方で行う

Get

# curl https://user_name:password@example.api.jp:8443/CallStatus/+81xxxxxxx

架電後、値を取得できれば問題なし