Subversion Repositories oidplus

Compare Revisions

Regard whitespace Rev 1015 → Rev 1016

/trunk/TODO
1,7 → 1,5
OIDplus (OP org)
- in setup : let the user enter a canonical url for the base config ( preset it with the current canonical url )
- recaptcha v3 does not work ... implement it
- recaptcha v2 invisible is not invisible
 
TODO Reproduce:
- microsoft Edge freezing Login with vts challenge captcha, other browsers work fast
12,6 → 10,8
 
Small things:
- when you copy something into the clipboard, please show a toast message
- Show metatag "canonical" only if "canonical url" was set in base config. Don't let this meta tag be filled with automatically detected URLs.
- Setup: "None" CAPTCHA plugin should be the first option
 
Ideas by Simon T.:
- System status plugin: Check if file owners are mixed
211,6 → 211,7
- How can we make sure that example objects are not exported using oid-info.com export?
- Administrator-Interface: enable and disable object types
- detailled change-history of each oid
- Add a "nonce" to all inline JavaScripts and add this nonce to CSP. Then disallow inline-JavaScripts in CSP completely.
 
BUGS?
- BUG! RA is logged in, then it is deleted => the RA can still edit their OIDs, since their session is not destroyed
/trunk/doc/config_values.txt
105,6 → 105,12
 
OIDplus::baseConfig()->setValue('CAPTCHA_PLUGIN', 'None');
 
OIDplus::baseConfig()->setValue('RECAPTCHA_VERSION', OIDplusCaptchaPluginRecaptcha::RECAPTCHA_V2_CHECKBOX);
Possible values:
OIDplusCaptchaPluginRecaptcha::RECAPTCHA_V2_CHECKBOX
OIDplusCaptchaPluginRecaptcha::RECAPTCHA_V2_INVISIBLE
OIDplusCaptchaPluginRecaptcha::RECAPTCHA_V3
 
OIDplus::baseConfig()->setValue('RECAPTCHA_ENABLED', true);
Deprecated!
RECAPTCHA_ENABLED=true becomes CAPTCHA_PLUGIN=ReCAPTCHA
/trunk/includes/classes/OIDplus.class.php
348,11 → 348,13
if ($db_plugin_name === '') {
throw new OIDplusConfigInitializationException(_L('No database plugin selected in config file'));
}
if (!isset(self::$dbPlugins[$db_plugin_name])) {
foreach (self::$dbPlugins as $name => $plugin) {
if (strtolower($name) == strtolower($db_plugin_name)) {
return $plugin;
}
}
throw new OIDplusConfigInitializationException(_L('Database plugin "%1" not found',$db_plugin_name));
}
return self::$dbPlugins[$db_plugin_name];
}
 
