Commit 53fda750 authored by nanahira's avatar nanahira

remake ygopro-tournament to ts

parent 02528579
......@@ -80,12 +80,12 @@ class Challonge {
return false;
}
}
// POST /v1/tournaments/${tournament_id}/participants/bulk_add.json { api_key: string, participants: { name: string }[] } returns ANY
async uploadParticipants(participantNames) {
// POST /v1/tournaments/${tournament_id}/participants/bulk_add.json { api_key: string, participants: { name: string, deckbuf?: string }[] } returns ANY
async uploadParticipants(participants) {
try {
await axios_1.default.post(`${this.config.challonge_url}/v1/tournaments/${this.config.tournament_id}/participants/bulk_add.json`, {
api_key: this.config.api_key,
participants: participantNames.map(name => ({ name })),
participants,
});
return true;
}
......
......@@ -37,11 +37,13 @@
"ygopro-deck-encode": "^1.0.14"
},
"devDependencies": {
"@types/async": "^3.2.25",
"@types/bunyan": "^1.8.8",
"@types/formidable": "^3.4.6",
"@types/ip6addr": "^0.2.3",
"@types/lzma": "^2.3.0",
"@types/node": "^16.18.126",
"@types/underscore": "^1.11.4",
"@types/underscore": "^1.13.0",
"@types/ws": "^8.5.3",
"coffeescript": "^2.7.0",
"typescript": "^5.8.3"
......@@ -93,6 +95,13 @@
"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.2.tgz",
"integrity": "sha512-/5O7Fq6Vnv8L6ucmPjaWbVG1XkP4FO+w5glqfkIsq3Xw4oyNAdJddbnYodNDAfjVUvo/rrSCTom4kAND7T1o5Q=="
},
"node_modules/@types/async": {
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/@types/async/-/async-3.2.25.tgz",
"integrity": "sha512-O6Th/DI18XjrL9TX8LO9F/g26qAz5vynmQqlXt/qLGrskvzCKXKc5/tATz3G2N6lM8eOf3M8/StB14FncAmocg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/bunyan": {
"version": "1.8.8",
"resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.8.tgz",
......@@ -102,6 +111,16 @@
"@types/node": "*"
}
},
"node_modules/@types/formidable": {
"version": "3.4.6",
"resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-3.4.6.tgz",
"integrity": "sha512-LI4Hk+KNsM5q7br4oMVoaWeb+gUqJpz1N8+Y2Q6Cz9cVH33ybahRKUWaRmMboVlkwSbOUGgwc/pEkS7yMSzoWg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/ip6addr": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/@types/ip6addr/-/ip6addr-0.2.3.tgz",
......@@ -126,10 +145,11 @@
"license": "MIT"
},
"node_modules/@types/underscore": {
"version": "1.11.4",
"resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.11.4.tgz",
"integrity": "sha512-uO4CD2ELOjw8tasUrAhvnn2W4A0ZECOvMjCivJr4gA9pGgjv+qxKWY9GLTMVEK8ej85BxQOocUyE7hImmSQYcg==",
"dev": true
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.13.0.tgz",
"integrity": "sha512-L6LBgy1f0EFQZ+7uSA57+n2g/s4Qs5r06Vwrwn0/nuK1de+adz00NWaztRQ30aEqw5qOaWbPI8u2cGQ52lj6VA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/ws": {
"version": "8.5.3",
......@@ -1557,6 +1577,7 @@
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.6.1.tgz",
"integrity": "sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@ioredis/commands": "^1.1.1",
"cluster-key-slot": "^1.1.0",
......@@ -3733,6 +3754,12 @@
"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.2.tgz",
"integrity": "sha512-/5O7Fq6Vnv8L6ucmPjaWbVG1XkP4FO+w5glqfkIsq3Xw4oyNAdJddbnYodNDAfjVUvo/rrSCTom4kAND7T1o5Q=="
},
"@types/async": {
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/@types/async/-/async-3.2.25.tgz",
"integrity": "sha512-O6Th/DI18XjrL9TX8LO9F/g26qAz5vynmQqlXt/qLGrskvzCKXKc5/tATz3G2N6lM8eOf3M8/StB14FncAmocg==",
"dev": true
},
"@types/bunyan": {
"version": "1.8.8",
"resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.8.tgz",
......@@ -3742,6 +3769,15 @@
"@types/node": "*"
}
},
"@types/formidable": {
"version": "3.4.6",
"resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-3.4.6.tgz",
"integrity": "sha512-LI4Hk+KNsM5q7br4oMVoaWeb+gUqJpz1N8+Y2Q6Cz9cVH33ybahRKUWaRmMboVlkwSbOUGgwc/pEkS7yMSzoWg==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/ip6addr": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/@types/ip6addr/-/ip6addr-0.2.3.tgz",
......@@ -3764,9 +3800,9 @@
"dev": true
},
"@types/underscore": {
"version": "1.11.4",
"resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.11.4.tgz",
"integrity": "sha512-uO4CD2ELOjw8tasUrAhvnn2W4A0ZECOvMjCivJr4gA9pGgjv+qxKWY9GLTMVEK8ej85BxQOocUyE7hImmSQYcg==",
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.13.0.tgz",
"integrity": "sha512-L6LBgy1f0EFQZ+7uSA57+n2g/s4Qs5r06Vwrwn0/nuK1de+adz00NWaztRQ30aEqw5qOaWbPI8u2cGQ52lj6VA==",
"dev": true
},
"@types/ws": {
......@@ -4809,6 +4845,7 @@
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.6.1.tgz",
"integrity": "sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA==",
"peer": true,
"requires": {
"@ioredis/commands": "^1.1.1",
"cluster-key-slot": "^1.1.0",
......
......@@ -48,11 +48,13 @@
"webhook": "node ygopro-webhook.js"
},
"devDependencies": {
"@types/async": "^3.2.25",
"@types/bunyan": "^1.8.8",
"@types/formidable": "^3.4.6",
"@types/ip6addr": "^0.2.3",
"@types/lzma": "^2.3.0",
"@types/node": "^16.18.126",
"@types/underscore": "^1.11.4",
"@types/underscore": "^1.13.0",
"@types/ws": "^8.5.3",
"coffeescript": "^2.7.0",
"typescript": "^5.8.3"
......
###
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
loadJSONPromise = require('load-json-file')
moment = require 'moment'
moment.updateLocale('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年'
}
})
bunyan = require 'bunyan'
log = bunyan.createLogger name: "auth"
util = require 'util'
if not fs.existsSync('./logs')
fs.mkdirSync('./logs')
add_log = (message) ->
mt = moment()
log.info(message)
text = mt.format('YYYY-MM-DD HH:mm:ss') + " --> " + message + "\n"
res = false
try
await fs.promises.appendFile("./logs/"+mt.format('YYYY-MM-DD')+".log", text)
res = true
catch
res = false
return res
default_data = loadJSON('./data/default_data.json')
setting_save = (settings) ->
try
await fs.promises.writeFile(settings.file, JSON.stringify(settings, null, 2))
catch e
add_log("save fail");
return
default_data = loadJSON('./data/default_data.json')
try
users = loadJSON('./config/admin_user.json')
catch
users = default_data.users
setting_save(users)
save = () ->
return await setting_save(users)
reload = () ->
user_backup = users
try
users = await loadJSONPromise('./config/admin_user.json')
catch
users = user_backup
await 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
await add_log("Permision not set:"+_permission)
return false
return permission[permission_required]
@auth = (name, pass, permission_required, action = 'unknown', no_log) ->
await reload()
user = users.users[name]
if !user
await add_log("Unknown user login. User: "+ name+", Permission needed: "+ permission_required+", Action: " +action)
return false
if user.password != pass
await add_log("Unauthorized user login. User: "+ name+", Permission needed: "+ permission_required+", Action: " +action)
return false
if !user.enabled
await add_log("Disabled user login. User: "+ name+", Permission needed: "+ permission_required+", Action: " +action)
return false
if !await check_permission(user, permission_required)
await add_log("Permission denied. User: "+ name+", Permission needed: "+ permission_required+", Action: " +action)
return false
if !no_log
await add_log("Operation success. User: "+ name+", Permission needed: "+ permission_required+", Action: " +action)
return true
@add_user = (name, pass, enabled, permissions) ->
await reload()
if users.users[name]
return false
users.users[name] = {
"password": pass,
"enabled": enabled,
"permissions": permissions
}
await save()
return true
@delete_user = (name) ->
await reload()
if !users.users[name]
return false
delete users.users[name]
await save()
return
@update_user = (name, key, value) ->
await reload()
if !users.users[name]
return false
users.users[name][key] = value
await save()
return
// Generated by CoffeeScript 2.7.0
(function() {
/*
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,
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.update_user = exports.delete_user = exports.add_user = exports.auth = void 0;
/*
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.
or as follows, to use a specific set of permissions.
"username": {
"password": "123456",
"enabled": true,
......@@ -25,168 +29,171 @@
"start_death": true
}
},
*/
var add_log, bunyan, check_permission, default_data, fs, loadJSON, loadJSONPromise, log, moment, reload, save, setting_save, users, util;
fs = require('fs');
loadJSON = require('load-json-file').sync;
loadJSONPromise = require('load-json-file');
moment = require('moment');
moment.updateLocale('zh-cn', {
*/
const fs_1 = __importDefault(require("fs"));
const load_json_file_1 = require("load-json-file");
const load_json_file_2 = __importDefault(require("load-json-file"));
const moment_1 = __importDefault(require("moment"));
const bunyan_1 = __importDefault(require("bunyan"));
moment_1.default.updateLocale("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年'
}
});
bunyan = require('bunyan');
log = bunyan.createLogger({
name: "auth"
});
util = require('util');
if (!fs.existsSync('./logs')) {
fs.mkdirSync('./logs');
}
add_log = async function(message) {
var mt, res, text;
mt = moment();
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年",
},
});
const log = bunyan_1.default.createLogger({ name: "auth" });
if (!fs_1.default.existsSync("./logs")) {
fs_1.default.mkdirSync("./logs");
}
const add_log = async function (message) {
const mt = (0, moment_1.default)();
log.info(message);
text = mt.format('YYYY-MM-DD HH:mm:ss') + " --> " + message + "\n";
res = false;
const text = mt.format("YYYY-MM-DD HH:mm:ss") + " --> " + message + "\n";
let res = false;
try {
await fs.promises.appendFile("./logs/" + mt.format('YYYY-MM-DD') + ".log", text);
await fs_1.default.promises.appendFile(`./logs/${mt.format("YYYY-MM-DD")}.log`, text);
res = true;
} catch (error) {
}
catch {
res = false;
}
return res;
};
default_data = loadJSON('./data/default_data.json');
setting_save = async function(settings) {
var e;
};
const default_data = (0, load_json_file_1.sync)("./data/default_data.json");
const setting_save = async function (settings) {
try {
await fs.promises.writeFile(settings.file, JSON.stringify(settings, null, 2));
} catch (error) {
e = error;
await fs_1.default.promises.writeFile(settings.file, JSON.stringify(settings, null, 2));
}
catch (e) {
add_log("save fail");
}
};
default_data = loadJSON('./data/default_data.json');
try {
users = loadJSON('./config/admin_user.json');
} catch (error) {
};
let users;
try {
users = (0, load_json_file_1.sync)("./config/admin_user.json");
}
catch {
users = default_data.users;
setting_save(users);
}
save = async function() {
return (await setting_save(users));
};
reload = async function() {
var user_backup;
user_backup = users;
}
const save = async function () {
await setting_save(users);
};
const reload = async function () {
const user_backup = users;
try {
users = (await loadJSONPromise('./config/admin_user.json'));
} catch (error) {
users = (await (0, load_json_file_2.default)("./config/admin_user.json"));
}
catch {
users = user_backup;
await add_log("Invalid user data JSON");
}
};
check_permission = async function(user, permission_required) {
var _permission, permission;
_permission = user.permissions;
permission = _permission;
if (typeof permission !== 'object') {
};
const check_permission = async function (user, permission_required) {
const _permission = user.permissions;
let permission;
if (typeof _permission !== "object") {
permission = users.permission_examples[_permission];
}
else {
permission = _permission;
}
if (!permission) {
await add_log("Permision not set:" + _permission);
await add_log("Permision not set:" + String(_permission));
return false;
}
return permission[permission_required];
};
this.auth = async function(name, pass, permission_required, action = 'unknown', no_log) {
var user;
return Boolean(permission[permission_required]);
};
const auth = async function (name, pass, permission_required, action = "unknown", no_log) {
await reload();
user = users.users[name];
const user = users.users[name];
if (!user) {
await add_log("Unknown user login. User: " + name + ", Permission needed: " + permission_required + ", Action: " + action);
await add_log("Unknown user login. User: " +
name +
", Permission needed: " +
permission_required +
", Action: " +
action);
return false;
}
if (user.password !== pass) {
await add_log("Unauthorized user login. User: " + name + ", Permission needed: " + permission_required + ", Action: " + action);
await add_log("Unauthorized user login. User: " +
name +
", Permission needed: " +
permission_required +
", Action: " +
action);
return false;
}
if (!user.enabled) {
await add_log("Disabled user login. User: " + name + ", Permission needed: " + permission_required + ", Action: " + action);
await add_log("Disabled user login. User: " +
name +
", Permission needed: " +
permission_required +
", Action: " +
action);
return false;
}
if (!(await check_permission(user, permission_required))) {
await add_log("Permission denied. User: " + name + ", Permission needed: " + permission_required + ", Action: " + action);
await add_log("Permission denied. User: " +
name +
", Permission needed: " +
permission_required +
", Action: " +
action);
return false;
}
if (!no_log) {
await add_log("Operation success. User: " + name + ", Permission needed: " + permission_required + ", Action: " + action);
await add_log("Operation success. User: " +
name +
", Permission needed: " +
permission_required +
", Action: " +
action);
}
return true;
};
this.add_user = async function(name, pass, enabled, permissions) {
};
exports.auth = auth;
const add_user = async function (name, pass, enabled, permissions) {
await reload();
if (users.users[name]) {
return false;
}
users.users[name] = {
"password": pass,
"enabled": enabled,
"permissions": permissions
password: pass,
enabled: enabled,
permissions: permissions,
};
await save();
return true;
};
this.delete_user = async function(name) {
};
exports.add_user = add_user;
const delete_user = async function (name) {
await reload();
if (!users.users[name]) {
return false;
return;
}
delete users.users[name];
await save();
};
this.update_user = async function(name, key, value) {
};
exports.delete_user = delete_user;
const update_user = async function (name, key, value) {
await reload();
if (!users.users[name]) {
return false;
return;
}
users.users[name][key] = value;
await save();
};
}).call(this);
};
exports.update_user = update_user;
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/*
ygopro-tournament.js
ygopro-tournament.ts
ygopro tournament util
Author: mercury233
License: MIT
不带参数运行时,会建立一个服务器,调用API执行对应操作
*/
const http = require('http');
const https = require('https');
const fs = require('fs');
const url = require('url');
const request = require('request');
const formidable = require('formidable');
const _ = require('underscore');
_.str = require('underscore.string');
_.mixin(_.str.exports());
const loadJSON = require('load-json-file').sync;
const auth = require('./ygopro-auth.js');
const settings = loadJSON('./config/config.json');
config = settings.modules.tournament_mode;
challonge_config = settings.modules.challonge;
const { Challonge } = require('./challonge');
const challonge = new Challonge(challonge_config);
ssl_config = settings.modules.http.ssl;
const _async = require("async");
const YGOProDeckEncode = require('ygopro-deck-encode').default;
const http = __importStar(require("http"));
const https = __importStar(require("https"));
const fs = __importStar(require("fs"));
const url = __importStar(require("url"));
const axios_1 = __importDefault(require("axios"));
const formidable = __importStar(require("formidable"));
const load_json_file_1 = require("load-json-file");
const challonge_1 = require("./challonge");
const asyncLib = __importStar(require("async"));
const ygopro_deck_encode_1 = __importDefault(require("ygopro-deck-encode"));
const auth = __importStar(require("./ygopro-auth"));
const underscore_1 = __importDefault(require("underscore"));
const settings = (0, load_json_file_1.sync)("./config/config.json");
const config = settings.modules.tournament_mode;
const challonge_config = settings.modules.challonge;
const challonge = new challonge_1.Challonge(challonge_config);
const ssl_config = settings.modules.http.ssl;
//http长连接
let responder;
config.wallpapers=[""];
request({
url: "http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=8&mkt=zh-CN",
json: true
}, function(error, response, body) {
if (_.isString(body)) {
config.wallpapers = [""];
axios_1.default
.get("http://www.bing.com/HPImageArchive.aspx", {
params: {
format: "js",
idx: 0,
n: 8,
mkt: "zh-CN",
},
})
.then((response) => {
const body = response.data;
if (typeof body !== "object" || !body.images) {
console.log("wallpapers bad json", body);
}
else if (error || !body) {
console.log('wallpapers error', error, response);
else if (!body) {
console.log("wallpapers error", null, response);
}
else {
config.wallpapers=[];
config.wallpapers = [];
for (const i in body.images) {
const wallpaper=body.images[i];
const img={
"url": "http://s.cn.bing.net"+wallpaper.urlbase+"_768x1366.jpg",
"desc": wallpaper.copyright
}
const wallpaper = body.images[i];
const img = {
url: "http://s.cn.bing.net" + wallpaper.urlbase + "_768x1366.jpg",
desc: wallpaper.copyright,
};
config.wallpapers.push(img);
}
}
})
.catch((error) => {
console.log("wallpapers error", error, error?.response);
});
//输出反馈信息,如有http长连接则输出到http,否则输出到控制台
const sendResponse = function(text) {
text=""+text;
const sendResponse = function (text) {
text = "" + text;
if (responder) {
text=text.replace(/\n/g,"<br>");
text = text.replace(/\n/g, "<br>");
responder.write("data: " + text + "\n\n");
}
else {
console.log(text);
}
}
};
//读取指定卡组
const readDeck = async function(deck_name, deck_full_path) {
const deck={};
deck.name=deck_name;
deck_text = await fs.promises.readFile(deck_full_path, { encoding: "ASCII" });
return YGOProDeckEncode.fromYdkString(deck_text);
}
const readDeck = async function (deck_name, deck_full_path) {
const deck_text = await fs.promises.readFile(deck_full_path, { encoding: "utf-8" });
const deck = ygopro_deck_encode_1.default.fromYdkString(deck_text);
deck.name = deck_name;
return deck;
};
//读取指定文件夹中所有卡组
const getDecks = function(callback) {
const decks=[];
_async.auto({
const getDecks = function (callback) {
const decks = [];
asyncLib.auto({
readDir: (done) => {
fs.readdir(config.deck_path, done);
},
handleDecks: ["readDir", (results, done) => {
handleDecks: [
"readDir",
(results, done) => {
const decks_list = results.readDir;
_async.each(decks_list, async(deck_name) => {
if (_.endsWith(deck_name, ".ydk")) {
asyncLib.each(decks_list, async (deck_name) => {
if (deck_name.endsWith(".ydk")) {
const deck = await readDeck(deck_name, config.deck_path + deck_name);
decks.push(deck);
}
}, done)
}]
}, done);
},
],
}, (err) => {
callback(err, decks);
});
}
};
const delDeck = function (deck_name, callback) {
if (deck_name.startsWith("../") || deck_name.match(/\/\.\.\//)) { //security issue
callback("Invalid deck");
if (deck_name.startsWith("../") || deck_name.match(/\/\.\.\//)) {
//security issue
callback(new Error("Invalid deck"));
}
fs.unlink(config.deck_path + deck_name, callback);
}
};
const clearDecks = function (callback) {
_async.auto({
asyncLib.auto({
deckList: (done) => {
fs.readdir(config.deck_path, done);
},
removeAll: ["deckList", (results, done) => {
removeAll: [
"deckList",
(results, done) => {
const decks_list = results.deckList;
_async.each(decks_list, delDeck, done);
}]
asyncLib.each(decks_list, delDeck, done);
},
],
}, callback);
}
};
const UploadToChallonge = async function () {
if (!challonge_config.enabled) {
sendResponse("未开启Challonge模式。");
......@@ -127,16 +168,10 @@ const UploadToChallonge = async function () {
const player_list = [];
for (const k in decks_list) {
const deck_name = decks_list[k];
if (_.endsWith(deck_name, ".ydk")) {
if (deck_name.endsWith(".ydk")) {
player_list.push({
name: deck_name.slice(0, deck_name.length - 4),
deckbuf: Buffer.from(
YGOProDeckEncode.fromYdkString(
await fs.promises.readFile(config.deck_path + deck_name, { encoding: "ASCII" })
)
.toUpdateDeckPayload()
)
.toString('base64')
deckbuf: Buffer.from(ygopro_deck_encode_1.default.fromYdkString(await fs.promises.readFile(config.deck_path + deck_name, { encoding: "utf-8" })).toUpdateDeckPayload()).toString("base64"),
});
}
}
......@@ -149,85 +184,100 @@ const UploadToChallonge = async function () {
sendResponse("开始清空 Challonge 玩家列表。");
await challonge.clearParticipants();
sendResponse("开始上传玩家列表至 Challonge。");
for (const chunk of _.chunk(player_list, 10)) {
sendResponse(`开始上传玩家 ${chunk.map(c => c.name).join(', ')} 至 Challonge。`);
for (const chunk of underscore_1.default.chunk(player_list, 10)) {
sendResponse(`开始上传玩家 ${chunk.map((c) => c.name).join(", ")} 至 Challonge。`);
await challonge.uploadParticipants(chunk);
}
sendResponse("玩家列表上传完成。");
} catch (e) {
}
catch (e) {
sendResponse("Challonge 上传失败:" + e.message);
}
return true;
}
const receiveDecks = function(files, callback) {
};
const receiveDecks = function (files, callback) {
const result = [];
_async.eachSeries(files, async(file) => {
if (_.endsWith(file.name, ".ydk")) {
asyncLib.eachSeries(files, async (file) => {
if (file.name.endsWith(".ydk")) {
const deck = await readDeck(file.name, file.path);
if (deck.main.length >= 40) {
fs.createReadStream(file.path).pipe(fs.createWriteStream(config.deck_path + file.name));
result.push({
file: file.name,
status: "OK"
status: "OK",
});
}
else {
result.push({
file: file.name,
status: "卡组不合格"
status: "卡组不合格",
});
}
}
else {
result.push({
file: file.name,
status: "不是卡组文件"
status: "不是卡组文件",
});
}
}, (err) => {
callback(err, result);
});
}
};
//建立一个http服务器,接收API操作
async function requestListener(req, res) {
const u = url.parse(req.url, true);
const u = url.parse(req.url || "", true);
// Allow all CORS + PNA (Private Network Access) requests.
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Private-Network", "true");
res.setHeader("Vary", "Origin, Access-Control-Request-Headers, Access-Control-Request-Method");
if ((req.method || "").toLowerCase() === "options") {
const requestHeaders = req.headers["access-control-request-headers"];
res.writeHead(204, {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,POST,OPTIONS",
"Access-Control-Allow-Headers": Array.isArray(requestHeaders)
? requestHeaders.join(", ")
: requestHeaders || "*",
"Access-Control-Allow-Private-Network": "true",
"Access-Control-Max-Age": "86400",
});
res.end();
return;
}
/*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 (!await auth.auth(u.query.username, u.query.password, "deck_dashboard_write", "upload_deck")) {
if (u.pathname === "/api/upload_decks" && (req.method || "").toLowerCase() == "post") {
if (!(await auth.auth(u.query.username, u.query.password, "deck_dashboard_write", "upload_deck"))) {
res.writeHead(403);
res.end("Auth Failed.");
return;
}
const form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
form.parse(req, function (err, fields, files) {
receiveDecks(files, (err, result) => {
if (err) {
console.error(`Upload error: ${err}`);
res.writeHead(500, {
"Access-Control-Allow-origin": "*",
'content-type': 'text/plain'
"content-type": "text/plain",
});
res.end(JSON.stringify({error: err.toString()}));
res.end(JSON.stringify({ error: err.toString() }));
return;
}
res.writeHead(200, {
"Access-Control-Allow-origin": "*",
'content-type': 'text/plain'
"content-type": "text/plain",
});
res.end(JSON.stringify(result));
});
});
}
else if (u.pathname === '/api/msg') {
if (!await auth.auth(u.query.username, u.query.password, "deck_dashboard_read", "login_deck_dashboard")) {
else if (u.pathname === "/api/msg") {
if (!(await auth.auth(u.query.username, u.query.password, "deck_dashboard_read", "login_deck_dashboard"))) {
res.writeHead(403);
res.end("Auth Failed.");
return;
......@@ -236,28 +286,28 @@ async function requestListener(req, res) {
"Access-Control-Allow-origin": "*",
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive"
Connection: "keep-alive",
});
res.on("close", function(){
res.on("close", function () {
responder = null;
});
responder = res;
sendResponse("已连接。");
}
else if (u.pathname === '/api/get_bg') {
if (!await auth.auth(u.query.username, u.query.password, "deck_dashboard_read", "login_deck_dashboard")) {
else if (u.pathname === "/api/get_bg") {
if (!(await 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)])+');');
res.end(u.query.callback +
"(" +
JSON.stringify(config.wallpapers[Math.floor(Math.random() * config.wallpapers.length)]) +
");");
}
else if (u.pathname === '/api/get_decks') {
if (!await auth.auth(u.query.username, u.query.password, "deck_dashboard_read", "get_decks")) {
else if (u.pathname === "/api/get_decks") {
if (!(await auth.auth(u.query.username, u.query.password, "deck_dashboard_read", "get_decks"))) {
res.writeHead(403);
res.end("Auth Failed.");
return;
......@@ -265,15 +315,16 @@ async function requestListener(req, res) {
getDecks((err, decks) => {
if (err) {
res.writeHead(500);
res.end(u.query.callback + '(' + err.toString() +');');
} else {
res.end(u.query.callback + "(" + err.toString() + ");");
}
else {
res.writeHead(200);
res.end(u.query.callback+'('+JSON.stringify(decks)+');');
res.end(u.query.callback + "(" + JSON.stringify(decks) + ");");
}
})
});
}
else if (u.pathname === '/api/del_deck') {
if (!await auth.auth(u.query.username, u.query.password, "deck_dashboard_write", "delete_deck")) {
else if (u.pathname === "/api/del_deck") {
if (!(await auth.auth(u.query.username, u.query.password, "deck_dashboard_write", "delete_deck"))) {
res.writeHead(403);
res.end("Auth Failed.");
return;
......@@ -283,15 +334,16 @@ async function requestListener(req, res) {
let result;
if (err) {
result = "删除卡组 " + u.query.msg + "失败: " + err.toString();
} else {
}
else {
result = "删除卡组 " + u.query.msg + "成功。";
}
res.writeHead(200);
res.end(u.query.callback+'("'+result+'");');
res.end(u.query.callback + '("' + result + '");');
});
}
else if (u.pathname === '/api/clear_decks') {
if (!await auth.auth(u.query.username, u.query.password, "deck_dashboard_write", "clear_decks")) {
else if (u.pathname === "/api/clear_decks") {
if (!(await auth.auth(u.query.username, u.query.password, "deck_dashboard_write", "clear_decks"))) {
res.writeHead(403);
res.end("Auth Failed.");
return;
......@@ -300,38 +352,38 @@ async function requestListener(req, res) {
let result;
if (err) {
result = "删除全部卡组失败。" + err.toString();
} else {
}
else {
result = "删除全部卡组成功。";
}
res.writeHead(200);
res.end(u.query.callback+'("'+result+'");');
res.end(u.query.callback + '("' + result + '");');
});
}
else if (u.pathname === '/api/upload_to_challonge') {
if (!await auth.auth(u.query.username, u.query.password, "deck_dashboard_write", "upload_to_challonge")) {
else if (u.pathname === "/api/upload_to_challonge") {
if (!(await 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);
const result = await UploadToChallonge();
res.end(u.query.callback+'("操作完成。");');
await UploadToChallonge();
res.end(u.query.callback + '("操作完成。");');
}
else {
res.writeHead(400);
res.end("400");
}
}
if (ssl_config.enabled) {
const ssl_cert = fs.readFileSync(ssl_config.cert);
const ssl_key = fs.readFileSync(ssl_config.key);
const options = {
cert: ssl_cert,
key: ssl_key
}
key: ssl_key,
};
https.createServer(options, requestListener).listen(config.port);
} else {
}
else {
http.createServer(requestListener).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