diff --git a/requests/Switcher API.postman_collection.json b/requests/Switcher API.postman_collection.json index 7f1e0c2..d5fe71b 100644 --- a/requests/Switcher API.postman_collection.json +++ b/requests/Switcher API.postman_collection.json @@ -3793,6 +3793,54 @@ }, "response": [] }, + { + "name": "Config - Relay - Verify", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/config/relay/verify/:config?code=", + "host": [ + "{{url}}" + ], + "path": [ + "config", + "relay", + "verify", + ":config" + ], + "query": [ + { + "key": "code", + "value": "" + } + ], + "variable": [ + { + "key": "config", + "value": "5e0eceb66f4f994eac9007b2" + } + ] + } + }, + "response": [] + }, { "name": "Config - Read Relay Specs", "request": { diff --git a/src/api-docs/paths/path-config.js b/src/api-docs/paths/path-config.js index 7a22393..90da70a 100644 --- a/src/api-docs/paths/path-config.js +++ b/src/api-docs/paths/path-config.js @@ -302,6 +302,35 @@ export default { } } }, + '/config/relay/verify/{id}': { + patch: { + tags: ['Config'], + description: 'Verify Config Relay ownership based on given verification code', + security: [{ bearerAuth: [] }], + parameters: [ + pathParameter('id', 'Config ID', true), + queryParameter('code', 'Verification code', true, 'string') + ], + responses: { + '200': { + description: 'Config Relay verification code generated', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { + type: 'string', + description: 'Return verification status [verified/failed]' + } + } + } + } + } + } + } + } + }, '/config/spec/relay': { get: { tags: ['Config'], diff --git a/src/routers/config.js b/src/routers/config.js index f1010a2..dbbd897 100644 --- a/src/routers/config.js +++ b/src/routers/config.js @@ -219,6 +219,18 @@ router.patch('/config/relay/verificationCode/:id', auth, [ } }); +router.patch('/config/relay/verify/:id', auth, [ + check('id').isMongoId(), + query('code').isAscii() +], validate, async (req, res) => { + try { + const result = await Services.verifyRelay(req.params.id, req.query.code, req.admin); + res.send({ status: result }); + } catch (e) { + responseException(res, e, 500); + } +}); + router.get('/config/spec/relay', auth, (_req, res) => { res.send(relayOptions()); }); diff --git a/src/services/config.js b/src/services/config.js index e97e1c0..4261d99 100644 --- a/src/services/config.js +++ b/src/services/config.js @@ -1,5 +1,5 @@ import mongoose from 'mongoose'; -import { randomBytes } from 'crypto'; +import { randomUUID } from 'crypto'; import { response } from './common'; import { Config } from '../models/config'; import { formatInput, verifyOwnership, checkEnvironmentStatusRemoval } from '../helpers'; @@ -265,12 +265,22 @@ export async function getRelayVerificationCode(id, admin) { let config = await getConfigById(id); config = await verifyOwnership(admin, config, config.domain, ActionTypes.UPDATE, RouterTypes.CONFIG); - const buffer = randomBytes(32); - const code = Buffer.from(buffer).toString('base64'); - config.updatedBy = admin.email; - config.relay.verification_code = code; + config.relay.verification_code = randomUUID(); config.relay.verified = false; return config.save(); +} + +export async function verifyRelay(id, code, admin) { + let config = await getConfigById(id); + config = await verifyOwnership(admin, config, config.domain, ActionTypes.UPDATE, RouterTypes.CONFIG); + + if (!config.relay.verified && Object.is(config.relay.verification_code, code)) { + config.relay.verified = true; + await config.save(); + return 'verified'; + } + + return 'failed'; } \ No newline at end of file diff --git a/tests/config.test.js b/tests/config.test.js index ce84591..1f6998f 100644 --- a/tests/config.test.js +++ b/tests/config.test.js @@ -987,13 +987,76 @@ describe('Testing relay association', () => { expect(response.body.code).not.toBe(undefined); }); - test('CONFIG_SUITE - Should NOT generate verification code', async () => { + test('CONFIG_SUITE - Should NOT generate verification code - Config not found', async () => { await request(app) .patch(`/config/relay/verificationCode/${new mongoose.Types.ObjectId()}`) .set('Authorization', `Bearer ${adminMasterAccountToken}`) .send(bodyRelayProd).expect(404); }); + test('CONFIG_SUITE - Should verify code', async () => { + // Given + // Request verification code + let response = await request(app) + .patch(`/config/relay/verificationCode/${configId1}`) + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send().expect(200); + + // Test + response = await request(app) + .patch(`/config/relay/verify/${configId1}?code=${response.body.code}`) + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send().expect(200); + + expect(response.body.status).toBe('verified'); + }); + + test('CONFIG_SUITE - Should NOT verify code - Config not found', async () => { + // Given + // Request verification code + const response = await request(app) + .patch(`/config/relay/verificationCode/${configId1}`) + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send().expect(200); + + // Test + await request(app) + .patch(`/config/relay/verify/${new mongoose.Types.ObjectId()}?code=${response.body.code}`) + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send().expect(404); + }); + + test('CONFIG_SUITE - Should NOT verify code - Invalid code', async () => { + await request(app) + .patch(`/config/relay/verify/${configId1}?code=`) + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send().expect(422); + }); + + test('CONFIG_SUITE - Should NOT verify code - Relay already verified', async () => { + // Given + // Request verification code + let response = await request(app) + .patch(`/config/relay/verificationCode/${configId1}`) + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send().expect(200); + + // That + // Is already verified + await request(app) + .patch(`/config/relay/verify/${configId1}?code=${response.body.code}`) + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send().expect(200); + + // Test + response = await request(app) + .patch(`/config/relay/verify/${configId1}?code=${response.body.code}`) + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send().expect(200); + + expect(response.body.status).toBe('failed'); + }); + }); describe('Testing disable metrics', () => {