OSDN Git Service

fix a typo
[webchat/WebChat.git] / chat.js
1 $spilt_size = 1024 * 512;    //分割するサイズ\r
2 $reset_password_diff = 1000 * 60 * 60;  //ルームパスワードをリセットする間隔\r
3 $gc_time_interval = 1000 * 60 * 60;     //ゴミ掃除を行う間隔\r
4 $ip_ban_list_file_name = "ipbanlist.txt";       //アクセスを禁止するIPが記録されているファイル\r
5 $room_configure_file_name = "roomlist.txt";     //ルームの設定が記録されているファイル\r
6 $system_name = "system";        //システム発言を表す名前\r
7 $log_directory = "log"; //ログファイルを置くフォルダー\r
8 $log_file_name = "logfile%d.txt";       //ログファイル名(%dはそのままにしておくこと)\r
9 $splited_log_file_name = "logfile%d_%s.txt"     //分割後のファイル名(%dと%sはそのままにしておくこと)\r
10 \r
11 var clients = new Array();\r
12 \r
13 var IpBan = require("./ipban.js")\r
14 var ipbanlist = new IpBan();\r
15 var RoomInfomationCollection = require("./room.js");\r
16 var $rooms = new RoomInfomationCollection();\r
17 \r
18 createLogDirectory();\r
19 \r
20 var sessionStore;\r
21 \r
22 module.exports = function(app,server,express,session){\r
23         sessionStore = session;\r
24         app.get("/chat", chat_proc);\r
25         app.all("/log/*",express.basicAuth(auth_proc));\r
26         app.get("/log/*",log_proc);\r
27         app.all("/chat/admin",express.basicAuth(auth_proc));\r
28         app.get("/chat/admin", admin_proc);\r
29         app.post("/chat/admin",admin_postproc);\r
30 \r
31         var config = require("./configure.js");\r
32         var io = require("socket.io").listen(server);\r
33         io.configure("production", function(){\r
34                 io.set("transports", config.transports);\r
35                 io.enable("browser client minification");  // minified されたクライアントファイルを送信する\r
36                 io.enable("browser client etag");          // バージョンによって etag によるキャッシングを有効にする\r
37                 io.set("log level", 1);                    // ログレベルを設定(デフォルトより下げている)\r
38         });\r
39 \r
40         for(var i = 0; i < config.max_room_number; i++)\r
41         {\r
42                 clients[i] =io\r
43                 .of(GetNameFromRoomNumber(i))\r
44                 .authorization(ParseAuthorization)\r
45                 .on("connection",ParseConnect);\r
46         }\r
47 };\r
48 \r
49 function chat_proc(req, res){\r
50         var security = require("./security.js");\r
51         var info = new security.SessionInfomation(false);\r
52         req.session.items = info;\r
53 \r
54         var room_number = 0;\r
55         if(typeof(req.query.rno) != "undefined")\r
56                 room_number = req.query.rno;\r
57         res.render("chat",{rno:room_number,token:req.session._csrf});\r
58 }\r
59 \r
60 function auth_proc(user, pass) {\r
61         var config = require("./configure.js");\r
62         return user === config.username && pass === config.password;\r
63 }\r
64 \r
65 function log_proc(req, res) {\r
66         res.sendfile(__dirname + req.url);\r
67 }\r
68 \r
69 function admin_postproc(req,res){\r
70         if(typeof(req.body.erase) != "undefined")\r
71         {\r
72                 removeLog(req.body.file,function(){\r
73                         res.redirect("/chat/admin");\r
74                 });\r
75         }\r
76         if(typeof(req.body.registor) != "undefined")\r
77         {\r
78                 ipbanlist.Update(req.body.newbanlist,function(){\r
79                         res.redirect("/chat/admin");\r
80                 });\r
81         }\r
82         if(typeof(req.body.updateroom) != "undefined")\r
83         {\r
84                 $rooms.Update(req.body,function(){\r
85                         res.redirect("/chat/admin");\r
86                 });\r
87         }\r
88 }\r
89 \r
90 function admin_proc(req,res)\r
91 {\r
92         var security = require("./security.js");\r
93         var info = new security.SessionInfomation(true);\r
94         req.session.items = info;\r
95         var iplist = ipbanlist.GetText();\r
96         var fs = require("fs");\r
97 \r
98         fs.readdir($log_directory,function(err,list){\r
99                 res.setHeader("X-FRAME-OPTIONS","DENY");\r
100                 res.render("admin", {\r
101                         files: list,\r
102                         log_directory:$log_directory,\r
103                         ipbanlist:iplist,\r
104                         token:req.session._csrf,\r
105                         roomlist:$rooms.GetMessage()\r
106                 });\r
107         });\r
108 }\r
109 \r
110 function removeLog(files,callback)\r
111 {\r
112         if(typeof(files) == "undefined")\r
113         {\r
114                 if(typeof(callback) == "function")\r
115                         callback();\r
116                 return;\r
117         }\r
118         var async = require("async");\r
119         async.map(files,\r
120         function(item,callback){\r
121                 var fs = require("fs");\r
122                 fs.unlink($log_directory + "/" + item,callback);\r
123         },\r
124         function(err,results){\r
125                 if(typeof(callback) == "function")\r
126                         callback();\r
127         });\r
128 }\r
129 \r
130 function createLogDirectory()\r
131 {\r
132         var fs = require("fs");\r
133         fs.exists($log_directory,function(exists){\r
134                 if(exists == false)\r
135                         fs.mkdirSync($log_directory);\r
136         });\r
137 }\r
138 \r
139 function ParseConnect(socket)\r
140 {\r
141         var ip = GetClientIPAdress(socket);\r
142         console.log("connected from %s",ip);\r
143 \r
144         var rno = GetRoomNumberFromName(socket.namespace.name);\r
145 \r
146         var room = $rooms.Get(rno);\r
147 \r
148         room.AddRom(ip);\r
149 \r
150         var roomconfig = room.GetConfig();\r
151         socket.json.emit("send roominfo",roomconfig);\r
152 \r
153         var romcount = room.GetRomCount();\r
154         socket.json.emit("send romcount",romcount);\r
155         socket.json.broadcast.emit("send romcount",romcount);\r
156 \r
157         socket.on("get pastLog", function (msg) {\r
158                 ParseGetPastLog(socket,msg);\r
159         });\r
160         socket.on("join",function(msg){\r
161                 ParseJoin(socket,msg);\r
162         });\r
163         socket.on("quit",function(msg){\r
164                 ParseQuit(socket,msg);\r
165         });\r
166         socket.on("set password",function(msg){\r
167                 ParseSetPassword(socket,msg);\r
168         });\r
169         socket.on("send msg", function (msg) {\r
170                 ParseSendMsg(socket,msg);\r
171         });\r
172         socket.on("disconnect", function (msg) {\r
173                 ParseDisconnect(socket,msg);\r
174         });\r
175 }\r
176 \r
177 function ParseAuthorization(handshakeData, callback)\r
178 {\r
179         var connectUtils = require("express/node_modules/connect/lib/utils");\r
180         if(handshakeData.headers.cookie) {\r
181                 var cookie = require("express/node_modules/cookie");\r
182                 var signedCookie = cookie.parse(handshakeData.headers.cookie);\r
183                 var sessionID = connectUtils.parseSignedCookies(signedCookie, $secret)["connect.sid"];\r
184                 sessionStore.get(sessionID, function (err, session) {\r
185                         var result = null;\r
186                         if (ipbanlist.IsBaned(handshakeData.address.address))\r
187                                 result = "failed get from session store";\r
188                         else if(err)\r
189                                 result = err;\r
190                         else if(typeof(session) == "undefined" || typeof(session._csrf) == "undefined")\r
191                                 result = "session is undefined";\r
192                         else if(handshakeData.query.token != session._csrf)\r
193                                 result = "invaild token";\r
194                         if(result == null)\r
195                                 handshakeData.sessionID = sessionID;\r
196                         callback(result,result == null && !err);\r
197                 });\r
198         } else {\r
199                 return callback("failed get cookie", false);\r
200         }\r
201 }\r
202 \r
203 function ParseDisconnect(socket,msg)\r
204 {\r
205         var ip = GetClientIPAdress(socket);\r
206         var rno = GetRoomNumberFromName(socket.namespace.name);\r
207         $rooms.Get(rno).RemoveRom(ip);\r
208 \r
209         var romcount = $rooms.Get(rno).GetRomCount();\r
210         socket.json.emit("send romcount",romcount);\r
211         socket.json.broadcast.emit("send romcount",romcount);\r
212 \r
213         console.log("disconnected");\r
214 }\r
215 \r
216 function ParseSetPassword(socket,msg)\r
217 {\r
218         var rno = GetRoomNumberFromName(socket.namespace.name);\r
219         var newMeg = {\r
220                 name:$system_name,\r
221                 message:null,\r
222         };\r
223         var resource = require("./resources.js");\r
224         if($rooms.Get(rno).IsVolatile() == false && $rooms.Get(rno).SetPassword(msg.owner,msg.password))\r
225                 newMeg.message = resource.password_setted_message;\r
226         else\r
227                 newMeg.message = resource.failed_set_password_message;\r
228         ParseSendMsg(socket,newMeg);\r
229 }\r
230 \r
231 function ParseJoin(socket,msg)\r
232 {\r
233         var ip = GetClientIPAdress(socket);\r
234 \r
235         if(ipbanlist.IsBlockedToWrite(ip))\r
236         {\r
237                 var resource = require("./resources.js");\r
238                 socket.emit("error",resource.block_message);\r
239                 return;\r
240         }\r
241 \r
242         var rno = GetRoomNumberFromName(socket.namespace.name);\r
243 \r
244         $rooms.Get(rno).RemoveRom(ip);\r
245         \r
246         var romcount = $rooms.Get(rno).GetRomCount();\r
247         socket.json.emit("send romcount",romcount);\r
248         socket.json.broadcast.emit("send romcount",romcount);\r
249 \r
250         var util = require("util");\r
251         if($rooms.Get(rno).IsVolatile() == false)\r
252         {\r
253                 if($rooms.Get(rno).IsTimeout() ||\r
254                         $rooms.Get(rno).IsFirstAuth())\r
255                 {\r
256                         $rooms.Get(rno).Reset(msg.name);\r
257                         ParseGetPastLog(socket,util.format($log_file_name,rno));\r
258                 }\r
259                 else if($rooms.Get(rno).Auth(msg.name,msg.password))\r
260                 {\r
261                         ParseGetPastLog(socket,util.format($log_file_name,rno));\r
262                 }\r
263                 else\r
264                 {\r
265                         var resource = require("./resources.js");\r
266                         socket.emit("error",resource.unmatch_password);\r
267                         return;\r
268                 }\r
269         }\r
270 \r
271         var newMeg = {\r
272                 name:$system_name,\r
273                 message:util.format("/enteredby %s %s %s",msg.name,msg.color,msg.mailto),\r
274         };\r
275         ParseSendMsg(socket,newMeg);\r
276 }\r
277 \r
278 function ParseQuit(socket,msg)\r
279 {\r
280         var ip = GetClientIPAdress(socket);\r
281 \r
282         var resource = require("./resources.js");\r
283         if(ipbanlist.IsBlockedToWrite(ip))\r
284         {\r
285                 socket.emit("error",resource.block_message);\r
286                 return;\r
287         }\r
288 \r
289         var rno = GetRoomNumberFromName(socket.namespace.name);\r
290 \r
291         var newMeg = {\r
292                 name:$system_name,\r
293                 message:resource.password_resetted_message,\r
294         };\r
295 \r
296         $rooms.Get(rno).AddRom(ip);\r
297 \r
298         var romcount = $rooms.Get(rno).GetRomCount();\r
299         socket.json.emit("send romcount",romcount);\r
300         socket.json.broadcast.emit("send romcount",romcount);\r
301 \r
302         if($rooms.Get(rno).IsVolatile() == false)\r
303         {\r
304                 if($rooms.Get(rno).IsOwner(msg.name))\r
305                 {\r
306                         $rooms.Get(rno).Reset(null);\r
307                         ParseSendMsg(socket,newMeg);\r
308                 }\r
309                 if(!$rooms.Get(rno).IsFirstAuth() &&\r
310                         !$rooms.Get(rno).IsAuthed(msg.name))\r
311                         return;\r
312                 else\r
313                         $rooms.Get(rno).RemoveAuth(msg.name);\r
314         }\r
315 \r
316         var util = require("util");\r
317         newMeg.message = util.format("/quitedby %s",msg.name);\r
318         ParseSendMsg(socket,newMeg);\r
319 }\r
320 \r
321 //socket 接続中のソケット\r
322 //msg msgクラス\r
323 function ParseSendMsg(socket,msg)\r
324 {\r
325         var ip = GetClientIPAdress(socket);\r
326 \r
327         if(ip in ipbanlist)\r
328         {\r
329                 var resource = require("./resources.js");\r
330                 socket.emit("error",resource.block_message);\r
331                 return;\r
332         }\r
333 \r
334         var rno = GetRoomNumberFromName(socket.namespace.name);\r
335 \r
336         if(msg.name != $system_name && \r
337                 $rooms.Get(rno).IsVolatile() == false &&\r
338                 !$rooms.Get(rno).IsAuthed(msg.name) &&\r
339                 !$rooms.Get(rno).IsOwner(rno,msg.name))\r
340         {\r
341                 return;\r
342         }\r
343 \r
344         var date = new Date();\r
345 \r
346         var repacked_msg = CreateMessage(msg.name,date,msg.message);\r
347 \r
348         if(socket.handshake.admin)\r
349                 repacked_msg.ip = ip;\r
350 \r
351         socket.json.emit("req msg", repacked_msg);\r
352 \r
353         socket.json.broadcast.emit("req msg", repacked_msg);\r
354 \r
355         var util = require("util");\r
356         var path = $log_directory + "/" + util.format($log_file_name,rno);\r
357         var log = new ChatLog(path);\r
358         log.Save(repacked_msg,ip,rno);\r
359 }\r
360 \r
361 function GetNameFromRoomNumber(number)\r
362 {\r
363         return "/" + number;\r
364 }\r
365 \r
366 function GetRoomNumberFromName(name)\r
367 {\r
368         if(name.charAt(0) == "/")\r
369                 return parseInt(name.substr(1));\r
370         throw "GetRoomNumberFromName error";\r
371 }\r
372 \r
373 function ParseGetPastLog(socket,file)\r
374 {\r
375         if(file == "")\r
376                 return;\r
377         var path = $log_directory + "/" + file;\r
378         var log = new ChatLog(path);\r
379         var config = require("./configure.js");\r
380         log.ToArray(config.showip,function(array){\r
381                 socket.json.emit("req pastlog",array);\r
382         });\r
383 }\r
384 \r
385 function ChatLog(path)\r
386 {\r
387         this.ToArray = function(hasIp,callback)\r
388         {\r
389                 var fs = require("fs");\r
390                 var state = fs.stat(path,function(err,state){\r
391                         if(err)\r
392                                 return;\r
393                         var array = new Array();\r
394                         var stream = fs.createReadStream(path);\r
395                         var lazy = require("lazy");\r
396                         new lazy(stream)\r
397                                 .lines\r
398                                 .forEach(function(line){\r
399                                         var msg = CreateMessageFromText(line.toString());\r
400                                         if(hasIp == false)\r
401                                                 msg.ip = "";\r
402                                         array.push(msg);\r
403                                 })\r
404                                 .join(function(){\r
405                                         callback(array);\r
406                                 });\r
407                 });\r
408         }\r
409 \r
410         this.Save = function(msg,ip,rno){\r
411                 var text = GetTextFromMessage(msg,ip);\r
412 \r
413                 SplitLog(rno,function(){\r
414                         WritePastLog(path,text);\r
415                 });\r
416         };\r
417 \r
418         function GetTextFromMessage(msg,ip)\r
419         {\r
420                 var text = msg.name + "<>" +\r
421                                 msg.date + "<>" +\r
422                                 ip + "<>" +\r
423                                 msg.message +\r
424                                 "\n";\r
425                 return text;\r
426         }\r
427 \r
428         function SplitLog(rno,callback)\r
429         {\r
430                 var util = require("util");\r
431                 var fs = require("fs");\r
432                 var state = fs.stat(path,function(err,state){\r
433                         if(err && typeof(callback) == "function")\r
434                         {\r
435                                 callback();\r
436                                 return;\r
437                         }\r
438                         if(state.size > $spilt_size)\r
439                         {\r
440                                 var date = new Date();\r
441                                 var dateString = ""+date.getFullYear()+date.getMonth()+date.getDate()+date.getHours()+date.getMinutes()+date.getSeconds();\r
442 \r
443                                 var newpath = $log_directory + "/" +\r
444                                         util.format($splited_log_file_name,rno,dateString);\r
445                                 fs.rename(path,newpath,callback);\r
446                         }else{\r
447                                 if(typeof(callback) == "function")\r
448                                         callback();\r
449                         }\r
450                 });\r
451         }\r
452 \r
453         function WritePastLog(path,text)\r
454         {\r
455                 var fs = require("fs");\r
456                 var async = require("async");\r
457                 async.waterfall([\r
458                         function(callback){\r
459                                 fs.open(path,"a",callback);\r
460                         },\r
461                         function(fd,callback){\r
462                                 var buf = new Buffer(text);\r
463                                 fs.write(fd,buf,0,Buffer.byteLength(text),null,function(){\r
464                                         callback(null,fd);\r
465                                 });\r
466                         },\r
467                         function(fd){\r
468                                 fs.close(fd);\r
469                         }\r
470                 ]);\r
471         }\r
472 }\r
473 \r
474 function GetClientIPAdress(socket)\r
475 {\r
476         return socket.handshake.headers["x-forwarded-for"] || socket.handshake.address.address;\r
477 }\r
478 \r
479 // Message クラス\r
480 function CreateMessage(name,date,message)\r
481 {\r
482         var result = {name:name,\r
483                 date:date,\r
484                 ip:"",\r
485                 message:message};\r
486         return result;\r
487 }\r
488 function CreateMessageFromText(text)\r
489 {\r
490         var data = text.split("<>");\r
491         var msg = {name:data[0],\r
492                 ip:data[2],\r
493                 date:data[1],\r
494                 message:data[3]};\r
495         return msg;\r
496 }\r