From 2a1206b00974ed59f6a097aa347a77ae0cf3d33c Mon Sep 17 00:00:00 2001 From: RaizeTheLimit Date: Mon, 15 Sep 2025 14:07:29 +0700 Subject: [PATCH 1/3] feat(mobile-ui): add responsive design, add ability to quick copy proto message data --- src/parser/proto-parser.ts | 86 ++++++++++++++---- src/types/index.ts | 2 +- src/utils/index.ts | 3 + src/views/css/style.css | 112 +++++++++++++++++++++++ src/views/print-protos.html | 176 ++++++++++++++++++++++++++++-------- 5 files changed, 319 insertions(+), 60 deletions(-) diff --git a/src/parser/proto-parser.ts b/src/parser/proto-parser.ts index 700ea27..1512278 100644 --- a/src/parser/proto-parser.ts +++ b/src/parser/proto-parser.ts @@ -2,35 +2,22 @@ import { b64Decode } from "../utils"; import { requestMessagesResponses } from "../constants"; import { DecodedProto } from "../types"; -// For decode dynamics action social. let action_social = 0; -/** - * Callback as used by {@link DecoderInternalPayloadAsResponse}. - * @type {function} - * @param {number|any} - */ -/** - * Returns decoded proto as JSON. Uses Tuples by https://github.com/Furtif/pogo-protos/blob/master/test/test.js, if that implemented. - */ function DecoderInternalPayloadAsResponse(method: number, data: any): any { - // Reset value. action_social = 0; let proto_tuple: any = Object.values(requestMessagesResponses)[method]; let result: any = { Not_Implemented_yet: data }; + + if (!data) { + return {}; + } for (let i = 0; i < Object.keys(requestMessagesResponses).length; i++) { proto_tuple = Object.values(requestMessagesResponses)[i]; const my_req = proto_tuple[0]; if (my_req == method) { - if (proto_tuple[2] != null && b64Decode(data)) { + if (proto_tuple[2] != null && data && b64Decode(data).length > 0) { try { result = proto_tuple[2].decode(b64Decode(data)).toJSON(); - /* - // This not need more because protos as replaced bytes for the proto. - if (method == 10010) { - let profile = POGOProtos.Rpc.PlayerPublicProfileProto.decode(b64Decode(result.friend[0].player.public_data)).toJSON(); - result.friend[0].player.public_data = profile; - } - */ } catch (error) { console.error(`Intenal ProxySocial decoder ${my_req} Error: ${error}`); @@ -85,14 +72,22 @@ export const decodePayload = (contents: any, dataType: string): DecodedProto[] = export const decodeProto = (method: number, data: string, dataType: string): DecodedProto | string => { let returnObject: DecodedProto | string = "Not Found"; + let methodFound = false; + for (let i = 0; i < Object.keys(requestMessagesResponses).length; i++) { let foundMethod: any = Object.values(requestMessagesResponses)[i]; let foundMethodString: string = Object.keys(requestMessagesResponses)[i]; const foundReq = foundMethod[0]; if (foundReq == method) { + methodFound = true; if (foundMethod[1] != null && dataType === "request") { try { - let parsedData = foundMethod[1].decode(b64Decode(data)).toJSON(); + let parsedData; + if (!data || data === "") { + parsedData = {}; + } else { + parsedData = foundMethod[1].decode(b64Decode(data)).toJSON(); + } if (foundMethod[0] === 5012 || foundMethod[0] === 600005) { action_social = parsedData.action; Object.values(requestMessagesResponses).forEach(val => { @@ -109,13 +104,35 @@ export const decodeProto = (method: number, data: string, dataType: string): Dec }; } catch (error) { console.error(`Error parsing request ${foundMethodString} -> ${error}`); + returnObject = { + methodId: foundMethod[0], + methodName: remasterOrCleanMethodString(foundMethodString) + " [PARSE ERROR]", + data: { + error: "Failed to decode proto", + rawBase64: data, + errorMessage: error.toString() + }, + }; } } else if (dataType === "request") { console.warn(`Request ${foundMethod[0]} Not Implemented`) + returnObject = { + methodId: foundMethod[0], + methodName: remasterOrCleanMethodString(foundMethodString) + " [NOT IMPLEMENTED]", + data: { + error: "Proto not implemented", + rawBase64: data + }, + }; } if (foundMethod[2] != null && dataType === "response") { try { - let parsedData = foundMethod[2].decode(b64Decode(data)).toJSON(); + let parsedData; + if (!data || data === "") { + parsedData = {}; + } else { + parsedData = foundMethod[2].decode(b64Decode(data)).toJSON(); + } if (foundMethod[0] === 5012 && action_social > 0 && parsedData.payload) { parsedData.payload = DecoderInternalPayloadAsResponse(action_social, parsedData.payload); } @@ -129,11 +146,40 @@ export const decodeProto = (method: number, data: string, dataType: string): Dec }; } catch (error) { console.error(`Error parsing response ${foundMethodString} method: [${foundReq}] -> ${error}`); + returnObject = { + methodId: foundMethod[0], + methodName: remasterOrCleanMethodString(foundMethodString) + " [PARSE ERROR]", + data: { + error: "Failed to decode proto", + rawBase64: data, + errorMessage: error.toString() + }, + }; } } else if (dataType === "response") { console.warn(`Response ${foundReq} Not Implemented`) + returnObject = { + methodId: foundMethod[0], + methodName: remasterOrCleanMethodString(foundMethodString) + " [NOT IMPLEMENTED]", + data: { + error: "Proto not implemented", + rawBase64: data + }, + }; } } } + + if (!methodFound && returnObject === "Not Found") { + returnObject = { + methodId: method.toString(), + methodName: `Unknown Method ${method} [UNKNOWN]`, + data: { + error: "Unknown method ID", + rawBase64: data + }, + }; + } + return returnObject; }; \ No newline at end of file diff --git a/src/types/index.ts b/src/types/index.ts index ad35f5c..333c98c 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -2,5 +2,5 @@ export type DecodedProto = { identifier?: string; methodId: string; methodName: string; - data: string; + data: any; }; diff --git a/src/utils/index.ts b/src/utils/index.ts index 6be638d..02161ef 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -5,6 +5,9 @@ import { WebStreamBuffer } from "./web-stream-buffer"; import { decodePayloadTraffic } from "../parser/proto-parser"; export const b64Decode = (data: string) => { + if (!data || data === "") { + return Buffer.alloc(0); + } return Buffer.from(data, "base64"); }; diff --git a/src/views/css/style.css b/src/views/css/style.css index c102253..e0100ad 100644 --- a/src/views/css/style.css +++ b/src/views/css/style.css @@ -118,4 +118,116 @@ table tr td.important { text-align: right; border-top: 2px solid rgba(255, 255, 255, 0.5); width: 100%; +} + +/* Mobile styles - hide by default */ +.mobile-only { + display: none !important; +} + +.text-center { + text-align: center; +} + +.clickable-data:hover { + background-color: rgba(0, 123, 255, 0.05) !important; + border: 1px solid rgba(0, 123, 255, 0.2); + transition: all 0.2s ease; +} + +.dark .clickable-data:hover { + background-color: rgba(0, 123, 255, 0.1) !important; + border: 1px solid rgba(0, 123, 255, 0.3); +} + +/* Mobile breakpoint */ +@media (max-width: 768px) { + .mobile-hide { + display: none !important; + } + + .mobile-only { + display: table-cell !important; + } + + /* Optimize table for mobile */ + #data_socket { + font-size: smaller; + } + + #data_socket th, + #data_socket td { + padding: 4px !important; + font-size: 11px; + } + + /* Make method name wrap on mobile */ + #data_socket td:nth-child(3) { + word-break: break-word; + max-width: 120px; + } + + /* Filters optimization for mobile */ + .col-sm-10, .col-sm-2 { + padding: 5px !important; + } + + #filter-mode, #instance-filter-dropdown, #maxlogs { + width: 100% !important; + margin-bottom: 5px; + } + + #method-filter-ids { + width: 100% !important; + margin-top: 5px; + } + + label { + display: block !important; + width: 100% !important; + margin-bottom: 3px; + } + + /* Card header for mobile */ + .card-header .title-proto { + font-size: 16px !important; + } + + .card-header .icons i { + font-size: 12px !important; + margin-right: 8px !important; + } + + /* Footer for mobile */ + .footer { + font-size: 10px; + padding: 5px; + } + + /* Modal optimization for mobile */ + .modal-dialog { + max-width: 95% !important; + margin: 10px auto !important; + } + + .modal-content { + margin: 0 auto; + } + + .modal-body { + padding: 10px !important; + max-height: 70vh; + overflow-y: auto; + } + + .modal-footer { + padding: 10px !important; + flex-wrap: wrap; + } + + .modal-footer button { + margin: 3px !important; + font-size: 12px !important; + padding: 5px 10px !important; + } } \ No newline at end of file diff --git a/src/views/print-protos.html b/src/views/print-protos.html index d5992c0..9f588e4 100644 --- a/src/views/print-protos.html +++ b/src/views/print-protos.html @@ -96,11 +96,14 @@

> - Instance + Instance Method Method Name - Sended Data - Received Data + Sended Data + Received Data + Req + Res + DL @@ -132,10 +135,10 @@