From 13f1782ec1328c18ebd76395f57b9062b4bd6d5b Mon Sep 17 00:00:00 2001 From: nezumi0627 Date: Tue, 30 Dec 2025 23:45:05 +0900 Subject: [PATCH 1/3] refactor: extract push protocol logic to protocol.ts --- packages/linejs/base/push/connManager.ts | 53 ++---------------------- packages/linejs/base/push/protocol.ts | 32 ++++++++++++++ 2 files changed, 36 insertions(+), 49 deletions(-) create mode 100644 packages/linejs/base/push/protocol.ts diff --git a/packages/linejs/base/push/connManager.ts b/packages/linejs/base/push/connManager.ts index 82ebc64..3cfd551 100644 --- a/packages/linejs/base/push/connManager.ts +++ b/packages/linejs/base/push/connManager.ts @@ -1,35 +1,5 @@ -import { LegyH2PushFrame } from "./connData.ts"; -import { Conn } from "./conn.ts"; -import { BaseClient } from "@evex/linejs/base"; -// TODO: fix this -import { TCompactProtocol } from "npm:thrift@^0.20.0"; - -import { TMoreCompactProtocol } from "../thrift/readwrite/tmc.ts"; - -// GOMI: -import { - PartialDeep, - SquareService_fetchMyEvents_args as gen_SquareService_fetchMyEvents_args, - sync_args as gen_sync_args, -} from "../thrift/readwrite/struct.ts"; - -import { - Operation, - SquareEvent, - SquareService_fetchMyEvents_args, - SquareService_fetchMyEvents_result, - sync_args, - sync_result, -} from "@evex/linejs-types"; - -import { ParsedThrift } from "@evex/linejs/thrift"; -import { Buffer } from "node:buffer"; - -function gen_m(ss = [1, 3, 5, 6, 8, 9, 10]) { - let i = 0; - for (const s of ss) i |= 1 << (s - 1); - return i; -} +import { PushProtocol } from "./protocol.ts"; + export interface ReadableStreamWriter { stream: ReadableStream; @@ -150,7 +120,7 @@ export class ConnManager { .getHeader(); tosendHeaders["content-type"] = "application/octet-stream"; tosendHeaders["accept"] = "application/octet-stream"; - const m = gen_m(initServices); + const m = PushProtocol.genServiceBitmask(initServices); this.log(`Using \`m=${m}\` on \`/PUSH\``); const host = this.client.request.endpoint; const port = 443; @@ -158,16 +128,6 @@ export class ConnManager { return _conn; } - buildRequest(service: number, data: Uint8Array): Uint8Array { - const len = data.length; - const out = new Uint8Array(2 + 1 + len); - out[0] = (len >> 8) & 0xff; - out[1] = len & 0xff; - out[2] = service & 0xff; - out.set(data, 3); - return out; - } - async buildAndSendSignOnRequest( conn: Conn, serviceType: number, @@ -203,12 +163,7 @@ export class ConnManager { ); methodName = "sync"; } - const header = new Uint8Array(2 + 1 + 1 + 2 + req.length); - header.set(idBuf, 0); - header[2] = serviceType & 0xff; - header[3] = 0; - header[4] = (req.length >> 8) & 0xff; - header[5] = req.length & 0xff; + const header = PushProtocol.buildSignOnHeader(id, serviceType, req.length); header.set(req, 6); this.SignOnRequests[id] = [serviceType, methodName, null]; this.log( diff --git a/packages/linejs/base/push/protocol.ts b/packages/linejs/base/push/protocol.ts new file mode 100644 index 0000000..a2a7122 --- /dev/null +++ b/packages/linejs/base/push/protocol.ts @@ -0,0 +1,32 @@ +export class PushProtocol { + static genServiceBitmask(ss: number[] = [1, 3, 5, 6, 8, 9, 10]): number { + let i = 0; + for (const s of ss) i |= 1 << (s - 1); + return i; + } + + static buildRequest(service: number, data: Uint8Array): Uint8Array { + const len = data.length; + const out = new Uint8Array(2 + 1 + len); + out[0] = (len >> 8) & 0xff; + out[1] = len & 0xff; + out[2] = service & 0xff; + out.set(data, 3); + return out; + } + + static buildSignOnHeader( + id: number, + serviceType: number, + payloadLength: number, + ): Uint8Array { + const header = new Uint8Array(2 + 1 + 1 + 2); + header[0] = (id >> 8) & 0xff; + header[1] = id & 0xff; + header[2] = serviceType & 0xff; + header[3] = 0; + header[4] = (payloadLength >> 8) & 0xff; + header[5] = payloadLength & 0xff; + return header; + } +} From f68d89b11574d82cfcbb870b143235089e284511 Mon Sep 17 00:00:00 2001 From: nezumi0627 Date: Tue, 30 Dec 2025 23:46:23 +0900 Subject: [PATCH 2/3] refactor: use PushProtocol in ConnManager and restore imports --- packages/linejs/base/push/connManager.ts | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/packages/linejs/base/push/connManager.ts b/packages/linejs/base/push/connManager.ts index 3cfd551..2a275b1 100644 --- a/packages/linejs/base/push/connManager.ts +++ b/packages/linejs/base/push/connManager.ts @@ -1,4 +1,35 @@ import { PushProtocol } from "./protocol.ts"; +import { LegyH2PushFrame } from "./connData.ts"; +import { Conn } from "./conn.ts"; +import { BaseClient } from "@evex/linejs/base"; +// TODO: fix this +import { TCompactProtocol } from "npm:thrift@^0.20.0"; + +import { TMoreCompactProtocol } from "../thrift/readwrite/tmc.ts"; + +import { + PartialDeep, + SquareService_fetchMyEvents_args as gen_SquareService_fetchMyEvents_args, + sync_args as gen_sync_args, +} from "../thrift/readwrite/struct.ts"; + +import { + Operation, + SquareEvent, + SquareService_fetchMyEvents_args, + SquareService_fetchMyEvents_result, + sync_args, + sync_result, +} from "@evex/linejs-types"; + +import { ParsedThrift } from "@evex/linejs/thrift"; +import { Buffer } from "node:buffer"; + +function gen_m(ss = [1, 3, 5, 6, 8, 9, 10]) { + let i = 0; + for (const s of ss) i |= 1 << (s - 1); + return i; +} export interface ReadableStreamWriter { From a49aa2b2b634d35a764199d9156d4ce9f3ec7866 Mon Sep 17 00:00:00 2001 From: nezumi0627 Date: Wed, 31 Dec 2025 03:30:10 +0900 Subject: [PATCH 3/3] refactor: fix buffer overflow and type issues in push protocol --- packages/linejs/base/push/conn.ts | 7 ++-- packages/linejs/base/push/connManager.ts | 37 ++++-------------- packages/linejs/base/push/protocol.ts | 50 ++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 32 deletions(-) create mode 100644 packages/linejs/base/push/protocol.ts diff --git a/packages/linejs/base/push/conn.ts b/packages/linejs/base/push/conn.ts index 7797b00..edc4eaa 100644 --- a/packages/linejs/base/push/conn.ts +++ b/packages/linejs/base/push/conn.ts @@ -1,3 +1,4 @@ +import { PushProtocol } from "./protocol.ts"; import { BaseClient } from "../core/mod.ts"; import { LegyH2PingFrame, @@ -16,7 +17,7 @@ export class Conn { cacheData: Uint8Array = new Uint8Array(0); notFinPayloads: Record = {}; reqStream?: ReadableStreamWriter & { abort: AbortController }; - resStream?: ReadableStream; + resStream?: ReadableStream>; private _lastSendTime = 0; private _closed = false; @@ -39,7 +40,7 @@ export class Conn { const chunks: Uint8Array[] = []; const encoder = new TextEncoder(); - const stream = new ReadableStream({ + const stream = new ReadableStream>({ start(c) { controller = c; }, @@ -129,7 +130,7 @@ export class Conn { } async writeRequest(requestType: number, data: Uint8Array) { - const d = this.manager.buildRequest(requestType, data); + const d = PushProtocol.buildRequest(requestType, data); await this.writeByte(d); } diff --git a/packages/linejs/base/push/connManager.ts b/packages/linejs/base/push/connManager.ts index 82ebc64..910b394 100644 --- a/packages/linejs/base/push/connManager.ts +++ b/packages/linejs/base/push/connManager.ts @@ -1,3 +1,4 @@ +import { PushProtocol } from "./protocol.ts"; import { LegyH2PushFrame } from "./connData.ts"; import { Conn } from "./conn.ts"; import { BaseClient } from "@evex/linejs/base"; @@ -6,7 +7,6 @@ import { TCompactProtocol } from "npm:thrift@^0.20.0"; import { TMoreCompactProtocol } from "../thrift/readwrite/tmc.ts"; -// GOMI: import { PartialDeep, SquareService_fetchMyEvents_args as gen_SquareService_fetchMyEvents_args, @@ -25,11 +25,7 @@ import { import { ParsedThrift } from "@evex/linejs/thrift"; import { Buffer } from "node:buffer"; -function gen_m(ss = [1, 3, 5, 6, 8, 9, 10]) { - let i = 0; - for (const s of ss) i |= 1 << (s - 1); - return i; -} + export interface ReadableStreamWriter { stream: ReadableStream; @@ -46,7 +42,7 @@ export class ConnManager { SignOnRequests: Record = {}; OnPingCallback: (id: number) => void; OnSignReqResp: Record = {}; - OnSignOnResponse: (reqId: number, isFin: boolean, data: Uint8Array) => void; + OnSignOnResponse: (reqId: number, isFin: boolean, data: Uint8Array) => void; OnPushResponse: (frame: LegyH2PushFrame) => void; _eventSynced = false; _pingInterval = 30; @@ -150,7 +146,7 @@ export class ConnManager { .getHeader(); tosendHeaders["content-type"] = "application/octet-stream"; tosendHeaders["accept"] = "application/octet-stream"; - const m = gen_m(initServices); + const m = PushProtocol.genServiceBitmask(initServices); this.log(`Using \`m=${m}\` on \`/PUSH\``); const host = this.client.request.endpoint; const port = 443; @@ -158,30 +154,19 @@ export class ConnManager { return _conn; } - buildRequest(service: number, data: Uint8Array): Uint8Array { - const len = data.length; - const out = new Uint8Array(2 + 1 + len); - out[0] = (len >> 8) & 0xff; - out[1] = len & 0xff; - out[2] = service & 0xff; - out.set(data, 3); - return out; - } + async buildAndSendSignOnRequest( conn: Conn, serviceType: number, kwargs: Record = {}, ): Promise<{ - payload: Uint8Array; + payload: Uint8Array; id: number; }> { this.log("buildAndSendSignOnRequest", { serviceType, kwargs }); const cl = this.client; const id = Object.keys(this.SignOnRequests).length + 1; - const idBuf = new Uint8Array(2); - idBuf[0] = (id >> 8) & 0xff; - idBuf[1] = id & 0xff; let methodName: string | undefined; // build payload body depending on serviceType let req = new Uint8Array(0); @@ -203,13 +188,7 @@ export class ConnManager { ); methodName = "sync"; } - const header = new Uint8Array(2 + 1 + 1 + 2 + req.length); - header.set(idBuf, 0); - header[2] = serviceType & 0xff; - header[3] = 0; - header[4] = (req.length >> 8) & 0xff; - header[5] = req.length & 0xff; - header.set(req, 6); + const header = PushProtocol.buildSignOnRequest(id, serviceType, req); this.SignOnRequests[id] = [serviceType, methodName, null]; this.log( `[H2][PUSH] send sign-on-request. requestId:${id}, service:${serviceType}`, @@ -221,7 +200,7 @@ export class ConnManager { async _OnSignOnResponse( reqId: number, isFin: boolean, - data: Uint8Array, + data: Uint8Array, ): Promise { // data = data.slice(5); const cl = this.client; diff --git a/packages/linejs/base/push/protocol.ts b/packages/linejs/base/push/protocol.ts new file mode 100644 index 0000000..7897d16 --- /dev/null +++ b/packages/linejs/base/push/protocol.ts @@ -0,0 +1,50 @@ +export class PushProtocol { + /** + * Generates a service bitmask for the PUSH connection. + */ + static genServiceBitmask(ss: number[] = [1, 3, 5, 6, 8, 9, 10]): number { + let i = 0; + for (const s of ss) i |= 1 << (s - 1); + return i; + } + + /** + * Builds a standard push request frame. + * [2 bytes length][1 byte service type][payload] + */ + static buildRequest(service: number, data: Uint8Array): Uint8Array { + const len = data.length; + const out = new Uint8Array(3 + len); + out[0] = (len >> 8) & 0xff; + out[1] = len & 0xff; + out[2] = service & 0xff; + out.set(data, 3); + return out; + } + + /** + * Builds a SignOn request packet. + * [2 bytes request id][1 byte service type][1 byte unknown(0)][2 bytes payload length][payload] + */ + static buildSignOnRequest( + requestId: number, + serviceType: number, + payload: Uint8Array, + ): Uint8Array { + const len = payload.length; + const out = new Uint8Array(6 + len); + // Request ID (2 bytes) + out[0] = (requestId >> 8) & 0xff; + out[1] = requestId & 0xff; + // Service Type (1 byte) + out[2] = serviceType & 0xff; + // Unknown (1 byte, always 0) + out[3] = 0; + // Payload Length (2 bytes) + out[4] = (len >> 8) & 0xff; + out[5] = len & 0xff; + // Payload + out.set(payload, 6); + return out; + } +}