import xss from 'xss' ; import { RicardianContractRenderError } from '../../RicardianContractRenderError' ; import { VariableWrapper } from './VariableWrapper' ; import { EmptyElements , WhiteList } from './whitelist' ; export function indexTransaction ( entry ) { if ( Array . isArray ( entry ) ) { entry . forEach ( ( item , index ) : any => { item . $index = index ; indexTransaction ( item ) ; } ) ; return ; } for ( const [ , value ] of Object . entries ( entry ) ) { if ( Array . isArray ( value ) && value . length ) { indexTransaction ( value ) ; } } return entry ; } export function hasVariable ( text ) { const regex = RegExp ( '{{[{]?(.*?)[}]?}}' ) ; return regex . test ( text ) ; } export function tagTemplateVariables ( wrappedHelpers , template ) { const variableWrapper = new VariableWrapper ( wrappedHelpers , ( prefix , className , variable , suffix ) => { return `${ prefix }{{#wrap class="${ className }"}}${ variable }{{/wrap}}${ suffix }` ; } ) ; return variableWrapper . wrap ( template ) ; } export function tagMetadataVariables ( wrappedHelpers , metadata ) { const variableWrapper = new VariableWrapper ( wrappedHelpers , ( prefix , className , variable , suffix ) => { return `${ prefix }<div class="variable ${ className }">${ variable }</div>${ suffix }` ; } ) ; const processedMetadata = { } ; Object . keys ( metadata ) . forEach ( ( key ) => { if ( metadata [ key ] ) { processedMetadata [ key ] = variableWrapper . wrap ( metadata [ key ] ) ; } } ) ; return processedMetadata ; } export function extractSymbolCode ( text ) { const regex = RegExp ( '.+[^A-Za-z]([A-Za-z]+)$' ) ; const match = text . match ( regex ) ; if ( match ) { return match [ 1 ] ; } return '' ; } export function sanitizeHtml ( html ) { const tagStack = [ ] ; const whiteList = getWhiteList ( ) ; const sanitizer = new xss . FilterXSS ( { whiteList , onTag : ( tag , _1 , options ) : string | void => { return processTag ( tagStack , tag , options ) ; } , onIgnoreTag : ( tag , _1 , options ) => { throw new RicardianContractRenderError ( { tag , reason : `Disallowed tag "${ tag }" found at position ${ options . sourcePosition }` , } ) ; } , onIgnoreTagAttr : ( tag , name , _1 , _2 ) => { throw new RicardianContractRenderError ( { tag , reason : `Disallowed attribute "${ name }" found on tag "${ tag }"` , } ) ; } , } ) ; const sanitized = sanitizer . process ( html ) ; if ( tagStack . length !== 0 ) { const tag = tagStack . pop ( ) as string ; throw new RicardianContractRenderError ( { tag , reason : `Expected closing tag for "${ tag }" not found` , } ) ; } return sanitized ; } function processTag ( tagStack , tag , options ) { if ( ! options . isWhite ) { return ; } if ( options . isClosing ) { if ( EmptyElements . includes ( tag ) ) { throw new RicardianContractRenderError ( { tag , reason : `Unexpected closing tag for empty element "${ tag }"` , } ) ; } const openTag = tagStack . pop ( ) ; if ( openTag == null ) { throw new RicardianContractRenderError ( { tag , reason : `Unexpected closing tag "${ tag }" with no open tag` , } ) ; } else if ( tag !== openTag ) { throw new RicardianContractRenderError ( { tag , reason : `Unexpected closing tag "${ tag }"; expected closing tag for "${ openTag }"` , } ) ; } } else if ( ! EmptyElements . includes ( tag ) ) { tagStack . push ( tag ) ; } } function getWhiteList ( ) { const processedWL = { } ; Object . keys ( WhiteList ) . forEach ( ( tag ) => { if ( tag !== '_commonattrs_' ) { processedWL [ tag ] = [ ... WhiteList [ tag ] , ... WhiteList . _commonattrs_ ] ; } } ) ; return processedWL ; }