Browse Source

Merge pull request #502 from troymccabe/enhancement-intranet_validity

Allowing sites without TLD to pass URI validation
Phuoc Nguyen 11 years ago
parent
commit
88c565717e
3 changed files with 321 additions and 1 deletions
  1. 4 1
      src/js/validator/uri.js
  2. 159 0
      test/spec.js
  3. 158 0
      test/spec/validator/uri.js

+ 4 - 1
src/js/validator/uri.js

@@ -46,7 +46,7 @@
             // Notes on possible differences from a standard/generic validation:
             //
             // - utf-8 char class take in consideration the full Unicode range
-            // - TLDs have been made mandatory so single names like "localhost" fails
+            // - TLDs are mandatory unless `allowLocal` is true
             // - protocols have been restricted to ftp, http and https only as requested
             //
             // Changes:
@@ -56,6 +56,7 @@
             //   (since they are broadcast/network addresses)
             //
             // - Added exclusion of private, reserved and/or local networks ranges
+            //   unless `allowLocal` is true
             //
             var allowLocal = options.allowLocal === true || options.allowLocal === 'true',
                 urlExp     = new RegExp(
@@ -87,6 +88,8 @@
                     "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*" +
                     // TLD identifier
                     "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
+                    // Allow intranet sites (no TLD) if `allowLocal` is true
+                    (allowLocal ? '?' : '') +
                     ")" +
                     // port number
                     "(?::\\d{2,5})?" +

+ 159 - 0
test/spec.js

@@ -3561,6 +3561,165 @@ describe('lessThan', function() {
     });
 });
 
