Subversion Repositories oidplus

Rev

Rev 1210 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1001 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
1086 daniel-mar 5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
1001 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
1050 daniel-mar 20
namespace ViaThinkSoft\OIDplus;
1001 daniel-mar 21
 
1086 daniel-mar 22
// phpcs:disable PSR1.Files.SideEffects
23
\defined('INSIDE_OIDPLUS') or die;
24
// phpcs:enable PSR1.Files.SideEffects
25
 
1210 daniel-mar 26
class OIDplusCaptchaPluginHCaptcha extends OIDplusCaptchaPlugin
27
        implements INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8  /* getNotifications */
28
{
1001 daniel-mar 29
 
1116 daniel-mar 30
        /**
31
         * @return string
32
         */
1001 daniel-mar 33
        public static function id(): string {
34
                return 'hCaptcha';
35
        }
36
 
1116 daniel-mar 37
        /**
38
         * @return bool
39
         */
1016 daniel-mar 40
        public function isVisible(): bool {
1001 daniel-mar 41
                return true;
42
        }
43
 
1116 daniel-mar 44
        /**
45
         * @param string|null $header_text
46
         * @param string|null $footer_text
47
         * @return string
48
         * @throws OIDplusException
49
         */
50
        public function captchaGenerate(string $header_text=null, string $footer_text=null): string {
1001 daniel-mar 51
                return ($header_text ? '<p>'.$header_text.'</p>' : '') .
52
                       '<noscript>'.
53
                       '<p><font color="red">'._L('You need to enable JavaScript to solve the CAPTCHA.').'</font></p>'.
54
                       '</noscript>'.
55
                       '<div id="h-captcha"></div>'.
1019 daniel-mar 56
                       '<script src="https://js.hcaptcha.com/1/api.js"></script>'.
1024 daniel-mar 57
                       '<script>'.
58
                       'OIDplusCaptchaPluginHCaptcha.captchaShow('.js_escape(OIDplus::baseConfig()->getValue('HCAPTCHA_SITEKEY', '')).')'.
59
                       '</script>'.
1001 daniel-mar 60
                       ($footer_text ? '<p>'.$footer_text.'</p>' : '');
61
        }
62
 
1116 daniel-mar 63
        /**
64
         * @param string[] $params
65
         * @param string|null $fieldname
66
         * @return void
67
         * @throws OIDplusException
68
         */
69
        public function captchaVerify(array $params, string $fieldname=null) {
1001 daniel-mar 70
                $sitekey=OIDplus::baseConfig()->getValue('HCAPTCHA_SITEKEY', '');
71
                $secret=OIDplus::baseConfig()->getValue('HCAPTCHA_SECRET', '');
72
 
73
                // Yes, it is really "g-recaptcha-response"!
74
                if (is_null($fieldname)) $fieldname = 'g-recaptcha-response'; // no individual field name (created by oidplus_captcha_response()) means that it is a plain POST event (e.g. by oobe.php)
75
                _CheckParamExists($params, $fieldname);
76
                $response=$params[$fieldname];
77
 
1149 daniel-mar 78
                $res = url_post_contents(
79
                        'https://hcaptcha.com/siteverify',
80
                        array(
81
                                "secret"   => $secret,
82
                                "response" => $response,
1345 daniel-mar 83
                                "remoteip" => OIDplus::getClientIpAddress() ?: '',
1149 daniel-mar 84
                                "sitekey"  => $sitekey
85
                        )
86
                );
87
 
88
                if ($res === false) {
89
                        throw new OIDplusException(_L('Communication with %1 server failed', 'hCaptcha'));
1001 daniel-mar 90
                }
91
 
92
                $captcha_success=@json_decode($res);
1162 daniel-mar 93
                if (!$captcha_success || !$captcha_success->success) {
1001 daniel-mar 94
                        throw new OIDplusException(_L('CAPTCHA not successfully verified').' ('.implode(", ",$captcha_success->{'error-codes'}).')');
95
                }
96
        }
97
 
1116 daniel-mar 98
        /**
99
         * @return string
100
         */
1001 daniel-mar 101
        public static function setupHTML(): string {
1181 daniel-mar 102
                $curl_status = url_post_contents_available(true, $reason) ? 1 : 0;
1001 daniel-mar 103
                return '<div id="CAPTCHAPLUGIN_PARAMS_HCAPTCHA">'.
104
                       '<p>(<a href="https://www.hcaptcha.com/" target="_blank">'._L('more information and obtain key').'</a>)</p>'.
105
                       '<p>'._L('hCaptcha Site key').'<br><input id="hcaptcha_sitekey" type="text" onkeypress="rebuild()" onkeyup="rebuild()"> <span id="hcaptcha_sitekey_warn"></span></p>'.
106
                       '<p>'._L('hCaptcha Secret').'<br><input id="hcaptcha_secret" type="text" onkeypress="rebuild()" onkeyup="rebuild()"> <span id="hcaptcha_secret_warn"></span></p>'.
1003 daniel-mar 107
                       '<input id="hcaptcha_curl_status" value="'.$curl_status.'" type="hidden">'.
1181 daniel-mar 108
                       (!$curl_status ? '<p><font color="red">'._L('The %1 plugin cannot connect to the Internet.', self::id()).' '.$reason.'</font></p>' : '').
1001 daniel-mar 109
                       '</div>';
110
        }
111
 
1116 daniel-mar 112
        /**
113
         * @param array $http_headers
114
         * @return void
115
         */
116
        function httpHeaderCheck(array &$http_headers) {
1001 daniel-mar 117
 
118
                // If you use CSP headers, please add the following to your configuration:
119
                // script-src should include https://hcaptcha.com, https://*.hcaptcha.com
120
                $http_headers["Content-Security-Policy"]["script-src"][] = "https://hcaptcha.com";
121
                $http_headers["Content-Security-Policy"]["script-src"][] = "https://*.hcaptcha.com";
122
                // frame-src should include https://hcaptcha.com, https://*.hcaptcha.com
123
                $http_headers["Content-Security-Policy"]["frame-src"][] = "https://hcaptcha.com";
124
                $http_headers["Content-Security-Policy"]["frame-src"][] = "https://*.hcaptcha.com";
125
                // style-src should include https://hcaptcha.com, https://*.hcaptcha.com
126
                $http_headers["Content-Security-Policy"]["style-src"][] = "https://hcaptcha.com";
127
                $http_headers["Content-Security-Policy"]["style-src"][] = "https://*.hcaptcha.com";
128
                // connect-src should include https://hcaptcha.com, https://*.hcaptcha.com
129
                $http_headers["Content-Security-Policy"]["connect-src"][] = "https://hcaptcha.com";
130
                $http_headers["Content-Security-Policy"]["connect-src"][] = "https://*.hcaptcha.com";
131
 
132
                //If you are an enterprise customer and would like to enable additional verification to be performed, you can optionally choose the following CSP strategy:
133
                //unsafe-eval and unsafe-inline should include https://hcaptcha.com, https://*.hcaptcha.com
134
                //$http_headers["Content-Security-Policy"]["unsafe-eval"][] = "https://hcaptcha.com";
135
                //$http_headers["Content-Security-Policy"]["unsafe-eval"][] = "https://*.hcaptcha.com";
136
                //$http_headers["Content-Security-Policy"]["unsafe-inline"][] = "https://hcaptcha.com";
137
                //$http_headers["Content-Security-Policy"]["unsafe-inline"][] = "https://*.hcaptcha.com";
138
 
139
        }
140
 
1210 daniel-mar 141
        /**
142
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8
143
         * @param string|null $user
144
         * @return array
145
         * @throws OIDplusException
146
         */
147
        public function getNotifications(string $user=null): array {
148
                $notifications = array();
149
                if ((!$user || ($user == 'admin')) && OIDplus::authUtils()->isAdminLoggedIn()) {
150
                        if ($this->isActive()) {
151
                                if (!url_post_contents_available(true, $reason)) {
152
                                        $notifications[] = new OIDplusNotification('CRIT', _L('OIDplus plugin "%1" is enabled, but OIDplus cannot connect to the Internet.', htmlentities(self::id())) . ' ' . $reason);
153
                                }
154
                        }
155
                }
156
                return $notifications;
157
        }
158
 
1001 daniel-mar 159
}