diff --git a/packages/fxa-settings/src/lib/channels/pairing-channel.test.ts b/packages/fxa-settings/src/lib/channels/pairing-channel.test.ts index dcc0b5cdadf..37a63ab9a81 100644 --- a/packages/fxa-settings/src/lib/channels/pairing-channel.test.ts +++ b/packages/fxa-settings/src/lib/channels/pairing-channel.test.ts @@ -22,6 +22,7 @@ let mockChannel: { _channelId?: string; _channelKey?: Uint8Array; _connection?: unknown; + closed?: boolean; }; jest.mock( @@ -56,6 +57,7 @@ describe('PairingChannelClient', () => { // 'testkey1' — the same bytes VALID_KEY decodes to. _channelId: CHAN, _channelKey: new TextEncoder().encode('testkey1'), + closed: false, }; jest.clearAllMocks(); client = new PairingChannelClient(); @@ -186,6 +188,16 @@ describe('PairingChannelClient', () => { await expect(client.send('msg')).rejects.toThrow('Not connected'); }); + it('throws CONNECTION_CLOSED when the channel is torn down', async () => { + await client.open(SERVER, CHAN, VALID_KEY); + mockChannel.closed = true; + + await expect(client.send('pair:supp:authorize')).rejects.toMatchObject({ + errno: 1006, + }); + expect(mockChannel.send).not.toHaveBeenCalled(); + }); + it('throws for empty message', async () => { await client.open(SERVER, CHAN, VALID_KEY); await expect(client.send('')).rejects.toThrow('malformed message'); diff --git a/packages/fxa-settings/src/lib/channels/pairing-channel.ts b/packages/fxa-settings/src/lib/channels/pairing-channel.ts index bc52bd7d167..e82066910c8 100644 --- a/packages/fxa-settings/src/lib/channels/pairing-channel.ts +++ b/packages/fxa-settings/src/lib/channels/pairing-channel.ts @@ -156,6 +156,8 @@ type PairingChannelSocket = { * socket goes away, and the package's `close()` dereferences it unguarded. */ _connection?: unknown; + /** True once fxa-pairing-channel has torn the WebSocket down. */ + readonly closed?: boolean; }; export class PairingChannelClient extends EventTarget { @@ -291,6 +293,10 @@ export class PairingChannelClient extends EventTarget { console.warn('No pairing channel!'); throw new PairingChannelError('NOT_CONNECTED'); } + if (this.channel.closed) { + console.warn('Pairing channel is closed!'); + throw new PairingChannelError('CONNECTION_CLOSED'); + } if (!message) { console.warn('No message!'); throw new PairingChannelError('INVALID_OUTBOUND_MESSAGE');