Skip to content

Commit 054216a

Browse files
authored
Merge pull request #12 from agentur/master
Made changes to support the V3 Captcha
2 parents 2cdfd6e + 2864ae2 commit 054216a

File tree

17 files changed

+370
-23
lines changed

17 files changed

+370
-23
lines changed

Classes/FormElements/Recaptcha.php

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,23 +82,61 @@ public function onSubmit(FormRuntime $formRuntime, &$elementValue)
8282

8383
$properties = $this->getProperties();
8484
$recaptcha = new \ReCaptcha\ReCaptcha($properties['secretKey'], $requestMethod);
85+
8586
if (!empty($properties['expectedHostname'])) {
8687
$recaptcha->setExpectedHostname($properties['expectedHostname']);
8788
}
89+
/**
90+
* If one of the following three is set, it is the V3 Captcha.
91+
* Action and Threshold can't be empty due to validators, we still
92+
* need to look if they are set because it could be the V2 Captcha.
93+
*/
94+
if(isset($properties['action'])) {
95+
$recaptcha->setExpectedAction($properties['action']);
96+
}
97+
if(isset($properties['threshold'])) {
98+
$recaptcha->setScoreThreshold($properties['threshold']);
99+
}
100+
/**
101+
* Optional
102+
*/
103+
if(isset($properties['timeout'])) {
104+
$recaptcha->setChallengeTimeout($properties['timeout']);
105+
}
106+
88107
$resp = $recaptcha->verify($elementValue, $_SERVER['REMOTE_ADDR']);
89108

90109
if ($resp->isSuccess() === false) {
91-
$processingRule = $this
92-
->getRootForm()
93-
->getProcessingRule($this->getIdentifier());
94-
$processingRule
95-
->getProcessingMessages()
96-
->addError(
97-
new Error(
98-
'Please check the box "I am not a robot" and try again.',
99-
1450180934
100-
)
101-
);
110+
111+
$processingRule =
112+
$this
113+
->getRootForm()
114+
->getProcessingRule($this->getIdentifier());
115+
/**
116+
* If the Check failed and it's the V3-Captcha, identified by
117+
* $properties['action'] it will return an diffrent Error.
118+
* The Error 'Please check the box "I am not a robot" and try again.'
119+
* Is not suitable for the V3 Captcha.
120+
*/
121+
if(isset($properties['action'])) {
122+
$processingRule
123+
->getProcessingMessages()
124+
->addError(
125+
new Error(
126+
'The reCaptcha-Check failed.',
127+
1221560719
128+
)
129+
);
130+
} else {
131+
$processingRule
132+
->getProcessingMessages()
133+
->addError(
134+
new Error(
135+
'Please check the box "I am not a robot" and try again.',
136+
1450180934
137+
)
138+
);
139+
}
102140
}
103141
}
104142
}

Configuration/NodeTypes.FormElements.Captcha.yaml

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,84 @@
1010
# nodeTypes:
1111
# 'Wegmeister.Recaptcha:Captcha': false
1212

