Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/captcha/captcha_modal.vue')
-rw-r--r--app/assets/javascripts/captcha/captcha_modal.vue110
1 files changed, 110 insertions, 0 deletions
diff --git a/app/assets/javascripts/captcha/captcha_modal.vue b/app/assets/javascripts/captcha/captcha_modal.vue
new file mode 100644
index 00000000000..e6c73bc9643
--- /dev/null
+++ b/app/assets/javascripts/captcha/captcha_modal.vue
@@ -0,0 +1,110 @@
+<script>
+// NOTE 1: This is similar to recaptcha_modal.vue, but it directly uses the reCAPTCHA Javascript API
+// (https://developers.google.com/recaptcha/docs/display#js_api) and gl-modal, rather than relying
+// on the form-based ReCAPTCHA HTML being pre-rendered by the backend and using deprecated-modal.
+
+// NOTE 2: Even though this modal currently only supports reCAPTCHA, we use 'captcha' instead
+// of 'recaptcha' throughout the code, so that we can easily add support for future alternative
+// captcha implementations other than reCAPTCHA (e.g. FriendlyCaptcha) without having to
+// change the references in the code or API.
+
+import { GlModal } from '@gitlab/ui';
+import { uniqueId } from 'lodash';
+import { initRecaptchaScript } from '~/captcha/init_recaptcha_script';
+
+export default {
+ components: {
+ GlModal,
+ },
+ props: {
+ needsCaptchaResponse: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ captchaSiteKey: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ modalId: uniqueId('captcha-modal-'),
+ };
+ },
+ watch: {
+ needsCaptchaResponse(newNeedsCaptchaResponse) {
+ // If this is true, we need to present the captcha modal to the user.
+ // When the modal is shown we will also initialize and render the form.
+ if (newNeedsCaptchaResponse) {
+ this.$refs.modal.show();
+ }
+ },
+ },
+ methods: {
+ emitReceivedCaptchaResponse(captchaResponse) {
+ this.$emit('receivedCaptchaResponse', captchaResponse);
+ this.$refs.modal.hide();
+ },
+ emitNullReceivedCaptchaResponse() {
+ this.emitReceivedCaptchaResponse(null);
+ },
+ /**
+ * handler for when modal is shown
+ */
+ shown() {
+ const containerRef = this.$refs.captcha;
+
+ // NOTE: This is the only bit that is specific to Google's reCAPTCHA captcha implementation.
+ initRecaptchaScript()
+ .then((grecaptcha) => {
+ grecaptcha.render(containerRef, {
+ sitekey: this.captchaSiteKey,
+ // This callback will emit and let the parent handle the response
+ callback: this.emitReceivedCaptchaResponse,
+ // TODO: Also need to handle expired-callback and error-callback
+ // See https://gitlab.com/gitlab-org/gitlab/-/issues/217722#future-follow-on-issuesmrs
+ });
+ })
+ .catch((e) => {
+ // TODO: flash the error or notify the user some other way
+ // See https://gitlab.com/gitlab-org/gitlab/-/issues/217722#future-follow-on-issuesmrs
+ this.emitNullReceivedCaptchaResponse();
+ this.$refs.modal.hide();
+
+ // eslint-disable-next-line no-console
+ console.error(
+ '[gitlab] an unexpected exception was caught while initializing captcha',
+ e,
+ );
+ });
+ },
+ /**
+ * handler for when modal is about to hide
+ */
+ hide(bvModalEvent) {
+ // If hide() was called without any argument, the value of trigger will be null.
+ // See https://bootstrap-vue.org/docs/components/modal#prevent-closing
+ if (bvModalEvent.trigger) {
+ this.emitNullReceivedCaptchaResponse();
+ }
+ },
+ },
+};
+</script>
+<template>
+ <!-- Note: The action-cancel button isn't necessary for the functionality of the modal, but -->
+ <!-- there must be at least one button or focusable element, or the gl-modal fails to render. -->
+ <!-- We could modify gl-model to remove this requirement. -->
+ <gl-modal
+ ref="modal"
+ :modal-id="modalId"
+ :title="__('Please solve the captcha')"
+ :action-cancel="{ text: __('Cancel') }"
+ @shown="shown"
+ @hide="hide"
+ >
+ <div ref="captcha"></div>
+ <p>{{ __('We want to be sure it is you, please confirm you are not a robot.') }}</p>
+ </gl-modal>
+</template>