idz: Dispatch on declared protocol version

This commit is contained in:
Tau
2021-02-03 23:43:39 +00:00
committed by Tau
parent 93db3831be
commit 44cd74ea86
32 changed files with 274 additions and 328 deletions
+84 -34
View File
@@ -18,7 +18,7 @@ import { loadRewardTable } from "./loadRewardTable";
import { loadServerList } from "./loadServerList";
import { loadStocker } from "./loadStocker";
import { loadTeam } from "./loadTeam";
import { loadTeamRanking, loadTeamRanking2 } from "./loadTeamRanking";
import { loadTeamRanking1, loadTeamRanking2 } from "./loadTeamRanking";
import { loadTopTen1 } from "./loadTopTen1";
import { loadTopTen2 } from "./loadTopTen2";
import { lockGarage } from "./lockGarage";
@@ -48,7 +48,7 @@ import { updateTeamPoints } from "./updateTeamPoints";
import { updateUiReport } from "./updateUiReport";
import { updateUserLog } from "./updateUserLog";
import { lockProfileExtend } from "./lockProfileExtend";
import { BLOCK_SIZE } from "../../common";
import { BLOCK_SIZE, ClientHello } from "../../common";
import { ByteStream } from "../../../util/stream";
const debug = logger("app:idz:userdb:decoder");
@@ -58,53 +58,55 @@ export type ReaderFn = ((buf: Buffer) => Request) & {
msgLen: number;
};
const funcList: ReaderFn[] = [
function makeReaderMap(funcList: ReaderFn[]): Map<number, ReaderFn> {
const result = new Map<number, ReaderFn>();
for (const fn of funcList) {
result.set(fn.msgCode, fn);
}
return result;
}
// TODO confirm v1.21.00 proto version
const funcList110: ReaderFn[] = [
checkTeamName,
createAutoTeam,
createProfile,
createTeam,
discoverProfile,
load2on2_v1,
load2on2_v2,
loadConfig,
loadConfig2,
loadEventInfo,
loadGacha,
loadGarage,
loadGeneralReward1,
loadGeneralReward2,
loadGhost,
loadProfile2,
loadProfile3,
loadRewardTable,
loadServerList,
loadStocker,
loadTeam,
loadTeamRanking,
loadTeamRanking2,
loadTopTen1,
loadTopTen2,
loadTeamRanking1,
lockGarage,
lockProfile,
lockProfileExtend,
loadTopTen1,
msg00AD,
saveExpedition1,
saveExpedition2,
saveGarage,
saveNewCar,
saveProfile2,
saveProfile3,
saveSettings,
saveStocker,
saveTeamBanner,
saveTimeAttack1,
saveTimeAttack2,
saveTopic,
unlockProfile,
updateProvisionalStoreRank,
updateResult,
updateStoryClearNum1,
updateStoryClearNum2,
updateTeamLeader,
updateTeamMember,
updateTeamPoints,
@@ -112,15 +114,66 @@ const funcList: ReaderFn[] = [
updateUserLog,
];
const readerFns = new Map<number, ReaderFn>();
const msgLengths = new Map<number, number>();
const funcList130: ReaderFn[] = [
checkTeamName,
createAutoTeam,
createProfile,
createTeam,
discoverProfile,
load2on2_v2,
updateStoryClearNum2,
loadConfig,
loadConfig2,
loadEventInfo,
loadGacha,
loadGarage,
loadGeneralReward2,
loadGhost,
loadProfile3,
loadRewardTable,
loadServerList,
loadStocker,
loadTeam,
loadTeamRanking2,
loadTopTen2,
lockGarage,
lockProfile,
lockProfileExtend,
msg00AD,
saveExpedition2,
saveGarage,
saveNewCar,
saveProfile3,
saveSettings,
saveStocker,
saveTeamBanner,
saveTimeAttack2,
saveTopic,
unlockProfile,
updateProvisionalStoreRank,
updateResult,
updateTeamLeader,
updateTeamMember,
updateTeamPoints,
updateUiReport,
updateUserLog,
];
for (const fn of funcList) {
readerFns.set(fn.msgCode, fn);
msgLengths.set(fn.msgCode, fn.msgLen);
}
const protocols = new Map<string, Map<number, ReaderFn>>();
protocols.set("110", makeReaderMap(funcList110));
protocols.set("130", makeReaderMap(funcList130));
async function readRequest(
clientHello: ClientHello,
stm: ByteStream
): Promise<Request | undefined> {
const protocol = protocols.get(clientHello.protocol);
if (protocol === undefined) {
throw new Error(`Unsupported protocol version ${clientHello.protocol}`);
}
async function readRequest(stm: ByteStream): Promise<Request | undefined> {
const head = await stm.read(BLOCK_SIZE);
if (head.length === 0) {
@@ -129,16 +182,16 @@ async function readRequest(stm: ByteStream): Promise<Request | undefined> {
}
const msgCode = head.readUInt16LE(0x0000);
const msgLen = msgLengths.get(msgCode);
const readerFn = protocol.get(msgCode);
if (msgLen === undefined) {
if (readerFn === undefined) {
throw new Error(`Message ${msgCode.toString(16)}: Unknown command code`);
}
const tail = await stm.read(msgLen - BLOCK_SIZE);
const tail = await stm.read(readerFn.msgLen - BLOCK_SIZE);
const msg = Buffer.concat([head, tail]);
if (msg.length < msgLen) {
if (msg.length < readerFn.msgLen) {
throw new Error(`Message ${msgCode.toString(16)}: Truncated read`);
}
@@ -146,22 +199,19 @@ async function readRequest(stm: ByteStream): Promise<Request | undefined> {
debug("Raw: %s", msg.toString("hex"));
}
const reader = readerFns.get(msgCode);
if (reader === undefined) {
throw new Error(`Message ${msgCode.toString(16)}: No read handler`);
}
const payload = reader(msg);
const payload = readerFn(msg);
debug("Payload: %j", payload);
return payload;
}
export default async function* readRequestStream(stm: ByteStream) {
export default async function* readRequestStream(
clientHello: ClientHello,
stm: ByteStream
) {
while (true) {
const req = await readRequest(stm);
const req = await readRequest(clientHello, stm);
if (req === undefined) {
return;
+3 -5
View File
@@ -1,15 +1,14 @@
import { ExtId } from "../model/base";
import { Team } from "../model/team";
import { Load2on2Request1, Load2on2Request2 } from "../request/load2on2";
import { Load2on2Request } from "../request/load2on2";
import { AimeId } from "../../../model";
load2on2_v1.msgCode = 0x00b0;
load2on2_v1.msgLen = 0x0010;
export function load2on2_v1(buf: Buffer): Load2on2Request1 {
export function load2on2_v1(buf: Buffer): Load2on2Request {
return {
type: "load_2on2_req",
format: 1,
field_0002: buf.readUInt16LE(0x0002),
aimeId: buf.readUInt32LE(0x0004) as AimeId,
teamId: buf.readUInt32LE(0x0008) as ExtId<Team>,
@@ -19,10 +18,9 @@ export function load2on2_v1(buf: Buffer): Load2on2Request1 {
load2on2_v2.msgCode = 0x0132;
load2on2_v2.msgLen = 0x0010;
export function load2on2_v2(buf: Buffer): Load2on2Request2 {
export function load2on2_v2(buf: Buffer): Load2on2Request {
return {
type: "load_2on2_req",
format: 2,
field_0002: buf.readUInt16LE(0x0002),
aimeId: buf.readUInt32LE(0x0004) as AimeId,
teamId: buf.readUInt32LE(0x0008) as ExtId<Team>,
+3 -8
View File
@@ -1,16 +1,12 @@
import {
LoadGeneralRewardRequest1,
LoadGeneralRewardRequest2,
} from "../request/loadGeneralReward";
import { LoadGeneralRewardRequest } from "../request/loadGeneralReward";
import { AimeId } from "../../../model";
loadGeneralReward1.msgCode = 0x009c;
loadGeneralReward1.msgLen = 0x0010;
export function loadGeneralReward1(buf: Buffer): LoadGeneralRewardRequest1 {
export function loadGeneralReward1(buf: Buffer): LoadGeneralRewardRequest {
return {
type: "load_general_reward_req",
format: 1,
aimeId: buf.readUInt32LE(0x0004) as AimeId,
};
}
@@ -18,10 +14,9 @@ export function loadGeneralReward1(buf: Buffer): LoadGeneralRewardRequest1 {
loadGeneralReward2.msgCode = 0x013b;
loadGeneralReward2.msgLen = 0x0010;
export function loadGeneralReward2(buf: Buffer): LoadGeneralRewardRequest2 {
export function loadGeneralReward2(buf: Buffer): LoadGeneralRewardRequest {
return {
type: "load_general_reward_req",
format: 2,
aimeId: buf.readUInt32LE(0x0004) as AimeId,
};
}
+3 -8
View File
@@ -1,17 +1,13 @@
import {
LoadProfileRequest2,
LoadProfileRequest3,
} from "../request/loadProfile";
import { LoadProfileRequest } from "../request/loadProfile";
import { AimeId } from "../../../model";
import { readAsciiStr } from "../../util/bin";
loadProfile2.msgCode = 0x0067;
loadProfile2.msgLen = 0x0020;
export function loadProfile2(buf: Buffer): LoadProfileRequest2 {
export function loadProfile2(buf: Buffer): LoadProfileRequest {
return {
type: "load_profile_req",
format: 2,
aimeId: buf.readUInt32LE(0x0004) as AimeId,
version: 1,
luid: readAsciiStr(buf, 0x0008, 0x0020),
@@ -21,10 +17,9 @@ export function loadProfile2(buf: Buffer): LoadProfileRequest2 {
loadProfile3.msgCode = 0x0012f;
loadProfile3.msgLen = 0x0020;
export function loadProfile3(buf: Buffer): LoadProfileRequest3 {
export function loadProfile3(buf: Buffer): LoadProfileRequest {
return {
type: "load_profile_req",
format: 3,
aimeId: buf.readUInt32LE(0x0004) as AimeId,
version: 1,
luid: readAsciiStr(buf, 0x0008, 0x0020),
+3 -3
View File
@@ -1,9 +1,9 @@
import { LoadTeamRankingRequest } from "../request/loadTeamRanking";
loadTeamRanking.msgCode = 0x00b9;
loadTeamRanking.msgLen = 0x0010;
loadTeamRanking1.msgCode = 0x00b9;
loadTeamRanking1.msgLen = 0x0010;
export function loadTeamRanking(buf: Buffer): LoadTeamRankingRequest {
export function loadTeamRanking1(buf: Buffer): LoadTeamRankingRequest {
return {
type: "load_team_ranking_req",
};
+3 -8
View File
@@ -1,15 +1,11 @@
import {
SaveExpeditionRequest1,
SaveExpeditionRequest2,
} from "../request/saveExpedition";
import { SaveExpeditionRequest } from "../request/saveExpedition";
saveExpedition1.msgCode = 0x008c;
saveExpedition1.msgLen = 0x0010;
export function saveExpedition1(buf: Buffer): SaveExpeditionRequest1 {
export function saveExpedition1(buf: Buffer): SaveExpeditionRequest {
return {
type: "save_expedition_req",
format: 1,
field_0004: buf.readUInt32LE(0x0004),
};
}
@@ -17,10 +13,9 @@ export function saveExpedition1(buf: Buffer): SaveExpeditionRequest1 {
saveExpedition2.msgCode = 0x013f;
saveExpedition2.msgLen = 0x0010;
export function saveExpedition2(buf: Buffer): SaveExpeditionRequest2 {
export function saveExpedition2(buf: Buffer): SaveExpeditionRequest {
return {
type: "save_expedition_req",
format: 2,
field_0004: buf.readUInt32LE(0x0004),
};
}
+2 -3
View File
@@ -1,14 +1,14 @@
import { car } from "./_car";
import { mission } from "./_mission";
import { BackgroundCode, CourseNo, TitleCode } from "../model/base";
import { SaveProfileRequest2 } from "../request/saveProfile";
import { SaveProfileRequest } from "../request/saveProfile";
import { bitmap } from "./_bitmap";
import { AimeId } from "../../../model";
saveProfile2.msgCode = 0x0068;
saveProfile2.msgLen = 0x0940;
export function saveProfile2(buf: Buffer): SaveProfileRequest2 {
export function saveProfile2(buf: Buffer): SaveProfileRequest {
const storyRows = new Array();
for (let i = 0; i < 9; i++) {
@@ -45,7 +45,6 @@ export function saveProfile2(buf: Buffer): SaveProfileRequest2 {
return {
type: "save_profile_req",
format: 2,
aimeId: buf.readUInt32LE(0x0004) as AimeId,
version: 1,
lv: buf.readUInt16LE(0x0026),
+2 -3
View File
@@ -1,14 +1,14 @@
import { car } from "./_car";
import { mission } from "./_mission";
import { BackgroundCode, CourseNo, TitleCode } from "../model/base";
import { SaveProfileRequest2 } from "../request/saveProfile";
import { SaveProfileRequest } from "../request/saveProfile";
import { bitmap } from "./_bitmap";
import { AimeId } from "../../../model";
saveProfile3.msgCode = 0x0138;
saveProfile3.msgLen = 0x0a70;
export function saveProfile3(buf: Buffer): SaveProfileRequest2 {
export function saveProfile3(buf: Buffer): SaveProfileRequest {
const storyRows = new Array();
// Story layout has changed somewhat...
@@ -47,7 +47,6 @@ export function saveProfile3(buf: Buffer): SaveProfileRequest2 {
return {
type: "save_profile_req",
format: 2,
aimeId: buf.readUInt32LE(0x0004) as AimeId,
version: 1,
lv: buf.readUInt16LE(0x0026),
+3 -12
View File
@@ -1,28 +1,19 @@
import {
UpdateStoryClearNumRequest1,
UpdateStoryClearNumRequest2,
} from "../request/updateStoryClearNum";
import { UpdateStoryClearNumRequest } from "../request/updateStoryClearNum";
updateStoryClearNum1.msgCode = 0x007f;
updateStoryClearNum1.msgLen = 0x0010;
export function updateStoryClearNum1(
buf: Buffer
): UpdateStoryClearNumRequest1 {
export function updateStoryClearNum1(buf: Buffer): UpdateStoryClearNumRequest {
return {
type: "update_story_clear_num_req",
format: 1,
};
}
updateStoryClearNum2.msgCode = 0x013d;
updateStoryClearNum2.msgLen = 0x0010;
export function updateStoryClearNum2(
buf: Buffer
): UpdateStoryClearNumRequest2 {
export function updateStoryClearNum2(buf: Buffer): UpdateStoryClearNumRequest {
return {
type: "update_story_clear_num_req",
format: 2,
};
}