@stoprocent/noble
Version:
A Node.js BLE (Bluetooth Low Energy) central library.
270 lines (219 loc) • 9.66 kB
JavaScript
// Mock the crypto module
jest.mock('../../../lib/hci-socket/crypto', () => ({
r: jest.fn(),
c1: jest.fn(),
s1: jest.fn()
}));
// Import the mocked modules
const crypto = require('../../../lib/hci-socket/crypto');
const Smp = require('../../../lib/hci-socket/smp');
describe('hci-socket smp', () => {
let smp;
let aclStream;
const localAddressType = 'public';
const localAddress = 'aa:bb:cc:dd:ee:ff';
const remoteAddressType = 'random';
const remoteAddress = '00:11:22:33:44:55';
beforeEach(() => {
aclStream = {
on: jest.fn(),
removeListener: jest.fn(),
write: jest.fn()
};
smp = new Smp(aclStream, localAddressType, localAddress, remoteAddressType, remoteAddress);
});
afterEach(() => {
jest.clearAllMocks();
});
test('construct 1', () => {
expect(aclStream.on).toHaveBeenCalledTimes(2);
expect(aclStream.on).toHaveBeenCalledWith('data', expect.any(Function));
expect(aclStream.on).toHaveBeenCalledWith('end', expect.any(Function));
expect(smp._iat).toEqual(Buffer.from([0x00]));
expect(smp._ia).toEqual(Buffer.from([0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa]));
expect(smp._rat).toEqual(Buffer.from([0x01]));
expect(smp._ra).toEqual(Buffer.from([0x55, 0x44, 0x33, 0x22, 0x11, 0x00]));
});
test('construct 2', () => {
jest.clearAllMocks();
const smp = new Smp(aclStream, remoteAddressType, remoteAddress, localAddressType, localAddress);
expect(aclStream.on).toHaveBeenCalledTimes(2);
expect(aclStream.on).toHaveBeenCalledWith('data', expect.any(Function));
expect(aclStream.on).toHaveBeenCalledWith('end', expect.any(Function));
expect(smp._iat).toEqual(Buffer.from([0x01]));
expect(smp._ia).toEqual(Buffer.from([0x55, 0x44, 0x33, 0x22, 0x11, 0x00]));
expect(smp._rat).toEqual(Buffer.from([0x00]));
expect(smp._ra).toEqual(Buffer.from([0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa]));
});
test('should write sendPairingRequest', () => {
smp.write = jest.fn();
smp.sendPairingRequest();
expect(smp.write).toHaveBeenCalledWith(Buffer.from([0x01, 0x03, 0x00, 0x01, 0x10, 0x00, 0x01]));
});
describe('onAclStreamData', () => {
beforeEach(() => {
smp.handlePairingResponse = jest.fn();
smp.handlePairingConfirm = jest.fn();
smp.handlePairingRandom = jest.fn();
smp.handlePairingFailed = jest.fn();
smp.handleEncryptInfo = jest.fn();
smp.handleMasterIdent = jest.fn();
});
test('should do nothing with !SMP_CID', () => {
smp.onAclStreamData(0);
expect(smp.handlePairingResponse).not.toHaveBeenCalled();
expect(smp.handlePairingConfirm).not.toHaveBeenCalled();
expect(smp.handlePairingRandom).not.toHaveBeenCalled();
expect(smp.handlePairingFailed).not.toHaveBeenCalled();
expect(smp.handleEncryptInfo).not.toHaveBeenCalled();
expect(smp.handleMasterIdent).not.toHaveBeenCalled();
});
test('should handlePairingResponse', () => {
const data = Buffer.from([0x02, 0x33, 0x44]);
smp.onAclStreamData(6, data);
expect(smp.handlePairingResponse).toHaveBeenCalledWith(data);
expect(smp.handlePairingConfirm).not.toHaveBeenCalled();
expect(smp.handlePairingRandom).not.toHaveBeenCalled();
expect(smp.handlePairingFailed).not.toHaveBeenCalled();
expect(smp.handleEncryptInfo).not.toHaveBeenCalled();
expect(smp.handleMasterIdent).not.toHaveBeenCalled();
});
test('should handlePairingConfirm', () => {
const data = Buffer.from([0x03, 0x33, 0x44]);
smp.onAclStreamData(6, data);
expect(smp.handlePairingResponse).not.toHaveBeenCalled();
expect(smp.handlePairingConfirm).toHaveBeenCalledWith(data);
expect(smp.handlePairingRandom).not.toHaveBeenCalled();
expect(smp.handlePairingFailed).not.toHaveBeenCalled();
expect(smp.handleEncryptInfo).not.toHaveBeenCalled();
expect(smp.handleMasterIdent).not.toHaveBeenCalled();
});
test('should handlePairingRandom', () => {
const data = Buffer.from([0x04, 0x33, 0x44]);
smp.onAclStreamData(6, data);
expect(smp.handlePairingResponse).not.toHaveBeenCalled();
expect(smp.handlePairingConfirm).not.toHaveBeenCalled();
expect(smp.handlePairingRandom).toHaveBeenCalledWith(data);
expect(smp.handlePairingFailed).not.toHaveBeenCalled();
expect(smp.handleEncryptInfo).not.toHaveBeenCalled();
expect(smp.handleMasterIdent).not.toHaveBeenCalled();
});
test('should handlePairingFailed', () => {
const data = Buffer.from([0x05, 0x33, 0x44]);
smp.onAclStreamData(6, data);
expect(smp.handlePairingResponse).not.toHaveBeenCalled();
expect(smp.handlePairingConfirm).not.toHaveBeenCalled();
expect(smp.handlePairingRandom).not.toHaveBeenCalled();
expect(smp.handlePairingFailed).toHaveBeenCalledWith(data);
expect(smp.handleEncryptInfo).not.toHaveBeenCalled();
expect(smp.handleMasterIdent).not.toHaveBeenCalled();
});
test('should handleEncryptInfo', () => {
const data = Buffer.from([0x06, 0x33, 0x44]);
smp.onAclStreamData(6, data);
expect(smp.handlePairingResponse).not.toHaveBeenCalled();
expect(smp.handlePairingConfirm).not.toHaveBeenCalled();
expect(smp.handlePairingRandom).not.toHaveBeenCalled();
expect(smp.handlePairingFailed).not.toHaveBeenCalled();
expect(smp.handleEncryptInfo).toHaveBeenCalledWith(data);
expect(smp.handleMasterIdent).not.toHaveBeenCalled();
});
test('should handleMasterIdent', () => {
const data = Buffer.from([0x07, 0x33, 0x44]);
smp.onAclStreamData(6, data);
expect(smp.handlePairingResponse).not.toHaveBeenCalled();
expect(smp.handlePairingConfirm).not.toHaveBeenCalled();
expect(smp.handlePairingRandom).not.toHaveBeenCalled();
expect(smp.handlePairingFailed).not.toHaveBeenCalled();
expect(smp.handleEncryptInfo).not.toHaveBeenCalled();
expect(smp.handleMasterIdent).toHaveBeenCalledWith(data);
});
test('should do nothing on bad code', () => {
const data = Buffer.from([0x08, 0x33, 0x44]);
smp.onAclStreamData(6, data);
expect(smp.handlePairingResponse).not.toHaveBeenCalled();
expect(smp.handlePairingConfirm).not.toHaveBeenCalled();
expect(smp.handlePairingRandom).not.toHaveBeenCalled();
expect(smp.handlePairingFailed).not.toHaveBeenCalled();
expect(smp.handleEncryptInfo).not.toHaveBeenCalled();
expect(smp.handleMasterIdent).not.toHaveBeenCalled();
});
});
test('onAclStreamEnd', () => {
const callback = jest.fn();
smp.on('end', callback);
smp.onAclStreamEnd();
expect(aclStream.removeListener).toHaveBeenCalledTimes(2);
expect(aclStream.removeListener).toHaveBeenCalledWith('data', expect.any(Function));
expect(aclStream.removeListener).toHaveBeenCalledWith('end', expect.any(Function));
expect(callback).toHaveBeenCalled();
});
test('handlePairingResponse', () => {
smp.write = jest.fn();
crypto.c1.mockReturnValue(Buffer.from([0x99]));
smp.handlePairingResponse('data');
expect(smp._pres).toBe('data');
expect(crypto.r).toHaveBeenCalled();
expect(crypto.c1).toHaveBeenCalled();
expect(smp.write).toHaveBeenCalledWith(Buffer.from([0x03, 0x99]));
});
test('handlePairingConfirm', () => {
smp.write = jest.fn();
smp._r = Buffer.from([0x99]);
smp.handlePairingConfirm('data');
expect(smp._pcnf).toBe('data');
expect(smp.write).toHaveBeenCalledWith(Buffer.from([0x04, 0x99]));
});
describe('handlePairingRandom', () => {
test('should emit stk', () => {
crypto.c1.mockReturnValue(Buffer.from([0x99]));
crypto.s1.mockReturnValue('stk_answer');
const data = Buffer.from([0, 1]);
const callback = jest.fn();
const failCallback = jest.fn();
smp._pcnf = Buffer.from([3, 153]);
smp.on('stk', callback);
smp.on('fail', failCallback);
smp.handlePairingRandom(data);
expect(callback).toHaveBeenCalledWith('stk_answer');
expect(failCallback).not.toHaveBeenCalled();
});
test('should write and emit fail stk', () => {
crypto.c1.mockReturnValue(Buffer.from([0x99]));
crypto.s1.mockReturnValue('stk_answer');
const data = Buffer.from([0, 1]);
const callback = jest.fn();
const failCallback = jest.fn();
smp.write = jest.fn();
smp._pcnf = Buffer.from([0]);
smp.on('stk', callback);
smp.on('fail', failCallback);
smp.handlePairingRandom(data);
expect(smp.write).toHaveBeenCalledWith(Buffer.from([4, 3]));
expect(callback).not.toHaveBeenCalled();
expect(failCallback).toHaveBeenCalled();
});
});
test('should emit fail on handlePairingFailed', () => {
const callback = jest.fn();
smp.on('fail', callback);
smp.handlePairingFailed();
expect(callback).toHaveBeenCalled();
});
test('should emit ltk on handleEncryptInfo', () => {
const callback = jest.fn();
smp.on('ltk', callback);
smp.handleEncryptInfo(Buffer.from([0x02, 0x03, 0x04]));
expect(callback).toHaveBeenCalledWith(Buffer.from([0x03, 0x04]));
});
test('should emit masterIdent on handleMasterIdent', () => {
const callback = jest.fn();
smp.on('masterIdent', callback);
smp.handleMasterIdent(Buffer.from([0x02, 0x03, 0x04, 0x05, 0x06]));
expect(callback).toHaveBeenCalledWith(Buffer.from([0x03, 0x04]), Buffer.from([0x05, 0x06]));
});
test('should write on aclStream', () => {
smp.write('data');
expect(aclStream.write).toHaveBeenCalledWith(6, 'data');
});
});