it('verify that encodeForHTMLAttribute escapes strings correctly', function(callback) {

        // Sanitize a string
        var stringToEscape = '\n\n\n<script>window.alert("hello world!");</script><p class="test"><span>Nice</span> link, would <a href="http://www.google.be" target="_blank"><a>click</a></b> again</p>';
        var stringEscaped = '&#xa;&#xa;&#xa;&lt;script&gt;window.alert&#x28;&quot;hello world&#x21;&quot;&#x29;&#x3b;&lt;&#x2f;script&gt;&lt;p class&#x3d;&quot;test&quot;&gt;&lt;span&gt;Nice&lt;&#x2f;span&gt; link, would &lt;a href&#x3d;&quot;http&#x3a;&#x2f;&#x2f;www.google.be&quot; target&#x3d;&quot;_blank&quot;&gt;&lt;a&gt;click&lt;&#x2f;a&gt;&lt;&#x2f;b&gt; again&lt;&#x2f;p&gt;';

        // Check if the returned value contains HTML entities instead of HTML tags
        assert.equal(Sanitization.encodeForHTMLAttribute(stringToEscape), stringEscaped);

        return callback();
    });
Example #2
0
const renderTemplate = function(template, data, locale) {
  data = data || {};
  data.util = data.util || {};
  locale = locale || 'en_US';

  // Pass in some utility functions
  _.extend(data.util, {
    html: {
      /*!
       * @see Sanitization.encodeForHTML
       */
      encodeForHTML(str) {
        return Sanitization.encodeForHTML(str);
      },

      /*!
       * @see Sanitization.encodeForHTMLAttribute
       */
      encodeForHTMLAttribute(str) {
        return Sanitization.encodeForHTMLAttribute(str);
      },

      /*!
       * Returns the text for a given HTML string. If desired, links can be formatted in plain-text.
       * e.g.,
       *     <p>The <a href="/fox">quick brown fox</a> jumped over the <a href="/moon">moon</a>.
       * becomes
       *     The quick brown fox (/fox) jumped over the moon (/moon)
       *
       * @param  {String}     str             The HTML string to parse and extra text from
       * @param  {Boolean}    retainLinks     Set to `true` to convert links to a plain-text link.
       * @return {String}                     The extracted text
       */
      toText(str, retainLinks) {
        const html = $('<div>' + str + '</div>');
        if (retainLinks) {
          html.find('a').replaceWith(function() {
            const href = $(this).attr('href');
            const text = $(this).text();
            if (text && href && href !== '#') {
              return util.format('%s (%s)', text, href);
            }

            return $(this);
          });
        }

        // We need to wrap the string in a `div` element as plain-text would otherwise be lost
        return html.text();
      }
    },
    text: {
      /*!
       * Standard string trimming + strips out HTML comments
       *
       * @param  {String}     str     The string to trim
       * @return {String}             The trimmed string
       */
      trim(str) {
        str = str.replace(/<!--(?:.|\n)*?-->/gm, '');
        str = str.trim();
        return str;
      },

      /*!
       * Truncate a string and append three dots if the length of the string is longer
       * than `maxChars`. Before truncating, the string will be trimmed. If the given
       * string is not longer than `maxChars` characters, the string is returned as-is.
       *
       * @param  {String}     text        The text to truncate
       * @param  {Number}     maxChars    The maximum length of the string before cutting it off and appending three dots
       * @return {String}                 The truncated string
       */
      truncate(text, maxChars) {
        text = data.util.text.trim(text);
        if (text.length > maxChars) {
          text = text.substring(0, maxChars) + '...';
        }

        return text;
      },

      /*!
       * Given plain text content, convert it to an appropriate HTML string. Particularly:
       *
       *  * Escape all HTML characters so the content shows as it is in plain text; and
       *  * Convert all line-breaks to <br/> so that line breaks in the content are preserved
       *
       * @param  {String}     content     The plain-text content to convert to HTML
       * @return {String}                 The HTML version of the content
       */
      toHtml(str) {
        // First escape HTML
        const sanitized = Sanitization.encodeForHTML(str);

        // Honour the new-line characters in the plain text by converting to <br />
        return sanitized.replace(/&#xa;/g, '<br/>');
      },

      /**
       * Get a human readable mimeType description for a content item. Unrecognized mimeTypes
       * will default to the `other` type.
       *
       * @param  {String}     resourceSubType     The resource sub type for which to generate an appropriate description
       * @param  {String}     [mimeType]          In case the `resourceSubType` is a `file` a more detailed description can be returned by providing a mime type
       * @return {String}                         Human readable mimetype description for the provided resource subtype and mime type
       */
      getMimetypeDescription(resourceSubType, mimeType) {
        const descriptor = _getMimeTypeDescriptor();
        return descriptor.getDescription(resourceSubType, mimeType);
      }
    },

    markdown: {
      /*!
       * Convert markdown input into an HTML string
       *
       * @param  {String}     str         The markdown input to convert to HTML
       * @return {String}                 The converted HTML
       */
      toHtml(str) {
        return marked(str, {
          gfm: true,
          breaks: true,
          sanitize: true
        });
      }
    },

    json: {
      /*!
       * Makes a string safe to embed in a json value
       *
       * @param  {String}     str     The string to place in a json value
       * @return {String}             The safe string
       */
      escape(str) {
        if (!_.isString(str)) {
          return '';
        }

        return JSON.stringify(str).slice(1, -1);
      }
    },

    i18n: {
      /*!
       * Translates a key
       *
       * @param  {String}     key             The i18n key to translate
       * @param  {Object}     [properties]    A set of properties that can be used to translate the key
       * @return {String}                     The translated key
       */
      translate(key, properties) {
        return translate(key, locale, properties);
      },

      /*!
       * Format a date
       *
       * @param  {Date}       date            The date to format
       * @param  {String}     dateFormat      The format in which the date should be formatted. See https://github.com/jquery/globalize/tree/v0.1.1#dates
       * @param  {String}     [timezone]      The timezone the date should be presented in. Defaults to UTC
       * @return {String}                     The formatted date
       */
      formatDate(date, dateFormat, timezone) {
        timezone = timezone || 'UTC';
        // Gloablize requires the locale to use a `-` rather than a `_`
        const globalizeLocale = locale.replace('_', '-');

        // Globalize can't handle our TZ dates, so we'll make a regular Date object that will look like it's from the tenant timezone when serialized in UTC
        const kludgeDate = new TZ.timezone.Date(date.valueOf(), timezone);
        kludgeDate.setMinutes(kludgeDate.getMinutes() + kludgeDate.getTimezoneOffset() * 2);

        // Return a properly formatted date
        const formatted = Globalize.format(kludgeDate, dateFormat, globalizeLocale);
        return formatted.toString();
      }
    },

    ui: {
      /*!
       * Get the optimized path in the UI for a pre-optimized path
       *
       * @param  {String}     path    The pre-optimized path to resolve
       * @return {String}             The optimized path. In case no optimized path could be found, the given path is returned
       */
      getHashedPath
    },

    url: {
      /*!
       * Take a URL string, and return an object.
       *
       * @see http://nodejs.org/docs/latest/api/url.html#url_url_parse_urlstr_parsequerystring_slashesdenotehost
       */
      parse: url.parse,

      /**
       * Escape all characters except the following: alphabetic, decimal digits, - _ . ! ~ * ' ( )
       *
       * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
       */
      encode: encodeURIComponent,

      /**
       * Ensure that a link is an absolute URL. If a relative link is
       * passed in, it will be prefixed with the base url.
       *
       * @param  {String}     link        The link to check
       * @param  {String}     baseUrl     The base url that can be used to prefix relative urls
       * @return {String}                 The absolute link prefixed with the base url
       */
      ensureAbsoluteLink(link, baseUrl) {
        // If the link is empty or null, we return the empty string. This can happen when
        // we try to link a private user (private users are scrubbed and have no profile path)
        if (!link) {
          return '';

          // If the link already has `http` in it (e.g., twitter profile pics) we return as-is
        }

        if (link.indexOf('http') === 0) {
          return link;

          // Otherwise we prefix it with the base url
        }

        return baseUrl + link;
      },

      /**
       * Ensure that each link in an HTML fragment is an abolute url, If a relative link is
       * found, it will be prefixed with the base url.
       *
       * @param  {String}     str         The html string in which to check for absolute links
       * @param  {String}     baseUrl     The base url that can be used to prefix relative urls
       * @return {String}                 The html in which each link is absolute
       */
      ensureAbsoluteLinks(str, baseUrl) {
        const html = $('<div>' + str + '</div>');
        // eslint-disable-next-line no-unused-vars
        html.find('a').each(function(i, elem) {
          let link = $(this).attr('href');
          link = data.util.url.ensureAbsoluteLink(link, baseUrl);
          $(this).attr('href', link);
        });
        return html.html();
      }
    }
  });

  // Parse and process it with Underscore
  try {
    let compiledTemplate = null;
    if (_.isString(template)) {
      compiledTemplate = compileTemplate(template);
    } else if (_.isFunction(template)) {
      compiledTemplate = template;
    } else {
      log().error('A malformed template was passed in');
      return '';
    }

    // Render the template
    let renderedTemplate = compiledTemplate(data);

    // Remove HTML comments
    renderedTemplate = renderedTemplate.replace(/<!--(?:.|\n)*?-->/gm, '');

    // Translate the template
    const translatedTemplate = translate(renderedTemplate, locale);

    // Trim useless spaces
    return translatedTemplate.trim();
  } catch (error) {
    log().error({ err: error }, 'Unable to render template');
    return '';
  }
};
Example #3
0
 'encodeForHTMLAttribute': function(str) {
     return Sanitization.encodeForHTMLAttribute(str);
 },