From fffea98462b7ba3250118b4bdf4e5678cf6e4ba7 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 7 Oct 2017 04:30:57 +0900
Subject: [PATCH] :v:

---
 src/api/bot/core.ts            |  4 +-
 src/api/bot/interfaces/line.ts | 69 +++++++++++++++++++++++++++-------
 src/api/server.ts              |  7 +++-
 src/config.ts                  |  1 +
 tslint.json                    |  1 +
 5 files changed, 66 insertions(+), 16 deletions(-)

diff --git a/src/api/bot/core.ts b/src/api/bot/core.ts
index 002ac1b06e..47989dbaa2 100644
--- a/src/api/bot/core.ts
+++ b/src/api/bot/core.ts
@@ -4,11 +4,11 @@ import * as bcrypt from 'bcryptjs';
 import User, { IUser } from '../models/user';
 
 export default class BotCore extends EventEmitter {
-	public user: IUser;
+	public user: IUser = null;
 
 	private context: Context = null;
 
-	constructor(user: IUser) {
+	constructor(user?: IUser) {
 		super();
 
 		this.user = user;
diff --git a/src/api/bot/interfaces/line.ts b/src/api/bot/interfaces/line.ts
index 4bee844c12..8c7d6acfd5 100644
--- a/src/api/bot/interfaces/line.ts
+++ b/src/api/bot/interfaces/line.ts
@@ -1,34 +1,77 @@
 import * as EventEmitter from 'events';
 import * as express from 'express';
+import * as request from 'request';
 import * as crypto from 'crypto';
 //import User from '../../models/user';
 import config from '../../../conf';
-/*import BotCore from '../core';
+import BotCore from '../core';
 
-const sessions: {
-	userId: string;
+const sessions: Array<{
+	sourceId: string;
 	session: BotCore;
-}[] = [];
-*/
+}> = [];
+
 module.exports = async (app: express.Application) => {
 	if (config.line_bot == null) return;
 
 	const handler = new EventEmitter();
 
-	app.post('/hooks/line', (req, res, next) => {
-		// req.headers['X-Line-Signature'] は常に string ですが、型定義の都合上
-		// string | string[] になっているので string を明示しています
-		const sig1 = req.headers['X-Line-Signature'] as string;
+	handler.on('message', async (ev) => {
+		// テキスト以外(スタンプなど)は無視
+		if (ev.message.type !== 'text') return;
 
-		const hash = crypto.createHmac('sha256', config.line_bot.channel_secret)
-			.update(JSON.stringify(req.body));
+		const sourceId = ev.source.userId;
+		let session = sessions.find(s => {
+			return s.sourceId === sourceId;
+		});
+
+		if (!session) {
+			session = {
+				sourceId: sourceId,
+				session: new BotCore()
+			};
+
+			sessions.push(session);
+		}
+
+		const res = await session.session.q(ev.message.text);
+
+		request({
+			url: 'https://api.line.me/v2/bot/message/reply',
+			headers: {
+				'Authorization': `Bearer ${config.line_bot.channel_access_token}`
+			},
+			json: {
+				replyToken: ev.replyToken,
+				messages: [{
+					type: 'text',
+					text: res
+				}]
+			}
+		}, (err, res, body) => {
+			if (err) {
+				console.error(err);
+				return;
+			}
+		});
+	});
+
+	app.post('/hooks/line', (req, res, next) => {
+		// req.headers['x-line-signature'] は常に string ですが、型定義の都合上
+		// string | string[] になっているので string を明示しています
+		const sig1 = req.headers['x-line-signature'] as string;
+
+		const hash = crypto.createHmac('SHA256', config.line_bot.channel_secret)
+			.update((req as any).rawBody);
 
 		const sig2 = hash.digest('base64');
 
 		// シグネチャ比較
 		if (sig1 === sig2) {
-			console.log(req.body);
-			handler.emit(req.body.type);
+			req.body.events.forEach(ev => {
+				handler.emit(ev.type, ev);
+			});
+
 			res.sendStatus(200);
 		} else {
 			res.sendStatus(400);
diff --git a/src/api/server.ts b/src/api/server.ts
index fdff0c7546..3de32d9eab 100644
--- a/src/api/server.ts
+++ b/src/api/server.ts
@@ -19,7 +19,12 @@ app.disable('x-powered-by');
 app.set('etag', false);
 app.use(bodyParser.urlencoded({ extended: true }));
 app.use(bodyParser.json({
-	type: ['application/json', 'text/plain']
+	type: ['application/json', 'text/plain'],
+	verify: (req, res, buf, encoding) => {
+		if (buf && buf.length) {
+			(req as any).rawBody = buf.toString(encoding || 'utf8');
+		}
+	}
 }));
 app.use(cors({
 	origin: true
diff --git a/src/config.ts b/src/config.ts
index 0ea332f67d..46a93f5fef 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -70,6 +70,7 @@ type Source = {
 	};
 	line_bot?: {
 		channel_secret: string;
+		channel_access_token: string;
 	};
 	analysis?: {
 		mecab_command?: string;
diff --git a/tslint.json b/tslint.json
index 33704ca43b..1c44579512 100644
--- a/tslint.json
+++ b/tslint.json
@@ -16,6 +16,7 @@
 		"ordered-imports": [false],
 		"arrow-parens": false,
 		"object-literal-shorthand": false,
+		"object-literal-key-quotes": false,
 		"triple-equals": [false],
 		"no-shadowed-variable": false,
 		"no-string-literal": false,