OSDN Git Service

/sendコマンドが動作しなくなっていた不具合を修正した
[webchat/WebChat.git] / chatServer.js
1 /*\r
2  * 設定\r
3  */\r
4 $max_room_number = 3;   //最大ルーム数\r
5 $spilt_size = 1024 * 512;       //分割するサイズ\r
6 $reset_password_diff = 1000 * 60 * 60;  //ルームパスワードをリセットする間隔\r
7 $gc_time_interval = 1000 * 60 * 60;     //ゴミ掃除を行う間隔\r
8 $block_message = "メッセージの送信に失敗しました";       //ブロック時のメッセージ\r
9 $not_match_password = "パスワードが一致しませんでした";  //パスワードが一致しない場合に表示されるメッセージ\r
10 $password_setted_message = "パスワードを設定しました";      //パスワードが設定されたときに表示されるメッセージ\r
11 $password_resetted_message = "パスワードをリセットしました";      //パスワードが再設定されたときに表示されるメッセージ\r
12 $failed_set_password_message = "パスワードの設定に失敗しました"; //パスワードが再設定されたときに表示されるメッセージ\r
13 $ip_ban_list_file_name = "ipbanlist.txt";       //アクセスを禁止するIPが記録されているファイル\r
14 $room_configure_file_name = "roomlist.txt";     //ルームの設定が記録されているファイル\r
15 $port = process.env.port || 3000;       //ポート\r
16 $username = "admin";    //管理者用のページにアクセスできるユーザ名\r
17 $password = "admin";    //管理者用のページにアクセスするのに必要なパスワード\r
18 $token_length = 32;     //トークンの長さ\r
19 $redisHost = "localhost";       //redisサーバのアドレス\r
20 $redisPort = 6379;      //redisサーバのポート\r
21 $redisPassword = "";    //redisサーバのパスワード\r
22 $system_name = "system";        //システム発言を表す名前\r
23 $log_directory = "log"; //ログファイルを置くフォルダー\r
24 $log_file_name = "logfile%d.txt";       //ログファイル名(%dはそのままにしておくこと)\r
25 $splited_log_file_name = "logfile%d_%s.txt"     //分割後のファイル名(%dと%sはそのままにしておくこと)\r
26 $pastlogfile_pattern = "logfile%d(_+.*)?\.txt"; //過去ログと判定する正規表現\r
27 \r
28 /**\r
29  * Module dependencies.\r
30  */\r
31 \r
32 // Server\r
33 var express = require('express');\r
34 \r
35 var app = module.exports = express.createServer();\r
36 \r
37 var util = require("util");\r
38 \r
39 var lazy = require("./lazy.js");\r
40 \r
41 var fs = require("fs");\r
42 \r
43 var parseCookie = require("connect").utils.parseCookie;\r
44 \r
45 var RedisStore = require("connect-redis")(express);\r
46 var sessionStore = new RedisStore({host:$redisHost,port:$redisPort,pass:$redisPassword});\r
47 \r
48 var async = require("async");\r
49 \r
50 var path = require("path");\r
51 \r
52 // Configuration\r
53 \r
54 app.configure(function(){\r
55         app.disabled("view cache");\r
56         app.set("view options", { layout: false })\r
57         app.set("views", __dirname + "/public");\r
58         app.set("view engine", "ejs");\r
59         app.use(express.bodyParser());\r
60         app.use(express.methodOverride());\r
61         app.use(express.cookieParser());\r
62         app.use(express.session({\r
63                 store:sessionStore,\r
64                 secret: "5514EA2B-C9B2-4D65-8D81-1F33A180A0C2",\r
65                 cookie: { httpOnly: false }\r
66         }));\r
67         app.use(app.router);\r
68         app.use(express.static(__dirname + "/public"));\r
69 });\r
70 \r
71 app.configure('development', function(){\r
72   app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); \r
73 });\r
74 \r
75 app.configure('production', function(){\r
76   app.use(express.errorHandler()); \r
77 });\r
78 \r
79 function SessionInfomation(token,admin)\r
80 {\r
81         this.token = token;\r
82         this.admin = admin;\r
83 }\r
84 \r
85 // Routes\r
86 app.get("/chat", function(req, res){\r
87         var auth_string = getRandomString($token_length);\r
88         req.session.items = new SessionInfomation(auth_string,false);\r
89 \r
90         var room_number = 0;\r
91         if(typeof(req.query.rno) != "undefined")\r
92                 room_number = req.query.rno;\r
93         res.render("chat",{rno:room_number,token:auth_string});\r
94 });\r
95 \r
96 app.all("/log/*",express.basicAuth(function (user, pass) {\r
97         return user === $username && pass === $password;\r
98 }));\r
99 \r
100 app.get("/log/*",function (req, res) {\r
101         res.sendfile(__dirname + req.url);\r
102 });\r
103 \r
104 app.all("/admin_chat",express.basicAuth(function (user, pass) {\r
105         return user === $username && pass === $password;\r
106 }));\r
107 \r
108 app.get("/admin_chat", function(req, res){\r
109         var auth_string = getRandomString($token_length);\r
110         req.session.items = new SessionInfomation(auth_string,true);\r
111 \r
112         var room_number = 0;\r
113         if(typeof(req.query.rno) != "undefined")\r
114                 room_number = req.query.rno;\r
115         res.render("chat",{rno:room_number,token:auth_string});\r
116 });\r
117 \r
118 app.all("/admin",express.basicAuth(function (user, pass) {\r
119         return user === $username && pass === $password;\r
120 }));\r
121 \r
122 app.get("/admin", function(req, res){\r
123         renderAdmin(req,res);\r
124 });\r
125 \r
126 app.post("/admin",function(req,res){\r
127         if(req.session.items.token != req.body.token)\r
128         {\r
129                 res.send($invaild_token_message);\r
130                 return;\r
131         }\r
132         if(typeof(req.body.erase) != "undefined")\r
133         {\r
134                 removeLog(req.body.file,function(){\r
135                         renderAdmin(req,res);\r
136                 });\r
137         }\r
138         if(typeof(req.body.registor) != "undefined")\r
139         {\r
140                 ipbanlist.Update(req.body.newbanlist,function(){\r
141                         renderAdmin(req,res);\r
142                 });\r
143         }\r
144         if(typeof(req.body.updateroom) != "undefined")\r
145         {\r
146                 $rooms.Update(req.body.newroomlist,function(){\r
147                         renderAdmin(req,res);\r
148                 });\r
149         }\r
150 });\r
151 \r
152 function renderAdmin(req,res)\r
153 {\r
154         var auth_string = getRandomString($token_length);\r
155         req.session.items = {token:auth_string};\r
156         var iplist = ipbanlist.GetText();\r
157 \r
158         fs.readdir($log_directory,function(err,list){\r
159                 res.render("admin", {\r
160                         files: list,\r
161                         log_directory:$log_directory,\r
162                         ipbanlist:iplist,\r
163                         token:auth_string,\r
164                         roomlist:$rooms.GetString()\r
165                 });\r
166         });\r
167 }\r
168 \r
169 function getRandomString(length)\r
170 {\r
171         var RandomString = "";\r
172         var BaseString ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&'()=~|-^\@[;:],./\`{+*}<>?_";\r
173         for(var i=0; i<length; i++) {\r
174                 RandomString += BaseString.charAt( Math.floor( Math.random() * BaseString.length));\r
175         }\r
176         return RandomString\r
177 }\r
178 \r
179 function removeLog(files,callback)\r
180 {\r
181         async.map(files,\r
182         function(item,callback){\r
183                 fs.unlink($log_directory + "/" + item,callback);\r
184         },\r
185         function(err,results){\r
186                 if(typeof(callback) == "function")\r
187                         callback();\r
188         });\r
189 }\r
190 \r
191 app.listen($port);\r
192 console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);\r
193 \r
194 /*\r
195  * サーバー部分\r
196  */\r
197 \r
198 var io = require("socket.io").listen(app);\r
199 io.configure('production', function(){\r
200   io.enable('browser client minification');  // minified されたクライアントファイルを送信する\r
201   io.enable('browser client etag');          // バージョンによって etag によるキャッシングを有効にする\r
202   io.set('log level', 1);                    // ログレベルを設定(デフォルトより下げている)\r
203 });\r
204 var clients = new Array();\r
205 \r
206 var ipbanlist = new IpBanCollecion();\r
207 var $rooms = new RoomInfomationCollection();\r
208 \r
209 createLogDirectory();\r
210 \r
211 for(var i = 0; i < $max_room_number; i++)\r
212 {\r
213         clients[i] =io\r
214         .of(GetNameFromRoomNumber(i))\r
215         .authorization(ParseAuthorization)\r
216         .on("connection", function (socket) {\r
217                 var ip = GetClientIPAdress(socket);\r
218 \r
219                 console.log("connected from %s",ip);\r
220 \r
221                 var rno = GetRoomNumberFromName(socket.namespace.name);\r
222                 var roomconfig = {};\r
223                 $rooms.Get(rno).AddRom(ip);\r
224                 if($rooms.Get(rno).IsVolatile() == false)\r
225                 {\r
226                         if($rooms.Get(rno).IsFixedPassword())\r
227                                 roomconfig.type = 2;\r
228                         else if($rooms.Get(rno).IsHiddenLogFromRom())\r
229                                 roomconfig.type = 3;\r
230                         else\r
231                                 roomconfig.type = 1;\r
232                         roomconfig.IsOwned = !$rooms.Get(rno).IsFirstAuth();\r
233                 }else{\r
234                         roomconfig.type = 0;\r
235                 }\r
236                 roomconfig.admin = socket.handshake.admin;\r
237                 socket.json.emit("send roominfo",roomconfig);\r
238 \r
239                 var romcount = $rooms.Get(rno).GetRomCount();\r
240                 socket.json.emit("send romcount",romcount);\r
241                 socket.json.broadcast.emit("send romcount",romcount);\r
242 \r
243                 socket.on("get pastLogList", function (msg) {\r
244                         ParseGetPastLogList(socket,msg);\r
245                 });\r
246                 socket.on("get pastLog", function (msg) {\r
247                         ParseGetPastLog(socket,msg);\r
248                 });\r
249                 socket.on("join",function(msg){\r
250                         ParseJoin(socket,msg);\r
251                 });\r
252                 socket.on("quit",function(msg){\r
253                         ParseQuit(socket,msg);\r
254                 });\r
255                 socket.on("set password",function(msg){\r
256                         ParseSetPassword(socket,msg);\r
257                 });\r
258                 socket.on("send msg", function (msg) {\r
259                         ParseSendMsg(socket,msg);\r
260                 });\r
261                 socket.on("disconnect", function (msg) {\r
262                         ParseDisconnect(socket,msg);\r
263                 });\r
264         });\r
265 }\r
266 \r
267 function createLogDirectory()\r
268 {\r
269         path.exists($log_directory,function(exists){\r
270                 if(exists == false)\r
271                         fs.mkdirSync($log_directory);\r
272         });\r
273 }\r
274 \r
275 function ParseAuthorization(handshakeData, callback)\r
276 {\r
277         if(handshakeData.headers.cookie) {\r
278                 var cookie = handshakeData.headers.cookie;\r
279                 var sessionID = parseCookie(cookie)["connect.sid"];\r
280                 sessionStore.get(sessionID, function (err, session) {\r
281                         var result = null;\r
282                         if (ipbanlist.IsBaned(handshakeData.address.address))\r
283                                 result = "failed get from session store";\r
284                         else if(err)\r
285                                 result = err;\r
286                         else if(handshakeData.query.token != session.items.token)\r
287                                 result = "invaild token";\r
288                         if(typeof(session) != "undefined" && result == null)\r
289                         {\r
290                                 handshakeData.admin = session.items.admin;\r
291                                 handshakeData.sessionID = sessionID;\r
292                         }\r
293                         callback(result,result == null && !err);\r
294                 });\r
295         } else {\r
296                 return callback("failed get cookie", false);\r
297         }\r
298 }\r
299 \r
300 function ParseDisconnect(socket,msg)\r
301 {\r
302         var ip = GetClientIPAdress(socket);\r
303         var rno = GetRoomNumberFromName(socket.namespace.name);\r
304         $rooms.Get(rno).RemoveRom(ip);\r
305 \r
306         var romcount = $rooms.Get(rno).GetRomCount();\r
307         socket.json.emit("send romcount",romcount);\r
308         socket.json.broadcast.emit("send romcount",romcount);\r
309 \r
310         sessionStore.destroy(socket.handshake.sessionID);\r
311 \r
312         console.log("disconnected");\r
313 }\r
314 \r
315 function ParseSetPassword(socket,msg)\r
316 {\r
317         var rno = GetRoomNumberFromName(socket.namespace.name);\r
318         var newMeg = {\r
319                 name:$system_name,\r
320                 message:null,\r
321         };\r
322         if($rooms.Get(rno).IsVolatile() == false && $rooms.Get(rno).SetPassword(msg.owner,msg.password))\r
323                 newMeg.message = $password_setted_message;\r
324         else\r
325                 newMeg.message = $failed_set_password_message;\r
326         ParseSendMsg(socket,newMeg);\r
327 }\r
328 \r
329 function ParseJoin(socket,msg)\r
330 {\r
331         var ip = GetClientIPAdress(socket);\r
332 \r
333         if(ipbanlist.IsBlockedToWrite(ip))\r
334         {\r
335                 socket.emit("error",$block_message);\r
336                 return;\r
337         }\r
338 \r
339         var rno = GetRoomNumberFromName(socket.namespace.name);\r
340 \r
341         $rooms.Get(rno).RemoveRom(ip);\r
342         \r
343         var romcount = $rooms.Get(rno).GetRomCount();\r
344         socket.json.emit("send romcount",romcount);\r
345         socket.json.broadcast.emit("send romcount",romcount);\r
346 \r
347         if($rooms.Get(rno).IsVolatile() == false)\r
348         {\r
349                 if($rooms.Get(rno).IsTimeout() ||\r
350                         $rooms.Get(rno).IsFirstAuth())\r
351                 {\r
352                         $rooms.Get(rno).Reset(msg.name);\r
353                         ParseGetPastLog(socket,util.format($log_file_name,rno));\r
354                 }\r
355                 else if($rooms.Get(rno).Auth(msg.name,msg.password))\r
356                 {\r
357                         ParseGetPastLog(socket,util.format($log_file_name,rno));\r
358                 }\r
359                 else\r
360                 {\r
361                         socket.emit("error",$not_match_password);\r
362                         return;\r
363                 }\r
364         }\r
365 \r
366         var newMeg = {\r
367                 name:$system_name,\r
368                 message:util.format("/enteredby %s %s %s",msg.name,msg.color,msg.mailto),\r
369         };\r
370         ParseSendMsg(socket,newMeg);\r
371 }\r
372 \r
373 function ParseQuit(socket,msg)\r
374 {\r
375         var ip = GetClientIPAdress(socket);\r
376 \r
377         if(ipbanlist.IsBlockedToWrite(ip))\r
378         {\r
379                 socket.emit("error",$block_message);\r
380                 return;\r
381         }\r
382 \r
383         var rno = GetRoomNumberFromName(socket.namespace.name);\r
384 \r
385         var newMeg = {\r
386                 name:$system_name,\r
387                 message:$password_resetted_message,\r
388         };\r
389 \r
390         $rooms.Get(rno).AddRom(ip);\r
391 \r
392         var romcount = $rooms.Get(rno).GetRomCount();\r
393         socket.json.emit("send romcount",romcount);\r
394         socket.json.broadcast.emit("send romcount",romcount);\r
395 \r
396         if($rooms.Get(rno).IsVolatile() == false)\r
397         {\r
398                 if($rooms.Get(rno).IsOwner(msg.name))\r
399                 {\r
400                         $rooms.Get(rno).Reset(null);\r
401                         ParseSendMsg(socket,newMeg);\r
402                 }\r
403                 if(!$rooms.Get(rno).IsFirstAuth() &&\r
404                         !$rooms.Get(rno).IsAuthed(msg.name))\r
405                         return;\r
406                 else\r
407                         $rooms.Get(rno).RemoveAuth(msg.name);\r
408         }\r
409 \r
410         newMeg.message = util.format("/quitedby %s",msg.name);\r
411         ParseSendMsg(socket,newMeg);\r
412 }\r
413 \r
414 //socket 接続中のソケット\r
415 //msg msgクラス\r
416 function ParseSendMsg(socket,msg)\r
417 {\r
418         var ip = GetClientIPAdress(socket);\r
419 \r
420         if(ip in ipbanlist)\r
421         {\r
422                 socket.emit("error",$block_message);\r
423                 return;\r
424         }\r
425 \r
426         var rno = GetRoomNumberFromName(socket.namespace.name);\r
427 \r
428         if(msg.name != $system_name && \r
429                 $rooms.Get(rno).IsVolatile() == false &&\r
430                 !$rooms.Get(rno).IsAuthed(msg.name) &&\r
431                 !$rooms.Get(rno).IsOwner(rno,msg.name))\r
432         {\r
433                 return;\r
434         }\r
435 \r
436         var date = new Date();\r
437 \r
438         var repacked_msg = CreateMessage(msg.name,date,msg.message);\r
439 \r
440         if(socket.handshake.admin)\r
441                 repacked_msg.ip = ip;\r
442 \r
443         socket.json.emit("req msg", repacked_msg);\r
444 \r
445         socket.json.broadcast.emit("req msg", repacked_msg);\r
446 \r
447         var path = $log_directory + "/" + util.format($log_file_name,rno);\r
448         var log = new ChatLog(path);\r
449         log.Save(repacked_msg,ip,rno);\r
450 }\r
451 \r
452 function GetNameFromRoomNumber(number)\r
453 {\r
454         return "/" + number;\r
455 }\r
456 \r
457 function GetRoomNumberFromName(name)\r
458 {\r
459         if(name.charAt(0) == "/")\r
460                 return parseInt(name.substr(1));\r
461         throw "GetRoomNumberFromName error";\r
462 }\r
463 \r
464 function ParseGetPastLogList(socket,msg)\r
465 {\r
466         var list = fs.readdir($log_directory,function(err,files){\r
467                 var text = "";\r
468                 var rno = GetRoomNumberFromName(socket.namespace.name);\r
469                 var pattern = $pastlogfile_pattern.replace("%d",rno);\r
470                 for(var i = 0; i < files.length; i++)\r
471                 {\r
472                         var logname = files[i];\r
473                         if(logname.match(pattern))\r
474                                 text += files[i] + "\n";\r
475                 }\r
476                 socket.emit("req pastloglist",text);\r
477         });\r
478 }\r
479 \r
480 function ParseGetPastLog(socket,file)\r
481 {\r
482         if(file == "")\r
483                 return;\r
484         var path = $log_directory + "/" + file;\r
485         var log = new ChatLog(path);\r
486         log.ToArray(socket.handshake.admin,function(array){\r
487                 socket.json.emit("req pastlog",array);\r
488         });\r
489 }\r
490 \r
491 function ChatLog(path)\r
492 {\r
493         this.ToArray = function(hasIp,callback)\r
494         {\r
495                 var state = fs.stat(path,function(err,state){\r
496                         if(err)\r
497                                 return;\r
498                         var array = new Array();\r
499                         var stream = fs.createReadStream(path);\r
500                         new lazy(stream)\r
501                                 .spilt(";")\r
502                                 .forEach(function(line){\r
503                                         var msg = CreateMessageFromText(line.toString());\r
504                                         if(hasIp == false)\r
505                                                 msg.ip = "";\r
506                                         array.push(msg);\r
507                                 })\r
508                                 .join(function(){\r
509                                         callback(array);\r
510                                 });\r
511                 });\r
512         }\r
513 \r
514         this.Save = function(msg,ip,rno){\r
515                 var text = GetTextFromMessage(msg,ip);\r
516 \r
517                 SplitLog(rno,function(){\r
518                         WritePastLog(path,text);\r
519                 });\r
520         };\r
521 \r
522         function GetTextFromMessage(msg,ip)\r
523         {\r
524                 var text = msg.name + "<>" +\r
525                                 msg.date + "<>" +\r
526                                 ip + "<>" +\r
527                                 msg.message +\r
528                                 ";";\r
529                 return text;\r
530         }\r
531 \r
532         function SplitLog(rno,callback)\r
533         {\r
534                 var state = fs.stat(path,function(err,state){\r
535                         if(err && typeof(callback) == "function")\r
536                         {\r
537                                 callback();\r
538                                 return;\r
539                         }\r
540                         if(state.size > $spilt_size)\r
541                         {\r
542                                 var date = new Date();\r
543                                 var dateString = ""+date.getFullYear()+date.getMonth()+date.getDate()+date.getHours()+date.getMinutes()+date.getSeconds();\r
544 \r
545                                 var newpath = $log_directory + "/" +\r
546                                         util.format($splited_log_file_name,rno,dateString);\r
547                                 fs.rename(path,newpath,callback);\r
548                         }else{\r
549                                 if(typeof(callback) == "function")\r
550                                         callback();\r
551                         }\r
552                 });\r
553         }\r
554 \r
555         function WritePastLog(path,text)\r
556         {\r
557                 async.waterfall([\r
558                         function(callback){\r
559                                 fs.open(path,"a",callback);\r
560                         },\r
561                         function(fd,callback){\r
562                                 var buf = new Buffer(text);\r
563                                 fs.write(fd,buf,0,Buffer.byteLength(text),null,function(){\r
564                                         callback(null,fd);\r
565                                 });\r
566                         },\r
567                         function(fd){\r
568                                 fs.close(fd);\r
569                         }\r
570                 ]);\r
571         }\r
572 }\r
573 \r
574 function GetClientIPAdress(socket)\r
575 {\r
576         return socket.handshake.headers["x-forwarded-for"] || socket.handshake.address.address;\r
577 }\r
578 \r
579 // Message クラス\r
580 function CreateMessage(name,date,message)\r
581 {\r
582         var result = {name:name,\r
583                 date:date,\r
584                 ip:"",\r
585                 message:message};\r
586         return result;\r
587 }\r
588 function CreateMessageFromText(text)\r
589 {\r
590         var data = text.split("<>");\r
591         var msg = {name:data[0],\r
592                 ip:data[2],\r
593                 date:data[1],\r
594                 message:data[3]};\r
595         return msg;\r
596 }\r
597 \r
598 //RoomInfomationCollecionクラス\r
599 function RoomInfomationCollection()\r
600 {\r
601         var collection = {};\r
602         this.Get = function(rno){\r
603                 return collection[rno];\r
604         }\r
605         this.IsContains = function(rno){\r
606                 return rno in collection;\r
607         };\r
608         this.GetString = function(){\r
609                 var retval = "";\r
610                 for(var rno in collection)\r
611                 {\r
612                         if($rooms.Get(rno).IsVolatile())\r
613                                 continue;\r
614                         var pass = collection[rno].password;\r
615                         if(pass == null)\r
616                                 pass = "";\r
617                         var hiddenlog = collection[rno].hiddenlog;\r
618                         retval += rno + ":" + pass + ":" + hiddenlog + "\r\n";\r
619                 }\r
620                 return retval;\r
621         };\r
622         this.GetKeys = function(){\r
623                 var retval = {};\r
624                 for(var rno in collection)\r
625                 {\r
626                         retval[rno] = {};\r
627                 }\r
628                 return retval;\r
629         }\r
630         this.Update = function(text,callfunc){\r
631                 async.waterfall([\r
632                         function(callback){\r
633                                 fs.open($room_configure_file_name,"w",callback);\r
634                         },\r
635                         function(fd,callback){\r
636                                 var buf = new Buffer(text);\r
637                                 fs.write(fd,buf,0,Buffer.byteLength(text),null,function(){\r
638                                         callback(null,fd);\r
639                                 });\r
640                         },\r
641                         function(fd,callback){\r
642                                 fs.close(fd,function(){\r
643                                         GetRoomList(callfunc);\r
644                                 });\r
645                         }\r
646                 ]);\r
647         }\r
648         function GetRoomList(callback){\r
649                 Clear();\r
650                 path.exists($room_configure_file_name,function(exists){\r
651                         if(exists == false)\r
652                         {\r
653                                 if(typeof(callback) == "function")\r
654                                         callback();\r
655                                 return;\r
656                         }\r
657                         var stream = fs.createReadStream($room_configure_file_name);\r
658                         new lazy(stream)\r
659                                 .lines\r
660                                 .forEach(function(line){\r
661                                         var token = line.toString().replace(/(\r|\n|\r\n)/gm, "").split(":");\r
662                                         if(token.length == 1)\r
663                                         {\r
664                                                 Add(token[0],null,false);\r
665                                         }\r
666                                         else if(token.length == 2)\r
667                                         {\r
668                                                 var rno = token[0];\r
669                                                 var pass = token[1];\r
670                                                 if(pass == "")\r
671                                                         pass = null;\r
672                                                 Add(rno, pass,false);\r
673                                         }\r
674                                         else if(token.length == 3)\r
675                                         {\r
676                                                 var rno = token[0];\r
677                                                 var pass = token[1];\r
678                                                 if(pass == "")\r
679                                                         pass = null;\r
680                                                 var hiddenlog = false;\r
681                                                 if(token[2] == "true")\r
682                                                         hiddenlog = true;\r
683                                                 Add(rno, pass,hiddenlog);\r
684                                         }\r
685                                 })\r
686                                 .join(function(){\r
687                                         if(typeof(callback) == "function")\r
688                                                 callback();\r
689                                 });\r
690                 });\r
691         }\r
692         function Clear(){\r
693                 collection = {};\r
694                 for(var i = 0; i < $max_room_number; i++)\r
695                         Add(i,null,null);\r
696         };\r
697         function Add(rno,pass,hiddenlogflag){\r
698                 collection[rno] = new RoomInfomation(pass,hiddenlogflag);\r
699                 if(pass != null)\r
700                         collection[rno].owner = $system_name;\r
701         };\r
702         var $gc_interval_id = setInterval(function(){\r
703                 for(var rno in this.rom_list)\r
704                         collection[rno].GCRomList();\r
705         },$gc_time_interval);\r
706         GetRoomList();\r
707 }\r
708 \r
709 //RoomInfomationクラス\r
710 function RoomInfomation(pass,hiddenlogflag)\r
711 {\r
712         this.password = pass;\r
713         this.rom_list = {};\r
714         this.authed_list = {};\r
715         this.owner = null;\r
716         this.time = null;\r
717         this.hiddenlog = hiddenlogflag;\r
718         this.IsVolatile = function(){\r
719                 return this.owner == null &&\r
720                         this.password == null &&\r
721                         this.time == null &&\r
722                         this.hiddenlog == null;\r
723         }\r
724         this.GetRomCount = function(){\r
725                 var count = 0;\r
726                 for(var key in this.rom_list)\r
727                         count++;\r
728                 return count;\r
729         };\r
730         this.AddRom = function(ip){\r
731                 var date = new Date();\r
732                 this.rom_list[ip] = {time:date.getTime()};\r
733         };\r
734         this.RemoveRom = function(ip){\r
735                 delete this.rom_list[ip];\r
736         };\r
737         this.Reset = function(owner){\r
738                 var date = new Date();\r
739                 var time = date.getTime();\r
740                 this.password = null;\r
741                 this.authed_list = {};\r
742                 this.owner = owner;\r
743                 this.time = time;\r
744         };\r
745         this.IsFirstAuth = function(){\r
746                 return this.owner == null;\r
747         };\r
748         this.IsAuthed = function(name){\r
749                 return name == this.owner ||\r
750                         name in this.authed_list;\r
751         };\r
752         this.IsHiddenLogFromRom = function(){\r
753                 return this.hiddenlog;\r
754         };\r
755         this.IsFixedPassword = function(){\r
756                 return this.owner == $system_name;\r
757         };\r
758         this.IsOwner = function(name){\r
759                 return this.owner == name;\r
760         };\r
761         this.IsTimeout = function(){\r
762                 var date = new Date();\r
763                 var current_time = date.getTime();\r
764                 return !this.IsFixedPassword() &&\r
765                         current_time - this.time >= $reset_password_diff;\r
766         };\r
767         this.RemoveAuth = function(name)\r
768         {\r
769                 delete this.authed_list[name];\r
770         };\r
771         this.Auth = function(name,password){\r
772                 if(this.password != password)\r
773                         return false;\r
774                 var date = new Date();\r
775                 var time = date.getTime();\r
776                 this.time = time;\r
777                 this.authed_list[name] = "";\r
778                 return true;\r
779         };\r
780         this.SetPassword = function(owner,password){\r
781                 if(owner == this.owner &&\r
782                         !this.IsFixedPassword() &&\r
783                         !this.IsHiddenLogFromRom())\r
784                 {\r
785                         var date = new Date();\r
786                         this.time = date.getTime();\r
787                         this.password = password;\r
788                         return true;\r
789                 }\r
790                 return false;\r
791         };\r
792         this.GCRomList = function(){\r
793                 var date = new Date();\r
794                 var current_time = date.getTime();\r
795                 for(var ip in this.rom_list)\r
796                 {\r
797                         if(current_time - this.rom_list[ip].time >= $gc_time_interval)\r
798                                 delete this.rom_list[ip];\r
799                 }\r
800         };\r
801 }\r
802 \r
803 //IPBANクラス\r
804 function IpBanCollecion()\r
805 {\r
806         var collection = {};\r
807         this.IsBaned = function(ip){\r
808                 return collection[ip] == "r";\r
809         }\r
810         this.IsBlockedToWrite = function(ip){\r
811                 return ip in collection;\r
812         }\r
813         this.GetText = function(){\r
814                 var text = "";\r
815                 for(var key in collection)\r
816                 {\r
817                         if(collection[key] == "")\r
818                                 text += key + "\r\n";\r
819                         else\r
820                                 text += key + ":" + collection[key] + "\r\n";\r
821                 }\r
822                 return text;\r
823         }\r
824         this.Update = function(text,callfunc){\r
825                 async.waterfall([\r
826                         function(callback){\r
827                                 fs.open($ip_ban_list_file_name,"w",callback);\r
828                         },\r
829                         function(fd,callback){\r
830                                 var buf = new Buffer(text);\r
831                                 fs.write(fd,buf,0,Buffer.byteLength(text),null,function(){\r
832                                         callback(null,fd);\r
833                                 });\r
834                         },\r
835                         function(fd,callback){\r
836                                 fs.close(fd,function(){\r
837                                         GetIpBanList(callfunc);\r
838                                 });\r
839                         }\r
840                 ]);\r
841         }\r
842         function GetIpBanList(callback)\r
843         {\r
844                 collection = {};\r
845                 path.exists($ip_ban_list_file_name,function(exists){\r
846                         if(exists == false)\r
847                         {\r
848                                 if(typeof(callback) == "function")\r
849                                         callback();\r
850                                 return;\r
851                         }\r
852                         var stream = fs.createReadStream($ip_ban_list_file_name);\r
853                         new lazy(stream)\r
854                                 .lines\r
855                                 .forEach(function(line){\r
856                                         var token = line.toString().replace(/(\r|\n|\r\n)/gm, "").split(":");\r
857                                         var ip = token[0];\r
858                                         if(token.length == 1)\r
859                                                 collection[ip] = "";\r
860                                         else\r
861                                                 collection[ip] = token[1];\r
862                                 })\r
863                                 .join(function(){\r
864                                         if(typeof(callback) == "function")\r
865                                                 callback();\r
866                                 });\r
867                 });\r
868         }\r
869         GetIpBanList();\r
870 }\r
871 \r