diff --git a/docs/captcha-providers.md b/docs/captcha-providers.md index c1fe51b..a735dd8 100644 --- a/docs/captcha-providers.md +++ b/docs/captcha-providers.md @@ -25,3 +25,15 @@ captchaProvider: { } }, ``` + +## hCaptcha + +``` +captchaProvider: { + name: 'hcaptcha', + config: { + secretKey: 'your-key', + minimumScore: 0.5 + } +}, +``` \ No newline at end of file diff --git a/server/services/captcha-providers/hcaptcha.js b/server/services/captcha-providers/hcaptcha.js new file mode 100644 index 0000000..e604541 --- /dev/null +++ b/server/services/captcha-providers/hcaptcha.js @@ -0,0 +1,55 @@ +'use strict' +const axios = require('axios') + +module.exports = ({strapi}) => ({ + async validate(token) { + if (!token) { + strapi.log.error('Missing hCaptcha Token') + return { + valid: false, + message: 'Missing token', + code: 400 + } + } + const secret_key = strapi.config.get('plugin.ezforms.captchaProvider.config.secretKey') + const url = `https://api.hcaptcha.com/siteverify?secret=${secret_key}&response=${token}` + let hcaptcha_verify + try { + hcaptcha_verify = await axios.post(url) + } catch (e) { + strapi.log.error(e) + return { + + valid: false, + message: 'Unable to verify captcha', + code: 500 + + } + } + + if (!hcaptcha_verify.data.success) { + strapi.log.error('hcaptcha_verify') + strapi.log.error(hcaptcha_verify) + return { + valid: false, + message: 'Unable to verify captcha', + code: 500 + } + } + + if (hcaptcha_verify.data.score < strapi.config.get('plugin.ezforms.captchaProvider.config.score')) { + return { + + valid: false, + message: 'Score Not High Enough', + code: 400 + + } + } + return { + score: hcaptcha_verify.data.score, + valid: true + } + }, +}) + diff --git a/server/services/index.js b/server/services/index.js index 1c2470d..96602d0 100644 --- a/server/services/index.js +++ b/server/services/index.js @@ -1,12 +1,14 @@ 'use strict' const recaptcha = require('./captcha-providers/recaptcha') +const hcaptcha = require('./captcha-providers/hcaptcha') const email = require('./notification-providers/email') const twilio = require('./notification-providers/twilio') const formatData = require('./utils/formatData') module.exports = { recaptcha, + hcaptcha, email, twilio, formatData diff --git a/tests/hcaptcha.test.js b/tests/hcaptcha.test.js new file mode 100644 index 0000000..3a6cccd --- /dev/null +++ b/tests/hcaptcha.test.js @@ -0,0 +1,105 @@ +const hcaptcha = require('../server/services/captcha-providers/hcaptcha') +const axios = require('axios') + + +describe('hCaptcha Captcha Provider', function () { + let strapi + + beforeEach(async function () { + strapi = { + config: { + get: jest.fn() + }, + log: { + error: jest.fn() + } + } + + }) + + test('should return error if no token is provided', async function () { + let result = await hcaptcha({strapi}).validate() + + expect(result).toEqual({ + valid: false, + message: 'Missing token', + code: 400 + }) + + }) + test('should return error if captcha post failed', async function () { + + jest.spyOn(axios, 'post').mockRejectedValueOnce(new Error('Unable to verify captcha')) + + let result = await hcaptcha({strapi}).validate('fakeToken') + + await expect(result).toEqual({ + valid: false, + message: 'Unable to verify captcha', + code: 500 + }) + + }) + + test('should return error if captcha is unsuccessful', async function () { + + jest.spyOn(axios, 'post').mockResolvedValueOnce({ + data: { + success: false, + } + }) + + let result = await hcaptcha({strapi}).validate('fakeToken') + + await expect(result).toEqual({ + valid: false, + message: 'Unable to verify captcha', + code: 500 + }) + + }) + test('should reject due to low score', async function () { + + jest.spyOn(axios, 'post').mockResolvedValueOnce({ + data: { + success: true, + score: 0.4, + } + }) + strapi.config.get = jest.fn(() => { + return .5 + }) + + let result = await hcaptcha({strapi}).validate('fakeToken') + + await expect(result).toEqual({ + + valid: false, + message: 'Score Not High Enough', + code: 400 + + }) + + }) + test('should be valid captcha', async function () { + + jest.spyOn(axios, 'post').mockResolvedValueOnce({ + data: { + success: true, + score: 0.8, + } + }) + strapi.config.get = jest.fn(() => { + return .5 + }) + + let result = await hcaptcha({strapi}).validate('fakeToken') + + await expect(result).toEqual({ + score: .8, + valid: true + }) + + }) + +})