Skip to content

Commit b87dbe7

Browse files
committed
refactor: make MessageProcessor generator
1 parent ec68927 commit b87dbe7

File tree

6 files changed

+56
-57
lines changed

6 files changed

+56
-57
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"run:tsc": "node --experimental-strip-types",
2424
"test:pure-js": "npm run run:tsc -- --import=./src/tests/load-purejs-crypto.ts --test",
2525
"test:webcrypto": "npm run run:tsc -- --import=./src/tests/load-webcrypto.ts --test",
26-
"handshake": "npm run run:tsc -- --import=./src/tests/load-purejs-crypto.ts ./src/scripts/handshake.ts",
26+
"handshake": "npm run run:tsc -- --import=./src/tests/load-webcrypto.ts ./src/scripts/handshake.ts",
2727
"lint": "eslint . --ext .js,.ts,.jsx,.tsx",
2828
"lint:fix": "eslint . --fix --ext .js,.ts,.jsx,.tsx",
2929
"prepare": "npm run build",

src/make-tls-client.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { crypto } from './crypto/index.ts'
2-
import type { CipherSuite, Key, KeyPair, ProcessPacket, TLSClientOptions, TLSHandshakeOptions, TLSKeyType, TLSPacket, TLSPacketContext, TLSProtocolVersion, TLSSessionTicket, X509Certificate } from './types/index.ts'
2+
import type { CipherSuite, Key, KeyPair, TLSClientOptions, TLSHandshakeOptions, TLSKeyType, TLSPacket, TLSPacketContext, TLSPacketWithType, TLSProtocolVersion, TLSSessionTicket, X509Certificate } from './types/index.ts'
33
import { packClientHello } from './utils/client-hello.ts'
44
import { CONTENT_TYPE_MAP, MAX_ENC_PACKET_SIZE, PACKET_TYPE, SUPPORTED_CIPHER_SUITE_MAP, SUPPORTED_NAMED_CURVE_MAP, SUPPORTED_NAMED_CURVES, SUPPORTED_RECORD_TYPE_MAP } from './utils/constants.ts'
55
import type { SharedKeyData } from './utils/decryption-utils.ts'
@@ -65,7 +65,9 @@ export function makeTLSClient({
6565
let clientCertificateRequested = false
6666
let certificatesVerified = false
6767

68-
const processPacketUnsafe: ProcessPacket = async(type, { header, content }) => {
68+
const processPacketUnsafe = async(
69+
{ type, packet: { content, header } }: TLSPacketWithType
70+
) => {
6971
if(ended) {
7072
logger.warn('connection closed, ignoring packet')
7173
return
@@ -173,8 +175,8 @@ export function makeTLSClient({
173175
}
174176
}
175177

176-
const processPacket: ProcessPacket = (...args) => (
177-
enqueueServerPacket(processPacketUnsafe, ...args)
178+
const processPacket = (pkt: TLSPacketWithType) => (
179+
enqueueServerPacket(processPacketUnsafe, pkt)
178180
)
179181

180182
async function processRecord(
@@ -799,8 +801,10 @@ export function makeTLSClient({
799801
* Handle bytes received from the server.
800802
* Could be a complete or partial TLS packet
801803
*/
802-
handleReceivedBytes(data: Uint8Array) {
803-
return processor.onData(data, processPacket)
804+
async handleReceivedBytes(data: Uint8Array) {
805+
for(const pkt of processor.onData(data)) {
806+
await processPacket(pkt)
807+
}
804808
},
805809
/**
806810
* Handle a complete TLS packet received

src/scripts/handshake.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ await new Promise<void>((resolve, reject) => {
2020
verifyServerCertificate: true,
2121
logger: LOGGER,
2222
// write raw bytes to the socket
23-
async write({ header, content }) {
23+
write({ header, content }) {
2424
socket.write(header)
2525
socket.write(content)
2626
},
@@ -46,8 +46,14 @@ await new Promise<void>((resolve, reject) => {
4646

4747
socket.on('data', tls.handleReceivedBytes)
4848
// start handshake as soon as the socket connects
49-
socket.on('connect', () => tls.startHandshake())
49+
socket.once('connect', () => tls.startHandshake())
5050
socket.once('error', (err) => reject(err))
51+
socket.once('close', () => {
52+
console.log('Socket closed')
53+
if(!tls.isHandshakeDone()) {
54+
reject(new Error('Handshake was not completed before socket closed'))
55+
}
56+
})
5157
// use the TCP socket to connect to the server
5258
socket.connect({ host, port })
5359
})
Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,61 @@
11
import assert from 'node:assert'
2-
import { describe, it } from 'node:test'
3-
import type { TLSPacket } from '../types/index.ts'
2+
import { beforeEach, describe, it } from 'node:test'
3+
import type { PacketProcessor, TLSPacket, TLSPacketWithType } from '../types/index.ts'
44
import { logger } from '../utils/index.ts'
55
import { makeMessageProcessor } from '../utils/index.ts'
66
import { expectBuffsEq } from './utils.ts'
77

88
describe('TLS Message Processor', () => {
99

10-
it('should process a complete message', async() => {
11-
const processor = makeTestMsgProcessor()
12-
const pkts = await processor.onData(
13-
Buffer.from('15030300050101010101', 'hex')
10+
let processor: PacketProcessor
11+
beforeEach(() => {
12+
processor = makeMessageProcessor(logger)
13+
})
14+
15+
it('should process a complete message', () => {
16+
const pkts = Array.from(
17+
processor.onData(Buffer.from('15030300050101010101', 'hex'))
1418
)
1519
assert.equal(pkts.length, 1)
16-
expectBuffsEq(pkts[0].header, Buffer.from('1503030005', 'hex'))
17-
expectBuffsEq(pkts[0].content, Buffer.from('0101010101', 'hex'))
20+
expectBuffsEq(pkts[0].packet.header, Buffer.from('1503030005', 'hex'))
21+
expectBuffsEq(pkts[0].packet.content, Buffer.from('0101010101', 'hex'))
1822
})
1923

20-
it('should process a message byte-by-byte', async() => {
21-
const processor = makeTestMsgProcessor()
24+
it('should process a message byte-by-byte', () => {
2225
const buffer = Buffer.from('15030300050101010101', 'hex')
2326
for(let i = 0;i < buffer.length;i++) {
24-
const pkts = await processor.onData(buffer.subarray(i, i + 1))
27+
const pkts = Array.from(processor.onData(buffer.subarray(i, i + 1)))
2528
if(i < buffer.length - 1) {
2629
assert.equal(pkts.length, 0)
2730
} else {
2831
assert.equal(pkts.length, 1)
29-
expectBuffsEq(pkts[0].content, Buffer.from('0101010101', 'hex'))
32+
expectBuffsEq(pkts[0].packet.content, Buffer.from('0101010101', 'hex'))
3033
}
3134
}
3235
})
3336

3437
it('should process multiple messages', async() => {
35-
const processor = makeTestMsgProcessor()
3638
const buffers = [
3739
Buffer.from('15030300050101010101', 'hex'),
3840
Buffer.from('1503030006010101010101', 'hex')
3941
]
40-
const pkts = await processor.onData(Buffer.concat(buffers))
42+
const pkts = Array.from(processor.onData(Buffer.concat(buffers)))
4143
assert.equal(pkts.length, 2)
42-
expectBuffsEq(pkts[0].content, Buffer.from('0101010101', 'hex'))
43-
expectBuffsEq(pkts[1].content, Buffer.from('010101010101', 'hex'))
44+
expectBuffsEq(pkts[0].packet.content, Buffer.from('0101010101', 'hex'))
45+
expectBuffsEq(pkts[1].packet.content, Buffer.from('010101010101', 'hex'))
4446
})
4547

4648
it('should process a message and a half', async() => {
47-
const processor = makeTestMsgProcessor()
4849
const msgAndHalfBuffer = Buffer.concat(
4950
[
5051
Buffer.from('15030300050101010101', 'hex'),
5152
Buffer.from('1503030006', 'hex')
5253
]
5354
)
5455
const finalBuffer = Buffer.from('010101010101', 'hex')
55-
const pkts = await processor.onData(msgAndHalfBuffer)
56+
const pkts = Array.from(processor.onData(msgAndHalfBuffer))
5657
assert.equal(pkts.length, 1)
57-
const pkts2 = await processor.onData(finalBuffer)
58+
const pkts2 = Array.from(processor.onData(finalBuffer))
5859
assert.equal(pkts2.length, 1)
5960
})
60-
61-
// eslint-disable-next-line unicorn/consistent-function-scoping
62-
function makeTestMsgProcessor() {
63-
const processor = makeMessageProcessor(logger)
64-
65-
return {
66-
...processor,
67-
async onData(packet: Buffer) {
68-
const packets: TLSPacket[] = []
69-
await processor.onData(
70-
packet,
71-
(_, pkt) => {
72-
packets.push(pkt)
73-
}
74-
)
75-
76-
return packets
77-
}
78-
}
79-
}
8061
})

src/types/tls.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,11 @@ export type TLSEventHandlers = {
140140
onSessionTicket?(ticket: TLSSessionTicket): void
141141
}
142142

143-
export type ProcessPacket = (type: number, packet: TLSPacket) => void
143+
export type TLSPacketWithType = {
144+
type: number
145+
packet: TLSPacket
146+
}
144147

145148
export type PacketProcessor = {
146-
onData(data: Uint8Array, onChunk: ProcessPacket): void
149+
onData(data: Uint8Array): Generator<TLSPacketWithType>
147150
}

src/utils/packets.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Logger, ProcessPacket, TLSProtocolVersion } from '../types/index.ts'
1+
import type { Logger, TLSPacketWithType, TLSProtocolVersion } from '../types/index.ts'
22
import { PACKET_TYPE, TLS_PROTOCOL_VERSION_MAP } from './constants.ts'
33
import { concatenateUint8Arrays, uint8ArrayToDataView } from './generics.ts'
44

@@ -116,7 +116,7 @@ export function makeMessageProcessor(logger: Logger) {
116116
* or a single packet
117117
* @param onChunk handle a complete packet
118118
*/
119-
async onData(packet: Uint8Array, onChunk: ProcessPacket) {
119+
*onData(packet: Uint8Array) {
120120
buffer = concatenateUint8Arrays([ buffer, packet ])
121121
while(buffer.length) {
122122
// if we already aren't processing a packet
@@ -151,7 +151,7 @@ export function makeMessageProcessor(logger: Logger) {
151151
// remove the packet header
152152
buffer = buffer.slice(5)
153153
logger.trace(
154-
{ bytesLeft, type: currentMessageType },
154+
{ bytesLeft, recvBuffer: buffer.length, type: currentMessageType },
155155
'starting processing packet'
156156
)
157157
}
@@ -165,17 +165,22 @@ export function makeMessageProcessor(logger: Logger) {
165165
const body = buffer.slice(0, bytesLeft)
166166

167167
logger.trace({ type: currentMessageType }, 'got complete packet')
168-
await onChunk(currentMessageType, {
169-
header: currentMessageHeader!,
170-
content: body
171-
})
168+
const pktWithType: TLSPacketWithType = {
169+
type: currentMessageType,
170+
packet: {
171+
header: currentMessageHeader!,
172+
content: body
173+
}
174+
}
172175

173176
currentMessageType = undefined
174177

175178
// if the current chunk we have still has bytes left
176179
// then that means we have another packet in the chunk
177180
// this will be processed in the next iteration of the loop
178181
buffer = buffer.slice(body.length)
182+
183+
yield pktWithType
179184
}
180185
},
181186
reset() {

0 commit comments

Comments
 (0)