13+
# This is the recaptcha V3 implementation.
14+
# Didn't use Mixin because I would need to create
15+
# a new one for just one Propertie.
16+
'Wegmeister.Recaptcha:CaptchaV3':
17+
superTypes:
18+
'Neos.Form.Builder:FormElement': true
19+
ui:
20+
icon: 'icon-shield'
21+
group: 'form.custom'
22+
label: i18n
23+
properties:
24+
'siteKey':
25+
type: string
26+
defaultValue: ''
27+
ui:
28+
label: i18n
29+
reloadIfChanged: TRUE
30+
inspector:
31+
group: 'formElement'
32+
validation:
33+
'Neos.Neos/Validation/NotEmptyValidator': []
34+
'secretKey':
35+
type: string
36+
ui:
37+
label: i18n
38+
inspector:
39+
group: 'formElement'
40+
position: 'after siteKey'
41+
validation:
42+
'Neos.Neos/Validation/NotEmptyValidator': []
43+
'expectedHostname':
44+
type: string
45+
ui:
46+
label: i18n
47+
inspector:
48+
group: 'formElement'
49+
position: 'after secretKey'
50+
'action':
51+
type: string
52+
defaultValue: 'homepage'
53+
ui:
54+
label: i18n
55+
reloadIfChanged: TRUE
56+
inspector:
57+
group: 'formElement'
58+
position: 'after expectedHostname'
59+
editor: 'Neos.Neos/Inspector/Editors/SelectBoxEditor'
60+
editorOptions:
61+
values:
62+
'homepage':
63+
label: i18n
64+
'login':
65+
label: i18n
66+
'social':
67+
label: i18n
68+
'e-commerce':
69+
label: i18n
70+
'threshold':
71+
type: string
72+
defaultValue: 0.5
73+
ui:
74+
label: i18n
75+
reloadIfChanged: TRUE
76+
inspector:
77+
group: 'formElement'
78+
position: 'after action'
79+
validation:
80+
'Neos.Neos/Validation/NotEmptyValidator': []
81+
'timeout':
82+
type: string
83+
ui:
84+
label: i18n
85+
reloadIfChanged: TRUE
86+
inspector:
87+
group: 'formElement'
88+
position: 'after threshold'
89+
90+
# This is the recaptcha V2 implementation.
1391
'Wegmeister.Recaptcha:CaptchaV2':
1492
superTypes:
1593
'Neos.Form.Builder:FormElement': true
@@ -34,8 +112,6 @@
34112
group: 'formElement'
35113
position: 'after secretKey'
36114

37-
38-
39115
# This is the old recaptcha implementation.
40116
# It should be updated to the new version as soon as possible.
41117
# @deprecated since 2.2 will be removed with 3.0

