Home Reference Source

src/components/recaptcha/ReCaptcha.js

/*globals grecaptcha*/
import Component from '../_classes/component/Component';
import Formio from '../../Formio';
import _get from 'lodash/get';
import NativePromise from 'native-promise-only';

export default class ReCaptchaComponent extends Component {
  static schema(...extend) {
    return Component.schema({
      type: 'recaptcha',
      key: 'recaptcha',
      label: 'reCAPTCHA'
    }, ...extend);
  }

  static get builderInfo() {
    return {
      title: 'reCAPTCHA',
      group: 'premium',
      icon: 'refresh',
      documentation: '/userguide/#recaptcha',
      weight: 40,
      schema: ReCaptchaComponent.schema()
    };
  }

  render() {
    if (this.builderMode) {
      return super.render('reCAPTCHA');
    }
    else {
      return super.render('', true);
    }
  }

  createInput() {
    if (this.builderMode) {
      // We need to see it in builder mode.
      this.append(this.text(this.name));
    }
    else {
      const siteKey = _get(this.root.form, 'settings.recaptcha.siteKey');
      if (siteKey) {
        const recaptchaApiScriptUrl = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
        this.recaptchaApiReady = Formio.requireLibrary('googleRecaptcha', 'grecaptcha', recaptchaApiScriptUrl, true);
      }
      else {
        console.warn('There is no Site Key specified in settings in form JSON');
      }
    }
  }

  createLabel() {
    return;
  }

  verify(actionName) {
    const siteKey = _get(this.root.form, 'settings.recaptcha.siteKey');
    if (!siteKey) {
      console.warn('There is no Site Key specified in settings in form JSON');
      return;
    }
    if (!this.recaptchaApiReady) {
      const recaptchaApiScriptUrl = `https://www.google.com/recaptcha/api.js?render=${_get(this.root.form, 'settings.recaptcha.siteKey')}`;
      this.recaptchaApiReady = Formio.requireLibrary('googleRecaptcha', 'grecaptcha', recaptchaApiScriptUrl, true);
    }
    if (this.recaptchaApiReady) {
      this.recaptchaVerifiedPromise = new NativePromise((resolve, reject) => {
        this.recaptchaApiReady
          .then(() => {
            grecaptcha.ready(() => {
              grecaptcha
                .execute(siteKey, {
                  action: actionName
                })
                .then((token) => {
                  return this.sendVerificationRequest(token);
                })
                .then(verificationResult => {
                  this.setValue(verificationResult);
                  return resolve(verificationResult);
                });
            });
          })
          .catch(() => {
            return reject();
          });
      });
    }
  }

  beforeSubmit() {
    if (this.recaptchaVerifiedPromise) {
      return this.recaptchaVerifiedPromise
        .then(() => super.beforeSubmit());
    }
    return super.beforeSubmit();
  }

  sendVerificationRequest(token) {
    return Formio.makeStaticRequest(`${Formio.projectUrl}/recaptcha?recaptchaToken=${token}`);
  }

  setValue(value) {
    const changed = this.hasChanged(value, this.dataValue);
    this.dataValue = value;
    return changed;
  }

  getValue() {
    return this.dataValue;
  }
}