Skip to content

Commit ea0842c

Browse files
committed
イベントデータ型チェック
1 parent f4a1844 commit ea0842c

2 files changed

Lines changed: 82 additions & 1 deletion

File tree

src/channel.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,24 @@ import type { MessageData, Transport } from "./types";
33
import { createLogger } from "./log";
44
const logger = createLogger();
55

6+
/**
7+
* メッセージデータの型をチェックします。
8+
* @param obj チェック対象のオブジェクト
9+
* @returns
10+
*/
11+
export function isMessageData(obj: any): obj is MessageData {
12+
if (obj === null || obj === undefined) {
13+
return false;
14+
}
15+
16+
return (
17+
typeof obj === "object" &&
18+
typeof obj.type === "string" &&
19+
typeof obj.requestId === "string" &&
20+
(typeof obj.tabId === "string" || obj.tabId === null)
21+
);
22+
}
23+
624
/**
725
* BroadcastChannel トランスポート実装
826
* iOSだとバックグラウンドタブとの通信うまくいかないかも
@@ -23,6 +41,10 @@ export class BroadcastChannelTransport implements Transport {
2341

2442
private handleMessage(event: MessageEvent) {
2543
if (event.data && typeof event.data === "object" && this.messageCallback) {
44+
if (!isMessageData(event.data)) {
45+
logger.warn(`Received invalid message data:`, event.data);
46+
return;
47+
}
2648
this.messageCallback(event.data as MessageData);
2749
}
2850
}
@@ -62,6 +84,10 @@ export class LocalStorageTransport implements Transport {
6284
if (event.key && event.key.startsWith(`${this.keyPrefix}_`) && event.newValue && this.messageCallback) {
6385
try {
6486
const message = JSON.parse(event.newValue) as MessageData;
87+
if (!isMessageData(message)) {
88+
logger.warn(`Received invalid message data:`, message);
89+
return;
90+
}
6591
this.messageCallback(message);
6692
} catch (e) {
6793
// JSON parse エラーは無視

tests/unit/channel.test.ts

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, it, expect, beforeEach, vi } from 'vitest';
2-
import { LocalStorageTransport, BroadcastChannelTransport, TransportRacer } from '../../src/channel';
2+
import { LocalStorageTransport, BroadcastChannelTransport, TransportRacer, isMessageData } from '../../src/channel';
33
import { MessageData } from '../../src/types';
44

55
describe('LocalStorageTransport', () => {
@@ -133,4 +133,59 @@ describe('TransportRacer', () => {
133133
it('getTransportNamesでトランスポート名が取得できる', () => {
134134
expect(racer.getTransportNames()).toEqual(['localStorage']);
135135
});
136+
});
137+
138+
139+
140+
describe("isMessageData", () => {
141+
it("正しいMessageData型のオブジェクトの場合はtrueを返す", () => {
142+
const obj = {
143+
type: "test",
144+
requestId: "req-1",
145+
tabId: "tab-1"
146+
};
147+
expect(isMessageData(obj)).toBe(true);
148+
});
149+
150+
it("tabIdがnullでもtrueを返す", () => {
151+
const obj = {
152+
type: "test",
153+
requestId: "req-2",
154+
tabId: null
155+
};
156+
expect(isMessageData(obj)).toBe(true);
157+
});
158+
159+
it("typeがstringでない場合はfalseを返す", () => {
160+
const obj = {
161+
type: 123,
162+
requestId: "req-3",
163+
tabId: "tab-3"
164+
};
165+
expect(isMessageData(obj)).toBe(false);
166+
});
167+
168+
it("requestIdがstringでない場合はfalseを返す", () => {
169+
const obj = {
170+
type: "test",
171+
requestId: 456,
172+
tabId: "tab-4"
173+
};
174+
expect(isMessageData(obj)).toBe(false);
175+
});
176+
177+
it("tabIdがstringでもnullでもない場合はfalseを返す", () => {
178+
const obj = {
179+
type: "test",
180+
requestId: "req-5",
181+
tabId: 789
182+
};
183+
expect(isMessageData(obj)).toBe(false);
184+
});
185+
186+
it("オブジェクトでない値の場合はfalseを返す", () => {
187+
expect(isMessageData(null)).toBe(false);
188+
expect(isMessageData(undefined)).toBe(false);
189+
expect(isMessageData("string")).toBe(false);
190+
});
136191
});

0 commit comments

Comments
 (0)