Commit 9f3fc8ea authored by nanahira's avatar nanahira

Merge branch 'auth' into mc

parents a4096a16 011b723a
......@@ -19,6 +19,7 @@ config.user.bak
/ssl
/ygosrv233
/challonge
/logs
test*
*.heapsnapshot
......
......@@ -154,7 +154,6 @@
"show_ip": false,
"show_info": true,
"log_save_path": "./config/",
"password": "123456",
"port": 7933
},
"side_restrict": {
......@@ -170,7 +169,6 @@
"pre_util": {
"enabled": false,
"port": 7944,
"password": "123456",
"git_html_path": "../mercury233.github.io/",
"html_path": "../mercury233.github.io/ygosrv233/",
"html_filename": "pre.html",
......@@ -249,7 +247,6 @@
"update_util": {
"enabled": false,
"port": 7955,
"password": "123456",
"git_html_path": "../ygo233-web/",
"html_path": "../ygo233-web/",
"cdb_path": "./ygopro/cards.cdb",
......@@ -275,7 +272,6 @@
},
"http": {
"port": 7922,
"password": "123456",
"websocket_roomlist": false,
"public_roomlist": false,
"show_ip": false,
......
......@@ -31,5 +31,49 @@
"chat_color": {
"file": "./config/chat_color.json",
"save_list": {}
},
"users": {
"file": "./config/admin_user.json",
"permission_examples": {
"sudo": {
"get_rooms": true,
"duel_log": true,
"download_replay": true,
"clear_duel_log": true,
"deck_dashboard_read": true,
"deck_dashboard_write": true,
"shout": true,
"stop": true,
"change_settings": true,
"ban_user": true,
"kick_user": true,
"start_death": true,
"pre_dashboard": true,
"update_dashboard": true
},
"judge": {
"get_rooms": true,
"duel_log": true,
"download_replay": true,
"deck_dashboard_read": true,
"deck_dashboard_write": true,
"shout": true,
"kick_user": true,
"start_death": true
},
"streamer": {
"get_rooms": true,
"duel_log": true,
"download_replay": true,
"deck_dashboard_read": true
}
},
"users": {
"root": {
"password": "123456",
"enabled": false,
"permissions": "sudo"
}
}
}
}
\ No newline at end of file
}
###
Main script of new dashboard account system.
The account list file is stored at `./config/admin_user.json`. The users are stored at `users`.
The key is the username. The `permissions` field could be a string, using a permission set from the example, or an object, to define a specific set of permissions.
eg. An account for a judge could be as follows, to use the default permission of judges,
"username": {
"password": "123456",
"enabled": true,
"permissions": "judge"
},
or as follows, to use a specific set of permissions.
"username": {
"password": "123456",
"enabled": true,
"permissions": {
"get_rooms": true,
"duel_log": true,
"download_replay": true,
"deck_dashboard_read": true,
"deck_dashboard_write": true,
"shout": true,
"kick_user": true,
"start_death": true
}
},
###
fs = require 'fs'
loadJSON = require('load-json-file').sync
moment = require 'moment'
moment.locale('zh-cn', {
relativeTime: {
future: '%s内',
past: '%s前',
s: '%d秒',
m: '1分钟',
mm: '%d分钟',
h: '1小时',
hh: '%d小时',
d: '1天',
dd: '%d天',
M: '1个月',
MM: '%d个月',
y: '1年',
yy: '%d年'
}
})
if not fs.existsSync('./logs')
fs.mkdirSync('./logs')
add_log = (message) ->
mt = moment()
text = mt.format('YYYY-MM-DD HH:mm:ss') + " --> " + message + "\n"
console.log(text)
res = false
try
fs.appendFileSync("./logs/"+mt.format('YYYY-MM-DD')+".log", text)
res = true
catch
res = false
return
default_data = loadJSON('./data/default_data.json')
setting_save = (settings) ->
fs.writeFileSync(settings.file, JSON.stringify(settings, null, 2))
return
default_data = loadJSON('./data/default_data.json')
try
users = loadJSON('./config/admin_user.json')
catch
users = default_data.users
setting_save(users)
save = () ->
setting_save(users)
return
reload = () ->
user_backup = users
try
users = loadJSON('./config/admin_user.json')
catch
users = user_backup
add_log("Invalid user data JSON")
return
check_permission = (user, permission_required) ->
_permission = user.permissions
permission = _permission
if typeof(permission) != 'object'
permission = users.permission_examples[_permission]
if !permission
add_log("Permision not set:"+_permission)
return false
return permission[permission_required]
@auth = (name, pass, permission_required, action = 'unknown') ->
reload()
user = users.users[name]
if !user
add_log("Unknown user login. User: "+ name+", Permission needed: "+ permission_required+", Action: " +action)
return false
if user.password != pass
add_log("Unauthorized user login. User: "+ name+", Permission needed: "+ permission_required+", Action: " +action)
return false
if !user.enabled
add_log("Disabled user login. User: "+ name+", Permission needed: "+ permission_required+", Action: " +action)
return false
if !check_permission(user, permission_required)
add_log("Permission denied. User: "+ name+", Permission needed: "+ permission_required+", Action: " +action)
return false
add_log("Operation success. User: "+ name+", Permission needed: "+ permission_required+", Action: " +action)
return true
@add_user = (name, pass, enabled, permissions) ->
reload()
if users.users[name]
return false
users.users[name] = {
"password": pass,
"enabled": enabled,
"permissions": permissions
}
save()
return true
@delete_user = (name) ->
reload()
if !users.users[name]
return false
delete users.users[name]
save()
return true
@update_user = (name, key, value) ->
reload()
if !users.users[name]
return false
users.users[name][key] = value
save()
return true
// Generated by CoffeeScript 1.12.7
/*
Main script of new dashboard account system.
The account list file is stored at `./config/admin_user.json`. The users are stored at `users`.
The key is the username. The `permissions` field could be a string, using a permission set from the example, or an object, to define a specific set of permissions.
eg. An account for a judge could be as follows, to use the default permission of judges,
"username": {
"password": "123456",
"enabled": true,
"permissions": "judge"
},
or as follows, to use a specific set of permissions.
"username": {
"password": "123456",
"enabled": true,
"permissions": {
"get_rooms": true,
"duel_log": true,
"download_replay": true,
"deck_dashboard_read": true,
"deck_dashboard_write": true,
"shout": true,
"kick_user": true,
"start_death": true
}
},
*/
(function() {
var add_log, check_permission, default_data, fs, loadJSON, moment, reload, save, setting_save, users;
fs = require('fs');
loadJSON = require('load-json-file').sync;
moment = require('moment');
moment.locale('zh-cn', {
relativeTime: {
future: '%s内',
past: '%s前',
s: '%d秒',
m: '1分钟',
mm: '%d分钟',
h: '1小时',
hh: '%d小时',
d: '1天',
dd: '%d天',
M: '1个月',
MM: '%d个月',
y: '1年',
yy: '%d年'
}
});
if (!fs.existsSync('./logs')) {
fs.mkdirSync('./logs');
}
add_log = function(message) {
var mt, res, text;
mt = moment();
text = mt.format('YYYY-MM-DD HH:mm:ss') + " --> " + message + "\n";
console.log(text);
res = false;
try {
fs.appendFileSync("./logs/" + mt.format('YYYY-MM-DD') + ".log", text);
res = true;
} catch (error) {
res = false;
}
};
default_data = loadJSON('./data/default_data.json');
setting_save = function(settings) {
fs.writeFileSync(settings.file, JSON.stringify(settings, null, 2));
};
default_data = loadJSON('./data/default_data.json');
try {
users = loadJSON('./config/admin_user.json');
} catch (error) {
users = default_data.users;
setting_save(users);
}
save = function() {
setting_save(users);
};
reload = function() {
var user_backup;
user_backup = users;
try {
users = loadJSON('./config/admin_user.json');
} catch (error) {
users = user_backup;
add_log("Invalid user data JSON");
}
};
check_permission = function(user, permission_required) {
var _permission, permission;
_permission = user.permissions;
permission = _permission;
if (typeof permission !== 'object') {
permission = users.permission_examples[_permission];
}
if (!permission) {
add_log("Permision not set:" + _permission);
return false;
}
return permission[permission_required];
};
this.auth = function(name, pass, permission_required, action) {
var user;
if (action == null) {
action = 'unknown';
}
reload();
user = users.users[name];
if (!user) {
add_log("Unknown user login. User: " + name + ", Permission needed: " + permission_required + ", Action: " + action);
return false;
}
if (user.password !== pass) {
add_log("Unauthorized user login. User: " + name + ", Permission needed: " + permission_required + ", Action: " + action);
return false;
}
if (!user.enabled) {
add_log("Disabled user login. User: " + name + ", Permission needed: " + permission_required + ", Action: " + action);
return false;
}
if (!check_permission(user, permission_required)) {
add_log("Permission denied. User: " + name + ", Permission needed: " + permission_required + ", Action: " + action);
return false;
}
add_log("Operation success. User: " + name + ", Permission needed: " + permission_required + ", Action: " + action);
return true;
};
this.add_user = function(name, pass, enabled, permissions) {
reload();
if (users.users[name]) {
return false;
}
users.users[name] = {
"password": pass,
"enabled": enabled,
"permissions": permissions
};
save();
return true;
};
this.delete_user = function(name) {
reload();
if (!users.users[name]) {
return false;
}
delete users.users[name];
save();
return true;
};
this.update_user = function(name, key, value) {
reload();
if (!users.users[name]) {
return false;
}
users.users[name][key] = value;
save();
return true;
};
}).call(this);
......@@ -17,6 +17,8 @@ var moment = require('moment');
moment.locale('zh-cn');
var loadJSON = require('load-json-file').sync;
var auth = require('./ygopro-auth.js');
var constants = loadJSON('./data/constants.json');
var settings = loadJSON('./config/config.json');
......@@ -404,7 +406,7 @@ var packDatas = function () {
http.createServer(function (req, res) {
var u = url.parse(req.url, true);
if (u.query.password !== config.password) {
if (!auth.auth(u.query.username, u.query.password, "pre_dashboard", "pre_dashboard")) {
res.writeHead(403);
res.end("Auth Failed.");
return;
......@@ -462,4 +464,3 @@ http.createServer(function (req, res) {
}
}).listen(config.port);
......@@ -157,6 +157,8 @@ catch
config = {}
settings = global.settings = merge(default_config, config, { arrayMerge: (destination, source) -> source })
auth = require './ygopro-auth.js'
#import old configs
imported = false
#reset http.quick_death_rule from true to 1
......@@ -168,6 +170,41 @@ if settings.modules.cloud_replay.redis_port
settings.modules.cloud_replay.redis.port = settings.modules.cloud_replay.redis_port
delete settings.modules.cloud_replay.redis_port
imported = true
#import the old passwords to new admin user system
if settings.modules.http.password
auth.add_user("olduser", settings.modules.http.password, true, {
"get_rooms": true,
"shout": true,
"stop": true,
"change_settings": true,
"ban_user": true,
"kick_user": true,
"start_death": true
})
delete settings.modules.http.password
imported = true
if settings.modules.tournament_mode.password
auth.add_user("tournament", settings.modules.tournament_mode.password, true, {
"duel_log": true,
"download_replay": true,
"clear_duel_log": true,
"deck_dashboard_read": true,
"deck_dashboard_write": true,
})
delete settings.modules.tournament_mode.password
imported = true
if settings.modules.pre_util.password
auth.add_user("pre", settings.modules.pre_util.password, true, {
"pre_dashboard": true
})
delete settings.modules.pre_util.password
imported = true
if settings.modules.update_util.password
auth.add_user("update", settings.modules.update_util.password, true, {
"update_dashboard": true
})
delete settings.modules.update_util.password
imported = true
#finish
if imported
setting_save(settings)
......@@ -3205,10 +3242,11 @@ if settings.modules.http
requestListener = (request, response)->
parseQueryString = true
u = url.parse(request.url, parseQueryString)
pass_validated = u.query.pass == settings.modules.http.password
#pass_validated = u.query.pass == settings.modules.http.password
#console.log(u.query.username, u.query.pass)
if u.pathname == '/api/getrooms'
if !pass_validated and !settings.modules.http.public_roomlist
if !settings.modules.http.public_roomlist and !auth.auth(u.query.username, u.query.pass, "get_rooms", "get_rooms")
response.writeHead(200)
response.end(addCallback(u.query.callback, '{"rooms":[{"roomid":"0","roomname":"密码错误","needpass":"true"}]}'))
else
......@@ -3234,7 +3272,7 @@ if settings.modules.http
response.end(addCallback(u.query.callback, roomsjson))
else if u.pathname == '/api/duellog' and settings.modules.tournament_mode.enabled
if !(u.query.pass == settings.modules.tournament_mode.password)
if !auth.auth(u.query.username, u.query.pass, "duel_log", "duel_log")
response.writeHead(200)
response.end(addCallback(u.query.callback, "[{name:'密码错误'}]"))
return
......@@ -3244,7 +3282,7 @@ if settings.modules.http
response.end(addCallback(u.query.callback, duellog))
else if u.pathname == '/api/archive.zip' and settings.modules.tournament_mode.enabled
if !(u.query.pass == settings.modules.tournament_mode.password)
if !auth.auth(u.query.username, u.query.pass, "download_replay", "download_replay_archive")
response.writeHead(403)
response.end("Invalid password.")
return
......@@ -3287,7 +3325,7 @@ if settings.modules.http
response.end("Failed reading replays. " + error)
else if u.pathname == '/api/clearlog' and settings.modules.tournament_mode.enabled
if !(u.query.pass == settings.modules.tournament_mode.password)
if !auth.auth(u.query.username, u.query.pass, "clear_duel_log", "clear_duel_log")
response.writeHead(200)
response.end(addCallback(u.query.callback, "[{name:'密码错误'}]"))
return
......@@ -3303,7 +3341,7 @@ if settings.modules.http
response.end(addCallback(u.query.callback, "[{name:'Success'}]"))
else if _.startsWith(u.pathname, '/api/replay') and settings.modules.tournament_mode.enabled
if !(u.query.pass == settings.modules.tournament_mode.password)
if !auth.auth(u.query.username, u.query.pass, "download_replay", "download_replay")
response.writeHead(403)
response.end("密码错误")
return
......@@ -3321,18 +3359,26 @@ if settings.modules.http
)
else if u.pathname == '/api/message'
if !pass_validated
response.writeHead(200)
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
#if !pass_validated
# response.writeHead(200)
# response.end(addCallback(u.query.callback, "['密码错误', 0]"))
# return
if u.query.shout
if !auth.auth(u.query.username, u.query.pass, "shout", "shout")
response.writeHead(200)
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
for room in ROOM_all when room and room.established
ygopro.stoc_send_chat_to_room(room, u.query.shout, ygopro.constants.COLORS.YELLOW)
response.writeHead(200)
response.end(addCallback(u.query.callback, "['shout ok', '" + u.query.shout + "']"))
else if u.query.stop
if !auth.auth(u.query.username, u.query.pass, "stop", "stop")
response.writeHead(200)
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
if u.query.stop == 'false'
u.query.stop = false
setting_change(settings, 'modules:stop', u.query.stop)
......@@ -3340,30 +3386,54 @@ if settings.modules.http
response.end(addCallback(u.query.callback, "['stop ok', '" + u.query.stop + "']"))
else if u.query.welcome
if !auth.auth(u.query.username, u.query.pass, "change_settings", "change_welcome")
response.writeHead(200)
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
setting_change(settings, 'modules:welcome', u.query.welcome)
response.writeHead(200)
response.end(addCallback(u.query.callback, "['welcome ok', '" + u.query.welcome + "']"))
else if u.query.getwelcome
if !auth.auth(u.query.username, u.query.pass, "change_settings", "get_welcome")
response.writeHead(200)
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
response.writeHead(200)
response.end(addCallback(u.query.callback, "['get ok', '" + settings.modules.welcome + "']"))
else if u.query.loadtips
if !auth.auth(u.query.username, u.query.pass, "change_settings", "change_tips")
response.writeHead(200)
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
load_tips()
response.writeHead(200)
response.end(addCallback(u.query.callback, "['loading tip', '" + settings.modules.tips.get + "']"))
else if u.query.loaddialogues
if !auth.auth(u.query.username, u.query.pass, "change_settings", "change_dialogues")
response.writeHead(200)
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
load_dialogues()
response.writeHead(200)
response.end(addCallback(u.query.callback, "['loading dialogues', '" + settings.modules.dialogues.get + "']"))
else if u.query.ban
if !auth.auth(u.query.username, u.query.pass, "ban_user", "ban_user")
response.writeHead(200)
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
ban_user(u.query.ban)
response.writeHead(200)
response.end(addCallback(u.query.callback, "['ban ok', '" + u.query.ban + "']"))
else if u.query.kick
if !auth.auth(u.query.username, u.query.pass, "kick_user", "kick_user")
response.writeHead(200)
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
kick_room_found = false
for room in ROOM_all when room and room.established and (u.query.kick == "all" or u.query.kick == room.process_pid.toString() or u.query.kick == room.name)
kick_room_found = true
......@@ -3381,6 +3451,10 @@ if settings.modules.http
response.end(addCallback(u.query.callback, "['room not found', '" + u.query.kick + "']"))
else if u.query.death
if !auth.auth(u.query.username, u.query.pass, "start_death", "start_death")
response.writeHead(200)
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
death_room_found = false
for room in ROOM_all when room and room.established and room.started and !room.death and (u.query.death == "all" or u.query.death == room.process_pid.toString() or u.query.death == room.name)
death_room_found = true
......@@ -3426,6 +3500,10 @@ if settings.modules.http
response.end(addCallback(u.query.callback, "['room not found', '" + u.query.death + "']"))
else if u.query.deathcancel
if !auth.auth(u.query.username, u.query.pass, "start_death", "cancel_death")
response.writeHead(200)
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
death_room_found = false
for room in ROOM_all when room and room.established and room.started and room.death and (u.query.deathcancel == "all" or u.query.deathcancel == room.process_pid.toString())
death_room_found = true
......
This diff is collapsed.
......@@ -16,6 +16,8 @@ _.str = require('underscore.string');
_.mixin(_.str.exports());
var loadJSON = require('load-json-file').sync;
var auth = require('./ygopro-auth.js');
var settings = loadJSON('./config/config.json');
config=settings.modules.tournament_mode;
challonge_config=settings.modules.challonge;
......@@ -215,13 +217,18 @@ var receiveDecks = function(files) {
http.createServer(function (req, res) {
var u = url.parse(req.url, true);
if (u.query.password !== config.password) {
/*if (u.query.password !== config.password) {
res.writeHead(403);
res.end("Auth Failed.");
return;
}
}*/
if (u.pathname === '/api/upload_decks' && req.method.toLowerCase() == 'post') {
if (!auth.auth(u.query.username, u.query.password, "deck_dashboard_write", "upload_deck")) {
res.writeHead(403);
res.end("Auth Failed.");
return;
}
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
res.writeHead(200, {
......@@ -234,6 +241,11 @@ http.createServer(function (req, res) {
});
}
else if (u.pathname === '/api/msg') {
if (!auth.auth(u.query.username, u.query.password, "deck_dashboard_read", "login_deck_dashboard")) {
res.writeHead(403);
res.end("Auth Failed.");
return;
}
res.writeHead(200, {
"Access-Control-Allow-origin": "*",
"Content-Type": "text/event-stream",
......@@ -250,25 +262,50 @@ http.createServer(function (req, res) {
sendResponse("已连接。");
}
else if (u.pathname === '/api/get_bg') {
if (!auth.auth(u.query.username, u.query.password, "deck_dashboard_read", "login_deck_dashboard")) {
res.writeHead(403);
res.end("Auth Failed.");
return;
}
res.writeHead(200);
res.end(u.query.callback+'('+JSON.stringify(config.wallpapers[Math.floor(Math.random() * config.wallpapers.length)])+');');
}
else if (u.pathname === '/api/get_decks') {
if (!auth.auth(u.query.username, u.query.password, "deck_dashboard_read", "get_decks")) {
res.writeHead(403);
res.end("Auth Failed.");
return;
}
res.writeHead(200);
var decklist=getDecks();
res.end(u.query.callback+'('+JSON.stringify(decklist)+');');
}
else if (u.pathname === '/api/del_deck') {
if (!auth.auth(u.query.username, u.query.password, "deck_dashboard_write", "delete_deck")) {
res.writeHead(403);
res.end("Auth Failed.");
return;
}
res.writeHead(200);
var result=delDeck(u.query.msg);
res.end(u.query.callback+'("'+result+'");');
}
else if (u.pathname === '/api/clear_decks') {
if (!auth.auth(u.query.username, u.query.password, "deck_dashboard_write", "clear_decks")) {
res.writeHead(403);
res.end("Auth Failed.");
return;
}
res.writeHead(200);
clearDecks();
res.end(u.query.callback+'("已删除全部卡组。");');
}
else if (u.pathname === '/api/upload_to_challonge') {
if (!auth.auth(u.query.username, u.query.password, "deck_dashboard_write", "upload_to_challonge")) {
res.writeHead(403);
res.end("Auth Failed.");
return;
}
res.writeHead(200);
var result=UploadToChallonge();
res.end(u.query.callback+'("操作完成。");');
......@@ -279,4 +316,3 @@ http.createServer(function (req, res) {
}
}).listen(config.port);
......@@ -18,6 +18,8 @@ var moment = require('moment');
moment.locale('zh-cn');
var loadJSON = require('load-json-file').sync;
var auth = require('./ygopro-auth.js');
var constants = loadJSON('./data/constants.json');
var settings = loadJSON('./config/config.json');
......@@ -209,7 +211,7 @@ var pushHTMLs = function() {
http.createServer(function (req, res) {
var u = url.parse(req.url, true);
if (u.query.password !== config.password) {
if (!auth.auth(u.query.username, u.query.password, "update_dashboard", "update_dashboard")) {
res.writeHead(403);
res.end("Auth Failed.");
return;
......@@ -270,4 +272,3 @@ http.createServer(function (req, res) {
}
}).listen(config.port);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment