mirror of
https://github.com/djhackersdev/minime.git
synced 2026-07-12 22:24:52 -05:00
aimedb: Refactor codec
This commit is contained in:
parent
bc8185b26c
commit
b278c6bf08
|
|
@ -1,7 +1,7 @@
|
|||
import { Decoder } from "./decoder";
|
||||
|
||||
function decode(req) {
|
||||
const decoder = new Decoder({});
|
||||
const decoder = new Decoder();
|
||||
|
||||
decoder.write(req);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,82 @@
|
|||
import { Transform } from "stream";
|
||||
|
||||
import * as Request from "./request";
|
||||
|
||||
function begin(msg: Buffer): Request.AimeRequestBase {
|
||||
const gameId = msg.toString("ascii", 0x000a, 0x000e);
|
||||
const keychipId = msg.toString("ascii", 0x0014, 0x001f);
|
||||
|
||||
return { gameId, keychipId };
|
||||
}
|
||||
|
||||
function readerRegisterRequest(msg: Buffer): Request.RegisterRequest {
|
||||
const luid = msg.slice(0x0020, 0x002a).toString("hex");
|
||||
|
||||
return {
|
||||
...begin(msg),
|
||||
type: "register",
|
||||
luid,
|
||||
};
|
||||
}
|
||||
|
||||
function readLogRequest(msg: Buffer): Request.LogRequest {
|
||||
// idk what any of this stuff means yet
|
||||
// field20 and field28 appear to be an aime id but that is all.
|
||||
|
||||
return {
|
||||
...begin(msg),
|
||||
type: "log",
|
||||
field20: msg.readUInt32LE(0x20),
|
||||
field24: msg.readUInt32LE(0x24),
|
||||
field28: msg.readUInt32LE(0x28),
|
||||
field2C: msg.readUInt32LE(0x2c),
|
||||
field30: msg.readUInt32LE(0x30),
|
||||
field34: msg.readUInt32LE(0x34),
|
||||
field38: msg.readUInt32LE(0x38),
|
||||
field3C: msg.readUInt32LE(0x3c),
|
||||
};
|
||||
}
|
||||
|
||||
function readCampaignRequest(msg: Buffer): Request.CampaignRequest {
|
||||
return {
|
||||
...begin(msg),
|
||||
type: "campaign",
|
||||
};
|
||||
}
|
||||
|
||||
function readLookupRequest(msg: Buffer): Request.LookupRequest {
|
||||
const luid = msg.slice(0x0020, 0x002a).toString("hex");
|
||||
|
||||
return {
|
||||
...begin(msg),
|
||||
type: "lookup",
|
||||
luid,
|
||||
};
|
||||
}
|
||||
|
||||
function readHelloRequest(msg: Buffer): Request.HelloRequest {
|
||||
return {
|
||||
...begin(msg),
|
||||
type: "hello",
|
||||
};
|
||||
}
|
||||
|
||||
function readGoodbyeRequest(msg: Buffer): Request.GoodbyeRequest {
|
||||
return {
|
||||
...begin(msg),
|
||||
type: "goodbye",
|
||||
};
|
||||
}
|
||||
|
||||
const readers = new Map<number, (msg: Buffer) => Request.AimeRequest>();
|
||||
|
||||
readers.set(0x0005, readerRegisterRequest);
|
||||
readers.set(0x0009, readLogRequest);
|
||||
readers.set(0x000b, readCampaignRequest);
|
||||
readers.set(0x000f, readLookupRequest);
|
||||
readers.set(0x0064, readHelloRequest);
|
||||
readers.set(0x0066, readGoodbyeRequest);
|
||||
|
||||
export class Decoder extends Transform {
|
||||
constructor() {
|
||||
super({
|
||||
|
|
@ -8,88 +85,16 @@ export class Decoder extends Transform {
|
|||
});
|
||||
}
|
||||
|
||||
static ident(chunk) {
|
||||
const gameId = chunk.toString("ascii", 0x000a, 0x000e);
|
||||
const keychipId = chunk.toString("ascii", 0x0014, 0x001f);
|
||||
_transform(msg: Buffer, encoding, callback) {
|
||||
const code = msg.readUInt16LE(0x04);
|
||||
const reader = readers.get(code);
|
||||
|
||||
return { gameId, keychipId };
|
||||
}
|
||||
|
||||
static cardId(chunk) {
|
||||
const luid = chunk.slice(0x0020, 0x002a);
|
||||
|
||||
return { luid, ...Decoder.ident(chunk) };
|
||||
}
|
||||
|
||||
static log(chunk) {
|
||||
// idk what any of this stuff means yet
|
||||
// field20 and field28 appear to be an aime id but that is all.
|
||||
|
||||
const field20 = chunk.readUInt32LE(0x20);
|
||||
const field24 = chunk.readUInt32LE(0x24);
|
||||
const field28 = chunk.readUInt32LE(0x28);
|
||||
const field2C = chunk.readUInt32LE(0x2c);
|
||||
const field30 = chunk.readUInt32LE(0x30);
|
||||
const field34 = chunk.readUInt32LE(0x34);
|
||||
const field38 = chunk.readUInt32LE(0x38);
|
||||
const field3C = chunk.readUInt32LE(0x3c);
|
||||
|
||||
return {
|
||||
field20,
|
||||
field24,
|
||||
field28,
|
||||
field2C,
|
||||
field30,
|
||||
field34,
|
||||
field38,
|
||||
field3C,
|
||||
...Decoder.ident(chunk),
|
||||
};
|
||||
}
|
||||
|
||||
_transform(chunk, encoding, callback) {
|
||||
const cmd = chunk.readUInt16LE(0x04);
|
||||
|
||||
switch (cmd) {
|
||||
case 0x0005:
|
||||
return callback(null, {
|
||||
cmd: "register",
|
||||
...Decoder.cardId(chunk),
|
||||
});
|
||||
|
||||
case 0x0009:
|
||||
return callback(null, {
|
||||
cmd: "log",
|
||||
...Decoder.log(chunk),
|
||||
});
|
||||
|
||||
case 0x000b:
|
||||
return callback(null, {
|
||||
cmd: "campaign",
|
||||
...Decoder.ident(chunk),
|
||||
});
|
||||
|
||||
case 0x000f:
|
||||
return callback(null, {
|
||||
cmd: "lookup",
|
||||
...Decoder.cardId(chunk),
|
||||
});
|
||||
|
||||
case 0x0064:
|
||||
return callback(null, {
|
||||
cmd: "hello",
|
||||
...Decoder.ident(chunk),
|
||||
});
|
||||
|
||||
case 0x0066:
|
||||
return callback(null, {
|
||||
cmd: "goodbye",
|
||||
});
|
||||
|
||||
default:
|
||||
return callback(null, {
|
||||
cmd: `unknown_${cmd}`,
|
||||
});
|
||||
if (reader === undefined) {
|
||||
return callback(
|
||||
new Error(`Unknown command code 0x${code.toString(16)}`)
|
||||
);
|
||||
}
|
||||
|
||||
return callback(null, reader(msg));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,22 @@
|
|||
import { Transform } from "stream";
|
||||
|
||||
const registerLevels = {
|
||||
none: 0,
|
||||
portal: 1,
|
||||
segaid: 2,
|
||||
};
|
||||
import { AimeResponse, RegisterLevel } from "./response";
|
||||
|
||||
const registerLevels = new Map<RegisterLevel, number>();
|
||||
|
||||
registerLevels.set("none", 0);
|
||||
registerLevels.set("portal", 1);
|
||||
registerLevels.set("segaid", 2);
|
||||
|
||||
function begin(length: number) {
|
||||
const buf = Buffer.alloc(length);
|
||||
|
||||
buf.writeUInt16LE(0xa13e, 0x0000); // Magic?
|
||||
buf.writeUInt16LE(0x3087, 0x0002); // ???
|
||||
buf.writeUInt16LE(length, 0x0006);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export class Encoder extends Transform {
|
||||
constructor() {
|
||||
|
|
@ -14,35 +26,25 @@ export class Encoder extends Transform {
|
|||
});
|
||||
}
|
||||
|
||||
static init(length) {
|
||||
const buf = Buffer.alloc(length);
|
||||
_transform(msg: AimeResponse, encoding, callback) {
|
||||
console.log("Aimedb: Encode", msg);
|
||||
|
||||
buf.writeUInt16LE(0xa13e, 0x0000); // Magic?
|
||||
buf.writeUInt16LE(0x3087, 0x0002); // ???
|
||||
buf.writeUInt16LE(length, 0x0006);
|
||||
let buf: Buffer;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
_transform(chunk, encoding, callback) {
|
||||
console.log("Aimedb: Encode", chunk);
|
||||
|
||||
let buf;
|
||||
|
||||
switch (chunk.cmd) {
|
||||
switch (msg.type) {
|
||||
case "hello":
|
||||
buf = Encoder.init(0x0020);
|
||||
buf = begin(0x0020);
|
||||
buf.writeUInt16LE(0x0065, 0x0004); // cmd code
|
||||
buf.writeUInt16LE(chunk.status, 0x0008);
|
||||
buf.writeUInt16LE(msg.status, 0x0008);
|
||||
|
||||
break;
|
||||
|
||||
case "campaign":
|
||||
// Still figuring this out...
|
||||
|
||||
buf = Encoder.init(0x0200);
|
||||
buf = begin(0x0200);
|
||||
buf.writeUInt16LE(0x000c, 0x0004); // cmd code
|
||||
buf.writeUInt16LE(chunk.status, 0x0008);
|
||||
buf.writeUInt16LE(msg.status, 0x0008);
|
||||
|
||||
// Campaign array starts at 0x20
|
||||
// Element size is 0xA0
|
||||
|
|
@ -53,31 +55,31 @@ export class Encoder extends Transform {
|
|||
// -1 aime id means card is not registered
|
||||
// register level does not seem to matter
|
||||
|
||||
buf = Encoder.init(0x0130);
|
||||
buf = begin(0x0130);
|
||||
buf.writeUInt16LE(0x0010, 0x0004); // cmd code
|
||||
buf.writeUInt16LE(chunk.status, 0x0008);
|
||||
buf.writeInt32LE(chunk.aimeId || -1, 0x0020);
|
||||
buf.writeUInt8(registerLevels[chunk.registerLevel], 0x0024);
|
||||
buf.writeUInt16LE(msg.status, 0x0008);
|
||||
buf.writeInt32LE(msg.aimeId || -1, 0x0020);
|
||||
buf.writeUInt8(registerLevels[msg.registerLevel], 0x0024);
|
||||
|
||||
break;
|
||||
|
||||
case "register":
|
||||
buf = Encoder.init(0x0030);
|
||||
buf = begin(0x0030);
|
||||
buf.writeUInt16LE(0x0006, 0x0004); // cmd code
|
||||
buf.writeUInt16LE(chunk.status, 0x0008);
|
||||
buf.writeInt32LE(chunk.aimeId, 0x0020);
|
||||
buf.writeUInt16LE(msg.status, 0x0008);
|
||||
buf.writeInt32LE(msg.aimeId, 0x0020);
|
||||
|
||||
break;
|
||||
|
||||
case "log":
|
||||
buf = Encoder.init(0x0020);
|
||||
buf = begin(0x0020);
|
||||
buf.writeUInt16LE(0x000a, 0x0004); // cmd code
|
||||
buf.writeUInt16LE(chunk.status, 0x0008);
|
||||
buf.writeUInt16LE(msg.status, 0x0008);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return callback(new Error(`Unimplemented response: ${chunk.cmd}`));
|
||||
return callback(new Error("Unimplemented response type"));
|
||||
}
|
||||
|
||||
console.log("Aimedb: Send", buf);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { AimeRequest } from "./request";
|
||||
import { setup } from "./pipeline";
|
||||
|
||||
export default async function aimedb(socket) {
|
||||
|
|
@ -6,27 +7,27 @@ export default async function aimedb(socket) {
|
|||
const { input, output } = setup(socket);
|
||||
|
||||
try {
|
||||
for await (const req of input) {
|
||||
for await (const obj of input) {
|
||||
const req = obj as AimeRequest;
|
||||
|
||||
console.log("Aimedb: Decode", req);
|
||||
|
||||
const { cmd } = req;
|
||||
|
||||
switch (cmd) {
|
||||
switch (req.type) {
|
||||
case "hello":
|
||||
console.log("Aimedb: Hello");
|
||||
output.write({ cmd, status: 1 });
|
||||
output.write({ type: req.type, status: 1 });
|
||||
|
||||
break;
|
||||
|
||||
case "campaign":
|
||||
console.log("Aimedb: Campaign stuff");
|
||||
output.write({ cmd, status: 1 });
|
||||
output.write({ type: req.type, status: 1 });
|
||||
|
||||
break;
|
||||
|
||||
case "lookup":
|
||||
console.log("Aimedb: Mifare lookup", req.luid);
|
||||
output.write({ cmd, status: 1 }); // Add aimeId if desired
|
||||
output.write({ type: req.type, status: 1 }); // Add aimeId if desired
|
||||
|
||||
break;
|
||||
|
||||
|
|
@ -34,13 +35,13 @@ export default async function aimedb(socket) {
|
|||
// We get sent here if lookup does not return an aimeId
|
||||
|
||||
console.log("Aimedb: Mifare register", req.luid);
|
||||
output.write({ cmd, status: 1, aimeId: 12345678 });
|
||||
output.write({ type: req.type, status: 1, aimeId: 12345678 });
|
||||
|
||||
break;
|
||||
|
||||
case "log":
|
||||
console.log("Aimedb: Log message");
|
||||
output.write({ cmd, status: 1 });
|
||||
output.write({ type: req.type, status: 1 });
|
||||
|
||||
break;
|
||||
|
||||
|
|
|
|||
46
src/aimedb/request.ts
Normal file
46
src/aimedb/request.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
export interface AimeRequestBase {
|
||||
gameId: string;
|
||||
keychipId: string;
|
||||
}
|
||||
|
||||
export interface RegisterRequest extends AimeRequestBase {
|
||||
type: "register";
|
||||
luid: string;
|
||||
}
|
||||
|
||||
export interface LogRequest extends AimeRequestBase {
|
||||
type: "log";
|
||||
field20: number;
|
||||
field24: number;
|
||||
field28: number;
|
||||
field2C: number;
|
||||
field30: number;
|
||||
field34: number;
|
||||
field38: number;
|
||||
field3C: number;
|
||||
}
|
||||
|
||||
export interface CampaignRequest extends AimeRequestBase {
|
||||
type: "campaign";
|
||||
}
|
||||
|
||||
export interface LookupRequest extends AimeRequestBase {
|
||||
type: "lookup";
|
||||
luid: string;
|
||||
}
|
||||
|
||||
export interface HelloRequest extends AimeRequestBase {
|
||||
type: "hello";
|
||||
}
|
||||
|
||||
export interface GoodbyeRequest extends AimeRequestBase {
|
||||
type: "goodbye";
|
||||
}
|
||||
|
||||
export type AimeRequest =
|
||||
| CampaignRequest
|
||||
| GoodbyeRequest
|
||||
| HelloRequest
|
||||
| LogRequest
|
||||
| LookupRequest
|
||||
| RegisterRequest;
|
||||
35
src/aimedb/response.ts
Normal file
35
src/aimedb/response.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
export type RegisterLevel = "none" | "portal" | "segaid";
|
||||
|
||||
export interface AimeResponseBase {
|
||||
status: number;
|
||||
}
|
||||
|
||||
export interface CampaignResponse extends AimeResponseBase {
|
||||
type: "campaign";
|
||||
}
|
||||
|
||||
export interface HelloResponse extends AimeResponseBase {
|
||||
type: "hello";
|
||||
}
|
||||
|
||||
export interface LogResponse extends AimeResponseBase {
|
||||
type: "log";
|
||||
}
|
||||
|
||||
export interface LookupResponse extends AimeResponseBase {
|
||||
type: "lookup";
|
||||
aimeId?: number;
|
||||
registerLevel: RegisterLevel;
|
||||
}
|
||||
|
||||
export interface RegisterResponse extends AimeResponseBase {
|
||||
type: "register";
|
||||
aimeId: number;
|
||||
}
|
||||
|
||||
export type AimeResponse =
|
||||
| CampaignResponse
|
||||
| HelloResponse
|
||||
| LogResponse
|
||||
| LookupResponse
|
||||
| RegisterResponse;
|
||||
Loading…
Reference in New Issue
Block a user