From 49010a70a02d8edfa5a48c68554b708c1d53a4f1 Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 11 Sep 2023 21:44:57 +0200 Subject: [PATCH 0001/1002] Resolve #1237 --- snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php b/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php index 947e8f47f..4e420a734 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php @@ -299,13 +299,13 @@ class GnuPG 'private' => [] ]; // Public - foreach ($this->handler()->keyinfo($pattern) as $key) { + foreach (($this->handler()->keyinfo($pattern) ?: []) as $key) { $key['can_verify'] = $key['can_sign']; unset($key['can_sign']); $keys['public'][] = $key; } // Private, read https://github.com/php-gnupg/php-gnupg/issues/5 - foreach ($this->handler()->keyinfo($pattern, 1) as $key) { + foreach (($this->handler()->keyinfo($pattern, 1) ?: []) as $key) { $key['can_decrypt'] = $key['can_encrypt']; unset($key['can_encrypt']); $keys['private'][] = $key; From a221ebfab8d52a43671129a04b46561ebe346dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Wed, 13 Sep 2023 01:07:45 +0200 Subject: [PATCH 0002/1002] [ldap-contacts-suggestions] Shorten overlong label This is just cosmetic, but the "to use" is superfluous and doesn't match the wording of the other labels (and makes the rendered UI a bit weird by pushing everything to the side). --- plugins/ldap-contacts-suggestions/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ldap-contacts-suggestions/index.php b/plugins/ldap-contacts-suggestions/index.php index 5b8b8dee1..266b166c1 100644 --- a/plugins/ldap-contacts-suggestions/index.php +++ b/plugins/ldap-contacts-suggestions/index.php @@ -81,7 +81,7 @@ class LdapContactsSuggestionsPlugin extends \RainLoop\Plugins\AbstractPlugin \RainLoop\Plugins\Property::NewInstance('base_dn')->SetLabel('Search base DN') ->SetDescription('DN to use as the search base. Supported tokens: {domain}, {domain:dc}, {email}, {email:user}, {email:domain}, {login}, {imap:login}, {imap:host}, {imap:port}') ->SetDefaultValue('ou=People,dc=example,dc=com'), - \RainLoop\Plugins\Property::NewInstance('object_classes')->SetLabel('objectClasses to use') + \RainLoop\Plugins\Property::NewInstance('object_classes')->SetLabel('objectClasses') ->SetDescription('LDAP objectClasses to search for, comma separated list') ->SetDefaultValue('inetOrgPerson'), \RainLoop\Plugins\Property::NewInstance('uid_attributes')->SetLabel('uid attributes') From 15e59ef65fd2bf98ccf476b25d06cff0f3d0ad58 Mon Sep 17 00:00:00 2001 From: Sergey Mosin Date: Thu, 13 Jul 2023 19:22:04 -0400 Subject: [PATCH 0003/1002] fix: allow clicking action on entire "ListItem" area, instead of just the "text elements" --- dev/Common/Selector.js | 12 ++++++++++-- dev/View/User/MailBox/MessageList.js | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/dev/Common/Selector.js b/dev/Common/Selector.js index 88c044daf..bb7cfed70 100644 --- a/dev/Common/Selector.js +++ b/dev/Common/Selector.js @@ -200,8 +200,16 @@ export class Selector { addEventsListeners(contentScrollable, { click: event => { - let el = event.target.closestWithin(this.sItemSelector, contentScrollable); - el && this.actionClick(ko.dataFor(el), event); + + const lowerClassName = event.target.className.toLowerCase(); + if (this.sItemSelector !== '.messageListItem' + || (lowerClassName.indexOf('flagparent') === -1 + && lowerClassName.indexOf('checkbox') === -1)) { + + let el = event.target.closestWithin(this.sItemSelector, contentScrollable); + el && this.actionClick(ko.dataFor(el), event); + + } const item = getItem(this.sItemCheckedSelector); if (item) { diff --git a/dev/View/User/MailBox/MessageList.js b/dev/View/User/MailBox/MessageList.js index cf409f3b7..ef91c15ea 100644 --- a/dev/View/User/MailBox/MessageList.js +++ b/dev/View/User/MailBox/MessageList.js @@ -219,7 +219,7 @@ export class MailMessageList extends AbstractViewRight { MessagelistUserStore, MessagelistUserStore.selectedMessage, MessagelistUserStore.focusedMessage, - '.messageListItem .actionHandle', + '.messageListItem', '.messageListItem .messageCheckbox', '.messageListItem.focused' ); From d5965bf1d79910cd87fc9ca9c66b851198336525 Mon Sep 17 00:00:00 2001 From: Sergey Mosin Date: Sat, 29 Jul 2023 08:24:52 -0400 Subject: [PATCH 0004/1002] fix: nextcloud iFrame mode: click on unified search result opens inner iFrame --- integrations/nextcloud/snappymail/js/snappymail.js | 7 +++++++ .../nextcloud/snappymail/lib/Search/Provider.php | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/integrations/nextcloud/snappymail/js/snappymail.js b/integrations/nextcloud/snappymail/js/snappymail.js index 38a915ab7..fcbd88da3 100644 --- a/integrations/nextcloud/snappymail/js/snappymail.js +++ b/integrations/nextcloud/snappymail/js/snappymail.js @@ -141,3 +141,10 @@ function SnappyMailFormHelper(oForm) console.error(e); } } + +addEventListener('hashchange', (event) => { + const search = event.newURL.substring(event.newURL.lastIndexOf('/') + 1); + if (search && search.length < 25) { + document.getElementById('rliframe').contentWindow.rl.app.messageList.mainSearch(search); + } +}); diff --git a/integrations/nextcloud/snappymail/lib/Search/Provider.php b/integrations/nextcloud/snappymail/lib/Search/Provider.php index 7b9b63157..f0eccbf79 100644 --- a/integrations/nextcloud/snappymail/lib/Search/Provider.php +++ b/integrations/nextcloud/snappymail/lib/Search/Provider.php @@ -91,12 +91,12 @@ class Provider implements IProvider $MessageCollection = $oMailClient->MessageList($oParams); $baseURL = $this->urlGenerator->linkToRoute('snappymail.page.index'); - $config = \OC::$server->getConfig(); - if ($config->getAppValue('snappymail', 'snappymail-no-embed')) { - $baseURL .= '?target='; - } else { +// $config = \OC::$server->getConfig(); +// if ($config->getAppValue('snappymail', 'snappymail-no-embed')) { +// $baseURL .= '?target='; +// } else { $baseURL .= '#'; - } +// } $search = \rawurlencode($oParams->sSearch); // $MessageCollection->totalEmails; From 1b7e144a6e84b845c9a792db7e64683bee349f09 Mon Sep 17 00:00:00 2001 From: Sergey Mosin Date: Thu, 10 Aug 2023 00:07:31 -0400 Subject: [PATCH 0005/1002] fix: tag 'style' is lost in replies --- vendors/squire/build/squire-raw.js | 1 + 1 file changed, 1 insertion(+) diff --git a/vendors/squire/build/squire-raw.js b/vendors/squire/build/squire-raw.js index a12152ce4..4b20e8311 100644 --- a/vendors/squire/build/squire-raw.js +++ b/vendors/squire/build/squire-raw.js @@ -1345,6 +1345,7 @@ const color = node.color, newTag = createElement('SPAN'), css = newTag.style; + newTag.style.cssText = node.style.cssText; if (face) { css.fontFamily = face; } From 8ab30552232786458824fd6e5ae5670ed78ced33 Mon Sep 17 00:00:00 2001 From: Sergey Mosin Date: Fri, 11 Aug 2023 21:08:05 -0400 Subject: [PATCH 0006/1002] fix: unseen indicator is not shown in thread view when 'listGrouped' settings is false + show unseen message count when the message list is threaded --- dev/Model/Message.js | 5 +++++ dev/Stores/User/Messagelist.js | 22 ++++++++++++++----- .../templates/Views/User/MailMessageList.html | 4 ++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/dev/Model/Message.js b/dev/Model/Message.js index 8e9e97bc7..9f2c54b49 100644 --- a/dev/Model/Message.js +++ b/dev/Model/Message.js @@ -128,6 +128,11 @@ export class MessageModel extends AbstractModel { threadsLen: () => rl.app.messageList.threadUid() ? 0 : this.threads().length, threadUnseenLen: () => rl.app.messageList.threadUid() ? 0 : this.threadUnseen().length, + threadsLenText: () => { + const unseenLen = this.threadUnseenLen(); + return this.threadsLen() + (unseenLen > 0 ? '/' + unseenLen : ''); + }, + isUnseen: () => !this.flags().includes('\\seen'), isFlagged: () => this.flags().includes('\\flagged'), // isJunk: () => this.flags().includes('$junk') && !this.flags().includes('$nonjunk'), diff --git a/dev/Stores/User/Messagelist.js b/dev/Stores/User/Messagelist.js index c9ada4545..025ea728b 100644 --- a/dev/Stores/User/Messagelist.js +++ b/dev/Stores/User/Messagelist.js @@ -344,13 +344,23 @@ MessagelistUserStore.setAction = (sFolderFullName, iSetAction, messages) => { length; if (iSetAction == MessageSetAction.SetSeen) { - messages.forEach(oMessage => - oMessage.isUnseen() && rootUids.push(oMessage.uid) && oMessage.flags.push('\\seen') - ); + messages.forEach(oMessage => { + if (oMessage.isUnseen() && rootUids.push(oMessage.uid)) { + oMessage.flags.push('\\seen'); + if (oMessage.threads().length > 0 && oMessage.threadUnseen().includes(oMessage.uid)) { + oMessage.threadUnseen.remove(oMessage.uid); + } + } + }); } else if (iSetAction == MessageSetAction.UnsetSeen) { - messages.forEach(oMessage => - !oMessage.isUnseen() && rootUids.push(oMessage.uid) && oMessage.flags.remove('\\seen') - ); + messages.forEach(oMessage => { + if (!oMessage.isUnseen() && rootUids.push(oMessage.uid)) { + oMessage.flags.remove('\\seen'); + if (oMessage.threads().length > 0 && !oMessage.threadUnseen().includes(oMessage.uid)) { + oMessage.threadUnseen.push(oMessage.uid); + } + } + }); } else if (iSetAction == MessageSetAction.SetFlag) { messages.forEach(oMessage => !oMessage.isFlagged() && rootUids.push(oMessage.uid) && oMessage.flags.push('\\flagged') diff --git a/snappymail/v/0.0.0/app/templates/Views/User/MailMessageList.html b/snappymail/v/0.0.0/app/templates/Views/User/MailMessageList.html index 4a4dd3701..a5bd63588 100644 --- a/snappymail/v/0.0.0/app/templates/Views/User/MailMessageList.html +++ b/snappymail/v/0.0.0/app/templates/Views/User/MailMessageList.html @@ -139,7 +139,7 @@
-
+
@@ -159,7 +159,7 @@
-
+
From 11c616715d5e40296a1a2725262e0b656bd7284e Mon Sep 17 00:00:00 2001 From: Sergey Mosin Date: Wed, 26 Jul 2023 20:01:11 -0400 Subject: [PATCH 0007/1002] improve: use calendar icon in message list for messages with '.ics' or 'text/calendar' attachments --- dev/Common/File.js | 7 ++++++- vendors/fontastic/styles.css | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dev/Common/File.js b/dev/Common/File.js index acd5a370e..f333235fa 100644 --- a/dev/Common/File.js +++ b/dev/Common/File.js @@ -116,7 +116,8 @@ export const FileType = { Spreadsheet: 'spreadsheet', Presentation: 'presentation', Certificate: 'certificate', - Archive: 'archive' + Archive: 'archive', + Calendar: 'calendar' }; export const FileInfo = { @@ -190,6 +191,9 @@ export const FileInfo = { case 'eml' == ext || ['message/delivery-status', 'message/rfc822'].includes(mimeType): result = FileType.Eml; break; + case 'ics' == ext || mimeType == 'text/calendar': + result = FileType.Calendar; + break; case 'text' == mimeTypeParts[0] || 'txt' == ext || 'log' == ext: result = FileType.Text; break; @@ -240,6 +244,7 @@ export const FileInfo = { case FileType.Certificate: case FileType.Spreadsheet: case FileType.Presentation: + case FileType.Calendar: return result + '-' + fileType; } return result; diff --git a/vendors/fontastic/styles.css b/vendors/fontastic/styles.css index 576869646..ae034056f 100644 --- a/vendors/fontastic/styles.css +++ b/vendors/fontastic/styles.css @@ -106,3 +106,6 @@ .icon-check-mark-circle-two::before { content: "\e073"; } +.icon-file-calendar::before { + content: "📅"; +} From d97ccf0cfb6e7a1ab7adf6be3f2813b985f531b1 Mon Sep 17 00:00:00 2001 From: Sergey Mosin Date: Sat, 29 Jul 2023 17:01:44 -0400 Subject: [PATCH 0008/1002] improve: add "Add/Edit signature" label to PopupsIdentity.html --- snappymail/v/0.0.0/app/localization/en/user.json | 1 + snappymail/v/0.0.0/app/templates/Views/User/PopupsIdentity.html | 1 + 2 files changed, 2 insertions(+) diff --git a/snappymail/v/0.0.0/app/localization/en/user.json b/snappymail/v/0.0.0/app/localization/en/user.json index e777708ff..b444b2dbc 100644 --- a/snappymail/v/0.0.0/app/localization/en/user.json +++ b/snappymail/v/0.0.0/app/localization/en/user.json @@ -254,6 +254,7 @@ "TITLE_UPDATE_IDENTITY": "Update Identity?", "BUTTON_ADD_IDENTITY": "Add", "BUTTON_UPDATE_IDENTITY": "Update", + "LABEL_SIGNATURE_ADD": "Add/Edit signature", "LABEL_SIGNATURE_INSERT_BEFORE": "Insert this signature before quoted text in replies" }, "POPUPS_CREATE_FOLDER": { diff --git a/snappymail/v/0.0.0/app/templates/Views/User/PopupsIdentity.html b/snappymail/v/0.0.0/app/templates/Views/User/PopupsIdentity.html index 484da4202..e5fffa2b2 100644 --- a/snappymail/v/0.0.0/app/templates/Views/User/PopupsIdentity.html +++ b/snappymail/v/0.0.0/app/templates/Views/User/PopupsIdentity.html @@ -52,6 +52,7 @@
+

- + From 22691450afc79e1d5e0268f265d03ea68c036f84 Mon Sep 17 00:00:00 2001 From: Sergey Mosin Date: Thu, 10 Aug 2023 17:20:58 -0400 Subject: [PATCH 0012/1002] improve: if applicable set '\\answered' or '$forwarded' flag after a message is sent so the proper icon is shown in the message list view --- dev/View/Popup/Compose.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js index 183e5b831..e1557d268 100644 --- a/dev/View/Popup/Compose.js +++ b/dev/View/Popup/Compose.js @@ -493,6 +493,19 @@ export class ComposePopupView extends AbstractViewPopup { || getNotification(Notifications.CantSendMessage)); } } else { + if (arrayLength(this.aDraftInfo) > 0) { + const flag = { + 'reply': '\\answered', + 'forward': '$forwarded' + }[this.aDraftInfo[0]]; + if (flag) { + const aFlags = MessageUserStore.message().flags(); + if (aFlags.indexOf(flag) === -1) { + aFlags.push(flag); + MessageUserStore.message().flags(aFlags); + } + } + } this.close(); } setFolderETag(this.draftsFolder(), ''); From 35cd3543530d3fb1304ad972e9a8a27ee575ec0a Mon Sep 17 00:00:00 2001 From: Sergey Mosin Date: Fri, 11 Aug 2023 14:44:42 -0400 Subject: [PATCH 0013/1002] improve: add 'collapse_blockquotes', 'allow_spellcheck' and 'mail_list_grouped' to admin settings ('defaults' section) --- snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php | 7 ++++--- .../v/0.0.0/app/libraries/RainLoop/Config/Application.php | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php index eb7356db5..febf39be7 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -679,16 +679,17 @@ class Actions 'contactsAllowed' => $this->AddressBookProvider($oAccount)->IsActive(), + 'allowSpellcheck' => $oConfig->Get('defaults', 'allow_spellcheck', false), 'ViewHTML' => (bool) $oConfig->Get('defaults', 'view_html', true), 'ViewImages' => $oConfig->Get('defaults', 'view_images', 'ask'), 'ViewImagesWhitelist' => '', 'RemoveColors' => (bool) $oConfig->Get('defaults', 'remove_colors', false), 'AllowStyles' => false, 'ListInlineAttachments' => false, - 'CollapseBlockquotes' => true, + 'CollapseBlockquotes' => $oConfig->Get('defaults', 'collapse_blockquotes', true), 'MaxBlockquotesLevel' => 0, 'simpleAttachmentsList' => false, - 'listGrouped' => false, + 'listGrouped' => $oConfig->Get('defaults', 'mail_list_grouped', false), 'MessagesPerPage' => (int) $oConfig->Get('webmail', 'messages_per_page', 25), 'MessageReadDelay' => (int) $oConfig->Get('webmail', 'message_read_delay', 5), 'MsgDefaultAction' => (int) $oConfig->Get('defaults', 'msg_default_action', 1), @@ -773,7 +774,7 @@ class Actions $aResult['requireTLS'] = (bool) $oSettings->GetConf('requireTLS', false); $aResult['pgpSign'] = (bool) $oSettings->GetConf('pgpSign', false); $aResult['pgpEncrypt'] = (bool) $oSettings->GetConf('pgpEncrypt', false); - $aResult['allowSpellcheck'] = (bool) $oSettings->GetConf('allowSpellcheck', false); + $aResult['allowSpellcheck'] = (bool) $oSettings->GetConf('allowSpellcheck', $aResult['allowSpellcheck']); // $aResult['allowCtrlEnterOnCompose'] = (bool) $oSettings->GetConf('allowCtrlEnterOnCompose', true); $aResult['ViewHTML'] = (bool)$oSettings->GetConf('ViewHTML', $aResult['ViewHTML']); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php index b9c92220c..8f7bdf1a1 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php @@ -301,10 +301,13 @@ Values: "match" - whitelist or ask "always" - show always'), 'contacts_autosave' => array(true), - 'mail_use_threads' => array(false), + 'mail_list_grouped' => array(false), + 'mail_use_threads' => array(false), 'allow_draft_autosave' => array(true), 'mail_reply_same_folder' => array(false), 'msg_default_action' => array(1, '1 - reply, 2 - reply all'), + 'collapse_blockquotes' => array(true), + 'allow_spellcheck' => array(false) ), 'logs' => array( From 79c8281a6b948aa095c0e51a9ed2a53ee6f360fc Mon Sep 17 00:00:00 2001 From: Sergey Mosin Date: Wed, 16 Aug 2023 10:42:17 -0400 Subject: [PATCH 0014/1002] improve: nextcloud: set 'smremember' cookie if 'sign_me_auto' is set to 'DefaultOn' when using 'snappymail-autologin*', otherwise nextcloud users need to re-login when the browser is re-opened. --- .../nextcloud/snappymail/lib/AppInfo/Application.php | 3 ++- .../nextcloud/snappymail/lib/Util/SnappyMailHelper.php | 4 +++- .../v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php | 9 ++++++++- snappymail/v/0.0.0/app/libraries/snappymail/cookies.php | 6 +++--- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/integrations/nextcloud/snappymail/lib/AppInfo/Application.php b/integrations/nextcloud/snappymail/lib/AppInfo/Application.php index 5fad178eb..9a8e0748c 100644 --- a/integrations/nextcloud/snappymail/lib/AppInfo/Application.php +++ b/integrations/nextcloud/snappymail/lib/AppInfo/Application.php @@ -86,7 +86,8 @@ class Application extends App implements IBootstrap // https://github.com/nextcloud/server/issues/36083#issuecomment-1387370634 // \OC::$server->getSession()['snappymail-password'] = ''; SnappyMailHelper::loadApp(); - \RainLoop\Api::Actions()->Logout(true); +// \RainLoop\Api::Actions()->Logout(true); + \RainLoop\Api::Actions()->DoLogout(); }); // https://github.com/nextcloud/impersonate/issues/179 diff --git a/integrations/nextcloud/snappymail/lib/Util/SnappyMailHelper.php b/integrations/nextcloud/snappymail/lib/Util/SnappyMailHelper.php index 5764da4c8..4839779d2 100644 --- a/integrations/nextcloud/snappymail/lib/Util/SnappyMailHelper.php +++ b/integrations/nextcloud/snappymail/lib/Util/SnappyMailHelper.php @@ -80,7 +80,9 @@ class SnappyMailHelper if ($doLogin && $aCredentials[1] && $aCredentials[2]) { try { $oActions->Logger()->AddSecret($aCredentials[2]); - $oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2], false); + + $bSignMe = $oConfig->Get('login', 'sign_me_auto', \RainLoop\Enumerations\SignMeType::DEFAULT_OFF) === \RainLoop\Enumerations\SignMeType::DEFAULT_ON; + $oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2], $bSignMe); if ($oAccount) { $oActions->Plugins()->RunHook('login.success', array($oAccount)); $oActions->SetAuthToken($oAccount); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php index 33f7fa2cf..63d3c9737 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php @@ -139,7 +139,14 @@ trait UserAuth $this->imapConnect($oAccount, true); if ($bMainAccount) { - $bSignMe && $this->SetSignMeToken($oAccount); + if($bSignMe){ + // SetAuthToken token needs to be called before SetSignMeToken + // because $_COOKIE['smctoken'] is used by Crypt::Passphrase. + // If the $_COOKIE['smctoken'] is not set then SetSignMeToken + // throws an exception + $this->SetAuthToken($oAccount); + $this->SetSignMeToken($oAccount); + } $this->StorageProvider()->Put($oAccount, StorageType::SESSION, Utils::GetSessionToken(), 'true'); } diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/cookies.php b/snappymail/v/0.0.0/app/libraries/snappymail/cookies.php index 9c670239e..3ac579b2f 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/cookies.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/cookies.php @@ -83,7 +83,7 @@ class Cookies if ($cookie_remove) { \header_remove('Set-Cookie'); foreach ($cookies as $cookie) { - \header($cookie); + \header($cookie,false); } } @@ -118,14 +118,14 @@ class Cookies foreach (\str_split($sValue, $iMaxSize) as $i => $sPart) { $sCookieName = $i ? "{$sName}~{$i}" : $sName; Log::debug('COOKIE', "set {$sCookieName}"); - static::_set($sCookieName, $sPart, $iExpire); + static::_set($sCookieName, $sPart, $iExpire, $httponly); } // Delete unused old 4K split cookie parts foreach (\array_keys($_COOKIE) as $sCookieName) { $aSplit = \explode('~', $sCookieName); if (isset($aSplit[1]) && $aSplit[0] == $sName && $aSplit[1] > $i) { Log::debug('COOKIE', "unset {$sCookieName}"); - static::_set($sCookieName, '', 0); + static::_set($sCookieName, '', 0, $httponly); } } } From c599847aea4187de610abbbfe8a777422a13b1d2 Mon Sep 17 00:00:00 2001 From: Ronak Patel Date: Thu, 28 Sep 2023 11:06:21 -0700 Subject: [PATCH 0015/1002] Make the Put in calendar option more obvious in Mail --- plugins/nextcloud/js/webdav.js | 115 ++++++++++++++---- plugins/nextcloud/langs/en.json | 2 +- .../templates/Views/User/MailMessageView.html | 2 +- 3 files changed, 92 insertions(+), 27 deletions(-) diff --git a/plugins/nextcloud/js/webdav.js b/plugins/nextcloud/js/webdav.js index 887e686fd..0b788c9a4 100644 --- a/plugins/nextcloud/js/webdav.js +++ b/plugins/nextcloud/js/webdav.js @@ -29,13 +29,14 @@ const `, propfindCal = ` - - - - - - -`, + + + + + + + +`, xmlParser = new DOMParser(), pathRegex = /.*\/remote.php\/dav\/[^/]+\/[^/]+/g, @@ -285,7 +286,51 @@ class NextcloudFilesPopupView extends rl.pluginPopupView { } }); } + createCalendarListItem(calendarData, treeElement) { + const { + displayName, + href, + calendarColor + } = calendarData; + const li = document.createElement('li'); + li.style.display = 'flex'; + + const span = document.createElement('span'); + span.setAttribute('role', 'img'); + span.className = 'material-design-icon checkbox-blank-circle-icon'; + span.style.fill = calendarColor; + span.style.width = '20px'; + span.style.height = '20px'; + + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + svg.setAttribute('width', '20'); + svg.setAttribute('height', '20'); + svg.setAttribute('viewBox', '0 0 24 24'); + + const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + path.setAttribute('d', 'M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z'); + svg.appendChild(path); + + span.appendChild(svg); + + const button = document.createElement('button'); + button.className = 'button-vue'; + button.style.backgroundColor = 'transparent'; + button.style.border = '0'; + button.style.fontSize = 'large'; + button.style.padding = '0'; + button.style.cursor = 'pointer'; + button.style.marginLeft = '5px'; + button.href = href.replace(pathRegex, '').replace(/\/$/, ''); + button.textContent = displayName; + button.style.color = '#1968DF'; + + li.appendChild(span); + li.appendChild(button); + + treeElement.appendChild(li); + } // Happens after showModal() beforeShow(files, fResolve) { this.select = ''; @@ -341,26 +386,30 @@ class NextcloudCalendarsPopupView extends rl.pluginPopupView { }) .then(response => (response.status < 400) ? response.text() : Promise.reject(new Error({ response }))) .then(text => { - const - responseList = getDavElementsByTagName( - xmlParser.parseFromString(text, 'application/xml').documentElement, - 'response' - ); + // Parse the XML text + const xmlDoc = xmlParser.parseFromString(text, 'application/xml').documentElement; + const responseList = getElementsInNamespaces(xmlDoc, 'response'); for (let i = 0; i < responseList.length; ++i) { - const e = responseList.item(i); + const e = responseList[i]; if (getDavElementByTagName(e, 'resourcetype').getElementsByTagNameNS(nsCalDAV, 'calendar').length) { -// && getDavElementsByTagName(getDavElementByTagName(e, 'current-user-privilege-set'), 'write').length) { - const li = document.createElement('li'), - btn = document.createElement('button'); - li.dataset.icon = '📅'; - li.textContent = getDavElementByTagName(e, 'displayname').textContent; - btn.href = getDavElementByTagName(e, 'href').textContent - .replace(pathRegex, '').replace(/\/$/, ''); - btn.textContent = 'select'; - btn.className = 'button-vue'; - btn.style.marginLeft = '1em'; - li.append(btn); - this.tree.append(li); + const displayNameElement = getElementsInNamespaces(e, 'displayname')[0]; + const displayName = displayNameElement ? displayNameElement.textContent.trim() : ''; + + const hrefElement = getElementsInNamespaces(e, 'href')[0]; + const href = hrefElement ? hrefElement.textContent.trim() : ''; + + const calendarColorElement = getElementsInNamespaces(e, 'calendar-color')[0]; + const calendarColor = calendarColorElement ? calendarColorElement.textContent.trim() : '#000000'; + + // Create an object to hold calendar data + const calendarData = { + displayName, + href, + calendarColor + }; + + // Call the function to create and append the list item + this.createCalendarListItem(calendarData, this.tree); } } }) @@ -433,3 +482,19 @@ rl.nextcloud = { }; })(window.rl); + +function getElementsInNamespaces(xmlDocument, tagName) { + const namespaces = { + d: 'DAV:', + x1: 'http://apple.com/ns/ical/', + }; + const results = []; + for (const prefix in namespaces) { + const namespaceURI = namespaces[prefix]; + const elements = xmlDocument.getElementsByTagNameNS(namespaceURI, tagName); + for (const element of elements) { + results.push(element); + } + } + return results; +} \ No newline at end of file diff --git a/plugins/nextcloud/langs/en.json b/plugins/nextcloud/langs/en.json index 1f2660547..2c19d11c2 100644 --- a/plugins/nextcloud/langs/en.json +++ b/plugins/nextcloud/langs/en.json @@ -2,7 +2,7 @@ "NEXTCLOUD": { "SAVE_ATTACHMENTS": "Save in Nextcloud", "SAVE_EML": "Save as .eml in Nextcloud", - "SAVE_ICS": "Put in Calendar", + "SAVE_ICS": "Add to calendar", "SELECT_FOLDER": "Select folder", "SELECT_FILES": "Select file(s)", "ATTACH_FILES": "Attach Nextcloud files", diff --git a/snappymail/v/0.0.0/app/templates/Views/User/MailMessageView.html b/snappymail/v/0.0.0/app/templates/Views/User/MailMessageView.html index abad87de3..ad199eb40 100644 --- a/snappymail/v/0.0.0/app/templates/Views/User/MailMessageView.html +++ b/snappymail/v/0.0.0/app/templates/Views/User/MailMessageView.html @@ -225,7 +225,7 @@
-
+
    From 775faa9d7969ce7f3c2709f3b40ada8130c4e31c Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Sun, 1 Oct 2023 11:18:37 +0200 Subject: [PATCH 0016/1002] #1243 version bump --- plugins/ldap-contacts-suggestions/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/ldap-contacts-suggestions/index.php b/plugins/ldap-contacts-suggestions/index.php index 266b166c1..c3c1242d4 100644 --- a/plugins/ldap-contacts-suggestions/index.php +++ b/plugins/ldap-contacts-suggestions/index.php @@ -4,8 +4,8 @@ class LdapContactsSuggestionsPlugin extends \RainLoop\Plugins\AbstractPlugin { const NAME = 'Contacts suggestions (LDAP)', - VERSION = '2.12', - RELEASE = '2023-01-31', + VERSION = '2.13', + RELEASE = '2023-10-01', REQUIRED = '2.23.0', CATEGORY = 'Contacts', DESCRIPTION = 'Get contacts suggestions from LDAP.'; From 63d0d138e66508359f65b6ad9acda336a9c8ad9f Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 2 Oct 2023 12:26:34 +0200 Subject: [PATCH 0017/1002] Simplify change of #1247 --- dev/View/User/MailBox/FolderList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/View/User/MailBox/FolderList.js b/dev/View/User/MailBox/FolderList.js index 2120e8e7f..de8685829 100644 --- a/dev/View/User/MailBox/FolderList.js +++ b/dev/View/User/MailBox/FolderList.js @@ -115,7 +115,7 @@ export class MailFolderList extends AbstractViewLeft { hasher.setHash(mailBox(folder.fullNameHash, 1, search)); // in mobile mode hide the panel when a folder is clicked - ThemeStore.isMobile() && leftPanelDisabled()===false && leftPanelDisabled(true); + ThemeStore.isMobile() && leftPanelDisabled(true); } AppUserStore.focusedState(ScopeMessageList); From 6b0e6ec02a88ecea2e7a14a37af2c220d0c1d4f6 Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 2 Oct 2023 12:47:47 +0200 Subject: [PATCH 0018/1002] Improved selector changes of #1248 --- dev/Common/Selector.js | 19 ++++------ dev/Stores/User/Messagelist.js | 2 +- dev/View/User/MailBox/MessageList.js | 36 ++++++++++--------- .../templates/Views/User/MailMessageList.html | 20 +++++------ 4 files changed, 37 insertions(+), 40 deletions(-) diff --git a/dev/Common/Selector.js b/dev/Common/Selector.js index bb7cfed70..3d43ed3da 100644 --- a/dev/Common/Selector.js +++ b/dev/Common/Selector.js @@ -7,7 +7,7 @@ import { koComputable } from 'External/ko'; oCallbacks: ItemSelect MiddleClick - AutoSelect + canSelect ItemGetUid UpOrDown */ @@ -200,18 +200,11 @@ export class Selector { addEventsListeners(contentScrollable, { click: event => { + const el = event.target.closestWithin(this.sItemSelector, contentScrollable); + let item = el && ko.dataFor(el); + el && (this.oCallbacks.click || (()=>1))(event, item) && this.actionClick(item, event); - const lowerClassName = event.target.className.toLowerCase(); - if (this.sItemSelector !== '.messageListItem' - || (lowerClassName.indexOf('flagparent') === -1 - && lowerClassName.indexOf('checkbox') === -1)) { - - let el = event.target.closestWithin(this.sItemSelector, contentScrollable); - el && this.actionClick(ko.dataFor(el), event); - - } - - const item = getItem(this.sItemCheckedSelector); + item = getItem(this.sItemCheckedSelector); if (item) { if (event.shiftKey) { this.actionClick(item, event); @@ -257,7 +250,7 @@ export class Selector { * @returns {boolean} */ autoSelect(bForce) { - (bForce || (this.oCallbacks.AutoSelect || (()=>1))()) + (bForce || (this.oCallbacks.canSelect || (()=>1))()) && this.focusedItem() && this.selectedItem(this.focusedItem()); } diff --git a/dev/Stores/User/Messagelist.js b/dev/Stores/User/Messagelist.js index 025ea728b..42ebda1e8 100644 --- a/dev/Stores/User/Messagelist.js +++ b/dev/Stores/User/Messagelist.js @@ -165,7 +165,7 @@ MessagelistUserStore.notifyNewMessages = (folder, newMessages) => { } } -MessagelistUserStore.canAutoSelect = () => +MessagelistUserStore.canSelect = () => !disableAutoSelect() && SettingsUserStore.usePreviewPane(); // && !SettingsUserStore.showNextMessage(); diff --git a/dev/View/User/MailBox/MessageList.js b/dev/View/User/MailBox/MessageList.js index ef91c15ea..a77de45f9 100644 --- a/dev/View/User/MailBox/MessageList.js +++ b/dev/View/User/MailBox/MessageList.js @@ -237,7 +237,25 @@ export class MailMessageList extends AbstractViewRight { this.selector.on('ItemGetUid', message => (message ? message.generateUid() : '')); - this.selector.on('AutoSelect', () => MessagelistUserStore.canAutoSelect()); + this.selector.on('canSelect', () => MessagelistUserStore.canSelect()); + + this.selector.on('click', (event, currentMessage) => { + const el = event.target; + if (el.closest('.flagparent')) { + if (currentMessage) { + const checked = MessagelistUserStore.listCheckedOrSelected(); + listAction( + currentMessage.folder, + currentMessage.isFlagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, + checked.find(message => message.uid == currentMessage.uid) ? checked : [currentMessage] + ); + } + } else if (el.closest('.threads-len')) { + this.gotoThread(currentMessage); + } else { + return 1; + } + }); this.selector.on('UpOrDown', up => { if (MessagelistUserStore.hasChecked()) { @@ -594,20 +612,6 @@ export class MailMessageList extends AbstractViewRight { el && this.gotoPage(ko.dataFor(el)); eqs(event, '.checkboxCheckAll') && this.checkAll(!this.checkAll()); - - el = eqs(event, '.flagParent'); - let currentMessage = el && ko.dataFor(el); - if (currentMessage) { - const checked = MessagelistUserStore.listCheckedOrSelected(); - listAction( - currentMessage.folder, - currentMessage.isFlagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, - checked.find(message => message.uid == currentMessage.uid) ? checked : [currentMessage] - ); - } - - el = eqs(event, '.threads-len'); - el && this.gotoThread(ko.dataFor(el)); }, dblclick: event => { let el = eqs(event, '.actionHandle'); @@ -674,7 +678,7 @@ export class MailMessageList extends AbstractViewRight { MessagelistUserStore.mainSearch(sLastSearchValue); return false; } - if (MessageUserStore.message() && MessagelistUserStore.canAutoSelect()) { + if (MessageUserStore.message() && MessagelistUserStore.canSelect()) { isFullscreen() || toggleFullscreen(); return false; } diff --git a/snappymail/v/0.0.0/app/templates/Views/User/MailMessageList.html b/snappymail/v/0.0.0/app/templates/Views/User/MailMessageList.html index a5bd63588..39a62aec3 100644 --- a/snappymail/v/0.0.0/app/templates/Views/User/MailMessageList.html +++ b/snappymail/v/0.0.0/app/templates/Views/User/MailMessageList.html @@ -137,14 +137,14 @@
