From 041bd1ae1b17a52915c2da02cb4dda6899ee302d Mon Sep 17 00:00:00 2001 From: RainLoop Team Date: Thu, 6 Feb 2014 15:56:55 +0400 Subject: [PATCH] Find links in html messages --- .../app/libraries/MailSo/Base/HtmlUtils.php | 114 +++- .../app/libraries/MailSo/Base/LinkFinder.php | 57 +- .../0.0.0/app/libraries/MailSo/Base/Utils.php | 14 +- .../v/0.0.0/app/libraries/MailSo/Version.php | 2 +- .../0.0.0/app/libraries/RainLoop/Actions.php | 31 +- .../libraries/RainLoop/Config/Application.php | 505 +++++++++--------- 6 files changed, 388 insertions(+), 335 deletions(-) diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php b/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php index 38230505e..9fbd1dcc3 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php @@ -8,6 +8,8 @@ namespace MailSo\Base; */ class HtmlUtils { + static $KOS = '@@_KOS_@@'; + /** * @access private */ @@ -261,14 +263,106 @@ class HtmlUtils return \implode(';', $aOutStyles); } + /** + * @param \DOMDocument $oDom + */ + public static function FindLinksInDOM(&$oDom) + { + $aNodes = $oDom->getElementsByTagName('*'); + foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement) + { + $sTagNameLower = \strtolower($oElement->tagName); + $sParentTagNameLower = isset($oElement->parentNode) && isset($oElement->parentNode->tagName) ? + \strtolower($oElement->parentNode->tagName) : ''; + + if (!\in_array($sTagNameLower, array('html', 'meta', 'head', 'style', 'script', 'img', 'button', 'input', 'textarea', 'a')) && + 'a' !== $sParentTagNameLower && $oElement->childNodes && 0 < $oElement->childNodes->length) + { + $oSubItem = null; + $aTextNodes = array(); + $iIndex = $oElement->childNodes->length - 1; + while ($iIndex > -1) + { + $oSubItem = $oElement->childNodes->item($iIndex); + if ($oSubItem && XML_TEXT_NODE === $oSubItem->nodeType) + { + $aTextNodes[] = $oSubItem; + } + + $iIndex--; + } + + unset($oSubItem); + + foreach ($aTextNodes as $oTextNode) + { + if ($oTextNode && 0 < \strlen($oTextNode->wholeText)/* && \preg_match('/http[s]?:\/\//i', $oTextNode->wholeText)*/) + { + $sText = \MailSo\Base\LinkFinder::NewInstance() + ->Text($oTextNode->wholeText) + ->UseDefaultWrappers(true) + ->CompileText() + ; + + $oSubDom = \MailSo\Base\HtmlUtils::GetDomFromText(''.$sText.''); + if ($oSubDom) + { + $oBodyNodes = $oSubDom->getElementsByTagName('body'); + if ($oBodyNodes && 0 < $oBodyNodes->length) + { + $oBodyChildNodes = $oBodyNodes->item(0)->childNodes; + if ($oBodyChildNodes && $oBodyChildNodes->length) + { + for ($iIndex = 0, $iLen = $oBodyChildNodes->length; $iIndex < $iLen; $iIndex++) + { + $oSubItem = $oBodyChildNodes->item($iIndex); + if ($oSubItem) + { + if (XML_ELEMENT_NODE === $oSubItem->nodeType && + 'a' === \strtolower($oSubItem->tagName)) + { + $oLink = $oDom->createElement('a', + \str_replace(':', \MailSo\Base\HtmlUtils::$KOS, \htmlspecialchars($oSubItem->nodeValue))); + + $sHref = $oSubItem->getAttribute('href'); + if ($sHref) + { + $oLink->setAttribute('href', $sHref); + } + + $oElement->insertBefore($oLink, $oTextNode); + } + else + { + $oElement->insertBefore($oDom->importNode($oSubItem), $oTextNode); + } + } + } + + $oElement->removeChild($oTextNode); + } + } + + unset($oBodyNodes); + } + + unset($oSubDom, $sText); + } + } + } + } + + unset($aNodes); + } /** * @param string $sHtml * @param bool $bDoNotReplaceExternalUrl = false + * @param bool $bFindLinksInHtml = false * * @return string */ - public static function ClearHtmlSimple($sHtml, $bDoNotReplaceExternalUrl = false) + public static function ClearHtmlSimple($sHtml, $bDoNotReplaceExternalUrl = false, $bFindLinksInHtml = false) { $bHasExternals = false; $aFoundCIDs = array(); @@ -276,7 +370,7 @@ class HtmlUtils $aFoundedContentLocationUrls = array(); return \MailSo\Base\HtmlUtils::ClearHtml($sHtml, $bHasExternals, $aFoundCIDs, - $aContentLocationUrls, $aFoundedContentLocationUrls, $bDoNotReplaceExternalUrl); + $aContentLocationUrls, $aFoundedContentLocationUrls, $bDoNotReplaceExternalUrl, $bFindLinksInHtml); } /** @@ -286,11 +380,13 @@ class HtmlUtils * @param array $aContentLocationUrls = array() * @param array $aFoundedContentLocationUrls = array() * @param bool $bDoNotReplaceExternalUrl = false + * @param bool $bFindLinksInHtml = false * * @return string */ public static function ClearHtml($sHtml, &$bHasExternals = false, &$aFoundCIDs = array(), - $aContentLocationUrls = array(), &$aFoundedContentLocationUrls = array(), $bDoNotReplaceExternalUrl = false) + $aContentLocationUrls = array(), &$aFoundedContentLocationUrls = array(), + $bDoNotReplaceExternalUrl = false, $bFindLinksInHtml = false) { $sHtml = null === $sHtml ? '' : (string) $sHtml; $sHtml = \trim($sHtml); @@ -313,11 +409,16 @@ class HtmlUtils if ($oDom) { + if ($bFindLinksInHtml) + { + \MailSo\Base\HtmlUtils::FindLinksInDOM($oDom); + } + $aNodes = $oDom->getElementsByTagName('*'); foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement) { $sTagNameLower = \strtolower($oElement->tagName); - + // convert body attributes to styles if ('body' === $sTagNameLower) { @@ -493,6 +594,8 @@ class HtmlUtils $sResult = '
'.$sResult.'
'; $sResult = '
'.$sResult.'
'; + $sResult = \str_replace(\MailSo\Base\HtmlUtils::$KOS, ':', $sResult); + return \trim($sResult); } @@ -658,8 +761,7 @@ class HtmlUtils $sText = \MailSo\Base\LinkFinder::NewInstance() ->Text($sText) ->UseDefaultWrappers($bLinksWithTargetBlank) -// ->CompileText(true, false); - ->CompileText(true, true); + ->CompileText(); $sText = \str_replace("\r", '', $sText); diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Base/LinkFinder.php b/rainloop/v/0.0.0/app/libraries/MailSo/Base/LinkFinder.php index 6be013ba5..27a99989e 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Base/LinkFinder.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Base/LinkFinder.php @@ -126,13 +126,8 @@ class LinkFinder */ public function UseDefaultWrappers($bAddTargetBlank = false) { - $this->fLinkWrapper = function ($sLink, $bShortLink = false) use ($bAddTargetBlank) { - - if ($bShortLink && \in_array(\strtolower($sLink), array('asp.net', 'vb.net', 'mailbee.net'))) - { - return $sLink; - } - + $this->fLinkWrapper = function ($sLink) use ($bAddTargetBlank) { + $sNameLink = $sLink; if (!\preg_match('/^[a-z]{3,5}\:\/\//i', \ltrim($sLink))) { @@ -151,11 +146,10 @@ class LinkFinder /** * @param bool $bUseHtmlSpecialChars = true - * @param bool $bFindShortLinks = true * * @return string */ - public function CompileText($bUseHtmlSpecialChars = true, $bFindShortLinks = true) + public function CompileText($bUseHtmlSpecialChars = true) { $sText = \substr($this->sText, 0, $this->iOptimizationLimit); $sSubText = \substr($this->sText, $this->iOptimizationLimit); @@ -171,11 +165,6 @@ class LinkFinder $sText = $this->findMails($sText, $this->fMailWrapper); } - if ($bFindShortLinks && null !== $this->fLinkWrapper && \is_callable($this->fLinkWrapper)) - { - $sText = $this->findShortLinks($sText, $this->fLinkWrapper); - } - $sResult = ''; if ($bUseHtmlSpecialChars) { @@ -259,46 +248,6 @@ class LinkFinder return $sText; } - /** - * @param string $sText - * @param mixed $fWrapper - * - * @return string - */ - private function findShortLinks($sText, $fWrapper) - { - $sPattern = '/([a-z0-9-\.]+\.(?:com|org|net|ru))([^a-z0-9-\.])/i'; - - $aPrepearPlainStringUrls = $this->aPrepearPlainStringUrls; - $sText = \preg_replace_callback($sPattern, function ($aMatch) use ($fWrapper, &$aPrepearPlainStringUrls) { - - if (\is_array($aMatch) && 2 < \count($aMatch) && isset($aMatch[1]) && 0 < \strlen($aMatch[1])) - { - $sLinkWithWrap = \call_user_func_array($fWrapper, array($aMatch[1], true)); - if (\is_string($sLinkWithWrap)) - { - $aPrepearPlainStringUrls[] = \stripslashes($sLinkWithWrap); - return \MailSo\Base\LinkFinder::OPEN_LINK. - (\count($aPrepearPlainStringUrls) - 1). - \MailSo\Base\LinkFinder::CLOSE_LINK. - $aMatch[2]; - } - - return $aMatch[0]; - } - - return ''; - - }, $sText); - - if (0 < \count($aPrepearPlainStringUrls)) - { - $this->aPrepearPlainStringUrls = $aPrepearPlainStringUrls; - } - - return $sText; - } - /** * @param string $sText * @param mixed $fWrapper diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Base/Utils.php b/rainloop/v/0.0.0/app/libraries/MailSo/Base/Utils.php index 12700a058..201dd46e0 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Base/Utils.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Base/Utils.php @@ -740,7 +740,7 @@ class Utils { $sResult = ''; $sContentType = \strtolower($sContentType); - if (0 === strpos($sContentType, 'image/')) + if (0 === \strpos($sContentType, 'image/')) { $sResult = 'image'; } @@ -847,7 +847,7 @@ class Utils */ public static function Php2js($mInput) { - return \json_encode($mInput, defined('JSON_UNESCAPED_UNICODE') ? JSON_UNESCAPED_UNICODE : 0); + return \json_encode($mInput, \defined('JSON_UNESCAPED_UNICODE') ? JSON_UNESCAPED_UNICODE : 0); // if (\is_null($mInput)) // { @@ -918,25 +918,25 @@ class Utils */ public static function RecRmDir($sDir) { - if (@is_dir($sDir)) + if (@\is_dir($sDir)) { - $aObjects = scandir($sDir); + $aObjects = \scandir($sDir); foreach ($aObjects as $sObject) { if ('.' !== $sObject && '..' !== $sObject) { - if ('dir' === filetype($sDir.'/'.$sObject)) + if ('dir' === \filetype($sDir.'/'.$sObject)) { self::RecRmDir($sDir.'/'.$sObject); } else { - @unlink($sDir.'/'.$sObject); + @\unlink($sDir.'/'.$sObject); } } } - return @rmdir($sDir); + return @\rmdir($sDir); } return false; diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Version.php b/rainloop/v/0.0.0/app/libraries/MailSo/Version.php index e8263281c..9d45af44e 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Version.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Version.php @@ -10,7 +10,7 @@ final class Version /** * @var string */ - const APP_VERSION = '1.2.2'; + const APP_VERSION = '1.3.0'; /** * @var string diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php index 666b46d21..bea6a42f8 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -6264,7 +6264,7 @@ class Actions protected function responseObject($mResponse, $sParent = '', $aParameters = array()) { $mResult = $mResponse; - if (is_object($mResponse)) + if (\is_object($mResponse)) { $bHook = true; $sClassName = \get_class($mResponse); @@ -6327,7 +6327,7 @@ class Actions $sSubject = $mResult['Subject']; $mResult['RequestHash'] = \RainLoop\Utils::EncodeKeyValues(array( 'V' => APP_VERSION, - 'Account' => $oAccount ? md5($oAccount->Hash()) : '', + 'Account' => $oAccount ? \md5($oAccount->Hash()) : '', 'Folder' => $mResult['Folder'], 'Uid' => $mResult['Uid'], 'MimeType' => 'message/rfc822', @@ -6372,12 +6372,12 @@ class Actions } $sPlain = ''; - $sHtml = $mResponse->Html(); + $sHtml = \trim($mResponse->Html()); $bRtl = false; if (0 === \strlen($sHtml)) { - $sPlain = $mResponse->Plain(); + $sPlain = \trim($mResponse->Plain()); $bRtl = \MailSo\Base\Utils::IsRTL($sPlain); } else @@ -6389,7 +6389,8 @@ class Actions $mResult['InReplyTo'] = $mResponse->InReplyTo(); $mResult['References'] = $mResponse->References(); $mResult['Html'] = 0 === \strlen($sHtml) ? '' : \MailSo\Base\HtmlUtils::ClearHtml( - $sHtml, $bHasExternals, $mFoundedCIDs, $aContentLocationUrls, $mFoundedContentLocationUrls); + $sHtml, $bHasExternals, $mFoundedCIDs, $aContentLocationUrls, $mFoundedContentLocationUrls, false, + !!$this->Config()->Get('labs', 'allow_smart_html_links', true)); $mResult['PlainRaw'] = $sPlain; $mResult['Plain'] = 0 === \strlen($sPlain) ? '' : \MailSo\Base\HtmlUtils::ConvertPlainToHtml($sPlain); @@ -6418,7 +6419,7 @@ class Actions try { $oReadReceipt = \MailSo\Mime\Email::Parse($mResult['ReadReceipt']); - if ($oReadReceipt && \strtolower($oAccount->Email()) === \strtolower($oReadReceipt->GetEmail())) + if (!$oReadReceipt || ($oReadReceipt && \strtolower($oAccount->Email()) === \strtolower($oReadReceipt->GetEmail()))) { $mResult['ReadReceipt'] = ''; } @@ -6495,13 +6496,13 @@ class Actions 'CID' => $mResponse->Cid(), 'ContentLocation' => $mResponse->ContentLocation(), 'IsInline' => $mResponse->IsInline(), - 'IsLinked' => ($mFoundedCIDs && \in_array(trim(trim($mResponse->Cid()), '<>'), $mFoundedCIDs)) || + 'IsLinked' => ($mFoundedCIDs && \in_array(\trim(\trim($mResponse->Cid()), '<>'), $mFoundedCIDs)) || ($mFoundedContentLocationUrls && \in_array(\trim($mResponse->ContentLocation()), $mFoundedContentLocationUrls)) )); $mResult['Download'] = \RainLoop\Utils::EncodeKeyValues(array( 'V' => APP_VERSION, - 'Account' => $oAccount ? md5($oAccount->Hash()) : '', + 'Account' => $oAccount ? \md5($oAccount->Hash()) : '', 'Folder' => $mResult['Folder'], 'Uid' => $mResult['Uid'], 'MimeIndex' => $mResult['MimeIndex'], @@ -6513,7 +6514,7 @@ class Actions { $aExtended = null; $mStatus = $mResponse->Status(); - if (is_array($mStatus) && isset($mStatus['MESSAGES'], $mStatus['UNSEEN'], $mStatus['UIDNEXT'])) + if (\is_array($mStatus) && isset($mStatus['MESSAGES'], $mStatus['UNSEEN'], $mStatus['UIDNEXT'])) { $aExtended = array( 'MessageCount' => (int) $mStatus['MESSAGES'], @@ -6524,7 +6525,7 @@ class Actions ); } - $mResult = array_merge($this->objectData($mResponse, $sParent, $aParameters), array( + $mResult = \array_merge($this->objectData($mResponse, $sParent, $aParameters), array( 'Name' => $mResponse->Name(), 'FullName' => $mResponse->FullName(), 'FullNameRaw' => $mResponse->FullNameRaw(), @@ -6541,7 +6542,7 @@ class Actions } else if ('MailSo\Mail\MessageCollection' === $sClassName) { - $mResult = array_merge($this->objectData($mResponse, $sParent, $aParameters), array( + $mResult = \array_merge($this->objectData($mResponse, $sParent, $aParameters), array( 'MessageCount' => $mResponse->MessageCount, 'MessageUnseenCount' => $mResponse->MessageUnseenCount, 'MessageResultCount' => $mResponse->MessageResultCount, @@ -6557,13 +6558,13 @@ class Actions } else if ('MailSo\Mail\AttachmentCollection' === $sClassName) { - $mResult = array_merge($this->objectData($mResponse, $sParent, $aParameters), array( + $mResult = \array_merge($this->objectData($mResponse, $sParent, $aParameters), array( 'InlineCount' => $mResponse->InlineCount() )); } else if ('MailSo\Mail\FolderCollection' === $sClassName) { - $mResult = array_merge($this->objectData($mResponse, $sParent, $aParameters), array( + $mResult = \array_merge($this->objectData($mResponse, $sParent, $aParameters), array( 'Namespace' => $mResponse->GetNamespace(), 'FoldersHash' => isset($mResponse->FoldersHash) ? $mResponse->FoldersHash : '', 'IsThreadsSupported' => $mResponse->IsThreadsSupported, @@ -6579,7 +6580,7 @@ class Actions } else { - $mResult = '['.get_class($mResponse).']'; + $mResult = '['.\get_class($mResponse).']'; $bHook = false; } @@ -6588,7 +6589,7 @@ class Actions $this->Plugins()->RunHook('filter.response-object', array($sClassName, $mResult), false); } } - else if (is_array($mResponse)) + else if (\is_array($mResponse)) { foreach ($mResponse as $iKey => $oItem) { diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php index be88bb8cd..d73706d22 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php @@ -1,252 +1,253 @@ -Set('security', 'admin_password', \md5(APP_SALT.$sPassword.APP_SALT)); - } - - /** - * @param string $sPassword - * - * @return bool - */ - public function ValidatePassword($sPassword) - { - $sPassword = (string) $sPassword; - $sConfigPassword = (string) $this->Get('security', 'admin_password', ''); - - return 0 < \strlen($sPassword) && - ($sPassword === $sConfigPassword || \md5(APP_SALT.$sPassword.APP_SALT) === $sConfigPassword); - } - - /** - * @return bool - */ - public function Save() - { - $this->Set('version', 'current', APP_VERSION); - $this->Set('version', 'saved', \gmdate('r')); - - return parent::Save(); - } - - /** - * @return array - */ - protected function defaultValues() - { - return array( - 'webmail' => array( - - 'title' => array('RainLoop Webmail', 'Text displayed as page title'), - 'loading_description' => array('RainLoop', 'Text displayed on startup'), - - 'theme' => array('Default', 'Theme used by default'), - 'allow_themes' => array(true, 'Allow theme selection on settings screen'), - 'allow_custom_theme' => array(true, ''), - - 'language' => array('en', 'Language used by default'), - 'allow_languages_on_settings' => array(true, 'Allow language selection on settings screen'), - - 'allow_additional_accounts' => array(true, ''), - 'allow_identities' => array(true, ''), - - 'messages_per_page' => array(20, ' Number of messages displayed on page by default'), - - 'editor_default_type' => array('Html', 'Editor mode used by default (Html or Plain)'), - - 'attachment_size_limit' => array(5, - 'File size limit (MB) for file upload on compose screen -0 for unlimited.') - ), - - 'branding' => array( - 'login_logo' => array(''), - 'login_desc' => array(''), - 'login_css' => array(''), - ), - - 'contacts' => array( - 'enable' => array(false, 'Enable contacts'), - 'allow_sharing' => array(true), - 'allow_sync' => array(false), - 'suggestions_limit' => array(30), - 'type' => array('sqlite', ''), - 'pdo_dsn' => array('mysql:host=127.0.0.1;port=3306;dbname=rainloop', ''), - 'pdo_user' => array('root', ''), - 'pdo_password' => array('', ''), - ), - - 'security' => array( - 'csrf_protection' => array(true, - 'Enable CSRF protection (http://en.wikipedia.org/wiki/Cross-site_request_forgery)'), - - 'custom_server_signature' => array('RainLoop'), - 'openpgp' => array(false), - 'admin_login' => array('admin', 'Login and password for web admin panel'), - 'admin_password' => array('12345'), - 'allow_admin_panel' => array(true, 'Access settings'), - 'admin_panel_host' => array(''), - 'core_install_access_domains' => array('') - ), - - 'login' => array( - - 'allow_custom_login' => array(false, - 'Enable additional Login field on webmail login screen'), - - 'default_domain' => array('', ''), - - 'allow_languages_on_login' => array(true, - 'Allow language selection on webmail login screen'), - - 'sign_me_auto' => array(\RainLoop\Enumerations\SignMeType::DEFAILT_OFF, - 'This option allows webmail to remember the logged in user -once they closed the browser window. - -Values: - "DefaultOff" - can be used, disabled by default; - "DefaultOn" - can be used, enabled by default; - "Unused" - cannot be used') - ), - - 'plugins' => array( - 'enable' => array(false, 'Enable plugin support'), - 'enabled_list' => array('', 'List of enabled plugins'), - ), - - 'logs' => array( - - 'enable' => array(false, 'Enable logging'), - - 'write_on_error_only' => array(false, 'Logs entire request only if error occured'), - - 'filename' => array('log-{date:Y-m-d}.txt', - 'Log filename. -For security reasons, some characters are removed from filename. -Allows for pattern-based folder creation (see examples below). - -Patterns: - {date:Y-m-d} - Replaced by pattern-based date - Detailed info: http://www.php.net/manual/en/function.date.php - {user:email} - Replaced by user\'s email address - If user is not logged in, value is set to "unknown" - {user:login} - Replaced by user\'s login - If user is not logged in, value is set to "unknown" - {user:domain} - Replaced by user\'s domain name - If user is not logged in, value is set to "unknown" - {user:uid} - Replaced by user\'s UID regardless of account currently used - -Examples: - filename = "log-{date:Y-m-d}.txt" - filename = "{date:Y-m-d}/{user:domain}/{user:email}_{user:uid}.log" - filename = "{user:email}-{date:Y-m-d}.txt"') - ), - - 'debug' => array( - 'enable' => array(false, 'Special option required for development purposes'), - ), - - 'version' => array( - 'current' => array(''), - 'saved' => array('') - ), - - 'social' => array( - 'google_enable' => array(false, 'Google'), - 'google_client_id' => array(''), - 'google_client_secret' => array(''), - - 'fb_enable' => array(false, 'Facebook'), - 'fb_app_id' => array(''), - 'fb_app_secret' => array(''), - - 'twitter_enable' => array(false, 'Twitter'), - 'twitter_consumer_key' => array(''), - 'twitter_consumer_secret' => array(''), - - 'dropbox_enable' => array(false, 'Dropbox'), - 'dropbox_api_key' => array(''), - ), - - 'cache' => array( - 'enable' => array(true, - 'The section controls caching of the entire application. - -Enables caching in the system'), - - 'index' => array('v1', 'Additional caching key. If changed, cache is purged'), - - 'fast_cache_driver' => array('files', 'Can be: files, APC, memcache'), - 'fast_cache_index' => array('v1', 'Additional caching key. If changed, fast cache is purged'), - - 'http' => array(true, 'Browser-level cache. If enabled, caching is maintainted without using files'), - 'server_uids' => array(false, 'Caching message UIDs when searching and sorting (threading)') - ), - - 'labs' => array( - 'ignore_folders_subscription' => array(false, - 'Experimental settings. Handle with care. -'), - 'sync_dav_digest_auth' => array(true), - 'sync_dav_domain' => array(''), - 'sync_use_dav_browser' => array(true), - 'allow_message_append' => array(false), - 'date_from_headers' => array(false), - 'cache_system_data' => array(true), - 'use_app_debug_js' => array(false), - 'use_app_debug_css' => array(false), - 'use_dav_digest_auth' => array(false), - 'login_fault_delay' => array(1), - 'log_ajax_response_write_limit' => array(300), - 'determine_user_language' => array(true), - 'use_imap_sort' => array(false), - 'use_imap_force_selection' => array(false), - 'use_imap_list_subscribe' => array(true), - 'use_imap_thread' => array(true), - 'use_imap_move' => array(true), - 'use_imap_auth_plain' => array(false), - 'imap_forwarded_flag' => array('$Forwarded'), - 'imap_read_receipt_flag' => array('$ReadReceipt'), - 'smtp_show_server_errors' => array(false), - 'allow_prefetch' => array(true), - 'autocreate_system_folders' => array(true), - 'repo_type' => array('stable'), - 'custom_repo' => array(''), - 'additional_repo' => array(''), - 'cdn_static_domain' => array(''), - 'curl_proxy' => array(''), - 'curl_proxy_auth' => array(''), - 'in_iframe' => array(false), - 'custom_login_link' => array(''), - 'custom_logout_link' => array(''), - 'allow_external_login' => array(false), - 'fast_cache_memcache_host' => array('127.0.0.1'), - 'fast_cache_memcache_port' => array(11211), - 'fast_cache_memcache_expire' => array(43200), - 'dev_email' => array(''), - 'dev_login' => array(''), - 'dev_password' => array('') - ) - ); - } -} +Set('security', 'admin_password', \md5(APP_SALT.$sPassword.APP_SALT)); + } + + /** + * @param string $sPassword + * + * @return bool + */ + public function ValidatePassword($sPassword) + { + $sPassword = (string) $sPassword; + $sConfigPassword = (string) $this->Get('security', 'admin_password', ''); + + return 0 < \strlen($sPassword) && + ($sPassword === $sConfigPassword || \md5(APP_SALT.$sPassword.APP_SALT) === $sConfigPassword); + } + + /** + * @return bool + */ + public function Save() + { + $this->Set('version', 'current', APP_VERSION); + $this->Set('version', 'saved', \gmdate('r')); + + return parent::Save(); + } + + /** + * @return array + */ + protected function defaultValues() + { + return array( + 'webmail' => array( + + 'title' => array('RainLoop Webmail', 'Text displayed as page title'), + 'loading_description' => array('RainLoop', 'Text displayed on startup'), + + 'theme' => array('Default', 'Theme used by default'), + 'allow_themes' => array(true, 'Allow theme selection on settings screen'), + 'allow_custom_theme' => array(true, ''), + + 'language' => array('en', 'Language used by default'), + 'allow_languages_on_settings' => array(true, 'Allow language selection on settings screen'), + + 'allow_additional_accounts' => array(true, ''), + 'allow_identities' => array(true, ''), + + 'messages_per_page' => array(20, ' Number of messages displayed on page by default'), + + 'editor_default_type' => array('Html', 'Editor mode used by default (Html or Plain)'), + + 'attachment_size_limit' => array(5, + 'File size limit (MB) for file upload on compose screen +0 for unlimited.') + ), + + 'branding' => array( + 'login_logo' => array(''), + 'login_desc' => array(''), + 'login_css' => array(''), + ), + + 'contacts' => array( + 'enable' => array(false, 'Enable contacts'), + 'allow_sharing' => array(true), + 'allow_sync' => array(false), + 'suggestions_limit' => array(30), + 'type' => array('sqlite', ''), + 'pdo_dsn' => array('mysql:host=127.0.0.1;port=3306;dbname=rainloop', ''), + 'pdo_user' => array('root', ''), + 'pdo_password' => array('', ''), + ), + + 'security' => array( + 'csrf_protection' => array(true, + 'Enable CSRF protection (http://en.wikipedia.org/wiki/Cross-site_request_forgery)'), + + 'custom_server_signature' => array('RainLoop'), + 'openpgp' => array(false), + 'admin_login' => array('admin', 'Login and password for web admin panel'), + 'admin_password' => array('12345'), + 'allow_admin_panel' => array(true, 'Access settings'), + 'admin_panel_host' => array(''), + 'core_install_access_domains' => array('') + ), + + 'login' => array( + + 'allow_custom_login' => array(false, + 'Enable additional Login field on webmail login screen'), + + 'default_domain' => array('', ''), + + 'allow_languages_on_login' => array(true, + 'Allow language selection on webmail login screen'), + + 'sign_me_auto' => array(\RainLoop\Enumerations\SignMeType::DEFAILT_OFF, + 'This option allows webmail to remember the logged in user +once they closed the browser window. + +Values: + "DefaultOff" - can be used, disabled by default; + "DefaultOn" - can be used, enabled by default; + "Unused" - cannot be used') + ), + + 'plugins' => array( + 'enable' => array(false, 'Enable plugin support'), + 'enabled_list' => array('', 'List of enabled plugins'), + ), + + 'logs' => array( + + 'enable' => array(false, 'Enable logging'), + + 'write_on_error_only' => array(false, 'Logs entire request only if error occured'), + + 'filename' => array('log-{date:Y-m-d}.txt', + 'Log filename. +For security reasons, some characters are removed from filename. +Allows for pattern-based folder creation (see examples below). + +Patterns: + {date:Y-m-d} - Replaced by pattern-based date + Detailed info: http://www.php.net/manual/en/function.date.php + {user:email} - Replaced by user\'s email address + If user is not logged in, value is set to "unknown" + {user:login} - Replaced by user\'s login + If user is not logged in, value is set to "unknown" + {user:domain} - Replaced by user\'s domain name + If user is not logged in, value is set to "unknown" + {user:uid} - Replaced by user\'s UID regardless of account currently used + +Examples: + filename = "log-{date:Y-m-d}.txt" + filename = "{date:Y-m-d}/{user:domain}/{user:email}_{user:uid}.log" + filename = "{user:email}-{date:Y-m-d}.txt"') + ), + + 'debug' => array( + 'enable' => array(false, 'Special option required for development purposes'), + ), + + 'version' => array( + 'current' => array(''), + 'saved' => array('') + ), + + 'social' => array( + 'google_enable' => array(false, 'Google'), + 'google_client_id' => array(''), + 'google_client_secret' => array(''), + + 'fb_enable' => array(false, 'Facebook'), + 'fb_app_id' => array(''), + 'fb_app_secret' => array(''), + + 'twitter_enable' => array(false, 'Twitter'), + 'twitter_consumer_key' => array(''), + 'twitter_consumer_secret' => array(''), + + 'dropbox_enable' => array(false, 'Dropbox'), + 'dropbox_api_key' => array(''), + ), + + 'cache' => array( + 'enable' => array(true, + 'The section controls caching of the entire application. + +Enables caching in the system'), + + 'index' => array('v1', 'Additional caching key. If changed, cache is purged'), + + 'fast_cache_driver' => array('files', 'Can be: files, APC, memcache'), + 'fast_cache_index' => array('v1', 'Additional caching key. If changed, fast cache is purged'), + + 'http' => array(true, 'Browser-level cache. If enabled, caching is maintainted without using files'), + 'server_uids' => array(false, 'Caching message UIDs when searching and sorting (threading)') + ), + + 'labs' => array( + 'ignore_folders_subscription' => array(false, + 'Experimental settings. Handle with care. +'), + 'allow_prefetch' => array(true), + 'allow_smart_html_links' => array(true), + 'cache_system_data' => array(true), + 'date_from_headers' => array(false), + 'autocreate_system_folders' => array(true), + 'allow_message_append' => array(false), + 'determine_user_language' => array(true), + 'login_fault_delay' => array(1), + 'log_ajax_response_write_limit' => array(300), + 'sync_dav_digest_auth' => array(true), + 'sync_dav_domain' => array(''), + 'sync_use_dav_browser' => array(true), + 'use_app_debug_js' => array(false), + 'use_app_debug_css' => array(false), + 'use_imap_sort' => array(false), + 'use_imap_force_selection' => array(false), + 'use_imap_list_subscribe' => array(true), + 'use_imap_thread' => array(true), + 'use_imap_move' => array(true), + 'use_imap_auth_plain' => array(false), + 'imap_forwarded_flag' => array('$Forwarded'), + 'imap_read_receipt_flag' => array('$ReadReceipt'), + 'smtp_show_server_errors' => array(false), + 'repo_type' => array('stable'), + 'custom_repo' => array(''), + 'additional_repo' => array(''), + 'cdn_static_domain' => array(''), + 'curl_proxy' => array(''), + 'curl_proxy_auth' => array(''), + 'in_iframe' => array(false), + 'custom_login_link' => array(''), + 'custom_logout_link' => array(''), + 'allow_external_login' => array(false), + 'in_iframe' => array(false), + 'fast_cache_memcache_host' => array('127.0.0.1'), + 'fast_cache_memcache_port' => array(11211), + 'fast_cache_memcache_expire' => array(43200), + 'dev_email' => array(''), + 'dev_login' => array(''), + 'dev_password' => array('') + ) + ); + } +}