2013-03-24 02:28:20 +00:00
|
|
|
/*
|
|
|
|
The MIT License (MIT)
|
|
|
|
Copyright (c) 2013 Calvin Montgomery
|
2013-04-19 19:50:08 +00:00
|
|
|
|
2013-03-24 02:28:20 +00:00
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
2013-04-19 19:50:08 +00:00
|
|
|
|
2013-03-24 02:28:20 +00:00
|
|
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
2013-04-19 19:50:08 +00:00
|
|
|
|
2013-03-24 02:28:20 +00:00
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
2013-02-16 17:19:59 +00:00
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
var Rank = require("./rank.js");
|
|
|
|
var Auth = require("./auth.js");
|
|
|
|
var Channel = require("./channel.js").Channel;
|
2013-06-02 17:54:58 +00:00
|
|
|
var formatTime = require("./media.js").formatTime;
|
2013-03-24 17:23:48 +00:00
|
|
|
var Server = require("./server.js");
|
|
|
|
var Database = require("./database.js");
|
2013-03-27 19:28:51 +00:00
|
|
|
var Logger = require("./logger.js");
|
2013-05-03 03:13:46 +00:00
|
|
|
var Config = require("./config.js");
|
2013-06-20 23:45:21 +00:00
|
|
|
var ACP = require("./acp");
|
2013-06-22 01:28:21 +00:00
|
|
|
var ActionLog = require("./actionlog");
|
2013-02-16 05:02:42 +00:00
|
|
|
|
|
|
|
// Represents a client connected via socket.io
|
|
|
|
var User = function(socket, ip) {
|
|
|
|
this.ip = ip;
|
|
|
|
this.socket = socket;
|
|
|
|
this.loggedIn = false;
|
2013-05-22 19:38:16 +00:00
|
|
|
this.rank = Rank.Anonymous;
|
2013-06-20 23:45:21 +00:00
|
|
|
this.global_rank = Rank.Anonymous;
|
2013-02-16 05:02:42 +00:00
|
|
|
this.channel = null;
|
|
|
|
this.name = "";
|
2013-04-19 19:50:08 +00:00
|
|
|
this.meta = {
|
2013-06-25 14:18:33 +00:00
|
|
|
afk: false,
|
|
|
|
icon: false
|
2013-04-19 19:50:08 +00:00
|
|
|
};
|
2013-06-25 14:18:33 +00:00
|
|
|
this.muted = false;
|
2013-04-23 19:17:42 +00:00
|
|
|
this.throttle = {};
|
|
|
|
this.flooded = {};
|
2013-05-13 00:41:02 +00:00
|
|
|
this.profile = {
|
|
|
|
image: "",
|
|
|
|
text: ""
|
|
|
|
};
|
2013-02-16 05:02:42 +00:00
|
|
|
|
|
|
|
this.initCallbacks();
|
2013-03-20 18:35:06 +00:00
|
|
|
if(Server.announcement != null) {
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.emit("announcement", Server.announcement);
|
2013-03-20 18:35:06 +00:00
|
|
|
}
|
2013-02-16 05:02:42 +00:00
|
|
|
};
|
|
|
|
|
2013-04-23 19:17:42 +00:00
|
|
|
// Throttling/cooldown
|
|
|
|
User.prototype.noflood = function(name, hz) {
|
|
|
|
var time = new Date().getTime();
|
|
|
|
if(!(name in this.throttle)) {
|
|
|
|
this.throttle[name] = [time];
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else if(name in this.flooded && time < this.flooded[name]) {
|
|
|
|
this.socket.emit("noflood", {
|
|
|
|
action: name,
|
|
|
|
msg: "You're still on cooldown!"
|
|
|
|
});
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.throttle[name].push(time);
|
|
|
|
var diff = (time - this.throttle[name][0]) / 1000.0;
|
2013-04-30 15:30:59 +00:00
|
|
|
// Twice might be an accident, more than that is probably spam
|
|
|
|
if(this.throttle[name].length > 2) {
|
2013-04-23 19:17:42 +00:00
|
|
|
var rate = this.throttle[name].length / diff;
|
|
|
|
this.throttle[name] = [time];
|
|
|
|
if(rate > hz) {
|
|
|
|
this.flooded[name] = time + 5000;
|
|
|
|
this.socket.emit("noflood", {
|
|
|
|
action: name,
|
|
|
|
msg: "Stop doing that so fast! Cooldown: 5s"
|
|
|
|
});
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-20 23:10:23 +00:00
|
|
|
|
2013-02-16 05:02:42 +00:00
|
|
|
User.prototype.initCallbacks = function() {
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("disconnect", function() {
|
2013-02-16 05:02:42 +00:00
|
|
|
if(this.channel != null)
|
|
|
|
this.channel.userLeave(this);
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("joinChannel", function(data) {
|
2013-06-02 22:09:52 +00:00
|
|
|
if(this.channel != null)
|
|
|
|
return;
|
|
|
|
if(typeof data.name != "string")
|
2013-03-28 23:51:08 +00:00
|
|
|
return;
|
2013-05-11 19:21:14 +00:00
|
|
|
if(!data.name.match(/^[a-zA-Z0-9-_]+$/))
|
2013-03-20 23:10:23 +00:00
|
|
|
return;
|
2013-03-28 23:51:08 +00:00
|
|
|
if(data.name.length > 100)
|
|
|
|
return;
|
2013-04-05 19:03:35 +00:00
|
|
|
data.name = data.name.toLowerCase();
|
2013-02-16 05:02:42 +00:00
|
|
|
// Channel already loaded
|
2013-06-15 20:07:38 +00:00
|
|
|
if(data.name in Server.channels && Server.channels[data.name] != null) {
|
2013-02-16 05:02:42 +00:00
|
|
|
this.channel = Server.channels[data.name];
|
|
|
|
}
|
|
|
|
// Channel not loaded
|
|
|
|
else {
|
|
|
|
Server.channels[data.name] = new Channel(data.name);
|
|
|
|
this.channel = Server.channels[data.name];
|
|
|
|
}
|
2013-05-17 15:02:45 +00:00
|
|
|
if(this.loggedIn) {
|
|
|
|
var chanrank = this.channel.getRank(this.name);
|
|
|
|
if(chanrank > this.rank) {
|
|
|
|
this.rank = chanrank;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.channel.userJoin(this);
|
2013-02-16 05:02:42 +00:00
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("login", function(data) {
|
2013-04-26 03:50:12 +00:00
|
|
|
var name = data.name || "";
|
|
|
|
var pw = data.pw || "";
|
|
|
|
var session = data.session || "";
|
|
|
|
if(pw.length > 100)
|
|
|
|
pw = pw.substring(0, 100);
|
2013-03-05 20:12:55 +00:00
|
|
|
if(this.name == "")
|
2013-04-26 03:50:12 +00:00
|
|
|
this.login(name, pw, session);
|
2013-02-16 05:02:42 +00:00
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("register", function(data) {
|
2013-03-28 23:51:08 +00:00
|
|
|
if(data.name == undefined || data.pw == undefined)
|
|
|
|
return;
|
|
|
|
if(data.pw.length > 100)
|
|
|
|
data.pw = data.pw.substring(0, 100);
|
2013-03-26 19:12:02 +00:00
|
|
|
this.register(data.name, data.pw);
|
2013-02-16 05:02:42 +00:00
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("assignLeader", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryChangeLeader(this, data);
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("promote", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
2013-04-04 20:41:41 +00:00
|
|
|
this.channel.tryPromoteUser(this, data);
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("demote", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
2013-04-04 20:41:41 +00:00
|
|
|
this.channel.tryDemoteUser(this, data);
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-06-05 15:40:59 +00:00
|
|
|
this.socket.on("setChannelRank", function(data) {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.trySetRank(this, data);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-05-21 16:17:01 +00:00
|
|
|
this.socket.on("banName", function(data) {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.banName(this, data.name || "");
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
|
|
|
this.socket.on("banIP", function(data) {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryIPBan(this, data);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
|
|
|
this.socket.on("unban", function(data) {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryUnban(this, data);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("chatMsg", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryChat(this, data);
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-04-18 16:42:07 +00:00
|
|
|
this.socket.on("newPoll", function(data) {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryOpenPoll(this, data);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("playerReady", function() {
|
2013-02-16 05:02:42 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.sendMediaUpdate(this);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-04-17 19:05:45 +00:00
|
|
|
this.socket.on("requestPlaylist", function() {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.sendPlaylist(this);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("queue", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryQueue(this, data);
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-05-04 22:54:28 +00:00
|
|
|
this.socket.on("setTemp", function(data) {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.trySetTemp(this, data);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-06-11 15:29:21 +00:00
|
|
|
this.socket.on("delete", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryDequeue(this, data);
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-04-27 16:48:36 +00:00
|
|
|
this.socket.on("uncache", function(data) {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryUncache(this, data);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("moveMedia", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryMove(this, data);
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-28 23:51:08 +00:00
|
|
|
this.socket.on("jumpTo", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryJumpTo(this, data);
|
2013-03-28 23:51:08 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("playNext", function() {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
2013-04-03 17:47:41 +00:00
|
|
|
this.channel.tryPlayNext(this);
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-06-11 19:41:03 +00:00
|
|
|
this.socket.on("clearPlaylist", function() {
|
2013-04-22 20:37:42 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryClearqueue(this);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-06-11 19:41:03 +00:00
|
|
|
this.socket.on("shufflePlaylist", function() {
|
2013-04-22 20:37:42 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryShufflequeue(this);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-06-11 15:29:21 +00:00
|
|
|
this.socket.on("togglePlaylistLock", function() {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
2013-06-11 15:29:21 +00:00
|
|
|
this.channel.tryToggleLock(this);
|
2013-03-16 20:39:58 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("mediaUpdate", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryUpdate(this, data);
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-06-11 15:29:21 +00:00
|
|
|
this.socket.on("searchMedia", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
2013-06-11 19:41:03 +00:00
|
|
|
if(data.source == "yt") {
|
2013-04-04 16:39:43 +00:00
|
|
|
var callback = function(vids) {
|
2013-06-11 15:29:21 +00:00
|
|
|
this.socket.emit("searchResults", {
|
2013-04-04 16:39:43 +00:00
|
|
|
results: vids
|
|
|
|
});
|
|
|
|
}.bind(this);
|
|
|
|
this.channel.search(data.query, callback);
|
|
|
|
}
|
|
|
|
else {
|
2013-06-11 15:29:21 +00:00
|
|
|
this.socket.emit("searchResults", {
|
2013-04-04 16:39:43 +00:00
|
|
|
results: this.channel.search(data.query)
|
|
|
|
});
|
|
|
|
}
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("closePoll", function() {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryClosePoll(this);
|
2013-03-16 21:49:58 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("vote", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryVote(this, data);
|
2013-03-16 21:49:58 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("registerChannel", function(data) {
|
2013-03-17 17:14:34 +00:00
|
|
|
if(this.channel == null) {
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.emit("channelRegistration", {
|
2013-03-17 17:14:34 +00:00
|
|
|
success: false,
|
|
|
|
error: "You're not in any channel!"
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.channel.tryRegister(this);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-05-13 19:41:29 +00:00
|
|
|
this.socket.on("unregisterChannel", function() {
|
|
|
|
if(this.channel == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(!this.channel.registered) {
|
|
|
|
this.socket.emit("unregisterChannel", {
|
|
|
|
success: false,
|
|
|
|
error: "This channel is already unregistered"
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else if(this.rank < 10) {
|
|
|
|
this.socket.emit("unregisterChannel", {
|
|
|
|
success: false,
|
|
|
|
error: "You don't have permission to unregister"
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else if(this.channel.unregister()) {
|
|
|
|
this.socket.emit("unregisterChannel", {
|
|
|
|
success: true
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.socket.emit("unregisterChannel", {
|
|
|
|
success: false,
|
|
|
|
error: "Unregistration failed. Please see a site admin if this continues."
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.on("announce", function(data) {
|
2013-03-20 18:35:06 +00:00
|
|
|
if(Rank.hasPermission(this, "announce")) {
|
|
|
|
if(data.clear) {
|
|
|
|
Server.announcement = null;
|
|
|
|
}
|
|
|
|
else {
|
2013-03-24 17:23:48 +00:00
|
|
|
Server.io.sockets.emit("announcement", data);
|
2013-03-20 18:35:06 +00:00
|
|
|
Server.announcement = data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}.bind(this));
|
2013-03-22 20:04:04 +00:00
|
|
|
|
2013-06-17 22:16:59 +00:00
|
|
|
this.socket.on("setOptions", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryUpdateOptions(this, data);
|
2013-03-22 20:04:04 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
2013-03-31 19:27:54 +00:00
|
|
|
|
2013-05-22 19:38:16 +00:00
|
|
|
this.socket.on("setPermissions", function(data) {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryUpdatePermissions(this, data);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-05-15 15:34:27 +00:00
|
|
|
this.socket.on("setChannelCSS", function(data) {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.trySetCSS(this, data);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
|
|
|
this.socket.on("setChannelJS", function(data) {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.trySetJS(this, data);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-06-18 15:51:42 +00:00
|
|
|
this.socket.on("updateFilter", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
2013-06-18 15:51:42 +00:00
|
|
|
this.channel.tryUpdateFilter(this, data);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
|
|
|
this.socket.on("removeFilter", function(data) {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryRemoveFilter(this, data);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
|
|
|
this.socket.on("moveFilter", function(data) {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryMoveFilter(this, data);
|
2013-03-31 19:27:54 +00:00
|
|
|
}
|
2013-04-01 21:02:09 +00:00
|
|
|
}.bind(this));
|
|
|
|
|
2013-06-11 19:41:03 +00:00
|
|
|
this.socket.on("setMotd", function(data) {
|
2013-04-03 17:10:05 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryUpdateMotd(this, data);
|
2013-03-31 19:27:54 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
2013-04-19 19:50:08 +00:00
|
|
|
|
2013-06-18 03:57:29 +00:00
|
|
|
this.socket.on("requestLoginHistory", function() {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.sendLoginHistory(this);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-06-18 04:26:44 +00:00
|
|
|
this.socket.on("requestBanlist", function() {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.sendBanlist(this);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-06-18 14:57:53 +00:00
|
|
|
this.socket.on("requestChatFilters", function() {
|
2013-04-23 18:47:09 +00:00
|
|
|
if(this.channel != null) {
|
2013-06-18 14:57:53 +00:00
|
|
|
this.channel.sendChatFilters(this);
|
2013-04-23 18:47:09 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-06-18 14:57:53 +00:00
|
|
|
this.socket.on("requestChannelRanks", function() {
|
2013-04-29 23:59:51 +00:00
|
|
|
if(this.channel != null) {
|
2013-06-18 14:57:53 +00:00
|
|
|
if(this.noflood("requestChannelRanks", 0.25))
|
2013-05-26 16:43:11 +00:00
|
|
|
return;
|
2013-06-18 14:57:53 +00:00
|
|
|
this.channel.sendChannelRanks(this);
|
2013-04-29 23:59:51 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
|
|
|
|
2013-04-02 19:07:22 +00:00
|
|
|
this.socket.on("voteskip", function(data) {
|
|
|
|
if(this.channel != null) {
|
2013-04-03 17:47:41 +00:00
|
|
|
this.channel.tryVoteskip(this);
|
2013-04-02 19:07:22 +00:00
|
|
|
}
|
|
|
|
}.bind(this));
|
2013-05-13 00:41:02 +00:00
|
|
|
|
|
|
|
this.socket.on("setProfile", function(data) {
|
|
|
|
if(!this.name) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
data.image = data.image || "";
|
|
|
|
data.text = data.text || "";
|
|
|
|
if(data.text.length > 4000) {
|
|
|
|
data.text = data.text.substring(0, 4000);
|
|
|
|
}
|
|
|
|
if(Database.setProfile(this.name, data)) {
|
|
|
|
this.profile = data;
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.broadcastUserUpdate(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}.bind(this));
|
2013-06-01 15:59:04 +00:00
|
|
|
|
|
|
|
this.socket.on("listPlaylists", function(data) {
|
|
|
|
if(this.name == "" || this.rank < 1) {
|
2013-06-01 19:42:08 +00:00
|
|
|
this.socket.emit("listPlaylists", {
|
2013-06-01 15:59:04 +00:00
|
|
|
pllist: [],
|
|
|
|
error: "You must be logged in to manage playlists"
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var list = Database.getUserPlaylists(this.name);
|
2013-06-02 17:54:58 +00:00
|
|
|
for(var i = 0; i < list.length; i++) {
|
|
|
|
list[i].time = formatTime(list[i].time);
|
|
|
|
}
|
2013-06-01 19:42:08 +00:00
|
|
|
this.socket.emit("listPlaylists", {
|
2013-06-01 15:59:04 +00:00
|
|
|
pllist: list,
|
|
|
|
});
|
|
|
|
}.bind(this));
|
|
|
|
|
|
|
|
this.socket.on("savePlaylist", function(data) {
|
|
|
|
if(this.rank < 1) {
|
|
|
|
socket.emit("savePlaylist", {
|
|
|
|
success: false,
|
|
|
|
error: "You must be logged in to manage playlists"
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(this.channel == null) {
|
|
|
|
socket.emit("savePlaylist", {
|
|
|
|
success: false,
|
|
|
|
error: "Not in a channel"
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(typeof data.name != "string") {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-03 03:19:17 +00:00
|
|
|
var pl = this.channel.playlist.items.toArray();
|
2013-06-01 15:59:04 +00:00
|
|
|
var result = Database.saveUserPlaylist(pl, this.name, data.name);
|
|
|
|
this.socket.emit("savePlaylist", {
|
|
|
|
success: result,
|
|
|
|
error: result ? false : "Unknown"
|
|
|
|
});
|
2013-06-01 20:56:23 +00:00
|
|
|
var list = Database.getUserPlaylists(this.name);
|
2013-06-02 17:54:58 +00:00
|
|
|
for(var i = 0; i < list.length; i++) {
|
|
|
|
list[i].time = formatTime(list[i].time);
|
|
|
|
}
|
2013-06-01 20:56:23 +00:00
|
|
|
this.socket.emit("listPlaylists", {
|
|
|
|
pllist: list,
|
|
|
|
});
|
2013-06-01 15:59:04 +00:00
|
|
|
}.bind(this));
|
2013-06-01 19:42:08 +00:00
|
|
|
|
|
|
|
this.socket.on("queuePlaylist", function(data) {
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.tryQueuePlaylist(this, data);
|
|
|
|
}
|
|
|
|
}.bind(this));
|
2013-06-01 20:56:23 +00:00
|
|
|
|
|
|
|
this.socket.on("deletePlaylist", function(data) {
|
|
|
|
if(typeof data.name != "string") {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Database.deleteUserPlaylist(this.name, data.name);
|
|
|
|
var list = Database.getUserPlaylists(this.name);
|
2013-06-02 17:54:58 +00:00
|
|
|
for(var i = 0; i < list.length; i++) {
|
|
|
|
list[i].time = formatTime(list[i].time);
|
|
|
|
}
|
2013-06-01 20:56:23 +00:00
|
|
|
this.socket.emit("listPlaylists", {
|
|
|
|
pllist: list,
|
|
|
|
});
|
|
|
|
}.bind(this));
|
2013-06-20 23:45:21 +00:00
|
|
|
|
|
|
|
this.socket.on("acp-init", function() {
|
|
|
|
if(this.global_rank >= Rank.Siteadmin)
|
|
|
|
ACP.init(this);
|
|
|
|
}.bind(this));
|
2013-06-23 14:25:49 +00:00
|
|
|
|
|
|
|
this.socket.on("borrow-rank", function(rank) {
|
|
|
|
if(this.global_rank < 255)
|
|
|
|
return;
|
|
|
|
if(rank > this.global_rank)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.rank = rank;
|
|
|
|
this.socket.emit("rank", rank);
|
|
|
|
if(this.channel != null)
|
|
|
|
this.channel.broadcastUserUpdate(this);
|
|
|
|
|
|
|
|
}.bind(this));
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
|
|
|
|
2013-05-03 03:13:46 +00:00
|
|
|
var lastguestlogin = {};
|
2013-02-16 05:02:42 +00:00
|
|
|
// Attempt to login
|
2013-04-26 03:50:12 +00:00
|
|
|
User.prototype.login = function(name, pw, session) {
|
2013-02-16 05:02:42 +00:00
|
|
|
// No password => try guest login
|
2013-04-26 03:50:12 +00:00
|
|
|
if(pw == "" && session == "") {
|
2013-05-03 03:13:46 +00:00
|
|
|
if(this.ip in lastguestlogin) {
|
|
|
|
var diff = (Date.now() - lastguestlogin[this.ip])/1000;
|
|
|
|
if(diff < Config.GUEST_LOGIN_DELAY) {
|
|
|
|
this.socket.emit("login", {
|
|
|
|
success: false,
|
|
|
|
error: ["Guest logins are restricted to one per ",
|
|
|
|
Config.GUEST_LOGIN_DELAY + " seconds per IP. ",
|
|
|
|
"This restriction does not apply to registered users."
|
|
|
|
].join("")
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2013-06-19 21:54:27 +00:00
|
|
|
try {
|
|
|
|
// Sorry bud, can't take that name
|
|
|
|
if(Auth.isRegistered(name)) {
|
|
|
|
this.socket.emit("login", {
|
|
|
|
success: false,
|
|
|
|
error: "That username is already taken"
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// YOUR ARGUMENT IS INVALID
|
|
|
|
else if(!Auth.validateName(name)) {
|
|
|
|
this.socket.emit("login", {
|
|
|
|
success: false,
|
|
|
|
error: "Invalid username. Usernames must be 1-20 characters long and consist only of alphanumeric characters and underscores"
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
2013-07-03 03:24:03 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
for(var i = 0; i < this.channel.users.length; i++) {
|
|
|
|
if(this.channel.users[i].name == name) {
|
|
|
|
this.socket.emit("login", {
|
|
|
|
success: false,
|
|
|
|
error: "That name is already taken on this channel"
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-06-19 21:54:27 +00:00
|
|
|
lastguestlogin[this.ip] = Date.now();
|
|
|
|
this.rank = Rank.Guest;
|
|
|
|
Logger.syslog.log(this.ip + " signed in as " + name);
|
|
|
|
Database.recordVisit(this.ip, name);
|
|
|
|
this.name = name;
|
|
|
|
this.loggedIn = false;
|
|
|
|
this.socket.emit("login", {
|
|
|
|
success: true,
|
|
|
|
name: name
|
|
|
|
});
|
|
|
|
this.socket.emit("rank", this.rank);
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.logger.log(this.ip + " signed in as " + name);
|
|
|
|
this.channel.broadcastNewUser(this);
|
|
|
|
}
|
|
|
|
}
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
2013-06-19 21:54:27 +00:00
|
|
|
catch(e) {
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.emit("login", {
|
2013-02-16 05:02:42 +00:00
|
|
|
success: false,
|
2013-06-19 21:54:27 +00:00
|
|
|
error: e
|
2013-02-16 05:02:42 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2013-06-19 21:54:27 +00:00
|
|
|
try {
|
|
|
|
var row;
|
|
|
|
if((row = Auth.login(name, pw, session))) {
|
2013-06-22 01:28:21 +00:00
|
|
|
if(this.channel != null) {
|
|
|
|
for(var i = 0; i < this.channel.users.length; i++) {
|
|
|
|
if(this.channel.users[i].name == name) {
|
|
|
|
this.channel.kick(this.channel.users[i], "Duplicate login");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ActionLog.record(this.ip, name, "login-success");
|
2013-06-19 21:54:27 +00:00
|
|
|
this.loggedIn = true;
|
|
|
|
this.socket.emit("login", {
|
|
|
|
success: true,
|
|
|
|
session: row.session_hash,
|
|
|
|
name: name
|
|
|
|
});
|
|
|
|
Logger.syslog.log(this.ip + " logged in as " + name);
|
|
|
|
Database.recordVisit(this.ip, name);
|
|
|
|
this.profile = {
|
|
|
|
image: row.profile_image,
|
|
|
|
text: row.profile_text
|
|
|
|
};
|
|
|
|
var chanrank = (this.channel != null) ? this.channel.getRank(name)
|
|
|
|
: Rank.Guest;
|
|
|
|
var rank = (chanrank > row.global_rank) ? chanrank
|
|
|
|
: row.global_rank;
|
|
|
|
this.rank = (this.rank > rank) ? this.rank : rank;
|
2013-06-20 23:45:21 +00:00
|
|
|
this.global_rank = row.global_rank;
|
2013-06-19 21:54:27 +00:00
|
|
|
this.socket.emit("rank", this.rank);
|
|
|
|
this.name = name;
|
|
|
|
if(this.channel != null) {
|
|
|
|
this.channel.logger.log(this.ip + " logged in as " + name);
|
|
|
|
this.channel.broadcastNewUser(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Wrong password
|
|
|
|
else {
|
2013-06-22 01:28:21 +00:00
|
|
|
ActionLog.record(this.ip, this.name, "login-failure");
|
2013-06-19 21:54:27 +00:00
|
|
|
this.socket.emit("login", {
|
|
|
|
success: false,
|
|
|
|
error: "Invalid session"
|
|
|
|
});
|
|
|
|
return false;
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
|
|
|
}
|
2013-06-19 21:54:27 +00:00
|
|
|
catch(e) {
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.emit("login", {
|
2013-02-16 05:02:42 +00:00
|
|
|
success: false,
|
2013-06-19 21:54:27 +00:00
|
|
|
error: e
|
2013-02-16 05:02:42 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to register a user account
|
2013-03-26 19:12:02 +00:00
|
|
|
User.prototype.register = function(name, pw) {
|
|
|
|
if(pw == "") {
|
2013-02-16 05:02:42 +00:00
|
|
|
// Sorry bud, password required
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.emit("register", {
|
2013-02-16 05:02:42 +00:00
|
|
|
success: false,
|
|
|
|
error: "You must provide a password"
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else if(Auth.isRegistered(name)) {
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.emit("register", {
|
2013-02-16 05:02:42 +00:00
|
|
|
success: false,
|
|
|
|
error: "That username is already taken"
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else if(!Auth.validateName(name)) {
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.emit("register", {
|
2013-02-16 05:02:42 +00:00
|
|
|
success: false,
|
|
|
|
error: "Invalid username. Usernames must be 1-20 characters long and consist only of alphanumeric characters and underscores"
|
|
|
|
});
|
|
|
|
}
|
2013-03-26 19:12:02 +00:00
|
|
|
else if(Auth.register(name, pw)) {
|
2013-02-16 05:02:42 +00:00
|
|
|
console.log(this.ip + " registered " + name);
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.emit("register", {
|
2013-02-16 05:02:42 +00:00
|
|
|
success: true
|
|
|
|
});
|
2013-03-26 19:12:02 +00:00
|
|
|
this.login(name, pw);
|
2013-02-16 05:02:42 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-03-24 17:23:48 +00:00
|
|
|
this.socket.emit("register", {
|
2013-02-16 05:02:42 +00:00
|
|
|
success: false,
|
|
|
|
error: "[](/ppshrug) Registration Failed."
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
exports.User = User;
|