'use strict';

describe('sanitizeUri', function() {
  var sanitizeHref, sanitizeImg, sanitizeUriProvider, testUrl;
  beforeEach(function() {
    module(function(_$$sanitizeUriProvider_) {
      sanitizeUriProvider = _$$sanitizeUriProvider_;
    });
    inject(function($$sanitizeUri) {
      sanitizeHref = function(uri) {
        return $$sanitizeUri(uri, false);
      };
      sanitizeImg = function(uri) {
        return $$sanitizeUri(uri, true);
      }
    });
  });

  function isEvilInCurrentBrowser(uri) {
    var a = document.createElement('a');
    a.setAttribute('href', uri);
    return a.href.substring(0, 4) !== 'http';
  }

  describe('img[src] sanitization', function() {

    it('should sanitize javascript: urls', function() {
      testUrl = "javascript:doEvilStuff()";
      expect(sanitizeImg(testUrl)).toBe('unsafe:javascript:doEvilStuff()');
    });

    it('should sanitize non-image data: urls', function() {
      testUrl = "data:application/javascript;charset=US-ASCII,alert('evil!');";
      expect(sanitizeImg(testUrl)).toBe("unsafe:data:application/javascript;charset=US-ASCII,alert('evil!');");

      testUrl = "data:,foo";
      expect(sanitizeImg(testUrl)).toBe("unsafe:data:,foo");
    });

    it('should not sanitize data: URIs for images', function() {
      // image data uri
      // ref: http://probablyprogramming.com/2009/03/15/the-tiniest-gif-ever
      testUrl = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
      expect(sanitizeImg(testUrl)).toBe('data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==');
    });

    it('should sanitize mailto: urls', function() {
      testUrl = "mailto:foo@bar.com";
      expect(sanitizeImg(testUrl)).toBe('unsafe:mailto:foo@bar.com');
    });

    it('should sanitize obfuscated javascript: urls', function() {
      // case-sensitive
      testUrl = "JaVaScRiPt:doEvilStuff()";
      expect(sanitizeImg(testUrl)).toBe('unsafe:javascript:doEvilStuff()');

      // tab in protocol
      testUrl = "java\u0009script:doEvilStuff()";
      if (isEvilInCurrentBrowser(testUrl)) {
        expect(sanitizeImg(testUrl)).toEqual('unsafe:javascript:doEvilStuff()');
      }

      // space before
      testUrl = " javascript:doEvilStuff()";
      expect(sanitizeImg(testUrl)).toBe('unsafe:javascript:doEvilStuff()');

      // ws chars before
      testUrl = " \u000e javascript:doEvilStuff()";
      if (isEvilInCurrentBrowser(testUrl)) {
        expect(sanitizeImg(testUrl)).toEqual('unsafe:javascript:doEvilStuff()');
      }

      // post-fixed with proper url
      testUrl = "javascript:doEvilStuff(); http://make.me/look/good";
      expect(sanitizeImg(testUrl)).toBeOneOf(
        'unsafe:javascript:doEvilStuff(); http://make.me/look/good',
        'unsafe:javascript:doEvilStuff();%20http://make.me/look/good'
      );
    });

    it('should sanitize ng-src bindings as well', function() {
      testUrl = "javascript:doEvilStuff()";
      expect(sanitizeImg(testUrl)).toBe('unsafe:javascript:doEvilStuff()');
    });


    it('should not sanitize valid urls', function() {
      testUrl = "foo/bar";
      expect(sanitizeImg(testUrl)).toBe('foo/bar');

      testUrl = "/foo/bar";
      expect(sanitizeImg(testUrl)).toBe('/foo/bar');

      testUrl = "../foo/bar";
      expect(sanitizeImg(testUrl)).toBe('../foo/bar');

      testUrl = "#foo";
      expect(sanitizeImg(testUrl)).toBe('#foo');

      testUrl = "http://foo.com/bar";
      expect(sanitizeImg(testUrl)).toBe('http://foo.com/bar');

      testUrl = " http://foo.com/bar";
      expect(sanitizeImg(testUrl)).toBe(' http://foo.com/bar');

      testUrl = "https://foo.com/bar";
      expect(sanitizeImg(testUrl)).toBe('https://foo.com/bar');

      testUrl = "ftp://foo.com/bar";
      expect(sanitizeImg(testUrl)).toBe('ftp://foo.com/bar');

      testUrl = "file:///foo/bar.html";
      expect(sanitizeImg(testUrl)).toBe('file:///foo/bar.html');
    });


    it('should allow reconfiguration of the src whitelist', function() {
      var returnVal;
      expect(sanitizeUriProvider.imgSrcSanitizationWhitelist() instanceof RegExp).toBe(true);
      returnVal = sanitizeUriProvider.imgSrcSanitizationWhitelist(/javascript:/);
      expect(returnVal).toBe(sanitizeUriProvider);

      testUrl = "javascript:doEvilStuff()";
      expect(sanitizeImg(testUrl)).toBe('javascript:doEvilStuff()');

      testUrl = "http://recon/figured";
      expect(sanitizeImg(testUrl)).toBe('unsafe:http://recon/figured');
    });

  });


  describe('a[href] sanitization', function() {

    it('should sanitize javascript: urls', inject(function() {
      testUrl = "javascript:doEvilStuff()";
      expect(sanitizeHref(testUrl)).toBe('unsafe:javascript:doEvilStuff()');
    }));


    it('should sanitize data: urls', inject(function() {
      testUrl = "data:evilPayload";
      expect(sanitizeHref(testUrl)).toBe('unsafe:data:evilPayload');
    }));


    it('should sanitize obfuscated javascript: urls', inject(function() {
      // case-sensitive
      testUrl = "JaVaScRiPt:doEvilStuff()";
      expect(sanitizeHref(testUrl)).toBe('unsafe:javascript:doEvilStuff()');

      // tab in protocol
      testUrl = "java\u0009script:doEvilStuff()";
      if (isEvilInCurrentBrowser(testUrl)) {
        expect(sanitizeHref(testUrl)).toEqual('unsafe:javascript:doEvilStuff()');
      }

      // space before
      testUrl = " javascript:doEvilStuff()";
      expect(sanitizeHref(testUrl)).toBe('unsafe:javascript:doEvilStuff()');

      // ws chars before
      testUrl = " \u000e javascript:doEvilStuff()";
      if (isEvilInCurrentBrowser(testUrl)) {
        expect(sanitizeHref(testUrl)).toEqual('unsafe:javascript:doEvilStuff()');
      }

      // post-fixed with proper url
      testUrl = "javascript:doEvilStuff(); http://make.me/look/good";
      expect(sanitizeHref(testUrl)).toBeOneOf(
        'unsafe:javascript:doEvilStuff(); http://make.me/look/good',
        'unsafe:javascript:doEvilStuff();%20http://make.me/look/good'
      );
    }));


    it('should sanitize ngHref bindings as well', inject(function() {
      testUrl = "javascript:doEvilStuff()";
      expect(sanitizeHref(testUrl)).toBe('unsafe:javascript:doEvilStuff()');
    }));


    it('should not sanitize valid urls', inject(function() {
      testUrl = "foo/bar";
      expect(sanitizeHref(testUrl)).toBe('foo/bar');

      testUrl = "/foo/bar";
      expect(sanitizeHref(testUrl)).toBe('/foo/bar');

      testUrl = "../foo/bar";
      expect(sanitizeHref(testUrl)).toBe('../foo/bar');

      testUrl = "#foo";
      expect(sanitizeHref(testUrl)).toBe('#foo');

      testUrl = "http://foo/bar";
      expect(sanitizeHref(testUrl)).toBe('http://foo/bar');

      testUrl = " http://foo/bar";
      expect(sanitizeHref(testUrl)).toBe(' http://foo/bar');

      testUrl = "https://foo/bar";
      expect(sanitizeHref(testUrl)).toBe('https://foo/bar');

      testUrl = "ftp://foo/bar";
      expect(sanitizeHref(testUrl)).toBe('ftp://foo/bar');

      testUrl = "mailto:foo@bar.com";
      expect(sanitizeHref(testUrl)).toBe('mailto:foo@bar.com');

      testUrl = "file:///foo/bar.html";
      expect(sanitizeHref(testUrl)).toBe('file:///foo/bar.html');
    }));

    it('should allow reconfiguration of the href whitelist', function() {
      var returnVal;
      expect(sanitizeUriProvider.aHrefSanitizationWhitelist() instanceof RegExp).toBe(true);
      returnVal = sanitizeUriProvider.aHrefSanitizationWhitelist(/javascript:/);
      expect(returnVal).toBe(sanitizeUriProvider);

      testUrl = "javascript:doEvilStuff()";
        expect(sanitizeHref(testUrl)).toBe('javascript:doEvilStuff()');

      testUrl = "http://recon/figured";
        expect(sanitizeHref(testUrl)).toBe('unsafe:http://recon/figured');
    });

  });

});