UNPKG

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
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=