mirror of https://github.com/calzoneman/sync.git
Implement ACL for channel owners (Issue #42)
This commit is contained in:
parent
d7de1fc69e
commit
bb019deeb7
18
auth.js
18
auth.js
|
@ -109,3 +109,21 @@ exports.login = function(name, pw) {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.getGlobalRank = function(name) {
|
||||||
|
var db = mysql.createConnectionSync();
|
||||||
|
db.connectSync(Config.MYSQL_SERVER, Config.MYSQL_USER,
|
||||||
|
Config.MYSQL_PASSWORD, Config.MYSQL_DB);
|
||||||
|
if(!db.connectedSync()) {
|
||||||
|
Logger.errlog.log("Auth.getGlobalRank: DB connection failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var query = "SELECT * FROM registrations WHERE uname='{1}'"
|
||||||
|
.replace(/\{1\}/, name)
|
||||||
|
var results = db.querySync(query);
|
||||||
|
var rows = results.fetchAllSync();
|
||||||
|
if(rows.length > 0) {
|
||||||
|
return rows[0].global_rank;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
51
channel.js
51
channel.js
|
@ -18,6 +18,7 @@ var Logger = require("./logger.js");
|
||||||
var InfoGetter = require("./get-info.js");
|
var InfoGetter = require("./get-info.js");
|
||||||
var io = require("./server.js").io;
|
var io = require("./server.js").io;
|
||||||
var Rank = require("./rank.js");
|
var Rank = require("./rank.js");
|
||||||
|
var Auth = require("./auth.js");
|
||||||
var ChatCommand = require("./chatcommand.js");
|
var ChatCommand = require("./chatcommand.js");
|
||||||
|
|
||||||
var Channel = function(name) {
|
var Channel = function(name) {
|
||||||
|
@ -181,10 +182,12 @@ Channel.prototype.tryRegister = function(user) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.getRank = function(name) {
|
Channel.prototype.getRank = function(name) {
|
||||||
|
var global = Auth.getGlobalRank(name);
|
||||||
if(!this.registered) {
|
if(!this.registered) {
|
||||||
return Rank.Guest;
|
return global;
|
||||||
}
|
}
|
||||||
return Database.lookupChannelRank(this.name, name);
|
var local = Database.lookupChannelRank(this.name, name);
|
||||||
|
return local > global ? local : global;
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.saveRank = function(user) {
|
Channel.prototype.saveRank = function(user) {
|
||||||
|
@ -385,6 +388,9 @@ Channel.prototype.sendRankStuff = function(user) {
|
||||||
}
|
}
|
||||||
user.socket.emit("chatFilters", {filters: filts});
|
user.socket.emit("chatFilters", {filters: filts});
|
||||||
}
|
}
|
||||||
|
if(Rank.hasPermission(user, "acl")) {
|
||||||
|
user.socket.emit("acl", Database.getChannelRanks(this.name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.sendPlaylist = function(user) {
|
Channel.prototype.sendPlaylist = function(user) {
|
||||||
|
@ -445,6 +451,10 @@ Channel.prototype.broadcastNewUser = function(user) {
|
||||||
meta: user.meta
|
meta: user.meta
|
||||||
});
|
});
|
||||||
this.sendRankStuff(user);
|
this.sendRankStuff(user);
|
||||||
|
if(user.rank > Rank.Guest) {
|
||||||
|
this.saveRank(user);
|
||||||
|
this.broadcastRankTable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.broadcastRankUpdate = function(user) {
|
Channel.prototype.broadcastRankUpdate = function(user) {
|
||||||
|
@ -491,6 +501,15 @@ Channel.prototype.broadcastBanlist = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Channel.prototype.broadcastRankTable = function() {
|
||||||
|
var ranks = Database.getChannelRanks(this.name);
|
||||||
|
for(var i = 0; i < this.users.length; i++) {
|
||||||
|
if(Rank.hasPermission(this.users[i], "acl")) {
|
||||||
|
this.users[i].socket.emit("acl", ranks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Channel.prototype.broadcastChatFilters = function() {
|
Channel.prototype.broadcastChatFilters = function() {
|
||||||
var filts = new Array(this.filters.length);
|
var filts = new Array(this.filters.length);
|
||||||
for(var i = 0; i < this.filters.length; i++) {
|
for(var i = 0; i < this.filters.length; i++) {
|
||||||
|
@ -1079,15 +1098,25 @@ Channel.prototype.tryPromoteUser = function(actor, data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var rank = receiver ? receiver.rank : this.getRank(data.name);
|
||||||
|
|
||||||
|
if(actor.rank > rank + 1) {
|
||||||
|
rank++;
|
||||||
if(receiver) {
|
if(receiver) {
|
||||||
if(actor.rank > receiver.rank + 1) {
|
|
||||||
receiver.rank++;
|
receiver.rank++;
|
||||||
if(receiver.loggedIn) {
|
if(receiver.loggedIn) {
|
||||||
this.saveRank(receiver);
|
this.saveRank(receiver);
|
||||||
}
|
}
|
||||||
this.logger.log("*** " + actor.name + " promoted " + receiver.name + " from " + (receiver.rank - 1) + " to " + receiver.rank);
|
|
||||||
this.broadcastRankUpdate(receiver);
|
this.broadcastRankUpdate(receiver);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
Database.saveChannelRank(this.name, {
|
||||||
|
name: data.name,
|
||||||
|
rank: rank
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.logger.log("*** " + actor.name + " promoted " + data.name + " from " + (rank - 1) + " to " + rank);
|
||||||
|
this.broadcastRankTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1109,15 +1138,25 @@ Channel.prototype.tryDemoteUser = function(actor, data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var rank = receiver ? receiver.rank : this.getRank(data.name);
|
||||||
|
|
||||||
|
if(actor.rank > rank) {
|
||||||
|
rank--;
|
||||||
if(receiver) {
|
if(receiver) {
|
||||||
if(actor.rank > receiver.rank) {
|
|
||||||
receiver.rank--;
|
receiver.rank--;
|
||||||
if(receiver.loggedIn) {
|
if(receiver.loggedIn) {
|
||||||
this.saveRank(receiver);
|
this.saveRank(receiver);
|
||||||
}
|
}
|
||||||
this.logger.log("*** " + actor.name + " demoted " + receiver.name + " from " + (receiver.rank + 1) + " to " + receiver.rank);
|
|
||||||
this.broadcastRankUpdate(receiver);
|
this.broadcastRankUpdate(receiver);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
Database.saveChannelRank(this.name, {
|
||||||
|
name: data.name,
|
||||||
|
rank: rank
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.logger.log("*** " + actor.name + " demoted " + data.name + " from " + (rank + 1) + " to " + rank);
|
||||||
|
this.broadcastRankTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
database.js
20
database.js
|
@ -264,3 +264,23 @@ exports.removeChannelBan = function(channame, ip) {
|
||||||
db.closeSync();
|
db.closeSync();
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.getChannelRanks = function(channame) {
|
||||||
|
var db = exports.getConnection();
|
||||||
|
if(!db) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var query = "SELECT * FROM chan_{}_ranks WHERE 1"
|
||||||
|
.replace("{}", channame);
|
||||||
|
|
||||||
|
var results = db.querySync(query);
|
||||||
|
if(results) {
|
||||||
|
var rows = results.fetchAllSync();
|
||||||
|
db.closeSync();
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"author": "Calvin Montgomery",
|
"author": "Calvin Montgomery",
|
||||||
"name": "CyTube",
|
"name": "CyTube",
|
||||||
"description": "Online media synchronizer and chat",
|
"description": "Online media synchronizer and chat",
|
||||||
"version": "1.2.2",
|
"version": "1.2.3",
|
||||||
"repository": {
|
"repository": {
|
||||||
"url": "http://github.com/calzoneman/sync"
|
"url": "http://github.com/calzoneman/sync"
|
||||||
},
|
},
|
||||||
|
|
1
rank.js
1
rank.js
|
@ -19,6 +19,7 @@ var permissions = {
|
||||||
acp : exports.Siteadmin,
|
acp : exports.Siteadmin,
|
||||||
announce : exports.Siteadmin,
|
announce : exports.Siteadmin,
|
||||||
registerChannel : exports.Owner,
|
registerChannel : exports.Owner,
|
||||||
|
acl : exports.Owner,
|
||||||
queue : exports.Moderator,
|
queue : exports.Moderator,
|
||||||
assignLeader : exports.Moderator,
|
assignLeader : exports.Moderator,
|
||||||
kick : exports.Moderator,
|
kick : exports.Moderator,
|
||||||
|
|
|
@ -9,7 +9,7 @@ The above copyright notice and this permission notice shall be included in all c
|
||||||
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.
|
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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const VERSION = "1.2.2";
|
const VERSION = "1.2.3";
|
||||||
|
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var Logger = require("./logger.js");
|
var Logger = require("./logger.js");
|
||||||
|
|
|
@ -101,6 +101,8 @@ function initCallbacks() {
|
||||||
updateBanlist(data.entries);
|
updateBanlist(data.entries);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on("acl", updateACL);
|
||||||
|
|
||||||
socket.on("voteskip", function(data) {
|
socket.on("voteskip", function(data) {
|
||||||
if(data.count > 0) {
|
if(data.count > 0) {
|
||||||
$("#voteskip").text("Voteskip ("+data.count+"/"+data.need+")");
|
$("#voteskip").text("Voteskip ("+data.count+"/"+data.need+")");
|
||||||
|
|
|
@ -382,41 +382,50 @@ $("#updatemotd").click(function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#show_chancontrols").click(function() {
|
$("#show_chancontrols").click(function() {
|
||||||
$("#show_banlist").parent().removeClass("active");
|
$("#modnav li").each(function() {
|
||||||
$("#show_motdeditor").parent().removeClass("active");
|
$(this).removeClass("active");
|
||||||
$("#show_filtereditor").parent().removeClass("active");
|
});
|
||||||
$("#show_chancontrols").parent().addClass("active");
|
|
||||||
$(".modonly").hide();
|
$(".modonly").hide();
|
||||||
|
$("#show_chancontrols").parent().addClass("active");
|
||||||
$("#chancontrols").show();
|
$("#chancontrols").show();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#show_banlist").click(function() {
|
$("#show_banlist").click(function() {
|
||||||
$("#show_chancontrols").parent().removeClass("active");
|
$("#modnav li").each(function() {
|
||||||
$("#show_motdeditor").parent().removeClass("active");
|
$(this).removeClass("active");
|
||||||
$("#show_filtereditor").parent().removeClass("active");
|
});
|
||||||
$("#show_banlist").parent().addClass("active");
|
|
||||||
$(".modonly").hide();
|
$(".modonly").hide();
|
||||||
|
$("#show_banlist").parent().addClass("active");
|
||||||
$("#banlist").show();
|
$("#banlist").show();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#show_motdeditor").click(function() {
|
$("#show_motdeditor").click(function() {
|
||||||
$("#show_chancontrols").parent().removeClass("active");
|
$("#modnav li").each(function() {
|
||||||
$("#show_banlist").parent().removeClass("active");
|
$(this).removeClass("active");
|
||||||
$("#show_filtereditor").parent().removeClass("active");
|
});
|
||||||
$("#show_motdeditor").parent().addClass("active");
|
|
||||||
$(".modonly").hide();
|
$(".modonly").hide();
|
||||||
|
$("#show_motdeditor").parent().addClass("active");
|
||||||
$("#motdeditor").show();
|
$("#motdeditor").show();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#show_filtereditor").click(function() {
|
$("#show_filtereditor").click(function() {
|
||||||
$("#show_chancontrols").parent().removeClass("active");
|
$("#modnav li").each(function() {
|
||||||
$("#show_banlist").parent().removeClass("active");
|
$(this).removeClass("active");
|
||||||
$("#show_motdeditor").parent().removeClass("active");
|
});
|
||||||
$("#show_filtereditor").parent().addClass("active");
|
|
||||||
$(".modonly").hide();
|
$(".modonly").hide();
|
||||||
|
$("#show_filtereditor").parent().addClass("active");
|
||||||
$("#filtereditor").show();
|
$("#filtereditor").show();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#show_acl").click(function() {
|
||||||
|
$("#modnav li").each(function() {
|
||||||
|
$(this).removeClass("active");
|
||||||
|
});
|
||||||
|
$(".modonly").hide();
|
||||||
|
$("#show_acl").parent().addClass("active");
|
||||||
|
$("#channelranks").show();
|
||||||
|
});
|
||||||
|
|
||||||
function searchLibrary() {
|
function searchLibrary() {
|
||||||
socket.emit("searchLibrary", {
|
socket.emit("searchLibrary", {
|
||||||
query: $("#library_query").val()
|
query: $("#library_query").val()
|
||||||
|
|
|
@ -672,6 +672,50 @@ function updateChatFilters(entries) {
|
||||||
add.click(cback);
|
add.click(cback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateACL(entries) {
|
||||||
|
entries.sort(function(a, b) {
|
||||||
|
var x = a.name.toLowerCase();
|
||||||
|
var y = b.name.toLowerCase();
|
||||||
|
return y == x ? 0 : (x < y ? -1 : 1);
|
||||||
|
});
|
||||||
|
var tbl = $("#channelranks table");
|
||||||
|
if(tbl.children().length > 1) {
|
||||||
|
$(tbl.children()[1]).remove();
|
||||||
|
}
|
||||||
|
for(var i = 0; i < entries.length; i++) {
|
||||||
|
var tr = $("<tr/>").appendTo(tbl);
|
||||||
|
var name = $("<td/>").text(entries[i].name).appendTo(tr);
|
||||||
|
name.addClass(getNameColor(entries[i].rank));
|
||||||
|
var rank = $("<td/>").text(entries[i].rank).appendTo(tr);
|
||||||
|
var control = $("<td/>").appendTo(tr);
|
||||||
|
var up = $("<button/>").addClass("btn btn-mini btn-success")
|
||||||
|
.appendTo(control);
|
||||||
|
$("<i/>").addClass("icon-plus").appendTo(up);
|
||||||
|
var down = $("<button/>").addClass("btn btn-mini btn-danger")
|
||||||
|
.appendTo(control);
|
||||||
|
$("<i/>").addClass("icon-minus").appendTo(down);
|
||||||
|
if(entries[i].rank + 1 >= RANK) {
|
||||||
|
up.attr("disabled", true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
up.click(function(name) { return function() {
|
||||||
|
socket.emit("promote", {
|
||||||
|
name: name
|
||||||
|
});
|
||||||
|
}}(entries[i].name));
|
||||||
|
}
|
||||||
|
if(entries[i].rank >= RANK) {
|
||||||
|
down.attr("disabled", true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
down.click(function(name) { return function() {
|
||||||
|
socket.emit("demote", {
|
||||||
|
name: name
|
||||||
|
});
|
||||||
|
}}(entries[i].name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
function handleRankChange() {
|
function handleRankChange() {
|
||||||
rebuildPlaylist();
|
rebuildPlaylist();
|
||||||
if(RANK >= Rank.Moderator || LEADER) {
|
if(RANK >= Rank.Moderator || LEADER) {
|
||||||
|
|
|
@ -113,6 +113,9 @@
|
||||||
<li>
|
<li>
|
||||||
<a href="javascript:void(0)" id="show_filtereditor">Chat Filters</a>
|
<a href="javascript:void(0)" id="show_filtereditor">Chat Filters</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="javascript:void(0)" id="show_acl">Channel Ranks</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -199,6 +202,17 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row modonly" id="channelranks" style="display: none;">
|
||||||
|
<div class="span10 offset1">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Rank</th>
|
||||||
|
<th>Control</th>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row" id="layout_buttons">
|
<div class="row" id="layout_buttons">
|
||||||
<div class="span4 offset3">
|
<div class="span4 offset3">
|
||||||
<div class="btn-group" style="width: 100%">
|
<div class="btn-group" style="width: 100%">
|
||||||
|
|
Loading…
Reference in New Issue