From 17a7d5f1c703b0a418d34583faa250c748ef9b00 Mon Sep 17 00:00:00 2001 From: mvrlin Date: Sat, 21 May 2022 11:46:26 +0300 Subject: [PATCH] feat: add enterprise mode --- README.md | 5 +- example/{ => base}/both/nuxt.config.js | 4 +- example/{ => base}/both/pages/index.vue | 0 example/{ => base}/v2/api/recaptcha.js | 0 example/{ => base}/v2/nuxt.config.js | 2 +- example/{ => base}/v2/pages/about.vue | 0 example/{ => base}/v2/pages/index.vue | 0 example/{ => base}/v3/nuxt.config.js | 4 +- example/{ => base}/v3/pages/index.vue | 0 example/enterprise/both/nuxt.config.js | 21 +++++++ example/enterprise/both/pages/index.vue | 62 +++++++++++++++++++++ example/enterprise/v2/api/recaptcha.js | 49 ++++++++++++++++ example/enterprise/v2/nuxt.config.js | 24 ++++++++ example/enterprise/v2/pages/about.vue | 8 +++ example/enterprise/v2/pages/index.vue | 74 +++++++++++++++++++++++++ example/enterprise/v3/nuxt.config.js | 21 +++++++ example/enterprise/v3/pages/index.vue | 51 +++++++++++++++++ lib/plugin.js | 30 +++++++--- package.json | 9 ++- types/index.d.ts | 5 ++ yarn.lock | 23 ++------ 21 files changed, 356 insertions(+), 36 deletions(-) rename example/{ => base}/both/nuxt.config.js (86%) rename example/{ => base}/both/pages/index.vue (100%) rename example/{ => base}/v2/api/recaptcha.js (100%) rename example/{ => base}/v2/nuxt.config.js (93%) rename example/{ => base}/v2/pages/about.vue (100%) rename example/{ => base}/v2/pages/index.vue (100%) rename example/{ => base}/v3/nuxt.config.js (86%) rename example/{ => base}/v3/pages/index.vue (100%) create mode 100644 example/enterprise/both/nuxt.config.js create mode 100644 example/enterprise/both/pages/index.vue create mode 100644 example/enterprise/v2/api/recaptcha.js create mode 100644 example/enterprise/v2/nuxt.config.js create mode 100644 example/enterprise/v2/pages/about.vue create mode 100644 example/enterprise/v2/pages/index.vue create mode 100644 example/enterprise/v3/nuxt.config.js create mode 100644 example/enterprise/v3/pages/index.vue diff --git a/README.md b/README.md index 326eef3..388d945 100755 --- a/README.md +++ b/README.md @@ -50,8 +50,9 @@ using top level options recaptcha: { hideBadge: Boolean, // Hide badge element (v3 & v2 via size=invisible) language: String, // Recaptcha language (v2) + mode: String, // Mode: 'base', 'enterprise' siteKey: String, // Site key for requests - version: Number, // Version + version: Number, // Version size: String // Size: 'compact', 'normal', 'invisible' (v2) }, // ... @@ -160,7 +161,7 @@ You're allowed to hide the badge (i.e. for v3 and v2 invisible), as long as you For example: ```html -This site is protected by reCAPTCHA and the Google +This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply. diff --git a/example/both/nuxt.config.js b/example/base/both/nuxt.config.js similarity index 86% rename from example/both/nuxt.config.js rename to example/base/both/nuxt.config.js index 6ec9af5..0e550de 100644 --- a/example/both/nuxt.config.js +++ b/example/base/both/nuxt.config.js @@ -4,11 +4,11 @@ module.exports = { buildDir: resolve(__dirname, '.nuxt'), modules: [ - ['../../lib/module', { + ['../../../lib/module', { hideBadge: true, siteKey: '6LeE3ZAUAAAAANVaDO60w4ZBK44khqO7OpsitZNY', - version: 3, + version: 3 }] ], diff --git a/example/both/pages/index.vue b/example/base/both/pages/index.vue similarity index 100% rename from example/both/pages/index.vue rename to example/base/both/pages/index.vue diff --git a/example/v2/api/recaptcha.js b/example/base/v2/api/recaptcha.js similarity index 100% rename from example/v2/api/recaptcha.js rename to example/base/v2/api/recaptcha.js diff --git a/example/v2/nuxt.config.js b/example/base/v2/nuxt.config.js similarity index 93% rename from example/v2/nuxt.config.js rename to example/base/v2/nuxt.config.js index eae2283..6c5a049 100644 --- a/example/v2/nuxt.config.js +++ b/example/base/v2/nuxt.config.js @@ -4,7 +4,7 @@ module.exports = { buildDir: resolve(__dirname, '.nuxt'), modules: [ - ['../../lib/module', { + ['../../../lib/module', { siteKey: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI', size: 'invisible', hideBadge: false, diff --git a/example/v2/pages/about.vue b/example/base/v2/pages/about.vue similarity index 100% rename from example/v2/pages/about.vue rename to example/base/v2/pages/about.vue diff --git a/example/v2/pages/index.vue b/example/base/v2/pages/index.vue similarity index 100% rename from example/v2/pages/index.vue rename to example/base/v2/pages/index.vue diff --git a/example/v3/nuxt.config.js b/example/base/v3/nuxt.config.js similarity index 86% rename from example/v3/nuxt.config.js rename to example/base/v3/nuxt.config.js index 6ec9af5..0e550de 100644 --- a/example/v3/nuxt.config.js +++ b/example/base/v3/nuxt.config.js @@ -4,11 +4,11 @@ module.exports = { buildDir: resolve(__dirname, '.nuxt'), modules: [ - ['../../lib/module', { + ['../../../lib/module', { hideBadge: true, siteKey: '6LeE3ZAUAAAAANVaDO60w4ZBK44khqO7OpsitZNY', - version: 3, + version: 3 }] ], diff --git a/example/v3/pages/index.vue b/example/base/v3/pages/index.vue similarity index 100% rename from example/v3/pages/index.vue rename to example/base/v3/pages/index.vue diff --git a/example/enterprise/both/nuxt.config.js b/example/enterprise/both/nuxt.config.js new file mode 100644 index 0000000..8e72355 --- /dev/null +++ b/example/enterprise/both/nuxt.config.js @@ -0,0 +1,21 @@ +const { resolve } = require('path') + +module.exports = { + buildDir: resolve(__dirname, '.nuxt'), + + modules: [ + ['../../../lib/module', { + mode: 'enterprise', + + hideBadge: true, + siteKey: process.env.RECATPCHA_KEY, + + version: 3 + }] + ], + + srcDir: __dirname, + + render: { resourceHints: false }, + rootDir: resolve(__dirname, '..') +} diff --git a/example/enterprise/both/pages/index.vue b/example/enterprise/both/pages/index.vue new file mode 100644 index 0000000..f72fa91 --- /dev/null +++ b/example/enterprise/both/pages/index.vue @@ -0,0 +1,62 @@ + + + diff --git a/example/enterprise/v2/api/recaptcha.js b/example/enterprise/v2/api/recaptcha.js new file mode 100644 index 0000000..d11a298 --- /dev/null +++ b/example/enterprise/v2/api/recaptcha.js @@ -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' + })) + } +} diff --git a/example/enterprise/v2/nuxt.config.js b/example/enterprise/v2/nuxt.config.js new file mode 100644 index 0000000..4185b20 --- /dev/null +++ b/example/enterprise/v2/nuxt.config.js @@ -0,0 +1,24 @@ +const { resolve } = require('path') + +module.exports = { + buildDir: resolve(__dirname, '.nuxt'), + + modules: [ + ['../../../lib/module', { + mode: 'enterprise', + siteKey: process.env.RECATPCHA_KEY, + size: 'invisible', + hideBadge: false, + version: 2 + }] + ], + + serverMiddleware: [ + { path: '/api/check-token', handler: '~/api/recaptcha' } + ], + + srcDir: __dirname, + + render: { resourceHints: false }, + rootDir: resolve(__dirname, '..') +} diff --git a/example/enterprise/v2/pages/about.vue b/example/enterprise/v2/pages/about.vue new file mode 100644 index 0000000..96a630d --- /dev/null +++ b/example/enterprise/v2/pages/about.vue @@ -0,0 +1,8 @@ + diff --git a/example/enterprise/v2/pages/index.vue b/example/enterprise/v2/pages/index.vue new file mode 100644 index 0000000..1606326 --- /dev/null +++ b/example/enterprise/v2/pages/index.vue @@ -0,0 +1,74 @@ + + + diff --git a/example/enterprise/v3/nuxt.config.js b/example/enterprise/v3/nuxt.config.js new file mode 100644 index 0000000..8e72355 --- /dev/null +++ b/example/enterprise/v3/nuxt.config.js @@ -0,0 +1,21 @@ +const { resolve } = require('path') + +module.exports = { + buildDir: resolve(__dirname, '.nuxt'), + + modules: [ + ['../../../lib/module', { + mode: 'enterprise', + + hideBadge: true, + siteKey: process.env.RECATPCHA_KEY, + + version: 3 + }] + ], + + srcDir: __dirname, + + render: { resourceHints: false }, + rootDir: resolve(__dirname, '..') +} diff --git a/example/enterprise/v3/pages/index.vue b/example/enterprise/v3/pages/index.vue new file mode 100644 index 0000000..d1f9e7e --- /dev/null +++ b/example/enterprise/v3/pages/index.vue @@ -0,0 +1,51 @@ + + + diff --git a/lib/plugin.js b/lib/plugin.js index 8eba35d..ef3cad6 100644 --- a/lib/plugin.js +++ b/lib/plugin.js @@ -4,7 +4,7 @@ import Vue from 'vue' const API_URL = 'https://www.recaptcha.net/recaptcha/api.js' class ReCaptcha { - constructor ({ hideBadge, language, siteKey, version, size }) { + constructor ({ hideBadge, language, mode, siteKey, version, size }) { if (!siteKey) { throw new Error('ReCaptcha error: No key provided') } @@ -14,6 +14,7 @@ class ReCaptcha { } this._elements = {} + this._grecaptcha = null this._eventBus = null this._ready = false @@ -24,6 +25,8 @@ class ReCaptcha { this.siteKey = siteKey this.version = version this.size = size + + this.mode = mode } destroy () { @@ -43,7 +46,7 @@ class ReCaptcha { if (head.contains(style)) { head.removeChild(style) } - + const badge = document.querySelector('.grecaptcha-badge') if (badge) { badge.remove() @@ -56,7 +59,7 @@ class ReCaptcha { await this.init() if ('grecaptcha' in window) { - return window.grecaptcha.execute( + return this._grecaptcha.execute( this.siteKey, { action } ) @@ -70,7 +73,7 @@ class ReCaptcha { return new Promise((resolve, reject) => { if ('grecaptcha' in window) { if(this.size == 'invisible'){ - window.grecaptcha.execute(widgetId) + this._grecaptcha.execute(widgetId) window.recaptchaSuccessCallback = token => { this._eventBus.emit('recaptcha-success', token) @@ -82,7 +85,7 @@ class ReCaptcha { reject(error) } } else { - const response = window.grecaptcha.getResponse(widgetId) + const response = this._grecaptcha.getResponse(widgetId) if (response) { this._eventBus.emit('recaptcha-success', response) @@ -119,7 +122,15 @@ class ReCaptcha { const params = [] if (this.version === 3) { params.push('render=' + this.siteKey) } if (this.language) { params.push('hl=' + this.language) } - script.setAttribute('src', API_URL + '?' + params.join('&')) + + let scriptUrl = API_URL + + if (this.version === 'enterprise') { + scriptUrl = scriptUrl.replace('api.js', 'enterprise.js') + params.push('render=' + this.siteKey) + } + + script.setAttribute('src', scriptUrl + '?' + params.join('&')) window.recaptchaSuccessCallback = (token) => this._eventBus.emit('recaptcha-success', token) window.recaptchaExpiredCallback = () => this._eventBus.emit('recaptcha-expired') @@ -137,7 +148,8 @@ class ReCaptcha { document.head.appendChild(style) } - window.grecaptcha.ready(resolve) + this._grecaptcha = window.grecaptcha.enterprise || window.grecaptcha + this._grecaptcha.ready(resolve) }) script.addEventListener('error', () => { @@ -158,12 +170,12 @@ class ReCaptcha { reset (widgetId) { if (this.version === 2 || typeof widgetId !== 'undefined') { - window.grecaptcha.reset(widgetId) + this._grecaptcha.reset(widgetId) } } render (reference, { sitekey, theme }) { - return window.grecaptcha.render(reference.$el || reference, { sitekey, theme }) + return this._grecaptcha.render(reference.$el || reference, { sitekey, theme }) } } diff --git a/package.json b/package.json index a602d1b..a8bca8a 100755 --- a/package.json +++ b/package.json @@ -23,9 +23,12 @@ "access": "public" }, "scripts": { - "dev": "nuxt example/both", - "dev:v3": "nuxt example/v3", - "dev:v2": "nuxt example/v2", + "dev": "nuxt example/base/both", + "dev:v3": "nuxt example/base/v3", + "dev:v2": "nuxt example/base/v2", + "dev:enterprise": "nuxt example/enterprise/both", + "dev:enterprise:v3": "nuxt example/enterprise/v3", + "dev:enterprise:v2": "nuxt example/enterprise/v2", "lint": "eslint lib test", "test": "yarn lint && jest", "release": "standard-version && git push --follow-tags && npm publish" diff --git a/types/index.d.ts b/types/index.d.ts index 1b09df1..9100a2c 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -6,6 +6,11 @@ export interface ReCaptchaOptions { */ hideBadge?: boolean + /** + * ReCaptcha mode. + */ + mode?: 'base' | 'enterprise' + /** * Site key to send requests */ diff --git a/yarn.lock b/yarn.lock index a1292b8..9fea28d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5661,17 +5661,15 @@ gzip-size@^5.0.0: duplexer "^0.1.1" pify "^3.0.0" -<<<<<<< HEAD -hable@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/hable/-/hable-3.0.0.tgz#6de089b2df946635cf8134b9e4859f1b62de255f" - integrity sha512-7+G0/2/COR8pwteYFqHIVYfQpuEiO2HXwJrhCBJVgrNrl9O5eaUoJVDGXUJX+0RpGncNVTuestexjk1afj01wQ== -======= h3@latest: version "0.2.4" resolved "https://registry.yarnpkg.com/h3/-/h3-0.2.4.tgz#14884b6413a4a0bdcf5e003b7fc5b410be6c87ce" integrity sha512-xiV5nMp5MsmJgzHIDo5IAuc2V9uhCsXnDs5wPcWOtyJ/zBjohqvpjUb94/ZFGmMkh4fjz05HWvuXUZDuwS210Q== ->>>>>>> upstream/master + +hable@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/hable/-/hable-3.0.0.tgz#6de089b2df946635cf8134b9e4859f1b62de255f" + integrity sha512-7+G0/2/COR8pwteYFqHIVYfQpuEiO2HXwJrhCBJVgrNrl9O5eaUoJVDGXUJX+0RpGncNVTuestexjk1afj01wQ== handlebars@^4.0.11, handlebars@^4.0.2: version "4.1.0" @@ -7944,11 +7942,6 @@ node-html-parser@^2.0.2: dependencies: he "1.2.0" -node-fetch@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== - node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -8249,9 +8242,6 @@ object.values@^1.0.4: function-bind "^1.1.1" has "^1.0.3" -<<<<<<< HEAD -on-finished@^2.3.0, on-finished@~2.3.0: -======= ohmyfetch@latest: version "0.1.6" resolved "https://registry.yarnpkg.com/ohmyfetch/-/ohmyfetch-0.1.6.tgz#fe137b46ee5b5598815f988315bb4254e2b5cb12" @@ -8259,8 +8249,7 @@ ohmyfetch@latest: dependencies: node-fetch "^2.6.1" -on-finished@~2.3.0: ->>>>>>> upstream/master +on-finished@^2.3.0, on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=