Skip to content

Commit 83555e9

Browse files
Merge pull request #15 from RaizeTheLimit/responsive_ui
Responsive UI + Proto Decode logging to JSON
2 parents 2316596 + afc9a01 commit 83555e9

9 files changed

Lines changed: 534 additions & 76 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ dist
55
/src/config/config.json
66
/.vs/
77
/.idea/
8+
/proto_samples/

src/config/example.config.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,11 @@
22
"default_port": 8081,
33
"trafficlight_identifier": "AwesomeProtoSender",
44
"redirect_to_golbat_url": null,
5-
"redirect_to_golbat_token": null
5+
"redirect_to_golbat_token": null,
6+
"sample_saving": {
7+
"enabled": true,
8+
"save_directory": "./proto_samples",
9+
"max_samples_per_method": 1,
10+
"endpoints": ["traffic", "golbat"]
11+
}
612
}

src/index.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import http from "http";
22
import fs from "fs";
33
import { WebStreamBuffer, getIPAddress, handleData, moduleConfigIsAvailable, redirect_post_golbat } from "./utils";
44
import { decodePayload, decodePayloadTraffic } from "./parser/proto-parser";
5+
import SampleSaver from "./utils/sample-saver";
56

67
// try looking if config file exists...
78
let config = require("./config/example.config.json");
@@ -14,6 +15,9 @@ const incomingProtoWebBufferInst = new WebStreamBuffer();
1415
const outgoingProtoWebBufferInst = new WebStreamBuffer();
1516
const portBind = config["default_port"];
1617

