X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=chatServer.js;h=7cd3b4baa546d33f11e4399d24beb81b0bcaf57e;hb=d501b546a3aef96a7746665ddc99b7c948cdc0fd;hp=461c0e5c17dabfc802aed8724347f539fda0eafd;hpb=3c69f5a69c77a3369b8505d4f1d846b2c20d5fba;p=webchat%2FWebChat.git diff --git a/chatServer.js b/chatServer.js index 461c0e5..7cd3b4b 100644 --- a/chatServer.js +++ b/chatServer.js @@ -3,16 +3,15 @@ */ $max_room_number = 3; //最大ルーム数 $spilt_size = 1024 * 512; //分割するサイズ -$reset_password_diff = 1000 * 60 * 60; +$reset_password_diff = 1000 * 60 * 60; //ルームパスワードをリセットする間隔 +$gc_time_interval = 1000 * 60 * 60; //ゴミ掃除を行う間隔 $block_message = "メッセージの送信に失敗しました"; //ブロック時のメッセージ $not_match_password = "パスワードが一致しませんでした"; //パスワードが一致しない場合に表示されるメッセージ $password_setted_message = "パスワードを設定しました"; //パスワードが設定されたときに表示されるメッセージ $password_resetted_message = "パスワードをリセットしました"; //パスワードが再設定されたときに表示されるメッセージ $failed_set_password_message = "パスワードの設定に失敗しました"; //パスワードが再設定されたときに表示されるメッセージ -$free_password1 = "最初に入室する人が自由にパスワードを設定できます"; //自由パスワードメッセージ1 -$free_password2 = "この部屋は使用されています。パスワードを入力してください"; //自由パスワードメッセージ2 -$fixed_password = "この部屋にはパスワードが設定されています"; //固定パスワードルーム $ip_ban_list_file_name = "ipbanlist.txt"; //アクセスを禁止するIPが記録されているファイル +$room_configure_file_name = "roomlist.txt"; //ルームの設定が記録されているファイル $port = process.env.port || 3000; //ポート $username = "admin"; //管理者用のページにアクセスできるユーザ名 $password = "admin"; //管理者用のページにアクセスするのに必要なパスワード @@ -25,36 +24,27 @@ $log_directory = "log"; //ログファイルを置くフォルダー $log_file_name = "logfile%d.txt"; //ログファイル名(%dはそのままにしておくこと) $splited_log_file_name = "logfile%d_%s.txt" //分割後のファイル名(%dと%sはそのままにしておくこと) $pastlogfile_pattern = "logfile%d(_+.*)?\.txt"; //過去ログと判定する正規表現 -$logfile_pattern = "logfile[0-9]+(_*.*)?\.txt" //過去ログと判定する正規表現 -//パスワードを自由に設定できる部屋のリスト -// rno 設定したい部屋番号 -// password パスワードを設定する。nullにすると利用者がパスワードの設定をすることができる -//記述例: -// new RoomInfomationCollection( -// {rno:"1",password:"test"}, -// {rno:"2",password:null} -// ) -$rooms = new RoomInfomationCollection( - {rno:"1",password:"test"}, - {rno:"2",password:null} -); - +$secret = "5514EA2B-C9B2-4D65-8D81-1F33A180A0C2"; /** * Module dependencies. */ // Server -var express = require('express'); +var express = require("express"); + +var app = express(); -var app = module.exports = express.createServer(); +var http = require("http"); var util = require("util"); -var lazy = require("lazy"); +var lazy = require("./lazy.js"); var fs = require("fs"); -var parseCookie = require("connect").utils.parseCookie; +var cookie = require("express/node_modules/cookie"); + +var connectUtils = require("express/node_modules/connect/lib/utils"); var RedisStore = require("connect-redis")(express); var sessionStore = new RedisStore({host:$redisHost,port:$redisPort,pass:$redisPassword}); @@ -72,10 +62,9 @@ app.configure(function(){ app.set("view engine", "ejs"); app.use(express.bodyParser()); app.use(express.methodOverride()); - app.use(express.cookieParser()); + app.use(express.cookieParser($secret)); app.use(express.session({ store:sessionStore, - secret: "5514EA2B-C9B2-4D65-8D81-1F33A180A0C2", cookie: { httpOnly: false } })); app.use(app.router); @@ -90,32 +79,45 @@ app.configure('production', function(){ app.use(express.errorHandler()); }); +function SessionInfomation(token,admin) +{ + this.token = token; + this.admin = admin; +} + // Routes app.get("/chat", function(req, res){ var auth_string = getRandomString($token_length); - req.session.items = {token:auth_string}; + req.session.items = new SessionInfomation(auth_string,false); var room_number = 0; if(typeof(req.query.rno) != "undefined") room_number = req.query.rno; - var msg = ""; - if($rooms.IsFixedPassword(room_number)) - msg = $fixed_password; - else if($rooms.IsContains(room_number)) - msg = $free_password2; - if($rooms.IsFirstAuth(room_number)) - msg = $free_password1; - res.render("chat",{rno:room_number,token:auth_string,message:msg}); + res.render("chat",{rno:room_number,token:auth_string}); }); -app.all("/log/" + $logfile_pattern,express.basicAuth(function (user, pass) { +app.all("/log/*",express.basicAuth(function (user, pass) { return user === $username && pass === $password; })); -app.get("/log/" + $logfile_pattern, function(req, res){ +app.get("/log/*",function (req, res) { res.sendfile(__dirname + req.url); }); +app.all("/admin_chat",express.basicAuth(function (user, pass) { + return user === $username && pass === $password; +})); + +app.get("/admin_chat", function(req, res){ + var auth_string = getRandomString($token_length); + req.session.items = new SessionInfomation(auth_string,true); + + var room_number = 0; + if(typeof(req.query.rno) != "undefined") + room_number = req.query.rno; + res.render("chat",{rno:room_number,token:auth_string}); +}); + app.all("/admin",express.basicAuth(function (user, pass) { return user === $username && pass === $password; })); @@ -138,14 +140,15 @@ app.post("/admin",function(req,res){ } if(typeof(req.body.registor) != "undefined") { - updateIpBanList(req.body.newbanlist,function(){ + ipbanlist.Update(req.body.newbanlist,function(){ renderAdmin(req,res); }); } if(typeof(req.body.updateroom) != "undefined") { - CreateRoomsFromString(req.body.newroomlist); - renderAdmin(req,res); + $rooms.Update(req.body.newroomlist,function(){ + renderAdmin(req,res); + }); } }); @@ -153,12 +156,13 @@ function renderAdmin(req,res) { var auth_string = getRandomString($token_length); req.session.items = {token:auth_string}; + var iplist = ipbanlist.GetText(); fs.readdir($log_directory,function(err,list){ res.render("admin", { files: list, log_directory:$log_directory, - ipbanlist:getTextFromIpBanlist(ipbanlist), + ipbanlist:iplist, token:auth_string, roomlist:$rooms.GetString() }); @@ -187,14 +191,13 @@ function removeLog(files,callback) }); } -app.listen($port); -console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env); +var server = http.createServer(app).listen($port); /* * サーバー部分 */ -var io = require("socket.io").listen(app); +var io = require("socket.io").listen(server); io.configure('production', function(){ io.enable('browser client minification'); // minified されたクライアントファイルを送信する io.enable('browser client etag'); // バージョンによって etag によるキャッシングを有効にする @@ -202,20 +205,43 @@ io.configure('production', function(){ }); var clients = new Array(); -var ipbanlist = {}; +var ipbanlist = new IpBanCollecion(); +var $rooms = new RoomInfomationCollection(); createLogDirectory(); -getIpBanList(); - for(var i = 0; i < $max_room_number; i++) { clients[i] =io .of(GetNameFromRoomNumber(i)) .authorization(ParseAuthorization) .on("connection", function (socket) { - console.log("connected from %s",GetClientIPAdress(socket)); - socket.json.emit("send roomlist",$rooms.GetKeys()); + var ip = GetClientIPAdress(socket); + + console.log("connected from %s",ip); + + var rno = GetRoomNumberFromName(socket.namespace.name); + var roomconfig = {}; + $rooms.Get(rno).AddRom(ip); + if($rooms.Get(rno).IsVolatile() == false) + { + if($rooms.Get(rno).IsFixedPassword()) + roomconfig.type = 2; + else if($rooms.Get(rno).IsHiddenLogFromRom()) + roomconfig.type = 3; + else + roomconfig.type = 1; + roomconfig.IsOwned = !$rooms.Get(rno).IsFirstAuth(); + }else{ + roomconfig.type = 0; + } + roomconfig.admin = socket.handshake.admin; + socket.json.emit("send roominfo",roomconfig); + + var romcount = $rooms.Get(rno).GetRomCount(); + socket.json.emit("send romcount",romcount); + socket.json.broadcast.emit("send romcount",romcount); + socket.on("get pastLogList", function (msg) { ParseGetPastLogList(socket,msg); }); @@ -242,7 +268,7 @@ for(var i = 0; i < $max_room_number; i++) function createLogDirectory() { - path.exists($log_directory,function(exists){ + fs.exists($log_directory,function(exists){ if(exists == false) fs.mkdirSync($log_directory); }); @@ -251,15 +277,21 @@ function createLogDirectory() function ParseAuthorization(handshakeData, callback) { if(handshakeData.headers.cookie) { - var cookie = handshakeData.headers.cookie; - var sessionID = parseCookie(cookie)["connect.sid"]; + var signedCookie = cookie.parse(handshakeData.headers.cookie); + var sessionID = connectUtils.parseSignedCookies(signedCookie, $secret)["connect.sid"]; sessionStore.get(sessionID, function (err, session) { var result = null; - if (err || ipbanlist[handshakeData.address.address] == "r") + if (ipbanlist.IsBaned(handshakeData.address.address)) result = "failed get from session store"; + else if(err) + result = err; else if(handshakeData.query.token != session.items.token) result = "invaild token"; - sessionStore.destroy(sessionID); + if(typeof(session) != "undefined" && result == null) + { + handshakeData.admin = session.items.admin; + handshakeData.sessionID = sessionID; + } callback(result,result == null && !err); }); } else { @@ -269,6 +301,16 @@ function ParseAuthorization(handshakeData, callback) function ParseDisconnect(socket,msg) { + var ip = GetClientIPAdress(socket); + var rno = GetRoomNumberFromName(socket.namespace.name); + $rooms.Get(rno).RemoveRom(ip); + + var romcount = $rooms.Get(rno).GetRomCount(); + socket.json.emit("send romcount",romcount); + socket.json.broadcast.emit("send romcount",romcount); + + sessionStore.destroy(socket.handshake.sessionID); + console.log("disconnected"); } @@ -279,7 +321,7 @@ function ParseSetPassword(socket,msg) name:$system_name, message:null, }; - if($rooms.SetPassword(rno,msg.owner,msg.password)) + if($rooms.Get(rno).IsVolatile() == false && $rooms.Get(rno).SetPassword(msg.owner,msg.password)) newMeg.message = $password_setted_message; else newMeg.message = $failed_set_password_message; @@ -290,22 +332,29 @@ function ParseJoin(socket,msg) { var ip = GetClientIPAdress(socket); - if(ip in ipbanlist) + if(ipbanlist.IsBlockedToWrite(ip)) { socket.emit("error",$block_message); return; } var rno = GetRoomNumberFromName(socket.namespace.name); - if($rooms.IsContains(rno)) + + $rooms.Get(rno).RemoveRom(ip); + + var romcount = $rooms.Get(rno).GetRomCount(); + socket.json.emit("send romcount",romcount); + socket.json.broadcast.emit("send romcount",romcount); + + if($rooms.Get(rno).IsVolatile() == false) { - if($rooms.IsTimeout(rno) || - $rooms.IsFirstAuth(rno)) + if($rooms.Get(rno).IsTimeout() || + $rooms.Get(rno).IsFirstAuth()) { - $rooms.Reset(rno,msg.name); + $rooms.Get(rno).Reset(msg.name); ParseGetPastLog(socket,util.format($log_file_name,rno)); } - else if($rooms.Auth(rno,msg.name,msg.password)) + else if($rooms.Get(rno).Auth(msg.name,msg.password)) { ParseGetPastLog(socket,util.format($log_file_name,rno)); } @@ -327,7 +376,7 @@ function ParseQuit(socket,msg) { var ip = GetClientIPAdress(socket); - if(ip in ipbanlist) + if(ipbanlist.IsBlockedToWrite(ip)) { socket.emit("error",$block_message); return; @@ -339,18 +388,25 @@ function ParseQuit(socket,msg) name:$system_name, message:$password_resetted_message, }; - if($rooms.IsContains(rno)) + + $rooms.Get(rno).AddRom(ip); + + var romcount = $rooms.Get(rno).GetRomCount(); + socket.json.emit("send romcount",romcount); + socket.json.broadcast.emit("send romcount",romcount); + + if($rooms.Get(rno).IsVolatile() == false) { - if($rooms.IsOwner(rno,msg.name)) + if($rooms.Get(rno).IsOwner(msg.name)) { - $rooms.Reset(rno,null); + $rooms.Get(rno).Reset(null); ParseSendMsg(socket,newMeg); } - if(!$rooms.IsFirstAuth(rno) && - !$rooms.IsAuthed(rno,msg.name)) + if(!$rooms.Get(rno).IsFirstAuth() && + !$rooms.Get(rno).IsAuthed(msg.name)) return; else - $rooms.RemoveAuth(rno,msg.name); + $rooms.Get(rno).RemoveAuth(msg.name); } newMeg.message = util.format("/quitedby %s",msg.name); @@ -372,9 +428,9 @@ function ParseSendMsg(socket,msg) var rno = GetRoomNumberFromName(socket.namespace.name); if(msg.name != $system_name && - $rooms.IsContains(rno) && - !$rooms.IsAuthed(rno,msg.name) && - !$rooms.IsOwner(rno,msg.name)) + $rooms.Get(rno).IsVolatile() == false && + !$rooms.Get(rno).IsAuthed(msg.name) && + !$rooms.Get(rno).IsOwner(rno,msg.name)) { return; } @@ -383,6 +439,9 @@ function ParseSendMsg(socket,msg) var repacked_msg = CreateMessage(msg.name,date,msg.message); + if(socket.handshake.admin) + repacked_msg.ip = ip; + socket.json.emit("req msg", repacked_msg); socket.json.broadcast.emit("req msg", repacked_msg); @@ -426,14 +485,14 @@ function ParseGetPastLog(socket,file) return; var path = $log_directory + "/" + file; var log = new ChatLog(path); - log.ToArray(function(array){ + log.ToArray(socket.handshake.admin,function(array){ socket.json.emit("req pastlog",array); }); } function ChatLog(path) { - this.ToArray = function(callback) + this.ToArray = function(hasIp,callback) { var state = fs.stat(path,function(err,state){ if(err) @@ -441,9 +500,12 @@ function ChatLog(path) var array = new Array(); var stream = fs.createReadStream(path); new lazy(stream) - .lines + .spilt(";") .forEach(function(line){ - array.push(CreateMessageFromText(line.toString())); + var msg = CreateMessageFromText(line.toString()); + if(hasIp == false) + msg.ip = ""; + array.push(msg); }) .join(function(){ callback(array); @@ -465,7 +527,7 @@ function ChatLog(path) msg.date + "<>" + ip + "<>" + msg.message + - "\n"; + ";"; return text; } @@ -521,6 +583,7 @@ function CreateMessage(name,date,message) { var result = {name:name, date:date, + ip:"", message:message}; return result; } @@ -528,6 +591,7 @@ function CreateMessageFromText(text) { var data = text.split("<>"); var msg = {name:data[0], + ip:data[2], date:data[1], message:data[3]}; return msg; @@ -537,95 +601,23 @@ function CreateMessageFromText(text) function RoomInfomationCollection() { var collection = {}; - this.Clear = function(){ - collection = {}; - }; - this.Add = function(rno,pass){ - collection[rno] = {time : null, - password : pass, - owner : null, - authed_list : {}}; - if(pass != null) - collection[rno].owner = $system_name; - }; - this.Reset = function(rno,owner){ - var date = new Date(); - var time = date.getTime(); - collection[rno].password = null; - collection[rno].authed_list = {}; - collection[rno].owner = owner; - collection[rno].time = time; - console.log(util.format("password is reseted in %s",rno)); - }; + this.Get = function(rno){ + return collection[rno]; + } this.IsContains = function(rno){ return rno in collection; }; - this.IsFirstAuth = function(rno){ - if(!this.IsContains(rno) || typeof(collection[rno].owner) == "undefined") - return false; - return collection[rno].owner == null; - } - this.IsAuthed = function(rno,name){ - if(!this.IsContains(rno)) - return false; - console.log(util.inspect(collection[rno].authed_list)); - return name == collection[rno].owner || - name in collection[rno].authed_list; - }; - this.IsFixedPassword = function(rno){ - if(!this.IsContains(rno)) - return false; - return collection[rno].owner == $system_name; - }; - this.IsOwner = function(rno,name){ - return this.IsContains(rno) && - typeof(collection[rno].owner) != "undefined" && - collection[rno].owner == name; - } - this.IsTimeout = function(rno){ - var date = new Date(); - var time = date.getTime(); - return this.IsContains(rno) && - !this.IsFixedPassword(rno) && - (typeof(collection[rno].time) != "undefined" && - time - collection[rno].time >= $reset_password_diff); - }; - this.RemoveAuth = function(rno,name) - { - delete collection[rno].authed_list[name]; - } - this.Auth = function(rno,name,password){ - if(typeof(collection[rno].password) != "undefined" && - collection[rno].password != password) - return false; - var date = new Date(); - var time = date.getTime(); - collection[rno].time = time; - collection[rno].authed_list[name] = ""; - return true; - } - this.SetPassword = function(rno,owner,password){ - if(this.IsContains(rno) && - owner == collection[rno].owner && - !this.IsFixedPassword(rno)) - { - var date = new Date(); - collection[rno].time = date.getTime(); - collection[rno].password = password; - - console.log(util.format("password is seted to %s in %s",password,rno)); - return true; - } - return false; - }; this.GetString = function(){ var retval = ""; for(var rno in collection) { + if($rooms.Get(rno).IsVolatile()) + continue; var pass = collection[rno].password; if(pass == null) pass = ""; - retval += rno + ":" + pass + "\r\n"; + var hiddenlog = collection[rno].hiddenlog; + retval += rno + ":" + pass + ":" + hiddenlog + "\r\n"; } return retval; }; @@ -637,94 +629,245 @@ function RoomInfomationCollection() } return retval; } - - for(var i=0; i= $reset_password_diff; + }; + this.RemoveAuth = function(name) { - var token = lines[i].split(":"); - console.log(util.inspect(token)); - if(token.length == 1) + delete this.authed_list[name]; + }; + this.Auth = function(name,password){ + if(this.password != password) + return false; + var date = new Date(); + var time = date.getTime(); + this.time = time; + this.authed_list[name] = ""; + return true; + }; + this.SetPassword = function(owner,password){ + if(owner == this.owner && + !this.IsFixedPassword() && + !this.IsHiddenLogFromRom()) { - $rooms.Add(token[0],null); + var date = new Date(); + this.time = date.getTime(); + this.password = password; + return true; } - else if(token.length == 2) + return false; + }; + this.GCRomList = function(){ + var date = new Date(); + var current_time = date.getTime(); + for(var ip in this.rom_list) { - var rno = token[0]; - var pass = token[1]; - if(pass == "") - pass = null; - $rooms.Add(rno, pass); + if(current_time - this.rom_list[ip].time >= $gc_time_interval) + delete this.rom_list[ip]; } - } + }; } -//IPBAN -function getTextFromIpBanlist(list) +//IPBANクラス +function IpBanCollecion() { - var text = ""; - for(var key in ipbanlist) - { - if(ipbanlist[key] == "") - text += key + "\r\n"; - else - text += key + ":" + ipbanlist[key] + "\r\n"; + var collection = {}; + this.IsBaned = function(ip){ + return collection[ip] == "r"; } - return text; -} - -function updateIpBanList(text,callfunc) -{ - async.waterfall([ - function(callback){ - fs.open($ip_ban_list_file_name,"w",callback); - }, - function(fd,callback){ - var buf = new Buffer(text); - fs.write(fd,buf,0,Buffer.byteLength(text),null,function(){ - callback(null,fd); - }); - }, - function(fd,callback){ - fs.close(fd,function(){ - getIpBanList(callfunc); - }); - } - ]); -} - -function getIpBanList(callback) -{ - ipbanlist = {}; - path.exists($ip_ban_list_file_name,function(exists){ - if(exists == false) + this.IsBlockedToWrite = function(ip){ + return ip in collection; + } + this.GetText = function(){ + var text = ""; + for(var key in collection) { - if(typeof(callback) == "function") - callback(); - return; + if(collection[key] == "") + text += key + "\r\n"; + else + text += key + ":" + collection[key] + "\r\n"; } - var stream = fs.createReadStream($ip_ban_list_file_name); - new lazy(stream) - .lines - .forEach(function(line){ - var token = line.toString().split(":"); - var ip = token[0].replace(/(\r|\n|\r\n)/gm, ""); - if(token.length == 1) - ipbanlist[ip] = ""; - else - ipbanlist[ip] = token[1]; - }) - .join(function(){ + return text; + } + this.Update = function(text,callfunc){ + async.waterfall([ + function(callback){ + fs.open($ip_ban_list_file_name,"w",callback); + }, + function(fd,callback){ + var buf = new Buffer(text); + fs.write(fd,buf,0,Buffer.byteLength(text),null,function(){ + callback(null,fd); + }); + }, + function(fd,callback){ + fs.close(fd,function(){ + GetIpBanList(callfunc); + }); + } + ]); + } + function GetIpBanList(callback) + { + collection = {}; + fs.exists($ip_ban_list_file_name,function(exists){ + if(exists == false) + { if(typeof(callback) == "function") callback(); - }); - }); + return; + } + var stream = fs.createReadStream($ip_ban_list_file_name); + new lazy(stream) + .lines + .forEach(function(line){ + var token = line.toString().replace(/(\r|\n|\r\n)/gm, "").split(":"); + var ip = token[0]; + if(token.length == 1) + collection[ip] = ""; + else + collection[ip] = token[1]; + }) + .join(function(){ + if(typeof(callback) == "function") + callback(); + }); + }); + } + GetIpBanList(); } +