Skip to content

Commit

Permalink
add encryption to post-register handler
Browse files Browse the repository at this point in the history
  • Loading branch information
aerlaut committed Jun 5, 2023
1 parent a20a6e0 commit dcab1bc
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 27 deletions.
32 changes: 30 additions & 2 deletions src/api.v2/helpers/access/postRegistrationHandler.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,40 @@
const crypto = require('crypto');

const ENC_METHOD = 'aes-256-cbc';

const getLogger = require('../../../utils/getLogger');
const { OK } = require('../../../utils/responses');
const { OK, BadRequestError } = require('../../../utils/responses');

const UserAccess = require('../../model/UserAccess');

const logger = getLogger('[PostRegistrationHandler] - ');
const config = require('../../../config');

const decrypt = (encryptedData, key, iv) => {
const buff = Buffer.from(encryptedData, 'base64');
const decipher = crypto.createDecipheriv(ENC_METHOD, key, iv);
return (
decipher.update(buff.toString('utf8'), 'hex', 'utf8')
+ decipher.final('utf8')
);
};

const postRegistrationHandler = async (req) => {
const { userEmail, userId } = req.body;
const key = crypto.createHash('sha512').update(config.domainName)
.digest('hex')
.substring(0, 32);

const [encryptedData, iv] = req.body.split('.');
let payload = '';

try {
// An invalid request will not be parsed into JSON correctly
payload = decrypt(encryptedData, key, iv);
} catch (e) {
throw new BadRequestError('Invalid request');
}

const { userEmail, userId } = JSON.parse(payload);

new UserAccess().registerNewUserAccess(userEmail, userId);

Expand Down
13 changes: 2 additions & 11 deletions src/specs/api.v2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1659,17 +1659,8 @@ paths:
text/plain:
schema:
type: string
examples: {}
application/json:
schema:
type: object
properties:
userEmail:
type: string
minLength: 1
userId:
type: string
minLength: 1


"/workResults/{experimentId}/{ETag}":
get:
summary: Get the work results from S3
Expand Down
39 changes: 32 additions & 7 deletions tests/api.v2/helpers/access/postRegistrationHandler.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Disabled ts because it doesn't recognize jest mocks
// @ts-nocheck
const crypto = require('crypto');
const UserAccess = require('../../../../src/api.v2/model/UserAccess');

const postRegistrationHandler = require('../../../../src/api.v2/helpers/access/postRegistrationHandler');
const { OK } = require('../../../../src/utils/responses');
const { OK, BadRequestError } = require('../../../../src/utils/responses');
const config = require('../../../../src/config');

jest.mock('../../../../src/api.v2/model/UserAccess');

Expand All @@ -18,22 +20,45 @@ describe('postRegistrationHandler', () => {
jest.clearAllMocks();
});

it('Registers new user on correct message', async () => {
it('Associates new users with experiemnts correctly', async () => {
const ENC_METHOD = 'aes-256-cbc';

const mockKey = crypto.createHash('sha512').update(config.domainName)
.digest('hex')
.substring(0, 32);

// iv length has to be 16
const mockIV = '1234567890111213';

const mockUserEmail = 'mock-user-email';
const mockUserId = 'mock-user-email';

const mockReq = {
body: {
userEmail: mockUserEmail,
userId: mockUserId,
},
const payload = {
userEmail: mockUserEmail,
userId: mockUserId,
};

const cipher = crypto.createCipheriv(ENC_METHOD, mockKey, mockIV);
const encryptedBody = Buffer.from(
cipher.update(JSON.stringify(payload), 'utf8', 'hex') + cipher.final('hex'),
).toString('base64');

const mockReq = {
body: `${encryptedBody}.${mockIV}`,
};
const res = await postRegistrationHandler(mockReq);

expect(mockUserAccess.registerNewUserAccess).toHaveBeenCalledWith(mockUserEmail, mockUserId);
expect(mockUserAccess.registerNewUserAccess).toHaveBeenCalledTimes(1);

expect(res).toEqual(OK());
});

it('Throws an error if message is invalid', async () => {
const mockReq = {
body: 'SomeInvalidMessage',
};

await expect(postRegistrationHandler(mockReq)).rejects.toThrowError(BadRequestError);
});
});
31 changes: 24 additions & 7 deletions tests/api.v2/routes/access.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const expressLoader = require('../../../src/loaders/express');

const accessController = require('../../../src/api.v2/controllers/accessController');
const {
UnauthenticatedError, UnauthorizedError, NotFoundError, OK,
UnauthenticatedError, UnauthorizedError, NotFoundError, OK, BadRequestError,
} = require('../../../src/utils/responses');
const AccessRole = require('../../../src/utils/enums/AccessRole');

Expand Down Expand Up @@ -181,15 +181,12 @@ describe('User access endpoint', () => {
Promise.resolve();
});

const mockUserInfo = JSON.stringify({
userId: 'mockUserId',
userEmail: '[email protected]',
});
const mockPayload = 'mock.payload';

request(app)
.post('/v2/access/post-registration')
.send(mockUserInfo)
.set('Content-type', 'application/json')
.send(mockPayload)
.set('Content-type', 'text/plain')
.expect(200)
.end((err) => {
if (err) {
Expand All @@ -198,4 +195,24 @@ describe('User access endpoint', () => {
return done();
});
});

it('Post-user registration endpoint returns error on invalid body', async (done) => {
accessController.postRegistration.mockImplementationOnce((req, res) => {
throw new BadRequestError('Invalid request');
});

const mockPayload = 'invalid.payload';

request(app)
.post('/v2/access/post-registration')
.send(mockPayload)
.set('Content-type', 'text/plain')
.expect(400)
.end((err) => {
if (err) {
return done(err);
}
return done();
});
});
});

0 comments on commit dcab1bc

Please sign in to comment.