Skip to content

Commit

Permalink
Merge branch 'main' into WLT-135-support-self-CA-SSL
Browse files Browse the repository at this point in the history
  • Loading branch information
nirfireblocks committed Jul 9, 2024
2 parents 4303477 + c973723 commit 079498f
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 14 deletions.
41 changes: 40 additions & 1 deletion src/customer-server-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ describe('Customer server client', () => {
//@ts-ignore
jest.spyOn(customerServerApi, 'messagesStatus').mockImplementation(() => {
return {
messages: [],
statuses: [],
};
});

Expand All @@ -58,4 +58,43 @@ describe('Customer server client', () => {
await jest.advanceTimersByTimeAsync(2000);
expect(customerServerApi.messagesStatus).toHaveBeenCalledTimes(2);
});

it(`got same unexpected status from customer server in response to messagesStatus`, async () => {
const requestId = c.guid();
const requestType = 'KEY_LINK_PROOF_OF_OWNERSHIP_REQUEST'
const responseType = 'KEY_LINK_PROOF_OF_OWNERSHIP_RESPONSE'
const aTxToSignMessage = messageBuilder.aMessagePayload(requestType, { requestId });
const fbMessage = messageBuilder.fbMessage(aTxToSignMessage);
const msgEnvelop = messageBuilder.aMessageEnvelope(requestId, requestType, fbMessage.payload);
const messageStatus: MessageStatus = {
type: responseType,
status: 'SIGNED',
requestId,
response: {},
};
const messageStatus2: MessageStatus = {
type: responseType,
status: 'SIGNED',
requestId: c.guid(),
response: {},
};
const messageStatus3: MessageStatus = {
type: responseType,
status: 'INVALID' as any,
requestId: c.guid(),
response: {},
};
jest.spyOn(messagesService, 'getPendingMessages').mockReturnValue([{ messageStatus, msgId: c.natural(), request: msgEnvelop }]);
jest.spyOn(messagesService, 'updateStatus').mockResolvedValue();
// @ts-ignore
jest.spyOn(customerServerApi, 'messagesStatus').mockImplementation(() => {
return {
statuses: [messageStatus2, messageStatus3, messageStatus],
};
});


await service.pullMessagesStatus();
expect(messagesService.updateStatus).toHaveBeenCalledWith([{ msgId: expect.any(Number), request: msgEnvelop, messageStatus }]);
});
});
10 changes: 7 additions & 3 deletions src/customer-server-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@ class CustomerClient {
try {
const messages = messagesService.getPendingMessages() ?? [];
const requestsIds = messages.map((msg) => msg.messageStatus.requestId);
logger.info(`Pulling messages status for ${JSON.stringify(requestsIds)} from customer server`);
logger.info(`Pulling messages status for ${JSON.stringify(requestsIds)}`);
const { statuses: serverStatuses } = await customerServerApi.messagesStatus({ requestsIds });
logger.info(`Got ${messages.length} statuses from Customer server`);
if (!!serverStatuses.length) {
logger.info(`Got messages status for ${JSON.stringify(serverStatuses.map((status) => { return { requestId: status.requestId, status: status.status } }))}`);
logger.info(`Got from customer server messages status for ${JSON.stringify(serverStatuses.map((status) => { return { requestId: status.requestId, status: status.status } }))}`);

await messagesService.updateStatus(serverStatuses.map((messagesStatus): ExtendedMessageStatusCache => {
const decodedMsg = messages.find((msg) => msg.messageStatus.requestId === messagesStatus.requestId);
if (!decodedMsg) {
logger.error(`Message with requestId ${messagesStatus.requestId} not in pending cache messages`);
return null;
}
return {
msgId: decodedMsg.msgId,
request: decodedMsg.request,
messageStatus: messagesStatus,
};
}));
}).filter((msg) => msg !== null));
}
} catch (e) {
logger.error(`Got error from customer server: "${e.message}"`);
Expand Down
2 changes: 1 addition & 1 deletion src/services/fireblocks-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class FireblocksAgentImpl implements FireblocksAgent {

_runLoopStep = async () => {
const start = Date.now();
logger.info(`Waiting for a message from Fireblocks`);
logger.info(`Waiting for messages from Fireblocks...`);
const messages = await fbServerApi.getMessages();
logger.info(`Got ${messages.length} messages from Fireblocks after ${Date.now() - start}ms`);
await messageService.handleMessages(messages);
Expand Down
45 changes: 45 additions & 0 deletions src/services/messages.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,4 +214,49 @@ describe('messages service', () => {
expect(customerServerApi.messagesToSign).toHaveBeenCalledTimes(1);
expect(fbServerApi.ackMessage).toHaveBeenCalledWith(msgId3);
});

it('got same unexpected status from customer server in response to messagesToSign', async () => {
const requestId = c.guid();
const msgId = c.natural();
const requestType = 'KEY_LINK_PROOF_OF_OWNERSHIP_REQUEST';
const responseType = 'KEY_LINK_PROOF_OF_OWNERSHIP_RESPONSE';
const aTxToSignMessage = messageBuilder.aMessagePayload(requestType, { requestId });
const fbMessage = messageBuilder.fbMessage(aTxToSignMessage);
const fbMessageEnvelope = messageBuilder.fbProofOfOwnershipMsgEnvelope({}, fbMessage);
const msgEnvelop = messageBuilder.aMessageEnvelope(requestId, requestType, fbMessage.payload);

jest.spyOn(messagesUtils, 'decodeAndVerifyMessage').mockReturnValue({ request: msgEnvelop, msgId });

const msgStatus: MessageStatus = {
type: responseType,
status: 'SIGNED',
requestId,
response: {},
};

const msgStatus2: MessageStatus = {
type: responseType,
status: 'SIGNED',
requestId: c.guid(),
response: {},
};

const msgStatus3: MessageStatus = {
type: responseType,
status: 'INVALID' as any,
requestId: c.guid(),
response: {},
};

jest.spyOn(customerServerApi, 'messagesToSign').mockResolvedValue([msgStatus2, msgStatus3, msgStatus]);
jest.spyOn(fbServerApi, 'broadcastResponse').mockImplementation(jest.fn(() => Promise.resolve()));
jest.spyOn(fbServerApi, 'ackMessage').mockImplementation(jest.fn(() => Promise.resolve()));

await service.handleMessages([fbMessageEnvelope]);

// Verify the agent ignores a message it didn't asked for
expect(fbServerApi.ackMessage).toHaveBeenCalledWith(msgId);
expect(fbServerApi.broadcastResponse).toHaveBeenCalledWith(msgStatus, msgEnvelop);
});

});
22 changes: 13 additions & 9 deletions src/services/messages.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class MessageService implements IMessageService {
try {
const { msgId, request } = decodeAndVerifyMessage(messageEnvelope, certificates);
const { transportMetadata } = request;
logger.info(`Got message id ${msgId} with type ${transportMetadata.type} and request id ${transportMetadata.requestId}`);
logger.info(`Got from Fireblocks message id ${msgId} with type ${transportMetadata.type} and request id ${transportMetadata.requestId}`);
return { msgId, request };
} catch (e) {
logger.error(`Error decoding message ${e.message}`);
Expand All @@ -51,7 +51,7 @@ class MessageService implements IMessageService {
});

if (!!cachedMessages.length) {
cachedMessages.forEach((msg) => logger.info(`Got cached message id ${msg.msgId} request id ${msg.request.transportMetadata.requestId}`));
cachedMessages.forEach((msg) => logger.info(`Found cached message id ${msg.msgId} request id ${msg.request.transportMetadata.requestId}`));
const cachedMsgsStatus = cachedMessages.map((msg): ExtendedMessageStatusCache => {
return {
msgId: msg.msgId,
Expand All @@ -66,19 +66,24 @@ class MessageService implements IMessageService {

if (!!messagesToHandle.length) {
const msgStatuses = await customerServerApi.messagesToSign(messagesToHandle.map((msg) => msg.request));
logger.info(`Got messages status for ${JSON.stringify(msgStatuses.map((status) => { return { requestId: status.requestId, status: status.status } }))}`);
logger.info(`Got from customer server messages status for ${JSON.stringify(msgStatuses.map((status) => { return { requestId: status.requestId, status: status.status } }))}`);
await this.updateStatus(msgStatuses.map((messageStatus): ExtendedMessageStatusCache => {
const decodedMessage = messagesToHandle.find((msg) => msg.request.transportMetadata.requestId === messageStatus.requestId);
if (!decodedMessage) {
logger.error(`Message with requestId ${messageStatus.requestId} wasn't expected`);
return null;
}

return {
msgId: decodedMessage.msgId,
request: decodedMessage.request,
messageStatus,
};
}));
}).filter((msg) => msg !== null));
}

if (!!unknownMessages.length) {
unknownMessages.forEach((msg) => logger.error(`Got unknown message type ${msg.request.transportMetadata.type} and id ${msg.msgId}`));
unknownMessages.forEach((msg) => logger.error(`Got from Fireblocks unknown message type ${msg.request.transportMetadata.type} and id ${msg.msgId}`));
await this.ackMessages(unknownMessages.map((msg) => msg.msgId));
}
}
Expand All @@ -105,14 +110,13 @@ class MessageService implements IMessageService {
}

if (status === 'SIGNED' || status === 'FAILED') {
logger.info(`Got message from customer server with status: ${status}, msgId ${msgId}, cacheId: ${requestId}`);
this.msgCache[messageStatus.requestId].messageStatus = messageStatus;

logger.info(`Got ${isInCache ? "cached" : "from customer server"} message with final status: ${status}, msgId ${msgId}, cacheId: ${requestId}`);
await fbServerApi.broadcastResponse(messageStatus, request);
await fbServerApi.ackMessage(msgId);
this.msgCache[messageStatus.requestId].messageStatus = messageStatus;
}
} catch (e) {
throw new Error(`Error updating status to fireblocks ${e.message} for message ${msgStatus.msgId} and status ${msgStatus.messageStatus}`);
throw new Error(`Error updating status for message ${msgStatus.msgId} and status ${JSON.stringify(msgStatus.messageStatus)}. Error: ${e.message}`);
}
}
}
Expand Down

0 comments on commit 079498f

Please sign in to comment.