18+
// Initialize sample saver
19+
const sampleSaver = config.sample_saving ? new SampleSaver(config.sample_saving) : null;
20+
1721
// server
1822
const httpServer = http.createServer(function (req, res) {
1923
let incomingData: Array<Buffer> = [];
@@ -44,11 +48,25 @@ const httpServer = http.createServer(function (req, res) {
4448
}
4549
const identifier = parsedData['username'];
4650
for (let i = 0; i < parsedData['contents'].length; i++) {
51+
const rawRequest = parsedData['contents'][i].request || "";
52+
const rawResponse = parsedData['contents'][i].payload || "";
53+
4754
const parsedRequestData = decodePayloadTraffic(
4855
parsedData['contents'][i].type,
49-
parsedData['contents'][i].request,
56+
rawRequest,
5057
"request"
5158
);
59+
const parsedResponseData = decodePayloadTraffic(
60+
parsedData['contents'][i].type,
61+
rawResponse,
62+
"response"
63+
);
64+
65+
// Save sample if enabled
66+
if (sampleSaver && parsedRequestData.length > 0 && parsedResponseData.length > 0) {
67+
sampleSaver.savePair(parsedRequestData[0], parsedResponseData[0], rawRequest, rawResponse, "golbat");
68+
}
69+
5270
if (typeof parsedRequestData === "string") {
5371
incomingProtoWebBufferInst.write({ error: parsedRequestData });
5472
} else {
@@ -57,11 +75,7 @@ const httpServer = http.createServer(function (req, res) {
5775
incomingProtoWebBufferInst.write(parsedObject);
5876
}
5977
}
60-
const parsedResponseData = decodePayloadTraffic(
61-
parsedData['contents'][i].type,
62-
parsedData['contents'][i].payload,
63-
"response"
64-
);
78+
6579
if (typeof parsedResponseData === "string") {
6680
outgoingProtoWebBufferInst.write({ error: parsedResponseData });
6781
} else {
@@ -85,10 +99,10 @@ const httpServer = http.createServer(function (req, res) {
8599
res.end("");
86100
if (Array.isArray(parsedData)) {
87101
for (let i = 0; i < parsedData.length; i++) {
88-
handleData(incomingProtoWebBufferInst, outgoingProtoWebBufferInst, identifier, parsedData[i])
102+
handleData(incomingProtoWebBufferInst, outgoingProtoWebBufferInst, identifier, parsedData[i], sampleSaver)
89103
}
90104
} else {
91-
handleData(incomingProtoWebBufferInst, outgoingProtoWebBufferInst, identifier, parsedData)
105+
handleData(incomingProtoWebBufferInst, outgoingProtoWebBufferInst, identifier, parsedData, sampleSaver)
92106
}
93107
});
94108
break;

src/parser/proto-parser.ts

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,22 @@ import { b64Decode } from "../utils";
22
import { requestMessagesResponses } from "../constants";
33
import { DecodedProto } from "../types";
44

5-
// For decode dynamics action social.
65
let action_social = 0;
7-
/**
8-
* Callback as used by {@link DecoderInternalPayloadAsResponse}.
9-
* @type {function}
10-
* @param {number|any}
11-
*/
12-
/**
13-
* Returns decoded proto as JSON. Uses Tuples by https://github.com/Furtif/pogo-protos/blob/master/test/test.js, if that implemented.
14-
*/
156
function DecoderInternalPayloadAsResponse(method: number, data: any): any {
16-
// Reset value.
177
action_social = 0;
188
let proto_tuple: any = Object.values(requestMessagesResponses)[method];
199
let result: any = { Not_Implemented_yet: data };
10+
11+
if (!data) {
12+
return {};
13+
}
2014
for (let i = 0; i < Object.keys(requestMessagesResponses).length; i++) {
2115
proto_tuple = Object.values(requestMessagesResponses)[i];
2216
const my_req = proto_tuple[0];
2317
if (my_req == method) {
24-
if (proto_tuple[2] != null && b64Decode(data)) {
18+
if (proto_tuple[2] != null && data && b64Decode(data).length > 0) {
2519
try {
2620
result = proto_tuple[2].decode(b64Decode(data)).toJSON();
27-
/*
28-
// This not need more because protos as replaced bytes for the proto.
29-
if (method == 10010) {
30-
let profile = POGOProtos.Rpc.PlayerPublicProfileProto.decode(b64Decode(result.friend[0].player.public_data)).toJSON();
31-
result.friend[0].player.public_data = profile;
32-
}
33-
*/
3421
}
3522
catch (error) {
3623
console.error(`Intenal ProxySocial decoder ${my_req} Error: ${error}`);
@@ -85,14 +72,22 @@ export const decodePayload = (contents: any, dataType: string): DecodedProto[] =
8572

8673
export const decodeProto = (method: number, data: string, dataType: string): DecodedProto | string => {
8774
let returnObject: DecodedProto | string = "Not Found";
75+
let methodFound = false;
76+
8877
for (let i = 0; i < Object.keys(requestMessagesResponses).length; i++) {
8978
let foundMethod: any = Object.values(requestMessagesResponses)[i];
9079
let foundMethodString: string = Object.keys(requestMessagesResponses)[i];
9180
const foundReq = foundMethod[0];
9281
if (foundReq == method) {
82+
methodFound = true;
9383
if (foundMethod[1] != null && dataType === "request") {
9484
try {
95-
let parsedData = foundMethod[1].decode(b64Decode(data)).toJSON();
85+
let parsedData;
86+
if (!data || data === "") {
87+
parsedData = {};
88+
} else {
89+
parsedData = foundMethod[1].decode(b64Decode(data)).toJSON();
90+
}
9691
if (foundMethod[0] === 5012 || foundMethod[0] === 600005) {
9792
action_social = parsedData.action;
9893
Object.values(requestMessagesResponses).forEach(val => {
@@ -109,13 +104,35 @@ export const decodeProto = (method: number, data: string, dataType: string): Dec
109104
};
110105
} catch (error) {
111106
console.error(`Error parsing request ${foundMethodString} -> ${error}`);
107+
returnObject = {
108+
methodId: foundMethod[0],
109+
methodName: remasterOrCleanMethodString(foundMethodString) + " [PARSE ERROR]",
110+
data: {
111+
error: "Failed to decode proto",
112+
rawBase64: data,
113+
errorMessage: error.toString()
114+
},
115+
};
112116
}
113117
} else if (dataType === "request") {
114118
console.warn(`Request ${foundMethod[0]} Not Implemented`)
119+
returnObject = {
120+
methodId: foundMethod[0],
121+
methodName: remasterOrCleanMethodString(foundMethodString) + " [NOT IMPLEMENTED]",
122+
data: {
123+
error: "Proto not implemented",
124+
rawBase64: data
125+
},
126+
};
115127
}
116128
if (foundMethod[2] != null && dataType === "response") {
117129
try {
118-
let parsedData = foundMethod[2].decode(b64Decode(data)).toJSON();
130+
let parsedData;
131+
if (!data || data === "") {
132+
parsedData = {};
133+
} else {
134+
parsedData = foundMethod[2].decode(b64Decode(data)).toJSON();
135+
}
119136
if (foundMethod[0] === 5012 && action_social > 0 && parsedData.payload) {
120137
parsedData.payload = DecoderInternalPayloadAsResponse(action_social, parsedData.payload);
121138
}
@@ -129,11 +146,40 @@ export const decodeProto = (method: number, data: string, dataType: string): Dec
129146
};
130147
} catch (error) {
131148
console.error(`Error parsing response ${foundMethodString} method: [${foundReq}] -> ${error}`);
149+
returnObject = {
150+
methodId: foundMethod[0],
151+
methodName: remasterOrCleanMethodString(foundMethodString) + " [PARSE ERROR]",
152+
data: {
153+
error: "Failed to decode proto",
154+
rawBase64: data,
155+
errorMessage: error.toString()
156+
},
157+
};
132158
}
133159
} else if (dataType === "response") {
134160
console.warn(`Response ${foundReq} Not Implemented`)
161+
returnObject = {
162+
methodId: foundMethod[0],
163+
methodName: remasterOrCleanMethodString(foundMethodString) + " [NOT IMPLEMENTED]",
164+
data: {
165+
error: "Proto not implemented",
166+
rawBase64: data
167+
},
168+
};
135169
}
136170
}
137171
}
172+
173+
if (!methodFound && returnObject === "Not Found") {
174+
returnObject = {
175+
methodId: method.toString(),
176+
methodName: `Unknown Method ${method} [UNKNOWN]`,
177+
data: {
178+
error: "Unknown method ID",
179+
rawBase64: data
180+
},
181+
};
182+
}
183+
138184
return returnObject;
139185
};

src/types/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ export type DecodedProto = {
22
identifier?: string;
33
methodId: string;
44
methodName: string;
5-
data: string;
5+
data: any;
66
};

src/utils/index.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import { WebStreamBuffer } from "./web-stream-buffer";
55
import { decodePayloadTraffic } from "../parser/proto-parser";
66

77
export const b64Decode = (data: string) => {
8+
if (!data || data === "") {
9+
return Buffer.alloc(0);
10+
}
811
return Buffer.from(data, "base64");
912
};
1013

@@ -30,13 +33,27 @@ export function getIPAddress() {
3033
return '0.0.0.0';
3134
}
3235

33-
export function handleData(incoming: WebStreamBuffer, outgoing: WebStreamBuffer, identifier: any, parsedData: string) {
36+
export function handleData(incoming: WebStreamBuffer, outgoing: WebStreamBuffer, identifier: any, parsedData: string, sampleSaver?: any) {
3437
for (let i = 0; i < parsedData['protos'].length; i++) {
38+
const rawRequest = parsedData['protos'][i].request || "";
39+
const rawResponse = parsedData['protos'][i].response || "";
40+
3541
const parsedRequestData = decodePayloadTraffic(
3642
parsedData['protos'][i].method,
37-
parsedData['protos'][i].request,
43+
rawRequest,
3844
"request"
3945
);
46+
const parsedResponseData = decodePayloadTraffic(
47+
parsedData['protos'][i].method,
48+
rawResponse,
49+
"response"
50+
);
51+
52+
// Save sample if enabled
53+
if (sampleSaver && parsedRequestData.length > 0 && parsedResponseData.length > 0) {
54+
sampleSaver.savePair(parsedRequestData[0], parsedResponseData[0], rawRequest, rawResponse, "traffic");
55+
}
56+
4057
if (typeof parsedRequestData === "string") {
4158
incoming.write({ error: parsedRequestData });
4259
} else {
@@ -45,11 +62,7 @@ export function handleData(incoming: WebStreamBuffer, outgoing: WebStreamBuffer,
4562
incoming.write(parsedObject);
4663
}
4764
}
48-
const parsedResponseData = decodePayloadTraffic(
49-
parsedData['protos'][i].method,
50-
parsedData['protos'][i].response,
51-
"response"
52-
);
65+
5366
if (typeof parsedResponseData === "string") {
5467
outgoing.write({ error: parsedResponseData });
5568
} else {

0 commit comments

Comments
 (0)