Commit 69402caa authored by nanahira's avatar nanahira

Merge branch 'develop'

parents 46bdd961 0d2b5bb9
Pipeline #38314 passed with stages
in 22 minutes and 12 seconds
lzma = require 'lzma'
fs = require 'fs'
# Deck = require './Deck.js'
class replayHeader
@replayCompressedFlag = 0x1
@replayTagFlag = 0x2
@replayDecodedFlag = 0x4
constructor: ->
@id = 0
@version = 0
@flag = 0
@seed = 0
@dataSizeRaw = []
@hash = 0
@props = []
getDataSize: ->
@dataSizeRaw[0] + @dataSizeRaw[1] * 0x100 + @dataSizeRaw[2] * 0x10000 + @dataSizeRaw[3] * 0x1000000
getIsTag: ->
@flag & replayHeader.replayTagFlag > 0
getIsCompressed: ->
@flag & replayHeader.replayCompressedFlag > 0
getLzmaHeader: ->
bytes = [].concat(@props[0..4], @dataSizeRaw, [0, 0, 0, 0])
Buffer.from(bytes)
Object.defineProperty replayHeader.prototype, 'dataSize', get: @getDataSize
Object.defineProperty replayHeader.prototype, 'isTag', get: @getIsTag
Object.defineProperty replayHeader.prototype, 'isCompressed', get: @getIsCompressed
class ReplayReader
constructor: (buffer) ->
@pointer = 0
@buffer = buffer
readByte: ->
answer = @buffer.readUInt8(@pointer)
@pointer += 1
answer
readByteArray: (length) ->
answer = []
answer.push @readByte() for i in [1..length]
answer
readInt8: ->
answer = @buffer.readInt8(@pointer)
@pointer += 1
answer
readUInt8: ->
answer = @buffer.readUInt8(@pointer)
@pointer += 1
answer
readInt16: ->
answer = @buffer.readInt16LE @pointer
@pointer += 2
answer
readInt32: ->
answer = @buffer.readInt32LE @pointer
@pointer += 4
answer
readAll: ->
answer = @buffer.slice(@pointer)
# @pointer = 0
answer
readString: (length) ->
if @pointer + length > @buffer.length
return null
full = @buffer.slice(@pointer, @pointer + length).toString('utf-16le')
answer = full.split("\u0000")[0]
@pointer += length
answer
readRaw: (length) ->
if @pointer + length > @buffer.length
return null
answer = @buffer.slice(@pointer, @pointer + length)
@pointer += length
answer
class Replay
constructor: ->
@header = null
@hostName = ""
@clientName = ""
@startLp = 0
@startHand = 0
@drawCount = 0
@opt = 0
@hostDeck = null
@clientDeck = null
@tagHostName = null
@tagClientName = null
@tagHostDeck = null
@tagClientDeck = null
@responses = null
getDecks: ->
if @isTag
[@hostDeck, @clientDeck, @tagHostDeck, @tagClientDeck]
else
[@hostDeck, @clientDeck]
getIsTag: ->
@header == null ? false : @header.isTag
@fromFile: (filePath) ->
Replay.fromBuffer await fs.promises.readFile filePath
@fromBuffer: (buffer) ->
reader = new ReplayReader buffer
header = Replay.readHeader reader
restBuffer = reader.readAll()
lzmaBuffer = Buffer.concat [header.getLzmaHeader(), restBuffer]
if header.isCompressed
decompressed = restBuffer
else
decompressed = Buffer.from lzma.decompress lzmaBuffer
reader = new ReplayReader decompressed
replay = Replay.readReplay header, reader
replay
@readHeader: (reader) ->
header = new replayHeader()
header.id = reader.readInt32()
header.version = reader.readInt32()
header.flag = reader.readInt32()
header.seed = reader.readInt32()
header.dataSizeRaw = reader.readByteArray 4
header.hash = reader.readInt32()
header.props = reader.readByteArray 8
header
@readReplay: (header, reader) ->
replay = new Replay()
replay.header = header
replay.hostName = reader.readString(40)
replay.tagHostName = reader.readString(40) if header.isTag
replay.tagClientName = reader.readString(40) if header.isTag
replay.clientName = reader.readString(40)
replay.startLp = reader.readInt32()
replay.startHand = reader.readInt32()
replay.drawCount = reader.readInt32()
replay.opt = reader.readInt32()
replay.hostDeck = Replay.readDeck reader
replay.tagHostDeck = Replay.readDeck reader if header.isTag
replay.tagClientDeck = Replay.readDeck reader if header.isTag
replay.clientDeck = Replay.readDeck reader
replay.responses = Replay.readResponses reader
replay
@readDeck: (reader) ->
deck = {}
deck.main = Replay.readDeckPack reader
deck.ex = Replay.readDeckPack reader
deck
@readDeckPack: (reader) ->
length = reader.readInt32()
answer = []
answer.push reader.readInt32() for i in [1..length]
answer
@readResponses: (reader) ->
answer = []
while true
try
length = reader.readUInt8()
if length > 64
length = 64
single = reader.readRaw(length)
if !single
break
answer.push(single)
catch
break
answer
Object.defineProperty replayHeader.prototype, 'decks', get: @getDecks
Object.defineProperty replayHeader.prototype, 'isTag', get: @getIsTag
module.exports = Replay
// Generated by CoffeeScript 2.7.0 "use strict";
(function() { var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
var Replay, ReplayReader, fs, lzma, replayHeader; if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
lzma = require('lzma'); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
fs = require('fs'); }
Object.defineProperty(o, k2, desc);
replayHeader = (function() { }) : (function(o, m, k, k2) {
// Deck = require './Deck.js' if (k2 === undefined) k2 = k;
class replayHeader { 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;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Replay = exports.ReplayHeader = exports.REPLAY_ID_YRP2 = exports.REPLAY_ID_YRP1 = exports.SEED_COUNT = void 0;
const fs = __importStar(require("fs"));
const lzma = __importStar(require("lzma"));
exports.SEED_COUNT = 8;
exports.REPLAY_ID_YRP1 = 0x31707279;
exports.REPLAY_ID_YRP2 = 0x32707279;
/**
* Metadata stored at the beginning of every replay file.
*/
class ReplayHeader {
constructor() { constructor() {
this.id = 0; this.id = 0;
this.version = 0; this.version = 0;
...@@ -17,136 +51,154 @@ ...@@ -17,136 +51,154 @@
this.dataSizeRaw = []; this.dataSizeRaw = [];
this.hash = 0; this.hash = 0;
this.props = []; this.props = [];
this.seedSequence = [];
this.headerVersion = 0;
this.value1 = 0;
this.value2 = 0;
this.value3 = 0;
} }
/** Decompressed size as little‑endian 32‑bit */
getDataSize() { get dataSize() {
return this.dataSizeRaw[0] + this.dataSizeRaw[1] * 0x100 + this.dataSizeRaw[2] * 0x10000 + this.dataSizeRaw[3] * 0x1000000; return Buffer.from(this.dataSizeRaw).readUInt32LE(0);
} }
get isTag() {
getIsTag() { return (this.flag & ReplayHeader.REPLAY_TAG_FLAG) !== 0;
return this.flag & replayHeader.replayTagFlag > 0;
} }
get isCompressed() {
getIsCompressed() { return (this.flag & ReplayHeader.REPLAY_COMPRESSED_FLAG) !== 0;
return this.flag & replayHeader.replayCompressedFlag > 0;
} }
/** Compose a valid 13‑byte LZMA header for this replay */
getLzmaHeader() { getLzmaHeader() {
var bytes; const bytes = [
bytes = [].concat(this.props.slice(0, 5), this.dataSizeRaw, [0, 0, 0, 0]); ...this.props.slice(0, 5),
...this.dataSizeRaw,
0,
0,
0,
0,
];
return Buffer.from(bytes); return Buffer.from(bytes);
} }
}
}; exports.ReplayHeader = ReplayHeader;
ReplayHeader.REPLAY_COMPRESSED_FLAG = 0x1;
replayHeader.replayCompressedFlag = 0x1; ReplayHeader.REPLAY_TAG_FLAG = 0x2;
ReplayHeader.REPLAY_DECODED_FLAG = 0x4;
replayHeader.replayTagFlag = 0x2; ReplayHeader.REPLAY_SINGLE_MODE = 0x8;
ReplayHeader.REPLAY_UNIFORM = 0x10;
replayHeader.replayDecodedFlag = 0x4; /** Utility for reading little‑endian primitives from a Buffer */
class ReplayReader {
Object.defineProperty(replayHeader.prototype, 'dataSize', {
get: replayHeader.getDataSize
});
Object.defineProperty(replayHeader.prototype, 'isTag', {
get: replayHeader.getIsTag
});
Object.defineProperty(replayHeader.prototype, 'isCompressed', {
get: replayHeader.getIsCompressed
});
return replayHeader;
}).call(this);
ReplayReader = class ReplayReader {
constructor(buffer) { constructor(buffer) {
this.pointer = 0;
this.buffer = buffer; this.buffer = buffer;
this.pointer = 0;
}
advance(size, read) {
const value = read();
this.pointer += size;
return value;
} }
readByte() { readByte() {
var answer; return this.advance(1, () => this.buffer.readUInt8(this.pointer));
answer = this.buffer.readUInt8(this.pointer);
this.pointer += 1;
return answer;
} }
readByteArray(length) { readByteArray(length) {
var answer, i, j, ref; const out = [];
answer = []; for (let i = 0; i < length; i++)
for (i = j = 1, ref = length; (1 <= ref ? j <= ref : j >= ref); i = 1 <= ref ? ++j : --j) { out.push(this.readByte());
answer.push(this.readByte()); return out;
}
return answer;
} }
readInt8() { readInt8() {
var answer; return this.advance(1, () => this.buffer.readInt8(this.pointer));
answer = this.buffer.readInt8(this.pointer);
this.pointer += 1;
return answer;
} }
readUInt8() { readUInt8() {
var answer; return this.advance(1, () => this.buffer.readUInt8(this.pointer));
answer = this.buffer.readUInt8(this.pointer);
this.pointer += 1;
return answer;
} }
readInt16() { readInt16() {
var answer; return this.advance(2, () => this.buffer.readInt16LE(this.pointer));
answer = this.buffer.readInt16LE(this.pointer);
this.pointer += 2;
return answer;
} }
readInt32() { readInt32() {
var answer; return this.advance(4, () => this.buffer.readInt32LE(this.pointer));
answer = this.buffer.readInt32LE(this.pointer); }
this.pointer += 4; readUInt16() {
return answer; return this.advance(2, () => this.buffer.readUInt16LE(this.pointer));
}
readUInt32() {
return this.advance(4, () => this.buffer.readUInt32LE(this.pointer));
} }
readAll() { readAll() {
var answer; return this.buffer.slice(this.pointer);
answer = this.buffer.slice(this.pointer);
// @pointer = 0
return answer;
} }
readString(length) { readString(length) {
var answer, full; if (this.pointer + length > this.buffer.length)
if (this.pointer + length > this.buffer.length) {
return null; return null;
} const raw = this.buffer
full = this.buffer.slice(this.pointer, this.pointer + length).toString('utf-16le'); .slice(this.pointer, this.pointer + length)
answer = full.split("\u0000")[0]; .toString('utf16le');
this.pointer += length; this.pointer += length;
return answer; return raw.split('\u0000')[0];
} }
readRaw(length) { readRaw(length) {
var answer; if (this.pointer + length > this.buffer.length)
if (this.pointer + length > this.buffer.length) {
return null; return null;
} const buf = this.buffer.slice(this.pointer, this.pointer + length);
answer = this.buffer.slice(this.pointer, this.pointer + length);
this.pointer += length; this.pointer += length;
return answer; return buf;
} }
}
}; /** Utility for writing little‑endian primitives into a Buffer */
class ReplayWriter {
Replay = (function() { constructor(buffer) {
class Replay { this.buffer = buffer;
this.pointer = 0;
}
advance(action, size) {
action();
this.pointer += size;
}
writeByte(val) {
this.advance(() => this.buffer.writeUInt8(val, this.pointer), 1);
}
writeByteArray(values) {
for (const v of values)
this.writeByte(v);
}
writeInt8(val) {
this.advance(() => this.buffer.writeInt8(val, this.pointer), 1);
}
writeUInt8(val) {
this.advance(() => this.buffer.writeUInt8(val, this.pointer), 1);
}
writeInt16(val) {
this.advance(() => this.buffer.writeInt16LE(val, this.pointer), 2);
}
writeInt32(val) {
this.advance(() => this.buffer.writeInt32LE(val, this.pointer), 4);
}
writeUInt16(val) {
this.advance(() => this.buffer.writeUInt16LE(val, this.pointer), 2);
}
writeUInt32(val) {
this.advance(() => this.buffer.writeUInt32LE(val, this.pointer), 4);
}
writeAll(buf) {
this.buffer = Buffer.concat([this.buffer, buf]);
}
writeString(val, length) {
const raw = Buffer.from(val ?? '', 'utf16le');
const bytes = [...raw];
if (length !== undefined) {
const padding = new Array(Math.max(length - bytes.length, 0)).fill(0);
this.writeByteArray([...bytes, ...padding]);
}
else {
this.writeByteArray(bytes);
}
}
}
class Replay {
constructor() { constructor() {
this.header = null; this.header = null;
this.hostName = ""; this.hostName = '';
this.clientName = ""; this.clientName = '';
this.startLp = 0; this.startLp = 0;
this.startHand = 0; this.startHand = 0;
this.drawCount = 0; this.drawCount = 0;
...@@ -157,138 +209,197 @@ ...@@ -157,138 +209,197 @@
this.tagClientName = null; this.tagClientName = null;
this.tagHostDeck = null; this.tagHostDeck = null;
this.tagClientDeck = null; this.tagClientDeck = null;
this.responses = null; this.responses = [];
} }
/** All deck objects in play order */
getDecks() { get decks() {
if (this.isTag) { return this.isTag
return [this.hostDeck, this.clientDeck, this.tagHostDeck, this.tagClientDeck]; ? [
} else { this.hostDeck,
return [this.hostDeck, this.clientDeck]; this.clientDeck,
} this.tagHostDeck,
} this.tagClientDeck,
]
getIsTag() { : [this.hostDeck, this.clientDeck];
var ref; }
return (ref = this.header === null) != null ? ref : { get isTag() {
false: this.header.isTag return this.header?.isTag ?? false;
}; }
} /* ------------------ Static helpers ------------------ */
static async fromFile(path) {
static async fromFile(filePath) { return Replay.fromBuffer(await fs.promises.readFile(path));
return Replay.fromBuffer((await fs.promises.readFile(filePath)));
} }
static fromBuffer(buffer) { static fromBuffer(buffer) {
var decompressed, header, lzmaBuffer, reader, replay, restBuffer; const headerReader = new ReplayReader(buffer);
reader = new ReplayReader(buffer); const header = Replay.readHeader(headerReader);
header = Replay.readHeader(reader); const raw = headerReader.readAll();
restBuffer = reader.readAll(); const body = header.isCompressed
lzmaBuffer = Buffer.concat([header.getLzmaHeader(), restBuffer]); ? Replay.decompressBody(header, raw)
if (header.isCompressed) { : raw;
decompressed = restBuffer; const bodyReader = new ReplayReader(body);
} else { return Replay.readReplay(header, bodyReader);
decompressed = Buffer.from(lzma.decompress(lzmaBuffer)); }
} static decompressBody(header, raw) {
reader = new ReplayReader(decompressed); const lzmaBuffer = Buffer.concat([header.getLzmaHeader(), raw]);
replay = Replay.readReplay(header, reader); // lzma‑native provides synchronous helpers.
return replay; return Buffer.from(lzma.decompress(lzmaBuffer));
} }
static readHeader(reader) { static readHeader(reader) {
var header; const h = new ReplayHeader();
header = new replayHeader(); h.id = reader.readUInt32();
header.id = reader.readInt32(); h.version = reader.readUInt32();
header.version = reader.readInt32(); h.flag = reader.readUInt32();
header.flag = reader.readInt32(); h.seed = reader.readUInt32();
header.seed = reader.readInt32(); h.dataSizeRaw = reader.readByteArray(4);
header.dataSizeRaw = reader.readByteArray(4); h.hash = reader.readUInt32();
header.hash = reader.readInt32(); h.props = reader.readByteArray(8);
header.props = reader.readByteArray(8); if (h.id === exports.REPLAY_ID_YRP2) {
return header; for (let i = 0; i < exports.SEED_COUNT; i++) {
} h.seedSequence.push(reader.readUInt32());
}
static readReplay(header, reader) { h.headerVersion = reader.readUInt32();
var replay; h.value1 = reader.readUInt32();
replay = new Replay(); h.value2 = reader.readUInt32();
replay.header = header; h.value3 = reader.readUInt32();
replay.hostName = reader.readString(40); }
if (header.isTag) { return h;
replay.tagHostName = reader.readString(40);
} }
static readReplay(header, reader) {
const r = new Replay();
r.header = header;
r.hostName = reader.readString(40) ?? '';
if (header.isTag) { if (header.isTag) {
replay.tagClientName = reader.readString(40); r.tagHostName = reader.readString(40);
} r.tagClientName = reader.readString(40);
replay.clientName = reader.readString(40); }
replay.startLp = reader.readInt32(); r.clientName = reader.readString(40) ?? '';
replay.startHand = reader.readInt32(); r.startLp = reader.readInt32();
replay.drawCount = reader.readInt32(); r.startHand = reader.readInt32();
replay.opt = reader.readInt32(); r.drawCount = reader.readInt32();
replay.hostDeck = Replay.readDeck(reader); r.opt = reader.readInt32();
if (header.isTag) { r.hostDeck = Replay.readDeck(reader);
replay.tagHostDeck = Replay.readDeck(reader);
}
if (header.isTag) { if (header.isTag) {
replay.tagClientDeck = Replay.readDeck(reader); r.tagHostDeck = Replay.readDeck(reader);
r.tagClientDeck = Replay.readDeck(reader);
} }
replay.clientDeck = Replay.readDeck(reader); r.clientDeck = Replay.readDeck(reader);
replay.responses = Replay.readResponses(reader); r.responses = Replay.readResponses(reader);
return replay; return r;
} }
/* ------------------ Deck helpers ------------------ */
static readDeck(reader) { static readDeck(reader) {
var deck; return {
deck = {}; main: Replay.readDeckPack(reader),
deck.main = Replay.readDeckPack(reader); ex: Replay.readDeckPack(reader),
deck.ex = Replay.readDeckPack(reader); };
return deck;
} }
static readDeckPack(reader) { static readDeckPack(reader) {
var answer, i, j, length, ref; const length = reader.readInt32();
length = reader.readInt32(); const cards = [];
answer = []; for (let i = 0; i < length; i++)
for (i = j = 1, ref = length; (1 <= ref ? j <= ref : j >= ref); i = 1 <= ref ? ++j : --j) { cards.push(reader.readInt32());
answer.push(reader.readInt32()); return cards;
}
return answer;
} }
/* ------------------ Response helpers ------------------ */
static readResponses(reader) { static readResponses(reader) {
var answer, length, single; const out = [];
answer = [];
while (true) { while (true) {
try { try {
length = reader.readUInt8(); let length = reader.readUInt8();
if (length > 64) { if (length > 64)
length = 64; length = 64;
} const segment = reader.readRaw(length);
single = reader.readRaw(length); if (!segment)
if (!single) {
break; break;
out.push(segment);
} }
answer.push(single); catch {
} catch (error) {
break; break;
} }
} }
return answer; return out;
} }
/* ------------------ Writing ------------------ */
}; toBuffer() {
if (!this.header)
Object.defineProperty(replayHeader.prototype, 'decks', { throw new Error('Header not initialised');
get: Replay.getDecks const headerWriter = new ReplayWriter(Buffer.alloc(32));
}); this.writeHeader(headerWriter);
const deckSize = (d) => ((d?.main.length ?? 0) + (d?.ex.length ?? 0)) * 4 + 8;
Object.defineProperty(replayHeader.prototype, 'isTag', { const responseSize = this.responses.reduce((s, b) => s + b.length + 1, 0);
get: Replay.getIsTag let contentSize = 96 + deckSize(this.hostDeck) + deckSize(this.clientDeck) + responseSize;
}); if (this.header.isTag) {
contentSize +=
return Replay; deckSize(this.tagHostDeck) + deckSize(this.tagClientDeck) + 80;
}
}).call(this); const contentWriter = new ReplayWriter(Buffer.alloc(contentSize));
this.writeContent(contentWriter);
module.exports = Replay; let body = contentWriter.buffer;
if (this.header.isCompressed) {
}).call(this); body = Buffer.from(lzma.compress(body));
body = body.slice(13); // strip header like original implementation
}
return Buffer.concat([headerWriter.buffer, body]);
}
async writeToFile(path) {
await fs.promises.writeFile(path, this.toBuffer());
}
writeHeader(w) {
w.writeUInt32(this.header.id);
w.writeUInt32(this.header.version);
w.writeUInt32(this.header.flag);
w.writeUInt32(this.header.seed);
w.writeByteArray(this.header.dataSizeRaw);
w.writeUInt32(this.header.hash);
w.writeByteArray(this.header.props);
if (this.header.id === exports.REPLAY_ID_YRP2) {
for (let i = 0; i < exports.SEED_COUNT; i++) {
w.writeUInt32(this.header.seedSequence[i]);
}
w.writeUInt32(this.header.headerVersion);
w.writeUInt32(this.header.value1);
w.writeUInt32(this.header.value2);
w.writeUInt32(this.header.value3);
}
}
writeContent(w) {
w.writeString(this.hostName, 40);
if (this.header.isTag) {
w.writeString(this.tagHostName, 40);
w.writeString(this.tagClientName, 40);
}
w.writeString(this.clientName, 40);
w.writeInt32(this.startLp);
w.writeInt32(this.startHand);
w.writeInt32(this.drawCount);
w.writeInt32(this.opt);
Replay.writeDeck(w, this.hostDeck);
if (this.header.isTag) {
Replay.writeDeck(w, this.tagHostDeck);
Replay.writeDeck(w, this.tagClientDeck);
}
Replay.writeDeck(w, this.clientDeck);
Replay.writeResponses(w, this.responses);
}
static writeDeck(w, d) {
if (!d) {
w.writeInt32(0);
w.writeInt32(0);
return;
}
Replay.writeDeckPack(w, d.main);
Replay.writeDeckPack(w, d.ex);
}
static writeDeckPack(w, pack) {
w.writeInt32(pack.length);
for (const card of pack)
w.writeInt32(card);
}
static writeResponses(w, res) {
for (const buf of res) {
w.writeUInt8(buf.length);
w.writeByteArray(buf);
}
}
}
exports.Replay = Replay;
import * as fs from 'fs';
import * as lzma from 'lzma';
/** A minimal deck representation */
export interface DeckObject {
main: number[];
ex: number[];
}
export const SEED_COUNT = 8;
export const REPLAY_ID_YRP1 = 0x31707279;
export const REPLAY_ID_YRP2 = 0x32707279;
/**
* Metadata stored at the beginning of every replay file.
*/
export class ReplayHeader {
static readonly REPLAY_COMPRESSED_FLAG = 0x1;
static readonly REPLAY_TAG_FLAG = 0x2;
static readonly REPLAY_DECODED_FLAG = 0x4;
static readonly REPLAY_SINGLE_MODE = 0x8;
static readonly REPLAY_UNIFORM = 0x10;
id = 0;
version = 0;
flag = 0;
seed = 0;
dataSizeRaw: number[] = [];
hash = 0;
props: number[] = [];
seedSequence: number[] = [];
headerVersion = 0;
value1 = 0;
value2 = 0;
value3 = 0;
/** Decompressed size as little‑endian 32‑bit */
get dataSize(): number {
return Buffer.from(this.dataSizeRaw).readUInt32LE(0);
}
get isTag(): boolean {
return (this.flag & ReplayHeader.REPLAY_TAG_FLAG) !== 0;
}
get isCompressed(): boolean {
return (this.flag & ReplayHeader.REPLAY_COMPRESSED_FLAG) !== 0;
}
/** Compose a valid 13‑byte LZMA header for this replay */
getLzmaHeader(): Buffer {
const bytes = [
...this.props.slice(0, 5),
...this.dataSizeRaw,
0,
0,
0,
0,
];
return Buffer.from(bytes);
}
}
/** Utility for reading little‑endian primitives from a Buffer */
class ReplayReader {
private pointer = 0;
constructor(private readonly buffer: Buffer) {}
private advance<T>(size: number, read: () => T): T {
const value = read();
this.pointer += size;
return value;
}
readByte(): number {
return this.advance(1, () => this.buffer.readUInt8(this.pointer));
}
readByteArray(length: number): number[] {
const out: number[] = [];
for (let i = 0; i < length; i++) out.push(this.readByte());
return out;
}
readInt8(): number {
return this.advance(1, () => this.buffer.readInt8(this.pointer));
}
readUInt8(): number {
return this.advance(1, () => this.buffer.readUInt8(this.pointer));
}
readInt16(): number {
return this.advance(2, () => this.buffer.readInt16LE(this.pointer));
}
readInt32(): number {
return this.advance(4, () => this.buffer.readInt32LE(this.pointer));
}
readUInt16(): number {
return this.advance(2, () => this.buffer.readUInt16LE(this.pointer));
}
readUInt32(): number {
return this.advance(4, () => this.buffer.readUInt32LE(this.pointer));
}
readAll(): Buffer {
return this.buffer.slice(this.pointer);
}
readString(length: number): string | null {
if (this.pointer + length > this.buffer.length) return null;
const raw = this.buffer
.slice(this.pointer, this.pointer + length)
.toString('utf16le');
this.pointer += length;
return raw.split('\u0000')[0];
}
readRaw(length: number): Buffer | null {
if (this.pointer + length > this.buffer.length) return null;
const buf = this.buffer.slice(this.pointer, this.pointer + length);
this.pointer += length;
return buf;
}
}
/** Utility for writing little‑endian primitives into a Buffer */
class ReplayWriter {
private pointer = 0;
constructor(public buffer: Buffer) {}
private advance(action: () => void, size: number): void {
action();
this.pointer += size;
}
writeByte(val: number): void {
this.advance(() => this.buffer.writeUInt8(val, this.pointer), 1);
}
writeByteArray(values: Iterable<number>): void {
for (const v of values) this.writeByte(v);
}
writeInt8(val: number): void {
this.advance(() => this.buffer.writeInt8(val, this.pointer), 1);
}
writeUInt8(val: number): void {
this.advance(() => this.buffer.writeUInt8(val, this.pointer), 1);
}
writeInt16(val: number): void {
this.advance(() => this.buffer.writeInt16LE(val, this.pointer), 2);
}
writeInt32(val: number): void {
this.advance(() => this.buffer.writeInt32LE(val, this.pointer), 4);
}
writeUInt16(val: number): void {
this.advance(() => this.buffer.writeUInt16LE(val, this.pointer), 2);
}
writeUInt32(val: number): void {
this.advance(() => this.buffer.writeUInt32LE(val, this.pointer), 4);
}
writeAll(buf: Buffer): void {
this.buffer = Buffer.concat([this.buffer, buf]);
}
writeString(val: string | null, length?: number): void {
const raw = Buffer.from(val ?? '', 'utf16le');
const bytes = [...raw];
if (length !== undefined) {
const padding = new Array(Math.max(length - bytes.length, 0)).fill(0);
this.writeByteArray([...bytes, ...padding]);
} else {
this.writeByteArray(bytes);
}
}
}
export class Replay {
header: ReplayHeader | null = null;
hostName = '';
clientName = '';
startLp = 0;
startHand = 0;
drawCount = 0;
opt = 0;
hostDeck: DeckObject | null = null;
clientDeck: DeckObject | null = null;
tagHostName: string | null = null;
tagClientName: string | null = null;
tagHostDeck: DeckObject | null = null;
tagClientDeck: DeckObject | null = null;
responses: Buffer[] = [];
/** All deck objects in play order */
get decks(): DeckObject[] {
return this.isTag
? [
this.hostDeck!,
this.clientDeck!,
this.tagHostDeck!,
this.tagClientDeck!,
]
: [this.hostDeck!, this.clientDeck!];
}
get isTag(): boolean {
return this.header?.isTag ?? false;
}
/* ------------------ Static helpers ------------------ */
static async fromFile(path: string): Promise<Replay> {
return Replay.fromBuffer(await fs.promises.readFile(path));
}
static fromBuffer(buffer: Buffer): Replay {
const headerReader = new ReplayReader(buffer);
const header = Replay.readHeader(headerReader);
const raw = headerReader.readAll();
const body = header.isCompressed
? Replay.decompressBody(header, raw)
: raw;
const bodyReader = new ReplayReader(body);
return Replay.readReplay(header, bodyReader);
}
private static decompressBody(header: ReplayHeader, raw: Buffer): Buffer {
const lzmaBuffer = Buffer.concat([header.getLzmaHeader(), raw]);
// lzma‑native provides synchronous helpers.
return Buffer.from(lzma.decompress(lzmaBuffer));
}
private static readHeader(reader: ReplayReader): ReplayHeader {
const h = new ReplayHeader();
h.id = reader.readUInt32();
h.version = reader.readUInt32();
h.flag = reader.readUInt32();
h.seed = reader.readUInt32();
h.dataSizeRaw = reader.readByteArray(4);
h.hash = reader.readUInt32();
h.props = reader.readByteArray(8);
if (h.id === REPLAY_ID_YRP2) {
for(let i = 0; i < SEED_COUNT; i++) {
h.seedSequence.push(reader.readUInt32());
}
h.headerVersion = reader.readUInt32();
h.value1 = reader.readUInt32();
h.value2 = reader.readUInt32();
h.value3 = reader.readUInt32();
}
return h;
}
private static readReplay(header: ReplayHeader, reader: ReplayReader): Replay {
const r = new Replay();
r.header = header;
r.hostName = reader.readString(40) ?? '';
if (header.isTag) {
r.tagHostName = reader.readString(40);
r.tagClientName = reader.readString(40);
}
r.clientName = reader.readString(40) ?? '';
r.startLp = reader.readInt32();
r.startHand = reader.readInt32();
r.drawCount = reader.readInt32();
r.opt = reader.readInt32();
r.hostDeck = Replay.readDeck(reader);
if (header.isTag) {
r.tagHostDeck = Replay.readDeck(reader);
r.tagClientDeck = Replay.readDeck(reader);
}
r.clientDeck = Replay.readDeck(reader);
r.responses = Replay.readResponses(reader);
return r;
}
/* ------------------ Deck helpers ------------------ */
private static readDeck(reader: ReplayReader): DeckObject {
return {
main: Replay.readDeckPack(reader),
ex: Replay.readDeckPack(reader),
};
}
private static readDeckPack(reader: ReplayReader): number[] {
const length = reader.readInt32();
const cards: number[] = [];
for (let i = 0; i < length; i++) cards.push(reader.readInt32());
return cards;
}
/* ------------------ Response helpers ------------------ */
private static readResponses(reader: ReplayReader): Buffer[] {
const out: Buffer[] = [];
while (true) {
try {
let length = reader.readUInt8();
if (length > 64) length = 64;
const segment = reader.readRaw(length);
if (!segment) break;
out.push(segment);
} catch {
break;
}
}
return out;
}
/* ------------------ Writing ------------------ */
toBuffer(): Buffer {
if (!this.header) throw new Error('Header not initialised');
const headerWriter = new ReplayWriter(Buffer.alloc(32));
this.writeHeader(headerWriter);
const deckSize = (d: DeckObject | null) =>
((d?.main.length ?? 0) + (d?.ex.length ?? 0)) * 4 + 8;
const responseSize = this.responses.reduce((s, b) => s + b.length + 1, 0);
let contentSize =
96 + deckSize(this.hostDeck) + deckSize(this.clientDeck) + responseSize;
if (this.header.isTag) {
contentSize +=
deckSize(this.tagHostDeck) + deckSize(this.tagClientDeck) + 80;
}
const contentWriter = new ReplayWriter(Buffer.alloc(contentSize));
this.writeContent(contentWriter);
let body = contentWriter.buffer;
if (this.header.isCompressed) {
body = Buffer.from(lzma.compress(body));
body = body.slice(13); // strip header like original implementation
}
return Buffer.concat([headerWriter.buffer, body]);
}
async writeToFile(path: string): Promise<void> {
await fs.promises.writeFile(path, this.toBuffer());
}
private writeHeader(w: ReplayWriter): void {
w.writeUInt32(this.header!.id);
w.writeUInt32(this.header!.version);
w.writeUInt32(this.header!.flag);
w.writeUInt32(this.header!.seed);
w.writeByteArray(this.header!.dataSizeRaw);
w.writeUInt32(this.header!.hash);
w.writeByteArray(this.header!.props);
if (this.header!.id === REPLAY_ID_YRP2) {
for (let i = 0; i < SEED_COUNT; i++) {
w.writeUInt32(this.header!.seedSequence[i]);
}
w.writeUInt32(this.header!.headerVersion);
w.writeUInt32(this.header!.value1);
w.writeUInt32(this.header!.value2);
w.writeUInt32(this.header!.value3);
}
}
private writeContent(w: ReplayWriter): void {
w.writeString(this.hostName, 40);
if (this.header!.isTag) {
w.writeString(this.tagHostName, 40);
w.writeString(this.tagClientName, 40);
}
w.writeString(this.clientName, 40);
w.writeInt32(this.startLp);
w.writeInt32(this.startHand);
w.writeInt32(this.drawCount);
w.writeInt32(this.opt);
Replay.writeDeck(w, this.hostDeck);
if (this.header!.isTag) {
Replay.writeDeck(w, this.tagHostDeck);
Replay.writeDeck(w, this.tagClientDeck);
}
Replay.writeDeck(w, this.clientDeck);
Replay.writeResponses(w, this.responses);
}
private static writeDeck(w: ReplayWriter, d: DeckObject | null): void {
if (!d) {
w.writeInt32(0);
w.writeInt32(0);
return;
}
Replay.writeDeckPack(w, d.main);
Replay.writeDeckPack(w, d.ex);
}
private static writeDeckPack(w: ReplayWriter, pack: number[]): void {
w.writeInt32(pack.length);
for (const card of pack) w.writeInt32(card);
}
private static writeResponses(w: ReplayWriter, res: Buffer[]): void {
for (const buf of res) {
w.writeUInt8(buf.length);
w.writeByteArray(buf);
}
}
}
...@@ -17,7 +17,7 @@ class Handler { ...@@ -17,7 +17,7 @@ class Handler {
} }
async handle(buffer, info, datas, params) { async handle(buffer, info, datas, params) {
if (this.synchronous) { if (this.synchronous) {
return !!(await this.handler(buffer, info, datas, params)); return await this.handler(buffer, info, datas, params);
} }
else { else {
const newBuffer = Buffer.from(buffer); const newBuffer = Buffer.from(buffer);
...@@ -183,7 +183,7 @@ class YGOProMessagesHelper { ...@@ -183,7 +183,7 @@ class YGOProMessagesHelper {
let messageLength = 0; let messageLength = 0;
let bufferProto = 0; let bufferProto = 0;
let datas = []; let datas = [];
const limit = preconnect ? 2 : this.singleHandleLimit; const limit = preconnect ? protoFilter.length * 3 : this.singleHandleLimit;
for (let l = 0; l < limit; ++l) { for (let l = 0; l < limit; ++l) {
if (messageLength === 0) { if (messageLength === 0) {
if (messageBuffer.length >= 2) { if (messageBuffer.length >= 2) {
...@@ -223,7 +223,9 @@ class YGOProMessagesHelper { ...@@ -223,7 +223,9 @@ class YGOProMessagesHelper {
break; break;
} }
let buffer = messageBuffer.slice(3, 2 + messageLength); let buffer = messageBuffer.slice(3, 2 + messageLength);
let bufferMutated = false;
//console.log(l, direction, proto, cancel); //console.log(l, direction, proto, cancel);
let shrinkCount = 0;
for (let priority = 0; priority < 4; ++priority) { for (let priority = 0; priority < 4; ++priority) {
if (cancel) { if (cancel) {
break; break;
...@@ -231,28 +233,53 @@ class YGOProMessagesHelper { ...@@ -231,28 +233,53 @@ class YGOProMessagesHelper {
const handlerCollection = this.handlers[direction][priority]; const handlerCollection = this.handlers[direction][priority];
if (proto && handlerCollection.has(bufferProto)) { if (proto && handlerCollection.has(bufferProto)) {
let struct = this.structs.get(this.proto_structs[direction][proto]); let struct = this.structs.get(this.proto_structs[direction][proto]);
for (const handler of handlerCollection.get(bufferProto)) {
let info = null; let info = null;
if (struct) { if (struct) {
struct._setBuff(buffer); struct._setBuff(buffer);
info = underscore_1.default.clone(struct.fields); info = underscore_1.default.clone(struct.fields);
} }
for (let handler of handlerCollection.get(bufferProto)) {
cancel = await handler.handle(buffer, info, datas, params); cancel = await handler.handle(buffer, info, datas, params);
if (cancel) { if (cancel) {
if (Buffer.isBuffer(cancel)) {
buffer = cancel;
bufferMutated = true;
cancel = false;
}
else if (typeof cancel === "string") {
if (cancel === '_cancel') { if (cancel === '_cancel') {
return { return {
datas: [], datas: [],
feedback feedback
}; };
} }
else if (cancel.startsWith('_shrink_')) {
const targetShrinkCount = parseInt(cancel.slice(8));
if (targetShrinkCount > buffer.length) {
cancel = true;
}
else {
buffer = buffer.slice(0, buffer.length - targetShrinkCount);
bufferMutated = true;
cancel = false;
}
}
}
break; break;
} }
} }
} }
} }
if (!cancel) { if (!cancel) {
if (bufferMutated) {
const newLength = buffer.length + 1;
messageBuffer.writeUInt16LE(newLength, 0);
datas.push(Buffer.concat([messageBuffer.slice(0, 3), buffer]));
}
else {
datas.push(messageBuffer.slice(0, 2 + messageLength)); datas.push(messageBuffer.slice(0, 2 + messageLength));
} }
}
messageBuffer = messageBuffer.slice(2 + messageLength); messageBuffer = messageBuffer.slice(2 + messageLength);
messageLength = 0; messageLength = 0;
bufferProto = 0; bufferProto = 0;
...@@ -281,4 +308,3 @@ class YGOProMessagesHelper { ...@@ -281,4 +308,3 @@ class YGOProMessagesHelper {
} }
} }
exports.YGOProMessagesHelper = YGOProMessagesHelper; exports.YGOProMessagesHelper = YGOProMessagesHelper;
//# sourceMappingURL=YGOProMessages.js.map
\ No newline at end of file
...@@ -8,15 +8,15 @@ import net from "net"; ...@@ -8,15 +8,15 @@ import net from "net";
class Handler { class Handler {
private handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean | string>; private handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean | string | Buffer>;
synchronous: boolean; synchronous: boolean;
constructor(handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean | string>, synchronous: boolean) { constructor(handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean | string | Buffer>, synchronous: boolean) {
this.handler = handler; this.handler = handler;
this.synchronous = synchronous || false; this.synchronous = synchronous || false;
} }
async handle(buffer: Buffer, info: any, datas: Buffer[], params: any): Promise<boolean | string> { async handle(buffer: Buffer, info: any, datas: Buffer[], params: any): Promise<boolean | string | Buffer> {
if (this.synchronous) { if (this.synchronous) {
return !!(await this.handler(buffer, info, datas, params)); return await this.handler(buffer, info, datas, params);
} else { } else {
const newBuffer = Buffer.from(buffer); const newBuffer = Buffer.from(buffer);
const newDatas = datas.map(b => Buffer.from(b)); const newDatas = datas.map(b => Buffer.from(b));
...@@ -237,7 +237,7 @@ export class YGOProMessagesHelper { ...@@ -237,7 +237,7 @@ export class YGOProMessagesHelper {
let messageLength = 0; let messageLength = 0;
let bufferProto = 0; let bufferProto = 0;
let datas: Buffer[] = []; let datas: Buffer[] = [];
const limit = preconnect ? 2 : this.singleHandleLimit; const limit = preconnect ? protoFilter.length * 3 : this.singleHandleLimit;
for (let l = 0; l < limit; ++l) { for (let l = 0; l < limit; ++l) {
if (messageLength === 0) { if (messageLength === 0) {
if (messageBuffer.length >= 2) { if (messageBuffer.length >= 2) {
...@@ -264,7 +264,7 @@ export class YGOProMessagesHelper { ...@@ -264,7 +264,7 @@ export class YGOProMessagesHelper {
} else { } else {
if (messageBuffer.length >= 2 + messageLength) { if (messageBuffer.length >= 2 + messageLength) {
const proto = this.constants[direction][bufferProto]; const proto = this.constants[direction][bufferProto];
let cancel: string | boolean = proto && protoFilter && !protoFilter.includes(proto); let cancel: string | boolean | Buffer = proto && protoFilter && !protoFilter.includes(proto);
if (cancel && preconnect) { if (cancel && preconnect) {
feedback = { feedback = {
type: "INVALID_PACKET", type: "INVALID_PACKET",
...@@ -273,7 +273,9 @@ export class YGOProMessagesHelper { ...@@ -273,7 +273,9 @@ export class YGOProMessagesHelper {
break; break;
} }
let buffer = messageBuffer.slice(3, 2 + messageLength); let buffer = messageBuffer.slice(3, 2 + messageLength);
let bufferMutated = false;
//console.log(l, direction, proto, cancel); //console.log(l, direction, proto, cancel);
let shrinkCount = 0;
for (let priority = 0; priority < 4; ++priority) { for (let priority = 0; priority < 4; ++priority) {
if (cancel) { if (cancel) {
break; break;
...@@ -281,19 +283,34 @@ export class YGOProMessagesHelper { ...@@ -281,19 +283,34 @@ export class YGOProMessagesHelper {
const handlerCollection: Map<number, Handler[]> = this.handlers[direction][priority]; const handlerCollection: Map<number, Handler[]> = this.handlers[direction][priority];
if (proto && handlerCollection.has(bufferProto)) { if (proto && handlerCollection.has(bufferProto)) {
let struct = this.structs.get(this.proto_structs[direction][proto]); let struct = this.structs.get(this.proto_structs[direction][proto]);
for (const handler of handlerCollection.get(bufferProto)) {
let info = null; let info = null;
if (struct) { if (struct) {
struct._setBuff(buffer); struct._setBuff(buffer);
info = _.clone(struct.fields); info = _.clone(struct.fields);
} }
for (let handler of handlerCollection.get(bufferProto)) {
cancel = await handler.handle(buffer, info, datas, params); cancel = await handler.handle(buffer, info, datas, params);
if (cancel) { if (cancel) {
if (Buffer.isBuffer(cancel)) {
buffer = cancel as any;
bufferMutated = true;
cancel = false;
} else if (typeof cancel === "string") {
if (cancel === '_cancel') { if (cancel === '_cancel') {
return { return {
datas: [], datas: [],
feedback feedback
} }
} else if (cancel.startsWith('_shrink_')) {
const targetShrinkCount = parseInt(cancel.slice(8));
if (targetShrinkCount > buffer.length) {
cancel = true;
} else {
buffer = buffer.slice(0, buffer.length - targetShrinkCount);
bufferMutated = true;
cancel = false;
}
}
} }
break; break;
} }
...@@ -301,8 +318,14 @@ export class YGOProMessagesHelper { ...@@ -301,8 +318,14 @@ export class YGOProMessagesHelper {
} }
} }
if (!cancel) { if (!cancel) {
if (bufferMutated) {
const newLength = buffer.length + 1;
messageBuffer.writeUInt16LE(newLength, 0);
datas.push(Buffer.concat([messageBuffer.slice(0, 3), buffer]));
} else {
datas.push(messageBuffer.slice(0, 2 + messageLength)); datas.push(messageBuffer.slice(0, 2 + messageLength));
} }
}
messageBuffer = messageBuffer.slice(2 + messageLength); messageBuffer = messageBuffer.slice(2 + messageLength);
messageLength = 0; messageLength = 0;
bufferProto = 0; bufferProto = 0;
......
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientVersionBlocker = void 0;
const aragami_1 = require("aragami");
let ClientVersionBlocker = class ClientVersionBlocker {
};
exports.ClientVersionBlocker = ClientVersionBlocker;
__decorate([
(0, aragami_1.CacheKey)(),
__metadata("design:type", String)
], ClientVersionBlocker.prototype, "clientKey", void 0);
exports.ClientVersionBlocker = ClientVersionBlocker = __decorate([
(0, aragami_1.CacheTTL)(60000)
], ClientVersionBlocker);
import { CacheKey, CacheTTL } from "aragami";
@CacheTTL(60000)
export class ClientVersionBlocker {
@CacheKey()
clientKey: string;
}
...@@ -54,4 +54,3 @@ class AthleticChecker { ...@@ -54,4 +54,3 @@ class AthleticChecker {
} }
} }
exports.AthleticChecker = AthleticChecker; exports.AthleticChecker = AthleticChecker;
//# sourceMappingURL=athletic-check.js.map
\ No newline at end of file
...@@ -96,4 +96,3 @@ class Challonge { ...@@ -96,4 +96,3 @@ class Challonge {
} }
} }
exports.Challonge = Challonge; exports.Challonge = Challonge;
//# sourceMappingURL=challonge.js.map
\ No newline at end of file
...@@ -790,4 +790,3 @@ class DataManager { ...@@ -790,4 +790,3 @@ class DataManager {
} }
} }
exports.DataManager = DataManager; exports.DataManager = DataManager;
//# sourceMappingURL=DataManager.js.map
\ No newline at end of file
...@@ -5,42 +5,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) { ...@@ -5,42 +5,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.encodeDeck = encodeDeck; exports.encodeDeck = encodeDeck;
exports.decodeDeck = decodeDeck; exports.decodeDeck = decodeDeck;
const assert_1 = __importDefault(require("assert")); const ygopro_deck_encode_1 = __importDefault(require("ygopro-deck-encode"));
// deprecated. Use YGOProDeck instead
function encodeDeck(deck) { function encodeDeck(deck) {
deck.main ?? (deck.main = []); const pdeck = new ygopro_deck_encode_1.default();
deck.side ?? (deck.side = []); pdeck.main = deck.main;
let pointer = 0; pdeck.extra = [];
const bufferSize = (2 + deck.main.length + deck.side.length) * 4; pdeck.side = deck.side;
const buffer = Buffer.allocUnsafe(bufferSize); return Buffer.from(pdeck.toUpdateDeckPayload());
buffer.writeInt32LE(deck.main.length, pointer);
pointer += 4;
buffer.writeInt32LE(deck.side.length, pointer);
pointer += 4;
for (let cardCode of deck.main.concat(deck.side)) {
buffer.writeInt32LE(cardCode, pointer);
pointer += 4;
}
(0, assert_1.default)(pointer === bufferSize, `Invalid buffer size. Expected: ${bufferSize}. Got: ${pointer}`);
return buffer;
} }
function decodeDeck(buffer) { function decodeDeck(buffer) {
let pointer = 0; return ygopro_deck_encode_1.default.fromUpdateDeckPayload(buffer);
const mainLength = buffer.readInt32LE(pointer);
pointer += 4;
const sideLength = buffer.readInt32LE(pointer);
pointer += 4;
const correctBufferLength = (2 + mainLength + sideLength) * 4;
(0, assert_1.default)(buffer.length >= (2 + mainLength + sideLength) * 4, `Invalid buffer size. Expected: ${correctBufferLength}. Got: ${buffer.length}`);
const main = [];
const side = [];
for (let i = 0; i < mainLength; ++i) {
main.push(buffer.readInt32LE(pointer));
pointer += 4;
}
for (let i = 0; i < sideLength; ++i) {
side.push(buffer.readInt32LE(pointer));
pointer += 4;
}
return { main, side };
} }
//# sourceMappingURL=DeckEncoder.js.map
\ No newline at end of file
import assert from "assert"; import YGOProDeck from "ygopro-deck-encode";
export interface Deck { export interface Deck {
main: number[]; main: number[];
side: number[]; side: number[];
} }
// deprecated. Use YGOProDeck instead
export function encodeDeck(deck: Deck) { export function encodeDeck(deck: Deck) {
deck.main ??= []; const pdeck = new YGOProDeck();
deck.side ??= []; pdeck.main = deck.main;
let pointer = 0; pdeck.extra = [];
const bufferSize = (2 + deck.main.length + deck.side.length) * 4; pdeck.side = deck.side;
const buffer = Buffer.allocUnsafe(bufferSize); return Buffer.from(pdeck.toUpdateDeckPayload());
buffer.writeInt32LE(deck.main.length, pointer);
pointer += 4;
buffer.writeInt32LE(deck.side.length, pointer);
pointer += 4;
for(let cardCode of deck.main.concat(deck.side)) {
buffer.writeInt32LE(cardCode, pointer);
pointer += 4;
}
assert(pointer === bufferSize, `Invalid buffer size. Expected: ${bufferSize}. Got: ${pointer}`);
return buffer;
} }
export function decodeDeck(buffer: Buffer): Deck { export function decodeDeck(buffer: Buffer): Deck {
let pointer = 0; return YGOProDeck.fromUpdateDeckPayload(buffer);
const mainLength = buffer.readInt32LE(pointer);
pointer += 4;
const sideLength = buffer.readInt32LE(pointer);
pointer += 4;
const correctBufferLength = (2 + mainLength + sideLength) * 4;
assert(buffer.length >= (2 + mainLength + sideLength) * 4, `Invalid buffer size. Expected: ${correctBufferLength}. Got: ${buffer.length}`);
const main: number[] = [];
const side: number[] = [];
for(let i = 0; i < mainLength; ++i) {
main.push(buffer.readInt32LE(pointer));
pointer += 4;
}
for(let i = 0; i < sideLength; ++i) {
side.push(buffer.readInt32LE(pointer));
pointer += 4;
}
return {main, side};
} }
...@@ -33,4 +33,3 @@ exports.Ban = Ban = __decorate([ ...@@ -33,4 +33,3 @@ exports.Ban = Ban = __decorate([
(0, typeorm_1.Entity)(), (0, typeorm_1.Entity)(),
(0, typeorm_1.Unique)(["ip", "name"]) (0, typeorm_1.Unique)(["ip", "name"])
], Ban); ], Ban);
//# sourceMappingURL=Ban.js.map
\ No newline at end of file
...@@ -27,4 +27,3 @@ __decorate([ ...@@ -27,4 +27,3 @@ __decorate([
(0, typeorm_1.Column)({ type: "tinyint" }), (0, typeorm_1.Column)({ type: "tinyint" }),
__metadata("design:type", Number) __metadata("design:type", Number)
], BasePlayer.prototype, "pos", void 0); ], BasePlayer.prototype, "pos", void 0);
//# sourceMappingURL=BasePlayer.js.map
\ No newline at end of file
...@@ -62,4 +62,3 @@ exports.CloudReplay = CloudReplay = __decorate([ ...@@ -62,4 +62,3 @@ exports.CloudReplay = CloudReplay = __decorate([
} }
}) })
], CloudReplay); ], CloudReplay);
//# sourceMappingURL=CloudReplay.js.map
\ No newline at end of file
...@@ -36,4 +36,3 @@ __decorate([ ...@@ -36,4 +36,3 @@ __decorate([
exports.CloudReplayPlayer = CloudReplayPlayer = CloudReplayPlayer_1 = __decorate([ exports.CloudReplayPlayer = CloudReplayPlayer = CloudReplayPlayer_1 = __decorate([
(0, typeorm_1.Entity)() (0, typeorm_1.Entity)()
], CloudReplayPlayer); ], CloudReplayPlayer);
//# sourceMappingURL=CloudReplayPlayer.js.map
\ No newline at end of file
...@@ -22,4 +22,3 @@ __decorate([ ...@@ -22,4 +22,3 @@ __decorate([
(0, typeorm_1.UpdateDateColumn)(), (0, typeorm_1.UpdateDateColumn)(),
__metadata("design:type", Date) __metadata("design:type", Date)
], CreateAndUpdateTimeBase.prototype, "updateTime", void 0); ], CreateAndUpdateTimeBase.prototype, "updateTime", void 0);
//# sourceMappingURL=CreateAndUpdateTimeBase.js.map
\ No newline at end of file
...@@ -93,4 +93,3 @@ exports.DuelLog = DuelLog = __decorate([ ...@@ -93,4 +93,3 @@ exports.DuelLog = DuelLog = __decorate([
} }
}) })
], DuelLog); ], DuelLog);
//# sourceMappingURL=DuelLog.js.map
\ No newline at end of file
...@@ -98,4 +98,3 @@ __decorate([ ...@@ -98,4 +98,3 @@ __decorate([
exports.DuelLogPlayer = DuelLogPlayer = DuelLogPlayer_1 = __decorate([ exports.DuelLogPlayer = DuelLogPlayer = DuelLogPlayer_1 = __decorate([
(0, typeorm_1.Entity)() (0, typeorm_1.Entity)()
], DuelLogPlayer); ], DuelLogPlayer);
//# sourceMappingURL=DuelLogPlayer.js.map
\ No newline at end of file
...@@ -44,4 +44,3 @@ __decorate([ ...@@ -44,4 +44,3 @@ __decorate([
exports.RandomDuelBan = RandomDuelBan = __decorate([ exports.RandomDuelBan = RandomDuelBan = __decorate([
(0, typeorm_1.Entity)() (0, typeorm_1.Entity)()
], RandomDuelBan); ], RandomDuelBan);
//# sourceMappingURL=RandomDuelBan.js.map
\ No newline at end of file
...@@ -69,4 +69,3 @@ __decorate([ ...@@ -69,4 +69,3 @@ __decorate([
exports.RandomDuelScore = RandomDuelScore = __decorate([ exports.RandomDuelScore = RandomDuelScore = __decorate([
(0, typeorm_1.Entity)() (0, typeorm_1.Entity)()
], RandomDuelScore); ], RandomDuelScore);
//# sourceMappingURL=RandomDuelScore.js.map
\ No newline at end of file
...@@ -56,4 +56,3 @@ __decorate([ ...@@ -56,4 +56,3 @@ __decorate([
exports.User = User = __decorate([ exports.User = User = __decorate([
(0, typeorm_1.Entity)() (0, typeorm_1.Entity)()
], User); ], User);
//# sourceMappingURL=User.js.map
\ No newline at end of file
...@@ -35,4 +35,3 @@ __decorate([ ...@@ -35,4 +35,3 @@ __decorate([
exports.UserDialog = UserDialog = __decorate([ exports.UserDialog = UserDialog = __decorate([
(0, typeorm_1.Entity)() (0, typeorm_1.Entity)()
], UserDialog); ], UserDialog);
//# sourceMappingURL=UserDialog.js.map
\ No newline at end of file
...@@ -44,4 +44,3 @@ __decorate([ ...@@ -44,4 +44,3 @@ __decorate([
exports.VipKey = VipKey = __decorate([ exports.VipKey = VipKey = __decorate([
(0, typeorm_1.Entity)() (0, typeorm_1.Entity)()
], VipKey); ], VipKey);
//# sourceMappingURL=VipKey.js.map
\ No newline at end of file
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
"20": "SURRENDER", "20": "SURRENDER",
"21": "TIME_CONFIRM", "21": "TIME_CONFIRM",
"22": "CHAT", "22": "CHAT",
"23": "EXTERNAL_ADDRESS",
"32": "HS_TODUELIST", "32": "HS_TODUELIST",
"33": "HS_TOOBSERVER", "33": "HS_TOOBSERVER",
"34": "HS_READY", "34": "HS_READY",
......
...@@ -31,6 +31,15 @@ ...@@ -31,6 +31,15 @@
"replay_delay": true, "replay_delay": true,
"hide_name": false, "hide_name": false,
"display_watchers": false, "display_watchers": false,
"trusted_proxies": [
"127.0.0.1/8",
"::1/128"
],
"ygopro_path": "./ygopro",
"ygopro_exec_path": "./ygopro",
"expansions_path": [
"./expansions"
],
"i18n": { "i18n": {
"auto_pick": false, "auto_pick": false,
"default": "zh-cn", "default": "zh-cn",
...@@ -229,10 +238,6 @@ ...@@ -229,10 +238,6 @@
"neos": { "neos": {
"enabled": false, "enabled": false,
"port": 7977, "port": 7977,
"trusted_proxies": [
"127.0.0.1/8",
"::1/128"
],
"ip_header": "x-forwarded-for" "ip_header": "x-forwarded-for"
}, },
"chatgpt": { "chatgpt": {
......
...@@ -210,6 +210,8 @@ ...@@ -210,6 +210,8 @@
"banned_athletic_deck_part1": "Entertainment Mode does not allow top ", "banned_athletic_deck_part1": "Entertainment Mode does not allow top ",
"banned_athletic_deck_part2": " popular meta decks. Please change your deck.", "banned_athletic_deck_part2": " popular meta decks. Please change your deck.",
"chat_disabled": "Chat is disabled in this room.", "chat_disabled": "Chat is disabled in this room.",
"version_to_polyfill": "Your client version is not fully supported. Please rejoin to enable temporary compatibility mode. For the best experience, we recommend updating your game to the latest version.",
"version_polyfilled": "Temporary compatibility mode has been enabled for your version. We recommend updating your game to avoid potential compatibility issues in the future.",
"using_athletic_deck": " is using a competitive deck." "using_athletic_deck": " is using a competitive deck."
}, },
"es-es": { "es-es": {
...@@ -569,6 +571,8 @@ ...@@ -569,6 +571,8 @@
"banned_athletic_deck_part1": "娱乐匹配中禁止使用使用数前", "banned_athletic_deck_part1": "娱乐匹配中禁止使用使用数前",
"banned_athletic_deck_part2": "的竞技卡组。请更换卡组。", "banned_athletic_deck_part2": "的竞技卡组。请更换卡组。",
"chat_disabled": "本房间禁止聊天。", "chat_disabled": "本房间禁止聊天。",
"version_to_polyfill": "当前客户端版本暂未完全支持。请重新加入以启用临时兼容模式。为获得更佳体验,建议尽快更新游戏版本。",
"version_polyfilled": "已为当前版本启用临时兼容模式。建议尽快更新游戏,以避免后续兼容性问题。",
"using_athletic_deck": " 正在使用竞技卡组。" "using_athletic_deck": " 正在使用竞技卡组。"
}, },
"ko-kr": { "ko-kr": {
......
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
"HS_KICK":"CTOS_Kick", "HS_KICK":"CTOS_Kick",
"UPDATE_DECK": "deck", "UPDATE_DECK": "deck",
"CHANGE_SIDE":"", "CHANGE_SIDE":"",
"CHAT": "chat" "CHAT": "chat",
"EXTERNAL_ADDRESS": "CTOS_ExternalAddress"
}, },
"STOC":{ "STOC":{
"JOIN_GAME":"STOC_JoinGame", "JOIN_GAME":"STOC_JoinGame",
......
...@@ -42,6 +42,10 @@ ...@@ -42,6 +42,10 @@
{"name": "gameid", "type": "unsigned int"}, {"name": "gameid", "type": "unsigned int"},
{"name": "pass", "type": "unsigned short", "length": 20, "encoding": "UTF-16LE"} {"name": "pass", "type": "unsigned short", "length": 20, "encoding": "UTF-16LE"}
], ],
"CTOS_ExternalAddress": [
{"name": "real_ip", "type": "unsigned int"},
{"name": "hostname", "type": "unsigned short", "length":"256", "encoding": "UTF-16LE"}
],
"CTOS_Kick": [ "CTOS_Kick": [
{"name": "pos", "type": "unsigned char"} {"name": "pos", "type": "unsigned char"}
], ],
......
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BasePolyfiller = void 0;
class BasePolyfiller {
async polyfillGameMsg(msgTitle, buffer) {
return;
}
async polyfillResponse(msgTitle, buffer) {
return;
}
splice(buf, offset, deleteCount = 1) {
if (offset < 0 || offset >= buf.length)
return Buffer.alloc(0);
deleteCount = Math.min(deleteCount, buf.length - offset);
const end = offset + deleteCount;
const newBuf = Buffer.concat([
buf.slice(0, offset),
buf.slice(end)
]);
return newBuf;
}
insert(buf, offset, insertBuf) {
if (offset < 0)
offset = 0;
if (offset > buf.length)
offset = buf.length;
const newBuf = Buffer.concat([
buf.slice(0, offset),
insertBuf,
buf.slice(offset)
]);
return newBuf;
}
}
exports.BasePolyfiller = BasePolyfiller;
export class BasePolyfiller {
async polyfillGameMsg(msgTitle: string, buffer: Buffer): Promise<Buffer | undefined> {
return;
}
async polyfillResponse(msgTitle: string, buffer: Buffer): Promise<Buffer | undefined> {
return;
}
splice(buf: Buffer, offset: number, deleteCount = 1): Buffer {
if (offset < 0 || offset >= buf.length) return Buffer.alloc(0);
deleteCount = Math.min(deleteCount, buf.length - offset);
const end = offset + deleteCount;
const newBuf = Buffer.concat([
buf.slice(0, offset),
buf.slice(end)
]);
return newBuf;
}
insert(buf: Buffer, offset: number, insertBuf: Buffer): Buffer {
if (offset < 0) offset = 0;
if (offset > buf.length) offset = buf.length;
const newBuf = Buffer.concat([
buf.slice(0, offset),
insertBuf,
buf.slice(offset)
]);
return newBuf;
}
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.polyfillGameMsg = polyfillGameMsg;
exports.polyfillResponse = polyfillResponse;
const registry_1 = require("./registry");
const getPolyfillers = (version) => {
const polyfillers = [];
for (const [pVersion, polyfillerCls] of registry_1.polyfillRegistry.entries()) {
if (version <= pVersion) {
polyfillers.push({ version: pVersion, polyfiller: new polyfillerCls() });
}
}
polyfillers.sort((a, b) => a.version - b.version);
return polyfillers.map(p => p.polyfiller);
};
async function polyfillGameMsg(version, msgTitle, buffer) {
const polyfillers = getPolyfillers(version);
let mutated = false;
for (const polyfiller of polyfillers) {
const newBuf = await polyfiller.polyfillGameMsg(msgTitle, buffer);
if (newBuf) {
mutated = true;
buffer = newBuf;
}
}
return mutated ? buffer : undefined;
}
async function polyfillResponse(version, msgTitle, buffer) {
const polyfillers = getPolyfillers(version);
for (const polyfiller of polyfillers) {
await polyfiller.polyfillResponse(msgTitle, buffer);
}
}
import { BasePolyfiller } from "./base-polyfiller";
import { polyfillRegistry } from "./registry";
const getPolyfillers = (version: number) => {
const polyfillers: {version: number, polyfiller: BasePolyfiller}[] = [];
for (const [pVersion, polyfillerCls] of polyfillRegistry.entries()) {
if (version <= pVersion) {
polyfillers.push({ version: pVersion, polyfiller: new polyfillerCls() });
}
}
polyfillers.sort((a, b) => a.version - b.version);
return polyfillers.map(p => p.polyfiller);
}
export async function polyfillGameMsg(version: number, msgTitle: string, buffer: Buffer) {
const polyfillers = getPolyfillers(version);
let mutated = false;
for (const polyfiller of polyfillers) {
const newBuf = await polyfiller.polyfillGameMsg(msgTitle, buffer);
if (newBuf) {
mutated = true;
buffer = newBuf;
}
}
return mutated ? buffer : undefined;
}
export async function polyfillResponse(version: number, msgTitle: string, buffer: Buffer) {
const polyfillers = getPolyfillers(version);
for (const polyfiller of polyfillers) {
await polyfiller.polyfillResponse(msgTitle, buffer);
}
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Polyfiller1361 = exports.gcd = void 0;
const base_polyfiller_1 = require("../base-polyfiller");
const gcd = (nums) => {
const gcdTwo = (a, b) => {
if (b === 0)
return a;
return gcdTwo(b, a % b);
};
return nums.reduce((acc, num) => gcdTwo(acc, num));
};
exports.gcd = gcd;
class Polyfiller1361 extends base_polyfiller_1.BasePolyfiller {
async polyfillGameMsg(msgTitle, buffer) {
if (msgTitle === 'CONFIRM_CARDS') {
// buf[0]: MSG_CONFIRM_CARDS
// buf[1]: playerid
// buf[2]: ADDED skip_panel
return this.splice(buffer, 2, 1);
}
else if (msgTitle === 'SELECT_CHAIN') {
// buf[0]: MSG_SELECT_CHAIN
// buf[1]: playerid
// buf[2]: size
// buf[3]: spe_count
// buf[REMOVED]: forced
// buf[4-7]: hint_timing player
// buf[8-11]: hint_timing 1-player
// then it's 14 bytes for each item
// item[0]: not related
// item[1]: ADDED forced
// item[2-13] not related
const size = buffer[2];
const itemStartOffset = 12; // after the header (up to hint timings)
// 判断是否存在任何 item 的 forced = 1(在原始 buffer 中判断)
let anyForced = false;
for (let i = 0; i < size; i++) {
const itemOffset = itemStartOffset + i * 14;
const forced = buffer[itemOffset + 1];
if (forced === 1) {
anyForced = true;
break;
}
}
// 从后往前 splice 每个 item 的 forced 字段
for (let i = size - 1; i >= 0; i--) {
const itemOffset = itemStartOffset + i * 14;
buffer = this.splice(buffer, itemOffset + 1, 1); // 删除每个 item 的 forced(第 1 字节)
}
// 最后再插入旧版所需的 forced 标志
return this.insert(buffer, 4, Buffer.from([anyForced ? 1 : 0]));
}
else if (msgTitle === 'SELECT_SUM') {
// buf[0]: MSG_SELECT_SUM
// buf[1]: 0 => equal, 1 => greater
// buf[2]: playerid
// buf[3-6]: target_value
// buf[7]: min
// buf[8]: max
// buf[9]: forced_count
// then each item 11 bytes
// item[0-3] code
// item[4] controler
// item[5] location
// item[6] sequence
// item[7-10] value
// item[10 + forced_count * 11] card_count
// same as above items
const targetValue = buffer.readUInt32LE(3);
const forcedCount = buffer[9];
const cardCount = buffer[10 + forcedCount * 11];
const valueOffsets = [];
for (let i = 0; i < forcedCount; i++) {
const itemOffset = 10 + i * 11;
valueOffsets.push(itemOffset + 7);
}
for (let i = 0; i < cardCount; i++) {
const itemOffset = 11 + forcedCount * 11 + i * 11;
valueOffsets.push(itemOffset + 7);
}
const values = valueOffsets.map(offset => ({
offset,
value: buffer.readUInt32LE(offset),
}));
if (!values.some(v => v.value & 0x80000000)) {
return;
}
const gcds = [targetValue];
for (const { value } of values) {
if (value & 0x80000000) {
gcds.push(value & 0x7FFFFFFF);
}
else {
const op1 = value & 0xffff;
const op2 = (value >>> 16) & 0xffff;
[op1, op2].filter(v => v > 0)
.forEach(v => gcds.push(v));
}
}
const gcdValue = (0, exports.gcd)(gcds);
buffer.writeUInt32LE(targetValue / gcdValue, 3);
for (const trans of values) {
let target = 0;
const { value } = trans;
if (value & 0x80000000) {
target = ((value & 0x7FFFFFFF) / gcdValue) & 0xffff;
}
else {
// shrink op1 and op2
const op1 = value & 0xffff;
const op2 = (value >>> 16) & 0xffff;
target = ((op1 / gcdValue) & 0xffff) | ((((op2 / gcdValue) & 0xffff) << 16) >>> 0);
}
buffer.writeUInt32LE(target, trans.offset);
}
}
return;
}
}
exports.Polyfiller1361 = Polyfiller1361;
import { BasePolyfiller } from "../base-polyfiller";
export const gcd = (nums: number[]) => {
const gcdTwo = (a: number, b: number) => {
if (b === 0) return a;
return gcdTwo(b, a % b);
};
return nums.reduce((acc, num) => gcdTwo(acc, num));
}
export class Polyfiller1361 extends BasePolyfiller {
async polyfillGameMsg(msgTitle: string, buffer: Buffer) {
if (msgTitle === 'CONFIRM_CARDS') {
// buf[0]: MSG_CONFIRM_CARDS
// buf[1]: playerid
// buf[2]: ADDED skip_panel
return this.splice(buffer, 2, 1);
} else if (msgTitle === 'SELECT_CHAIN') {
// buf[0]: MSG_SELECT_CHAIN
// buf[1]: playerid
// buf[2]: size
// buf[3]: spe_count
// buf[REMOVED]: forced
// buf[4-7]: hint_timing player
// buf[8-11]: hint_timing 1-player
// then it's 14 bytes for each item
// item[0]: not related
// item[1]: ADDED forced
// item[2-13] not related
const size = buffer[2];
const itemStartOffset = 12; // after the header (up to hint timings)
// 判断是否存在任何 item 的 forced = 1(在原始 buffer 中判断)
let anyForced = false;
for (let i = 0; i < size; i++) {
const itemOffset = itemStartOffset + i * 14;
const forced = buffer[itemOffset + 1];
if (forced === 1) {
anyForced = true;
break;
}
}
// 从后往前 splice 每个 item 的 forced 字段
for (let i = size - 1; i >= 0; i--) {
const itemOffset = itemStartOffset + i * 14;
buffer = this.splice(buffer, itemOffset + 1, 1); // 删除每个 item 的 forced(第 1 字节)
}
// 最后再插入旧版所需的 forced 标志
return this.insert(buffer, 4, Buffer.from([anyForced ? 1 : 0]));
} else if (msgTitle === 'SELECT_SUM') {
// buf[0]: MSG_SELECT_SUM
// buf[1]: 0 => equal, 1 => greater
// buf[2]: playerid
// buf[3-6]: target_value
// buf[7]: min
// buf[8]: max
// buf[9]: forced_count
// then each item 11 bytes
// item[0-3] code
// item[4] controler
// item[5] location
// item[6] sequence
// item[7-10] value
// item[10 + forced_count * 11] card_count
// same as above items
const targetValue = buffer.readUInt32LE(3);
const forcedCount = buffer[9];
const cardCount = buffer[10 + forcedCount * 11];
const valueOffsets: number[] = [];
for(let i = 0; i < forcedCount; i++) {
const itemOffset = 10 + i * 11;
valueOffsets.push(itemOffset + 7);
}
for(let i = 0; i < cardCount; i++) {
const itemOffset = 11 + forcedCount * 11 + i * 11;
valueOffsets.push(itemOffset + 7);
}
const values = valueOffsets.map(offset => ({
offset,
value: buffer.readUInt32LE(offset),
}));
if (!values.some(v => v.value & 0x80000000)) {
return;
}
const gcds = [targetValue];
for(const { value } of values) {
if (value & 0x80000000) {
gcds.push(value & 0x7FFFFFFF);
} else {
const op1 = value & 0xffff;
const op2 = (value >>> 16) & 0xffff;
[op1, op2].filter(v => v > 0)
.forEach(v => gcds.push(v));
}
}
const gcdValue = gcd(gcds);
buffer.writeUInt32LE(targetValue / gcdValue, 3);
for (const trans of values) {
let target = 0;
const { value } = trans;
if (value & 0x80000000) {
target = ((value & 0x7FFFFFFF) / gcdValue) & 0xffff;
} else {
// shrink op1 and op2
const op1 = value & 0xffff;
const op2 = (value >>> 16) & 0xffff;
target = ((op1 / gcdValue) & 0xffff) | ((((op2 / gcdValue) & 0xffff) << 16) >>> 0);
}
buffer.writeUInt32LE(target, trans.offset);
}
}
return;
}
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.polyfillRegistry = void 0;
const _0x1361_1 = require("./polyfillers/0x1361");
exports.polyfillRegistry = new Map();
const addPolyfiller = (version, polyfiller) => {
exports.polyfillRegistry.set(version, polyfiller);
};
addPolyfiller(0x1361, _0x1361_1.Polyfiller1361);
import { BasePolyfiller } from "./base-polyfiller";
import { Polyfiller1361 } from "./polyfillers/0x1361";
export const polyfillRegistry = new Map<number, typeof BasePolyfiller>();
const addPolyfiller = (version: number, polyfiller: typeof BasePolyfiller) => {
polyfillRegistry.set(version, polyfiller);
}
addPolyfiller(0x1361, Polyfiller1361);
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
"version": "2.3.3", "version": "2.3.3",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {
"aragami": "^1.2.5",
"async": "^3.2.0", "async": "^3.2.0",
"axios": "^0.19.2", "axios": "^0.19.2",
"bunyan": "^1.8.14", "bunyan": "^1.8.14",
...@@ -32,16 +33,18 @@ ...@@ -32,16 +33,18 @@
"typeorm": "^0.2.29", "typeorm": "^0.2.29",
"underscore": "^1.11.0", "underscore": "^1.11.0",
"underscore.string": "^3.3.6", "underscore.string": "^3.3.6",
"ws": "^8.9.0" "ws": "^8.9.0",
"ygopro-deck-encode": "^1.0.9"
}, },
"devDependencies": { "devDependencies": {
"@types/bunyan": "^1.8.8", "@types/bunyan": "^1.8.8",
"@types/ip6addr": "^0.2.3", "@types/ip6addr": "^0.2.3",
"@types/node": "^17.0.19", "@types/lzma": "^2.3.0",
"@types/node": "^16.18.126",
"@types/underscore": "^1.11.4", "@types/underscore": "^1.11.4",
"@types/ws": "^8.5.3", "@types/ws": "^8.5.3",
"coffeescript": "^2.6.1", "coffeescript": "^2.7.0",
"typescript": "^4.5.5" "typescript": "^5.8.3"
} }
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
...@@ -67,6 +70,24 @@ ...@@ -67,6 +70,24 @@
"js-tokens": "^4.0.0" "js-tokens": "^4.0.0"
} }
}, },
"node_modules/@ioredis/commands": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==",
"license": "MIT"
},
"node_modules/@sesamecare-oss/redlock": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@sesamecare-oss/redlock/-/redlock-1.4.0.tgz",
"integrity": "sha512-2z589R+yxKLN4CgKxP1oN4dsg6Y548SE4bVYam/R0kHk7Q9VrQ9l66q+k1ehhSLLY4or9hcchuF9/MhuuZdjJg==",
"license": "UNLICENSED",
"engines": {
"node": ">=16"
},
"peerDependencies": {
"ioredis": ">=5"
}
},
"node_modules/@sqltools/formatter": { "node_modules/@sqltools/formatter": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.2.tgz", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.2.tgz",
...@@ -87,11 +108,22 @@ ...@@ -87,11 +108,22 @@
"integrity": "sha512-oe7hzc+P9DU6+gql8+bLKuUf4WL4aakyCSXZMZq2cjhhGK75qYwH1zJ4s94XOlnb4cAhrGKwnbrmMBaqDK8+Ww==", "integrity": "sha512-oe7hzc+P9DU6+gql8+bLKuUf4WL4aakyCSXZMZq2cjhhGK75qYwH1zJ4s94XOlnb4cAhrGKwnbrmMBaqDK8+Ww==",
"dev": true "dev": true
}, },
"node_modules/@types/lzma": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@types/lzma/-/lzma-2.3.0.tgz",
"integrity": "sha512-z7TknP6ts5GPnN7P2bkZC1B/tMpoMJXG3UnPY1XDrwBq1OJQ2EpHtEypFwq5Q0A5iS37+oc+MT/o/B7x5lgl8Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "17.0.19", "version": "16.18.126",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.19.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz",
"integrity": "sha512-PfeQhvcMR4cPFVuYfBN4ifG7p9c+Dlh3yUZR6k+5yQK7wX3gDgVxBly4/WkBRs9x4dmcy1TVl08SY67wwtEvmA==", "integrity": "sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==",
"dev": true "dev": true,
"license": "MIT"
}, },
"node_modules/@types/underscore": { "node_modules/@types/underscore": {
"version": "1.11.4", "version": "1.11.4",
...@@ -165,6 +197,41 @@ ...@@ -165,6 +197,41 @@
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
}, },
"node_modules/aragami": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/aragami/-/aragami-1.2.5.tgz",
"integrity": "sha512-w+jSXxXYAk3X/TSMoVfc12lY1c40MYqf6W6R2yGE1q7pY4ZC+xpzGBT+Bqa4hO6hlWsM5sFRnKvAE+72HCkT2w==",
"license": "MIT",
"dependencies": {
"@sesamecare-oss/redlock": "^1.4.0",
"better-lock": "^2.0.3",
"class-transformer": "^0.5.1",
"encoded-buffer": "^0.2.6",
"generic-pool": "^3.9.0",
"ioredis": "^5.2.3",
"lodash": "^4.17.21",
"lru-cache": "^7.13.1",
"typed-reflector": "^1.0.11"
}
},
"node_modules/aragami/node_modules/generic-pool": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
"integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==",
"license": "MIT",
"engines": {
"node": ">= 4"
}
},
"node_modules/aragami/node_modules/lru-cache": {
"version": "7.18.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/are-we-there-yet": { "node_modules/are-we-there-yet": {
"version": "1.1.5", "version": "1.1.5",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
...@@ -213,6 +280,21 @@ ...@@ -213,6 +280,21 @@
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
}, },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
"license": "MIT",
"dependencies": {
"possible-typed-array-names": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/aws-sign2": { "node_modules/aws-sign2": {
"version": "0.7.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
...@@ -267,6 +349,12 @@ ...@@ -267,6 +349,12 @@
"tweetnacl": "^0.14.3" "tweetnacl": "^0.14.3"
} }
}, },
"node_modules/better-lock": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/better-lock/-/better-lock-2.0.3.tgz",
"integrity": "sha512-3bCaToLrmEXZcIOOVWgi1STvp3/6EpoZAmlWBeuX2MvDB0Ql2ctl/vQ0CbhQIJYQiptdGypllP3ez+TeEmdnKQ==",
"license": "MIT"
},
"node_modules/bignumber.js": { "node_modules/bignumber.js": {
"version": "9.0.0", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
...@@ -361,6 +449,53 @@ ...@@ -361,6 +449,53 @@
"safe-json-stringify": "~1" "safe-json-stringify": "~1"
} }
}, },
"node_modules/call-bind": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.0",
"es-define-property": "^1.0.0",
"get-intrinsic": "^1.2.4",
"set-function-length": "^1.2.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/call-bound": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/camelcase": { "node_modules/camelcase": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
...@@ -403,6 +538,12 @@ ...@@ -403,6 +538,12 @@
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
}, },
"node_modules/class-transformer": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
"license": "MIT"
},
"node_modules/cli-highlight": { "node_modules/cli-highlight": {
"version": "2.1.4", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.4.tgz", "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.4.tgz",
...@@ -595,6 +736,15 @@ ...@@ -595,6 +736,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/code-point-at": { "node_modules/code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
...@@ -604,10 +754,11 @@ ...@@ -604,10 +754,11 @@
} }
}, },
"node_modules/coffeescript": { "node_modules/coffeescript": {
"version": "2.6.1", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.6.1.tgz", "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.7.0.tgz",
"integrity": "sha512-GG5nkF93qII8HmHqnnibkgpp/SV7PSnSPiWsbinwya7nNOe95aE/x2xrKZJFks8Qpko3TNrC+/LahaKgrz5YCg==", "integrity": "sha512-hzWp6TUE2d/jCcN67LrW1eh5b/rSDKQK6oD6VMLlggYVUUFexgTH9z3dNYihzX4RMhze5FTUsUmOXViJKFQR/A==",
"dev": true, "dev": true,
"license": "MIT",
"bin": { "bin": {
"cake": "bin/cake", "cake": "bin/cake",
"coffee": "bin/coffee" "coffee": "bin/coffee"
...@@ -707,6 +858,23 @@ ...@@ -707,6 +858,23 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delayed-stream": { "node_modules/delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
...@@ -720,6 +888,15 @@ ...@@ -720,6 +888,15 @@
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
}, },
"node_modules/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10"
}
},
"node_modules/detect-libc": { "node_modules/detect-libc": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
...@@ -752,6 +929,20 @@ ...@@ -752,6 +929,20 @@
"node": ">=0.10" "node": ">=0.10"
} }
}, },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/ecc-jsbn": { "node_modules/ecc-jsbn": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
...@@ -766,6 +957,18 @@ ...@@ -766,6 +957,18 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
}, },
"node_modules/encoded-buffer": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/encoded-buffer/-/encoded-buffer-0.2.6.tgz",
"integrity": "sha512-zEskqXs0FbF9HcwZkumyAoiB3NN23yAoJvPmLP0NuWQLXTeCDMeVRYK1kjIsZPkoXE2cIBS0iht95pqf8UKyog==",
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
"license": "MIT",
"dependencies": {
"lodash": "^4.17.10",
"to-buffer": "^1.1.1",
"tslib": "^1.9.3"
}
},
"node_modules/error-ex": { "node_modules/error-ex": {
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
...@@ -774,6 +977,36 @@ ...@@ -774,6 +977,36 @@
"is-arrayish": "^0.2.1" "is-arrayish": "^0.2.1"
} }
}, },
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/escalade": { "node_modules/escalade": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
...@@ -874,6 +1107,21 @@ ...@@ -874,6 +1107,21 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}, },
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
"license": "MIT",
"dependencies": {
"is-callable": "^1.2.7"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/forever-agent": { "node_modules/forever-agent": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
...@@ -942,6 +1190,15 @@ ...@@ -942,6 +1190,15 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gauge": { "node_modules/gauge": {
"version": "2.7.4", "version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
...@@ -1028,6 +1285,43 @@ ...@@ -1028,6 +1285,43 @@
"node": "6.* || 8.* || >= 10.*" "node": "6.* || 8.* || >= 10.*"
} }
}, },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/getpass": { "node_modules/getpass": {
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
...@@ -1051,6 +1345,18 @@ ...@@ -1051,6 +1345,18 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
"version": "1.1.14", "version": "1.1.14",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz",
...@@ -1101,11 +1407,62 @@ ...@@ -1101,11 +1407,62 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/has-property-descriptors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-unicode": { "node_modules/has-unicode": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
}, },
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/highlight.js": { "node_modules/highlight.js": {
"version": "9.18.3", "version": "9.18.3",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.3.tgz", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.3.tgz",
...@@ -1195,6 +1552,53 @@ ...@@ -1195,6 +1552,53 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/ioredis": {
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.6.1.tgz",
"integrity": "sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA==",
"license": "MIT",
"dependencies": {
"@ioredis/commands": "^1.1.1",
"cluster-key-slot": "^1.1.0",
"debug": "^4.3.4",
"denque": "^2.1.0",
"lodash.defaults": "^4.2.0",
"lodash.isarguments": "^3.1.0",
"redis-errors": "^1.2.0",
"redis-parser": "^3.0.0",
"standard-as-callback": "^2.1.0"
},
"engines": {
"node": ">=12.22.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/ioredis"
}
},
"node_modules/ioredis/node_modules/debug": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/ioredis/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/ip6addr": { "node_modules/ip6addr": {
"version": "0.2.5", "version": "0.2.5",
"resolved": "https://registry.npmjs.org/ip6addr/-/ip6addr-0.2.5.tgz", "resolved": "https://registry.npmjs.org/ip6addr/-/ip6addr-0.2.5.tgz",
...@@ -1228,6 +1632,18 @@ ...@@ -1228,6 +1632,18 @@
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
}, },
"node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-fullwidth-code-point": { "node_modules/is-fullwidth-code-point": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
...@@ -1239,6 +1655,21 @@ ...@@ -1239,6 +1655,21 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/is-typed-array": {
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
"license": "MIT",
"dependencies": {
"which-typed-array": "^1.1.16"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-typedarray": { "node_modules/is-typedarray": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
...@@ -1386,6 +1817,24 @@ ...@@ -1386,6 +1817,24 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
},
"node_modules/lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
"license": "MIT"
},
"node_modules/lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
"license": "MIT"
},
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "2.7.3", "version": "2.7.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz",
...@@ -1399,6 +1848,15 @@ ...@@ -1399,6 +1848,15 @@
"lzma.js": "bin/lzma.js" "lzma.js": "bin/lzma.js"
} }
}, },
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/mime-db": { "node_modules/mime-db": {
"version": "1.44.0", "version": "1.44.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
...@@ -2035,6 +2493,15 @@ ...@@ -2035,6 +2493,15 @@
"split": "^1.0.0" "split": "^1.0.0"
} }
}, },
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/postgres-array": { "node_modules/postgres-array": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.2.tgz", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.2.tgz",
...@@ -2156,6 +2623,27 @@ ...@@ -2156,6 +2623,27 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}, },
"node_modules/redis-errors": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/redis-parser": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
"license": "MIT",
"dependencies": {
"redis-errors": "^1.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/reflect-metadata": { "node_modules/reflect-metadata": {
"version": "0.1.13", "version": "0.1.13",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
...@@ -2264,6 +2752,23 @@ ...@@ -2264,6 +2752,23 @@
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
}, },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/set-immediate-shim": { "node_modules/set-immediate-shim": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
...@@ -2363,6 +2868,12 @@ ...@@ -2363,6 +2868,12 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/standard-as-callback": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
"license": "MIT"
},
"node_modules/stream-buffers": { "node_modules/stream-buffers": {
"version": "0.2.6", "version": "0.2.6",
"resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-0.2.6.tgz", "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-0.2.6.tgz",
...@@ -2492,6 +3003,26 @@ ...@@ -2492,6 +3003,26 @@
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
}, },
"node_modules/to-buffer": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz",
"integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==",
"license": "MIT",
"dependencies": {
"isarray": "^2.0.5",
"safe-buffer": "^5.2.1",
"typed-array-buffer": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/to-buffer/node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
"license": "MIT"
},
"node_modules/tough-cookie": { "node_modules/tough-cookie": {
"version": "2.5.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
...@@ -2541,6 +3072,29 @@ ...@@ -2541,6 +3072,29 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/typed-array-buffer": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
"is-typed-array": "^1.1.14"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/typed-reflector": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/typed-reflector/-/typed-reflector-1.0.11.tgz",
"integrity": "sha512-OhryVYaR+tBEW9Yt2PsPqAniNfbVk1idKbnLxBCBPUSHVRm+Ajik/QxifoJUuGoaXAZDLW9JlJTO6ctXGZX9gQ==",
"license": "MIT",
"dependencies": {
"reflect-metadata": "^0.1.13"
}
},
"node_modules/typeorm": { "node_modules/typeorm": {
"version": "0.2.29", "version": "0.2.29",
"resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.29.tgz", "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.29.tgz",
...@@ -2682,16 +3236,17 @@ ...@@ -2682,16 +3236,17 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.5.5", "version": "5.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"dev": true, "dev": true,
"license": "Apache-2.0",
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
}, },
"engines": { "engines": {
"node": ">=4.2.0" "node": ">=14.17"
} }
}, },
"node_modules/underscore": { "node_modules/underscore": {
...@@ -2773,6 +3328,27 @@ ...@@ -2773,6 +3328,27 @@
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
}, },
"node_modules/which-typed-array": {
"version": "1.1.19",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
"integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
"license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"for-each": "^0.3.5",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/wide-align": { "node_modules/wide-align": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
...@@ -3108,6 +3684,12 @@ ...@@ -3108,6 +3684,12 @@
"engines": { "engines": {
"node": ">=10" "node": ">=10"
} }
},
"node_modules/ygopro-deck-encode": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/ygopro-deck-encode/-/ygopro-deck-encode-1.0.9.tgz",
"integrity": "sha512-2aw/Lr8Sg4cPXKgq71Zk/GQPTZy5GhmviptVHWqMGEW0E2qTaxwpGmsQAN2Q4OWaK1lP+3g3bZt9BaqmWYZQSw==",
"license": "MIT"
} }
}, },
"dependencies": { "dependencies": {
...@@ -3134,6 +3716,17 @@ ...@@ -3134,6 +3716,17 @@
"js-tokens": "^4.0.0" "js-tokens": "^4.0.0"
} }
}, },
"@ioredis/commands": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
},
"@sesamecare-oss/redlock": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@sesamecare-oss/redlock/-/redlock-1.4.0.tgz",
"integrity": "sha512-2z589R+yxKLN4CgKxP1oN4dsg6Y548SE4bVYam/R0kHk7Q9VrQ9l66q+k1ehhSLLY4or9hcchuF9/MhuuZdjJg==",
"requires": {}
},
"@sqltools/formatter": { "@sqltools/formatter": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.2.tgz", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.2.tgz",
...@@ -3154,10 +3747,19 @@ ...@@ -3154,10 +3747,19 @@
"integrity": "sha512-oe7hzc+P9DU6+gql8+bLKuUf4WL4aakyCSXZMZq2cjhhGK75qYwH1zJ4s94XOlnb4cAhrGKwnbrmMBaqDK8+Ww==", "integrity": "sha512-oe7hzc+P9DU6+gql8+bLKuUf4WL4aakyCSXZMZq2cjhhGK75qYwH1zJ4s94XOlnb4cAhrGKwnbrmMBaqDK8+Ww==",
"dev": true "dev": true
}, },
"@types/lzma": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@types/lzma/-/lzma-2.3.0.tgz",
"integrity": "sha512-z7TknP6ts5GPnN7P2bkZC1B/tMpoMJXG3UnPY1XDrwBq1OJQ2EpHtEypFwq5Q0A5iS37+oc+MT/o/B7x5lgl8Q==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/node": { "@types/node": {
"version": "17.0.19", "version": "16.18.126",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.19.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz",
"integrity": "sha512-PfeQhvcMR4cPFVuYfBN4ifG7p9c+Dlh3yUZR6k+5yQK7wX3gDgVxBly4/WkBRs9x4dmcy1TVl08SY67wwtEvmA==", "integrity": "sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==",
"dev": true "dev": true
}, },
"@types/underscore": { "@types/underscore": {
...@@ -3219,6 +3821,34 @@ ...@@ -3219,6 +3821,34 @@
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
}, },
"aragami": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/aragami/-/aragami-1.2.5.tgz",
"integrity": "sha512-w+jSXxXYAk3X/TSMoVfc12lY1c40MYqf6W6R2yGE1q7pY4ZC+xpzGBT+Bqa4hO6hlWsM5sFRnKvAE+72HCkT2w==",
"requires": {
"@sesamecare-oss/redlock": "^1.4.0",
"better-lock": "^2.0.3",
"class-transformer": "^0.5.1",
"encoded-buffer": "^0.2.6",
"generic-pool": "^3.9.0",
"ioredis": "^5.2.3",
"lodash": "^4.17.21",
"lru-cache": "^7.13.1",
"typed-reflector": "^1.0.11"
},
"dependencies": {
"generic-pool": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
"integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g=="
},
"lru-cache": {
"version": "7.18.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="
}
}
},
"are-we-there-yet": { "are-we-there-yet": {
"version": "1.1.5", "version": "1.1.5",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
...@@ -3266,6 +3896,14 @@ ...@@ -3266,6 +3896,14 @@
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
}, },
"available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
"requires": {
"possible-typed-array-names": "^1.0.0"
}
},
"aws-sign2": { "aws-sign2": {
"version": "0.7.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
...@@ -3302,6 +3940,11 @@ ...@@ -3302,6 +3940,11 @@
"tweetnacl": "^0.14.3" "tweetnacl": "^0.14.3"
} }
}, },
"better-lock": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/better-lock/-/better-lock-2.0.3.tgz",
"integrity": "sha512-3bCaToLrmEXZcIOOVWgi1STvp3/6EpoZAmlWBeuX2MvDB0Ql2ctl/vQ0CbhQIJYQiptdGypllP3ez+TeEmdnKQ=="
},
"bignumber.js": { "bignumber.js": {
"version": "9.0.0", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
...@@ -3364,6 +4007,35 @@ ...@@ -3364,6 +4007,35 @@
"safe-json-stringify": "~1" "safe-json-stringify": "~1"
} }
}, },
"call-bind": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
"requires": {
"call-bind-apply-helpers": "^1.0.0",
"es-define-property": "^1.0.0",
"get-intrinsic": "^1.2.4",
"set-function-length": "^1.2.2"
}
},
"call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"requires": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
}
},
"call-bound": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"requires": {
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
}
},
"camelcase": { "camelcase": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
...@@ -3397,6 +4069,11 @@ ...@@ -3397,6 +4069,11 @@
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
}, },
"class-transformer": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw=="
},
"cli-highlight": { "cli-highlight": {
"version": "2.1.4", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.4.tgz", "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.4.tgz",
...@@ -3541,15 +4218,20 @@ ...@@ -3541,15 +4218,20 @@
} }
} }
}, },
"cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="
},
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
}, },
"coffeescript": { "coffeescript": {
"version": "2.6.1", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.6.1.tgz", "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.7.0.tgz",
"integrity": "sha512-GG5nkF93qII8HmHqnnibkgpp/SV7PSnSPiWsbinwya7nNOe95aE/x2xrKZJFks8Qpko3TNrC+/LahaKgrz5YCg==", "integrity": "sha512-hzWp6TUE2d/jCcN67LrW1eh5b/rSDKQK6oD6VMLlggYVUUFexgTH9z3dNYihzX4RMhze5FTUsUmOXViJKFQR/A==",
"dev": true "dev": true
}, },
"color-convert": { "color-convert": {
...@@ -3624,6 +4306,16 @@ ...@@ -3624,6 +4306,16 @@
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
}, },
"define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"requires": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.0.1"
}
},
"delayed-stream": { "delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
...@@ -3634,6 +4326,11 @@ ...@@ -3634,6 +4326,11 @@
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
}, },
"denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="
},
"detect-libc": { "detect-libc": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
...@@ -3653,6 +4350,16 @@ ...@@ -3653,6 +4350,16 @@
"nan": "^2.14.0" "nan": "^2.14.0"
} }
}, },
"dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"requires": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
}
},
"ecc-jsbn": { "ecc-jsbn": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
...@@ -3667,6 +4374,16 @@ ...@@ -3667,6 +4374,16 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
}, },
"encoded-buffer": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/encoded-buffer/-/encoded-buffer-0.2.6.tgz",
"integrity": "sha512-zEskqXs0FbF9HcwZkumyAoiB3NN23yAoJvPmLP0NuWQLXTeCDMeVRYK1kjIsZPkoXE2cIBS0iht95pqf8UKyog==",
"requires": {
"lodash": "^4.17.10",
"to-buffer": "^1.1.1",
"tslib": "^1.9.3"
}
},
"error-ex": { "error-ex": {
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
...@@ -3675,6 +4392,24 @@ ...@@ -3675,6 +4392,24 @@
"is-arrayish": "^0.2.1" "is-arrayish": "^0.2.1"
} }
}, },
"es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="
},
"es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="
},
"es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"requires": {
"es-errors": "^1.3.0"
}
},
"escalade": { "escalade": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
...@@ -3752,6 +4487,14 @@ ...@@ -3752,6 +4487,14 @@
} }
} }
}, },
"for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
"requires": {
"is-callable": "^1.2.7"
}
},
"forever-agent": { "forever-agent": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
...@@ -3806,6 +4549,11 @@ ...@@ -3806,6 +4549,11 @@
} }
} }
}, },
"function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
},
"gauge": { "gauge": {
"version": "2.7.4", "version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
...@@ -3878,6 +4626,32 @@ ...@@ -3878,6 +4626,32 @@
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
}, },
"get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"requires": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
}
},
"get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"requires": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
}
},
"getpass": { "getpass": {
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
...@@ -3898,6 +4672,11 @@ ...@@ -3898,6 +4672,11 @@
"path-is-absolute": "^1.0.0" "path-is-absolute": "^1.0.0"
} }
}, },
"gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="
},
"graceful-fs": { "graceful-fs": {
"version": "1.1.14", "version": "1.1.14",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz",
...@@ -3931,11 +4710,40 @@ ...@@ -3931,11 +4710,40 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
}, },
"has-property-descriptors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"requires": {
"es-define-property": "^1.0.0"
}
},
"has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="
},
"has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"requires": {
"has-symbols": "^1.0.3"
}
},
"has-unicode": { "has-unicode": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
}, },
"hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"requires": {
"function-bind": "^1.1.2"
}
},
"highlight.js": { "highlight.js": {
"version": "9.18.3", "version": "9.18.3",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.3.tgz", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.3.tgz",
...@@ -3996,6 +4804,37 @@ ...@@ -3996,6 +4804,37 @@
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
}, },
"ioredis": {
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.6.1.tgz",
"integrity": "sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA==",
"requires": {
"@ioredis/commands": "^1.1.1",
"cluster-key-slot": "^1.1.0",
"debug": "^4.3.4",
"denque": "^2.1.0",
"lodash.defaults": "^4.2.0",
"lodash.isarguments": "^3.1.0",
"redis-errors": "^1.2.0",
"redis-parser": "^3.0.0",
"standard-as-callback": "^2.1.0"
},
"dependencies": {
"debug": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"requires": {
"ms": "^2.1.3"
}
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
}
}
},
"ip6addr": { "ip6addr": {
"version": "0.2.5", "version": "0.2.5",
"resolved": "https://registry.npmjs.org/ip6addr/-/ip6addr-0.2.5.tgz", "resolved": "https://registry.npmjs.org/ip6addr/-/ip6addr-0.2.5.tgz",
...@@ -4028,6 +4867,11 @@ ...@@ -4028,6 +4867,11 @@
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
}, },
"is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="
},
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
...@@ -4036,6 +4880,14 @@ ...@@ -4036,6 +4880,14 @@
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
}, },
"is-typed-array": {
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
"requires": {
"which-typed-array": "^1.1.16"
}
},
"is-typedarray": { "is-typedarray": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
...@@ -4167,6 +5019,21 @@ ...@@ -4167,6 +5019,21 @@
"p-locate": "^4.1.0" "p-locate": "^4.1.0"
} }
}, },
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
},
"lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
},
"lru-cache": { "lru-cache": {
"version": "2.7.3", "version": "2.7.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz",
...@@ -4177,6 +5044,11 @@ ...@@ -4177,6 +5044,11 @@
"resolved": "https://registry.npmjs.org/lzma/-/lzma-2.3.2.tgz", "resolved": "https://registry.npmjs.org/lzma/-/lzma-2.3.2.tgz",
"integrity": "sha1-N4OySFi5wOdHoN88vx+1/KqSxEE=" "integrity": "sha1-N4OySFi5wOdHoN88vx+1/KqSxEE="
}, },
"math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="
},
"mime-db": { "mime-db": {
"version": "1.44.0", "version": "1.44.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
...@@ -4686,6 +5558,11 @@ ...@@ -4686,6 +5558,11 @@
"split": "^1.0.0" "split": "^1.0.0"
} }
}, },
"possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="
},
"postgres-array": { "postgres-array": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.2.tgz", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.2.tgz",
...@@ -4780,6 +5657,19 @@ ...@@ -4780,6 +5657,19 @@
} }
} }
}, },
"redis-errors": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w=="
},
"redis-parser": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
"requires": {
"redis-errors": "^1.0.0"
}
},
"reflect-metadata": { "reflect-metadata": {
"version": "0.1.13", "version": "0.1.13",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
...@@ -4861,6 +5751,19 @@ ...@@ -4861,6 +5751,19 @@
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
}, },
"set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"requires": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.2"
}
},
"set-immediate-shim": { "set-immediate-shim": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
...@@ -4929,6 +5832,11 @@ ...@@ -4929,6 +5832,11 @@
"tweetnacl": "~0.14.0" "tweetnacl": "~0.14.0"
} }
}, },
"standard-as-callback": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
},
"stream-buffers": { "stream-buffers": {
"version": "0.2.6", "version": "0.2.6",
"resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-0.2.6.tgz", "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-0.2.6.tgz",
...@@ -5037,6 +5945,23 @@ ...@@ -5037,6 +5945,23 @@
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
}, },
"to-buffer": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz",
"integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==",
"requires": {
"isarray": "^2.0.5",
"safe-buffer": "^5.2.1",
"typed-array-buffer": "^1.0.3"
},
"dependencies": {
"isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="
}
}
},
"tough-cookie": { "tough-cookie": {
"version": "2.5.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
...@@ -5074,6 +5999,24 @@ ...@@ -5074,6 +5999,24 @@
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
"integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="
}, },
"typed-array-buffer": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
"requires": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
"is-typed-array": "^1.1.14"
}
},
"typed-reflector": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/typed-reflector/-/typed-reflector-1.0.11.tgz",
"integrity": "sha512-OhryVYaR+tBEW9Yt2PsPqAniNfbVk1idKbnLxBCBPUSHVRm+Ajik/QxifoJUuGoaXAZDLW9JlJTO6ctXGZX9gQ==",
"requires": {
"reflect-metadata": "^0.1.13"
}
},
"typeorm": { "typeorm": {
"version": "0.2.29", "version": "0.2.29",
"resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.29.tgz", "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.29.tgz",
...@@ -5169,9 +6112,9 @@ ...@@ -5169,9 +6112,9 @@
} }
}, },
"typescript": { "typescript": {
"version": "4.5.5", "version": "5.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"dev": true "dev": true
}, },
"underscore": { "underscore": {
...@@ -5240,6 +6183,20 @@ ...@@ -5240,6 +6183,20 @@
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
}, },
"which-typed-array": {
"version": "1.1.19",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
"integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
"requires": {
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"for-each": "^0.3.5",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2"
}
},
"wide-align": { "wide-align": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
...@@ -5486,6 +6443,11 @@ ...@@ -5486,6 +6443,11 @@
"camelcase": "^5.0.0", "camelcase": "^5.0.0",
"decamelize": "^1.2.0" "decamelize": "^1.2.0"
} }
},
"ygopro-deck-encode": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/ygopro-deck-encode/-/ygopro-deck-encode-1.0.9.tgz",
"integrity": "sha512-2aw/Lr8Sg4cPXKgq71Zk/GQPTZy5GhmviptVHWqMGEW0E2qTaxwpGmsQAN2Q4OWaK1lP+3g3bZt9BaqmWYZQSw=="
} }
} }
} }
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
], ],
"author": "zh99998 <zh99998@gmail.com>, mercury233 <me@mercury233.me>, Nanahira <78877@qq.com>", "author": "zh99998 <zh99998@gmail.com>, mercury233 <me@mercury233.me>, Nanahira <78877@qq.com>",
"dependencies": { "dependencies": {
"aragami": "^1.2.5",
"async": "^3.2.0", "async": "^3.2.0",
"axios": "^0.19.2", "axios": "^0.19.2",
"bunyan": "^1.8.14", "bunyan": "^1.8.14",
...@@ -34,7 +35,8 @@ ...@@ -34,7 +35,8 @@
"typeorm": "^0.2.29", "typeorm": "^0.2.29",
"underscore": "^1.11.0", "underscore": "^1.11.0",
"underscore.string": "^3.3.6", "underscore.string": "^3.3.6",
"ws": "^8.9.0" "ws": "^8.9.0",
"ygopro-deck-encode": "^1.0.9"
}, },
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
...@@ -48,10 +50,11 @@ ...@@ -48,10 +50,11 @@
"devDependencies": { "devDependencies": {
"@types/bunyan": "^1.8.8", "@types/bunyan": "^1.8.8",
"@types/ip6addr": "^0.2.3", "@types/ip6addr": "^0.2.3",
"@types/node": "^17.0.19", "@types/lzma": "^2.3.0",
"@types/node": "^16.18.126",
"@types/underscore": "^1.11.4", "@types/underscore": "^1.11.4",
"@types/ws": "^8.5.3", "@types/ws": "^8.5.3",
"coffeescript": "^2.6.1", "coffeescript": "^2.7.0",
"typescript": "^4.5.5" "typescript": "^5.8.3"
} }
} }
...@@ -5,14 +5,15 @@ ...@@ -5,14 +5,15 @@
"esModuleInterop": true, "esModuleInterop": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true
"sourceMap": true
}, },
"compileOnSave": true, "compileOnSave": true,
"allowJs": true, "allowJs": true,
"include": [ "include": [
"*.ts", "*.ts",
"data-manager/*.ts", "data-manager/*.ts",
"data-manager/entities/*.ts" "data-manager/entities/*.ts",
"msg-polyfill/*.ts",
"msg-polyfill/polyfillers/*.ts"
] ]
} }
...@@ -18,4 +18,3 @@ async function retry(fn, count, delayFn = (attempt) => Math.pow(2, attempt) * 10 ...@@ -18,4 +18,3 @@ async function retry(fn, count, delayFn = (attempt) => Math.pow(2, attempt) * 10
// 如果全部尝试失败,抛出最后一个错误 // 如果全部尝试失败,抛出最后一个错误
throw lastError; throw lastError;
} }
//# sourceMappingURL=utility.js.map
\ No newline at end of file
...@@ -82,7 +82,8 @@ import_datas = global.import_datas = [ ...@@ -82,7 +82,8 @@ import_datas = global.import_datas = [
"join_time", "join_time",
"arena_quit_free", "arena_quit_free",
"replays_sent", "replays_sent",
"victory_words" "victory_words",
"actual_version",
] ]
merge = require 'deepmerge' merge = require 'deepmerge'
...@@ -95,6 +96,16 @@ util = require("util") ...@@ -95,6 +96,16 @@ util = require("util")
Q = require("q") Q = require("q")
YGOProDeck = require('ygopro-deck-encode').default
Aragami = require('aragami').Aragami
aragami = global.aragami = new Aragami() # we use memory mode only
aragami_classes = global.aragami_classes = require('./aragami-classes.js')
msg_polyfill = global.msg_polyfill = require('./msg-polyfill/index.js')
#heapdump = require 'heapdump' #heapdump = require 'heapdump'
checkFileExists = (path) => checkFileExists = (path) =>
...@@ -401,6 +412,10 @@ loadLFList = (path) -> ...@@ -401,6 +412,10 @@ loadLFList = (path) ->
if settings.modules.hide_name == true if settings.modules.hide_name == true
settings.modules.hide_name = "start" settings.modules.hide_name = "start"
imported = true imported = true
if settings.modules.neos.trusted_proxies
settings.modules.trusted_proxies = settings.modules.neos.trusted_proxies
delete settings.modules.neos.trusted_proxies
imported = true
#finish #finish
keysFromEnv = Object.keys(process.env).filter((key) => key.startsWith('SRVPRO_')) keysFromEnv = Object.keys(process.env).filter((key) => key.startsWith('SRVPRO_'))
if keysFromEnv.length > 0 if keysFromEnv.length > 0
...@@ -493,7 +508,7 @@ loadLFList = (path) -> ...@@ -493,7 +508,7 @@ loadLFList = (path) ->
catch catch
try try
log.info("Reading YGOPro version.") log.info("Reading YGOPro version.")
cppversion = parseInt((await fs.promises.readFile('ygopro/gframe/game.cpp', 'utf8')).match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16') cppversion = parseInt((await fs.promises.readFile(path.resolve(settings.modules.ygopro_path, 'gframe', 'game.cpp'), 'utf8')).match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16')
await setting_change(settings, "version", cppversion) await setting_change(settings, "version", cppversion)
log.info "ygopro version 0x"+settings.version.toString(16), "(from source code)" log.info "ygopro version 0x"+settings.version.toString(16), "(from source code)"
catch catch
...@@ -501,8 +516,9 @@ loadLFList = (path) -> ...@@ -501,8 +516,9 @@ loadLFList = (path) ->
log.info "ygopro version 0x"+settings.version.toString(16), "(from config)" log.info "ygopro version 0x"+settings.version.toString(16), "(from config)"
# load the lflist of current date # load the lflist of current date
log.info("Reading banlists.") log.info("Reading banlists.")
await loadLFList('ygopro/expansions/lflist.conf') for expansions in settings.modules.expansions_path
await loadLFList('ygopro/lflist.conf') await loadLFList(path.resolve(settings.modules.ygopro_path, expansions, 'lflist.conf'))
await loadLFList(path.resolve(settings.modules.ygopro_path, 'lflist.conf'))
badwordR = global.badwordR = {} badwordR = global.badwordR = {}
badwordR.level0=new RegExp('(?:'+badwords.level0.join(')|(?:')+')','i'); badwordR.level0=new RegExp('(?:'+badwords.level0.join(')|(?:')+')','i');
...@@ -540,7 +556,7 @@ loadLFList = (path) -> ...@@ -540,7 +556,7 @@ loadLFList = (path) ->
long_resolve_cards = global.long_resolve_cards = await loadJSONAsync('./data/long_resolve_cards.json') long_resolve_cards = global.long_resolve_cards = await loadJSONAsync('./data/long_resolve_cards.json')
if settings.modules.tournament_mode.enable_recover if settings.modules.tournament_mode.enable_recover
ReplayParser = global.ReplayParser = require "./Replay.js" ReplayParser = global.ReplayParser = (require "./Replay.js").Replay
if settings.modules.athletic_check.enabled if settings.modules.athletic_check.enabled
AthleticChecker = require("./athletic-check.js").AthleticChecker AthleticChecker = require("./athletic-check.js").AthleticChecker
...@@ -747,7 +763,7 @@ loadLFList = (path) -> ...@@ -747,7 +763,7 @@ loadLFList = (path) ->
plugin_list = await fs.promises.readdir("./plugins") plugin_list = await fs.promises.readdir("./plugins")
for plugin_filename in plugin_list for plugin_filename in plugin_list
if plugin_filename.endsWith '.js' if plugin_filename.endsWith '.js'
plugin_path = process.cwd() + "/plugins/" + plugin_filename plugin_path = path.resolve(process.cwd(), "plugins", plugin_filename)
require(plugin_path) require(plugin_path)
log.info("Plugin loaded:", plugin_filename) log.info("Plugin loaded:", plugin_filename)
...@@ -1301,6 +1317,56 @@ CLIENT_send_replays_and_kick = global.CLIENT_send_replays_and_kick = (client, ro ...@@ -1301,6 +1317,56 @@ CLIENT_send_replays_and_kick = global.CLIENT_send_replays_and_kick = (client, ro
CLIENT_kick(client) CLIENT_kick(client)
return return
toIpv4 = global.toIpv4 = (ip) ->
if ip.startsWith('::ffff:')
return ip.slice(7)
return ip
toIpv6 = global.toIpv6 = (ip) ->
if /^(\d{1,3}\.){3}\d{1,3}$/.test(ip)
return '::ffff:' + ip
return ip
isTrustedProxy = global.isTrustedProxy = (ip) ->
return settings.modules.trusted_proxies.some((trusted) ->
cidr = if trusted.includes('/') then ip6addr.createCIDR(trusted) else ip6addr.createAddrRange(trusted, trusted)
return cidr.contains(ip)
)
getRealIp = global.getRealIp = (physical_ip, xff_ip) ->
if not xff_ip or xff_ip == physical_ip
return toIpv6(physical_ip)
if isTrustedProxy(physical_ip)
return toIpv6(xff_ip.split(',')[0].trim())
log.warn("Untrusted proxy detected: #{physical_ip} -> #{xff_ip}")
return toIpv6(physical_ip)
CLIENT_set_ip = global.CLIENT_set_ip = (client, xff_ip) ->
client_prev_ip = client.ip
client.ip = getRealIp(client.physical_ip, xff_ip)
if client_prev_ip == client.ip
return false
if client_prev_ip and ROOM_connected_ip[client_prev_ip] and ROOM_connected_ip[client_prev_ip] > 0
ROOM_connected_ip[client_prev_ip]--
if ROOM_connected_ip[client_prev_ip] <= 0
delete ROOM_connected_ip[client_prev_ip]
client.is_local = client.ip and (client.ip.includes('127.0.0.1') or client.ip.includes(real_windbot_server_ip))
connect_count = ROOM_connected_ip[client.ip] or 0
if !settings.modules.test_mode.no_connect_count_limit and !client.is_local and !isTrustedProxy(client.ip)
connect_count++
ROOM_connected_ip[client.ip] = connect_count
# log.info "connect", client.ip, ROOM_connected_ip[client.ip]
if ROOM_bad_ip[client.ip] > 5 or ROOM_connected_ip[client.ip] > 10
log.info 'BAD IP', client.ip
client.destroy()
return true
return false
SOCKET_flush_data = global.SOCKET_flush_data = (sk, datas) -> SOCKET_flush_data = global.SOCKET_flush_data = (sk, datas) ->
if !sk or sk.isClosed if !sk or sk.isClosed
return false return false
...@@ -1309,9 +1375,6 @@ SOCKET_flush_data = global.SOCKET_flush_data = (sk, datas) -> ...@@ -1309,9 +1375,6 @@ SOCKET_flush_data = global.SOCKET_flush_data = (sk, datas) ->
await ygopro.helper.send(sk, buffer) await ygopro.helper.send(sk, buffer)
return true return true
getSeedTimet = global.getSeedTimet = (count) ->
return _.range(count).map(() => 0)
class Room class Room
constructor: (name, @hostinfo) -> constructor: (name, @hostinfo) ->
@name = name @name = name
...@@ -1538,15 +1601,28 @@ class Room ...@@ -1538,15 +1601,28 @@ class Room
@hostinfo.start_lp, @hostinfo.start_hand, @hostinfo.draw_count, @hostinfo.time_limit, @hostinfo.replay_mode] @hostinfo.start_lp, @hostinfo.start_hand, @hostinfo.draw_count, @hostinfo.time_limit, @hostinfo.replay_mode]
if firstSeed if firstSeed
param.push(firstSeed) # new replay with extended header and long seed
seeds = getSeedTimet(2) firstSeedBuf = Buffer.allocUnsafe(firstSeed.length * 4)
param.push(seeds[i]) for i in [0...2] for i in [0...firstSeed.length]
else firstSeedBuf.writeUInt32LE(firstSeed[i], i * 4)
seeds = getSeedTimet(3) param.push(firstSeedBuf.toString('base64'))
param.push(seeds[i]) for i in [0...3]
try try
@process = spawn './ygopro', param, {cwd: 'ygopro'} @process = spawn(
path.resolve(settings.modules.ygopro_path, settings.modules.ygopro_exec_path),
param,
{
cwd: path.resolve(settings.modules.ygopro_path),
env: {
...process.env,
YGOPRO_EXPANSIONS: settings.modules.expansions_path
.map((s) ->
path.resolve(settings.modules.ygopro_path, s)
)
.join(',')
}
}
)
@process_pid = @process.pid @process_pid = @process.pid
@process.on 'error', (err)=> @process.on 'error', (err)=>
log.warn 'CREATE ROOM ERROR', err log.warn 'CREATE ROOM ERROR', err
...@@ -1696,7 +1772,12 @@ class Room ...@@ -1696,7 +1772,12 @@ class Room
return false return false
try try
@recover_replay = await ReplayParser.fromFile(settings.modules.tournament_mode.replay_path + @recover_duel_log.replayFileName) @recover_replay = await ReplayParser.fromFile(settings.modules.tournament_mode.replay_path + @recover_duel_log.replayFileName)
@spawn(@recover_replay.header.seed) if !@recover_replay.header.seedSequence.length
# it's old replay, unsupported
log.warn("LOAD RECOVER REPLAY FAIL: Old replay format, unsupported", @recover_duel_log.replayFileName)
@terminate()
return false
@spawn(@recover_replay.header.seedSequence)
return true return true
catch e catch e
log.warn("LOAD RECOVER REPLAY FAIL", e.toString()) log.warn("LOAD RECOVER REPLAY FAIL", e.toString())
...@@ -2032,18 +2113,8 @@ class Room ...@@ -2032,18 +2113,8 @@ class Room
# 网络连接 # 网络连接
netRequestHandler = (client) -> netRequestHandler = (client) ->
if !client.isWs if !client.isWs
client.ip = client.remoteAddress or '' client.physical_ip = client.remoteAddress or ""
client.is_local = client.ip and (client.ip.includes('127.0.0.1') or client.ip.includes(real_windbot_server_ip)) if CLIENT_set_ip(client)
connect_count = ROOM_connected_ip[client.ip] or 0
if !settings.modules.test_mode.no_connect_count_limit and !client.is_local
connect_count++
ROOM_connected_ip[client.ip] = connect_count
#log.info "connect", client.ip, ROOM_connected_ip[client.ip]
if ROOM_bad_ip[client.ip] > 5 or ROOM_connected_ip[client.ip] > 10
log.info 'BAD IP', client.ip
client.destroy()
return return
# server stand for the connection to ygopro server process # server stand for the connection to ygopro server process
...@@ -2061,8 +2132,11 @@ netRequestHandler = (client) -> ...@@ -2061,8 +2132,11 @@ netRequestHandler = (client) ->
return return
room=ROOM_all[client.rid] room=ROOM_all[client.rid]
connect_count = ROOM_connected_ip[client.ip] connect_count = ROOM_connected_ip[client.ip]
if connect_count > 0 if connect_count and connect_count > 0
connect_count-- connect_count--
if connect_count == 0
delete ROOM_connected_ip[client.ip]
else
ROOM_connected_ip[client.ip] = connect_count ROOM_connected_ip[client.ip] = connect_count
client.isClosed = true client.isClosed = true
if settings.modules.heartbeat_detection.enabled if settings.modules.heartbeat_detection.enabled
...@@ -2170,8 +2244,8 @@ netRequestHandler = (client) -> ...@@ -2170,8 +2244,8 @@ netRequestHandler = (client) ->
preconnect = false preconnect = false
if settings.modules.reconnect.enabled and client.pre_reconnecting_to_room if settings.modules.reconnect.enabled and client.pre_reconnecting_to_room
ctos_filter = ["UPDATE_DECK"] ctos_filter = ["UPDATE_DECK"]
if client.name == null else if client.name == null
ctos_filter = ["JOIN_GAME", "PLAYER_INFO"] ctos_filter = ["EXTERNAL_ADDRESS", "JOIN_GAME", "PLAYER_INFO"]
preconnect = true preconnect = true
handle_data = await ygopro.helper.handleBuffer(ctos_buffer, "CTOS", ctos_filter, { handle_data = await ygopro.helper.handleBuffer(ctos_buffer, "CTOS", ctos_filter, {
client: client, client: client,
...@@ -2227,6 +2301,19 @@ deck_name_match = global.deck_name_match = (deck_name, player_name) -> ...@@ -2227,6 +2301,19 @@ deck_name_match = global.deck_name_match = (deck_name, player_name) ->
# 功能模块 # 功能模块
# return true to cancel a synchronous message # return true to cancel a synchronous message
ygopro.ctos_follow 'EXTERNAL_ADDRESS', true, (buffer, info, client, server, datas)->
ip_uint = buffer.readUInt32BE(0)
if ip_uint == 0
return false
ip_parts = [
(ip_uint >>> 24) & 0xFF,
(ip_uint >>> 16) & 0xFF,
(ip_uint >>> 8) & 0xFF,
ip_uint & 0xFF
]
xff_ip = ip_parts.join('.')
return CLIENT_set_ip(client, xff_ip)
ygopro.ctos_follow 'PLAYER_INFO', true, (buffer, info, client, server, datas)-> ygopro.ctos_follow 'PLAYER_INFO', true, (buffer, info, client, server, datas)->
# second PLAYER_INFO = attack # second PLAYER_INFO = attack
if client.name if client.name
...@@ -2274,6 +2361,41 @@ ygopro.ctos_follow 'PLAYER_INFO', true, (buffer, info, client, server, datas)-> ...@@ -2274,6 +2361,41 @@ ygopro.ctos_follow 'PLAYER_INFO', true, (buffer, info, client, server, datas)->
await return false await return false
ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
check_version = () ->
bad_version = (msg) ->
ygopro.stoc_send_chat(client, msg, ygopro.constants.COLORS.RED)
ygopro.stoc_send client, 'ERROR_MSG', {
msg: 4
code: settings.version
}
CLIENT_kick(client)
return false
if info.version == settings.version
return true
if settings.alternative_versions.includes(info.version)
client_key = CLIENT_get_authorize_key(client)
if !await aragami.has(aragami_classes.ClientVersionBlocker, client_key)
blocker_obj = new aragami_classes.ClientVersionBlocker()
blocker_obj.clientKey = client_key
await aragami.set(blocker_obj)
return bad_version("${version_to_polyfill}")
else
await aragami.del(aragami_classes.ClientVersionBlocker, client_key)
return true
return bad_version(if info.version < settings.version then settings.modules.update else settings.modules.wait_update)
polyfill_version = () ->
if client.actual_version
# already polyfilled
return
client.actual_version = info.version
if info.version != settings.version and settings.alternative_versions.includes(info.version)
info.version = settings.version
struct = ygopro.structs.get("CTOS_JoinGame")
struct._setBuff(buffer)
struct.set("version", info.version)
buffer = struct.buffer
ygopro.stoc_send_chat(client, "${version_polyfilled}", ygopro.constants.COLORS.BABYBLUE)
await return
#log.info info #log.info info
info.pass=info.pass.trim() info.pass=info.pass.trim()
client.pass = info.pass client.pass = info.pass
...@@ -2282,9 +2404,10 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ...@@ -2282,9 +2404,10 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
return return
else if settings.modules.stop else if settings.modules.stop
ygopro.stoc_die(client, settings.modules.stop) ygopro.stoc_die(client, settings.modules.stop)
return
else if info.pass == "Marshtomp" or info.pass == "the Big Brother" else if info.pass == "Marshtomp" or info.pass == "the Big Brother"
ygopro.stoc_die(client, "${bad_user_name}") ygopro.stoc_die(client, "${bad_user_name}")
return
else if info.pass.toUpperCase()=="R" and settings.modules.cloud_replay.enabled else if info.pass.toUpperCase()=="R" and settings.modules.cloud_replay.enabled
ygopro.stoc_send_chat(client,"${cloud_replay_hint}", ygopro.constants.COLORS.BABYBLUE) ygopro.stoc_send_chat(client,"${cloud_replay_hint}", ygopro.constants.COLORS.BABYBLUE)
replays = await dataManager.getCloudReplaysFromKey(CLIENT_get_authorize_key(client)) replays = await dataManager.getCloudReplaysFromKey(CLIENT_get_authorize_key(client))
...@@ -2295,7 +2418,7 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ...@@ -2295,7 +2418,7 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
code: 9 code: 9
} }
CLIENT_kick(client) CLIENT_kick(client)
return
else if info.pass.toUpperCase()=="IP" else if info.pass.toUpperCase()=="IP"
ygopro.stoc_send_chat(client, "IP: " + client.ip, ygopro.constants.COLORS.BABYBLUE) ygopro.stoc_send_chat(client, "IP: " + client.ip, ygopro.constants.COLORS.BABYBLUE)
ygopro.stoc_send client, 'ERROR_MSG', { ygopro.stoc_send client, 'ERROR_MSG', {
...@@ -2303,7 +2426,7 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ...@@ -2303,7 +2426,7 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
code: 9 code: 9
} }
CLIENT_kick(client) CLIENT_kick(client)
return
else if info.pass.toUpperCase()=="RC" and settings.modules.tournament_mode.enable_recover else if info.pass.toUpperCase()=="RC" and settings.modules.tournament_mode.enable_recover
ygopro.stoc_send_chat(client,"${recover_replay_hint}", ygopro.constants.COLORS.BABYBLUE) ygopro.stoc_send_chat(client,"${recover_replay_hint}", ygopro.constants.COLORS.BABYBLUE)
available_logs = await dataManager.getDuelLogFromRecoverSearch(client.name_vpass) available_logs = await dataManager.getDuelLogFromRecoverSearch(client.name_vpass)
...@@ -2314,28 +2437,21 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ...@@ -2314,28 +2437,21 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
code: 9 code: 9
} }
CLIENT_kick(client) CLIENT_kick(client)
return
else if info.pass[0...2].toUpperCase()=="R#" and settings.modules.cloud_replay.enabled else if info.pass[0...2].toUpperCase()=="R#" and settings.modules.cloud_replay.enabled
replay_id=info.pass.split("#")[1] replay_id=info.pass.split("#")[1]
replay = await dataManager.getCloudReplayFromId(replay_id) replay = await dataManager.getCloudReplayFromId(replay_id)
await client.open_cloud_replay(replay) await client.open_cloud_replay(replay)
return
else if info.pass.toUpperCase()=="W" and settings.modules.cloud_replay.enabled else if info.pass.toUpperCase()=="W" and settings.modules.cloud_replay.enabled
replay = await dataManager.getRandomCloudReplay() replay = await dataManager.getRandomCloudReplay()
await client.open_cloud_replay(replay) await client.open_cloud_replay(replay)
return
else if info.version != settings.version and !settings.alternative_versions.includes(info.version) else if !await check_version()
ygopro.stoc_send_chat(client, (if info.version < settings.version then settings.modules.update else settings.modules.wait_update), ygopro.constants.COLORS.RED) return
ygopro.stoc_send client, 'ERROR_MSG', {
msg: 4
code: settings.version
}
CLIENT_kick(client)
else if !info.pass.length and !settings.modules.random_duel.enabled and !settings.modules.windbot.enabled and !settings.modules.challonge.enabled else if !info.pass.length and !settings.modules.random_duel.enabled and !settings.modules.windbot.enabled and !settings.modules.challonge.enabled
ygopro.stoc_die(client, "${blank_room_name}") ygopro.stoc_die(client, "${blank_room_name}")
return
else if settings.modules.mysql.enabled and await dataManager.checkBan("name", client.name) #账号被封 else if settings.modules.mysql.enabled and await dataManager.checkBan("name", client.name) #账号被封
exactBan = await dataManager.checkBanWithNameAndIP(client.name, client.ip) exactBan = await dataManager.checkBanWithNameAndIP(client.name, client.ip)
if !exactBan if !exactBan
...@@ -2343,23 +2459,17 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ...@@ -2343,23 +2459,17 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
await dataManager.banPlayer(exactBan) await dataManager.banPlayer(exactBan)
log.warn("BANNED USER LOGIN", client.name, client.ip) log.warn("BANNED USER LOGIN", client.name, client.ip)
ygopro.stoc_die(client, "${banned_user_login}") ygopro.stoc_die(client, "${banned_user_login}")
return
else if settings.modules.mysql.enabled and await dataManager.checkBan("ip", client.ip) #IP被封 else if settings.modules.mysql.enabled and await dataManager.checkBan("ip", client.ip) #IP被封
log.warn("BANNED IP LOGIN", client.name, client.ip) log.warn("BANNED IP LOGIN", client.name, client.ip)
ygopro.stoc_die(client, "${banned_ip_login}") ygopro.stoc_die(client, "${banned_ip_login}")
return
else if info.pass.length and settings.modules.mycard.enabled and info.pass[0...3] != 'AI#' else if info.pass.length and settings.modules.mycard.enabled and info.pass[0...3] != 'AI#'
ygopro.stoc_send_chat(client, '${loading_user_info}', ygopro.constants.COLORS.BABYBLUE) ygopro.stoc_send_chat(client, '${loading_user_info}', ygopro.constants.COLORS.BABYBLUE)
if info.pass.length <= 8 if info.pass.length <= 8
ygopro.stoc_die(client, '${invalid_password_length}') ygopro.stoc_die(client, '${invalid_password_length}')
return return
await polyfill_version()
if info.version != settings.version and settings.alternative_versions.includes(info.version)
info.version = settings.version
struct = ygopro.structs.get("CTOS_JoinGame")
struct._setBuff(buffer)
struct.set("version", info.version)
buffer = struct.buffer
buffer = Buffer.from(info.pass[0...8], 'base64') buffer = Buffer.from(info.pass[0...8], 'base64')
...@@ -2594,33 +2704,28 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ...@@ -2594,33 +2704,28 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
else if !client.name or client.name=="" else if !client.name or client.name==""
ygopro.stoc_die(client, "${bad_user_name}") ygopro.stoc_die(client, "${bad_user_name}")
return
else if ROOM_connected_ip[client.ip] > 5 else if ROOM_connected_ip[client.ip] > 5
log.warn("MULTI LOGIN", client.name, client.ip) log.warn("MULTI LOGIN", client.name, client.ip)
ygopro.stoc_die(client, "${too_much_connection}" + client.ip) ygopro.stoc_die(client, "${too_much_connection}" + client.ip)
return
else if !settings.modules.tournament_mode.enabled and !settings.modules.challonge.enabled and badwordR.level3.test(client.name) else if !settings.modules.tournament_mode.enabled and !settings.modules.challonge.enabled and badwordR.level3.test(client.name)
log.warn("BAD NAME LEVEL 3", client.name, client.ip) log.warn("BAD NAME LEVEL 3", client.name, client.ip)
ygopro.stoc_die(client, "${bad_name_level3}") ygopro.stoc_die(client, "${bad_name_level3}")
return
else if !settings.modules.tournament_mode.enabled and !settings.modules.challonge.enabled and badwordR.level2.test(client.name) else if !settings.modules.tournament_mode.enabled and !settings.modules.challonge.enabled and badwordR.level2.test(client.name)
log.warn("BAD NAME LEVEL 2", client.name, client.ip) log.warn("BAD NAME LEVEL 2", client.name, client.ip)
ygopro.stoc_die(client, "${bad_name_level2}") ygopro.stoc_die(client, "${bad_name_level2}")
return
else if !settings.modules.tournament_mode.enabled and !settings.modules.challonge.enabled and badwordR.level1.test(client.name) else if !settings.modules.tournament_mode.enabled and !settings.modules.challonge.enabled and badwordR.level1.test(client.name)
log.warn("BAD NAME LEVEL 1", client.name, client.ip) log.warn("BAD NAME LEVEL 1", client.name, client.ip)
ygopro.stoc_die(client, "${bad_name_level1}") ygopro.stoc_die(client, "${bad_name_level1}")
return
else if info.pass.length && !ROOM_validate(info.pass) else if info.pass.length && !ROOM_validate(info.pass)
ygopro.stoc_die(client, "${invalid_password_room}") ygopro.stoc_die(client, "${invalid_password_room}")
return
else else
if info.version != settings.version and settings.alternative_versions.includes(info.version) await polyfill_version()
info.version = settings.version
struct = ygopro.structs.get("CTOS_JoinGame")
struct._setBuff(buffer)
struct.set("version", info.version)
buffer = struct.buffer
#log.info 'join_game',info.pass, client.name #log.info 'join_game',info.pass, client.name
room = await ROOM_find_or_create_by_name(info.pass, client.ip) room = await ROOM_find_or_create_by_name(info.pass, client.ip)
...@@ -2729,6 +2834,12 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)-> ...@@ -2729,6 +2834,12 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
return unless room and !client.reconnecting return unless room and !client.reconnecting
msg = buffer.readInt8(0) msg = buffer.readInt8(0)
msg_name = ygopro.constants.MSG[msg] msg_name = ygopro.constants.MSG[msg]
new_buf = await msg_polyfill.polyfillGameMsg(client.actual_version, msg_name, buffer)
if new_buf
buffer = new_buf
record_last_game_msg = () ->
client.last_game_msg = buffer
client.last_game_msg_title = msg_name
#console.log client.pos, "MSG", msg_name #console.log client.pos, "MSG", msg_name
if msg_name == 'RETRY' and room.recovering if msg_name == 'RETRY' and room.recovering
room.finish_recover(true) room.finish_recover(true)
...@@ -2754,12 +2865,10 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)-> ...@@ -2754,12 +2865,10 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
ygopro.stoc_send(client, 'GAME_MSG', client.last_game_msg) ygopro.stoc_send(client, 'GAME_MSG', client.last_game_msg)
return true return true
else else
client.last_game_msg = buffer record_last_game_msg()
client.last_game_msg_title = msg_name
# log.info(client.name, client.last_game_msg_title) # log.info(client.name, client.last_game_msg_title)
else if msg_name != 'RETRY' else if msg_name != 'RETRY'
client.last_game_msg = buffer record_last_game_msg()
client.last_game_msg_title = msg_name
# log.info(client.name, client.last_game_msg_title) # log.info(client.name, client.last_game_msg_title)
if (msg >= 10 and msg < 30) or msg == 132 or (msg >= 140 and msg <= 144) #SELECT和ANNOUNCE开头的消息 if (msg >= 10 and msg < 30) or msg == 132 or (msg >= 140 and msg <= 144) #SELECT和ANNOUNCE开头的消息
...@@ -3025,7 +3134,10 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)-> ...@@ -3025,7 +3134,10 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
room.recover_buffers[client.pos].push(buffer) room.recover_buffers[client.pos].push(buffer)
return true return true
await return false if new_buf
return buffer
else
return false
#房间管理 #房间管理
ygopro.ctos_follow 'HS_TOOBSERVER', true, (buffer, info, client, server, datas)-> ygopro.ctos_follow 'HS_TOOBSERVER', true, (buffer, info, client, server, datas)->
...@@ -3288,7 +3400,7 @@ ygopro.stoc_follow 'DUEL_START', false, (buffer, info, client, server, datas)-> ...@@ -3288,7 +3400,7 @@ ygopro.stoc_follow 'DUEL_START', false, (buffer, info, client, server, datas)->
deck_arena = deck_arena + 'custom' deck_arena = deck_arena + 'custom'
#log.info "DECK LOG START", client.name, room.arena #log.info "DECK LOG START", client.name, room.arena
if settings.modules.deck_log.local if settings.modules.deck_log.local
deck_name = moment_now.format('YYYY-MM-DD HH-mm-ss') + ' ' + room.process_pid + ' ' + client.pos + ' ' + client.ip.slice(7) + ' ' + client.name.replace(/[\/\\\?\*]/g, '_') deck_name = moment_now.format('YYYY-MM-DD HH-mm-ss') + ' ' + room.process_pid + ' ' + client.pos + ' ' + toIpv4(client.ip) + ' ' + client.name.replace(/[\/\\\?\*]/g, '_')
fs.writeFile settings.modules.deck_log.local + deck_name + '.ydk', deck_text, 'utf-8', (err) -> fs.writeFile settings.modules.deck_log.local + deck_name + '.ydk', deck_text, 'utf-8', (err) ->
if err if err
log.warn 'DECK SAVE ERROR', err log.warn 'DECK SAVE ERROR', err
...@@ -3638,13 +3750,13 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)-> ...@@ -3638,13 +3750,13 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)->
CLIENT_kick_reconnect(client, buffer) CLIENT_kick_reconnect(client, buffer)
else else
ygopro.stoc_send_chat(client, "${deck_incorrect_reconnect}", ygopro.constants.COLORS.RED) ygopro.stoc_send_chat(client, "${deck_incorrect_reconnect}", ygopro.constants.COLORS.RED)
ygopro.stoc_send(client, 'HS_PLAYER_CHANGE', {
status: (client.pos << 4) | 0xa
})
ygopro.stoc_send(client, 'ERROR_MSG', { ygopro.stoc_send(client, 'ERROR_MSG', {
msg: 2, msg: 2,
code: 0 code: 0
}) })
ygopro.stoc_send(client, 'HS_PLAYER_CHANGE', {
status: (client.pos << 4) | 0xa
})
return true return true
room=ROOM_all[client.rid] room=ROOM_all[client.rid]
return false unless room return false unless room
...@@ -3670,17 +3782,20 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)-> ...@@ -3670,17 +3782,20 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)->
CLIENT_kick(room.dueling_players[oppo_pos - win_pos]) CLIENT_kick(room.dueling_players[oppo_pos - win_pos])
CLIENT_kick(room.dueling_players[oppo_pos - win_pos + 1]) if room.hostinfo.mode == 2 CLIENT_kick(room.dueling_players[oppo_pos - win_pos + 1]) if room.hostinfo.mode == 2
return true return true
struct = ygopro.structs.get("deck")
struct._setBuff(buffer)
deck_ok = (msg) -> deck_ok = (msg) ->
ygopro.stoc_send_chat(client, msg, ygopro.constants.COLORS.BABYBLUE) await ygopro.stoc_send_chat(client, msg, ygopro.constants.COLORS.BABYBLUE)
return false return false
deck_bad = (msg) -> deck_bad = (msg) ->
struct.set("mainc", 1)
struct.set("sidec", 1)
struct.set("deckbuf", [4392470, 4392470])
ygopro.stoc_send_chat(client, msg, ygopro.constants.COLORS.RED) ygopro.stoc_send_chat(client, msg, ygopro.constants.COLORS.RED)
return false if room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN
ygopro.stoc_send(client, 'HS_PLAYER_CHANGE', {
status: (client.pos << 4) | 0xa
})
ygopro.stoc_send(client, 'ERROR_MSG', {
msg: 2,
code: 0
})
return true
if room.random_type or room.arena if room.random_type or room.arena
if client.pos == 0 if client.pos == 0
room.waiting_for_player = room.waiting_for_player2 room.waiting_for_player = room.waiting_for_player2
...@@ -3729,15 +3844,9 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)-> ...@@ -3729,15 +3844,9 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)->
found_deck=deck found_deck=deck
if found_deck if found_deck
deck_text = await fs.promises.readFile(settings.modules.tournament_mode.deck_path+found_deck,{encoding:"ASCII"}) deck_text = await fs.promises.readFile(settings.modules.tournament_mode.deck_path+found_deck,{encoding:"ASCII"})
deck_array=deck_text.split(/\r?\n/) deck_obj = YGOProDeck.fromYdkString(deck_text)
deck_main=[] deck_main=deck_obj.main.concat(deck_obj.extra)
deck_side=[] deck_side=deck_obj.side
current_deck=deck_main
for line in deck_array
if line.indexOf("!side")>=0
current_deck=deck_side
card=parseInt(line)
current_deck.push(card) unless isNaN(card) or line.endsWith("#")
if _.isEqual(buff_main, deck_main) and _.isEqual(buff_side, deck_side) if _.isEqual(buff_main, deck_main) and _.isEqual(buff_side, deck_side)
#log.info("deck ok: " + client.name) #log.info("deck ok: " + client.name)
return deck_ok("${deck_correct_part1} #{found_deck} ${deck_correct_part2}") return deck_ok("${deck_correct_part1} #{found_deck} ${deck_correct_part2}")
...@@ -3749,11 +3858,12 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)-> ...@@ -3749,11 +3858,12 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)->
return deck_bad("#{client.name}${deck_not_found}") return deck_bad("#{client.name}${deck_not_found}")
await return false await return false
ygopro.ctos_follow 'RESPONSE', false, (buffer, info, client, server, datas)-> ygopro.ctos_follow 'RESPONSE', true, (buffer, info, client, server, datas)->
room=ROOM_all[client.rid] room=ROOM_all[client.rid]
return unless room and (room.random_type or room.arena) if room and (room.random_type or room.arena)
room.refreshLastActiveTime() room.refreshLastActiveTime()
await return await msg_polyfill.polyfillResponse(client.actual_version, client.last_game_msg_title, buffer)
return false
ygopro.stoc_follow 'TIME_LIMIT', true, (buffer, info, client, server, datas)-> ygopro.stoc_follow 'TIME_LIMIT', true, (buffer, info, client, server, datas)->
room=ROOM_all[client.rid] room=ROOM_all[client.rid]
...@@ -4061,7 +4171,7 @@ if true ...@@ -4061,7 +4171,7 @@ if true
users: _.sortBy((for player in room.players when player.pos? users: _.sortBy((for player in room.players when player.pos?
id: (-1).toString(), id: (-1).toString(),
name: player.name, name: player.name,
ip: if settings.modules.http.show_ip and pass_validated and !player.is_local then player.ip.slice(7) else null, ip: if settings.modules.http.show_ip and pass_validated and !player.is_local then toIpv4(player.ip) else null,
status: if settings.modules.http.show_info and room.duel_stage != ygopro.constants.DUEL_STAGE.BEGIN and player.pos != 7 then ( status: if settings.modules.http.show_info and room.duel_stage != ygopro.constants.DUEL_STAGE.BEGIN and player.pos != 7 then (
score: room.scores[player.name_vpass], score: room.scores[player.name_vpass],
lp: if player.lp? then player.lp else room.hostinfo.start_lp, lp: if player.lp? then player.lp else room.hostinfo.start_lp,
...@@ -4347,19 +4457,13 @@ if true ...@@ -4347,19 +4457,13 @@ if true
ip6addr = require('ip6addr') ip6addr = require('ip6addr')
neosRequestListener = (client, req) -> neosRequestListener = (client, req) ->
physicalAddress = req.socket.remoteAddress
if settings.modules.neos.trusted_proxies.some((trusted) ->
cidr = if trusted.includes('/') then ip6addr.createCIDR(trusted) else ip6addr.createAddrRange(trusted, trusted)
return cidr.contains(physicalAddress)
)
ipHeader = req.headers[settings.modules.neos.trusted_proxy_header]
if ipHeader
client.ip = ipHeader.split(',')[0].trim()
if !client.ip
client.ip = physicalAddress
client.setTimeout = () -> true client.setTimeout = () -> true
client.destroy = () -> client.close() client.destroy = () -> client.close()
client.isWs = true client.isWs = true
client.physical_ip = req.socket.remoteAddress or ""
xff_ip = req.headers[settings.modules.neos.trusted_proxy_header]
if CLIENT_set_ip(client, xff_ip)
return
netRequestHandler(client) netRequestHandler(client)
......
// Generated by CoffeeScript 2.7.0 // Generated by CoffeeScript 2.7.0
(function() { (function() {
// 标准库 // 标准库
var CLIENT_check_vip, CLIENT_get_absolute_pos, CLIENT_get_authorize_key, CLIENT_get_kick_reconnect_target, CLIENT_get_partner, CLIENT_get_save_data, CLIENT_heartbeat_register, CLIENT_heartbeat_unregister, CLIENT_import_data, CLIENT_is_able_to_kick_reconnect, CLIENT_is_able_to_reconnect, CLIENT_is_banned_by_mc, CLIENT_is_player, CLIENT_kick, CLIENT_kick_reconnect, CLIENT_pre_reconnect, CLIENT_reconnect, CLIENT_reconnect_register, CLIENT_reconnect_unregister, CLIENT_send_pre_reconnect_info, CLIENT_send_reconnect_info, CLIENT_send_replays, CLIENT_send_replays_and_kick, CLIENT_send_vip_status, CLIENT_use_cdkey, Q, ROOM_all, ROOM_bad_ip, ROOM_ban_player, ROOM_clear_disconnect, ROOM_connected_ip, ROOM_find_by_name, ROOM_find_by_pid, ROOM_find_by_port, ROOM_find_by_title, ROOM_find_or_create_ai, ROOM_find_or_create_by_name, ROOM_find_or_create_random, ROOM_kick, ROOM_player_flee, ROOM_player_get_score, ROOM_player_lose, ROOM_player_win, ROOM_players_oppentlist, ROOM_unwelcome, ROOM_validate, ReplayParser, ResolveData, Room, SERVER_clear_disconnect, SERVER_kick, SOCKET_flush_data, VIP_generate_cdkeys, _, _async, addCallback, athleticChecker, auth, axios, badwordR, badwords, ban_user, bunyan, challonge, checkFileExists, concat_name, createDirectoryIfNotExists, crypto, dataManager, deck_name_match, dialogues, disconnect_list, exec, execFile, extra_mode_list, fs, geoip, getDuelLogQueryFromQs, getSeedTimet, get_memory_usage, http, httpRequestListener, importOldConfig, import_datas, init, ip6addr, lflists, loadJSON, loadJSONAsync, loadLFList, loadRemoteData, load_dialogues, load_dialogues_custom, load_tips, load_tips_zh, load_words, log, long_resolve_cards, memory_usage, merge, moment, moment_long_ago_string, moment_now, moment_now_string, neosRequestListener, net, netRequestHandler, os, osu, path, qs, real_windbot_server_ip, release_disconnect, report_to_big_brother, request, roomlist, rooms_count, setting_change, setting_get, setting_save, settings, spawn, spawnSync, spawn_windbot, tips, url, users_cache, util, utility, wait_room_start, wait_room_start_arena, windbot_looplimit, windbot_process, windbots, words, ygopro, zlib; var Aragami, CLIENT_check_vip, CLIENT_get_absolute_pos, CLIENT_get_authorize_key, CLIENT_get_kick_reconnect_target, CLIENT_get_partner, CLIENT_get_save_data, CLIENT_heartbeat_register, CLIENT_heartbeat_unregister, CLIENT_import_data, CLIENT_is_able_to_kick_reconnect, CLIENT_is_able_to_reconnect, CLIENT_is_banned_by_mc, CLIENT_is_player, CLIENT_kick, CLIENT_kick_reconnect, CLIENT_pre_reconnect, CLIENT_reconnect, CLIENT_reconnect_register, CLIENT_reconnect_unregister, CLIENT_send_pre_reconnect_info, CLIENT_send_reconnect_info, CLIENT_send_replays, CLIENT_send_replays_and_kick, CLIENT_send_vip_status, CLIENT_set_ip, CLIENT_use_cdkey, Q, ROOM_all, ROOM_bad_ip, ROOM_ban_player, ROOM_clear_disconnect, ROOM_connected_ip, ROOM_find_by_name, ROOM_find_by_pid, ROOM_find_by_port, ROOM_find_by_title, ROOM_find_or_create_ai, ROOM_find_or_create_by_name, ROOM_find_or_create_random, ROOM_kick, ROOM_player_flee, ROOM_player_get_score, ROOM_player_lose, ROOM_player_win, ROOM_players_oppentlist, ROOM_unwelcome, ROOM_validate, ReplayParser, ResolveData, Room, SERVER_clear_disconnect, SERVER_kick, SOCKET_flush_data, VIP_generate_cdkeys, YGOProDeck, _, _async, addCallback, aragami, aragami_classes, athleticChecker, auth, axios, badwordR, badwords, ban_user, bunyan, challonge, checkFileExists, concat_name, createDirectoryIfNotExists, crypto, dataManager, deck_name_match, dialogues, disconnect_list, exec, execFile, extra_mode_list, fs, geoip, getDuelLogQueryFromQs, getRealIp, get_memory_usage, http, httpRequestListener, importOldConfig, import_datas, init, ip6addr, isTrustedProxy, lflists, loadJSON, loadJSONAsync, loadLFList, loadRemoteData, load_dialogues, load_dialogues_custom, load_tips, load_tips_zh, load_words, log, long_resolve_cards, memory_usage, merge, moment, moment_long_ago_string, moment_now, moment_now_string, msg_polyfill, neosRequestListener, net, netRequestHandler, os, osu, path, qs, real_windbot_server_ip, release_disconnect, report_to_big_brother, request, roomlist, rooms_count, setting_change, setting_get, setting_save, settings, spawn, spawnSync, spawn_windbot, tips, toIpv4, toIpv6, url, users_cache, util, utility, wait_room_start, wait_room_start_arena, windbot_looplimit, windbot_process, windbots, words, ygopro, zlib;
net = require('net'); net = require('net');
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
} }
}); });
import_datas = global.import_datas = ["abuse_count", "ban_mc", "vip", "vpass", "rag", "rid", "is_post_watcher", "retry_count", "name", "pass", "name_vpass", "is_first", "lp", "card_count", "is_host", "pos", "surrend_confirm", "kick_count", "deck_saved", "main", "side", "side_interval", "side_tcount", "selected_preduel", "last_game_msg", "last_game_msg_title", "last_hint_msg", "start_deckbuf", "challonge_info", "ready_trap", "join_time", "arena_quit_free", "replays_sent", "victory_words"]; import_datas = global.import_datas = ["abuse_count", "ban_mc", "vip", "vpass", "rag", "rid", "is_post_watcher", "retry_count", "name", "pass", "name_vpass", "is_first", "lp", "card_count", "is_host", "pos", "surrend_confirm", "kick_count", "deck_saved", "main", "side", "side_interval", "side_tcount", "selected_preduel", "last_game_msg", "last_game_msg_title", "last_hint_msg", "start_deckbuf", "challonge_info", "ready_trap", "join_time", "arena_quit_free", "replays_sent", "victory_words", "actual_version"];
merge = require('deepmerge'); merge = require('deepmerge');
...@@ -85,6 +85,16 @@ ...@@ -85,6 +85,16 @@
Q = require("q"); Q = require("q");
YGOProDeck = require('ygopro-deck-encode').default;
Aragami = require('aragami').Aragami;
aragami = global.aragami = new Aragami(); // we use memory mode only
aragami_classes = global.aragami_classes = require('./aragami-classes.js');
msg_polyfill = global.msg_polyfill = require('./msg-polyfill/index.js');
//heapdump = require 'heapdump' //heapdump = require 'heapdump'
checkFileExists = async(path) => { checkFileExists = async(path) => {
var e; var e;
...@@ -375,7 +385,7 @@ ...@@ -375,7 +385,7 @@
}; };
init = async function() { init = async function() {
var AthleticChecker, Challonge, DataManager, chat_color, config, cppversion, defaultConfig, default_data, dirPath, dns, e, get_rooms_count, http_server, https, httpsOptions, https_server, imported, j, key, keysFromEnv, l, len, len1, len2, m, main_http_server, mkdirList, neosHttpServer, neosWsServer, pgClient, pg_client, pg_query, plugin_filename, plugin_list, plugin_path, postData, settingKey, val, valFromDefault, vip_info, ws; var AthleticChecker, Challonge, DataManager, chat_color, config, cppversion, defaultConfig, default_data, dirPath, dns, e, expansions, get_rooms_count, http_server, https, httpsOptions, https_server, imported, j, key, keysFromEnv, l, len, len1, len2, len3, m, main_http_server, mkdirList, n, neosHttpServer, neosWsServer, pgClient, pg_client, pg_query, plugin_filename, plugin_list, plugin_path, postData, ref, settingKey, val, valFromDefault, vip_info, ws;
log.info('Reading config.'); log.info('Reading config.');
await createDirectoryIfNotExists("./config"); await createDirectoryIfNotExists("./config");
await importOldConfig(); await importOldConfig();
...@@ -518,6 +528,11 @@ ...@@ -518,6 +528,11 @@
settings.modules.hide_name = "start"; settings.modules.hide_name = "start";
imported = true; imported = true;
} }
if (settings.modules.neos.trusted_proxies) {
settings.modules.trusted_proxies = settings.modules.neos.trusted_proxies;
delete settings.modules.neos.trusted_proxies;
imported = true;
}
//finish //finish
keysFromEnv = Object.keys(process.env).filter((key) => { keysFromEnv = Object.keys(process.env).filter((key) => {
return key.startsWith('SRVPRO_'); return key.startsWith('SRVPRO_');
...@@ -635,7 +650,7 @@ ...@@ -635,7 +650,7 @@
} }
try { try {
log.info("Reading YGOPro version."); log.info("Reading YGOPro version.");
cppversion = parseInt(((await fs.promises.readFile('ygopro/gframe/game.cpp', 'utf8'))).match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16'); cppversion = parseInt(((await fs.promises.readFile(path.resolve(settings.modules.ygopro_path, 'gframe', 'game.cpp'), 'utf8'))).match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16');
await setting_change(settings, "version", cppversion); await setting_change(settings, "version", cppversion);
log.info("ygopro version 0x" + settings.version.toString(16), "(from source code)"); log.info("ygopro version 0x" + settings.version.toString(16), "(from source code)");
} catch (error1) { } catch (error1) {
...@@ -644,8 +659,12 @@ ...@@ -644,8 +659,12 @@
} }
// load the lflist of current date // load the lflist of current date
log.info("Reading banlists."); log.info("Reading banlists.");
await loadLFList('ygopro/expansions/lflist.conf'); ref = settings.modules.expansions_path;
await loadLFList('ygopro/lflist.conf'); for (l = 0, len1 = ref.length; l < len1; l++) {
expansions = ref[l];
await loadLFList(path.resolve(settings.modules.ygopro_path, expansions, 'lflist.conf'));
}
await loadLFList(path.resolve(settings.modules.ygopro_path, 'lflist.conf'));
badwordR = global.badwordR = {}; badwordR = global.badwordR = {};
badwordR.level0 = new RegExp('(?:' + badwords.level0.join(')|(?:') + ')', 'i'); badwordR.level0 = new RegExp('(?:' + badwords.level0.join(')|(?:') + ')', 'i');
badwordR.level1 = new RegExp('(?:' + badwords.level1.join(')|(?:') + ')', 'i'); badwordR.level1 = new RegExp('(?:' + badwords.level1.join(')|(?:') + ')', 'i');
...@@ -660,10 +679,10 @@ ...@@ -660,10 +679,10 @@
if (settings.modules.max_rooms_count) { if (settings.modules.max_rooms_count) {
rooms_count = 0; rooms_count = 0;
get_rooms_count = function() { get_rooms_count = function() {
var _rooms_count, l, len1, room; var _rooms_count, len2, m, room;
_rooms_count = 0; _rooms_count = 0;
for (l = 0, len1 = ROOM_all.length; l < len1; l++) { for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
room = ROOM_all[l]; room = ROOM_all[m];
if (room && room.established) { if (room && room.established) {
_rooms_count++; _rooms_count++;
} }
...@@ -686,7 +705,7 @@ ...@@ -686,7 +705,7 @@
long_resolve_cards = global.long_resolve_cards = (await loadJSONAsync('./data/long_resolve_cards.json')); long_resolve_cards = global.long_resolve_cards = (await loadJSONAsync('./data/long_resolve_cards.json'));
} }
if (settings.modules.tournament_mode.enable_recover) { if (settings.modules.tournament_mode.enable_recover) {
ReplayParser = global.ReplayParser = require("./Replay.js"); ReplayParser = global.ReplayParser = (require("./Replay.js")).Replay;
} }
if (settings.modules.athletic_check.enabled) { if (settings.modules.athletic_check.enabled) {
AthleticChecker = require("./athletic-check.js").AthleticChecker; AthleticChecker = require("./athletic-check.js").AthleticChecker;
...@@ -745,9 +764,9 @@ ...@@ -745,9 +764,9 @@
if (settings.modules.tips.enabled) { if (settings.modules.tips.enabled) {
if (settings.modules.tips.interval) { if (settings.modules.tips.interval) {
setInterval(function() { setInterval(function() {
var l, len1, room; var len2, m, room;
for (l = 0, len1 = ROOM_all.length; l < len1; l++) { for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
room = ROOM_all[l]; room = ROOM_all[m];
if (room && room.established && room.duel_stage !== ygopro.constants.END) { if (room && room.established && room.duel_stage !== ygopro.constants.END) {
if (room.duel_stage !== ygopro.constants.DUEL_STAGE.DUELING) { if (room.duel_stage !== ygopro.constants.DUEL_STAGE.DUELING) {
ygopro.stoc_send_random_tip_to_room(room); ygopro.stoc_send_random_tip_to_room(room);
...@@ -758,9 +777,9 @@ ...@@ -758,9 +777,9 @@
} }
if (settings.modules.tips.interval_ingame) { if (settings.modules.tips.interval_ingame) {
setInterval(function() { setInterval(function() {
var l, len1, room; var len2, m, room;
for (l = 0, len1 = ROOM_all.length; l < len1; l++) { for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
room = ROOM_all[l]; room = ROOM_all[m];
if (room && room.established && room.duel_stage !== ygopro.constants.END) { if (room && room.established && room.duel_stage !== ygopro.constants.END) {
if (room.duel_stage === ygopro.constants.DUEL_STAGE.DUELING) { if (room.duel_stage === ygopro.constants.DUEL_STAGE.DUELING) {
ygopro.stoc_send_random_tip_to_room(room); ygopro.stoc_send_random_tip_to_room(room);
...@@ -796,9 +815,9 @@ ...@@ -796,9 +815,9 @@
} }
// clean zombie rooms // clean zombie rooms
setInterval(function() { setInterval(function() {
var l, len1, room; var len2, m, room;
for (l = 0, len1 = ROOM_all.length; l < len1; l++) { for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
room = ROOM_all[l]; room = ROOM_all[m];
if (room && !room.players.length) { if (room && !room.players.length) {
room.terminate(); room.terminate();
} }
...@@ -806,9 +825,9 @@ ...@@ -806,9 +825,9 @@
}, 300000); }, 300000);
if (settings.modules.random_duel.enabled) { if (settings.modules.random_duel.enabled) {
setInterval(async function() { setInterval(async function() {
var l, len1, room, time_passed; var len2, m, room, time_passed;
for (l = 0, len1 = ROOM_all.length; l < len1; l++) { for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
room = ROOM_all[l]; room = ROOM_all[m];
if (!(room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.random_type && room.last_active_time && room.waiting_for_player && room.get_disconnected_count() === 0 && (!settings.modules.side_timeout || room.duel_stage !== ygopro.constants.DUEL_STAGE.SIDING) && !room.recovered)) { if (!(room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.random_type && room.last_active_time && room.waiting_for_player && room.get_disconnected_count() === 0 && (!settings.modules.side_timeout || room.duel_stage !== ygopro.constants.DUEL_STAGE.SIDING) && !room.recovered)) {
continue; continue;
} }
...@@ -830,9 +849,9 @@ ...@@ -830,9 +849,9 @@
} }
if (settings.modules.mycard.enabled) { if (settings.modules.mycard.enabled) {
setInterval(function() { setInterval(function() {
var l, len1, len2, m, player, room, time_passed, waited_time; var len2, len3, m, n, player, room, time_passed, waited_time;
for (l = 0, len1 = ROOM_all.length; l < len1; l++) { for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
room = ROOM_all[l]; room = ROOM_all[m];
if (!(room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.arena && room.last_active_time && room.waiting_for_player && room.get_disconnected_count() === 0 && (!settings.modules.side_timeout || room.duel_stage !== ygopro.constants.DUEL_STAGE.SIDING) && !room.recovered)) { if (!(room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.arena && room.last_active_time && room.waiting_for_player && room.get_disconnected_count() === 0 && (!settings.modules.side_timeout || room.duel_stage !== ygopro.constants.DUEL_STAGE.SIDING) && !room.recovered)) {
continue; continue;
} }
...@@ -849,8 +868,8 @@ ...@@ -849,8 +868,8 @@
} }
} }
if (true) { // settings.modules.arena_mode.punish_quit_before_match if (true) { // settings.modules.arena_mode.punish_quit_before_match
for (m = 0, len2 = ROOM_all.length; m < len2; m++) { for (n = 0, len3 = ROOM_all.length; n < len3; n++) {
room = ROOM_all[m]; room = ROOM_all[n];
if (!(room && room.arena && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.get_playing_player().length < 2)) { if (!(room && room.arena && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.get_playing_player().length < 2)) {
continue; continue;
} }
...@@ -870,13 +889,13 @@ ...@@ -870,13 +889,13 @@
} }
if (settings.modules.heartbeat_detection.enabled) { if (settings.modules.heartbeat_detection.enabled) {
setInterval(function() { setInterval(function() {
var l, len1, len2, m, player, ref, room; var len2, len3, m, n, player, ref1, room;
for (l = 0, len1 = ROOM_all.length; l < len1; l++) { for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
room = ROOM_all[l]; room = ROOM_all[m];
if (room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && (room.hostinfo.time_limit === 0 || room.duel_stage !== ygopro.constants.DUEL_STAGE.DUELING) && !room.windbot) { if (room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && (room.hostinfo.time_limit === 0 || room.duel_stage !== ygopro.constants.DUEL_STAGE.DUELING) && !room.windbot) {
ref = room.get_playing_player(); ref1 = room.get_playing_player();
for (m = 0, len2 = ref.length; m < len2; m++) { for (n = 0, len3 = ref1.length; n < len3; n++) {
player = ref[m]; player = ref1[n];
if (player && (room.duel_stage !== ygopro.constants.DUEL_STAGE.SIDING || player.selected_preduel)) { if (player && (room.duel_stage !== ygopro.constants.DUEL_STAGE.SIDING || player.selected_preduel)) {
CLIENT_heartbeat_register(player, true); CLIENT_heartbeat_register(player, true);
} }
...@@ -889,10 +908,10 @@ ...@@ -889,10 +908,10 @@
spawn_windbot(); spawn_windbot();
} }
setInterval(function() { setInterval(function() {
var l, len1, results, room; var len2, m, results, room;
results = []; results = [];
for (l = 0, len1 = ROOM_all.length; l < len1; l++) { for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
room = ROOM_all[l]; room = ROOM_all[m];
if (!(room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.hostinfo.auto_death && !room.auto_death_triggered && moment_now.diff(room.start_time) > 60000 * room.hostinfo.auto_death)) { if (!(room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.hostinfo.auto_death && !room.auto_death_triggered && moment_now.diff(room.start_time) > 60000 * room.hostinfo.auto_death)) {
continue; continue;
} }
...@@ -939,15 +958,15 @@ ...@@ -939,15 +958,15 @@
neosHttpServer.listen(settings.modules.neos.port); neosHttpServer.listen(settings.modules.neos.port);
} }
mkdirList = ["./plugins", settings.modules.tournament_mode.deck_path, settings.modules.tournament_mode.replay_path, settings.modules.tournament_mode.log_save_path, settings.modules.deck_log.local]; mkdirList = ["./plugins", settings.modules.tournament_mode.deck_path, settings.modules.tournament_mode.replay_path, settings.modules.tournament_mode.log_save_path, settings.modules.deck_log.local];
for (l = 0, len1 = mkdirList.length; l < len1; l++) { for (m = 0, len2 = mkdirList.length; m < len2; m++) {
dirPath = mkdirList[l]; dirPath = mkdirList[m];
await createDirectoryIfNotExists(dirPath); await createDirectoryIfNotExists(dirPath);
} }
plugin_list = (await fs.promises.readdir("./plugins")); plugin_list = (await fs.promises.readdir("./plugins"));
for (m = 0, len2 = plugin_list.length; m < len2; m++) { for (n = 0, len3 = plugin_list.length; n < len3; n++) {
plugin_filename = plugin_list[m]; plugin_filename = plugin_list[n];
if (plugin_filename.endsWith('.js')) { if (plugin_filename.endsWith('.js')) {
plugin_path = process.cwd() + "/plugins/" + plugin_filename; plugin_path = path.resolve(process.cwd(), "plugins", plugin_filename);
require(plugin_path); require(plugin_path);
log.info("Plugin loaded:", plugin_filename); log.info("Plugin loaded:", plugin_filename);
} }
...@@ -1709,6 +1728,67 @@ ...@@ -1709,6 +1728,67 @@
CLIENT_kick(client); CLIENT_kick(client);
}; };
toIpv4 = global.toIpv4 = function(ip) {
if (ip.startsWith('::ffff:')) {
return ip.slice(7);
}
return ip;
};
toIpv6 = global.toIpv6 = function(ip) {
if (/^(\d{1,3}\.){3}\d{1,3}$/.test(ip)) {
return '::ffff:' + ip;
}
return ip;
};
isTrustedProxy = global.isTrustedProxy = function(ip) {
return settings.modules.trusted_proxies.some(function(trusted) {
var cidr;
cidr = trusted.includes('/') ? ip6addr.createCIDR(trusted) : ip6addr.createAddrRange(trusted, trusted);
return cidr.contains(ip);
});
};
getRealIp = global.getRealIp = function(physical_ip, xff_ip) {
if (!xff_ip || xff_ip === physical_ip) {
return toIpv6(physical_ip);
}
if (isTrustedProxy(physical_ip)) {
return toIpv6(xff_ip.split(',')[0].trim());
}
log.warn(`Untrusted proxy detected: ${physical_ip} -> ${xff_ip}`);
return toIpv6(physical_ip);
};
CLIENT_set_ip = global.CLIENT_set_ip = function(client, xff_ip) {
var client_prev_ip, connect_count;
client_prev_ip = client.ip;
client.ip = getRealIp(client.physical_ip, xff_ip);
if (client_prev_ip === client.ip) {
return false;
}
if (client_prev_ip && ROOM_connected_ip[client_prev_ip] && ROOM_connected_ip[client_prev_ip] > 0) {
ROOM_connected_ip[client_prev_ip]--;
if (ROOM_connected_ip[client_prev_ip] <= 0) {
delete ROOM_connected_ip[client_prev_ip];
}
}
client.is_local = client.ip && (client.ip.includes('127.0.0.1') || client.ip.includes(real_windbot_server_ip));
connect_count = ROOM_connected_ip[client.ip] || 0;
if (!settings.modules.test_mode.no_connect_count_limit && !client.is_local && !isTrustedProxy(client.ip)) {
connect_count++;
}
ROOM_connected_ip[client.ip] = connect_count;
// log.info "connect", client.ip, ROOM_connected_ip[client.ip]
if (ROOM_bad_ip[client.ip] > 5 || ROOM_connected_ip[client.ip] > 10) {
log.info('BAD IP', client.ip);
client.destroy();
return true;
}
return false;
};
SOCKET_flush_data = global.SOCKET_flush_data = async function(sk, datas) { SOCKET_flush_data = global.SOCKET_flush_data = async function(sk, datas) {
var buffer; var buffer;
if (!sk || sk.isClosed) { if (!sk || sk.isClosed) {
...@@ -1721,12 +1801,6 @@ ...@@ -1721,12 +1801,6 @@
return true; return true;
}; };
getSeedTimet = global.getSeedTimet = function(count) {
return _.range(count).map(() => {
return 0;
});
};
Room = class Room { Room = class Room {
constructor(name, hostinfo) { constructor(name, hostinfo) {
var death_time, draw_count, duel_rule, extra_mode_func, lflist, param, rule, start_hand, start_lp, time_limit; var death_time, draw_count, duel_rule, extra_mode_func, lflist, param, rule, start_hand, start_lp, time_limit;
...@@ -1976,7 +2050,7 @@ ...@@ -1976,7 +2050,7 @@
} }
spawn(firstSeed) { spawn(firstSeed) {
var duel_rule_flags, e, i, j, l, param, seeds; var duel_rule_flags, e, firstSeedBuf, i, j, param, ref;
duel_rule_flags = this.hostinfo.duel_rule & 0xf; duel_rule_flags = this.hostinfo.duel_rule & 0xf;
if (this.hostinfo.sideins) { if (this.hostinfo.sideins) {
duel_rule_flags |= 0x10; duel_rule_flags |= 0x10;
...@@ -1986,20 +2060,22 @@ ...@@ -1986,20 +2060,22 @@
} }
param = [0, this.hostinfo.lflist, this.hostinfo.rule, this.hostinfo.mode, duel_rule_flags, (this.hostinfo.no_check_deck ? 'T' : 'F'), (this.hostinfo.no_shuffle_deck ? 'T' : 'F'), this.hostinfo.start_lp, this.hostinfo.start_hand, this.hostinfo.draw_count, this.hostinfo.time_limit, this.hostinfo.replay_mode]; param = [0, this.hostinfo.lflist, this.hostinfo.rule, this.hostinfo.mode, duel_rule_flags, (this.hostinfo.no_check_deck ? 'T' : 'F'), (this.hostinfo.no_shuffle_deck ? 'T' : 'F'), this.hostinfo.start_lp, this.hostinfo.start_hand, this.hostinfo.draw_count, this.hostinfo.time_limit, this.hostinfo.replay_mode];
if (firstSeed) { if (firstSeed) {
param.push(firstSeed); // new replay with extended header and long seed
seeds = getSeedTimet(2); firstSeedBuf = Buffer.allocUnsafe(firstSeed.length * 4);
for (i = j = 0; j < 2; i = ++j) { for (i = j = 0, ref = firstSeed.length; (0 <= ref ? j < ref : j > ref); i = 0 <= ref ? ++j : --j) {
param.push(seeds[i]); firstSeedBuf.writeUInt32LE(firstSeed[i], i * 4);
}
} else {
seeds = getSeedTimet(3);
for (i = l = 0; l < 3; i = ++l) {
param.push(seeds[i]);
} }
param.push(firstSeedBuf.toString('base64'));
} }
try { try {
this.process = spawn('./ygopro', param, { this.process = spawn(path.resolve(settings.modules.ygopro_path, settings.modules.ygopro_exec_path), param, {
cwd: 'ygopro' cwd: path.resolve(settings.modules.ygopro_path),
env: {
...process.env,
YGOPRO_EXPANSIONS: settings.modules.expansions_path.map(function(s) {
return path.resolve(settings.modules.ygopro_path, s);
}).join(',')
}
}); });
this.process_pid = this.process.pid; this.process_pid = this.process.pid;
this.process.on('error', (err) => { this.process.on('error', (err) => {
...@@ -2024,10 +2100,10 @@ ...@@ -2024,10 +2100,10 @@
this.port = parseInt(data); this.port = parseInt(data);
_.each(this.players, (player) => { _.each(this.players, (player) => {
player.server.connect(this.port, '127.0.0.1', async function() { player.server.connect(this.port, '127.0.0.1', async function() {
var buffer, len, m, ref; var buffer, l, len, ref1;
ref = player.pre_establish_buffers; ref1 = player.pre_establish_buffers;
for (m = 0, len = ref.length; m < len; m++) { for (l = 0, len = ref1.length; l < len; l++) {
buffer = ref[m]; buffer = ref1[l];
await ygopro.helper.send(player.server, buffer); await ygopro.helper.send(player.server, buffer);
} }
player.established = true; player.established = true;
...@@ -2216,7 +2292,13 @@ ...@@ -2216,7 +2292,13 @@
} }
try { try {
this.recover_replay = (await ReplayParser.fromFile(settings.modules.tournament_mode.replay_path + this.recover_duel_log.replayFileName)); this.recover_replay = (await ReplayParser.fromFile(settings.modules.tournament_mode.replay_path + this.recover_duel_log.replayFileName));
this.spawn(this.recover_replay.header.seed); if (!this.recover_replay.header.seedSequence.length) {
// it's old replay, unsupported
log.warn("LOAD RECOVER REPLAY FAIL: Old replay format, unsupported", this.recover_duel_log.replayFileName);
this.terminate();
return false;
}
this.spawn(this.recover_replay.header.seedSequence);
return true; return true;
} catch (error1) { } catch (error1) {
e = error1; e = error1;
...@@ -2724,22 +2806,13 @@ ...@@ -2724,22 +2806,13 @@
// 网络连接 // 网络连接
netRequestHandler = function(client) { netRequestHandler = function(client) {
var closeHandler, connect_count, dataHandler, server; var closeHandler, dataHandler, server;
if (!client.isWs) { if (!client.isWs) {
client.ip = client.remoteAddress || ''; client.physical_ip = client.remoteAddress || "";
} if (CLIENT_set_ip(client)) {
client.is_local = client.ip && (client.ip.includes('127.0.0.1') || client.ip.includes(real_windbot_server_ip));
connect_count = ROOM_connected_ip[client.ip] || 0;
if (!settings.modules.test_mode.no_connect_count_limit && !client.is_local) {
connect_count++;
}
ROOM_connected_ip[client.ip] = connect_count;
//log.info "connect", client.ip, ROOM_connected_ip[client.ip]
if (ROOM_bad_ip[client.ip] > 5 || ROOM_connected_ip[client.ip] > 10) {
log.info('BAD IP', client.ip);
client.destroy();
return; return;
} }
}
// server stand for the connection to ygopro server process // server stand for the connection to ygopro server process
server = new net.Socket(); server = new net.Socket();
client.server = server; client.server = server;
...@@ -2748,7 +2821,7 @@ ...@@ -2748,7 +2821,7 @@
// 释放处理 // 释放处理
closeHandler = function(error) { closeHandler = function(error) {
var room; var connect_count, room;
//log.info "client closed", client.name, error, client.isClosed //log.info "client closed", client.name, error, client.isClosed
//log.info "disconnect", client.ip, ROOM_connected_ip[client.ip] //log.info "disconnect", client.ip, ROOM_connected_ip[client.ip]
if (client.isClosed) { if (client.isClosed) {
...@@ -2756,10 +2829,14 @@ ...@@ -2756,10 +2829,14 @@
} }
room = ROOM_all[client.rid]; room = ROOM_all[client.rid];
connect_count = ROOM_connected_ip[client.ip]; connect_count = ROOM_connected_ip[client.ip];
if (connect_count > 0) { if (connect_count && connect_count > 0) {
connect_count--; connect_count--;
} if (connect_count === 0) {
delete ROOM_connected_ip[client.ip];
} else {
ROOM_connected_ip[client.ip] = connect_count; ROOM_connected_ip[client.ip] = connect_count;
}
}
client.isClosed = true; client.isClosed = true;
if (settings.modules.heartbeat_detection.enabled) { if (settings.modules.heartbeat_detection.enabled) {
CLIENT_heartbeat_unregister(client); CLIENT_heartbeat_unregister(client);
...@@ -2899,9 +2976,8 @@ ...@@ -2899,9 +2976,8 @@
preconnect = false; preconnect = false;
if (settings.modules.reconnect.enabled && client.pre_reconnecting_to_room) { if (settings.modules.reconnect.enabled && client.pre_reconnecting_to_room) {
ctos_filter = ["UPDATE_DECK"]; ctos_filter = ["UPDATE_DECK"];
} } else if (client.name === null) {
if (client.name === null) { ctos_filter = ["EXTERNAL_ADDRESS", "JOIN_GAME", "PLAYER_INFO"];
ctos_filter = ["JOIN_GAME", "PLAYER_INFO"];
preconnect = true; preconnect = true;
} }
handle_data = (await ygopro.helper.handleBuffer(ctos_buffer, "CTOS", ctos_filter, { handle_data = (await ygopro.helper.handleBuffer(ctos_buffer, "CTOS", ctos_filter, {
...@@ -2975,6 +3051,17 @@ ...@@ -2975,6 +3051,17 @@
// 功能模块 // 功能模块
// return true to cancel a synchronous message // return true to cancel a synchronous message
ygopro.ctos_follow('EXTERNAL_ADDRESS', true, function(buffer, info, client, server, datas) {
var ip_parts, ip_uint, xff_ip;
ip_uint = buffer.readUInt32BE(0);
if (ip_uint === 0) {
return false;
}
ip_parts = [(ip_uint >>> 24) & 0xFF, (ip_uint >>> 16) & 0xFF, (ip_uint >>> 8) & 0xFF, ip_uint & 0xFF];
xff_ip = ip_parts.join('.');
return CLIENT_set_ip(client, xff_ip);
});
ygopro.ctos_follow('PLAYER_INFO', true, async function(buffer, info, client, server, datas) { ygopro.ctos_follow('PLAYER_INFO', true, async function(buffer, info, client, server, datas) {
var geo, lang, name, name_full, struct, vpass; var geo, lang, name, name_full, struct, vpass;
// second PLAYER_INFO = attack // second PLAYER_INFO = attack
...@@ -3031,7 +3118,51 @@ ...@@ -3031,7 +3118,51 @@
}); });
ygopro.ctos_follow('JOIN_GAME', true, async function(buffer, info, client, server, datas) { ygopro.ctos_follow('JOIN_GAME', true, async function(buffer, info, client, server, datas) {
var available_logs, check_buffer_indentity, create_room_name, create_room_with_action, decrypted_buffer, duelLog, e, exactBan, i, id, index, j, l, len, len1, len2, len3, m, matching_match, matching_participant, n, pre_room, recover_match, ref, ref1, replay, replay_id, replays, room, secret, struct, tournament_data, userData, userDataRes, userUrl; var available_logs, check_buffer_indentity, check_version, create_room_name, create_room_with_action, decrypted_buffer, duelLog, e, exactBan, i, id, index, j, l, len, len1, len2, len3, m, matching_match, matching_participant, n, polyfill_version, pre_room, recover_match, ref, ref1, replay, replay_id, replays, room, secret, struct, tournament_data, userData, userDataRes, userUrl;
check_version = async function() {
var bad_version, blocker_obj, client_key;
bad_version = function(msg) {
ygopro.stoc_send_chat(client, msg, ygopro.constants.COLORS.RED);
ygopro.stoc_send(client, 'ERROR_MSG', {
msg: 4,
code: settings.version
});
CLIENT_kick(client);
return false;
};
if (info.version === settings.version) {
return true;
}
if (settings.alternative_versions.includes(info.version)) {
client_key = CLIENT_get_authorize_key(client);
if (!(await aragami.has(aragami_classes.ClientVersionBlocker, client_key))) {
blocker_obj = new aragami_classes.ClientVersionBlocker();
blocker_obj.clientKey = client_key;
await aragami.set(blocker_obj);
return bad_version("${version_to_polyfill}");
} else {
await aragami.del(aragami_classes.ClientVersionBlocker, client_key);
return true;
}
}
return bad_version(info.version < settings.version ? settings.modules.update : settings.modules.wait_update);
};
polyfill_version = async function() {
var struct;
if (client.actual_version) {
return;
}
// already polyfilled
client.actual_version = info.version;
if (info.version !== settings.version && settings.alternative_versions.includes(info.version)) {
info.version = settings.version;
struct = ygopro.structs.get("CTOS_JoinGame");
struct._setBuff(buffer);
struct.set("version", info.version);
buffer = struct.buffer;
ygopro.stoc_send_chat(client, "${version_polyfilled}", ygopro.constants.COLORS.BABYBLUE);
}
};
//log.info info //log.info info
info.pass = info.pass.trim(); info.pass = info.pass.trim();
client.pass = info.pass; client.pass = info.pass;
...@@ -3040,8 +3171,10 @@ ...@@ -3040,8 +3171,10 @@
return; return;
} else if (settings.modules.stop) { } else if (settings.modules.stop) {
ygopro.stoc_die(client, settings.modules.stop); ygopro.stoc_die(client, settings.modules.stop);
return;
} else if (info.pass === "Marshtomp" || info.pass === "the Big Brother") { } else if (info.pass === "Marshtomp" || info.pass === "the Big Brother") {
ygopro.stoc_die(client, "${bad_user_name}"); ygopro.stoc_die(client, "${bad_user_name}");
return;
} else if (info.pass.toUpperCase() === "R" && settings.modules.cloud_replay.enabled) { } else if (info.pass.toUpperCase() === "R" && settings.modules.cloud_replay.enabled) {
ygopro.stoc_send_chat(client, "${cloud_replay_hint}", ygopro.constants.COLORS.BABYBLUE); ygopro.stoc_send_chat(client, "${cloud_replay_hint}", ygopro.constants.COLORS.BABYBLUE);
replays = (await dataManager.getCloudReplaysFromKey(CLIENT_get_authorize_key(client))); replays = (await dataManager.getCloudReplaysFromKey(CLIENT_get_authorize_key(client)));
...@@ -3054,6 +3187,7 @@ ...@@ -3054,6 +3187,7 @@
code: 9 code: 9
}); });
CLIENT_kick(client); CLIENT_kick(client);
return;
} else if (info.pass.toUpperCase() === "IP") { } else if (info.pass.toUpperCase() === "IP") {
ygopro.stoc_send_chat(client, "IP: " + client.ip, ygopro.constants.COLORS.BABYBLUE); ygopro.stoc_send_chat(client, "IP: " + client.ip, ygopro.constants.COLORS.BABYBLUE);
ygopro.stoc_send(client, 'ERROR_MSG', { ygopro.stoc_send(client, 'ERROR_MSG', {
...@@ -3061,6 +3195,7 @@ ...@@ -3061,6 +3195,7 @@
code: 9 code: 9
}); });
CLIENT_kick(client); CLIENT_kick(client);
return;
} else if (info.pass.toUpperCase() === "RC" && settings.modules.tournament_mode.enable_recover) { } else if (info.pass.toUpperCase() === "RC" && settings.modules.tournament_mode.enable_recover) {
ygopro.stoc_send_chat(client, "${recover_replay_hint}", ygopro.constants.COLORS.BABYBLUE); ygopro.stoc_send_chat(client, "${recover_replay_hint}", ygopro.constants.COLORS.BABYBLUE);
available_logs = (await dataManager.getDuelLogFromRecoverSearch(client.name_vpass)); available_logs = (await dataManager.getDuelLogFromRecoverSearch(client.name_vpass));
...@@ -3073,22 +3208,21 @@ ...@@ -3073,22 +3208,21 @@
code: 9 code: 9
}); });
CLIENT_kick(client); CLIENT_kick(client);
return;
} else if (info.pass.slice(0, 2).toUpperCase() === "R#" && settings.modules.cloud_replay.enabled) { } else if (info.pass.slice(0, 2).toUpperCase() === "R#" && settings.modules.cloud_replay.enabled) {
replay_id = info.pass.split("#")[1]; replay_id = info.pass.split("#")[1];
replay = (await dataManager.getCloudReplayFromId(replay_id)); replay = (await dataManager.getCloudReplayFromId(replay_id));
await client.open_cloud_replay(replay); await client.open_cloud_replay(replay);
return;
} else if (info.pass.toUpperCase() === "W" && settings.modules.cloud_replay.enabled) { } else if (info.pass.toUpperCase() === "W" && settings.modules.cloud_replay.enabled) {
replay = (await dataManager.getRandomCloudReplay()); replay = (await dataManager.getRandomCloudReplay());
await client.open_cloud_replay(replay); await client.open_cloud_replay(replay);
} else if (info.version !== settings.version && !settings.alternative_versions.includes(info.version)) { return;
ygopro.stoc_send_chat(client, (info.version < settings.version ? settings.modules.update : settings.modules.wait_update), ygopro.constants.COLORS.RED); } else if (!(await check_version())) {
ygopro.stoc_send(client, 'ERROR_MSG', { return;
msg: 4,
code: settings.version
});
CLIENT_kick(client);
} else if (!info.pass.length && !settings.modules.random_duel.enabled && !settings.modules.windbot.enabled && !settings.modules.challonge.enabled) { } else if (!info.pass.length && !settings.modules.random_duel.enabled && !settings.modules.windbot.enabled && !settings.modules.challonge.enabled) {
ygopro.stoc_die(client, "${blank_room_name}"); ygopro.stoc_die(client, "${blank_room_name}");
return;
} else if (settings.modules.mysql.enabled && (await dataManager.checkBan("name", client.name))) { //账号被封 } else if (settings.modules.mysql.enabled && (await dataManager.checkBan("name", client.name))) { //账号被封
exactBan = (await dataManager.checkBanWithNameAndIP(client.name, client.ip)); exactBan = (await dataManager.checkBanWithNameAndIP(client.name, client.ip));
if (!exactBan) { if (!exactBan) {
...@@ -3097,22 +3231,18 @@ ...@@ -3097,22 +3231,18 @@
} }
log.warn("BANNED USER LOGIN", client.name, client.ip); log.warn("BANNED USER LOGIN", client.name, client.ip);
ygopro.stoc_die(client, "${banned_user_login}"); ygopro.stoc_die(client, "${banned_user_login}");
return;
} else if (settings.modules.mysql.enabled && (await dataManager.checkBan("ip", client.ip))) { //IP被封 } else if (settings.modules.mysql.enabled && (await dataManager.checkBan("ip", client.ip))) { //IP被封
log.warn("BANNED IP LOGIN", client.name, client.ip); log.warn("BANNED IP LOGIN", client.name, client.ip);
ygopro.stoc_die(client, "${banned_ip_login}"); ygopro.stoc_die(client, "${banned_ip_login}");
return;
} else if (info.pass.length && settings.modules.mycard.enabled && info.pass.slice(0, 3) !== 'AI#') { } else if (info.pass.length && settings.modules.mycard.enabled && info.pass.slice(0, 3) !== 'AI#') {
ygopro.stoc_send_chat(client, '${loading_user_info}', ygopro.constants.COLORS.BABYBLUE); ygopro.stoc_send_chat(client, '${loading_user_info}', ygopro.constants.COLORS.BABYBLUE);
if (info.pass.length <= 8) { if (info.pass.length <= 8) {
ygopro.stoc_die(client, '${invalid_password_length}'); ygopro.stoc_die(client, '${invalid_password_length}');
return; return;
} }
if (info.version !== settings.version && settings.alternative_versions.includes(info.version)) { await polyfill_version();
info.version = settings.version;
struct = ygopro.structs.get("CTOS_JoinGame");
struct._setBuff(buffer);
struct.set("version", info.version);
buffer = struct.buffer;
}
buffer = Buffer.from(info.pass.slice(0, 8), 'base64'); buffer = Buffer.from(info.pass.slice(0, 8), 'base64');
if (buffer.length !== 6) { if (buffer.length !== 6) {
ygopro.stoc_die(client, '${invalid_password_payload}'); ygopro.stoc_die(client, '${invalid_password_payload}');
...@@ -3407,28 +3537,28 @@ ...@@ -3407,28 +3537,28 @@
} }
} else if (!client.name || client.name === "") { } else if (!client.name || client.name === "") {
ygopro.stoc_die(client, "${bad_user_name}"); ygopro.stoc_die(client, "${bad_user_name}");
return;
} else if (ROOM_connected_ip[client.ip] > 5) { } else if (ROOM_connected_ip[client.ip] > 5) {
log.warn("MULTI LOGIN", client.name, client.ip); log.warn("MULTI LOGIN", client.name, client.ip);
ygopro.stoc_die(client, "${too_much_connection}" + client.ip); ygopro.stoc_die(client, "${too_much_connection}" + client.ip);
return;
} else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && badwordR.level3.test(client.name)) { } else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && badwordR.level3.test(client.name)) {
log.warn("BAD NAME LEVEL 3", client.name, client.ip); log.warn("BAD NAME LEVEL 3", client.name, client.ip);
ygopro.stoc_die(client, "${bad_name_level3}"); ygopro.stoc_die(client, "${bad_name_level3}");
return;
} else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && badwordR.level2.test(client.name)) { } else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && badwordR.level2.test(client.name)) {
log.warn("BAD NAME LEVEL 2", client.name, client.ip); log.warn("BAD NAME LEVEL 2", client.name, client.ip);
ygopro.stoc_die(client, "${bad_name_level2}"); ygopro.stoc_die(client, "${bad_name_level2}");
return;
} else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && badwordR.level1.test(client.name)) { } else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && badwordR.level1.test(client.name)) {
log.warn("BAD NAME LEVEL 1", client.name, client.ip); log.warn("BAD NAME LEVEL 1", client.name, client.ip);
ygopro.stoc_die(client, "${bad_name_level1}"); ygopro.stoc_die(client, "${bad_name_level1}");
return;
} else if (info.pass.length && !ROOM_validate(info.pass)) { } else if (info.pass.length && !ROOM_validate(info.pass)) {
ygopro.stoc_die(client, "${invalid_password_room}"); ygopro.stoc_die(client, "${invalid_password_room}");
return;
} else { } else {
if (info.version !== settings.version && settings.alternative_versions.includes(info.version)) { await polyfill_version();
info.version = settings.version;
struct = ygopro.structs.get("CTOS_JoinGame");
struct._setBuff(buffer);
struct.set("version", info.version);
buffer = struct.buffer;
}
//log.info 'join_game',info.pass, client.name //log.info 'join_game',info.pass, client.name
room = (await ROOM_find_or_create_by_name(info.pass, client.ip)); room = (await ROOM_find_or_create_by_name(info.pass, client.ip));
if (!room) { if (!room) {
...@@ -3568,13 +3698,21 @@ ...@@ -3568,13 +3698,21 @@
}; };
ygopro.stoc_follow('GAME_MSG', true, async function(buffer, info, client, server, datas) { ygopro.stoc_follow('GAME_MSG', true, async function(buffer, info, client, server, datas) {
var act_pos, card, chain, check, count, cpos, deck_found, dialogText, found, hint_type, i, id, j, l, len, len1, len2, len3, limbo_found, loc, m, max_loop, msg, msg_name, n, o, oppo_pos, phase, player, playertype, pos, ppos, r_player, reason, ref, ref1, ref2, ref3, ref4, room, trigger_location, val, victoryWordPlayerList, win_pos; var act_pos, card, chain, check, count, cpos, deck_found, dialogText, found, hint_type, i, id, j, l, len, len1, len2, len3, limbo_found, loc, m, max_loop, msg, msg_name, n, new_buf, o, oppo_pos, phase, player, playertype, pos, ppos, r_player, reason, record_last_game_msg, ref, ref1, ref2, ref3, ref4, room, trigger_location, val, victoryWordPlayerList, win_pos;
room = ROOM_all[client.rid]; room = ROOM_all[client.rid];
if (!(room && !client.reconnecting)) { if (!(room && !client.reconnecting)) {
return; return;
} }
msg = buffer.readInt8(0); msg = buffer.readInt8(0);
msg_name = ygopro.constants.MSG[msg]; msg_name = ygopro.constants.MSG[msg];
new_buf = (await msg_polyfill.polyfillGameMsg(client.actual_version, msg_name, buffer));
if (new_buf) {
buffer = new_buf;
}
record_last_game_msg = function() {
client.last_game_msg = buffer;
return client.last_game_msg_title = msg_name;
};
//console.log client.pos, "MSG", msg_name //console.log client.pos, "MSG", msg_name
if (msg_name === 'RETRY' && room.recovering) { if (msg_name === 'RETRY' && room.recovering) {
room.finish_recover(true); room.finish_recover(true);
...@@ -3606,13 +3744,11 @@ ...@@ -3606,13 +3744,11 @@
return true; return true;
} }
} else { } else {
client.last_game_msg = buffer; record_last_game_msg();
client.last_game_msg_title = msg_name;
} }
// log.info(client.name, client.last_game_msg_title) // log.info(client.name, client.last_game_msg_title)
} else if (msg_name !== 'RETRY') { } else if (msg_name !== 'RETRY') {
client.last_game_msg = buffer; record_last_game_msg();
client.last_game_msg_title = msg_name;
} }
// log.info(client.name, client.last_game_msg_title) // log.info(client.name, client.last_game_msg_title)
if ((msg >= 10 && msg < 30) || msg === 132 || (msg >= 140 && msg <= 144)) { //SELECT和ANNOUNCE开头的消息 if ((msg >= 10 && msg < 30) || msg === 132 || (msg >= 140 && msg <= 144)) { //SELECT和ANNOUNCE开头的消息
...@@ -3978,7 +4114,11 @@ ...@@ -3978,7 +4114,11 @@
} }
return true; return true;
} }
if (new_buf) {
return buffer;
} else {
return false; return false;
}
}); });
//房间管理 //房间管理
...@@ -4387,7 +4527,7 @@ ...@@ -4387,7 +4527,7 @@
} }
//log.info "DECK LOG START", client.name, room.arena //log.info "DECK LOG START", client.name, room.arena
if (settings.modules.deck_log.local) { if (settings.modules.deck_log.local) {
deck_name = moment_now.format('YYYY-MM-DD HH-mm-ss') + ' ' + room.process_pid + ' ' + client.pos + ' ' + client.ip.slice(7) + ' ' + client.name.replace(/[\/\\\?\*]/g, '_'); deck_name = moment_now.format('YYYY-MM-DD HH-mm-ss') + ' ' + room.process_pid + ' ' + client.pos + ' ' + toIpv4(client.ip) + ' ' + client.name.replace(/[\/\\\?\*]/g, '_');
fs.writeFile(settings.modules.deck_log.local + deck_name + '.ydk', deck_text, 'utf-8', function(err) { fs.writeFile(settings.modules.deck_log.local + deck_name + '.ydk', deck_text, 'utf-8', function(err) {
if (err) { if (err) {
return log.warn('DECK SAVE ERROR', err); return log.warn('DECK SAVE ERROR', err);
...@@ -4851,7 +4991,7 @@ ...@@ -4851,7 +4991,7 @@
}); });
ygopro.ctos_follow('UPDATE_DECK', true, async function(buffer, info, client, server, datas) { ygopro.ctos_follow('UPDATE_DECK', true, async function(buffer, info, client, server, datas) {
var athleticCheckResult, buff_main, buff_side, card, current_deck, deck, deck_array, deck_bad, deck_main, deck_ok, deck_side, deck_text, deckbuf_from_challonge, decks, found_deck, i, j, l, len, len1, line, oppo_pos, recover_player_data, recoveredDeck, room, struct, trim_deckbuf, win_pos; var athleticCheckResult, buff_main, buff_side, deck, deck_bad, deck_main, deck_obj, deck_ok, deck_side, deck_text, deckbuf_from_challonge, decks, found_deck, i, j, len, oppo_pos, recover_player_data, recoveredDeck, room, trim_deckbuf, win_pos;
if (settings.modules.reconnect.enabled && client.pre_reconnecting) { if (settings.modules.reconnect.enabled && client.pre_reconnecting) {
if (!CLIENT_is_able_to_reconnect(client) && !CLIENT_is_able_to_kick_reconnect(client)) { if (!CLIENT_is_able_to_reconnect(client) && !CLIENT_is_able_to_kick_reconnect(client)) {
ygopro.stoc_send_chat(client, "${reconnect_failed}", ygopro.constants.COLORS.RED); ygopro.stoc_send_chat(client, "${reconnect_failed}", ygopro.constants.COLORS.RED);
...@@ -4862,13 +5002,13 @@ ...@@ -4862,13 +5002,13 @@
CLIENT_kick_reconnect(client, buffer); CLIENT_kick_reconnect(client, buffer);
} else { } else {
ygopro.stoc_send_chat(client, "${deck_incorrect_reconnect}", ygopro.constants.COLORS.RED); ygopro.stoc_send_chat(client, "${deck_incorrect_reconnect}", ygopro.constants.COLORS.RED);
ygopro.stoc_send(client, 'HS_PLAYER_CHANGE', {
status: (client.pos << 4) | 0xa
});
ygopro.stoc_send(client, 'ERROR_MSG', { ygopro.stoc_send(client, 'ERROR_MSG', {
msg: 2, msg: 2,
code: 0 code: 0
}); });
ygopro.stoc_send(client, 'HS_PLAYER_CHANGE', {
status: (client.pos << 4) | 0xa
});
} }
return true; return true;
} }
...@@ -4921,18 +5061,22 @@ ...@@ -4921,18 +5061,22 @@
} }
return true; return true;
} }
struct = ygopro.structs.get("deck"); deck_ok = async function(msg) {
struct._setBuff(buffer); await ygopro.stoc_send_chat(client, msg, ygopro.constants.COLORS.BABYBLUE);
deck_ok = function(msg) {
ygopro.stoc_send_chat(client, msg, ygopro.constants.COLORS.BABYBLUE);
return false; return false;
}; };
deck_bad = function(msg) { deck_bad = function(msg) {
struct.set("mainc", 1);
struct.set("sidec", 1);
struct.set("deckbuf", [4392470, 4392470]);
ygopro.stoc_send_chat(client, msg, ygopro.constants.COLORS.RED); ygopro.stoc_send_chat(client, msg, ygopro.constants.COLORS.RED);
return false; if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN) {
ygopro.stoc_send(client, 'HS_PLAYER_CHANGE', {
status: (client.pos << 4) | 0xa
});
}
ygopro.stoc_send(client, 'ERROR_MSG', {
msg: 2,
code: 0
});
return true;
}; };
if (room.random_type || room.arena) { if (room.random_type || room.arena) {
if (client.pos === 0) { if (client.pos === 0) {
...@@ -5000,20 +5144,9 @@ ...@@ -5000,20 +5144,9 @@
deck_text = (await fs.promises.readFile(settings.modules.tournament_mode.deck_path + found_deck, { deck_text = (await fs.promises.readFile(settings.modules.tournament_mode.deck_path + found_deck, {
encoding: "ASCII" encoding: "ASCII"
})); }));
deck_array = deck_text.split(/\r?\n/); deck_obj = YGOProDeck.fromYdkString(deck_text);
deck_main = []; deck_main = deck_obj.main.concat(deck_obj.extra);
deck_side = []; deck_side = deck_obj.side;
current_deck = deck_main;
for (l = 0, len1 = deck_array.length; l < len1; l++) {
line = deck_array[l];
if (line.indexOf("!side") >= 0) {
current_deck = deck_side;
}
card = parseInt(line);
if (!(isNaN(card) || line.endsWith("#"))) {
current_deck.push(card);
}
}
if (_.isEqual(buff_main, deck_main) && _.isEqual(buff_side, deck_side)) { if (_.isEqual(buff_main, deck_main) && _.isEqual(buff_side, deck_side)) {
//log.info("deck ok: " + client.name) //log.info("deck ok: " + client.name)
return deck_ok(`\${deck_correct_part1} ${found_deck} \${deck_correct_part2}`); return deck_ok(`\${deck_correct_part1} ${found_deck} \${deck_correct_part2}`);
...@@ -5032,13 +5165,14 @@ ...@@ -5032,13 +5165,14 @@
return false; return false;
}); });
ygopro.ctos_follow('RESPONSE', false, async function(buffer, info, client, server, datas) { ygopro.ctos_follow('RESPONSE', true, async function(buffer, info, client, server, datas) {
var room; var room;
room = ROOM_all[client.rid]; room = ROOM_all[client.rid];
if (!(room && (room.random_type || room.arena))) { if (room && (room.random_type || room.arena)) {
return;
}
room.refreshLastActiveTime(); room.refreshLastActiveTime();
}
await msg_polyfill.polyfillResponse(client.actual_version, client.last_game_msg_title, buffer);
return false;
}); });
ygopro.stoc_follow('TIME_LIMIT', true, async function(buffer, info, client, server, datas) { ygopro.stoc_follow('TIME_LIMIT', true, async function(buffer, info, client, server, datas) {
...@@ -5464,7 +5598,7 @@ ...@@ -5464,7 +5598,7 @@
results.push({ results.push({
id: (-1).toString(), id: (-1).toString(),
name: player.name, name: player.name,
ip: settings.modules.http.show_ip && pass_validated && !player.is_local ? player.ip.slice(7) : null, ip: settings.modules.http.show_ip && pass_validated && !player.is_local ? toIpv4(player.ip) : null,
status: settings.modules.http.show_info && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && player.pos !== 7 ? { status: settings.modules.http.show_info && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && player.pos !== 7 ? {
score: room.scores[player.name_vpass], score: room.scores[player.name_vpass],
lp: player.lp != null ? player.lp : room.hostinfo.start_lp, lp: player.lp != null ? player.lp : room.hostinfo.start_lp,
...@@ -5791,21 +5925,7 @@ ...@@ -5791,21 +5925,7 @@
ip6addr = require('ip6addr'); ip6addr = require('ip6addr');
neosRequestListener = function(client, req) { neosRequestListener = function(client, req) {
var ipHeader, physicalAddress; var xff_ip;
physicalAddress = req.socket.remoteAddress;
if (settings.modules.neos.trusted_proxies.some(function(trusted) {
var cidr;
cidr = trusted.includes('/') ? ip6addr.createCIDR(trusted) : ip6addr.createAddrRange(trusted, trusted);
return cidr.contains(physicalAddress);
})) {
ipHeader = req.headers[settings.modules.neos.trusted_proxy_header];
if (ipHeader) {
client.ip = ipHeader.split(',')[0].trim();
}
}
if (!client.ip) {
client.ip = physicalAddress;
}
client.setTimeout = function() { client.setTimeout = function() {
return true; return true;
}; };
...@@ -5813,6 +5933,11 @@ ...@@ -5813,6 +5933,11 @@
return client.close(); return client.close();
}; };
client.isWs = true; client.isWs = true;
client.physical_ip = req.socket.remoteAddress || "";
xff_ip = req.headers[settings.modules.neos.trusted_proxy_header];
if (CLIENT_set_ip(client, xff_ip)) {
return;
}
return netRequestHandler(client); return netRequestHandler(client);
}; };
......
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