diff --git a/CHANGES b/CHANGES index 599f234a1..62623cc28 100644 --- a/CHANGES +++ b/CHANGES @@ -1331,4 +1331,5 @@ * Display restore errors in the UI * Update Haraka to 2.8.19 * GPG verify releases +* Allow subdomains in location field diff --git a/src/apps.js b/src/apps.js index c176429dd..3c3fbd2d6 100644 --- a/src/apps.js +++ b/src/apps.js @@ -149,9 +149,9 @@ function validateHostname(location, domain, hostname) { if (location) { // label validation - if (location.length > 63) return new AppsError(AppsError.BAD_FIELD, 'Subdomain exceeds 63 characters'); - if (location.match(/^[A-Za-z0-9-]+$/) === null) return new AppsError(AppsError.BAD_FIELD, 'Subdomain can only contain alphanumerics and hyphen'); - if (location.startsWith('-') || location.endsWith('-')) return new AppsError(AppsError.BAD_FIELD, 'Subdomain cannot start or end with hyphen'); + if (location.split('.').some(function (p) { return p.length > 63 || p.length < 1; })) return new AppsError(AppsError.BAD_FIELD, 'Invalid subdomain length'); + if (location.match(/^[A-Za-z0-9-.]+$/) === null) return new AppsError(AppsError.BAD_FIELD, 'Subdomain can only contain alphanumeric, hyphen and dot'); + if (/^[-.]/.test(location)) return new AppsError(AppsError.BAD_FIELD, 'Subdomain cannot start or end with hyphen or dot'); } return null; diff --git a/src/test/apps-test.js b/src/test/apps-test.js index 7cb47cfa9..0a24b7861 100644 --- a/src/test/apps-test.js +++ b/src/test/apps-test.js @@ -182,16 +182,18 @@ describe('Apps', function () { }); it('cannot have >63 length subdomains', function () { - var s = ''; - for (var i = 0; i < 64; i++) s += 's'; + var s = Array(64).fill('s').join(''); expect(apps._validateHostname(s, 'example.com', s + '.example.com')).to.be.an(Error); + expect(apps._validateHostname(`dev.${s}`, 'example.com', `dev.${s}.example.com`)).to.be.an(Error); }); it('allows only alphanumerics and hypen', function () { expect(apps._validateHostname('#2r', 'example.com', '#2r.example.com')).to.be.an(Error); expect(apps._validateHostname('a%b', 'example.com', 'a%b.example.com')).to.be.an(Error); expect(apps._validateHostname('ab_', 'example.com', 'ab_.example.com')).to.be.an(Error); - expect(apps._validateHostname('a.b', 'example.com', 'a.b.example.com')).to.be.an(Error); + expect(apps._validateHostname('ab.', 'example.com', 'ab.example.com')).to.be.an(Error); + expect(apps._validateHostname('ab..c', 'example.com', 'ab..c.example.com')).to.be.an(Error); + expect(apps._validateHostname('.ab', 'example.com', '.ab.example.com')).to.be.an(Error); expect(apps._validateHostname('-ab', 'example.com', '-ab.example.com')).to.be.an(Error); expect(apps._validateHostname('ab-', 'example.com', 'ab-.example.com')).to.be.an(Error); }); @@ -206,6 +208,8 @@ describe('Apps', function () { it('allow valid domains', function () { expect(apps._validateHostname('a', 'example.com', 'a.example.com')).to.be(null); expect(apps._validateHostname('a0-x', 'example.com', 'a0-x.example.com')).to.be(null); + expect(apps._validateHostname('a0.x', 'example.com', 'a0-x.example.com')).to.be(null); + expect(apps._validateHostname('a0.x.y', 'example.com', 'a0.x.y.example.com')).to.be(null); expect(apps._validateHostname('01', 'example.com', '01.example.com')).to.be(null); }); });