Configuration/Settings.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ Neos:
1515
superTypes:
1616
- 'Wegmeister.Recaptcha:Captcha'
1717
implementationClassName: Wegmeister\Recaptcha\FormElements\Recaptcha
18+
'Wegmeister.Recaptcha:CaptchaV3':
19+
superTypes:
20+
- 'Wegmeister.Recaptcha:Captcha'
21+
renderingOptions:
22+
templatePathPattern: 'resource://Wegmeister.Recaptcha/Private/Form/CaptchaV3.html'
23+
implementationClassName: Wegmeister\Recaptcha\FormElements\Recaptcha
1824
validatorPresets:
1925
'Wegmeister.Recaptcha:IsValid':
2026
implementationClassName: Wegmeister\Recaptcha\Validation\Validator\IsValidValidator
Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
<f:layout name="Neos.Form:Field" />
22
<f:section name="field">
33
<f:form.hidden property="{element.identifier}" id="{element.uniqueIdentifier}" />
4-
<div class="g-recaptcha" id="g-recaptcha-{element.uniqueIdentifier}" data-sitekey="{element.properties.siteKey}"{f:if(condition: element.properties.theme, then: ' data-theme="{element.properties.theme}"')}{f:if(condition: element.properties.type, then: ' data-type="{element.properties.type}"')}{f:if(condition: element.properties.size, then: ' data-size="{element.properties.size}"')}{f:if(condition: element.properties.tabindex, then: ' data-tabindex="{element.properties.tabindex}"')}></div>
5-
<style>.g-recaptcha>div>div {margin: 0 auto;}</style>
6-
<f:if condition="{element.renderingOptions.includeClosestPolyfill}"><script src="{f:uri.resource(path: 'js/closest.min.js', package: 'Wegmeister.Recaptcha')}"></script></f:if>
7-
<script type="text/javascript">!function(d,w,m){<f:if condition="{element.renderingOptions.includeAPIScript}">w.hasReCaptchaAPI||(w.hasReCaptchaAPI=true,m=d.createElement('script'),m.async=1,m.defer=1,m.src='https://www.google.com/recaptcha/api.js{f:if(condition: element.properties.lang, then: "?hl={element.properties.lang}")}',d.body.appendChild(m));</f:if>w.gRecaptchaCount=w.gRecaptchaCount||0;var g=d.querySelectorAll(".g-recaptcha")[w.gRecaptchaCount],a=g.closest("form");a.addEventListener("submit",function(t){g.previousElementSibling.value=g.querySelector(".g-recaptcha-response").value},!1);w.gRecaptchaCount++}(document,window)</script>
8-
</f:section>
4+
<div class="g-recaptcha" id="g-recaptcha-{element.uniqueIdentifier}" data-sitekey="{element.properties.siteKey}"
5+
{f:if(condition: element.properties.theme, then: ' data-theme="{element.properties.theme}"' )}{f:if(condition:
6+
element.properties.type, then: ' data-type="{element.properties.type}"' )}{f:if(condition: element.properties.size,
7+
then: ' data-size="{element.properties.size}"' )}{f:if(condition: element.properties.tabindex,
8+
then: ' data-tabindex="{element.properties.tabindex}"' )}></div>
9+
<style>
10+
.g-recaptcha>div>div {
11+
margin: 0 auto;
12+
}
13+
</style>
14+
<f:if condition="{element.renderingOptions.includeClosestPolyfill}">
15+
<script src="{f:uri.resource(path: 'js/closest.min.js', package: 'Wegmeister.Recaptcha')}"></script>
16+
</f:if>
17+
<script
18+
type="text/javascript">!function (d, w, m) { <f: if condition="{element.renderingOptions.includeAPIScript}">w.hasReCaptchaAPI||(w.hasReCaptchaAPI=true,m=d.createElement('script'),m.async=1,m.defer=1,m.src='https://www.google.com/recaptcha/api.js{f: if(condition: element.properties.lang, then: "?hl={element.properties.lang}")}',d.body.appendChild(m));</f: if> w.gRecaptchaCount= w.gRecaptchaCount || 0; var g = d.querySelectorAll(".g-recaptcha")[w.gRecaptchaCount], a = g.closest("form"); a.addEventListener("submit", function (t) { g.previousElementSibling.value = g.querySelector(".g-recaptcha-response").value }, !1); w.gRecaptchaCount++ }(document, window)</script>
19+
</f:section>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<f:layout name="Neos.Form:Field" />
2+
3+
<f:section name="field">
4+
<f:form.hidden property="{element.identifier}" id="{element.uniqueIdentifier}" />
5+
<f:if condition="{element.renderingOptions.includeClosestPolyfill}">
6+
<script src="{f:uri.resource(path: 'js/closest.min.js', package: 'Wegmeister.Recaptcha')}"></script>
7+
</f:if>
8+
<script type="text/javascript">
9+
window.grecaptchaElements = window.grecaptchaElements || [];
10+
var siteKey = '{element.properties.siteKey}';
11+
var action = '{element.properties.action}'
12+
var selector = '#{element.uniqueIdentifier}';
13+
window.grecaptchaElements.push({
14+
siteKey: siteKey,
15+
action: action,
16+
selector: selector
17+
});
18+
19+
window.grecaptchaOnload = function () {
20+
grecaptcha.ready(function () {
21+
grecaptchaElements.forEach(function (data) {
22+
grecaptcha.execute(data.siteKey, { action: data.action })
23+
.then(function (r) {
24+
document.querySelector(data.selector).value = r;
25+
});
26+
});
27+
});
28+
}
29+
</script>
30+
31+
<f:if condition="{element.renderingOptions.includeAPIScript}">
32+
<script type="text/javascript">
33+
!function (d, w, m) {
34+
w.hasReCaptchaAPI || (
35+
w.hasReCaptchaAPI = true,
36+
m = d.createElement('script'),
37+
m.async = 1,
38+
m.defer = 1,
39+
m.src = 'https://www.google.com/recaptcha/api.js?render={element.properties.siteKey}&onload=grecaptchaOnload',
40+
d.body.appendChild(m)
41+
);
42+
}(document, window)
43+
</script>
44+
</f:if>
45+
46+
</f:section>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
prototype(Wegmeister.Recaptcha:CaptchaV3.Definition) < prototype(Neos.Form.Builder:FormElement.Definition) {
2+
formElementType = 'Wegmeister.Recaptcha:CaptchaV3'
3+
4+
properties {
5+
siteKey = ${null}
6+
secretKey = ${null}
7+
expectedHostname = ${null}
8+
type = ${null}
9+
}
10+
}

