OSDN Git Service

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