Recaptcha::init()   B
last analyzed

Complexity

Conditions 8
Paths 5

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 13
c 1
b 0
f 0
nc 5
nop 0
dl 0
loc 25
rs 8.4444
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2024
6
 * @package Client
7
 * @subpackage Html
8
 */
9
10
11
namespace Aimeos\Client\Html\Cms\Page\Decorator;
12
13
14
/**
15
 * Recaptcha decorator for HTML clients
16
 *
17
 * @package Client
18
 * @subpackage Html
19
 */
20
class Recaptcha
21
	extends \Aimeos\Client\Html\Common\Decorator\Base
22
	implements \Aimeos\Client\Html\Common\Decorator\Iface
23
{
24
	/**
25
	 * Processes the input, e.g. store given values.
26
	 */
27
	public function init()
28
	{
29
		$view = $this->view();
30
		$context = $this->context();
31
		$key = $context->config()->get( 'resource/recaptcha/secretkey' );
32
33
		if( $key && $view->request()->getMethod() === 'POST' )
34
		{
35
			if( ( $token = $view->param( 'g-recaptcha-response' ) ) === null ) {
36
				throw new \Aimeos\Client\Html\Exception( $context->translate( 'client', 'reCAPTCHA token missing' ) );
37
			}
38
39
			$ip = $view->request()->getClientAddress();
40
			$url = 'https://www.google.com/recaptcha/api/siteverify?secret=' . $key . '&response=' . $token . '&remoteip=' . $ip;
41
42
			if( ( $result = file_get_contents( $url ) ) === false || ( $data = json_decode( $result ) ) === null ) {
43
				throw new \Aimeos\Client\Html\Exception( $context->translate( 'client', 'Invalid reCAPTCHA response' ) );
44
			}
45
46
			if( $data->success != true || $data->score < 0.5 ) {
47
				throw new \Aimeos\Client\Html\Exception( $context->translate( 'client', 'Your request is likely spam and was not executed' ) );
48
			}
49
		}
50
51
		$this->client()->init();
52
	}
53
54
55
	/**
56
	 * Returns the HTML string for insertion into the body.
57
	 *
58
	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
59
	 * @return string HTML body content
60
	 */
61
	public function body( string $uid = '' ) : string
62
	{
63
		$context = $this->context();
64
		$content = $this->client()->body( $uid );
65
66
		if( $key = $context->config()->get( 'resource/recaptcha/sitekey' ) )
67
		{
68
			$content .= '
69
				<script type="text/javascript" nonce="' . $context->nonce() . '">
70
					document.addEventListener("DOMContentLoaded", () => {
71
						const forms = document.querySelectorAll(".aimeos.cms-page form")
72
73
						if(forms.length) {
74
							const script = document.createElement("script");
75
76
							script.src = "https://www.google.com/recaptcha/api.js?render=' . $key . '";
77
							script.nonce = "' . $context->nonce() . '";
78
							script.type = "text/javascript";
79
							script.defer = true;
80
81
							document.body.appendChild(script);
82
						}
83
84
						forms.forEach(el => {
85
							el.addEventListener("submit", ev => {
86
								ev.preventDefault();
87
								grecaptcha.ready(() => {
88
									grecaptcha.execute("' . $key . '", { action: "cmspage" }).then(token => {
89
										const input = document.createElement("input");
90
										input.name = "g-recaptcha-response";
91
										input.type = "hidden";
92
										input.value = token;
93
94
										ev.target.appendChild(input);
95
										ev.target.submit();
96
									});
97
								});
98
							});
99
						});
100
					});
101
				</script>
102
			';
103
		}
104
105
		return $content;
106
	}
107
}
108