diff --git a/dev/Settings/Admin/Security.js b/dev/Settings/Admin/Security.js index eec25904e..a891da2de 100644 --- a/dev/Settings/Admin/Security.js +++ b/dev/Settings/Admin/Security.js @@ -29,6 +29,7 @@ this.capaTwoFactorAuth = ko.observable(Settings.capa(Enums.Capa.TwoFactor)); this.verifySslCertificate = ko.observable(!!Settings.settingsGet('VerifySslCertificate')); + this.allowSelfSigned = ko.observable(!!Settings.settingsGet('AllowSelfSigned')); this.adminLogin = ko.observable(Settings.settingsGet('AdminLogin')); this.adminLoginError = ko.observable(false); @@ -138,6 +139,12 @@ 'VerifySslCertificate': bValue ? '1' : '0' }); }); + + this.allowSelfSigned.subscribe(function (bValue) { + Remote.saveAdminConfig(null, { + 'AllowSelfSigned': bValue ? '1' : '0' + }); + }); }; SecurityAdminSettings.prototype.onHide = function () diff --git a/dev/Styles/Components.less b/dev/Styles/Components.less index 750f9fd7d..cef5608ba 100644 --- a/dev/Styles/Components.less +++ b/dev/Styles/Components.less @@ -60,6 +60,9 @@ .e-component.material-design { + margin-top: 2px; + margin-bottom: 6px; + &.e-checkbox { .sub-checkbox-container { diff --git a/plugins/convert-headers-styles/CssToInlineStyles.php b/plugins/_depricated/convert-headers-styles/CssToInlineStyles.php similarity index 100% rename from plugins/convert-headers-styles/CssToInlineStyles.php rename to plugins/_depricated/convert-headers-styles/CssToInlineStyles.php diff --git a/plugins/convert-headers-styles/LICENSE b/plugins/_depricated/convert-headers-styles/LICENSE similarity index 100% rename from plugins/convert-headers-styles/LICENSE rename to plugins/_depricated/convert-headers-styles/LICENSE diff --git a/plugins/convert-headers-styles/README b/plugins/_depricated/convert-headers-styles/README similarity index 100% rename from plugins/convert-headers-styles/README rename to plugins/_depricated/convert-headers-styles/README diff --git a/plugins/convert-headers-styles/VERSION b/plugins/_depricated/convert-headers-styles/VERSION similarity index 100% rename from plugins/convert-headers-styles/VERSION rename to plugins/_depricated/convert-headers-styles/VERSION diff --git a/plugins/convert-headers-styles/index.php b/plugins/_depricated/convert-headers-styles/index.php similarity index 100% rename from plugins/convert-headers-styles/index.php rename to plugins/_depricated/convert-headers-styles/index.php diff --git a/plugins/_depricated/recaptcha/LICENSE b/plugins/_depricated/recaptcha/LICENSE new file mode 100644 index 000000000..271342337 --- /dev/null +++ b/plugins/_depricated/recaptcha/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 RainLoop Team + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/_depricated/recaptcha/README b/plugins/_depricated/recaptcha/README new file mode 100644 index 000000000..17e4ab032 --- /dev/null +++ b/plugins/_depricated/recaptcha/README @@ -0,0 +1,3 @@ +A CAPTCHA is a program that can generate and grade tests that humans can pass but current computer programs cannot. +For example, humans can read distorted text as the one shown below, but current computer programs can't. +More info at http://www.google.com/recaptcha \ No newline at end of file diff --git a/plugins/_depricated/recaptcha/VERSION b/plugins/_depricated/recaptcha/VERSION new file mode 100644 index 000000000..872765e5f --- /dev/null +++ b/plugins/_depricated/recaptcha/VERSION @@ -0,0 +1 @@ +1.9 \ No newline at end of file diff --git a/plugins/recaptcha-2/index.php b/plugins/_depricated/recaptcha/index.php similarity index 69% rename from plugins/recaptcha-2/index.php rename to plugins/_depricated/recaptcha/index.php index b3426cc02..2875839f7 100644 --- a/plugins/recaptcha-2/index.php +++ b/plugins/_depricated/recaptcha/index.php @@ -1,6 +1,6 @@ UseLangs(true); - + $this->addJs('js/recaptcha.js'); - + $this->addHook('ajax.action-pre-call', 'AjaxActionPreCall'); $this->addHook('filter.ajax-response', 'FilterAjaxResponse'); $this->addTemplate('templates/PluginLoginReCaptchaGroup.html'); $this->addTemplateHook('Login', 'BottomControlGroup', 'PluginLoginReCaptchaGroup'); } - + /** * @return array */ public function configMapping() { return array( - \RainLoop\Plugins\Property::NewInstance('public_key')->SetLabel('Site key') + \RainLoop\Plugins\Property::NewInstance('public_key')->SetLabel('Public Key') ->SetAllowedInJs(true) ->SetDefaultValue(''), - \RainLoop\Plugins\Property::NewInstance('private_key')->SetLabel('Secret key') + \RainLoop\Plugins\Property::NewInstance('private_key')->SetLabel('Private Key') ->SetDefaultValue(''), - \RainLoop\Plugins\Property::NewInstance('theme')->SetLabel('Theme') - ->SetAllowedInJs(true) - ->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION) - ->SetDefaultValue(array('light', 'dark')), \RainLoop\Plugins\Property::NewInstance('error_limit')->SetLabel('Limit') ->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION) ->SetDefaultValue(array(0, 1, 2, 3, 4, 5)) @@ -45,7 +41,7 @@ class Recaptcha2Plugin extends \RainLoop\Plugins\AbstractPlugin */ private function getCaptchaCacherKey() { - return 'Captcha2/Login/'.\RainLoop\Utils::GetConnectionToken(); + return 'Captcha/Login/'.\RainLoop\Utils::GetConnectionToken(); } /** @@ -58,8 +54,8 @@ class Recaptcha2Plugin extends \RainLoop\Plugins\AbstractPlugin { $oCacher = $this->Manager()->Actions()->Cacher(); $sLimit = $oCacher && $oCacher->IsInited() ? $oCacher->Get($this->getCaptchaCacherKey()) : '0'; - - if (0 < \strlen($sLimit) && \is_numeric($sLimit)) + + if (0 < strlen($sLimit) && is_numeric($sLimit)) { $iConfigLimit -= (int) $sLimit; } @@ -73,7 +69,7 @@ class Recaptcha2Plugin extends \RainLoop\Plugins\AbstractPlugin */ public function FilterAppDataPluginSection($bAdmin, $bAuth, &$aData) { - if (!$bAdmin && !$bAuth && \is_array($aData)) + if (!$bAdmin && !$bAuth && is_array($aData)) { $aData['show_captcha_on_login'] = 1 > $this->getLimit(); } @@ -86,25 +82,18 @@ class Recaptcha2Plugin extends \RainLoop\Plugins\AbstractPlugin { if ('Login' === $sAction && 0 >= $this->getLimit()) { - $bResult = false; + require_once __DIR__.'/recaptchalib.php'; - $sResult = $this->Manager()->Actions()->Http()->GetUrlAsString( - 'https://www.google.com/recaptcha/api/siteverify?secret='. - \urlencode($this->Config()->Get('plugin', 'private_key', '')).'&response='. - \urlencode($this->Manager()->Actions()->GetActionParam('RecaptchaResponse', ''))); + $oResp = recaptcha_check_answer( + $this->Config()->Get('plugin', 'private_key', ''), + isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '', + $this->Manager()->Actions()->GetActionParam('RecaptchaChallenge', ''), + $this->Manager()->Actions()->GetActionParam('RecaptchaResponse', '') + ); - if ($sResult) + if (!$oResp || !isset($oResp->is_valid) || !$oResp->is_valid) { - $aResp = @\json_decode($sResult, true); - if (\is_array($aResp) && isset($aResp['success']) && $aResp['success']) - { - $bResult = true; - } - } - - if (!$bResult) - { - $this->Manager()->Actions()->Logger()->Write('RecaptchaResponse:'.$sResult); + $this->Manager()->Actions()->Logger()->WriteDump($oResp); throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CaptchaError); } } @@ -128,7 +117,7 @@ class Recaptcha2Plugin extends \RainLoop\Plugins\AbstractPlugin { $iLimit = 0; $sLimut = $oCacher->Get($sKey); - if (0 < \strlen($sLimut) && \is_numeric($sLimut)) + if (0 < strlen($sLimut) && is_numeric($sLimut)) { $iLimit = (int) $sLimut; } diff --git a/plugins/_depricated/recaptcha/js/recaptcha.js b/plugins/_depricated/recaptcha/js/recaptcha.js new file mode 100644 index 000000000..cbda2d216 --- /dev/null +++ b/plugins/_depricated/recaptcha/js/recaptcha.js @@ -0,0 +1,78 @@ + +$(function () { + + var + bStarted = false, + bShown = false + ; + + function ShowRecaptcha() + { + if (window.Recaptcha) + { + if (bShown) + { + window.Recaptcha.reload(); + } + else + { + window.Recaptcha.create(window.rl.pluginSettingsGet('recaptcha', 'public_key'), 'recaptcha-place', { + 'theme': 'custom', + 'lang': window.rl.settingsGet('Language') + }); + } + + bShown = true; + } + } + + function StartRecaptcha() + { + if (!window.Recaptcha) + { + $.getScript('//www.google.com/recaptcha/api/js/recaptcha_ajax.js', ShowRecaptcha); + } + else + { + ShowRecaptcha(); + } + } + + if (window.rl) + { + window.rl.addHook('view-model-on-show', function (sName, oViewModel) { + if (!bStarted && oViewModel && + ('View:RainLoop:Login' === sName || 'View/App/Login' === sName || 'LoginViewModel' === sName || 'LoginAppView' === sName) && + window.rl.pluginSettingsGet('recaptcha', 'show_captcha_on_login')) + { + bStarted = true; + StartRecaptcha(); + } + }); + + window.rl.addHook('ajax-default-request', function (sAction, oParameters) { + if ('Login' === sAction && oParameters && bShown && window.Recaptcha) + { + oParameters['RecaptchaChallenge'] = window.Recaptcha.get_challenge(); + oParameters['RecaptchaResponse'] = window.Recaptcha.get_response(); + } + }); + + window.rl.addHook('ajax-default-response', function (sAction, oData, sType) { + if ('Login' === sAction) + { + if (!oData || 'success' !== sType || !oData['Result']) + { + if (bShown && window.Recaptcha) + { + window.Recaptcha.reload(); + } + else if (oData && oData['Captcha']) + { + StartRecaptcha(); + } + } + } + }); + } +}); \ No newline at end of file diff --git a/plugins/recaptcha/langs/en.ini b/plugins/_depricated/recaptcha/langs/en.ini similarity index 98% rename from plugins/recaptcha/langs/en.ini rename to plugins/_depricated/recaptcha/langs/en.ini index 782b117df..87ed5f76c 100644 --- a/plugins/recaptcha/langs/en.ini +++ b/plugins/_depricated/recaptcha/langs/en.ini @@ -1,2 +1,2 @@ -[PLUGIN] +[PLUGIN] LABEL_ENTER_THE_WORDS_ABOVE = "Enter the words above" \ No newline at end of file diff --git a/plugins/recaptcha/langs/ru.ini b/plugins/_depricated/recaptcha/langs/ru.ini similarity index 98% rename from plugins/recaptcha/langs/ru.ini rename to plugins/_depricated/recaptcha/langs/ru.ini index bc91f3555..77329095c 100644 --- a/plugins/recaptcha/langs/ru.ini +++ b/plugins/_depricated/recaptcha/langs/ru.ini @@ -1,2 +1,2 @@ -[PLUGIN] +[PLUGIN] LABEL_ENTER_THE_WORDS_ABOVE = "Введите слова с изображения" \ No newline at end of file diff --git a/plugins/recaptcha/recaptchalib.php b/plugins/_depricated/recaptcha/recaptchalib.php similarity index 100% rename from plugins/recaptcha/recaptchalib.php rename to plugins/_depricated/recaptcha/recaptchalib.php diff --git a/plugins/_depricated/recaptcha/templates/PluginLoginReCaptchaGroup.html b/plugins/_depricated/recaptcha/templates/PluginLoginReCaptchaGroup.html new file mode 100644 index 000000000..4a15d78c6 --- /dev/null +++ b/plugins/_depricated/recaptcha/templates/PluginLoginReCaptchaGroup.html @@ -0,0 +1,14 @@ +
\ No newline at end of file diff --git a/plugins/recaptcha-2/js/recaptcha.js b/plugins/recaptcha-2/js/recaptcha.js deleted file mode 100644 index d824f5a18..000000000 --- a/plugins/recaptcha-2/js/recaptcha.js +++ /dev/null @@ -1,83 +0,0 @@ - -$(function () { - - var - nId = null, - bStarted = false - ; - - function ShowRecaptcha() - { - if (window.grecaptcha) - { - if (null === nId) - { - $('#recaptcha-place').show(); - - nId = window.grecaptcha.render('recaptcha-div', { - 'sitekey': window.rl.pluginSettingsGet('recaptcha-2', 'public_key'), - 'theme': window.rl.pluginSettingsGet('recaptcha-2', 'theme') - }); - } - } - } - - window.__globalShowRecaptcha = ShowRecaptcha; - - function StartRecaptcha() - { - if (!window.grecaptcha && window.rl) - { - $.getScript('https://www.google.com/recaptcha/api.js?onload=__globalShowRecaptcha&render=explicit&hl=' + window.rl.settingsGet('Language')); - } - else - { - ShowRecaptcha(); - } - } - - if (window.rl) - { - window.rl.addHook('user-login-submit', function (fSubmitResult) { - if (null !== nId && !window.grecaptcha.getResponse(nId)) - { - fSubmitResult(105); - } - }); - - window.rl.addHook('view-model-on-show', function (sName, oViewModel) { - if (!bStarted && oViewModel && - ('View:RainLoop:Login' === sName || 'View/App/Login' === sName || 'LoginViewModel' === sName || 'LoginAppView' === sName) && - window.rl.pluginSettingsGet('recaptcha-2', 'show_captcha_on_login')) - { - bStarted = true; - StartRecaptcha(); - } - }); - - window.rl.addHook('ajax-default-request', function (sAction, oParameters) { - if ('Login' === sAction && oParameters && null !== nId && window.grecaptcha) - { - oParameters['RecaptchaResponse'] = window.grecaptcha.getResponse(nId); - } - }); - - window.rl.addHook('ajax-default-response', function (sAction, oData, sType) { - if ('Login' === sAction) - { - if (!oData || 'success' !== sType || !oData['Result']) - { - if (null !== nId && window.grecaptcha) - { - window.grecaptcha.reset(nId); - } - else if (oData && oData['Captcha']) - { - StartRecaptcha(); - } - - } - } - }); - } -}); \ No newline at end of file diff --git a/plugins/recaptcha-2/templates/PluginLoginReCaptchaGroup.html b/plugins/recaptcha-2/templates/PluginLoginReCaptchaGroup.html deleted file mode 100644 index 1f4332f6e..000000000 --- a/plugins/recaptcha-2/templates/PluginLoginReCaptchaGroup.html +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/plugins/recaptcha/LICENSE b/plugins/recaptcha/LICENSE index 271342337..4aed64b3a 100644 --- a/plugins/recaptcha/LICENSE +++ b/plugins/recaptcha/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 RainLoop Team +Copyright (c) 2015 RainLoop Team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/plugins/recaptcha/README b/plugins/recaptcha/README index 17e4ab032..ee29dbafc 100644 --- a/plugins/recaptcha/README +++ b/plugins/recaptcha/README @@ -1,3 +1,3 @@ -A CAPTCHA is a program that can generate and grade tests that humans can pass but current computer programs cannot. +A CAPTCHA (v2) is a program that can generate and grade tests that humans can pass but current computer programs cannot. For example, humans can read distorted text as the one shown below, but current computer programs can't. More info at http://www.google.com/recaptcha \ No newline at end of file diff --git a/plugins/recaptcha/VERSION b/plugins/recaptcha/VERSION index 872765e5f..415b19fc3 100644 --- a/plugins/recaptcha/VERSION +++ b/plugins/recaptcha/VERSION @@ -1 +1 @@ -1.9 \ No newline at end of file +2.0 \ No newline at end of file diff --git a/plugins/recaptcha/index.php b/plugins/recaptcha/index.php index 2875839f7..4d1ab96ea 100644 --- a/plugins/recaptcha/index.php +++ b/plugins/recaptcha/index.php @@ -8,27 +8,31 @@ class RecaptchaPlugin extends \RainLoop\Plugins\AbstractPlugin public function Init() { $this->UseLangs(true); - + $this->addJs('js/recaptcha.js'); - + $this->addHook('ajax.action-pre-call', 'AjaxActionPreCall'); $this->addHook('filter.ajax-response', 'FilterAjaxResponse'); $this->addTemplate('templates/PluginLoginReCaptchaGroup.html'); $this->addTemplateHook('Login', 'BottomControlGroup', 'PluginLoginReCaptchaGroup'); } - + /** * @return array */ public function configMapping() { return array( - \RainLoop\Plugins\Property::NewInstance('public_key')->SetLabel('Public Key') + \RainLoop\Plugins\Property::NewInstance('public_key')->SetLabel('Site key') ->SetAllowedInJs(true) ->SetDefaultValue(''), - \RainLoop\Plugins\Property::NewInstance('private_key')->SetLabel('Private Key') + \RainLoop\Plugins\Property::NewInstance('private_key')->SetLabel('Secret key') ->SetDefaultValue(''), + \RainLoop\Plugins\Property::NewInstance('theme')->SetLabel('Theme') + ->SetAllowedInJs(true) + ->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION) + ->SetDefaultValue(array('light', 'dark')), \RainLoop\Plugins\Property::NewInstance('error_limit')->SetLabel('Limit') ->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION) ->SetDefaultValue(array(0, 1, 2, 3, 4, 5)) @@ -41,7 +45,7 @@ class RecaptchaPlugin extends \RainLoop\Plugins\AbstractPlugin */ private function getCaptchaCacherKey() { - return 'Captcha/Login/'.\RainLoop\Utils::GetConnectionToken(); + return 'CaptchaNew/Login/'.\RainLoop\Utils::GetConnectionToken(); } /** @@ -54,8 +58,8 @@ class RecaptchaPlugin extends \RainLoop\Plugins\AbstractPlugin { $oCacher = $this->Manager()->Actions()->Cacher(); $sLimit = $oCacher && $oCacher->IsInited() ? $oCacher->Get($this->getCaptchaCacherKey()) : '0'; - - if (0 < strlen($sLimit) && is_numeric($sLimit)) + + if (0 < \strlen($sLimit) && \is_numeric($sLimit)) { $iConfigLimit -= (int) $sLimit; } @@ -69,7 +73,7 @@ class RecaptchaPlugin extends \RainLoop\Plugins\AbstractPlugin */ public function FilterAppDataPluginSection($bAdmin, $bAuth, &$aData) { - if (!$bAdmin && !$bAuth && is_array($aData)) + if (!$bAdmin && !$bAuth && \is_array($aData)) { $aData['show_captcha_on_login'] = 1 > $this->getLimit(); } @@ -82,18 +86,25 @@ class RecaptchaPlugin extends \RainLoop\Plugins\AbstractPlugin { if ('Login' === $sAction && 0 >= $this->getLimit()) { - require_once __DIR__.'/recaptchalib.php'; + $bResult = false; - $oResp = recaptcha_check_answer( - $this->Config()->Get('plugin', 'private_key', ''), - isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '', - $this->Manager()->Actions()->GetActionParam('RecaptchaChallenge', ''), - $this->Manager()->Actions()->GetActionParam('RecaptchaResponse', '') - ); + $sResult = $this->Manager()->Actions()->Http()->GetUrlAsString( + 'https://www.google.com/recaptcha/api/siteverify?secret='. + \urlencode($this->Config()->Get('plugin', 'private_key', '')).'&response='. + \urlencode($this->Manager()->Actions()->GetActionParam('RecaptchaResponse', ''))); - if (!$oResp || !isset($oResp->is_valid) || !$oResp->is_valid) + if ($sResult) { - $this->Manager()->Actions()->Logger()->WriteDump($oResp); + $aResp = @\json_decode($sResult, true); + if (\is_array($aResp) && isset($aResp['success']) && $aResp['success']) + { + $bResult = true; + } + } + + if (!$bResult) + { + $this->Manager()->Actions()->Logger()->Write('RecaptchaResponse:'.$sResult); throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CaptchaError); } } @@ -109,6 +120,7 @@ class RecaptchaPlugin extends \RainLoop\Plugins\AbstractPlugin { $oCacher = $this->Manager()->Actions()->Cacher(); $iConfigLimit = (int) $this->Config()->Get('plugin', 'error_limit', 0); + $sKey = $this->getCaptchaCacherKey(); if (0 < $iConfigLimit && $oCacher && $oCacher->IsInited()) @@ -117,7 +129,7 @@ class RecaptchaPlugin extends \RainLoop\Plugins\AbstractPlugin { $iLimit = 0; $sLimut = $oCacher->Get($sKey); - if (0 < strlen($sLimut) && is_numeric($sLimut)) + if (0 < \strlen($sLimut) && \is_numeric($sLimut)) { $iLimit = (int) $sLimut; } diff --git a/plugins/recaptcha/js/recaptcha.js b/plugins/recaptcha/js/recaptcha.js index cbda2d216..7b1802d31 100644 --- a/plugins/recaptcha/js/recaptcha.js +++ b/plugins/recaptcha/js/recaptcha.js @@ -1,78 +1,89 @@ +(function ($, window) { -$(function () { + $(function () { - var - bStarted = false, - bShown = false - ; + var + nId = null, + bStarted = false + ; - function ShowRecaptcha() - { - if (window.Recaptcha) + function ShowRecaptcha() { - if (bShown) + if (window.grecaptcha) { - window.Recaptcha.reload(); - } - else - { - window.Recaptcha.create(window.rl.pluginSettingsGet('recaptcha', 'public_key'), 'recaptcha-place', { - 'theme': 'custom', - 'lang': window.rl.settingsGet('Language') - }); - } - - bShown = true; - } - } - - function StartRecaptcha() - { - if (!window.Recaptcha) - { - $.getScript('//www.google.com/recaptcha/api/js/recaptcha_ajax.js', ShowRecaptcha); - } - else - { - ShowRecaptcha(); - } - } - - if (window.rl) - { - window.rl.addHook('view-model-on-show', function (sName, oViewModel) { - if (!bStarted && oViewModel && - ('View:RainLoop:Login' === sName || 'View/App/Login' === sName || 'LoginViewModel' === sName || 'LoginAppView' === sName) && - window.rl.pluginSettingsGet('recaptcha', 'show_captcha_on_login')) - { - bStarted = true; - StartRecaptcha(); - } - }); - - window.rl.addHook('ajax-default-request', function (sAction, oParameters) { - if ('Login' === sAction && oParameters && bShown && window.Recaptcha) - { - oParameters['RecaptchaChallenge'] = window.Recaptcha.get_challenge(); - oParameters['RecaptchaResponse'] = window.Recaptcha.get_response(); - } - }); - - window.rl.addHook('ajax-default-response', function (sAction, oData, sType) { - if ('Login' === sAction) - { - if (!oData || 'success' !== sType || !oData['Result']) + if (null === nId) { - if (bShown && window.Recaptcha) + var oEl = $('#recaptcha-div'); + if (oEl && oEl[0]) { - window.Recaptcha.reload(); - } - else if (oData && oData['Captcha']) - { - StartRecaptcha(); + oEl.show(); + nId = window.grecaptcha.render(oEl[0], { + 'sitekey': window.rl.pluginSettingsGet('recaptcha', 'public_key'), + 'theme': window.rl.pluginSettingsGet('recaptcha', 'theme') + }); } } } - }); - } -}); \ No newline at end of file + } + + window.__globalShowRecaptcha = ShowRecaptcha; + + function StartRecaptcha() + { + if (!window.grecaptcha && window.rl) + { + $.getScript('https://www.google.com/recaptcha/api.js?onload=__globalShowRecaptcha&render=explicit&hl=' + window.rl.settingsGet('Language')); + } + else + { + ShowRecaptcha(); + } + } + + if (window.rl) + { + window.rl.addHook('user-login-submit', function (fSubmitResult) { + if (null !== nId && !window.grecaptcha.getResponse(nId)) + { + fSubmitResult(105); + } + }); + + window.rl.addHook('view-model-on-show', function (sName, oViewModel) { + if (!bStarted && oViewModel && + ('View:RainLoop:Login' === sName || 'View/App/Login' === sName || 'LoginViewModel' === sName || 'LoginAppView' === sName) && + window.rl.pluginSettingsGet('recaptcha', 'show_captcha_on_login')) + { + bStarted = true; + StartRecaptcha(); + } + }); + + window.rl.addHook('ajax-default-request', function (sAction, oParameters) { + if ('Login' === sAction && oParameters && null !== nId && window.grecaptcha) + { + oParameters['RecaptchaResponse'] = window.grecaptcha.getResponse(nId); + } + }); + + window.rl.addHook('ajax-default-response', function (sAction, oData, sType) { + if ('Login' === sAction) + { + if (!oData || 'success' !== sType || !oData['Result']) + { + if (null !== nId && window.grecaptcha) + { + window.grecaptcha.reset(nId); + } + else if (oData && oData['Captcha']) + { + StartRecaptcha(); + } + + } + } + }); + } + }); + +}($, window)); \ No newline at end of file diff --git a/plugins/recaptcha/templates/PluginLoginReCaptchaGroup.html b/plugins/recaptcha/templates/PluginLoginReCaptchaGroup.html index 4a15d78c6..9749c8164 100644 --- a/plugins/recaptcha/templates/PluginLoginReCaptchaGroup.html +++ b/plugins/recaptcha/templates/PluginLoginReCaptchaGroup.html @@ -1,14 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php b/rainloop/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php index e08303806..38c3ed618 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php @@ -136,6 +136,7 @@ class ImapClient extends \MailSo\Net\NetClient * @param int $iPort = 143 * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT * @param bool $bVerifySsl = false + * @param bool $bAllowSelfSigned = true * * @return \MailSo\Imap\ImapClient * @@ -144,11 +145,12 @@ class ImapClient extends \MailSo\Net\NetClient * @throws \MailSo\Imap\Exceptions\Exception */ public function Connect($sServerName, $iPort = 143, - $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, $bVerifySsl = false) + $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, + $bVerifySsl = false, $bAllowSelfSigned = true) { $this->aTagTimeouts['*'] = \microtime(true); - parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl); + parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned); $this->parseResponseWithValidation('*', true); diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Net/NetClient.php b/rainloop/v/0.0.0/app/libraries/MailSo/Net/NetClient.php index 7c920969c..a4fee9941 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Net/NetClient.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Net/NetClient.php @@ -195,6 +195,7 @@ abstract class NetClient * @param int $iPort * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT * @param bool $bVerifySsl = false + * @param bool $bAllowSelfSigned = true * * @return void * @@ -203,7 +204,8 @@ abstract class NetClient * @throws \MailSo\Net\Exceptions\SocketCanNotConnectToHostException */ public function Connect($sServerName, $iPort, - $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, $bVerifySsl = false) + $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, + $bVerifySsl = false, $bAllowSelfSigned = true) { if (!\MailSo\Base\Validator::NotEmptyString($sServerName, true) || !\MailSo\Base\Validator::PortInt($iPort)) { @@ -251,12 +253,14 @@ abstract class NetClient // $iErrorNo, $sErrorStr, $this->iConnectTimeOut); $bVerifySsl = !!$bVerifySsl; + $bAllowSelfSigned = $bVerifySsl ? !!$bAllowSelfSigned : true; + $aStreamContextSettings = array( 'ssl' => array( 'verify_host' => $bVerifySsl, 'verify_peer' => $bVerifySsl, 'verify_peer_name' => $bVerifySsl, - 'allow_self_signed' => !$bVerifySsl + 'allow_self_signed' => $bAllowSelfSigned ) ); diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Pop3/Pop3Client.php b/rainloop/v/0.0.0/app/libraries/MailSo/Pop3/Pop3Client.php index 700e0aa5a..a42e3a571 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Pop3/Pop3Client.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Pop3/Pop3Client.php @@ -63,6 +63,7 @@ class Pop3Client extends \MailSo\Net\NetClient * @param int $iPort = 110 * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT * @param bool $bVerifySsl = false + * @param bool $bAllowSelfSigned = null * * @return \MailSo\Pop3\Pop3Client * @@ -71,11 +72,13 @@ class Pop3Client extends \MailSo\Net\NetClient * @throws \MailSo\Pop3\Exceptions\ResponseException */ public function Connect($sServerName, $iPort = 110, - $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, $bVerifySsl = false) + $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, + $bVerifySsl = false, $bAllowSelfSigned = null) { $this->iRequestTime = microtime(true); - parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl); + parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned); + $this->validateResponse(); if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS( diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Poppassd/PoppassdClient.php b/rainloop/v/0.0.0/app/libraries/MailSo/Poppassd/PoppassdClient.php index bdbb4e5a7..90fc509c3 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Poppassd/PoppassdClient.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Poppassd/PoppassdClient.php @@ -51,6 +51,7 @@ class PoppassdClient extends \MailSo\Net\NetClient * @param int $iPort = 106 * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT * @param bool $bVerifySsl = false + * @param bool $bAllowSelfSigned = true * * @return \MailSo\Poppassd\PoppassdClient * @@ -59,11 +60,13 @@ class PoppassdClient extends \MailSo\Net\NetClient * @throws \MailSo\Poppassd\Exceptions\ResponseException */ public function Connect($sServerName, $iPort = 106, - $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, $bVerifySsl = false) + $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, + $bVerifySsl = false, $bAllowSelfSigned = true) { $this->iRequestTime = \microtime(true); - parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl); + parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned); + $this->validateResponse(); return $this; diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Sieve/ManageSieveClient.php b/rainloop/v/0.0.0/app/libraries/MailSo/Sieve/ManageSieveClient.php index 281e52a85..987e8ff33 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Sieve/ManageSieveClient.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Sieve/ManageSieveClient.php @@ -26,12 +26,12 @@ class ManageSieveClient extends \MailSo\Net\NetClient * @var array */ private $aCapa; - + /** * @var int */ private $iRequestTime; - + /** * @access protected */ @@ -55,7 +55,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient /** * @param string $sCapa - * + * * @return bool */ public function IsSupported($sCapa) @@ -72,7 +72,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient { return $this->IsSupported('SIEVE') && \in_array(\strtoupper($sModule), $this->aModules); } - + /** * @param string $sAuth * @@ -88,6 +88,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient * @param int $iPort * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT * @param bool $bVerifySsl = false + * @param bool $bAllowSelfSigned = true * * @return \MailSo\Sieve\ManageSieveClient * @@ -96,12 +97,13 @@ class ManageSieveClient extends \MailSo\Net\NetClient * @throws \MailSo\Sieve\Exceptions\ResponseException */ public function Connect($sServerName, $iPort, - $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, $bVerifySsl = false) + $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, + $bVerifySsl = false, $bAllowSelfSigned = true) { $this->iRequestTime = microtime(true); - parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl); - + parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned); + $mResponse = $this->parseResponse(); $this->validateResponse($mResponse); $this->parseStartupResponse($mResponse); @@ -122,7 +124,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'), \MailSo\Log\Enumerations\Type::ERROR, true); } - + return $this; } @@ -254,7 +256,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient return $aResult; } - + /** * @return array * @@ -273,7 +275,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient /** * @return \MailSo\Sieve\ManageSieveClient - * + * * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Sieve\Exceptions\NegativeResponseException */ @@ -286,7 +288,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient /** * @param string $sScriptName - * + * * @return string * * @throws \MailSo\Net\Exceptions\Exception @@ -365,10 +367,10 @@ class ManageSieveClient extends \MailSo\Net\NetClient public function SetActiveScript($sScriptName) { $this->sendRequestWithCheck('SETACTIVE "'.$sScriptName.'"'); - + return $this; } - + /** * @param string $sScriptName * @@ -409,7 +411,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient /** * @param string $sScriptName - * + * * @return bool * * @throws \MailSo\Net\Exceptions\Exception @@ -419,7 +421,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient { return $sScriptName === $this->GetActiveScriptName(); } - + /** * @param string $sLine * @return array|false @@ -532,7 +534,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient /** * @param string $sLine - * + * * @return string */ private function convertEndOfLine($sLine) @@ -560,7 +562,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient return $sLine; } - + /** * @return array|bool */ @@ -572,7 +574,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient do { $this->getNextBuffer(); - + $sLine = $this->sResponseBuffer; if (false === $sLine) { @@ -620,7 +622,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient /** * @param \MailSo\Log\Logger $oLogger - * + * * @return \MailSo\Sieve\ManageSieveClient * * @throws \MailSo\Base\Exceptions\InvalidArgumentException diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php b/rainloop/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php index 9b01f7c28..0758c0079 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php @@ -129,7 +129,7 @@ class SmtpClient extends \MailSo\Net\NetClient { $sEhloHost = empty($_SERVER['HTTP_HOST']) ? '' : \trim($_SERVER['HTTP_HOST']); } - + if (empty($sEhloHost)) { $sEhloHost = \function_exists('gethostname') ? \gethostname() : 'localhost'; @@ -151,6 +151,7 @@ class SmtpClient extends \MailSo\Net\NetClient * @param string $sEhloHost = '[127.0.0.1]' * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT * @param bool $bVerifySsl = false + * @param bool $bAllowSelfSigned = true * * @return \MailSo\Smtp\SmtpClient * @@ -159,11 +160,13 @@ class SmtpClient extends \MailSo\Net\NetClient * @throws \MailSo\Smtp\Exceptions\ResponseException */ public function Connect($sServerName, $iPort = 25, $sEhloHost = '[127.0.0.1]', - $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, $bVerifySsl = false) + $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, + $bVerifySsl = false, $bAllowSelfSigned = true) { $this->iRequestTime = microtime(true); - parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl); + parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned); + $this->validateResponse(220); $this->preLoginStartTLSAndEhloProcess($sEhloHost); @@ -184,7 +187,7 @@ class SmtpClient extends \MailSo\Net\NetClient public function Login($sLogin, $sPassword) { $sLogin = \MailSo\Base\Utils::IdnToAscii($sLogin); - + if ($this->IsAuthSupported('LOGIN')) { try @@ -313,7 +316,7 @@ class SmtpClient extends \MailSo\Net\NetClient { $sFrom = \MailSo\Base\Utils::IdnToAscii($sFrom, true); $sCmd = 'FROM:<'.$sFrom.'>'; - + $sSizeIfSupported = (string) $sSizeIfSupported; if (0 < \strlen($sSizeIfSupported) && \is_numeric($sSizeIfSupported) && $this->IsSupported('SIZE')) { @@ -538,7 +541,7 @@ class SmtpClient extends \MailSo\Net\NetClient { $this->sendRequestWithCheck('STARTTLS', 220); $this->EnableCrypto(); - + $this->ehloOrHelo($sEhloHost); } else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType) diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Actions.php b/rainloop/v/0.0.0/app/src/RainLoop/Actions.php index b7e009d58..ff9150adc 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/Actions.php @@ -1247,7 +1247,9 @@ class Actions $aResult['AdminDomain'] = APP_SITE; $aResult['UseTokenProtection'] = (bool) $oConfig->Get('security', 'csrf_protection', true); $aResult['EnabledPlugins'] = (bool) $oConfig->Get('plugins', 'enable', false); + $aResult['VerifySslCertificate'] = !!$oConfig->Get('ssl', 'verify_certificate', false); + $aResult['AllowSelfSigned'] = !!$oConfig->Get('ssl', 'allow_self_signed', true); $aDrivers = \class_exists('PDO') ? \PDO::getAvailableDrivers() : array(); $aResult['MySqlIsSupported'] = \is_array($aDrivers) ? \in_array('mysql', $aDrivers) : false; @@ -2613,6 +2615,8 @@ class Actions }); $this->setConfigFromParams($oConfig, 'VerifySslCertificate', 'ssl', 'verify_certificate', 'bool'); + $this->setConfigFromParams($oConfig, 'AllowSelfSigned', 'ssl', 'allow_self_signed', 'bool'); + $this->setConfigFromParams($oConfig, 'UseLocalProxyForExternalImages', 'labs', 'use_local_proxy_for_external_images', 'bool'); $this->setConfigFromParams($oConfig, 'AllowLanguagesOnSettings', 'webmail', 'allow_languages_on_settings', 'bool'); @@ -3100,8 +3104,10 @@ class Actions $oImapClient->SetTimeOuts($iConnectionTimeout); $iTime = \microtime(true); - $oImapClient->Connect($oDomain->IncHost(), $oDomain->IncPort(), - $oDomain->IncSecure(), !!$this->Config()->Get('ssl', 'verify_certificate')); + $oImapClient->Connect($oDomain->IncHost(), $oDomain->IncPort(), $oDomain->IncSecure(), + !!$this->Config()->Get('ssl', 'verify_certificate', false), + !!$this->Config()->Get('ssl', 'allow_self_signed', true) + ); $iImapTime = \microtime(true) - $iTime; $oImapClient->Disconnect(); @@ -3139,8 +3145,10 @@ class Actions $iTime = \microtime(true); $oSmtpClient->Connect($oDomain->OutHost(), $oDomain->OutPort(), - \MailSo\Smtp\SmtpClient::EhloHelper(), - $oDomain->OutSecure(), !!$this->Config()->Get('ssl', 'verify_certificate')); + \MailSo\Smtp\SmtpClient::EhloHelper(), $oDomain->OutSecure(), + !!$this->Config()->Get('ssl', 'verify_certificate', false), + !!$this->Config()->Get('ssl', 'allow_self_signed', true) + ); $iSmtpTime = \microtime(true) - $iTime; $oSmtpClient->Disconnect(); diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Config/Application.php b/rainloop/v/0.0.0/app/src/RainLoop/Config/Application.php index 4f629d0e0..ab442c3a5 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/Config/Application.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/Config/Application.php @@ -122,6 +122,7 @@ class Application extends \RainLoop\Config\AbstractConfig 'ssl' => array( 'verify_certificate' => array(false, 'Require verification of SSL certificate used.'), + 'allow_self_signed' => array(true, 'Allow self-signed certificates. Requires verify_certificate.'), 'cafile' => array('', 'Location of Certificate Authority file on local filesystem (/etc/ssl/certs/ca-certificates.crt)'), 'capath' => array('', 'capath must be a correctly hashed certificate directory. (/etc/ssl/certs/)'), ), diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Model/Account.php b/rainloop/v/0.0.0/app/src/RainLoop/Model/Account.php index 355da816d..27e94c515 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/Model/Account.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/Model/Account.php @@ -346,7 +346,8 @@ class Account extends \RainLoop\Account // for backward compatibility 'Password' => $this->Password(), 'ProxyAuthUser' => $this->ProxyAuthUser(), 'ProxyAuthPassword' => $this->ProxyAuthPassword(), - 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate'), + 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false), + 'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true), 'UseAuthPlainIfSupported' => !!$oConfig->Get('labs', 'use_imap_auth_plain') ); @@ -358,7 +359,8 @@ class Account extends \RainLoop\Account // for backward compatibility { $oMailClient ->Connect($aImapCredentials['Host'], $aImapCredentials['Port'], - $aImapCredentials['Secure'], $aImapCredentials['VerifySsl']); + $aImapCredentials['Secure'], $aImapCredentials['VerifySsl'], $aImapCredentials['AllowSelfSigned']); + } $oPlugins->RunHook('event.imap-pre-login', array($this, $aImapCredentials['UseAuth'], $aImapCredentials)); @@ -410,7 +412,8 @@ class Account extends \RainLoop\Account // for backward compatibility 'Password' => $this->Password(), 'ProxyAuthUser' => $this->ProxyAuthUser(), 'ProxyAuthPassword' => $this->ProxyAuthPassword(), - 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate') + 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false), + 'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true) ); $oPlugins->RunHook('filter.smtp-credentials', array($this, &$aSmtpCredentials)); @@ -421,8 +424,9 @@ class Account extends \RainLoop\Account // for backward compatibility if ($aSmtpCredentials['UseConnect'] && !$aSmtpCredentials['UsePhpMail'] && $oSmtpClient) { - $oSmtpClient->Connect($aSmtpCredentials['Host'], $aSmtpCredentials['Port'], - $aSmtpCredentials['Ehlo'], $aSmtpCredentials['Secure'], $aSmtpCredentials['VerifySsl']); + $oSmtpClient->Connect($aSmtpCredentials['Host'], $aSmtpCredentials['Port'], $aSmtpCredentials['Ehlo'], + $aSmtpCredentials['Secure'], $aSmtpCredentials['VerifySsl'], $aSmtpCredentials['AllowSelfSigned'] + ); } $oPlugins->RunHook('event.smtp-post-connect', array($this, $aSmtpCredentials['UseConnect'], $aSmtpCredentials)); diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Plugins/Manager.php b/rainloop/v/0.0.0/app/src/RainLoop/Plugins/Manager.php index 797c08e30..4a332212c 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/Plugins/Manager.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/Plugins/Manager.php @@ -171,7 +171,9 @@ class Manager \file_exists($sPathName.'/index.php')) { $aList[] = array( - $sName, @\file_get_contents($sPathName.'/VERSION') + $sName, + \file_exists($sPathName.'/VERSION') ? + \file_get_contents($sPathName.'/VERSION') : '0.0' ); } } diff --git a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsSecurity.html b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsSecurity.html index d167c8472..8ede1e572 100644 --- a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsSecurity.html +++ b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsSecurity.html @@ -31,17 +31,36 @@