Add mucha & allnet emulation in bayshore
This commit is contained in:
parent
4cf03efa0b
commit
868d3fd3bd
3
.gitignore
vendored
3
.gitignore
vendored
@ -6,4 +6,5 @@ proto/
|
||||
dist/
|
||||
server_wangan.key
|
||||
cert.pfx
|
||||
key.pem
|
||||
key.pem
|
||||
config.json
|
4
config.example.json
Normal file
4
config.example.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"shopName": "Bayshore",
|
||||
"shopNickname": "BSH"
|
||||
}
|
@ -24,6 +24,9 @@
|
||||
"@types/pem": "^1.9.6",
|
||||
"body-parser": "^1.20.0",
|
||||
"express": "^4.18.1",
|
||||
"form-urlencoded": "^6.0.6",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"moment": "^2.29.4",
|
||||
"pem": "^1.14.6",
|
||||
"protobufjs": "^7.0.0",
|
||||
"ts-proto": "^1.117.0"
|
||||
|
102
src/allnet.ts
Normal file
102
src/allnet.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import bodyParser from "body-parser";
|
||||
import { Application } from "express";
|
||||
import { unzipSync } from "zlib";
|
||||
import { Module } from "./module";
|
||||
import iconv from "iconv-lite";
|
||||
import { Config } from "./config";
|
||||
|
||||
// TODO: Move this into the config
|
||||
const STARTUP_URI = "https://localhost:9002";
|
||||
const STARTUP_HOST = "localhost:9002";
|
||||
|
||||
export default class AllnetModule extends Module {
|
||||
register(app: Application): void {
|
||||
app.use(bodyParser.raw({
|
||||
type: '*/*'
|
||||
}));
|
||||
|
||||
app.use("/sys/servlet/PowerOn", async function(req, res, next) {
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).end();
|
||||
}
|
||||
|
||||
if (!req.is("application/x-www-form-urlencoded")) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const base64 = req.body.toString('ascii');
|
||||
const zbytes = Buffer.from(base64, "base64");
|
||||
const bytes = unzipSync(zbytes);
|
||||
const str = bytes.toString("ascii").trim();
|
||||
|
||||
const kvps = str.split("&");
|
||||
const reqParams: any = {};
|
||||
|
||||
// Keys and values are not URL-escaped
|
||||
|
||||
kvps.forEach(kvp => {
|
||||
const [key, val] = kvp.split("=");
|
||||
|
||||
reqParams[key] = val;
|
||||
});
|
||||
|
||||
const send_ = res.send;
|
||||
|
||||
req.body = reqParams;
|
||||
res.send = resParams => {
|
||||
const str =
|
||||
Object.entries(resParams)
|
||||
.map(([key, val]) => key + "=" + val)
|
||||
.join("&") + "\n";
|
||||
|
||||
res.set("content-type", "text/plain");
|
||||
|
||||
const bin = iconv.encode(str, "shift_jis");
|
||||
|
||||
return send_.apply(res, [bin]);
|
||||
};
|
||||
|
||||
return next();
|
||||
});
|
||||
|
||||
app.post("/sys/servlet/PowerOn", function(req, res) {
|
||||
console.log('ALL.net: Startup request');
|
||||
|
||||
// Cut milliseconds out of ISO timestamp
|
||||
|
||||
const now = new Date();
|
||||
const adjusted = now;
|
||||
|
||||
let shopName = Config.getConfig().shopName;
|
||||
let shopNick = Config.getConfig().shopNickname;
|
||||
|
||||
const resParams = {
|
||||
stat: 1,
|
||||
uri: STARTUP_URI,
|
||||
host: STARTUP_HOST,
|
||||
place_id: "JPN0123",
|
||||
name: shopName,
|
||||
nickname: shopNick,
|
||||
region0: "1",
|
||||
region_name0: "W",
|
||||
region_name1: "X",
|
||||
region_name2: "Y",
|
||||
region_name3: "Z",
|
||||
country: "JPN",
|
||||
allnet_id: "456",
|
||||
timezone: "002:00",
|
||||
setting: "",
|
||||
year: adjusted.getFullYear(),
|
||||
month: adjusted.getMonth() + 1, // I hate JS
|
||||
day: adjusted.getDate(),
|
||||
hour: adjusted.getHours(),
|
||||
minute: adjusted.getMinutes(),
|
||||
second: adjusted.getSeconds(),
|
||||
res_class: "PowerOnResponseVer2",
|
||||
token: req.body.token,
|
||||
};
|
||||
|
||||
res.send(resParams);
|
||||
});
|
||||
}
|
||||
}
|
21
src/config.ts
Normal file
21
src/config.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import fs from 'fs';
|
||||
|
||||
export interface ConfigFile {
|
||||
shopName: string;
|
||||
shopNickname: string;
|
||||
}
|
||||
|
||||
export class Config {
|
||||
private static cfg: ConfigFile;
|
||||
|
||||
static load() {
|
||||
console.log('Loading config file...');
|
||||
let cfg = fs.readFileSync('./config.json', 'utf-8');
|
||||
let json = JSON.parse(cfg);
|
||||
this.cfg = json as ConfigFile;
|
||||
}
|
||||
|
||||
static getConfig(): ConfigFile {
|
||||
return this.cfg;
|
||||
}
|
||||
}
|
45
src/index.ts
45
src/index.ts
@ -6,18 +6,40 @@ import {PrismaClient} from '@prisma/client';
|
||||
import https, {globalAgent} from 'https';
|
||||
import fs from 'fs';
|
||||
import bodyParser from 'body-parser';
|
||||
import AllnetModule from './allnet';
|
||||
import MuchaModule from './mucha';
|
||||
import { Config } from './config';
|
||||
globalAgent.options.keepAlive = true;
|
||||
|
||||
// @ts-ignore
|
||||
require('http').globalAgent.options.keepAlive = true;
|
||||
|
||||
const PORT_ALLNET = 80;
|
||||
const PORT_MUCHA = 10082;
|
||||
const PORT_BNGI = 9002;
|
||||
|
||||
Config.load();
|
||||
|
||||
const app = express();
|
||||
app.use(bodyParser.raw({
|
||||
type: '*/*'
|
||||
}));
|
||||
|
||||
const muchaApp = express();
|
||||
const allnetApp = express();
|
||||
|
||||
app.use((req, res, next) => {
|
||||
console.log(`${req.method} ${req.url}`);
|
||||
console.log(`[ MAIN] ${req.method} ${req.url}`);
|
||||
next()
|
||||
});
|
||||
|
||||
muchaApp.use((req, res, next) => {
|
||||
console.log(`[ MUCHA] ${req.method} ${req.url}`);
|
||||
next()
|
||||
});
|
||||
|
||||
allnetApp.use((req, res, next) => {
|
||||
console.log(`[ALLNET] ${req.method} ${req.url}`);
|
||||
next()
|
||||
});
|
||||
|
||||
@ -34,9 +56,20 @@ app.all('*', (req, res) => {
|
||||
res.status(200).end();
|
||||
})
|
||||
|
||||
https.createServer({
|
||||
key: fs.readFileSync('./server_wangan.key'),
|
||||
cert: fs.readFileSync('./server_wangan.crt')
|
||||
}, app).listen(9002, () => {
|
||||
console.log('Server listening on port 9002!');
|
||||
new AllnetModule().register(allnetApp);
|
||||
new MuchaModule().register(muchaApp);
|
||||
|
||||
let key = fs.readFileSync('./server_wangan.key');
|
||||
let cert = fs.readFileSync('./server_wangan.crt');
|
||||
|
||||
https.createServer({key, cert}, allnetApp).listen(PORT_ALLNET, () => {
|
||||
console.log(`ALL.net server listening on port ${PORT_ALLNET}!`);
|
||||
})
|
||||
|
||||
https.createServer({key, cert}, muchaApp).listen(PORT_MUCHA, () => {
|
||||
console.log(`Mucha server listening on port ${PORT_MUCHA}!`);
|
||||
})
|
||||
|
||||
https.createServer({key, cert}, app).listen(PORT_BNGI, () => {
|
||||
console.log(`Game server listening on port ${PORT_BNGI}!`);
|
||||
})
|
||||
|
92
src/mucha.ts
Normal file
92
src/mucha.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import express, { Application } from "express";
|
||||
import formUrlEncoded from "form-urlencoded";
|
||||
import moment from "moment";
|
||||
import { Config } from "./config";
|
||||
import { Module } from "./module";
|
||||
|
||||
const PORT = 10082;
|
||||
|
||||
export default class MuchaModule extends Module {
|
||||
register(app: Application): void {
|
||||
const URL_BASE = `https://localhost:${PORT}`
|
||||
|
||||
app.use(express.urlencoded({
|
||||
type: '*/*',
|
||||
extended: true
|
||||
}))
|
||||
|
||||
app.post('/updatacheck.do', (req, res) => {
|
||||
let response = {
|
||||
RESULTS: "001",
|
||||
UPDATE_VER_1: req.body.gameVer,
|
||||
UPDATE_URL_1: `${URL_BASE}/updUrl1/`,
|
||||
UPDATE_SIZE_1: 9318000,
|
||||
UPDATE_CRC_1: "55C4000000000000",
|
||||
CHECK_URL_1: `${URL_BASE}/checkUrl/`,
|
||||
EXE_VER_1: req.body.gameVer,
|
||||
INFO_SIZE_1: 180,
|
||||
COM_SIZE_1: 16384,
|
||||
COM_TIME_1: 100,
|
||||
LAN_INFO_SIZE_1: 180
|
||||
}
|
||||
|
||||
let urlResponse = formUrlEncoded(response);
|
||||
let decResponse = decodeURIComponent(urlResponse);
|
||||
|
||||
res.status(200).send(decResponse);
|
||||
})
|
||||
|
||||
app.post('/boardauth.do', (req, res) => {
|
||||
let serverTime = moment().format('YYYYMMDDHHmm');
|
||||
let utcServerTime = moment().utc().format('YYYYMMDDHHmm');
|
||||
|
||||
let shopName = Config.getConfig().shopName;
|
||||
let shopNick = Config.getConfig().shopNickname;
|
||||
|
||||
let response = {
|
||||
RESULTS: "001",
|
||||
AREA_0: "008",
|
||||
AREA_0_EN: "",
|
||||
AREA_1: "009",
|
||||
AREA_1_EN: "",
|
||||
AREA_2: "010",
|
||||
AREA_2_EN: "",
|
||||
AREA_3: "011",
|
||||
AREA_3_EN: "",
|
||||
AREA_FULL_0: "",
|
||||
AREA_FULL_0_EN: "",
|
||||
AREA_FULL_1: "",
|
||||
AREA_FULL_1_EN: "",
|
||||
AREA_FULL_2: "",
|
||||
AREA_FULL_2_EN: "",
|
||||
AREA_FULL_3: "",
|
||||
AREA_FULL_3_EN: "",
|
||||
AUTH_INTERVAL: "86400",
|
||||
CHARGE_URL: `${URL_BASE}/charge/`,
|
||||
CONSUME_TOKEN: "0",
|
||||
COUNTRY_CD: "JPN",
|
||||
DONGLE_FLG: "1",
|
||||
EXPIRATION_DATE: "null",
|
||||
FILE_URL: `${URL_BASE}/file/`,
|
||||
FORCE_BOOT: "0",
|
||||
PLACE_ID: req.body.placeId,
|
||||
PREFECTURE_ID: "14",
|
||||
SERVER_TIME: serverTime,
|
||||
UTC_SERVER_TIME: utcServerTime,
|
||||
SHOP_NAME: shopName,
|
||||
SHOP_NAME_EN: shopName,
|
||||
SHOP_NICKNAME: shopNick,
|
||||
SHOP_NICKNAME_EN: shopNick,
|
||||
URL_1: `${URL_BASE}/url1/`,
|
||||
URL_2: `${URL_BASE}/url2/`,
|
||||
URL_3: `${URL_BASE}/url3/`,
|
||||
USE_TOKEN: "0"
|
||||
}
|
||||
|
||||
let urlResponse = formUrlEncoded(response);
|
||||
let decResponse = decodeURIComponent(urlResponse);
|
||||
|
||||
res.status(200).send(decResponse);
|
||||
})
|
||||
}
|
||||
}
|
19
yarn.lock
19
yarn.lock
@ -557,6 +557,11 @@ finalhandler@1.2.0:
|
||||
statuses "2.0.1"
|
||||
unpipe "~1.0.0"
|
||||
|
||||
form-urlencoded@^6.0.6:
|
||||
version "6.0.6"
|
||||
resolved "https://registry.yarnpkg.com/form-urlencoded/-/form-urlencoded-6.0.6.tgz#6505aca762436f90f2a736f79c24ad30787daacc"
|
||||
integrity sha512-5n3L86l3uVJLFk8w+HTcuaV8WrEeH9pPqJcICxAbs3oW/gsKg9kJ8XVPZ3I1PJR50ld2fQjstT94p4G90JDMAg==
|
||||
|
||||
forwarded@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
||||
@ -644,6 +649,13 @@ iconv-lite@0.4.24:
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
iconv-lite@^0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
|
||||
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
@ -838,6 +850,11 @@ mkdirp@^1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
||||
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
||||
|
||||
moment@^2.29.4:
|
||||
version "2.29.4"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
|
||||
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
@ -1039,7 +1056,7 @@ safe-buffer@5.2.1:
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3":
|
||||
"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
Loading…
Reference in New Issue
Block a user