src/sanitizer.js
/**
 * Sanitizes the provided HTML.
 *
 * This function expects the HTML to be already pre-sanitized and thus it does
 * not validate all of the AMP rules - only the most dangerous security-related
 * cases, such as <SCRIPT>, <STYLE>, <IFRAME>.
 *
 * @param {string} html
 * @return {string}
 */
Sanitizes the provided HTML.
This function expects the HTML to be already pre-sanitized and thus it does
not validate all of the AMP rules - only the most dangerous security-related
cases, such as 

@param {string} html
@return {string}
Sanitizes the provided HTML . This function expects the HTML to be already pre - sanitized and thus it does not validate all of the AMP rules - only the most dangerous security - related cases such as @param { string } html @return { string }
function sanitizeHtml(html) {
  const tagPolicy = htmlSanitizer.makeTagPolicy();
  const output = [];
  let ignore = 0;
  function emit(content) {
    if (ignore == 0) {
      output.push(content);
    }
  }
  const parser = htmlSanitizer.makeSaxParser({
    'startTag': function(tagName, attribs) {
      if (ignore > 0) {
        if (!SELF_CLOSING_TAGS[tagName]) {
          ignore++;
        }
        return;
      }
      const bindAttribsIndices = map();
      for (let i = 0; i < attribs.length; i += 2) {
        const attr = attribs[i];
        if (attr && attr[0] == '[' && attr[attr.length - 1] == ']') {
          bindAttribsIndices[i] = true;
          attribs[i] = attr.slice(1, -1);
        }
      }
      if (BLACKLISTED_TAGS[tagName]) {
        ignore++;
      } else if (!startsWith(tagName, 'amp-')) {
        const savedAttribs = attribs.slice(0);
        const scrubbed = tagPolicy(tagName, attribs);
        if (!scrubbed) {
          ignore++;
        } else {
          attribs = scrubbed.attribs;
          for (let i = 0; i < attribs.length; i += 2) {
            const attrib = attribs[i];
            if (WHITELISTED_ATTRS.includes(attrib)) {
              attribs[i + 1] = savedAttribs[i + 1];
            } else if (attrib.search(WHITELISTED_ATTR_PREFIX_REGEX) == 0) {
              attribs[i + 1] = savedAttribs[i + 1];
            }
          }
        }
        if (tagName == 'a') {
          let index = -1;
          let hasHref = false;
          for (let i = 0; i < savedAttribs.length; i += 2) {
            if (savedAttribs[i] == 'target') {
              index = i + 1;
            } else if (savedAttribs[i] == 'href') {
              hasHref = attribs[i + 1] != null;
            }
          }
          let origTarget = index != -1 ? savedAttribs[index] : null;
          if (origTarget != null) {
            origTarget = origTarget.toLowerCase();
            if (WHITELISTED_TARGETS.indexOf(origTarget) != -1) {
              attribs[index] = origTarget;
            } else {
              attribs[index] = '_top';
            }
          } else if (hasHref) {
            attribs.push('target');
            attribs.push('_top');
          }
        }
      }
      if (ignore > 0) {
        if (SELF_CLOSING_TAGS[tagName]) {
          ignore--;
        }
        return;
      }
      emit('<');
      emit(tagName);
      for (let i = 0; i < attribs.length; i += 2) {
        const attrName = attribs[i];
        const attrValue = attribs[i + 1];
        if (!isValidAttr(tagName, attrName, attrValue)) {
          continue;
        }
        emit(' ');
        if (bindAttribsIndices[i]) {
          emit('[' + attrName + ']');
        } else {
          emit(attrName);
        }
        emit('="');
        if (attrValue) {
          emit(htmlSanitizer.escapeAttrib(rewriteAttributeValue(
              tagName, attrName, attrValue)));
        }
        emit('"');
      }
      emit('>');
    },
    'endTag': function(tagName) {
      if (ignore > 0) {
        ignore--;
        return;
      }
      emit('</');
      emit(tagName);
      emit('>');
    },
    'pcdata': emit,
    'rcdata': emit,
    'cdata': emit,
  });
  parser(html);
  return output.join('');
}
function sanitizeHtml ( html ) { const tagPolicy = htmlSanitizer . makeTagPolicy ( ) ; const output = [ ] ; let ignore = 0 ; function emit ( content ) { if ( ignore == 0 ) { output . push ( content ) ; } } const parser = htmlSanitizer . makeSaxParser ( { 'startTag' : function ( tagName , attribs ) { if ( ignore > 0 ) { if ( ! SELF_CLOSING_TAGS [ tagName ] ) { ignore ++ ; } return ; } const bindAttribsIndices = map ( ) ; for ( let i = 0 ; i < attribs . length ; i += 2 ) { const attr = attribs [ i ] ; if ( attr && attr [ 0 ] == '[' && attr [ attr . length - 1 ] == ']' ) { bindAttribsIndices [ i ] = true ; attribs [ i ] = attr . slice ( 1 , - 1 ) ; } } if ( BLACKLISTED_TAGS [ tagName ] ) { ignore ++ ; } else if ( ! startsWith ( tagName , 'amp-' ) ) { const savedAttribs = attribs . slice ( 0 ) ; const scrubbed = tagPolicy ( tagName , attribs ) ; if ( ! scrubbed ) { ignore ++ ; } else { attribs = scrubbed . attribs ; for ( let i = 0 ; i < attribs . length ; i += 2 ) { const attrib = attribs [ i ] ; if ( WHITELISTED_ATTRS . includes ( attrib ) ) { attribs [ i + 1 ] = savedAttribs [ i + 1 ] ; } else if ( attrib . search ( WHITELISTED_ATTR_PREFIX_REGEX ) == 0 ) { attribs [ i + 1 ] = savedAttribs [ i + 1 ] ; } } } if ( tagName == 'a' ) { let index = - 1 ; let hasHref = false ; for ( let i = 0 ; i < savedAttribs . length ; i += 2 ) { if ( savedAttribs [ i ] == 'target' ) { index = i + 1 ; } else if ( savedAttribs [ i ] == 'href' ) { hasHref = attribs [ i + 1 ] != null ; } } let origTarget = index != - 1 ? savedAttribs [ index ] : null ; if ( origTarget != null ) { origTarget = origTarget . toLowerCase ( ) ; if ( WHITELISTED_TARGETS . indexOf ( origTarget ) != - 1 ) { attribs [ index ] = origTarget ; } else { attribs [ index ] = '_top' ; } } else if ( hasHref ) { attribs . push ( 'target' ) ; attribs . push ( '_top' ) ; } } } if ( ignore > 0 ) { if ( SELF_CLOSING_TAGS [ tagName ] ) { ignore -- ; } return ; } emit ( '<' ) ; emit ( tagName ) ; for ( let i = 0 ; i < attribs . length ; i += 2 ) { const attrName = attribs [ i ] ; const attrValue = attribs [ i + 1 ] ; if ( ! isValidAttr ( tagName , attrName , attrValue ) ) { continue ; } emit ( ' ' ) ; if ( bindAttribsIndices [ i ] ) { emit ( '[' + attrName + ']' ) ; } else { emit ( attrName ) ; } emit ( '="' ) ; if ( attrValue ) { emit ( htmlSanitizer . escapeAttrib ( rewriteAttributeValue ( tagName , attrName , attrValue ) ) ) ; } emit ( '"' ) ; } emit ( '>' ) ; } , 'endTag' : function ( tagName ) { if ( ignore > 0 ) { ignore -- ; return ; } emit ( '</' ) ; emit ( tagName ) ; emit ( '>' ) ; } , 'pcdata' : emit , 'rcdata' : emit , 'cdata' : emit , } ) ; parser ( html ) ; return output . join ( '' ) ; }
Sanitizes the provided HTML.
Sanitizes the provided HTML .
// Special handling for attributes for amp-bind which are formatted as // [attr]. The brackets are restored at the end of this function. // Ask Caja to validate the element as well. // Use the resulting properties. // Restore some of the attributes that AMP is directly responsible // for, such as "on" // `<A>` has special target rules: // - Default target is "_top"; // - Allowed targets are "_blank", "_top"; // - All other targets are rewritted to "_top". // Only allow valid `href` values.