UNPKG

@ledgerhq/live-common

Version:
111 lines 5.44 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const hw_transport_mocker_1 = require("@ledgerhq/hw-transport-mocker"); const operators_1 = require("rxjs/operators"); const isomorphic_ws_1 = __importDefault(require("isomorphic-ws")); const scenarios_mock_1 = __importDefault(require("./scenarios.mock")); const _1 = require("."); const rxjs_1 = require("rxjs"); /** * Both ends of the exchange are mocked in this test file and we are merely testing * the logic that happens in-between. */ jest.mock("isomorphic-ws", () => ({ ...jest.requireActual("isomorphic-ws"), __esModule: true, default: jest.fn(), })); describe("Scriptrunner logic", () => { scenarios_mock_1.default.forEach(({ describe, device, events }) => { it(describe, async () => { // Generate a transport replayer with the data from the test const transport = await (0, hw_transport_mocker_1.openTransportReplayer)(hw_transport_mocker_1.RecordStore.fromString(device)); isomorphic_ws_1.default.mockImplementation(() => { let msgIndex = 0; // Exposed WebSocket callbacks: // - `on*` are implemented inside `createDeviceSocket` // - `send` is used to send back messages to the HSM // - `close` is used to close the connection with the HSM const callbacks = { onopen: undefined, onerror: undefined, onclose: undefined, onmessage: undefined, send: undefined, close: () => undefined, }; callbacks.send = _ => { // Iterates to the next scenario event once the fake device sends a response to the HSM msgIndex++; const [callback, payload] = events[msgIndex]; const nextEvent = events[msgIndex + 1]; const [nextEventCallback, nextEventPayload, nextEventEager] = nextEvent ? nextEvent : [undefined, undefined, undefined]; let isExchangeBlocked = false; // The next event (from the HSM) is an allow secure channel if (payload?.includes("e051000000")) { // Needs to delay the next APDU to see the allow secure channel event. transport.setArtificialExchangeDelay(1000); } // If the current message is a bulk, and we want the HSM to send a message (like success) directly after, // we slowdown if (payload?.includes("bulk") && nextEventEager) { isExchangeBlocked = true; transport.enableExchangeBlocker(); } const maybeCallback = callbacks[callback]; if (maybeCallback) { maybeCallback({ data: payload }); } // Checks if the next event should be emitted straight away instead of as // a (device) response to the current event HSM message. // This is used to trigger errors and closing the connection from the scriptrunner side. if (nextEvent && nextEventCallback) { const maybeCallback = callbacks[nextEventCallback]; if (maybeCallback && nextEventEager) { if (isExchangeBlocked) { maybeCallback({ data: nextEventPayload }); transport.unblockExchange(); isExchangeBlocked = false; } else { setTimeout(() => { // Emits without any further device interaction maybeCallback({ data: nextEventPayload }); }, 200); } } } }; // Starts the fake WebSocket communication with the HSM setTimeout(() => { if (callbacks.onopen) { callbacks.onopen(null); const [callback, payload] = events[msgIndex]; const maybeCallback = callbacks[callback]; if (maybeCallback) { maybeCallback({ data: payload }); } } }, 0); return callbacks; }); // Mock the socket connection try { const resolved = await (0, rxjs_1.firstValueFrom)((0, _1.createDeviceSocket)(transport, { url: "no-need-for-a-url", }).pipe((0, operators_1.toArray)())); expect(resolved).toMatchSnapshot(); } catch (error) { expect(error).toMatchSnapshot(); } return; }); }); }); //# sourceMappingURL=socket.test.js.map