mirror of
https://github.com/WorldEditAxe/eaglerproxy.git
synced 2024-11-24 14:36:05 -08:00
Provide options for binding IP and ports
This commit is contained in:
parent
083762fce1
commit
2e75776ff1
11
config.ts
11
config.ts
|
@ -2,10 +2,11 @@ import { Config } from "./types.js";
|
||||||
|
|
||||||
export const config: Config = {
|
export const config: Config = {
|
||||||
name: "BasedProxy",
|
name: "BasedProxy",
|
||||||
port: 80, // 443 if using TLS
|
bindHost: "0.0.0.0",
|
||||||
|
bindPort: 80, // 443 if using TLS
|
||||||
maxPlayers: 20,
|
maxPlayers: 20,
|
||||||
motd: {
|
motd: {
|
||||||
iconURL: null,
|
iconURL: "./icon.webp",
|
||||||
l1: "hi",
|
l1: "hi",
|
||||||
l2: "lol"
|
l2: "lol"
|
||||||
},
|
},
|
||||||
|
@ -18,4 +19,8 @@ export const config: Config = {
|
||||||
key: null,
|
key: null,
|
||||||
cert: null
|
cert: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const BRANDING: Readonly<string> = Object.freeze("EaglerXProxy")
|
||||||
|
export const VERSION: Readonly<string> = "1.0.0"
|
||||||
|
export const NETWORK_VERSION: Readonly<string> = Object.freeze(BRANDING + "/" + VERSION)
|
51
index.ts
51
index.ts
|
@ -2,12 +2,11 @@ import { readFileSync } from "fs";
|
||||||
import * as http from "http"
|
import * as http from "http"
|
||||||
import * as https from "https"
|
import * as https from "https"
|
||||||
import { WebSocketServer } from "ws";
|
import { WebSocketServer } from "ws";
|
||||||
import { ProxiedPlayer } from "./classes.js";
|
import { BRANDING, config, NETWORK_VERSION, VERSION } from "./config.js";
|
||||||
import { config } from "./config.js";
|
|
||||||
import { handlePacket } from "./listener.js";
|
import { handlePacket } from "./listener.js";
|
||||||
import { Logger } from "./logger.js";
|
import { Logger } from "./logger.js";
|
||||||
import { BRANDING, NETWORK_VERSION, VERSION } from "./meta.js";
|
import { disconnect, generateMOTDImage } from "./utils.js";
|
||||||
import { State } from "./types.js";
|
import { ChatColor, ProxiedPlayer, State } from "./types.js";
|
||||||
import { genUUID } from "./utils.js";
|
import { genUUID } from "./utils.js";
|
||||||
|
|
||||||
const logger = new Logger("EagXProxy")
|
const logger = new Logger("EagXProxy")
|
||||||
|
@ -22,25 +21,20 @@ global.PROXY = {
|
||||||
secure: false,
|
secure: false,
|
||||||
proxyUUID: genUUID(config.name),
|
proxyUUID: genUUID(config.name),
|
||||||
MOTD: {
|
MOTD: {
|
||||||
icon: null,
|
icon: config.motd.iconURL ? await generateMOTDImage(readFileSync(config.motd.iconURL)) : null,
|
||||||
motd: [config.motd.l1, config.motd.l2]
|
motd: [config.motd.l1, config.motd.l2]
|
||||||
},
|
},
|
||||||
|
|
||||||
playerStats: {
|
|
||||||
max: config.maxPlayers,
|
|
||||||
onlineCount: 0
|
|
||||||
},
|
|
||||||
wsServer: null,
|
wsServer: null,
|
||||||
players: new Map(),
|
players: new Map(),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
config: config
|
config: config
|
||||||
}
|
}
|
||||||
PROXY.playerStats.onlineCount = PROXY.players.size
|
|
||||||
|
|
||||||
let server: WebSocketServer
|
let server: WebSocketServer
|
||||||
|
|
||||||
if (PROXY.config.security.enabled) {
|
if (PROXY.config.security.enabled) {
|
||||||
logger.info(`Starting SECURE WebSocket proxy on port ${config.port}...`)
|
logger.info(`Starting SECURE WebSocket proxy on port ${config.bindPort}...`)
|
||||||
if (process.env.REPL_SLUG) {
|
if (process.env.REPL_SLUG) {
|
||||||
logger.warn("You appear to be running the proxy on Repl.it with encryption enabled. Please note that Repl.it by default provides encryption, and enabling encryption may or may not prevent you from connecting to the server.")
|
logger.warn("You appear to be running the proxy on Repl.it with encryption enabled. Please note that Repl.it by default provides encryption, and enabling encryption may or may not prevent you from connecting to the server.")
|
||||||
}
|
}
|
||||||
|
@ -48,29 +42,54 @@ if (PROXY.config.security.enabled) {
|
||||||
server: https.createServer({
|
server: https.createServer({
|
||||||
key: readFileSync(config.security.key),
|
key: readFileSync(config.security.key),
|
||||||
cert: readFileSync(config.security.cert)
|
cert: readFileSync(config.security.cert)
|
||||||
}).listen(config.port)
|
}).listen(config.bindPort, config.bindHost)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
logger.info(`Starting INSECURE WebSocket proxy on port ${config.port}...`)
|
logger.info(`Starting INSECURE WebSocket proxy on port ${config.bindPort}...`)
|
||||||
server = new WebSocketServer({
|
server = new WebSocketServer({
|
||||||
port: config.port
|
port: config.bindPort,
|
||||||
|
host: config.bindHost
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
PROXY.wsServer = server
|
PROXY.wsServer = server
|
||||||
|
|
||||||
server.addListener('connection', c => {
|
server.addListener('connection', c => {
|
||||||
connectionLogger.debug(`[CONNECTION] New inbound WebSocket connection from [/${(c as any)._socket.remoteAddress}:${(c as any)._socket.remotePort}]. (${(c as any)._socket.remotePort} -> ${config.port})`)
|
connectionLogger.debug(`[CONNECTION] New inbound WebSocket connection from [/${(c as any)._socket.remoteAddress}:${(c as any)._socket.remotePort}]. (${(c as any)._socket.remotePort} -> ${config.bindPort})`)
|
||||||
const plr = new ProxiedPlayer()
|
const plr = new ProxiedPlayer()
|
||||||
plr.ws = c
|
plr.ws = c
|
||||||
plr.ip = (c as any)._socket.remoteAddress
|
plr.ip = (c as any)._socket.remoteAddress
|
||||||
plr.remotePort = (c as any)._socket.remotePort
|
plr.remotePort = (c as any)._socket.remotePort
|
||||||
plr.state = State.PRE_HANDSHAKE
|
plr.state = State.PRE_HANDSHAKE
|
||||||
|
plr.queuedEaglerSkinPackets = []
|
||||||
c.on('message', msg => {
|
c.on('message', msg => {
|
||||||
handlePacket(msg as Buffer, plr)
|
handlePacket(msg as Buffer, plr)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
server.on('listening', () => {
|
server.on('listening', () => {
|
||||||
logger.info(`Successfully started${config.security.enabled ? " [secure]" : ""} WebSocket proxy on port ${config.port}!`)
|
logger.info(`Successfully started${config.security.enabled ? " [secure]" : ""} WebSocket proxy on port ${config.bindPort}!`)
|
||||||
|
})
|
||||||
|
|
||||||
|
process.on('uncaughtException', err => {
|
||||||
|
logger.error(`An uncaught exception was caught! Exception: ${err.stack ?? err}`)
|
||||||
|
})
|
||||||
|
process.on('unhandledRejection', err => {
|
||||||
|
logger.error(`An unhandled promise rejection was caught! Rejection: ${(err != null ? (err as any).stack : err) ?? err}`)
|
||||||
|
})
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
logger.info("Cleaning up before exiting...")
|
||||||
|
for (const [username, plr] of PROXY.players) {
|
||||||
|
if (plr.remoteConnection != null) plr.remoteConnection.end()
|
||||||
|
disconnect(plr, ChatColor.YELLOW + "Proxy is shutting down.")
|
||||||
|
}
|
||||||
|
process.exit(0)
|
||||||
|
})
|
||||||
|
process.on('SIGINT', () => {
|
||||||
|
logger.info("Cleaning up before exiting...")
|
||||||
|
for (const [username, plr] of PROXY.players) {
|
||||||
|
if (plr.remoteConnection != null) plr.remoteConnection.end()
|
||||||
|
disconnect(plr, ChatColor.YELLOW + "Proxy is shutting down.")
|
||||||
|
}
|
||||||
|
process.exit(0)
|
||||||
})
|
})
|
111
types.ts
111
types.ts
|
@ -1,8 +1,9 @@
|
||||||
import { randomUUID } from "crypto"
|
import { randomUUID } from "crypto"
|
||||||
import { WebSocketServer } from "ws"
|
import { Client } from "minecraft-protocol"
|
||||||
import { ProxiedPlayer } from "./classes.js"
|
import { WebSocketServer, WebSocket } from "ws"
|
||||||
|
import { BRANDING, VERSION, NETWORK_VERSION } from "./config.js"
|
||||||
|
import { EaglerSkinPacketId, SkinId } from "./eaglerPacketDef.js"
|
||||||
import { Logger } from "./logger.js"
|
import { Logger } from "./logger.js"
|
||||||
import { BRANDING, NETWORK_VERSION, VERSION } from "./meta.js"
|
|
||||||
|
|
||||||
export type UUID = ReturnType<typeof randomUUID>
|
export type UUID = ReturnType<typeof randomUUID>
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ export enum State {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MOTD = {
|
export type MOTD = {
|
||||||
icon?: Int8Array, // 16384
|
icon?: Buffer, // 16384
|
||||||
motd: [string, string]
|
motd: [string, string]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +33,6 @@ export type ProxyGlobals = {
|
||||||
proxyUUID: UUID,
|
proxyUUID: UUID,
|
||||||
MOTD: MOTD,
|
MOTD: MOTD,
|
||||||
|
|
||||||
playerStats: PlayerStats,
|
|
||||||
wsServer: WebSocketServer,
|
wsServer: WebSocketServer,
|
||||||
players: Map<string, ProxiedPlayer>,
|
players: Map<string, ProxiedPlayer>,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
|
@ -41,7 +41,8 @@ export type ProxyGlobals = {
|
||||||
|
|
||||||
export type Config = {
|
export type Config = {
|
||||||
name: string,
|
name: string,
|
||||||
port: number,
|
bindPort: number,
|
||||||
|
bindHost: string,
|
||||||
maxPlayers: number,
|
maxPlayers: number,
|
||||||
motd: {
|
motd: {
|
||||||
iconURL?: string,
|
iconURL?: string,
|
||||||
|
@ -57,4 +58,102 @@ export type Config = {
|
||||||
key: string,
|
key: string,
|
||||||
cert: string
|
cert: string
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ChatColor {
|
||||||
|
BLACK = "§0",
|
||||||
|
DARK_BLUE = "§1",
|
||||||
|
DARK_GREEN = "§2",
|
||||||
|
DARK_CYAN = "§3",
|
||||||
|
DARK_RED = "§4",
|
||||||
|
PURPLE = "§5",
|
||||||
|
GOLD = "§6",
|
||||||
|
GRAY = "§7",
|
||||||
|
DARK_GRAY = "§8",
|
||||||
|
BLUE = "§9",
|
||||||
|
BRIGHT_GREEN = "§a",
|
||||||
|
CYAN = "§b",
|
||||||
|
RED = "§c",
|
||||||
|
PINK = "§d",
|
||||||
|
YELLOW = "§e",
|
||||||
|
WHITE = "§f",
|
||||||
|
// text styling
|
||||||
|
OBFUSCATED = '§k',
|
||||||
|
BOLD = '§l',
|
||||||
|
STRIKETHROUGH = '§m',
|
||||||
|
UNDERLINED = '§n',
|
||||||
|
ITALIC = '§o',
|
||||||
|
RESET = '§r'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ChatExtra = {
|
||||||
|
text: string,
|
||||||
|
bold?: boolean,
|
||||||
|
italic?: boolean,
|
||||||
|
underlined?: boolean,
|
||||||
|
strikethrough?: boolean,
|
||||||
|
obfuscated?: boolean,
|
||||||
|
color?: ChatColor | 'reset'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Chat = {
|
||||||
|
text?: string,
|
||||||
|
bold?: boolean,
|
||||||
|
italic?: boolean,
|
||||||
|
underlined?: boolean,
|
||||||
|
strikethrough?: boolean,
|
||||||
|
obfuscated?: boolean,
|
||||||
|
color?: ChatColor | 'reset',
|
||||||
|
extra?: ChatExtra[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ProxiedPlayer {
|
||||||
|
public username: string
|
||||||
|
public uuid: string
|
||||||
|
public clientBrand: string
|
||||||
|
public state: State
|
||||||
|
public ws: WebSocket
|
||||||
|
public ip: string
|
||||||
|
public remotePort: number
|
||||||
|
public remoteConnection: Client
|
||||||
|
public skin: {
|
||||||
|
type: "CUSTOM" | "BUILTIN",
|
||||||
|
skinId?: number,
|
||||||
|
customSkin?: Buffer
|
||||||
|
}
|
||||||
|
public queuedEaglerSkinPackets: UnpackedChannelMessage[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ChannelMessageType {
|
||||||
|
CLIENT = 0x17,
|
||||||
|
SERVER = 0x3f
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UnpackedChannelMessage = {
|
||||||
|
channel: string,
|
||||||
|
data: Buffer,
|
||||||
|
type: ChannelMessageType
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DecodedCFetchSkin = {
|
||||||
|
id: EaglerSkinPacketId.C_FETCH_SKIN,
|
||||||
|
uuid: UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DecodedSSkinFetchBuiltin = {
|
||||||
|
id: EaglerSkinPacketId.S_SKIN_DL_BI,
|
||||||
|
uuid: UUID,
|
||||||
|
skinId: SkinId
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DecodedSSkinDl = {
|
||||||
|
id: EaglerSkinPacketId.S_SKIN_DL,
|
||||||
|
uuid: UUID,
|
||||||
|
skin: Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DecodedCSkinReq = {
|
||||||
|
id: EaglerSkinPacketId.C_REQ_SKIN,
|
||||||
|
uuid: UUID,
|
||||||
|
url: string
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user