Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"date-fns": "^2.21.3",
"lodash": "^4.17.21",
"vue": "^2.6.11",
"vue-recaptcha": "^1.3.0",
"vue-text-mask": "^6.1.2"
},
"devDependencies": {
Expand Down
53 changes: 53 additions & 0 deletions src/components/Recaptcha-README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Vue Recaptcha Component
A user interface component built using the Vue web application framework designed to adapt Google Recaptcha to replace the pre-existing captcha component.

## Integration:
First install the common-lib-vue package on the command line with: npm i common-lib-vue
Make the following changes to the component that is going to integrate the Recaptcha component (herein referred to as the host component).

### Template Section
Between the tags for the host component insert the Recaptcha tag.
#### Example:
```vue
<template>
<div id="host">
<Recaptcha v-if="!isRecaptchaValid"
:apiBasePath="recaptchaAPIBasePath"
:nonce="applicationUuid"
:publicKey="this.recaptchaPublicKey"
@recaptchaVerified="handleCaptchaVerified($event)" />
</div>
</template>
```
### Script Section
Import the recaptcha component and add it to the list of components. Also add the variables required by recaptcha to the object returned by the data function and add a handleCaptchaVerified method to the methods list.
#### Example:
```vue
<script>
import {Recaptcha} from 'common-lib-vue';
export default {
name: 'HostComponent',
components: {
Recaptcha,
},
data: () => {
return {
recaptchaPublicKey: "REPLACE_WITH_PUBLIC_KEY_FROM_GOOGLE",
recaptchaAPIBasePath: PATH_TO_RECAPTCHA_SERVICE,
applicationUuid: GENERATED_UUID,
isRecaptchaValid: false,
}
},
methods: {
handleCaptchaVerified(captchaToken) {
console.log("Verified", captchaToken);
// this.$store.dispatch(formModule + '/' + SET_CAPTCHA_TOKEN, captchaToken); //Use the token as needed by the application
this.isRecaptchaValid = true;
},
},
}
</script>
```
PATH_TO_RECAPTCHA_SERVICE is likely to be stored in the environment, but it is just the path to communicate with the recaptcha service.
REPLACE_WITH_PUBLIC_KEY_FROM_GOOGLE should be filled in with the public key provided by Google. The private key will be used via an environment variable on the recaptcha service.
GENERATED_UUID should be the UUID used by the application.
76 changes: 76 additions & 0 deletions src/components/Recaptcha.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<template>
<div>
<vue-recaptcha :sitekey="publicKey"
:loadRecaptchaScript="true"
@verify="validate"/>
<div v-if="errorMessage"
class="error-message mt-2 text-danger">{{errorMessage}}</div>
</div>
</template>

<script>
import axios from 'axios';
import VueRecaptcha from 'vue-recaptcha';

const RECAPTCHA_VERIFY_URL = '/verify/captcha';
const GENERIC_ERROR_MESSAGE = 'Could not connect to recaptcha service. Please try again later.';

export default {
name: 'Recaptcha',
components: {
VueRecaptcha,
},
props: {
// Example: '/oop/api/recaptcha'
apiBasePath: {
type: String,
required: true
},
nonce: {
type: String,
required: true
},
publicKey: {
type: String,
required: true
}
},
data: () => {
return {
isLoadingRecaptchaVerification: false,
isInputValid: null,
errorMessage: null,
}
},
methods: {
validate(response) {
this.isLoadingRecaptchaVerification = true;
this.errorMessage = null;

axios.post(this.apiBasePath + RECAPTCHA_VERIFY_URL, {
nonce: this.nonce,
token: response,
})
.then((res) => {
const isValid = res.data.valid;
const token = res.data.jwt;

this.isInputValid = isValid;
this.isLoadingRecaptchaVerification = false;

if (isValid) {
this.$emit('recaptchaVerified', token);
} else {
this.errorMessage = GENERIC_ERROR_MESSAGE;
}
})
.catch(() => {
this.isLoadingRecaptchaVerification = false;
this.errorMessage = GENERIC_ERROR_MESSAGE;
});
}
}
}
</script>

<style scoped></style>
2 changes: 2 additions & 0 deletions src/library.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Button from './components/Button.vue';
import Captcha from './components/Captcha.vue';
import Recaptcha from './components/Recaptcha.vue';
import ContinueBar from './components/ContinueBar.vue';
import DynamicTagWrapper from './components/DynamicTagWrapper.vue';
import Header from './components/Header.vue';
Expand Down Expand Up @@ -89,6 +90,7 @@ export {
PractitionerNumberInput,
PromptModal,
Radio,
Recaptcha,
Select,
Textarea,
TimeInput,
Expand Down
20 changes: 20 additions & 0 deletions stories/components/Recaptcha.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Recaptcha from '../../src/components/Recaptcha.vue';

export default {
title: 'Components/Recaptcha',
component: Recaptcha,
argTypes: {},
};

const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { Recaptcha },
template: '<Recaptcha v-bind="$props" />',
});

export const Example = Template.bind({});
Example.args = {
apiBasePath: '/project/api/recaptcha',
nonce: '0123456789',
publicKey:"6LfHcJcbAAAAAJA_kkeR4AXt92hSUpCxb-mKeWkT"
};