react-safe-src-doc-iframe
Version:
A component which applies guards to srcdoc iframes, providing a predictable and safe experience to the user.
120 lines (96 loc) • 11.4 kB
JavaScript
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
import React, { Component } from 'react';
import PropTypes from 'prop-types';
var disableStylesRaw = '\n *[href], button, img {\n pointer-events: none !important;\n display: inline-block !important;\n }\n';
var SafesrcDocIframe = function (_Component) {
_inherits(SafesrcDocIframe, _Component);
function SafesrcDocIframe() {
var _ref;
_classCallCheck(this, SafesrcDocIframe);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
var _this = _possibleConstructorReturn(this, (_ref = SafesrcDocIframe.__proto__ || Object.getPrototypeOf(SafesrcDocIframe)).call.apply(_ref, [this].concat(args)));
_this.iframeElement = null;
_this.disableStyleTag = document.createElement('style');
_this.disableStylesTextNode = document.createTextNode(disableStylesRaw);
_this.disableStyleTag.appendChild(_this.disableStylesTextNode);
return _this;
}
_createClass(SafesrcDocIframe, [{
key: 'componentDidMount',
value: function componentDidMount() {
var _this2 = this;
if (this.iframeElement) {
this.iframeElement.onload = function () {
_this2.applySafeguards();
};
}
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
this.disableStylesTextNode = null;
this.disableStyleTag = null;
}
}, {
key: 'applySafeguards',
value: function applySafeguards() {
if (!this.iframeElement.contentDocument) {
return;
}
var _iframeElement$conten = this.iframeElement.contentDocument.getElementsByTagName('body'),
_iframeElement$conten2 = _slicedToArray(_iframeElement$conten, 1),
iframeBody = _iframeElement$conten2[0];
if (iframeBody) {
// add safety guards last to ensure they are always applied.
iframeBody.appendChild(this.disableStyleTag);
}
}
}, {
key: 'render',
value: function render() {
var _this3 = this;
var _props = this.props,
title = _props.title,
referrerPolicy = _props.referrerPolicy,
sandbox = _props.sandbox,
srcDoc = _props.srcDoc,
omit = _props.src,
rest = _objectWithoutProperties(_props, ['title', 'referrerPolicy', 'sandbox', 'srcDoc', 'src']);
return React.createElement('iframe', _extends({
title: title,
srcDoc: srcDoc,
referrerPolicy: referrerPolicy,
sandbox: sandbox,
ref: function ref(el) {
_this3.iframeElement = el;
}
}, rest));
}
}]);
return SafesrcDocIframe;
}(Component);
SafesrcDocIframe.propTypes = {
title: PropTypes.string.isRequired,
srcDoc: PropTypes.string.isRequired,
sandbox: PropTypes.string,
referrerPolicy: PropTypes.string,
src: PropTypes.string
};
SafesrcDocIframe.defaultProps = {
// set all restrictions for sandbox except same origin
// to allow us to inject the safe guards.
sandbox: 'allow-same-origin',
referrerPolicy: 'no-referrer',
// will be omitted from props passed to the iframe
src: ''
};
export default SafesrcDocIframe;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9zYWZlLXNyYy1kb2MtaWZyYW1lLmpzIl0sIm5hbWVzIjpbIlJlYWN0IiwiQ29tcG9uZW50IiwiUHJvcFR5cGVzIiwiZGlzYWJsZVN0eWxlc1JhdyIsIlNhZmVzcmNEb2NJZnJhbWUiLCJhcmdzIiwiaWZyYW1lRWxlbWVudCIsImRpc2FibGVTdHlsZVRhZyIsImRvY3VtZW50IiwiY3JlYXRlRWxlbWVudCIsImRpc2FibGVTdHlsZXNUZXh0Tm9kZSIsImNyZWF0ZVRleHROb2RlIiwiYXBwZW5kQ2hpbGQiLCJvbmxvYWQiLCJhcHBseVNhZmVndWFyZHMiLCJjb250ZW50RG9jdW1lbnQiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsImlmcmFtZUJvZHkiLCJwcm9wcyIsInRpdGxlIiwicmVmZXJyZXJQb2xpY3kiLCJzYW5kYm94Iiwic3JjRG9jIiwib21pdCIsInNyYyIsInJlc3QiLCJlbCIsInByb3BUeXBlcyIsInN0cmluZyIsImlzUmVxdWlyZWQiLCJkZWZhdWx0UHJvcHMiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7O0FBQUEsT0FBT0EsS0FBUCxJQUFnQkMsU0FBaEIsUUFBaUMsT0FBakM7QUFDQSxPQUFPQyxTQUFQLE1BQXNCLFlBQXRCOztBQUVBLElBQU1DLG1JQUFOOztJQU9NQyxnQjs7O0FBbUJKLDhCQUFxQjtBQUFBOztBQUFBOztBQUFBLHNDQUFOQyxJQUFNO0FBQU5BLFVBQU07QUFBQTs7QUFBQSwrSkFDVkEsSUFEVTs7QUFFbkIsVUFBS0MsYUFBTCxHQUFxQixJQUFyQjtBQUNBLFVBQUtDLGVBQUwsR0FBdUJDLFNBQVNDLGFBQVQsQ0FBdUIsT0FBdkIsQ0FBdkI7QUFDQSxVQUFLQyxxQkFBTCxHQUE2QkYsU0FBU0csY0FBVCxDQUF3QlIsZ0JBQXhCLENBQTdCO0FBQ0EsVUFBS0ksZUFBTCxDQUFxQkssV0FBckIsQ0FBaUMsTUFBS0YscUJBQXRDO0FBTG1CO0FBTXBCOzs7O3dDQUVtQjtBQUFBOztBQUNsQixVQUFJLEtBQUtKLGFBQVQsRUFBd0I7QUFDdEIsYUFBS0EsYUFBTCxDQUFtQk8sTUFBbkIsR0FBNEIsWUFBTTtBQUNoQyxpQkFBS0MsZUFBTDtBQUNELFNBRkQ7QUFHRDtBQUNGOzs7MkNBRXNCO0FBQ3JCLFdBQUtKLHFCQUFMLEdBQTZCLElBQTdCO0FBQ0EsV0FBS0gsZUFBTCxHQUF1QixJQUF2QjtBQUNEOzs7c0NBRWlCO0FBQ2hCLFVBQUksQ0FBQyxLQUFLRCxhQUFMLENBQW1CUyxlQUF4QixFQUF5QztBQUN2QztBQUNEOztBQUhlLGtDQU1aLEtBQUtULGFBQUwsQ0FBbUJTLGVBQW5CLENBQW1DQyxvQkFBbkMsQ0FBd0QsTUFBeEQsQ0FOWTtBQUFBO0FBQUEsVUFLZEMsVUFMYzs7QUFPaEIsVUFBSUEsVUFBSixFQUFnQjtBQUNkO0FBQ0FBLG1CQUFXTCxXQUFYLENBQXVCLEtBQUtMLGVBQTVCO0FBQ0Q7QUFDRjs7OzZCQUVRO0FBQUE7O0FBQUEsbUJBUUgsS0FBS1csS0FSRjtBQUFBLFVBRUxDLEtBRkssVUFFTEEsS0FGSztBQUFBLFVBR0xDLGNBSEssVUFHTEEsY0FISztBQUFBLFVBSUxDLE9BSkssVUFJTEEsT0FKSztBQUFBLFVBS0xDLE1BTEssVUFLTEEsTUFMSztBQUFBLFVBTUFDLElBTkEsVUFNTEMsR0FOSztBQUFBLFVBT0ZDLElBUEU7O0FBU1AsYUFDRTtBQUNFLGVBQVFOLEtBRFY7QUFFRSxnQkFBU0csTUFGWDtBQUdFLHdCQUFpQkYsY0FIbkI7QUFJRSxpQkFBVUMsT0FKWjtBQUtFLGFBQU0saUJBQU07QUFDVixpQkFBS2YsYUFBTCxHQUFxQm9CLEVBQXJCO0FBQ0Q7QUFQSCxTQVFPRCxJQVJQLEVBREY7QUFZRDs7OztFQTFFNEJ4QixTOztBQUF6QkcsZ0IsQ0FFR3VCLFMsR0FBWTtBQUNqQlIsU0FBT2pCLFVBQVUwQixNQUFWLENBQWlCQyxVQURQO0FBRWpCUCxVQUFRcEIsVUFBVTBCLE1BQVYsQ0FBaUJDLFVBRlI7QUFHakJSLFdBQVNuQixVQUFVMEIsTUFIRjtBQUlqQlIsa0JBQWdCbEIsVUFBVTBCLE1BSlQ7QUFLakJKLE9BQUt0QixVQUFVMEI7QUFMRSxDO0FBRmZ4QixnQixDQVVHMEIsWSxHQUFlO0FBQ3BCO0FBQ0E7QUFDQVQsV0FBUyxtQkFIVztBQUlwQkQsa0JBQWdCLGFBSkk7QUFLcEI7QUFDQUksT0FBSztBQU5lLEM7OztBQW1FeEIsZUFBZXBCLGdCQUFmIiwiZmlsZSI6InNhZmUtc3JjLWRvYy1pZnJhbWUuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QsIHsgQ29tcG9uZW50IH0gZnJvbSAncmVhY3QnO1xuaW1wb3J0IFByb3BUeXBlcyBmcm9tICdwcm9wLXR5cGVzJztcblxuY29uc3QgZGlzYWJsZVN0eWxlc1JhdyA9IGBcbiAgKltocmVmXSwgYnV0dG9uLCBpbWcge1xuICAgIHBvaW50ZXItZXZlbnRzOiBub25lICFpbXBvcnRhbnQ7XG4gICAgZGlzcGxheTogaW5saW5lLWJsb2NrICFpbXBvcnRhbnQ7XG4gIH1cbmA7XG5cbmNsYXNzIFNhZmVzcmNEb2NJZnJhbWUgZXh0ZW5kcyBDb21wb25lbnQge1xuXG4gIHN0YXRpYyBwcm9wVHlwZXMgPSB7XG4gICAgdGl0bGU6IFByb3BUeXBlcy5zdHJpbmcuaXNSZXF1aXJlZCxcbiAgICBzcmNEb2M6IFByb3BUeXBlcy5zdHJpbmcuaXNSZXF1aXJlZCxcbiAgICBzYW5kYm94OiBQcm9wVHlwZXMuc3RyaW5nLFxuICAgIHJlZmVycmVyUG9saWN5OiBQcm9wVHlwZXMuc3RyaW5nLFxuICAgIHNyYzogUHJvcFR5cGVzLnN0cmluZ1xuICB9O1xuXG4gIHN0YXRpYyBkZWZhdWx0UHJvcHMgPSB7XG4gICAgLy8gc2V0IGFsbCByZXN0cmljdGlvbnMgZm9yIHNhbmRib3ggZXhjZXB0IHNhbWUgb3JpZ2luXG4gICAgLy8gdG8gYWxsb3cgdXMgdG8gaW5qZWN0IHRoZSBzYWZlIGd1YXJkcy5cbiAgICBzYW5kYm94OiAnYWxsb3ctc2FtZS1vcmlnaW4nLFxuICAgIHJlZmVycmVyUG9saWN5OiAnbm8tcmVmZXJyZXInLFxuICAgIC8vIHdpbGwgYmUgb21pdHRlZCBmcm9tIHByb3BzIHBhc3NlZCB0byB0aGUgaWZyYW1lXG4gICAgc3JjOiAnJ1xuICB9O1xuXG4gIGNvbnN0cnVjdG9yKC4uLmFyZ3MpIHtcbiAgICBzdXBlciguLi5hcmdzKTtcbiAgICB0aGlzLmlmcmFtZUVsZW1lbnQgPSBudWxsO1xuICAgIHRoaXMuZGlzYWJsZVN0eWxlVGFnID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3R5bGUnKTtcbiAgICB0aGlzLmRpc2FibGVTdHlsZXNUZXh0Tm9kZSA9IGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKGRpc2FibGVTdHlsZXNSYXcpO1xuICAgIHRoaXMuZGlzYWJsZVN0eWxlVGFnLmFwcGVuZENoaWxkKHRoaXMuZGlzYWJsZVN0eWxlc1RleHROb2RlKTtcbiAgfVxuXG4gIGNvbXBvbmVudERpZE1vdW50KCkge1xuICAgIGlmICh0aGlzLmlmcmFtZUVsZW1lbnQpIHtcbiAgICAgIHRoaXMuaWZyYW1lRWxlbWVudC5vbmxvYWQgPSAoKSA9PiB7XG4gICAgICAgIHRoaXMuYXBwbHlTYWZlZ3VhcmRzKCk7XG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgIHRoaXMuZGlzYWJsZVN0eWxlc1RleHROb2RlID0gbnVsbDtcbiAgICB0aGlzLmRpc2FibGVTdHlsZVRhZyA9IG51bGw7XG4gIH1cblxuICBhcHBseVNhZmVndWFyZHMoKSB7XG4gICAgaWYgKCF0aGlzLmlmcmFtZUVsZW1lbnQuY29udGVudERvY3VtZW50KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IFtcbiAgICAgIGlmcmFtZUJvZHlcbiAgICBdID0gdGhpcy5pZnJhbWVFbGVtZW50LmNvbnRlbnREb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnYm9keScpO1xuICAgIGlmIChpZnJhbWVCb2R5KSB7XG4gICAgICAvLyBhZGQgc2FmZXR5IGd1YXJkcyBsYXN0IHRvIGVuc3VyZSB0aGV5IGFyZSBhbHdheXMgYXBwbGllZC5cbiAgICAgIGlmcmFtZUJvZHkuYXBwZW5kQ2hpbGQodGhpcy5kaXNhYmxlU3R5bGVUYWcpO1xuICAgIH1cbiAgfVxuXG4gIHJlbmRlcigpIHtcbiAgICBjb25zdCB7XG4gICAgICB0aXRsZSxcbiAgICAgIHJlZmVycmVyUG9saWN5LFxuICAgICAgc2FuZGJveCxcbiAgICAgIHNyY0RvYyxcbiAgICAgIHNyYzogb21pdCwgLyogZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFycyAqL1xuICAgICAgLi4ucmVzdFxuICAgIH0gPSB0aGlzLnByb3BzO1xuICAgIHJldHVybiAoXG4gICAgICA8aWZyYW1lXG4gICAgICAgIHRpdGxlPXsgdGl0bGUgfVxuICAgICAgICBzcmNEb2M9eyBzcmNEb2MgfVxuICAgICAgICByZWZlcnJlclBvbGljeT17IHJlZmVycmVyUG9saWN5IH1cbiAgICAgICAgc2FuZGJveD17IHNhbmRib3ggfVxuICAgICAgICByZWY9eyBlbCA9PiB7XG4gICAgICAgICAgdGhpcy5pZnJhbWVFbGVtZW50ID0gZWw7XG4gICAgICAgIH0gfVxuICAgICAgICB7IC4uLnJlc3QgfVxuICAgICAgLz5cbiAgICApO1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFNhZmVzcmNEb2NJZnJhbWU7XG4iXX0=