-
-
+
+
-
+
-
- +
+
@@ -157,14 +157,14 @@
-
-
+
+
-
+
-
- +
+
From 1d27c220859ffe952c782618e4bba50162d932e7 Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 2 Oct 2023 14:41:27 +0200 Subject: [PATCH 0019/1002] Resolve #1251 --- plugins/two-factor-auth/js/TwoFactorAuthLogin.js | 2 +- snappymail/v/0.0.0/app/templates/Views/Admin/AdminLogin.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/two-factor-auth/js/TwoFactorAuthLogin.js b/plugins/two-factor-auth/js/TwoFactorAuthLogin.js index d4e4c61e5..e78f8fb3a 100644 --- a/plugins/two-factor-auth/js/TwoFactorAuthLogin.js +++ b/plugins/two-factor-auth/js/TwoFactorAuthLogin.js @@ -17,7 +17,7 @@ + '' + '' + '')); diff --git a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminLogin.html b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminLogin.html index 418b2e6fe..6c081d8ce 100644 --- a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminLogin.html +++ b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminLogin.html @@ -21,7 +21,7 @@
From 611c5f2631dd06f7b047498116b7cdce11bcbae9 Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 2 Oct 2023 14:46:26 +0200 Subject: [PATCH 0020/1002] Resolve #1250 --- snappymail/v/0.0.0/setup.php | 1 + 1 file changed, 1 insertion(+) diff --git a/snappymail/v/0.0.0/setup.php b/snappymail/v/0.0.0/setup.php index 1f460b1f9..c219f6cf3 100644 --- a/snappymail/v/0.0.0/setup.php +++ b/snappymail/v/0.0.0/setup.php @@ -34,6 +34,7 @@ $aRequirements = array( 'mbstring' => extension_loaded('mbstring'), 'Zlib' => extension_loaded('zlib'), // enabled by default: + 'ctype' => extension_loaded('ctype'), 'json' => function_exists('json_decode'), 'libxml' => function_exists('libxml_use_internal_errors'), 'dom' => class_exists('DOMDocument') From d0e6a78f721cbbaf7823da2c121be1a15cb8b198 Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 2 Oct 2023 15:22:24 +0200 Subject: [PATCH 0021/1002] Bump version #1251 --- plugins/two-factor-auth/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/two-factor-auth/index.php b/plugins/two-factor-auth/index.php index 61f583e9f..bcf86d767 100644 --- a/plugins/two-factor-auth/index.php +++ b/plugins/two-factor-auth/index.php @@ -7,8 +7,8 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin { const NAME = 'Two Factor Authentication', - VERSION = '2.16.3', - RELEASE = '2023-06-02', + VERSION = '2.16.4', + RELEASE = '2023-10-02', REQUIRED = '2.15.2', CATEGORY = 'Login', DESCRIPTION = 'Provides support for TOTP 2FA'; From 31d50cf67ea40a3676ae6f60469ea356e3a3f0d8 Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 2 Oct 2023 15:38:02 +0200 Subject: [PATCH 0022/1002] Remove spacing --- vendors/squire/build/squire-raw.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vendors/squire/build/squire-raw.js b/vendors/squire/build/squire-raw.js index 4b20e8311..5530e40ec 100644 --- a/vendors/squire/build/squire-raw.js +++ b/vendors/squire/build/squire-raw.js @@ -3287,7 +3287,7 @@ class Squire return this.focus(); } - _ensureBottomLine () { + _ensureBottomLine() { let root = this._root; let last = root.lastElementChild; if (!last || last.nodeName !== blockTag || !isBlock(last)) { @@ -3297,11 +3297,11 @@ class Squire // --- Get/Set data --- - _getHTML () { + _getHTML() { return this._root.innerHTML; } - _setHTML (html) { + _setHTML(html) { let root = this._root; let node = root; empty(root); From 26b7abf8932af0d44b3870ef754170f0941d25da Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 2 Oct 2023 15:51:19 +0200 Subject: [PATCH 0023/1002] Other solutions for nextcloud auto login #1247 due to a TOTP conflict --- .../snappymail/lib/Util/SnappyMailHelper.php | 7 ++++--- .../snappymail/lib/Util/SnappyMailHelper.php | 2 +- plugins/login-oauth2/index.php | 2 +- .../libraries/RainLoop/Actions/Accounts.php | 2 +- .../app/libraries/RainLoop/Actions/User.php | 4 ++-- .../libraries/RainLoop/Actions/UserAuth.php | 18 ++++++++---------- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/integrations/nextcloud/snappymail/lib/Util/SnappyMailHelper.php b/integrations/nextcloud/snappymail/lib/Util/SnappyMailHelper.php index 4839779d2..38c692c33 100644 --- a/integrations/nextcloud/snappymail/lib/Util/SnappyMailHelper.php +++ b/integrations/nextcloud/snappymail/lib/Util/SnappyMailHelper.php @@ -80,12 +80,13 @@ class SnappyMailHelper if ($doLogin && $aCredentials[1] && $aCredentials[2]) { try { $oActions->Logger()->AddSecret($aCredentials[2]); - - $bSignMe = $oConfig->Get('login', 'sign_me_auto', \RainLoop\Enumerations\SignMeType::DEFAULT_OFF) === \RainLoop\Enumerations\SignMeType::DEFAULT_ON; - $oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2], $bSignMe); + $oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2]); if ($oAccount) { $oActions->Plugins()->RunHook('login.success', array($oAccount)); $oActions->SetAuthToken($oAccount); + if ($oConfig->Get('login', 'sign_me_auto', \RainLoop\Enumerations\SignMeType::DEFAULT_OFF) === \RainLoop\Enumerations\SignMeType::DEFAULT_ON) { + $oActions->SetSignMeToken($oAccount); + } } } catch (\Throwable $e) { // Login failure, reset password to prevent more attempts diff --git a/integrations/owncloud/snappymail/lib/Util/SnappyMailHelper.php b/integrations/owncloud/snappymail/lib/Util/SnappyMailHelper.php index 08fbfd809..73796e2df 100644 --- a/integrations/owncloud/snappymail/lib/Util/SnappyMailHelper.php +++ b/integrations/owncloud/snappymail/lib/Util/SnappyMailHelper.php @@ -137,7 +137,7 @@ class SnappyMailHelper */ if ($doLogin && $aCredentials[1] && $aCredentials[2]) { $oActions->Logger()->AddSecret($aCredentials[2]); - $oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2], false); + $oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2]); if ($oAccount) { $oActions->Plugins()->RunHook('login.success', array($oAccount)); $oActions->SetAuthToken($oAccount); diff --git a/plugins/login-oauth2/index.php b/plugins/login-oauth2/index.php index 1e83dd328..e4e58fe13 100644 --- a/plugins/login-oauth2/index.php +++ b/plugins/login-oauth2/index.php @@ -89,7 +89,7 @@ class LoginOAuth2Plugin extends \RainLoop\Plugins\AbstractPlugin $iErrorCode = \RainLoop\Notifications::UnknownError; try { - $oAccount = $oActions->LoginProcess($sEmail, $sPassword, '', '', false, true); + $oAccount = $oActions->LoginProcess($sEmail, $sPassword); if ($oAccount instanceof \RainLoop\Model\Account) { $oActions->AuthToken($oAccount); $iErrorCode = 0; diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Accounts.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Accounts.php index 7316ddc2e..5a583f6e9 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Accounts.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Accounts.php @@ -93,7 +93,7 @@ trait Accounts } if ($bNew || $sPassword) { - $oNewAccount = $this->LoginProcess($sEmail, $sPassword, false, false); + $oNewAccount = $this->LoginProcess($sEmail, $sPassword, false); $aAccounts[$sEmail] = $oNewAccount->asTokenArray($oMainAccount); } else { $aAccounts[$sEmail] = \RainLoop\Model\AdditionalAccount::convertArray($aAccounts[$sEmail]); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php index 26ae9ad7a..6543aec53 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php @@ -36,18 +36,18 @@ trait User { $sEmail = \MailSo\Base\Utils::Trim($this->GetActionParam('Email', '')); $sPassword = $this->GetActionParam('Password', ''); - $bSignMe = !empty($this->GetActionParam('signMe', 0)); $this->logMask($sPassword); try { - $oAccount = $this->LoginProcess($sEmail, $sPassword, $bSignMe); + $oAccount = $this->LoginProcess($sEmail, $sPassword); } catch (\Throwable $oException) { $this->loginErrorDelay(); throw $oException; } $this->SetAuthToken($oAccount); + empty($this->GetActionParam('signMe', 0)) || $this->SetSignMeToken($oAccount); $this->Plugins()->RunHook('login.success', array($oAccount)); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php index 63d3c9737..75a1952f1 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php @@ -113,7 +113,7 @@ trait UserAuth /** * @throws \RainLoop\Exceptions\ClientException */ - public function LoginProcess(string &$sEmail, string &$sPassword, bool $bSignMe = false, bool $bMainAccount = true): Account + public function LoginProcess(string &$sEmail, string &$sPassword, bool $bMainAccount = true): Account { $sInputEmail = $sEmail; @@ -139,14 +139,6 @@ trait UserAuth $this->imapConnect($oAccount, true); if ($bMainAccount) { - if($bSignMe){ - // SetAuthToken token needs to be called before SetSignMeToken - // because $_COOKIE['smctoken'] is used by Crypt::Passphrase. - // If the $_COOKIE['smctoken'] is not set then SetSignMeToken - // throws an exception - $this->SetAuthToken($oAccount); - $this->SetSignMeToken($oAccount); - } $this->StorageProvider()->Put($oAccount, StorageType::SESSION, Utils::GetSessionToken(), 'true'); } @@ -334,8 +326,14 @@ trait UserAuth return null; } - private function SetSignMeToken(MainAccount $oAccount): void + public function SetSignMeToken(MainAccount $oAccount): void { + // SetAuthToken token needs to be called first + // because $_COOKIE['smctoken'] is used by Crypt::Passphrase. + // If the $_COOKIE['smctoken'] is not set then SetSignMeToken + // throws an exception +// $this->SetAuthToken($oAccount); + $this->ClearSignMeData(); $uuid = \SnappyMail\UUID::generate(); $data = \SnappyMail\Crypt::Encrypt($oAccount); From edad4ac025920eb2557babfcb4389650efb25f61 Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 2 Oct 2023 16:15:29 +0200 Subject: [PATCH 0024/1002] Resolve #1241 --- .../snappymail/lib/Util/SnappyMailHelper.php | 2 +- plugins/two-factor-auth/index.php | 11 +++++++---- .../0.0.0/app/libraries/RainLoop/Actions/UserAuth.php | 3 --- snappymail/v/0.0.0/app/libraries/snappymail/crypt.php | 5 +++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/integrations/nextcloud/snappymail/lib/Util/SnappyMailHelper.php b/integrations/nextcloud/snappymail/lib/Util/SnappyMailHelper.php index 38c692c33..8306cbcb4 100644 --- a/integrations/nextcloud/snappymail/lib/Util/SnappyMailHelper.php +++ b/integrations/nextcloud/snappymail/lib/Util/SnappyMailHelper.php @@ -82,11 +82,11 @@ class SnappyMailHelper $oActions->Logger()->AddSecret($aCredentials[2]); $oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2]); if ($oAccount) { - $oActions->Plugins()->RunHook('login.success', array($oAccount)); $oActions->SetAuthToken($oAccount); if ($oConfig->Get('login', 'sign_me_auto', \RainLoop\Enumerations\SignMeType::DEFAULT_OFF) === \RainLoop\Enumerations\SignMeType::DEFAULT_ON) { $oActions->SetSignMeToken($oAccount); } + $oActions->Plugins()->RunHook('login.success', array($oAccount)); } } catch (\Throwable $e) { // Login failure, reset password to prevent more attempts diff --git a/plugins/two-factor-auth/index.php b/plugins/two-factor-auth/index.php index bcf86d767..dae372f08 100644 --- a/plugins/two-factor-auth/index.php +++ b/plugins/two-factor-auth/index.php @@ -1,6 +1,7 @@ addJs('js/TwoFactorAuthLogin.js'); $this->addJs('js/TwoFactorAuthSettings.js'); - $this->addHook('login.success', 'DoLogin'); +// $this->addHook('login.success', 'DoLogin'); + $this->addHook('imap.after-login', 'DoLogin'); $this->addHook('filter.app-data', 'FilterAppData'); $this->addJsonHook('GetTwoFactorInfo', 'DoGetTwoFactorInfo'); @@ -57,7 +59,8 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin } } - public function DoLogin(MainAccount $oAccount) +// public function DoLogin(MainAccount $oAccount) + public function DoLogin(Account $oAccount) { if ($this->TwoFactorAuthProvider($oAccount)) { $aData = $this->getTwoFactorInfo($oAccount); @@ -240,10 +243,10 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin return $this->Manager()->Actions()->StorageProvider(); } - private $oTwoFactorAuthProvider; + private $oTwoFactorAuthProvider = null; protected function TwoFactorAuthProvider(MainAccount $oAccount) : ?TwoFactorAuthInterface { - if (!$this->oTwoFactorAuthProvider) { + if (!$this->oTwoFactorAuthProvider && $oAccount instanceof MainAccount) { require __DIR__ . '/providers/interface.php'; require __DIR__ . '/providers/totp.php'; $this->oTwoFactorAuthProvider = new TwoFactorAuthTotp(); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php index 75a1952f1..8bef86a96 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php @@ -294,9 +294,6 @@ trait UserAuth { $this->oAdditionalAuthAccount = false; $this->oMainAuthAccount = $oAccount; - if (!isset($_COOKIE['smctoken'])) { - Cookies::set('smctoken', \base64_encode(\random_bytes(16)), 0, false); - } static::SetAccountCookie(self::AUTH_SPEC_TOKEN_KEY, $oAccount); } diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php b/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php index 74246a40a..8028bd251 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php @@ -41,13 +41,14 @@ abstract class Crypt } /** - * When $key is empty, it will use a fingerprint of the user agent. + * When $key is empty, it will use the smctoken. */ private static function Passphrase(?string $key) : string { if (!$key) { if (empty($_COOKIE['smctoken'])) { - throw new \RuntimeException('Missing smctoken'); + \SnappyMail\Cookies::set('smctoken', \base64_encode(\random_bytes(16)), 0, false); +// throw new \RuntimeException('Missing smctoken'); } $key = $_COOKIE['smctoken'] . APP_VERSION; } From d4e76fb42c36b0501293e2708a4446d5d505dcbb Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 2 Oct 2023 16:36:22 +0200 Subject: [PATCH 0025/1002] Improved solution for #1241 --- plugins/two-factor-auth/index.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/two-factor-auth/index.php b/plugins/two-factor-auth/index.php index dae372f08..70df8cbc9 100644 --- a/plugins/two-factor-auth/index.php +++ b/plugins/two-factor-auth/index.php @@ -22,7 +22,7 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin $this->addJs('js/TwoFactorAuthSettings.js'); // $this->addHook('login.success', 'DoLogin'); - $this->addHook('imap.after-login', 'DoLogin'); + $this->addHook('imap.after-login', 'AfterImapLogin'); $this->addHook('filter.app-data', 'FilterAppData'); $this->addJsonHook('GetTwoFactorInfo', 'DoGetTwoFactorInfo'); @@ -60,9 +60,9 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin } // public function DoLogin(MainAccount $oAccount) - public function DoLogin(Account $oAccount) + public function AfterImapLogin(Account $oAccount, \MailSo\Imap\ImapClient $oImapClient, bool $bSuccess) { - if ($this->TwoFactorAuthProvider($oAccount)) { + if ($bSuccess && $this->TwoFactorAuthProvider($oAccount)) { $aData = $this->getTwoFactorInfo($oAccount); if (isset($aData['IsSet'], $aData['Enable']) && !empty($aData['Secret']) && $aData['IsSet'] && $aData['Enable']) { $sCode = \trim($this->jsonParam('totp_code', '')); From a25350aa607b58950065a6e6785d8a447f193c8d Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 2 Oct 2023 17:05:42 +0200 Subject: [PATCH 0026/1002] v2.29.0 --- .../files/usr/local/include/application.ini | 2 +- CHANGELOG.md | 611 ++++++++++-------- README.md | 28 +- integrations/cloudron/DESCRIPTION.md | 2 +- integrations/cloudron/Dockerfile | 2 +- .../nextcloud/snappymail/appinfo/info.xml | 2 +- integrations/virtualmin/snappymail.pl | 2 +- package.json | 2 +- 8 files changed, 358 insertions(+), 293 deletions(-) diff --git a/.docker/release/files/usr/local/include/application.ini b/.docker/release/files/usr/local/include/application.ini index f4bb30b77..31fb0bb40 100644 --- a/.docker/release/files/usr/local/include/application.ini +++ b/.docker/release/files/usr/local/include/application.ini @@ -316,5 +316,5 @@ dev_email = "" dev_password = "" [version] -current = "2.28.4" +current = "2.29.0" saved = "Sun, 18 Dec 2022 22:10:48 +0000" diff --git a/CHANGELOG.md b/CHANGELOG.md index c655d05bd..50d8b762a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,68 @@ +## 2.29.0 – 2023-10-02 + +## Added +- Modern UI / Nextcloud Theme + [#629](https://github.com/the-djmaze/snappymail/pull/629) by @hampoelz +- "Add/Edit signature" label to PopupsIdentity.html by @SergeyMosin + [#1248](https://github.com/the-djmaze/snappymail/pull/1248) +- use calendar icon in message list for messages with '.ics' or 'text/calendar' attachments by @SergeyMosin + [#1248](https://github.com/the-djmaze/snappymail/pull/1248) +- Show unseen message count when the message list is threaded by @SergeyMosin + [#1248](https://github.com/the-djmaze/snappymail/pull/1248) +- in mobile mode hide folders(left) panel when a folder is clicked by @SergeyMosin + [#1248](https://github.com/the-djmaze/snappymail/pull/1248) +- spellcheck the subject when 'allowSpellcheck' setting is true by @SergeyMosin + [#1248](https://github.com/the-djmaze/snappymail/pull/1248) +- 'collapse_blockquotes', 'allow_spellcheck' and 'mail_list_grouped' to admin settings ('defaults' section) by @SergeyMosin + [#1248](https://github.com/the-djmaze/snappymail/pull/1248) +- Browser support for autocompleting TOTP code + [#1251](https://github.com/the-djmaze/snappymail/issues/1251) + +## Changed +- URL strip tracking for + [#1225](https://github.com/the-djmaze/snappymail/issues/1225) +- Color picker use color blind palette "Tableau 10" by Maureen Stone by default + [#1199](https://github.com/the-djmaze/snappymail/issues/1199) +- Draft code to improve mobile breakpoints + [#1150](https://github.com/the-djmaze/snappymail/issues/1150) +- address input: space character can trigger '_parseValue' if the email address looks complete by @SergeyMosin + [#1248](https://github.com/the-djmaze/snappymail/pull/1248) +- if applicable set '\\answered' or '$forwarded' flag after a message is sent so the proper icon is shown in the message list view by @SergeyMosin + [#1248](https://github.com/the-djmaze/snappymail/pull/1248) + +## Fixed +- CHARSET is not valid in UTF8 mode + [#1230](https://github.com/the-djmaze/snappymail/issues/1230) +- Spam score is always "acceptable" + [#1228](https://github.com/the-djmaze/snappymail/issues/1228) +- Undefined constant PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT + [#1205](https://github.com/the-djmaze/snappymail/issues/1205) +- Fetch controller.abort(reason) handling + [#1220](https://github.com/the-djmaze/snappymail/issues/1220) +- "Request failed" on message move + [#1220](https://github.com/the-djmaze/snappymail/issues/1220) +- Unwrapped text nodes attached to squire._root by @SergeyMosin + [#1234](https://github.com/the-djmaze/snappymail/pull/1234) +- Extra wrapper div is added in Squire every time a Draft is open (or closed) after save. + [#1208](https://github.com/the-djmaze/snappymail/issues/1208) +- foreach() argument must be of type array|object + [#1237](https://github.com/the-djmaze/snappymail/issues/1237) +- `` tag 'style' is lost in replies by @SergeyMosin + [#1248](https://github.com/the-djmaze/snappymail/pull/1248) +- unseen indicator is not shown in thread view when 'listGrouped' settings is false by @SergeyMosin + [#1248](https://github.com/the-djmaze/snappymail/pull/1248) +- TOTP plugin is dependent on ctype + [#1250](https://github.com/the-djmaze/snappymail/issues/1250) + +## Nextcloud +- iFrame mode: click on unified search result opens inner iFrame by @SergeyMosin + [#1248](https://github.com/the-djmaze/snappymail/pull/1248) +- set 'smremember' cookie if 'sign_me_auto' is set to 'DefaultOn' when using 'snappymail-autologin*', otherwise nextcloud users need to re-login when the browser is re-opened. by @SergeyMosin + [#1248](https://github.com/the-djmaze/snappymail/pull/1248) +- Improve UX of "Put in Calendar" option in plugin by @theronakpatel + [#1259](https://github.com/the-djmaze/snappymail/pull/1259) + + ## 2.28.4 – 2023-07-10 ## Added @@ -10,29 +75,29 @@ - nextcloud add ability to include custom php file in InstallStep migration by @SergeyMosin [#1197](https://github.com/the-djmaze/snappymail/pull/1197) - Support plugin for Squire editor - [#1192](https://github.com/the-djmaze/snappymail/pull/1192) + [#1192](https://github.com/the-djmaze/snappymail/issues/1192) ## Changed - only show 'Add "domain.tld" as an application for mailto links?' message after login (firefox shows the message on every reload otherwise). - [#1204](https://github.com/the-djmaze/snappymail/pull/1204) + [#1204](https://github.com/the-djmaze/snappymail/issues/1204) - Convert getPdoAccessData() : array to a RainLoop\Pdo\Settings object instance - New bidi buttons to Squire editor by @rezaei92 [#1200](https://github.com/the-djmaze/snappymail/pull/1200) ## Fixed - Undefined constant PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT - [#1205](https://github.com/the-djmaze/snappymail/pull/1205) + [#1205](https://github.com/the-djmaze/snappymail/issues/1205) - 'reloadTime' function result is passed into 'setInterval' instead of the function by @SergeyMosin [#1204](https://github.com/the-djmaze/snappymail/pull/1204) - UNKNOWN-CTE Invalid data in MIME part - [#1186](https://github.com/the-djmaze/snappymail/pull/1186) + [#1186](https://github.com/the-djmaze/snappymail/issues/1186) ## 2.28.3 – 2023-06-22 ## Added - Attachments in "new window" view - [#1166](https://github.com/the-djmaze/snappymail/pull/1166) + [#1166](https://github.com/the-djmaze/snappymail/issues/1166) ## Changed - Update Portuguese by @ner00 @@ -40,22 +105,22 @@ ## Fixed - Some emails with inline CSS break the UI - [#1187](https://github.com/the-djmaze/snappymail/pull/1187) + [#1187](https://github.com/the-djmaze/snappymail/issues/1187) - Remote.get() Promise broken by previous change - [#1185](https://github.com/the-djmaze/snappymail/pull/1185) + [#1185](https://github.com/the-djmaze/snappymail/issues/1185) - Class "MailSo\Base\Exceptions\InvalidArgumentException" not found - [#1182](https://github.com/the-djmaze/snappymail/pull/1182) + [#1182](https://github.com/the-djmaze/snappymail/issues/1182) - First account not showed in the right list (dropbox) - [#1180](https://github.com/the-djmaze/snappymail/pull/1180) + [#1180](https://github.com/the-djmaze/snappymail/issues/1180) ## 2.28.2 – 2023-06-19 ## Added - Detailed error for "Cannot access the repository at the moment" - [#1164](https://github.com/the-djmaze/snappymail/pull/1164) + [#1164](https://github.com/the-djmaze/snappymail/issues/1164) - Bidi in Squire editor - [#1158](https://github.com/the-djmaze/snappymail/pull/1158) + [#1158](https://github.com/the-djmaze/snappymail/issues/1158) - Translate Squire UI - Nextcloud 27 compatibility by @LarsBel - JWT class for handling JSON Web Tokens @@ -65,19 +130,19 @@ - Update French by @hguilbert - Update Polish by @tinola - Merge handling of local Account Settings. Found while investigating - [#1170](https://github.com/the-djmaze/snappymail/pull/1170) + [#1170](https://github.com/the-djmaze/snappymail/issues/1170) - Image max-width now 100% instead of 90vw ## Fixed - Cannot modify header information - [#929](https://github.com/the-djmaze/snappymail/pull/929) (comment) + [#929](https://github.com/the-djmaze/snappymail/issues/929) (comment) - Admin Panel broken when admin_panel_host is set - [#1169](https://github.com/the-djmaze/snappymail/pull/1169) + [#1169](https://github.com/the-djmaze/snappymail/issues/1169) - Invalid CSP report-uri - Prevent MessageList multiple request at the same time - [#1071](https://github.com/the-djmaze/snappymail/pull/1071) + [#1071](https://github.com/the-djmaze/snappymail/issues/1071) - Error in Addressbook Sync - [#1179](https://github.com/the-djmaze/snappymail/pull/1179) + [#1179](https://github.com/the-djmaze/snappymail/issues/1179) - base64_decode() second parameter must be true @@ -85,7 +150,7 @@ ## Changed - Optical issue with input fields for mail and folder search - [#1149](https://github.com/the-djmaze/snappymail/pull/1149) + [#1149](https://github.com/the-djmaze/snappymail/issues/1149) - Update Chinese translation by @mayswind [#1157](https://github.com/the-djmaze/snappymail/pull/1157) - Update Polish translation by @tinola @@ -93,30 +158,30 @@ ## Fixed - Undefined SIG constants - [#1147](https://github.com/the-djmaze/snappymail/pull/1147) + [#1147](https://github.com/the-djmaze/snappymail/issues/1147) ## 2.28.0 – 2023-05-30 ## Added - Threaded view make number orange when unread sub-messages - [#1028](https://github.com/the-djmaze/snappymail/pull/1028) + [#1028](https://github.com/the-djmaze/snappymail/issues/1028) - Handle PHP pctnl messages - addEventListener('rl-view-model') missing for Settings - [#1013](https://github.com/the-djmaze/snappymail/pull/1013) + [#1013](https://github.com/the-djmaze/snappymail/issues/1013) - CSS `--btn-border-radius` ## Changed - Improved RTL languages support - [#1056](https://github.com/the-djmaze/snappymail/pull/1056) + [#1056](https://github.com/the-djmaze/snappymail/issues/1056) - Composer text/attachments as tabs - [#1119](https://github.com/the-djmaze/snappymail/pull/1119) + [#1119](https://github.com/the-djmaze/snappymail/issues/1119) - Filter dialog doesn't refer to folder names consistently - [#1111](https://github.com/the-djmaze/snappymail/pull/1111) + [#1111](https://github.com/the-djmaze/snappymail/issues/1111) - TLS connection for MYSQL contact db - [#1078](https://github.com/the-djmaze/snappymail/pull/1078) + [#1078](https://github.com/the-djmaze/snappymail/issues/1078) - Allow empty message body when there are attachments - [#1052](https://github.com/the-djmaze/snappymail/pull/1052) + [#1052](https://github.com/the-djmaze/snappymail/issues/1052) - PHP inherit logger as Trait - Update Portuguese by @ner00 [#1124](https://github.com/the-djmaze/snappymail/pull/1124) @@ -133,43 +198,43 @@ ## Fixed - Show messagelist timeout/abort error for - [#1071](https://github.com/the-djmaze/snappymail/pull/1071) + [#1071](https://github.com/the-djmaze/snappymail/issues/1071) - DesktopNotifications setting not saved - [#1137](https://github.com/the-djmaze/snappymail/pull/1137) + [#1137](https://github.com/the-djmaze/snappymail/issues/1137) - PHP Deprecation warning for $_openPipes - [#1141](https://github.com/the-djmaze/snappymail/pull/1141) + [#1141](https://github.com/the-djmaze/snappymail/issues/1141) - Images size wrong - [#1134](https://github.com/the-djmaze/snappymail/pull/1134) + [#1134](https://github.com/the-djmaze/snappymail/issues/1134) - Unable to preview body of encrypted mail in mailvelope reply-to - [#1130](https://github.com/the-djmaze/snappymail/pull/1130) + [#1130](https://github.com/the-djmaze/snappymail/issues/1130) - Replace `