+describe('uri', function() {
+    beforeEach(function () {
+        $([
+            '<form class="form-horizontal" id="uriForm">',
+            '<div id="msg"></div>',
+            '<div class="form-group">',
+            '<input type="text" name="uri" data-bv-uri />',
+            '</div>',
+            '</form>'
+        ].join('\n')).appendTo('body');
+
+        $('#uriForm').bootstrapValidator();
+
+        this.bv    = $('#uriForm').data('bootstrapValidator');
+        this.$uri = this.bv.getFieldElements('uri');
+    });
+
+    afterEach(function () {
+        $('#uriForm').bootstrapValidator('destroy').remove();
+    });
+
+    var validGlobalURIs = [
+        'http://foo.com/blah_blah',
+        'http://foo.com/blah_blah',
+        'http://foo.com/blah_blah/',
+        'http://foo.com/blah_blah_(wikipedia)',
+        'http://foo.com/blah_blah_(wikipedia)_(again)',
+        'http://www.example.com/wpstyle/?p=364',
+        'https://www.example.com/foo/?bar=baz&inga=42&quux',
+        'http://✪df.ws/123',
+        'http://userid:password@example.com:8080',
+        'http://userid:password@example.com:8080/',
+        'http://userid@example.com',
+        'http://userid@example.com/',
+        'http://userid@example.com:8080',
+        'http://userid@example.com:8080/',
+        'http://userid:password@example.com',
+        'http://userid:password@example.com/',
+        'http://142.42.1.1/',
+        'http://142.42.1.1:8080/',
+        'http://➡.ws/䨹',
+        'http://⌘.ws',
+        'http://⌘.ws/',
+        'http://foo.com/blah_(wikipedia)#cite-1',
+        'http://foo.com/blah_(wikipedia)_blah#cite-1',
+        'http://foo.com/unicode_(✪)_in_parens',
+        'http://foo.com/(something)?after=parens',
+        'http://☺.damowmow.com/',
+        'http://code.google.com/events/#&product=browser',
+        'http://j.mp',
+        'ftp://foo.bar/baz',
+        'http://foo.bar/?q=Test%20URL-encoded%20stuff',
+        'http://مثال.إختبار',
+        'http://例子.测试',
+        'http://उदाहरण.परीक्षा',
+        "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com",
+        'http://1337.net',
+        'http://a.b-c.de',
+        'http://223.255.255.254'
+    ];
+
+    var invalidGlobalURIs = [
+        'http://',
+        'http://.',
+        'http://..',
+        'http://../',
+        'http://?',
+        'http://??',
+        'http://??/',
+        'http://#',
+        'http://##',
+        'http://##/',
+        'http://foo.bar?q=Spaces should be encoded',
+        '//',
+        '//a',
+        '///a',
+        '///',
+        'http:///a',
+        'foo.com',
+        'rdar://1234',
+        'h://test',
+        'http:// shouldfail.com',
+        ':// should fail',
+        'http://foo.bar/foo(bar)baz quux',
+        'ftps://foo.bar/',
+        'http://-error-.invalid/',
+        'http://a.b--c.de/',
+        'http://-a.b.co',
+        'http://a.b-.co',
+        'http://.www.foo.bar/',
+        'http://www.foo.bar./',
+        'http://.www.foo.bar./'
+    ];
+
+    var localURIs = [
+        'http://intranetsite',
+        'http://intranetsite/test',
+        'http://intranetsite:80',
+        'http://intranetsite:80/test',
+        'http://user:pass@intranetsite',
+        'http://user:pass@intranetsite/test',
+        'http://user:pass@intranetsite:80',
+        'http://user:pass@intranetsite:80/test',
+        'http://10.1.1.0',
+        'http://10.1.1.255',
+        'http://10.1.1.1',
+        'http://10.1.1.254',
+        'http://127.0.0.1',
+        'http://192.168.0.1',
+        'http://0.0.0.0',
+        'http://224.1.1.1',
+        'http://1.1.1.1.1',
+        'http://123.123.123',
+        'http://3628126748'
+    ];
+
+    it('Valid URIs (allowLocal=false)', function() {
+        var me = this;
+        $.each(validGlobalURIs, function(index, uri) {
+            me.bv.resetForm();
+            me.$uri.val(uri);
+            me.bv.validate();
+            expect(me.bv.isValid()).toBeTruthy();
+        });
+    });
+
+    it('Invalid URIs (allowLocal=false)', function() {
+        var me = this;
+        $.each(invalidGlobalURIs.concat(localURIs), function(index, uri) {
+            me.bv.resetForm();
+            me.$uri.val(uri);
+            me.bv.validate();
+            expect(me.bv.isValid()).toEqual(false);
+        });
+    });
+
+    it('Valid URIs (allowLocal=true)', function() {
+        var me = this;
+        me.bv.updateOption('uri', 'uri', 'allowLocal', true);
+        $.each(validGlobalURIs.concat(localURIs), function(index, uri) {
+            me.bv.resetForm();
+            me.$uri.val(uri);
+            me.bv.validate();
+            expect(me.bv.isValid()).toBeTruthy();
+        });
+    });
+
+    it('Invalid URIs (allowLocal=true)', function() {
+        var me = this;
+        me.bv.updateOption('uri', 'uri', 'allowLocal', true);
+        $.each(invalidGlobalURIs, function(index, uri) {
+            me.bv.resetForm();
+            me.$uri.val(uri);
+            me.bv.validate();
+            expect(me.bv.isValid()).toEqual(false);
+        });
+    });
+});
+
 describe('vat', function() {
     beforeEach(function() {
         $([

+ 158 - 0
test/spec/validator/uri.js

@@ -0,0 +1,158 @@
+describe('uri', function() {
+    beforeEach(function () {
+        $([
+            '<form class="form-horizontal" id="uriForm">',
+            '<div id="msg"></div>',
+            '<div class="form-group">',
+            '<input type="text" name="uri" data-bv-uri />',
+            '</div>',
+            '</form>'
+        ].join('\n')).appendTo('body');
+
+        $('#uriForm').bootstrapValidator();
+
+        this.bv    = $('#uriForm').data('bootstrapValidator');
+        this.$uri = this.bv.getFieldElements('uri');
+    });
+
+    afterEach(function () {
+        $('#uriForm').bootstrapValidator('destroy').remove();
+    });
+
+    var validGlobalURIs = [
+        'http://foo.com/blah_blah',
+        'http://foo.com/blah_blah',
+        'http://foo.com/blah_blah/',
+        'http://foo.com/blah_blah_(wikipedia)',
+        'http://foo.com/blah_blah_(wikipedia)_(again)',
+        'http://www.example.com/wpstyle/?p=364',
+        'https://www.example.com/foo/?bar=baz&inga=42&quux',
+        'http://✪df.ws/123',
+        'http://userid:password@example.com:8080',
+        'http://userid:password@example.com:8080/',
+        'http://userid@example.com',
+        'http://userid@example.com/',
+        'http://userid@example.com:8080',
+        'http://userid@example.com:8080/',
+        'http://userid:password@example.com',
+        'http://userid:password@example.com/',
+        'http://142.42.1.1/',
+        'http://142.42.1.1:8080/',
+        'http://➡.ws/䨹',
+        'http://⌘.ws',
+        'http://⌘.ws/',
+        'http://foo.com/blah_(wikipedia)#cite-1',
+        'http://foo.com/blah_(wikipedia)_blah#cite-1',
+        'http://foo.com/unicode_(✪)_in_parens',
+        'http://foo.com/(something)?after=parens',
+        'http://☺.damowmow.com/',
+        'http://code.google.com/events/#&product=browser',
+        'http://j.mp',
+        'ftp://foo.bar/baz',
+        'http://foo.bar/?q=Test%20URL-encoded%20stuff',
+        'http://مثال.إختبار',
+        'http://例子.测试',
+        'http://उदाहरण.परीक्षा',
+        "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com",
+        'http://1337.net',
+        'http://a.b-c.de',
+        'http://223.255.255.254'
+    ];
+
+    var invalidGlobalURIs = [
+        'http://',
+        'http://.',
+        'http://..',
+        'http://../',
+        'http://?',
+        'http://??',
+        'http://??/',
+        'http://#',
+        'http://##',
+        'http://##/',
+        'http://foo.bar?q=Spaces should be encoded',
+        '//',
+        '//a',
+        '///a',
+        '///',
+        'http:///a',
+        'foo.com',
+        'rdar://1234',
+        'h://test',
+        'http:// shouldfail.com',
+        ':// should fail',
+        'http://foo.bar/foo(bar)baz quux',
+        'ftps://foo.bar/',
+        'http://-error-.invalid/',
+        'http://a.b--c.de/',
+        'http://-a.b.co',
+        'http://a.b-.co',
+        'http://.www.foo.bar/',
+        'http://www.foo.bar./',
+        'http://.www.foo.bar./'
+    ];
+
+    var localURIs = [
+        'http://intranetsite',
+        'http://intranetsite/test',
+        'http://intranetsite:80',
+        'http://intranetsite:80/test',
+        'http://user:pass@intranetsite',
+        'http://user:pass@intranetsite/test',
+        'http://user:pass@intranetsite:80',
+        'http://user:pass@intranetsite:80/test',
+        'http://10.1.1.0',
+        'http://10.1.1.255',
+        'http://10.1.1.1',
+        'http://10.1.1.254',
+        'http://127.0.0.1',
+        'http://192.168.0.1',
+        'http://0.0.0.0',
+        'http://224.1.1.1',
+        'http://1.1.1.1.1',
+        'http://123.123.123',
+        'http://3628126748'
+    ];
+
+    it('Valid URIs (allowLocal=false)', function() {
+        var me = this;
+        $.each(validGlobalURIs, function(index, uri) {
+            me.bv.resetForm();
+            me.$uri.val(uri);
+            me.bv.validate();
+            expect(me.bv.isValid()).toBeTruthy();
+        });
+    });
+
+    it('Invalid URIs (allowLocal=false)', function() {
+        var me = this;
+        $.each(invalidGlobalURIs.concat(localURIs), function(index, uri) {
+            me.bv.resetForm();
+            me.$uri.val(uri);
+            me.bv.validate();
+            expect(me.bv.isValid()).toEqual(false);
+        });
+    });
+
+    it('Valid URIs (allowLocal=true)', function() {
+        var me = this;
+        me.bv.updateOption('uri', 'uri', 'allowLocal', true);
+        $.each(validGlobalURIs.concat(localURIs), function(index, uri) {
+            me.bv.resetForm();
+            me.$uri.val(uri);
+            me.bv.validate();
+            expect(me.bv.isValid()).toBeTruthy();
+        });
+    });
+
+    it('Invalid URIs (allowLocal=true)', function() {
+        var me = this;
+        me.bv.updateOption('uri', 'uri', 'allowLocal', true);
+        $.each(invalidGlobalURIs, function(index, uri) {
+            me.bv.resetForm();
+            me.$uri.val(uri);
+            me.bv.validate();
+            expect(me.bv.isValid()).toEqual(false);
+        });
+    });
+});