Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env-cmdrc-template
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"JWT_CLIENT_TOKEN_EXP_TIME": "5m",
"JWT_ADMIN_TOKEN_RENEW_INTERVAL": "5m",
"MAX_STRATEGY_OPERATION": 100,
"RELAY_BYPASS_HTTPS": true,
"HISTORY_ACTIVATED": true,
"METRICS_ACTIVATED": true,
"METRICS_MAX_PAGE": 50,
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ jobs:
GOOGLE_RECAPTCHA_SECRET: ${{ secrets.GOOGLE_RECAPTCHA_SECRET }}
GOOGLE_SKIP_AUTH: false
MAX_STRATEGY_OPERATION: 100
RELAY_BYPASS_HTTPS: true
METRICS_ACTIVATED: true
METRICS_MAX_PAGE: 50
SWITCHER_API_ENABLE: false
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ jobs:
GOOGLE_RECAPTCHA_SECRET: ${{ secrets.GOOGLE_RECAPTCHA_SECRET }}
GOOGLE_SKIP_AUTH: false
MAX_STRATEGY_OPERATION: 100
RELAY_BYPASS_HTTPS: true
METRICS_ACTIVATED: true
METRICS_MAX_PAGE: 50
SWITCHER_API_ENABLE: false
Expand Down
1 change: 1 addition & 0 deletions config/.env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ RESOURCE_SECRET=[CHANGE_IT]
JWT_CLIENT_TOKEN_EXP_TIME=5m
JWT_ADMIN_TOKEN_RENEW_INTERVAL=10m
MAX_STRATEGY_OPERATION=100
RELAY_BYPASS_HTTPS=true
REGEX_MAX_TIMEOUT=3000
REGEX_MAX_BLACLIST=50
HISTORY_ACTIVATED=true
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ services:
- JWT_CLIENT_TOKEN_EXP_TIME=${JWT_CLIENT_TOKEN_EXP_TIME}
- JWT_ADMIN_TOKEN_RENEW_INTERVAL=${JWT_ADMIN_TOKEN_RENEW_INTERVAL}
- MAX_STRATEGY_OPERATION=${MAX_STRATEGY_OPERATION}
- RELAY_BYPASS_HTTPS=${RELAY_BYPASS_HTTPS}
- HISTORY_ACTIVATED=${HISTORY_ACTIVATED}
- METRICS_ACTIVATED=${METRICS_ACTIVATED}
- METRICS_MAX_PAGE=${METRICS_MAX_PAGE}
Expand Down
1 change: 1 addition & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ app.get('/check', (_req, res) => {
db_state: mongoose.connection.readyState,
switcherapi: process.env.SWITCHER_API_ENABLE,
switcherapi_logger: process.env.SWITCHER_API_LOGGER,
relay_bypass_https: process.env.RELAY_BYPASS_HTTPS,
history: process.env.HISTORY_ACTIVATED,
metrics: process.env.METRICS_ACTIVATED,
max_metrics_pages: process.env.METRICS_MAX_PAGE,
Expand Down
9 changes: 6 additions & 3 deletions src/client/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { verifyOwnership } from '../helpers';
import { resolveNotification, resolveValidation } from './relay/index';
import Component from '../models/component';
import Logger from '../helpers/logger';
import { validateRelay } from '../services/config';

export const resolveConfigByKey = async (domain, key) => Config.findOne({ domain, key }, null, { lean: true });

Expand Down Expand Up @@ -171,7 +172,9 @@ async function checkConfigStrategies(configId, strategyFilter) {

async function resolveRelay(config, environment, entry, response) {
try {
if (config.relay && config.relay.activated[environment]) {
if (config.relay?.activated[environment]) {
validateRelay(config.relay);

if (config.relay.type === RelayTypes.NOTIFICATION) {
resolveNotification(config.relay.endpoint[environment], config.relay.method, entry,
config.relay.auth_prefix, config.relay.auth_token[environment]);
Expand All @@ -194,7 +197,7 @@ async function resolveRelay(config, environment, entry, response) {
}

function isMetricDisabled(config, environment) {
if (config.disable_metrics && config.disable_metrics[environment]) {
if (config.disable_metrics) {
return config.disable_metrics[environment];
}
return false;
Expand Down Expand Up @@ -225,7 +228,7 @@ async function checkStrategy(entry, strategies, environment) {
}

async function checkStrategyInput(entry, { strategy, operation, values }) {
if (entry && entry.length) {
if (entry?.length) {
const strategyEntry = entry.filter(e => e.strategy === strategy);
if (strategyEntry.length == 0 || !(await processOperation(strategy, operation, strategyEntry[0].input, values))) {
throw new Error(`Strategy '${strategy}' does not agree`);
Expand Down
4 changes: 2 additions & 2 deletions src/middleware/validators.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { validationResult } from 'express-validator';
import { BadRequestError } from '../exceptions';
import { BadRequestError, responseException } from '../exceptions';
import { getConfig } from '../services/config';
import { getComponents } from '../services/component';
import { getEnvironments } from '../services/environment';
Expand Down Expand Up @@ -48,7 +48,7 @@ export function verifyInputUpdateParameters(allowedUpdates) {
const isValidOperation = updates.every((update) => allowedUpdates.includes(update));

if (!isValidOperation) {
return res.status(400).send({ error: 'Invalid update parameters' });
return responseException(res, new Error('Invalid update parameters'), 400);
}

req.updates = updates;
Expand Down
4 changes: 3 additions & 1 deletion src/routers/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ router.patch('/config/:id', auth, [

router.patch('/config/updateRelay/:id', auth, [
check('id').isMongoId()
], validate, async (req, res) => {
], validate, verifyInputUpdateParameters([
'type', 'description', 'activated', 'endpoint', 'method', 'auth_prefix', 'auth_token'
]), async (req, res) => {
try {
let config = await Services.updateConfigRelay(req.params.id, req.body, req.admin);
res.send(config);
Expand Down
17 changes: 16 additions & 1 deletion src/services/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ export async function updateConfig(id, args, admin) {

export async function updateConfigRelay(id, args, admin) {
let config = await getConfigById(id);
validateRelay(args);

config = await verifyOwnership(admin, config, config.domain, ActionTypes.UPDATE, RouterTypes.CONFIG);
config.updatedBy = admin.email;

Expand Down Expand Up @@ -245,7 +247,7 @@ export async function removeRelay(id, env, admin) {
config = await verifyOwnership(admin, config, config.domain, ActionTypes.DELETE, RouterTypes.CONFIG);
config.updatedBy = admin.email;

if (config.relay.activated && config.relay.activated.get(env) != undefined) {
if (config.relay.activated?.get(env) != undefined) {
if (config.relay.activated.size > 1) {
config.relay.activated.delete(env);
config.relay.endpoint.delete(env);
Expand Down Expand Up @@ -283,4 +285,17 @@ export async function verifyRelay(id, code, admin) {
}

return 'failed';
}

export function validateRelay(relay) {
const bypass = process.env.RELAY_BYPASS_HTTPS === 'true' || false;

if (bypass)
return;

const foundNotHttps = Object.values(relay.endpoint)
.filter(endpoint => !endpoint.toLowerCase().startsWith('https'));

if (foundNotHttps.length)
throw new BadRequestError('HTTPS required');
}
84 changes: 77 additions & 7 deletions tests/config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,64 @@ describe('Testing component association', () => {
});
});

describe('Testing relay verification', () => {
beforeAll(async () => {
await setupDatabase();
process.env.RELAY_BYPASS_HTTPS = false;
});

afterAll(() => {
process.env.RELAY_BYPASS_HTTPS = true;
});

const bodyRelay = {
type: 'VALIDATION',
activated: {
default: true
},
endpoint: {
default: {}
},
method: 'POST'
};

test('CONFIG_SUITE - Should NOT configure new Relay - Not HTTPS', async () => {
// Given HTTP
bodyRelay.endpoint.default = 'http://localhost:3001';

// Test
const response = await request(app)
.patch(`/config/updateRelay/${configId1}`)
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
.send(bodyRelay).expect(400);

expect(response.body.error).toEqual('HTTPS required');
});

test('CONFIG_SUITE - Should configure new Relay', async () => {
// Given HTTPS
bodyRelay.endpoint.default = 'https://localhost:3001';

// Test
await request(app)
.patch(`/config/updateRelay/${configId1}`)
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
.send(bodyRelay).expect(200);
});

test('CONFIG_SUITE - Should configure new Relay - All capital HTTPS', async () => {
// Given HTTPS
bodyRelay.endpoint.default = 'HTTPS://localhost:3001';

// Test
await request(app)
.patch(`/config/updateRelay/${configId1}`)
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
.send(bodyRelay).expect(200);
});

});

describe('Testing relay association', () => {
beforeAll(setupDatabase);

Expand Down Expand Up @@ -794,6 +852,7 @@ describe('Testing relay association', () => {
// DB validation - document updated
const config = await Config.findById(configId1).lean().exec();
expect(config.relay.verified).toEqual(false);
expect(config.relay.verification_code).toEqual(undefined);
expect(config.relay.activated['default']).toEqual(true);
expect(config.relay.endpoint['default']).toBe('http://localhost:3001');
expect(config.relay.auth_token['default']).toEqual('123');
Expand Down Expand Up @@ -860,7 +919,7 @@ describe('Testing relay association', () => {
});

test('CONFIG_SUITE - Should configure new Relay on new envrironment', async () => {
//given
// Given
// Creating development Environment...
await request(app)
.post('/environment/create')
Expand All @@ -870,7 +929,7 @@ describe('Testing relay association', () => {
domain: domainId
}).expect(201);

//test
// Test
await request(app)
.patch(`/config/updateRelay/${configId1}`)
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
Expand Down Expand Up @@ -898,7 +957,7 @@ describe('Testing relay association', () => {
});

test('CONFIG_SUITE - Should remove configured Relay when reseting environment', async () => {
//test
// Test
await request(app)
.patch('/config/removeStatus/' + configId1)
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
Expand All @@ -918,7 +977,7 @@ describe('Testing relay association', () => {
});

test('CONFIG_SUITE - Should remove Relay from an environment', async () => {
//given - adding development relay to be removed later on
// Given - adding development relay to be removed later on
await request(app)
.patch(`/config/updateRelay/${configId1}`)
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
Expand All @@ -940,7 +999,7 @@ describe('Testing relay association', () => {
expect(config.relay.endpoint['development']).toBe('http://localhost:7000');
expect(config.relay.auth_token['development']).toEqual('abcd');

//test
// Test
await request(app)
.patch(`/config/removeRelay/${configId1}/development`)
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
Expand Down Expand Up @@ -1060,6 +1119,7 @@ describe('Testing relay association', () => {
});

describe('Testing disable metrics', () => {
beforeAll(setupDatabase);

test('CONFIG_SUITE - Should disable metrics for production environment', async () => {
await request(app)
Expand Down Expand Up @@ -1090,7 +1150,17 @@ describe('Testing disable metrics', () => {
});

test('CONFIG_SUITE - Should reset disabled metric flag when reseting environment', async () => {
//given
// Given
// Creating development Environment...
await request(app)
.post('/environment/create')
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
.send({
name: 'development',
domain: domainId
}).expect(201);

// Update to true
await request(app)
.patch(`/config/${configId1}`)
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
Expand All @@ -1104,7 +1174,7 @@ describe('Testing disable metrics', () => {
let config = await Config.findById(configId1).lean().exec();
expect(config.disable_metrics['development']).toEqual(true);

//test
// Test
await request(app)
.patch('/config/removeStatus/' + configId1)
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
Expand Down
Loading