diff --git a/example/combined/api/recaptcha.js b/example/combined/api/recaptcha.js
new file mode 100644
index 0000000..02a5576
--- /dev/null
+++ b/example/combined/api/recaptcha.js
@@ -0,0 +1,60 @@
+import { useBody } from 'h3'
+import { $fetch } from 'ohmyfetch/node'
+
+/**
+ * It is highly recommended to use enviroment variables instead of hardcoded secrets.
+ */
+const SECRET_KEYS = {
+ '2': '6LecsLIaAAAAABd-yNkMXt_rf7GjWaxVJDlWryYy', // v2 secret key
+ '3': '6LfembIaAAAAACcZlTsRvwf62fuCGXfR7e2HIj8S' // v3 secret key
+}
+
+/**
+ * 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, v } = await useBody(req)
+
+ if (!SECRET_KEYS[v]) {
+ res.end(JSON.stringify({
+ success: false,
+ message: 'Invalid version'
+ }))
+ return
+ }
+
+ 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_KEYS[v]}&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'
+ }))
+ }
+}
diff --git a/example/combined/nuxt.config.js b/example/combined/nuxt.config.js
new file mode 100644
index 0000000..928f863
--- /dev/null
+++ b/example/combined/nuxt.config.js
@@ -0,0 +1,24 @@
+const { resolve } = require('path')
+
+module.exports = {
+ buildDir: resolve(__dirname, '.nuxt'),
+
+ modules: [
+ ['../../lib/module', {
+ hideBadge: true,
+ siteKey: [
+ '6LecsLIaAAAAAEeBOiX7b4rSwMDNL9zhIXlPNEB1', // v2 site key
+ '6LfembIaAAAAACPEdfjUpSmmYqMyJZn-ZU0aFUvb' // v3 site key
+ ]
+ }]
+ ],
+
+ serverMiddleware: [
+ { path: '/api/check-token', handler: '~/api/recaptcha' }
+ ],
+
+ srcDir: __dirname,
+
+ render: { resourceHints: false },
+ rootDir: resolve(__dirname, '..')
+}
diff --git a/example/combined/pages/about.vue b/example/combined/pages/about.vue
new file mode 100644
index 0000000..044392d
--- /dev/null
+++ b/example/combined/pages/about.vue
@@ -0,0 +1,8 @@
+
+
+ About page
+ Text
+
+ Go to Index
+
+
diff --git a/example/combined/pages/index.vue b/example/combined/pages/index.vue
new file mode 100644
index 0000000..ac0d5a7
--- /dev/null
+++ b/example/combined/pages/index.vue
@@ -0,0 +1,119 @@
+
+
+ With v2
+
+
+
+
+ With v3
+
+
+
+ About
+
+
+
+
diff --git a/lib/plugin.js b/lib/plugin.js
index 8eba35d..57247fd 100644
--- a/lib/plugin.js
+++ b/lib/plugin.js
@@ -9,7 +9,9 @@ class ReCaptcha {
throw new Error('ReCaptcha error: No key provided')
}
- if (!version) {
+ if (!version && !Array.isArray(siteKey)) {
+ throw new Error('ReCaptcha error: siteKey must be array when version not provided')
+ } else if (!version && typeof(siteKey) == 'string') {
throw new Error('ReCaptcha error: No version provided')
}
@@ -26,6 +28,18 @@ class ReCaptcha {
this.size = size
}
+ get siteKeyV2() {
+ if (this.version === 2) return this.siteKey;
+ else if (Array.isArray(this.siteKey)) return this.siteKey[0];
+ else return null;
+ }
+
+ get siteKeyV3() {
+ if (this.version === 3) return this.siteKey;
+ else if (Array.isArray(this.siteKey)) return this.siteKey[1];
+ else return null;
+ }
+
destroy () {
if (this._ready) {
this._ready = false
@@ -43,11 +57,13 @@ class ReCaptcha {
if (head.contains(style)) {
head.removeChild(style)
}
-
+
const badge = document.querySelector('.grecaptcha-badge')
if (badge) {
badge.remove()
}
+
+ delete window.grecaptcha;
}
}
@@ -57,7 +73,7 @@ class ReCaptcha {
if ('grecaptcha' in window) {
return window.grecaptcha.execute(
- this.siteKey,
+ this.siteKeyV3,
{ action }
)
}
@@ -117,7 +133,7 @@ class ReCaptcha {
script.setAttribute('defer', '')
const params = []
- if (this.version === 3) { params.push('render=' + this.siteKey) }
+ if (this.siteKeyV3) { params.push('render=' + this.siteKeyV3) }
if (this.language) { params.push('hl=' + this.language) }
script.setAttribute('src', API_URL + '?' + params.join('&'))
@@ -127,12 +143,7 @@ class ReCaptcha {
this._ready = new Promise((resolve, reject) => {
script.addEventListener('load', () => {
- if (this.version === 3 && this.hideBadge) {
- style.innerHTML = '.grecaptcha-badge { display: none }'
- document.head.appendChild(style)
- } else if(this.version === 2 && this.hideBadge) {
- // display: none DISABLES the spam checking!
- // ref: https://stackoverflow.com/questions/44543157/how-to-hide-the-google-invisible-recaptcha-badge
+ if (this.hideBadge) {
style.innerHTML = '.grecaptcha-badge { visibility: hidden; }'
document.head.appendChild(style)
}
@@ -156,14 +167,27 @@ class ReCaptcha {
return this._eventBus.on(event, callback)
}
+ off (event, callback) {
+ return this._eventBus.off(event, callback)
+ }
+
reset (widgetId) {
- if (this.version === 2 || typeof widgetId !== 'undefined') {
+ if (this.siteKeyV2 || typeof widgetId !== 'undefined') {
window.grecaptcha.reset(widgetId)
}
}
- render (reference, { sitekey, theme }) {
- return window.grecaptcha.render(reference.$el || reference, { sitekey, theme })
+ render (reference, options) {
+ return window.grecaptcha.render(reference.$el || reference, Object.assign({
+ "sitekey": this.siteKeyV2,
+ "size": this.size
+ },
+ options,
+ {
+ "callback": "recaptchaSuccessCallback",
+ "expired-callback": "recaptchaExpiredCallback",
+ "error-callback": "recaptchaErrorCallback",
+ }));
}
}
diff --git a/lib/recaptcha.vue b/lib/recaptcha.vue
index fc0f7f3..754c3ba 100644
--- a/lib/recaptcha.vue
+++ b/lib/recaptcha.vue
@@ -1,16 +1,5 @@
-
+