Skip to content

Commit e04f5e7

Browse files
committed
properly decode ASCII payload from the lambda
1 parent 989ec02 commit e04f5e7

File tree

3 files changed

+83
-6
lines changed

3 files changed

+83
-6
lines changed

src/bot/acceptReviewRequest.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ export const acceptReviewRequest = {
4848
const review = await activeReviewRepo.getReviewByThreadIdOrFail(threadId);
4949
if (review.pdfIdentifier) {
5050
const url = await generateHackParserPresignedURL(review.pdfIdentifier);
51-
log.e(url);
5251
blocks.push(textBlock(`HackerRank PDF: <${url}|${review.pdfIdentifier}>`));
5352

5453
const codeKeys = await listHackParserCodeKeys(review.pdfIdentifier);

src/services/HackParserService.ts

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,47 @@ async function invokeS3PresignedURLGeneratorLambda(
2424
expiration,
2525
requests,
2626
});
27-
log.e('status code: ' + result.StatusCode);
28-
log.e('payload: ' + result.Payload!.toString());
29-
const response = JSON.parse(result.Payload!.toString());
30-
return response;
27+
28+
if (!result.Payload) {
29+
log.e('Error: No payload on lambda response');
30+
return {};
31+
}
32+
33+
let payload: unknown = result.Payload;
34+
35+
if (payload instanceof Uint8Array) {
36+
payload = new TextDecoder().decode(payload);
37+
}
38+
39+
if (typeof payload === 'string') {
40+
try {
41+
payload = JSON.parse(payload);
42+
} catch (error) {
43+
log.e('Error parsing payload as JSON:', error);
44+
throw new Error('Invalid JSON response from Lambda');
45+
}
46+
}
47+
48+
if (Array.isArray(payload) && payload.every(num => typeof num === 'number')) {
49+
const asciiArray = payload as number[];
50+
const decoded = String.fromCharCode(...asciiArray);
51+
52+
log.e('Decoded Payload: ' + decoded);
53+
54+
try {
55+
return JSON.parse(decoded);
56+
} catch (error) {
57+
log.e('Error parsing decoded payload:', error);
58+
throw new Error('Invalid JSON structure after decoding');
59+
}
60+
}
61+
62+
if (typeof payload === 'object' && payload !== null) {
63+
return payload as Record<string, string>;
64+
}
65+
66+
log.e('Error: Unexpected payload format');
67+
throw new Error('Unexpected payload format');
3168
}
3269

3370
/**

src/services/__tests__/HackParserService.test.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,50 @@ describe('generateHackParserPresignedURL', () => {
3030
expect(result).toBeUndefined();
3131
});
3232

33-
it('should throw an error if the Lambda response is invalid', async () => {
33+
it('should throw an error if the Lambda response is invalid JSON', async () => {
3434
(invokeLambda as jest.Mock).mockResolvedValue({ Payload: 'invalid_json' });
3535

3636
await expect(generateHackParserPresignedURL('file3.txt')).rejects.toThrow();
3737
});
38+
39+
it('should decode ASCII-encoded payload and return a valid presigned URL', async () => {
40+
const key = 'file4.txt';
41+
const asciiPayload = JSON.stringify([
42+
123, 34, 102, 105, 108, 101, 52, 46, 116, 120, 116, 34, 58, 32, 34, 104, 116, 116, 112, 115,
43+
58, 47, 47, 109, 111, 99, 107, 45, 117, 114, 108, 45, 52, 34, 125,
44+
]);
45+
46+
(invokeLambda as jest.Mock).mockResolvedValue({ Payload: asciiPayload });
47+
48+
const result = await generateHackParserPresignedURL(key);
49+
50+
expect(result).toEqual('https://mock-url-4');
51+
});
52+
53+
it('should handle Uint8ArrayBlobAdapter payload correctly', async () => {
54+
const key = 'file5.txt';
55+
const mockResponse = { 'file5.txt': 'https://mock-url-5' };
56+
const uint8ArrayPayload = new TextEncoder().encode(JSON.stringify(mockResponse));
57+
58+
(invokeLambda as jest.Mock).mockResolvedValue({ Payload: uint8ArrayPayload });
59+
60+
const result = await generateHackParserPresignedURL(key);
61+
expect(result).toEqual('https://mock-url-5');
62+
});
63+
64+
it('should return undefined if Payload is undefined', async () => {
65+
const key = 'file6.txt';
66+
(invokeLambda as jest.Mock).mockResolvedValue({ Payload: undefined });
67+
68+
const result = await generateHackParserPresignedURL(key);
69+
expect(result).toBeUndefined();
70+
});
71+
72+
it('should handle empty Lambda response gracefully', async () => {
73+
const key = 'file8.txt';
74+
(invokeLambda as jest.Mock).mockResolvedValue({});
75+
76+
const result = await generateHackParserPresignedURL(key);
77+
expect(result).toBeUndefined();
78+
});
3879
});

0 commit comments

Comments
 (0)