@hcaptcha/react-hcaptcha
Version: 
A React library for hCaptcha
409 lines (398 loc) • 15.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof3 = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports["default"] = void 0;
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var React = _interopRequireWildcard(require("react"));
var _loader = require("@hcaptcha/loader");
var _utils = require("./utils.js");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof3(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; }
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2["default"])(o), (0, _possibleConstructorReturn2["default"])(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2["default"])(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
var HCaptcha = /*#__PURE__*/function (_React$Component) {
  (0, _inherits2["default"])(HCaptcha, _React$Component);
  function HCaptcha(props) {
    var _this;
    (0, _classCallCheck2["default"])(this, HCaptcha);
    _this = _callSuper(this, HCaptcha, [props]);
    /**
     * Internal reference to track hCaptcha API
     *
     * Required as window is relative to initialization in application
     * not where the script and iFrames have been loaded.
     */
    _this._hcaptcha = undefined;
    // API Methods
    _this.renderCaptcha = _this.renderCaptcha.bind((0, _assertThisInitialized2["default"])(_this));
    _this.resetCaptcha = _this.resetCaptcha.bind((0, _assertThisInitialized2["default"])(_this));
    _this.removeCaptcha = _this.removeCaptcha.bind((0, _assertThisInitialized2["default"])(_this));
    _this.isReady = _this.isReady.bind((0, _assertThisInitialized2["default"])(_this));
    _this._onReady = null;
    // Event Handlers
    _this.loadCaptcha = _this.loadCaptcha.bind((0, _assertThisInitialized2["default"])(_this));
    _this.handleOnLoad = _this.handleOnLoad.bind((0, _assertThisInitialized2["default"])(_this));
    _this.handleSubmit = _this.handleSubmit.bind((0, _assertThisInitialized2["default"])(_this));
    _this.handleExpire = _this.handleExpire.bind((0, _assertThisInitialized2["default"])(_this));
    _this.handleError = _this.handleError.bind((0, _assertThisInitialized2["default"])(_this));
    _this.handleOpen = _this.handleOpen.bind((0, _assertThisInitialized2["default"])(_this));
    _this.handleClose = _this.handleClose.bind((0, _assertThisInitialized2["default"])(_this));
    _this.handleChallengeExpired = _this.handleChallengeExpired.bind((0, _assertThisInitialized2["default"])(_this));
    _this.ref = /*#__PURE__*/React.createRef();
    _this.apiScriptRequested = false;
    _this.sentryHub = null;
    _this.captchaId = '';
    _this.state = {
      isApiReady: false,
      isRemoved: false,
      elementId: props.id
    };
    return _this;
  }
  (0, _createClass2["default"])(HCaptcha, [{
    key: "componentDidMount",
    value: function componentDidMount() {
      var _this2 = this;
      // Once captcha is mounted intialize hCaptcha - hCaptcha
      var element = (0, _utils.getMountElement)(this.props.scriptLocation);
      var frame = (0, _utils.getFrame)(element);
      this._hcaptcha = frame.window.hcaptcha || undefined;
      var isApiReady = typeof this._hcaptcha !== 'undefined';
      /*
       * Check if hCaptcha has already been loaded,
       * If Yes, render the captcha
       * If No, create script tag and wait to render the captcha
       */
      if (isApiReady) {
        this.setState({
          isApiReady: true
        }, function () {
          _this2.renderCaptcha();
        });
        return;
      }
      this.loadCaptcha();
    }
  }, {
    key: "componentWillUnmount",
    value: function componentWillUnmount() {
      var hcaptcha = this._hcaptcha;
      var captchaId = this.captchaId;
      if (!this.isReady()) {
        return;
      }
      // Reset any stored variables / timers when unmounting
      hcaptcha.reset(captchaId);
      hcaptcha.remove(captchaId);
    }
  }, {
    key: "shouldComponentUpdate",
    value: function shouldComponentUpdate(nextProps, nextState) {
      // Prevent component re-rendering when these internal state variables are updated
      if (this.state.isApiReady !== nextState.isApiReady || this.state.isRemoved !== nextState.isRemoved) {
        return false;
      }
      return true;
    }
  }, {
    key: "componentDidUpdate",
    value: function componentDidUpdate(prevProps) {
      var _this3 = this;
      // Prop Keys that could change
      var keys = ['sitekey', 'size', 'theme', 'tabindex', 'languageOverride', 'endpoint'];
      // See if any props changed during component update
      var match = keys.every(function (key) {
        return prevProps[key] === _this3.props[key];
      });
      // If they have changed, remove current captcha and render a new one
      if (!match) {
        this.removeCaptcha(function () {
          _this3.renderCaptcha();
        });
      }
    }
  }, {
    key: "loadCaptcha",
    value: function loadCaptcha() {
      if (this.apiScriptRequested) {
        return;
      }
      var _this$props = this.props,
        apihost = _this$props.apihost,
        assethost = _this$props.assethost,
        endpoint = _this$props.endpoint,
        host = _this$props.host,
        imghost = _this$props.imghost,
        hl = _this$props.languageOverride,
        reCaptchaCompat = _this$props.reCaptchaCompat,
        reportapi = _this$props.reportapi,
        sentry = _this$props.sentry,
        custom = _this$props.custom,
        loadAsync = _this$props.loadAsync,
        scriptLocation = _this$props.scriptLocation,
        scriptSource = _this$props.scriptSource,
        secureApi = _this$props.secureApi,
        _this$props$cleanup = _this$props.cleanup,
        cleanup = _this$props$cleanup === void 0 ? true : _this$props$cleanup;
      var mountParams = {
        render: 'explicit',
        apihost: apihost,
        assethost: assethost,
        endpoint: endpoint,
        hl: hl,
        host: host,
        imghost: imghost,
        recaptchacompat: reCaptchaCompat === false ? 'off' : null,
        reportapi: reportapi,
        sentry: sentry,
        custom: custom,
        loadAsync: loadAsync,
        scriptLocation: scriptLocation,
        scriptSource: scriptSource,
        secureApi: secureApi,
        cleanup: cleanup
      };
      (0, _loader.hCaptchaLoader)(mountParams).then(this.handleOnLoad, this.handleError)["catch"](this.handleError);
      this.apiScriptRequested = true;
    }
  }, {
    key: "renderCaptcha",
    value: function renderCaptcha(onRender) {
      var _this4 = this;
      var onReady = this.props.onReady;
      var isApiReady = this.state.isApiReady;
      var captchaId = this.captchaId;
      // Prevent calling hCaptcha render on two conditions:
      // • API is not ready
      // • Component has already been mounted
      if (!isApiReady || captchaId) return;
      var renderParams = Object.assign({
        "open-callback": this.handleOpen,
        "close-callback": this.handleClose,
        "error-callback": this.handleError,
        "chalexpired-callback": this.handleChallengeExpired,
        "expired-callback": this.handleExpire,
        "callback": this.handleSubmit
      }, this.props, {
        hl: this.props.hl || this.props.languageOverride,
        languageOverride: undefined
      });
      var hcaptcha = this._hcaptcha;
      //Render hCaptcha widget and provide necessary callbacks - hCaptcha
      var id = hcaptcha.render(this.ref.current, renderParams);
      this.captchaId = id;
      this.setState({
        isRemoved: false
      }, function () {
        onRender && onRender();
        onReady && onReady();
        _this4._onReady && _this4._onReady(id);
      });
    }
  }, {
    key: "resetCaptcha",
    value: function resetCaptcha() {
      var hcaptcha = this._hcaptcha;
      var captchaId = this.captchaId;
      if (!this.isReady()) {
        return;
      }
      // Reset captcha state, removes stored token and unticks checkbox
      hcaptcha.reset(captchaId);
    }
  }, {
    key: "removeCaptcha",
    value: function removeCaptcha(callback) {
      var _this5 = this;
      var hcaptcha = this._hcaptcha;
      var captchaId = this.captchaId;
      if (!this.isReady()) {
        return;
      }
      this.setState({
        isRemoved: true
      }, function () {
        _this5.captchaId = '';
        hcaptcha.remove(captchaId);
        callback && callback();
      });
    }
  }, {
    key: "handleOnLoad",
    value: function handleOnLoad() {
      var _this6 = this;
      this.setState({
        isApiReady: true
      }, function () {
        var element = (0, _utils.getMountElement)(_this6.props.scriptLocation);
        var frame = (0, _utils.getFrame)(element);
        _this6._hcaptcha = frame.window.hcaptcha;
        // render captcha and wait for captcha id
        _this6.renderCaptcha(function () {
          // trigger onLoad if it exists
          var onLoad = _this6.props.onLoad;
          if (onLoad) onLoad();
        });
      });
    }
  }, {
    key: "handleSubmit",
    value: function handleSubmit(event) {
      var onVerify = this.props.onVerify;
      var isRemoved = this.state.isRemoved;
      var hcaptcha = this._hcaptcha;
      var captchaId = this.captchaId;
      if (typeof hcaptcha === 'undefined' || isRemoved) return;
      var token = hcaptcha.getResponse(captchaId); //Get response token from hCaptcha widget
      var ekey = hcaptcha.getRespKey(captchaId); //Get current challenge session id from hCaptcha widget
      if (onVerify) onVerify(token, ekey); //Dispatch event to verify user response
    }
  }, {
    key: "handleExpire",
    value: function handleExpire() {
      var onExpire = this.props.onExpire;
      var hcaptcha = this._hcaptcha;
      var captchaId = this.captchaId;
      if (!this.isReady()) {
        return;
      }
      hcaptcha.reset(captchaId); // If hCaptcha runs into error, reset captcha - hCaptcha
      if (onExpire) onExpire();
    }
  }, {
    key: "handleError",
    value: function handleError(event) {
      var onError = this.props.onError;
      var hcaptcha = this._hcaptcha;
      var captchaId = this.captchaId;
      if (this.isReady()) {
        // If hCaptcha runs into error, reset captcha - hCaptcha
        hcaptcha.reset(captchaId);
      }
      if (onError) onError(event);
    }
  }, {
    key: "isReady",
    value: function isReady() {
      var _this$state = this.state,
        isApiReady = _this$state.isApiReady,
        isRemoved = _this$state.isRemoved;
      return isApiReady && !isRemoved;
    }
  }, {
    key: "handleOpen",
    value: function handleOpen() {
      if (!this.isReady() || !this.props.onOpen) {
        return;
      }
      this.props.onOpen();
    }
  }, {
    key: "handleClose",
    value: function handleClose() {
      if (!this.isReady() || !this.props.onClose) {
        return;
      }
      this.props.onClose();
    }
  }, {
    key: "handleChallengeExpired",
    value: function handleChallengeExpired() {
      if (!this.isReady() || !this.props.onChalExpired) {
        return;
      }
      this.props.onChalExpired();
    }
  }, {
    key: "execute",
    value: function execute() {
      var _this7 = this;
      var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
      opts = (0, _typeof2["default"])(opts) === 'object' ? opts : null;
      try {
        var hcaptcha = this._hcaptcha;
        var captchaId = this.captchaId;
        if (!this.isReady()) {
          var _opts;
          var onReady = new Promise(function (resolve, reject) {
            _this7._onReady = function (id) {
              try {
                var _hcaptcha = _this7._hcaptcha;
                if (opts && opts.async) {
                  _hcaptcha.execute(id, opts).then(resolve)["catch"](reject);
                } else {
                  resolve(_hcaptcha.execute(id, opts));
                }
              } catch (e) {
                reject(e);
              }
            };
          });
          return (_opts = opts) !== null && _opts !== void 0 && _opts.async ? onReady : null;
        }
        return hcaptcha.execute(captchaId, opts);
      } catch (error) {
        if (opts && opts.async) {
          return Promise.reject(error);
        }
        return null;
      }
    }
  }, {
    key: "close",
    value: function close() {
      var hcaptcha = this._hcaptcha;
      var captchaId = this.captchaId;
      if (!this.isReady()) {
        return;
      }
      return hcaptcha.close(captchaId);
    }
  }, {
    key: "setData",
    value: function setData(data) {
      var hcaptcha = this._hcaptcha;
      var captchaId = this.captchaId;
      if (!this.isReady()) {
        return;
      }
      if (data && (0, _typeof2["default"])(data) !== "object") {
        data = null;
      }
      hcaptcha.setData(captchaId, data);
    }
  }, {
    key: "getResponse",
    value: function getResponse() {
      var hcaptcha = this._hcaptcha;
      return hcaptcha.getResponse(this.captchaId);
    }
  }, {
    key: "getRespKey",
    value: function getRespKey() {
      var hcaptcha = this._hcaptcha;
      return hcaptcha.getRespKey(this.captchaId);
    }
  }, {
    key: "render",
    value: function render() {
      var elementId = this.state.elementId;
      return /*#__PURE__*/React.createElement("div", {
        ref: this.ref,
        id: elementId
      });
    }
  }]);
  return HCaptcha;
}(React.Component);
var _default = exports["default"] = HCaptcha;
module.exports = exports.default;