private static $dbMainSession = null;
public static function db() {
397,7 → 399,7
 
if (OIDplus::baseConfig()->getValue('RECAPTCHA_ENABLED', false) && ($captcha_plugin_name === '')) {
// Legacy config file support!
$captcha_plugin_name = 'ReCAPTCHA';
$captcha_plugin_name = 'reCAPTCHA';
}
 
if ($captcha_plugin_name === '') $captcha_plugin_name = 'None'; // the "None" plugin is a must-have!
407,12 → 409,13
 
public static function getActiveCaptchaPlugin() {
$captcha_plugin_name = OIDplus::getActiveCaptchaPluginId();
 
if (!isset(self::$captchaPlugins[$captcha_plugin_name])) {
foreach (self::$captchaPlugins as $name => $plugin) {
if (strtolower($name) == strtolower($captcha_plugin_name)) {
return $plugin;
}
}
throw new OIDplusConfigInitializationException(_L('CAPTCHA plugin "%1" not found',$captcha_plugin_name));
}
return self::$captchaPlugins[$captcha_plugin_name];
}
 
# --- Page plugin
 
/trunk/includes/classes/OIDplusCaptchaPlugin.class.php
23,7 → 23,7
 
public abstract static function id(): string; // this is the name that is set to the configuration value OIDplus::baseConfig()->getValue('CAPTCHA_PLUGIN') to identify the CAPTCHA plugin
 
public abstract static function isVisible(): bool;
public abstract function isVisible(): bool;
 
public function captchaDomHead() { return ''; }
 
/trunk/plugins/viathinksoft/adminPages/050_oobe/oobe.php
62,7 → 62,7
echo '<form method="POST" action="oobe.php">';
echo '<input type="hidden" name="sent" value="1">';
 
if (OIDplus::getActiveCaptchaPlugin()::isVisible()) echo '<p><u>'._L('Step %1: Solve CAPTCHA',$step++).'</u></p>';
if (OIDplus::getActiveCaptchaPlugin()->isVisible()) echo '<p><u>'._L('Step %1: Solve CAPTCHA',$step++).'</u></p>';
if (isset($_REQUEST['sent'])) {
try {
OIDplus::getActiveCaptchaPlugin()->captchaVerify($_POST);
/trunk/plugins/viathinksoft/captcha/hcaptcha/OIDplusCaptchaPluginHCaptcha.class.php
25,7 → 25,7
return 'hCaptcha';
}
 
public static function isVisible(): bool {
public function isVisible(): bool {
return true;
}
 
/trunk/plugins/viathinksoft/captcha/none/OIDplusCaptchaPluginNone.class.php
25,7 → 25,7
return 'None';
}
 
public static function isVisible(): bool {
public function isVisible(): bool {
return false;
}
 
/trunk/plugins/viathinksoft/captcha/recaptcha/OIDplusCaptchaPluginRecaptcha.js
File deleted
/trunk/plugins/viathinksoft/captcha/recaptcha/OIDplusCaptchaPluginRecaptcha.class.php
2,7 → 2,7
 
/*
* OIDplus 2.0
* Copyright 2019 - 2021 Daniel Marschall, ViaThinkSoft
* Copyright 2019 - 2022 Daniel Marschall, ViaThinkSoft
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
21,60 → 21,93
 
class OIDplusCaptchaPluginRecaptcha extends OIDplusCaptchaPlugin {
 
/*public*/ const RECAPTCHA_V2_CHECKBOX = 1;
/*public*/ const RECAPTCHA_V2_INVISIBLE = 2;
/*public*/ const RECAPTCHA_V3 = 3;
 
public static function id(): string {
return 'ReCAPTCHA';
return 'reCAPTCHA'; // TODO: Now it is called "reCAPTCHA"
}
 
public static function isVisible(): bool {
// TODO: Also implement Google invisible CAPTCHAs
return true;
public function isVisible(): bool {
return OIDplus::baseConfig()->getValue('RECAPTCHA_VERSION', self::RECAPTCHA_V2_CHECKBOX) == self::RECAPTCHA_V2_CHECKBOX;
}
 
public function captchaDomHead() {
// Here you can add styles and scripts to be included into the HTML <head> part
return '<script>
function oidplus_captcha_response() {
return OIDplusCaptchaPluginRecaptcha.captchaResponse();
}
function oidplus_captcha_reset() {
return OIDplusCaptchaPluginRecaptcha.captchaReset();
}
</script>
<script src="https://www.google.com/recaptcha/api.js"></script>';
}
 
public function captchaGenerate($header_text=null, $footer_text=null) {
return ($header_text ? '<p>'.$header_text.'</p>' : '') .
'<noscript>'.
return '<noscript>'.
'<p><font color="red">'._L('You need to enable JavaScript to solve the CAPTCHA.').'</font></p>'.
'</noscript>'.
'<div id="g-recaptcha" class="g-recaptcha" data-sitekey="'.OIDplus::baseConfig()->getValue('RECAPTCHA_PUBLIC', '').'"></div>'.
//Don't use jQuery, because we might not have included it (e.g. in oobe.php)
//'<script> grecaptcha.render($("#g-recaptcha")[0], { "sitekey" : "'.OIDplus::baseConfig()->getValue('RECAPTCHA_PUBLIC', '').'" }); </script>'.
// TODO: oobe.php:formatted:42 Uncaught TypeError: grecaptcha.render is not a function at oobe.php:formatted:42 (but it still works?!)
'<script> grecaptcha.render(document.getElementById("g-recaptcha"), { "sitekey" : "'.OIDplus::baseConfig()->getValue('RECAPTCHA_PUBLIC', '').'" }); </script>'.
($footer_text ? '<p>'.$footer_text.'</p>' : '');
(!$this->isVisible() || !$header_text ? '' : '<p>'.$header_text.'</p>').
'<div id="recaptcha"></div>'.
'<input type="hidden" id="oidplus-recaptcha-response" name="oidplus-recaptcha-response">'.
'<script>'.
// ' $("form").submit(function(e){'.
// // TODO: The form must not be submitted before recaptchaFinished() is called!
// ' event.preventDefault();'.
// ' });'.
' var recaptchaLoaded = function() {'.
' console.log("reCAPTCHA ready");'.
' grecaptcha.render("recaptcha", {'.
' "sitekey": "'.OIDplus::baseConfig()->getValue('RECAPTCHA_PUBLIC', '').'",'.
($this->isVisible() ? '' :
' "size": "invisible",').
' "callback": function (token) {'. // TODO: also 'expired-callback' and 'error-callback'
' console.log("reCAPTCHA solved");'.
' document.getElementById("oidplus-recaptcha-response").value = token;'.
' }'.
' });'.
($this->isVisible() ? '' :
' grecaptcha.execute();').
' };'.
' var oidplus_captcha_response = function() {'.
' return document.getElementById("oidplus-recaptcha-response").value;'.
' };'.
' var oidplus_captcha_reset = function() {'.
' grecaptcha.reset();'.
($this->isVisible() ? '' :
' grecaptcha.execute();').
' };'.
'</script>'.
'<script src="https://www.google.com/recaptcha/api.js?onload=recaptchaLoaded&render=explicit" async defer></script>'.
(!$this->isVisible() || !$footer_text ? '' : '<p>'.$footer_text.'</p>');
}
 
public function captchaVerify($params, $fieldname=null) {
$secret=OIDplus::baseConfig()->getValue('RECAPTCHA_PRIVATE', '');
 
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)
if (is_null($fieldname)) $fieldname = 'oidplus-recaptcha-response'; // no individual AJAX field name (created by oidplus_captcha_response()) means that it is a plain POST event (e.g. by oobe.php)
_CheckParamExists($params, $fieldname);
$response=$params[$fieldname];
$verify=url_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.urlencode($secret).'&response='.urlencode($response));
 
$verify=url_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.urlencode($secret).'&response='.urlencode($response).'&remoteip='.urlencode($_SERVER['REMOTE_ADDR']));
if (!$verify) {
throw new OIDplusException(_L('CAPTCHA not successfully verified'));
throw new OIDplusException(_L('CAPTCHA not successfully verified').' (Web request failed)');
}
$captcha_success=@json_decode($verify);
if (!$captcha_success || ($captcha_success->success==false)) {
throw new OIDplusException(_L('CAPTCHA not successfully verified'));
$SCORE_THRESHOLD = 0.5; // TODO: Make Score configurable (only V3)
if (!$captcha_success) {
throw new OIDplusException(_L('CAPTCHA not successfully verified').' (JSON Decode failed)');
}
if ($captcha_success->success==false) {
throw new OIDplusException(_L('CAPTCHA not successfully verified').' (Failed)');
}
if (isset($captcha_success->score) && ($captcha_success->score < $SCORE_THRESHOLD)) {
throw new OIDplusException(_L('CAPTCHA not successfully verified').' (Score '.($captcha_success->score).' too low)');
}
}
 
public static function setupHTML(): string {
return '<div id="CAPTCHAPLUGIN_PARAMS_RECAPTCHA">'.
'<p>(<a href="https://developers.google.com/recaptcha/intro" target="_blank">'._L('more information and obtain key').'</a>)</p>'.
'<p>'._L('reCAPTCHA Version').'<br><select id="recaptcha_version">'.
' <option name="OIDplusCaptchaPluginRecaptcha::RECAPTCHA_V2_CHECKBOX">reCAPTCHA V2 Checkbox</option>'.
' <option name="OIDplusCaptchaPluginRecaptcha::RECAPTCHA_V2_INVISIBLE">reCAPTCHA V2 Invisible</option>'.
' <option name="OIDplusCaptchaPluginRecaptcha::RECAPTCHA_V3">reCAPTCHA V3</option>'.
'</select></p>'.
'<p>'._L('reCAPTCHA Public key').'<br><input id="recaptcha_public" type="text" onkeypress="rebuild()" onkeyup="rebuild()"> <span id="recaptcha_public_warn"></span></p>'.
'<p>'._L('reCAPTCHA Private key').'<br><input id="recaptcha_private" type="text" onkeypress="rebuild()" onkeyup="rebuild()"> <span id="recaptcha_private_warn"></span></p>'.
'</div>';
81,7 → 114,6
}
 
function httpHeaderCheck(&$http_headers) {
 
$http_headers["Content-Security-Policy"]["script-src"][] = "https://www.google.com/";
$http_headers["Content-Security-Policy"]["script-src"][] = "https://www.gstatic.com/";
$http_headers["Content-Security-Policy"]["img-src"][] = "https://www.google.com/";
88,7 → 120,6
$http_headers["Content-Security-Policy"]["img-src"][] = "https://www.gstatic.com/";
$http_headers["Content-Security-Policy"]["frame-src"][] = "https://www.google.com/";
$http_headers["Content-Security-Policy"]["frame-src"][] = "https://www.gstatic.com/";
 
}
 
}
/trunk/plugins/viathinksoft/captcha/recaptcha/OIDplusCaptchaPluginRecaptchaSetup.js
16,13 → 16,13
*/
 
captcha_plugin_combobox_change_callbacks.push(function(strPlugin) {
$("#CAPTCHAPLUGIN_PARAMS_RECAPTCHA")[0].style.display = (strPlugin == 'ReCAPTCHA') ? "Block" : "None";
$("#CAPTCHAPLUGIN_PARAMS_RECAPTCHA")[0].style.display = (strPlugin.toLowerCase() == 'reCAPTCHA'.toLowerCase()) ? "Block" : "None";
});
 
rebuild_callbacks.push(function() {
var e = $("#captcha_plugin")[0];
var strPlugin = e.options[e.selectedIndex].value;
if (strPlugin != 'ReCAPTCHA') return true;
if (strPlugin.toLowerCase() != 'reCAPTCHA'.toLowerCase()) return true;
 
$("#recaptcha_public")[0].innerHTML = '';
$("#recaptcha_private")[0].innerHTML = '';
33,7 → 33,7
if ($("#recaptcha_public")[0].value.length == 0)
{
$("#recaptcha_public_warn")[0].innerHTML = '<font color="red">'+_L('Please specify a public key!')+'</font>';
$("#config")[0].innerHTML = '<b>&lt?php</b><br><br><i>// ERROR: Please specify a ReCAPTCHA public key!</i>'; // do not translate
$("#config")[0].innerHTML = '<b>&lt?php</b><br><br><i>// ERROR: Please specify a reCAPTCHA public key!</i>'; // do not translate
error = true;
} else {
$("#recaptcha_public_warn")[0].innerHTML = '';
43,7 → 43,7
if ($("#recaptcha_private")[0].value.length == 0)
{
$("#recaptcha_private_warn")[0].innerHTML = '<font color="red">'+_L('Please specify a private key!')+'</font>';
$("#config")[0].innerHTML = '<b>&lt?php</b><br><br><i>// ERROR: Please specify a ReCAPTCHA private key!</i>'; // do not translate
$("#config")[0].innerHTML = '<b>&lt?php</b><br><br><i>// ERROR: Please specify a reCAPTCHA private key!</i>'; // do not translate
error = true;
} else {
$("#recaptcha_private_warn")[0].innerHTML = '';
55,7 → 55,8
captcha_rebuild_config_callbacks.push(function() {
var e = $("#captcha_plugin")[0];
var strPlugin = e.options[e.selectedIndex].value;
if (strPlugin != 'ReCAPTCHA') return '';
return 'OIDplus::baseConfig()->setValue(\'RECAPTCHA_PUBLIC\', \''+$("#recaptcha_public")[0].value+'\');<br>' +
if (strPlugin.toLowerCase() != 'reCAPTCHA'.toLowerCase()) return '';
return 'OIDplus::baseConfig()->setValue(\'RECAPTCHA_VERSION\', '+$("#recaptcha_version").find('option:selected').attr("name")+');<br>' +
'OIDplus::baseConfig()->setValue(\'RECAPTCHA_PUBLIC\', \''+$("#recaptcha_public")[0].value+'\');<br>' +
'OIDplus::baseConfig()->setValue(\'RECAPTCHA_PRIVATE\', \''+$("#recaptcha_private")[0].value+'\');<br>';
});
/trunk/plugins/viathinksoft/captcha/recaptcha/manifest.xml
23,7 → 23,6
</css>
 
<js>
<file>OIDplusCaptchaPluginRecaptcha.js</file>
</js>
 
<cssSetup>
/trunk/plugins/viathinksoft/captcha/vts_challenge/OIDplusCaptchaPluginVtsClientChallenge.class.php
25,7 → 25,7
return 'ViaThinkSoft Client Challenge';
}
 
public static function isVisible(): bool {
public function isVisible(): bool {
return false;
}
 
/trunk/plugins/viathinksoft/language/dede/messages.xml
8150,6 → 8150,14
</message>
<message>
<source><![CDATA[
reCAPTCHA Version
]]></source>
<target><![CDATA[
reCAPTCHA Version
]]></target>
</message>
<message>
<source><![CDATA[
shell access with Git client
]]></source>
<target><![CDATA[