UNPKG

@bitrix24/b24jssdk

Version:

Bitrix24 REST API JavaScript SDK

1 lines 21.4 kB
{"version":3,"file":"controller.mjs","sources":["../../../../src/frame/message/controller.ts"],"sourcesContent":["import type { MessageCommands } from './commands'\nimport type { AppFrame } from '../frame'\nimport type { LoggerInterface } from '../../logger'\nimport { LoggerFactory } from '../../logger'\nimport { Type } from '../../tools/type'\nimport { Text } from '../../tools/text'\nimport { omit } from '../../tools'\nimport { SdkError } from '../../core/sdk-error'\n\n/**\n * Ceiling on {@link MessageManager.#rejectedOrigins}. The key is chosen by the\n * sender, so the set is only bounded if we bound it (#146).\n */\nconst MAX_REJECTED_ORIGINS = 50\n\n/**\n * How much of an inbound callback id may appear in an error message. The id is\n * sender-chosen, and error messages reach logs (#146).\n */\nconst MAX_CALLBACK_ID_IN_ERROR = 64\n\ninterface PromiseHandlers {\n resolve: (value: any) => void\n reject: (reason?: any) => void\n timeoutId: any\n}\n\n/**\n * Parent Window Request Parameters\n * - `isRawValue?: boolean` if true then JSON.stringify will not be executed\n * - `isSafely?: boolean` auto completion mode Promise.resolve()\n * - `safelyTime?: number` after what time (900 ms) should it be automatically resolved Promise\n * - `callBack?: () => void` for placement event\n * - `requestId?: string` Unique request identifier for tracking. Used for query deduplication and debugging.\n */\nexport interface SendParams {\n isRawValue?: boolean\n isSafely?: boolean\n safelyTime?: number\n callBack?: (...args: any[]) => void\n requestId?: string\n // @todo add this\n // singleOption: any\n [index: string]: any\n}\n\n/**\n * Parent Window Communication Manager at B24\n */\nexport class MessageManager {\n #appFrame: AppFrame\n #callbackPromises: Map<string, PromiseHandlers>\n #callbackSingletone: Map<string, (...args: any[]) => void>\n // origins already warned about (#244) — dedup so a peer spamming postMessage\n // from a foreign origin can't flood a wired logger sink. Capped, because the\n // dedup key is attacker-chosen: a peer can post from an unbounded supply of\n // distinct origins (`a.evil.test`, `b.evil.test`, …) and every unseen one adds\n // an entry. Past the cap the set stops growing and later origins are simply\n // not warned about — losing a log line is the right trade against unbounded\n // memory in a long-lived frame (#146).\n #rejectedOrigins: Set<string> = new Set()\n\n protected _logger: LoggerInterface\n\n private readonly runCallbackHandler: OmitThisParameter<(event: MessageEvent) => void>\n\n constructor(appFrame: AppFrame) {\n this._logger = LoggerFactory.createNullLogger()\n this.#appFrame = appFrame\n\n this.#callbackPromises = new Map()\n this.#callbackSingletone = new Map()\n\n this.runCallbackHandler = this._runCallback.bind(this)\n }\n\n setLogger(logger: LoggerInterface): void {\n this._logger = logger\n }\n\n getLogger(): LoggerInterface {\n return this._logger\n }\n\n // region Events ////\n /**\n * Subscribe to the onMessage event of the parent window\n */\n subscribe() {\n window.addEventListener('message', this.runCallbackHandler)\n }\n\n /**\n * Unsubscribe from the onMessage event of the parent window, and tear the\n * manager down.\n *\n * Removing the listener is not enough. Every in-flight `send()` is waiting on\n * a promise that only the listener could settle, so dropping the listener\n * alone strands each of them **forever** — with its `isSafely` timer still\n * armed and its entry still in the callback map. `B24Frame.destroy()` calls\n * this, so an SPA that mounts and unmounts the frame accumulated one such set\n * per cycle (#146; the same class of leak as #222 in `PullClient`).\n *\n * Pending sends are therefore **rejected**, not left hanging, with\n * `JSSDK_FRAME_DISPOSED` — mirroring how a disposed `PullClient` rejects\n * `start()` with `PULL_DISPOSED`. A caller awaiting a command that can no\n * longer be answered should learn that; silence is the one outcome it cannot\n * act on.\n *\n * Note the consequence: a `send()` whose result was discarded without a\n * `.catch()` turns into an unhandled rejection at teardown. Most SDK commands\n * pass `isSafely`, which settles them on their own timer, so they are normally\n * already gone by the time this runs — but **not all of them do**.\n * `ParentManager.closeApplication()` and `SliderManager.closeSliderAppPage()`\n * deliberately pass `isSafely: false` (\"everything will be closed, and timeout\n * will not be able to do anything\"), and those are exactly the calls made as\n * an app tears itself down — the likeliest race with this method. The awaited\n * commands (`getInitData`, `refreshAuth`, the dialog selectors) send without\n * `isSafely` too, but their callers await them, so the rejection surfaces\n * where it can be handled.\n *\n * A caller that fires `closeApplication()` without awaiting it should attach\n * `.catch(() => {})` if it also tears the frame down in the same breath.\n */\n unsubscribe(): void {\n window.removeEventListener('message', this.runCallbackHandler)\n\n for (const [key, promise] of this.#callbackPromises) {\n if (promise.timeoutId) {\n clearTimeout(promise.timeoutId)\n }\n\n this.#callbackPromises.delete(key)\n promise.reject(new SdkError({\n code: 'JSSDK_FRAME_DISPOSED',\n description: 'The B24Frame was destroyed before the parent window answered this command.',\n status: 0\n }))\n }\n\n // Placement event handlers are registered for the lifetime of the frame and\n // are never fired again once the listener is gone.\n this.#callbackSingletone.clear()\n this.#rejectedOrigins.clear()\n }\n\n // endregion ////\n\n /**\n * Send message to parent window\n * The answer (if) we will get in _runCallback\n *\n * @param command\n * @param params\n */\n async send(\n command: string | MessageCommands,\n params: null | SendParams = null\n ): Promise<any> {\n return new Promise((resolve, reject) => {\n let cmd: string | object\n const promiseHandler: PromiseHandlers = {\n resolve,\n reject,\n timeoutId: null\n }\n\n const keyPromise = this.#setCallbackPromise(promiseHandler)\n let paramsSend: null | string | Record<string, any> = null\n\n const optionsSend = omit(params || {}, ['singleOption', 'callBack', 'isSafely', 'safelyTime', 'requestId'])\n const { callBack, singleOption, requestId } = params || {}\n if (callBack) {\n this.#callbackSingletone.set(keyPromise, callBack)\n }\n\n if (singleOption) {\n paramsSend = singleOption\n } else if (Object.keys(optionsSend).length > 0) {\n paramsSend = { ...optionsSend }\n }\n\n if (command.toString().includes(':')) {\n cmd = {\n method: command.toString(),\n params: paramsSend || '',\n callback: keyPromise,\n appSid: this.#appFrame.getAppSid(),\n requestId\n }\n } else {\n cmd = command.toString()\n\n if (\n params?.isRawValue !== true\n && paramsSend\n ) {\n paramsSend = JSON.stringify(paramsSend)\n } else if (\n params?.isRawValue === true\n && paramsSend\n && Type.isPlainObject(paramsSend)\n && paramsSend['value']\n ) {\n paramsSend = paramsSend['value']\n }\n\n const listParams = [\n paramsSend || '',\n keyPromise,\n this.#appFrame.getAppSid()\n ]\n\n cmd += ':' + listParams.filter(Boolean).join(':')\n }\n\n // Log only the command + callback key, never the assembled `cmd` string:\n // for setAppOption / setUserOption it carries the serialised option\n // `value`, which an app may use to store a credential (#43).\n this.getLogger().debug(`send to ${this.#appFrame.getTargetOrigin()}`, {\n command: command.toString(),\n callbackKey: keyPromise,\n origin: this.#appFrame.getTargetOrigin()\n }).catch(() => {})\n\n parent.postMessage(cmd, this.#appFrame.getTargetOrigin())\n\n if (params?.isSafely) {\n const safelyTime = Number.parseInt(String(params?.safelyTime || 900))\n this.#callbackPromises.get(keyPromise)!.timeoutId = window.setTimeout(\n () => {\n if (this.#callbackPromises.has(keyPromise)) {\n this.getLogger().warning(`action ${command.toString()} stop by timeout`, {\n command: command.toString(),\n safelyTime\n }).catch(() => {})\n\n this.#callbackPromises.delete(keyPromise)\n resolve({ isSafely: true })\n }\n },\n safelyTime\n )\n }\n })\n }\n\n /**\n * Fulfilling a promise based on messages from the parent window\n *\n * @param event\n * @private\n */\n public _runCallback(event: MessageEvent): void {\n if (event.origin !== this.#appFrame.getTargetOrigin()) {\n // Surface a message from an unexpected origin (a probe, or a misconfigured\n // parent) — log the origins only, never event.data, which may carry the\n // AUTH_ID / REFRESH_ID a foreign sender must not have echoed back (#244).\n // Log once per distinct origin so a spamming peer can't flood the sink.\n if (!this.#rejectedOrigins.has(event.origin) && this.#rejectedOrigins.size < MAX_REJECTED_ORIGINS) {\n this.#rejectedOrigins.add(event.origin)\n this.getLogger().warning('message rejected: unexpected origin', {\n origin: event.origin,\n expected: this.#appFrame.getTargetOrigin()\n }).catch(() => {})\n }\n\n return\n }\n\n // The wire format is a colon-joined string. Anything else on this origin is\n // not ours: `postMessage` is a shared channel, and a page hosting the frame\n // may carry other libraries (or a browser extension) posting objects on it.\n // `event.data.split` on such a message threw a TypeError out of a window\n // event listener — an uncaught error, on traffic the SDK simply should have\n // ignored (#146).\n if (typeof event.data === 'string' && event.data.length > 0) {\n // Narrowing `event.data` to `string` above also made this indexing\n // checked — it used to sit behind `any`. `split` on a non-empty string\n // always yields at least one element, so the fallback is unreachable, but\n // it keeps the type honest rather than asserting it away.\n const [id = '', ...rest] = event.data.split(':')\n\n const cmd: { id: string, args: any } = {\n id,\n args: rest.join(':')\n }\n\n // Log only the callback id and origin — never `event.data` / `cmd.args`.\n // The inbound message carries the auth tokens (AUTH_ID / REFRESH_ID) for\n // refreshAuth / getInitData responses, embedded in the colon-joined\n // payload as an opaque substring a redactor can't see (#43).\n this.getLogger().debug(`get from ${event.origin}`, {\n id: cmd.id,\n origin: event.origin\n }).catch(() => {})\n\n if (cmd.args) {\n try {\n cmd.args = JSON.parse(cmd.args)\n } catch {\n // A payload we cannot read is not a payload we may guess at. Before\n // this, the throw escaped the listener and left the waiting promise\n // pending forever — the caller was told nothing, and waited for an\n // answer that had in fact already arrived, broken (#146).\n //\n // The caught error is deliberately not logged and not attached as\n // `cause`. V8 quotes the offending input in its message — `Unexpected\n // token 'a', \"auth=...\" is not valid JSON` — and this payload is the\n // one that carries AUTH_ID / REFRESH_ID (#43). The id and origin below\n // say which command failed, which is what a reader needs.\n this.getLogger().warning('message dropped: payload is not valid JSON', {\n id: cmd.id,\n origin: event.origin\n }).catch(() => {})\n\n // `cmd.id` is the first colon-segment of an inbound message, so its\n // content and length are chosen by the sender. It is a callback key,\n // not a credential — but unlike the payload it DOES reach logs, via\n // SdkError's enumerable `message`. Truncated so a sender cannot use\n // this description as an amplifier.\n this.#rejectPromise(cmd.id, new SdkError({\n code: 'JSSDK_FRAME_BAD_PAYLOAD',\n description: `The parent window answered command \"${cmd.id.slice(0, MAX_CALLBACK_ID_IN_ERROR)}\" with a payload that is not valid JSON.`,\n status: 0\n }))\n\n return\n }\n }\n\n if (this.#callbackPromises.has(cmd.id)) {\n const promise = this.#callbackPromises.get(cmd.id) as PromiseHandlers\n if (promise.timeoutId) {\n clearTimeout(promise.timeoutId)\n }\n\n this.#callbackPromises.delete(cmd.id)\n\n promise.resolve(cmd.args)\n // promise.reject(cmd.args) ////\n } else if (this.#callbackSingletone.has(cmd.id)) {\n const callBack = this.#callbackSingletone.get(cmd.id) as (...args: any[]) => void\n if (callBack) {\n callBack.apply(globalThis, [cmd.args])\n }\n }\n }\n }\n\n /**\n * Settle a waiting promise with a rejection, if one is still waiting.\n *\n * Silent when the key is unknown: a payload can arrive for a command that\n * already timed out under `isSafely`, and there is nothing left to reject.\n */\n #rejectPromise(key: string, error: SdkError): void {\n const promise = this.#callbackPromises.get(key)\n if (!promise) {\n return\n }\n\n if (promise.timeoutId) {\n clearTimeout(promise.timeoutId)\n }\n\n this.#callbackPromises.delete(key)\n promise.reject(error)\n }\n\n /**\n * Storing a promise for a message from the parent window\n *\n * @param promiseHandler\n * @private\n *\n * @memo We don't use Symbol here, because we need to pass it to the parent and then find and restore it.\n */\n #setCallbackPromise(promiseHandler: PromiseHandlers): string {\n const key = Text.getUniqId()\n this.#callbackPromises.set(key, promiseHandler)\n return key\n }\n}\n"],"names":[],"mappings":"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"}