diff --git a/package.json b/package.json index 43ded25..74289eb 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "switcher-api", "version": "1.2.8", "description": "Feature Flag/Toggle API", - "main": "start.js", + "main": "src/start.js", "type": "module", "author": { "name": "Roger Floriano", @@ -49,9 +49,9 @@ "helmet": "^7.1.0", "jsonwebtoken": "^9.0.2", "moment": "^2.30.1", - "mongodb": "^6.5.0", - "mongoose": "^8.3.2", - "pino": "^8.20.0", + "mongodb": "^6.6.1", + "mongoose": "^8.3.4", + "pino": "^9.0.0", "pino-pretty": "^11.0.0", "swagger-ui-express": "^5.0.0", "switcher-client": "^4.0.3", @@ -65,7 +65,7 @@ "node-notifier": "^10.0.1", "nodemon": "^3.1.0", "sinon": "^17.0.1", - "supertest": "^6.3.4" + "supertest": "^7.0.0" }, "overrides": { "formidable": "^3.5.1" diff --git a/src/middleware/auth.js b/src/middleware/auth.js index 642d79a..b52d1fc 100644 --- a/src/middleware/auth.js +++ b/src/middleware/auth.js @@ -2,6 +2,7 @@ import basicAuth from 'express-basic-auth'; import jwt from 'jsonwebtoken'; import { getAdmin, getAdminById } from '../services/admin.js'; import { getComponentById } from '../services/component.js'; +import { getEnvironmentByName } from '../services/environment.js'; import Admin from '../models/admin.js'; import Component from '../models/component.js'; import { getRateLimit } from '../external/switcher-api-facade.js'; @@ -114,6 +115,11 @@ export async function appGenerateCredentials(req, res, next) { try { const key = req.header('switcher-api-key'); const { component, domain } = await Component.findByCredentials(req.body.domain, req.body.component, key); + const environment = await getEnvironmentByName(component.domain, req.body.environment); + + if (!environment) { + throw new Error('Invalid environment'); + } const rate_limit = await getRateLimit(key, component); const token = await component.generateAuthToken(req.body.environment, rate_limit); diff --git a/src/routers/client-api.js b/src/routers/client-api.js index 853ffea..e3d1c15 100644 --- a/src/routers/client-api.js +++ b/src/routers/client-api.js @@ -1,5 +1,5 @@ import express from 'express'; -import { body, check, query } from 'express-validator'; +import { body, check, query, header } from 'express-validator'; import jwt from 'jsonwebtoken'; import { checkConfig, checkConfigComponent, validate } from '../middleware/validators.js'; import { componentAuth, appGenerateCredentials } from '../middleware/auth.js'; @@ -47,15 +47,13 @@ router.post('/criteria', componentAuth, clientLimiter, [ } }); -router.get('/criteria/snapshot_check/:version', componentAuth, clientLimiter, async (req, res) => { +router.get('/criteria/snapshot_check/:version', componentAuth, clientLimiter, [ + check('version', 'Wrong value for domain version').isNumeric() +], validate, async (req, res) => { try { const domain = await checkDomain(req.domain); const version = req.params.version; - if (isNaN(version)) { - return res.status(400).send({ error: 'Wrong value for domain version' }); - } - if (domain.lastUpdate > version) { res.send({ status: false }); } else { @@ -78,7 +76,12 @@ router.post('/criteria/switchers_check', componentAuth, clientLimiter, [ } }); -router.post('/criteria/auth', appGenerateCredentials, clientLimiter, async (req, res) => { +router.post('/criteria/auth', [ + header('switcher-api-key').isString().withMessage('API Key header is required'), + body('domain').isString().withMessage('Domain is required'), + body('component').isString().withMessage('Component is required'), + body('environment').isString().withMessage('Environment is required') +], validate, appGenerateCredentials, clientLimiter, async (req, res) => { try { const { exp } = jwt.decode(req.token); res.send({ token: req.token, exp }); diff --git a/src/services/environment.js b/src/services/environment.js index 3065578..6a8e7c4 100644 --- a/src/services/environment.js +++ b/src/services/environment.js @@ -40,13 +40,17 @@ export async function getEnvironmentById(id) { } export async function getEnvironment(where) { + const environment = await getEnvironmentByName(where.domain, where.name); + return response(environment, 'Environment not found'); +} + +export async function getEnvironmentByName(domain, name) { const query = Environment.findOne(); - if (where.domain) query.where('domain', where.domain); - if (where.name) query.where('name', where.name); + if (domain) query.where('domain', domain); + if (name) query.where('name', name); - let environment = await query.exec(); - return response(environment, 'Environment not found'); + return query.exec(); } export async function getEnvironments(where, projection, options) { diff --git a/tests/client-api.test.js b/tests/client-api.test.js index 96d40dc..f2330a8 100644 --- a/tests/client-api.test.js +++ b/tests/client-api.test.js @@ -142,31 +142,25 @@ describe('Testing criteria [GraphQL] ', () => { expect(JSON.parse(req.text)).toMatchObject(JSON.parse(graphqlUtils.expected101)); }); - test('CLIENT_SUITE - Should return success on Flat view resolved by Config Key - Unknown environment, should look to production', async () => { - const response = await request(app) + test('CLIENT_SUITE - Should NOT authenticate invalid component', async () => { + await request(app) .post('/criteria/auth') .set('switcher-api-key', `${apiKey}`) .send({ domain: domainDocument.name, - component: component1.name, - environment: 'UNKNOWN ENVIRONMENT' - }).expect(200); - - await request(app) - .post('/graphql') - .set('Authorization', `Bearer ${response.body.token}`) - .send(graphqlUtils.configurationQuery([['key', keyConfig]])) - .expect(200); + component: 'UNKNOWN COMPONENT', + environment: EnvType.DEFAULT + }).expect(401); }); - test('CLIENT_SUITE - Should NOT authenticate invalid component', async () => { + test('CLIENT_SUITE - Should NOT authenticate invalid environment', async () => { await request(app) .post('/criteria/auth') .set('switcher-api-key', `${apiKey}`) .send({ domain: domainDocument.name, - component: 'UNKNOWN COMPONENT', - environment: EnvType.DEFAULT + component: component1.name, + environment: 'UNKNOWN ENVIRONMENT' }).expect(401); }); @@ -772,8 +766,8 @@ describe('Testing criteria [REST] ', () => { .set('Authorization', `Bearer ${token}`) .send(); - expect(req.statusCode).toBe(400); - expect(req.body.error).toEqual('Wrong value for domain version'); + expect(req.statusCode).toBe(422); + expect(req.body.errors[0].msg).toEqual('Wrong value for domain version'); }); test('CLIENT_SUITE - Should return error when validating snapshot version - Invalid token', async () => {