Skip to content

Commit

Permalink
[ESD-13941] Implement a DOMPurify hook to enable target attributes on…
Browse files Browse the repository at this point in the history
… links (#2006)

* Implement a DOMPurify hook to enable target='_blank'

* Add test for target attribute sanitization
  • Loading branch information
Steve Hobbs authored Jun 11, 2021
1 parent f8455df commit aee1e60
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/__tests__/i18n.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import esDictionary from '../i18n/es';

import * as sync from '../sync';
import * as l from '../core/index';
import { initSanitizer } from '../sanitizer';

describe('i18n', () => {
let syncSpy;
Expand Down Expand Up @@ -61,5 +62,22 @@ describe('i18n', () => {
expect(html.props.dangerouslySetInnerHTML.__html).not.toMatch(/javascript:alert/);
expect(html.props.dangerouslySetInnerHTML.__html).toEqual('<img href="1" src="1">');
});

it('should allow target=_blank with noopener noreferrer attributes', () => {
initSanitizer();

const i18n = require('../i18n');

const strings = {
test: '<a href="#" target="_blank">link</a>'
};

const m = Immutable.fromJS({ i18n: { strings } });
const html = i18n.html(m, 'test');

expect(html.props.dangerouslySetInnerHTML.__html).toEqual(
'<a href="#" target="_blank" rel="noopener noreferrer">link</a>'
);
});
});
});
5 changes: 5 additions & 0 deletions src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { EventEmitter } from 'events';
import { getEntity, observe, read } from './store/index';
import { remove, render } from './ui/box';
import webAPI from './core/web_api';
import { initSanitizer } from './sanitizer';

import {
closeLock,
resumeAuth,
Expand Down Expand Up @@ -62,10 +64,13 @@ export default class Base extends EventEmitter {

this.id = idu.incremental();
this.engine = engine;

const hookRunner = ::this.runHook;
const emitEventFn = this.emit.bind(this);
const handleEventFn = this.on.bind(this);

go(this.id);
initSanitizer();

let m = setupLock(this.id, clientID, domain, options, hookRunner, emitEventFn, handleEventFn);

Expand Down
22 changes: 22 additions & 0 deletions src/sanitizer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { addHook } from 'dompurify';

export function initSanitizer() {
// Extracted from the example at
// https://github.com/cure53/DOMPurify/blob/main/demos/hooks-target-blank-demo.html
addHook('afterSanitizeAttributes', function(node) {
// set all elements owning target to target=_blank
if ('target' in node) {
node.setAttribute('target', '_blank');
// prevent https://www.owasp.org/index.php/Reverse_Tabnabbing
node.setAttribute('rel', 'noopener noreferrer');
}

// set non-HTML/MathML links to xlink:show=new
if (
!node.hasAttribute('target') &&
(node.hasAttribute('xlink:href') || node.hasAttribute('href'))
) {
node.setAttribute('xlink:show', 'new');
}
});
}

0 comments on commit aee1e60

Please sign in to comment.