Resources/Private/Translations/de/NodeTypes/CaptchaV2.xlf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
<file original="" product-name="Wegmeister.Recaptcha" source-language="en" datatype="plaintext" target-language="de">
44
<body>
55
<trans-unit id="ui.label" xml:space="preserve">
6-
<source>Captcha</source>
7-
<target>Captcha</target>
6+
<source>Captcha V2</source>
7+
<target>Captcha V2</target>
88
</trans-unit>
99
<trans-unit id="properties.secretKey" xml:space="preserve">
1010
<source>Secret Key</source>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3+
<file original="" product-name="Wegmeister.Recaptcha" source-language="en" datatype="plaintext" target-language="de">
4+
<body>
5+
<trans-unit id="ui.label" xml:space="preserve">
6+
<source>Captcha V3</source>
7+
<target>Captcha V3</target>
8+
</trans-unit>
9+
<trans-unit id="properties.siteKey" xml:space="preserve">
10+
<source>Site Key</source>
11+
<target>Websiteschlüssel</target>
12+
</trans-unit>
13+
<trans-unit id="properties.secretKey" xml:space="preserve">
14+
<source>Secret Key</source>
15+
<target>Geheimer Schlüssel</target>
16+
</trans-unit>
17+
<trans-unit id="properties.expectedHostname" xml:space="preserve">
18+
<source>Expected hostname (optional, allows further validation)</source>
19+
<target>Erwarteter Hostname (optional, ermöglicht erweiterte Validierung)</target>
20+
</trans-unit>
21+
<trans-unit id="properties.action" xml:space="preserve">
22+
<source>Action</source>
23+
<target>Aktion</target>
24+
</trans-unit>
25+
<trans-unit id="properties.theme.selectBoxEditor.values.homepage" xml:space="preserve">
26+
<source>Homepage</source>
27+
<target>Homepage</target>
28+
</trans-unit>
29+
<trans-unit id="properties.theme.selectBoxEditor.values.login" xml:space="preserve">
30+
<source>Login</source>
31+
<target>Login</target>
32+
</trans-unit>
33+
<trans-unit id="properties.theme.selectBoxEditor.values.social" xml:space="preserve">
34+
<source>Social</source>
35+
<target>Social</target>
36+
</trans-unit>
37+
<trans-unit id="properties.theme.selectBoxEditor.values.e-commerce" xml:space="preserve">
38+
<source>E-Commerce</source>
39+
<target>E-Commerce</target>
40+
</trans-unit>
41+
<trans-unit id="properties.threshold" xml:space="preserve">
42+
<source>Threshold (from 0.0 to 1.0)</source>
43+
<target>Threshold (from 0.0 to 1.0)</target>
44+
</trans-unit>
45+
<trans-unit id="properties.timeout" xml:space="preserve">
46+
<source>Timeout (In Seconds without trailing 's')</source>
47+
<target>Timeout (In Seconds without trailing 's')</target>
48+
</trans-unit>
49+
</body>
50+
</file>
51+
</xliff>

Resources/Private/Translations/de/ValidationErrors.xlf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
<source>This property is required</source>
2020
<target xml:lang="de"></target>
2121
</trans-unit>
22+
<trans-unit id="1221560719" xml:space="preserve" approved="yes">
23+
<source>The reCaptcha-Check failed.</source>
24+
<target xml:lang="de">Der reCaptcha-Check ist fehlgeschlagen.</target>
25+
</trans-unit>
2226
</body>
2327
</file>
2428
</xliff>

Resources/Private/Translations/en/NodeTypes/CaptchaV2.xlf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<file original="" product-name="Wegmeister.Recaptcha" source-language="en" datatype="plaintext">
44
<body>
55
<trans-unit id="ui.label" xml:space="preserve">
6-
<source>Captcha</source>
6+
<source>Captcha V2</source>
77
</trans-unit>
88
<trans-unit id="properties.secretKey" xml:space="preserve">
99
<source>Secret Key</source>

0 commit comments

Comments
 (0)