Skip to content

Commit

Permalink
next (#73)
Browse files Browse the repository at this point in the history
* Use PascalCase for component registration

This allows both `<Recaptcha>` and `<recaptcha>` to be used in templates.

Components that are registered in PascalCase can be used in templates with either PascalCase or kebab-case, whereas components registered in kebab-case can only be referenced in kebab-case. Some projects prefer to use PascalCase for component tags, so it's better for this plugin to make both options available.

See https://vuejs.org/v2/guide/components-registration.html#Name-Casing

* update plugin.js for global use

* Moved script element error callback to within promise so that the error can be caught further up the stack

* Reset ready state after error

* docs: remove david badge

* docs: add usage (#74)

Co-authored-by: Sébastien Chopin <seb@nuxtjs.com>

* feat(multi-widget): render and verify multiple v2 widgets (#75)

* feat(language): enable google auto detection (#72)

Co-authored-by: Sébastien Chopin <seb@nuxtjs.com>

* fix: describe error within execute() (#40)

Co-authored-by: Abdelhak Akermi <abdelhak@akermi.me>

* feat: runtime config (#70)

Co-authored-by: Sébastien Chopin <seb@nuxtjs.com>
Co-authored-by: Nikolay Baskov <baskov@adv.ru>

* fix: remove badge on destroy (#76)

* Apply suggestions from code review

Co-authored-by: Simon Garner <simon.garner@madscience.co.nz>
Co-authored-by: mvrlin <mvrlin@pm.me>
Co-authored-by: lat1992 <lat1992@users.noreply.github.com>
Co-authored-by: Owen Andrews <owen@owenandre.ws>
Co-authored-by: Sébastien Chopin <seb@nuxtjs.com>
Co-authored-by: Red Bayoub <40964509+redbayoub@users.noreply.github.com>
Co-authored-by: Abdelhak Akermi <abdelhak.akermi@gmail.com>
Co-authored-by: Abdelhak Akermi <abdelhak@akermi.me>
Co-authored-by: bason8800 <41577602+bason8800@users.noreply.github.com>
Co-authored-by: Nikolay Baskov <baskov@adv.ru>
  • Loading branch information
11 people authored Feb 3, 2021
1 parent fc6c496 commit 4a3e3f2
Show file tree
Hide file tree
Showing 11 changed files with 4,044 additions and 1,315 deletions.
98 changes: 95 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![Circle CI][circle-ci-src]][circle-ci-href]
[![Codecov][codecov-src]][codecov-href]
[![Dependencies][david-dm-src]][david-dm-href]
[![Standard JS][standard-js-src]][standard-js-href]

> 🤖 Simple and easy Google reCAPTCHA integration with Nuxt.js
Expand Down Expand Up @@ -59,6 +58,101 @@ using top level options
}
```

## Runtime config

```js
// nuxt.config.js
export default {
publicRuntimeConfig: {
recaptcha: {
/* reCAPTCHA options */
siteKey: process.env.RECAPTCHA_SITE_KEY // for example
}
}
}
```

## Usage

### reCAPTCHA v2

1. Add `<recaptcha>` component inside your form:

```vue
<form @submit.prevent="onSubmit">
<input autocomplete="true" placeholder="Email" type="email" v-model="email">
<input autocomplete="current-password" placeholder="Password" type="password" v-model="password">
<recaptcha />
<button type="submit">Sign In</button>
</form>
```

2. Call `getResponse` inside form submit handler to get reCAPTCHA token:

```js
async onSubmit() {
try {
const token = await this.$recaptcha.getResponse()
console.log('ReCaptcha token:', token)

// send token to server alongside your form data

// at the end you need to reset recaptcha
await this.$recaptcha.reset()
} catch (error) {
console.log('Login error:', error)
}
},
```
See: [v2 example](https://github.com/nuxt-community/recaptcha-module/tree/master/example/v2)

### reCAPTCHA v3

1. Call `init` function inside `mounted` hook of your page

```js
async mounted() {
try {
await this.$recaptcha.init()
} catch (e) {
console.error(e);
}
}
```

2. Call `execute` function form submit handler to get reCAPTCHA token:

```js
async onSubmit() {
try {
const token = await this.$recaptcha.execute('login')
console.log('ReCaptcha token:', token)

// send token to server alongside your form data

} catch (error) {
console.log('Login error:', error)
}
}
```

3. Call `destroy` function inside `beforeDestroy` hook of the page. (This will remove reCAPTCHA scripts, styles and badge from the page)

```js
beforeDestroy() {
this.$recaptcha.destroy()
}
```

See: [v3 example](https://github.com/nuxt-community/recaptcha-module/tree/master/example/v3)


### Server Side

When you send `data + token` to the server, you should verify the token on the server side to make sure it does not requested from a bot.
You can find out how to verify token on the server side by looking at the [server middleware](https://github.com/nuxt-community/recaptcha-module/tree/master/example/v2/api/recaptcha.js) inside v2 example. (The server side is same for both versions)


## Info Hiding Badges

You're allowed to hide the badge (i.e. for v3 and v2 invisible), as long as you include the recaptcha branding in the user flow.
Expand Down Expand Up @@ -93,7 +187,5 @@ Copyright (c) mvrlin <mvrlin@pm.me>
[circle-ci-href]: https://circleci.com/gh/nuxt-community/recaptcha-module
[codecov-src]: https://img.shields.io/codecov/c/github/nuxt-community/recaptcha-module.svg?style=flat-square
[codecov-href]: https://codecov.io/gh/@nuxtjs/recaptcha
[david-dm-src]: https://david-dm.org/@nuxtjs/recaptcha/status.svg?style=flat-square
[david-dm-href]: https://david-dm.org/@nuxtjs/recaptcha
[standard-js-src]: https://img.shields.io/badge/code_style-standard-brightgreen.svg?style=flat-square
[standard-js-href]: https://standardjs.com
19 changes: 19 additions & 0 deletions example/both/nuxt.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const { resolve } = require('path')

module.exports = {
buildDir: resolve(__dirname, '.nuxt'),

modules: [
['../../lib/module', {
hideBadge: true,
siteKey: '6LeE3ZAUAAAAANVaDO60w4ZBK44khqO7OpsitZNY',

version: 3,
}]
],

srcDir: __dirname,

render: { resourceHints: false },
rootDir: resolve(__dirname, '..')
}
62 changes: 62 additions & 0 deletions example/both/pages/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<template>
<section class="index-page">
<h2>Sign In</h2>

<form @submit.prevent="onSubmit">
<input
v-model="email"
autocomplete="true"
placeholder="Email"
type="email"
>

<input
v-model="password"
autocomplete="current-password"
placeholder="Password"
type="password"
>
<recaptcha
id="v2-normal"
site-key="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
/>
<button type="submit">
Sign In
</button>
</form>
</section>
</template>

<script>
export default {
data: () => ({
email: 'test@example.com',
password: '123',
widgetId: 0
}),
async mounted() {
await this.$recaptcha.init()
this.widgetId = this.$recaptcha.render('v2-normal', {
sitekey: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'
})
},
methods: {
async onSubmit() {
try {
const tokenV2 = await this.$recaptcha.getResponse(this.widgetId)
console.log('V2 ReCaptcha token:', tokenV2)
const token = await this.$recaptcha.execute('login')
console.log('V3 ReCaptcha token:', token)
this.$recaptcha.reset(this.widgetId)
} catch (error) {
console.log('Login error:', error)
}
}
}
}
</script>
49 changes: 49 additions & 0 deletions example/v2/api/recaptcha.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { useBody } from 'h3'
import { $fetch } from 'ohmyfetch/node'

/**
* It is highly recommended to use enviroment variables instead of hardcoded secrets.
*/
const SECRET_KEY = '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe'

/**
* This is an example that demonstrates how verifying reCAPTCHA on the server side works.
* Do not use this middleware in your production.
*/
export default async (req, res) => {
res.setHeader('Content-Type', 'application/json')
try {
const { token } = await useBody(req)

if (!token) {
res.end(JSON.stringify({
success: false,
message: 'Invalid token'
}))
return
}
const response = await $fetch(
`https://www.google.com/recaptcha/api/siteverify?secret=${SECRET_KEY}&response=${token}`
)

if (response.success) {
res.end(JSON.stringify({
success: true,
message: 'Token verifyed',
response: response
}))
} else {
res.end(JSON.stringify({
success: false,
message: 'Invalid token',
response: response
}))
}
} catch (e) {
console.log('ReCaptcha error:', e)
res.end(JSON.stringify({
success: false,
message: 'Internal error'
}))
}
}
4 changes: 4 additions & 0 deletions example/v2/nuxt.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ module.exports = {
}]
],

serverMiddleware: [
{ path: '/api/check-token', handler: '~/api/recaptcha' }
],

srcDir: __dirname,

render: { resourceHints: false },
Expand Down
12 changes: 11 additions & 1 deletion example/v2/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,17 @@ export default {
async onSubmit() {
try {
const token = await this.$recaptcha.getResponse()
console.log('ReCaptcha token:', token)
const response = await fetch('/api/check-token', {
method: 'POST',
body: JSON.stringify({
token,
email: this.email,
password: this.password
})
}).then(res => res.json())
console.log('Server Response: ', response)
await this.$recaptcha.reset()
} catch (error) {
Expand Down
6 changes: 5 additions & 1 deletion example/v3/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ export default {
}),
async mounted() {
await this.$recaptcha.init()
try {
await this.$recaptcha.init()
} catch (e) {
console.log(e);
}
},
methods: {
Expand Down
Loading

0 comments on commit 4a3e3f2

Please sign in to comment.