diff --git a/lib/routes/admin-api/feature.js b/lib/routes/admin-api/feature.js index 6056a238e8..ea99499982 100644 --- a/lib/routes/admin-api/feature.js +++ b/lib/routes/admin-api/feature.js @@ -15,6 +15,8 @@ const ValidationError = require('../../error/validation-error.js'); const validateRequest = require('../../error/validate-request'); const extractUser = require('../../extract-user'); +const nameRegex = /^[0-9a-zA-Z\-._]+$/; + const handleErrors = (req, res, error) => { logger.warn('Error creating or updating feature', error); switch (error.constructor) { @@ -115,8 +117,8 @@ module.exports.router = function(config) { router.post('/', (req, res) => { req.checkBody('name', 'Name is required').notEmpty(); req - .checkBody('name', 'Name must match format ^[0-9a-zA-Z\\.\\-\\_]+$') - .matches(/^[0-9a-zA-Z\\.\\-\\_]+$/i); + .checkBody('name', `Name must match format ${nameRegex.source}`) + .matches(nameRegex); const userName = extractUser(req); validateRequest(req) diff --git a/lib/routes/admin-api/feature.test.js b/lib/routes/admin-api/feature.test.js index cb6f30f546..3cc428246f 100644 --- a/lib/routes/admin-api/feature.test.js +++ b/lib/routes/admin-api/feature.test.js @@ -95,3 +95,31 @@ test('should require at least one strategy when updating a feature toggle', t => .set('Content-Type', 'application/json') .expect(400); }); + +test('valid feature names pass validation', async t => { + t.plan(0); + const { request, base } = getSetup(); + + const validNames = [ + 'com.example', + 'com.exampleFeature', + 'com.example-company.feature', + 'com.example-company.exampleFeature', + '123', + 'com.example-company.someFeature.123', + ]; + + return Promise.all( + validNames.map(name => + request + .post(`${base}/api/admin/features`) + .send({ + name, + enabled: false, + strategies: [{ name: 'default' }], + }) + .set('Content-Type', 'application/json') + .expect(201) + ) + ); +});