diff --git a/build/owncloud.php b/build/owncloud.php new file mode 100755 index 000000000..8f6510157 --- /dev/null +++ b/build/owncloud.php @@ -0,0 +1,97 @@ +version}-owncloud.tar"; + +@unlink($nc_destination); +@unlink("{$nc_destination}.gz"); + +$nc_tar = new PharData($nc_destination); +$hashes = []; + +file_put_contents(ROOT_DIR . '/integrations/owncloud/snappymail/VERSION', $package->version); +$file = ROOT_DIR . '/integrations/owncloud/snappymail/appinfo/info.xml'; +file_put_contents($file, preg_replace('/[^<]*{$package->version}<", file_get_contents($file))); + +$nc_tar->buildFromDirectory('./integrations/owncloud', "@integrations/owncloud/snappymail/@"); +$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('integrations/owncloud/snappymail')); +foreach ($files as $file) { + if (is_file($file)) { + $name = str_replace('\\', '/', $file); + $name = str_replace('integrations/owncloud/snappymail/', '', $name); + $name = str_replace('.htaccess', '_htaccess', $name); + $hashes[$name] = hash_file('sha512', $file); + } +} + +$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('snappymail/v'), RecursiveIteratorIterator::SELF_FIRST); +foreach ($files as $file) { + if (is_file($file)) { + $newFile = str_replace('\\', '/', $file); +// $newFile = str_replace("'snappymail/v/'.", '', $newFile); + $nc_tar->addFile($file, "snappymail/app/{$newFile}"); + $hashes["app/{$newFile}"] = hash_file('sha512', $file); + } +} +/* +$nc_tar->addFile('data/.htaccess'); +$nc_tar->addFromString('data/VERSION', $package->version); +$nc_tar->addFile('data/README.md'); +$nc_tar->addFile('_include.php', 'snappymail/app/_include.php'); +*/ +$nc_tar->addFile('.htaccess', 'snappymail/app/_htaccess'); +$hashes['app/.htaccess'] = hash_file('sha512', '.htaccess'); + +$index = file_get_contents('index.php'); +$index = str_replace('0.0.0', $package->version, $index); +//$index = str_replace('snappymail/v/', '', $index); +$nc_tar->addFromString('snappymail/app/index.php', $index); +$hashes['app/index.php'] = hash('sha512', $index); + +$nc_tar->addFile('README.md', 'snappymail/app/README.md'); +$hashes['app/README.md'] = hash_file('sha512', 'README.md'); + +$nc_tar->addFile('CHANGELOG.md', 'snappymail/CHANGELOG.md'); +$hashes['CHANGELOG.md'] = hash_file('sha512', 'CHANGELOG.md'); + +$data = file_get_contents('dev/serviceworker.js'); +$nc_tar->addFromString('snappymail/app/serviceworker.js', $data); +$hashes['app/serviceworker.js'] = hash('sha512', $data); + +spl_autoload_register(function($name){ + $file = __DIR__ . '/' . str_replace('\\', '/', $name) . '.php'; + echo "{$file}\n"; + require $file; +}); + +if ($cert_dir) { + ksort($hashes); + $cert = file_get_contents($cert_dir.'/snappymail.crt'); + $rsa = new \phpseclib\Crypt\RSA(); + $rsa->loadKey(file_get_contents($cert_dir.'/snappymail.key')); + $x509 = new \phpseclib\File\X509(); + $x509->loadX509($cert); + $x509->setPrivateKey($rsa); + $rsa->setSignatureMode(\phpseclib\Crypt\RSA::SIGNATURE_PSS); + $rsa->setMGFHash('sha512'); + $rsa->setSaltLength(0); + $signature = $rsa->sign(json_encode($hashes)); + $nc_tar->addFromString('snappymail/appinfo/signature.json', json_encode([ + 'hashes' => $hashes, + 'signature' => base64_encode($signature), + 'certificate' => $cert + ], JSON_PRETTY_PRINT)); +} + +$nc_tar->compress(Phar::GZ); +unlink($nc_destination); +$nc_destination .= '.gz'; + +if ($cert_dir) { + $signature = shell_exec("openssl dgst -sha512 -sign {$cert_dir}/snappymail.key {$nc_destination} | openssl base64"); + file_put_contents($nc_destination.'.sig', $signature); +} + +echo "{$nc_destination} created\n"; diff --git a/integrations/owncloud/snappymail/CHANGELOG.md b/integrations/owncloud/snappymail/CHANGELOG.md new file mode 100644 index 000000000..4d0457f06 --- /dev/null +++ b/integrations/owncloud/snappymail/CHANGELOG.md @@ -0,0 +1,774 @@ +## 2.24.4 – 2022-12-30 + +## Added +- Check PHP_INT_SIZE if SnappyMail runs on 64bit + +## Changed +- A lot of MessageList sorting improvements + [#796](https://github.com/the-djmaze/snappymail/pull/796) +- On upgrade also update plugins in Nextcloud due to many misunderstandings and prevent invalid open issues +- Moved application.ini labs.use_app_debug_* to debug.* + +## Fixed +- Dutch translation for confusing message (threads vs grouped) +- Workaround Nextcloud disallowed .htaccess + [#790](https://github.com/the-djmaze/snappymail/pull/790) +- Searching on Nextcloud search failed + [#787](https://github.com/the-djmaze/snappymail/pull/787) + + +## 2.24.3 – 2022-12-28 + +## Changed +- When sorting on FROM also sort on REVERSE DATE + +## Fixed +- F5 and Ctrl-F5 reload logs out of Snappymail in Chrome. + [#800](https://github.com/the-djmaze/snappymail/pull/800) +- Switching accounts does not work anymore with 2.24.2 + [#802](https://github.com/the-djmaze/snappymail/pull/802) + + +## 2.24.2 – 2022-12-27 + +### Changed +- Disable sorting when viewing message thread + [#445](https://github.com/the-djmaze/snappymail/pull/445) +- Update Chinese translation by @mayswind + [#794](https://github.com/the-djmaze/snappymail/pull/794) +- No need to call IMAP EXAMINE when current folder already SELECT +- Thread view now has tree indentation + +### Fixed +- Nextcloud failed on Integrity check + [#790](https://github.com/the-djmaze/snappymail/pull/790) +- Deleting message fails with message "Cannot move message" on hMailServer + [#793](https://github.com/the-djmaze/snappymail/pull/793) +- List messages per day feature is enabled by default and breaks sorting + [#796](https://github.com/the-djmaze/snappymail/pull/796) +- Custom page login not working for first time due to smctoken security + [#798](https://github.com/the-djmaze/snappymail/pull/798) +- Message list is always empty due to wrong implementation of RFC 8474 + [#799](https://github.com/the-djmaze/snappymail/pull/799) + + +## 2.24.1 – 2022-12-23 + +### Changed +- Intl.DateTimeFormat() into toLocaleString() for iOS < 14 +- Cleanup locale date/time handling +- Make MessageList per day optional + [#737](https://github.com/the-djmaze/snappymail/pull/737) + +### Fixed +- Typed property MailSo\Cache\Drivers\Redis::$sKeyPrefix must not be accessed before initialization #792 + [#792](https://github.com/the-djmaze/snappymail/pull/792) +- Attachments in mails in 2.24 not loading in reply/forward #789 + [#789](https://github.com/the-djmaze/snappymail/pull/789) +- Rollback #280 due to complications + [#280](https://github.com/the-djmaze/snappymail/pull/280) + + +## 2.24.0 – 2022-12-22 + +### Added +- Option to enable additional account unread messages count +- Prevent godaddy click tracking +- Dark theme use `color-scheme: dark;` +- More imapsync.php CLI options and help + +### Changed +- MessageList now grouped/split per day + [#737](https://github.com/the-djmaze/snappymail/pull/737) +- Account switcher still shown when allow_additional_accounts is set to Off + [#280](https://github.com/the-djmaze/snappymail/pull/280) +- PHP classes use typed properties +- Speedup Contacts Suggestions handling +- Check SMTP SIZE + [#779](https://github.com/the-djmaze/snappymail/pull/779) + +### Fixed +- Handle multiple DKIM signatures authentication results +- Reload admin extensions on update +- SieveClient quoted string parsing failed +- Invalid Attachments (PDF) + [#466](https://github.com/the-djmaze/snappymail/pull/466) +- Email HTML images rendering issue + [#564](https://github.com/the-djmaze/snappymail/pull/564) +- "Server message: No supported SASL mechanism found, remote server wants:" in hMailServer + [#780](https://github.com/the-djmaze/snappymail/pull/780) + +### Removed +- Some unused plugin hooks to improve Action handling speed + + +## 2.23.1 – 2022-12-15 + +### Changed +- More JMAP RFC matching including role +- Speedup fetch all Folders/mailboxes +- Disable unused folder_list_limit +- Merge MailSo\Mail\Folder into MailSo\Imap\Folder and speedup process +- SnappyMail\Imap\Sync now matches folders based on JMAP role +- Added the new imapsync.php command line script for + [#744](https://github.com/the-djmaze/snappymail/pull/744) +- Added manual setting for 12/24h clock + [#760](https://github.com/the-djmaze/snappymail/pull/760) +- Add options to mark the message I'm viewing as unread and return to the inbox #766 + +### Fixed +- Extension menu shows only some available extensions #778 +- New solution for [#423](https://github.com/the-djmaze/snappymail/pull/423) due to [#774](https://github.com/the-djmaze/snappymail/pull/774) +- Avatars extension error on smartphone + [#764](https://github.com/the-djmaze/snappymail/pull/764) +- Don't fetch Unread count for main account +- CSS .e-checkbox.material-design invisible on show/hide + + +## 2.23.0 – 2022-12-08 + +### Added +- Show the number of unread mails on all mail addresses/accounts + [#437](https://github.com/the-djmaze/snappymail/pull/437) +- Show OpenSSL version in Admin => About + +### Changed +- Redirect to login page instead of "invalid token" popup + [#752](https://github.com/the-djmaze/snappymail/pull/752) +- Make all dialogs fit in mobile view +- Changed some Plugin hooks for better handling: + * json.action-pre-call => json.before-{actionname} + * json.action-post-call => json.after-{actionname} +- Cleaner accounts list in systemdropdown +- Multiple imapConnect handling for new import mail feature + [#744](https://github.com/the-djmaze/snappymail/pull/744) + +### Fixed +- Loosing HTML signature in account identity under settings + [#750](https://github.com/the-djmaze/snappymail/pull/750) +- Plugin configuration did not load anymore when type was SELECTION by @cm-schl + [#753](https://github.com/the-djmaze/snappymail/pull/753) +- Nextcloud Default theme shows gray text on gray background + [#754](https://github.com/the-djmaze/snappymail/pull/754) +- Only run JSON hooks when $sAction is set + [#755](https://github.com/the-djmaze/snappymail/pull/755) +- Unsupported SASL mechanism OAUTHBEARER + [#756](https://github.com/the-djmaze/snappymail/pull/756) + [#758](https://github.com/the-djmaze/snappymail/pull/758) + [#759](https://github.com/the-djmaze/snappymail/pull/759) +- border-box issue with .buttonCompose + +### Removed +- Deprecate \RainLoop\Account->Login() and \RainLoop\Account->Password() + + +## 2.22.7 – 2022-12-06 + +### Changed +- Scroll bar with the mobile version in "Advanced search" screen + [#712](https://github.com/the-djmaze/snappymail/pull/712) + +### Fixed +- Undefined property: MailSo\Mail\FolderCollection::$capabilities +- PHP 8.2 Creation of dynamic property is deprecated +- Attempt to solve #745 in v2.22.6 failed and resulted in errors #746 and #748 + [#745](https://github.com/the-djmaze/snappymail/pull/745) + [#746](https://github.com/the-djmaze/snappymail/pull/746) + [#748](https://github.com/the-djmaze/snappymail/pull/748) +- Admin domain test undefined matched domain should say email@example matched domain + + +## 2.22.6 – 2022-12-05 + +### Changed +- Narrow MessageList wraps star icon + [#737](https://github.com/the-djmaze/snappymail/pull/737) +- Use UIDVALIDITY when HIGHESTMODSEQ not available, maybe solves + [#745](https://github.com/the-djmaze/snappymail/pull/745) +- No need to generate 1000's of ID's for MessageListByRequestIndexOrUids() +- Update Chinese translation by @mayswind + +### Fixed +- PluginProperty DefaultValue contained array while it should not + [#741](https://github.com/the-djmaze/snappymail/pull/741) + +### Removed +- IMAP SELECT/EXAMINE unset `UNSEEN` because IMAP4rev2 deprecated + + +## 2.22.5 – 2022-12-02 + +### Added +- Support plugin minified .min.js and .min.css +- ZIP Download multiple emails + [#717](https://github.com/the-djmaze/snappymail/pull/717) + +### Changed +- Replaced some data-bind="click: function(){} with object functions to prevent eval() +- Improved plugins hash when there are changes + +### Fixed +- Settings Themes style due to border-box change +- "Remember me" failed due to v2.22.4 Session token change + [#719](https://github.com/the-djmaze/snappymail/pull/719) + [#731](https://github.com/the-djmaze/snappymail/pull/731) + +### Removed +- Vacation filter: Button to add recipients (+) + [#728](https://github.com/the-djmaze/snappymail/pull/728) + + +## 2.22.4 – 2022-11-28 + +### Changed +- Contacts dialog layout using flex +- Session token is related to the user agent string + [#713](https://github.com/the-djmaze/snappymail/pull/713) +- Better browser cache handling for avatars plugin + [#714](https://github.com/the-djmaze/snappymail/pull/714) +- Force HTML editor when set as default when replying to message + [#355](https://github.com/the-djmaze/snappymail/pull/355) + +### Fixed +- Contact Error - object Object + [#716](https://github.com/the-djmaze/snappymail/pull/716) +- Unable to move messages to different folder by drag and drop + [#710](https://github.com/the-djmaze/snappymail/pull/710) +- v2.22.3 unknown error + [#709https://github.com/the-djmaze/snappymail/pull/709) + + +## 2.22.3 – 2022-11-25 + +### Added +- application.ini config logs.path and cache.path to improve custom data structure. + +### Changed +- Improved cPanel integration + [#697](https://github.com/the-djmaze/snappymail/pull/697) +- Update to OpenPGP.js v5.5.0 + +### Fixed +- drag & drop folder expansion + [#707](https://github.com/the-djmaze/snappymail/pull/707) +- Save selected messages as .eml in Nextcloud failed + [#704](https://github.com/the-djmaze/snappymail/pull/704) + + +## 2.22.2 – 2022-11-24 + +### Added +- Support cPanel #697 + + +## 2.22.1 – 2022-11-23 + +### Added +- AddressBookInterface::GetContactByEmail() to support sender image/avatar extension + [#115](https://github.com/the-djmaze/snappymail/pull/115) + +### Changed +- All the attachment zone is not clickable, even if the cursor is a hand + [#691](https://github.com/the-djmaze/snappymail/pull/691) +- Different approach for "update button duplicated in admin panel" + [#677](https://github.com/the-djmaze/snappymail/pull/677) +- Better drag & drop solution for leftPanel + +### Fixed +- The page does not change after batch deletion + [#684](https://github.com/the-djmaze/snappymail/pull/684) +- Prevent domain uppercase issues found in + [#689](https://github.com/the-djmaze/snappymail/pull/689) +- Login invalid response: VXNlcm5hbWU6CG + [#693](https://github.com/the-djmaze/snappymail/pull/693) + + +## 2.21.4 – 2022-11-22 + +### Added +- Added domain matcher test for + [#689](https://github.com/the-djmaze/snappymail/pull/689) +- Download all Attachments of selected Emails + [#361](https://github.com/the-djmaze/snappymail/pull/361) + +### Changed +- Log current shortcuts scope for + [#690](https://github.com/the-djmaze/snappymail/pull/690) +- CSS everything to be box-sizing: border-box; +- Make messageview a bit larger so that it is the same height as the messagelist +- Cleanup and rearrange some fontastic glyphs +- Also show From email address by default + [#683](https://github.com/the-djmaze/snappymail/pull/683) + +### Fixed +- Contact.display() returns [object Object] +- When left panel disabled and drag messages, show it +- Issue with admin domain connection type settings selectbox + [#689](https://github.com/the-djmaze/snappymail/pull/689) +- Mobile View on cellphones: automatic scrolling not working near the visual keyboard + [#686](https://github.com/the-djmaze/snappymail/pull/686) +- Unable to separate runtime from installation + [#685](https://github.com/the-djmaze/snappymail/pull/685) + +### Removed +- Removed inline parameter of checkbox and select components + + +## 2.21.3 – 2022-11-16 + +### Added +- Click on PGP KEY attachment opens "Import key" dialog + +### Changed +- Increase visible reading area for small screens + [#672](https://github.com/the-djmaze/snappymail/pull/672) +- Improved message spam score detailed view +- Improved DAV connection logging + +### Fixed +- Handling attachments MIME type / content-type +- Message responsive resizing width/height of elements + [#678](https://github.com/the-djmaze/snappymail/pull/678) +- Focus on textarea when creating a new plain text email + [#501](https://github.com/the-djmaze/snappymail/pull/501) +- CardDav remove photos of my contacts when synchronizing + [#679](https://github.com/the-djmaze/snappymail/pull/679) + +### Removed +- \MailSo\Mime\Enumerations\MimeType + +### Nextcloud +- Use fontastic in Nextcloud Files selector dialog +- Firefox < 98 dialogs + [#673](https://github.com/the-djmaze/snappymail/pull/673) + +## 2.21.2 – 2022-11-15 + +### Added +- Allow browser Spellchecker + [#574](https://github.com/the-djmaze/snappymail/pull/574) +- Decode MIME charset of .EML attachments + [#662](https://github.com/the-djmaze/snappymail/pull/662) + +### Changed +- Increase message visible text area + [#672](https://github.com/the-djmaze/snappymail/pull/672) +- When copy/paste image use the raw data instead of clipboard HTML + [#654](https://github.com/the-djmaze/snappymail/pull/654) +- When application.ini debug.enable is true, also debug js and css +- JavaScript rl.setWindowTitle() renamed to rl.setTitle() + +### Removed +- Message toggle fullscreen button which was only in mobile view + +### Nextcloud +- Workaround Nextcloud calendar crashes + [#622](https://github.com/the-djmaze/snappymail/pull/622) + [#661](https://github.com/the-djmaze/snappymail/pull/661) +- Added share public/internal file link + [#569](https://github.com/the-djmaze/snappymail/pull/569) + + +## 2.21.1 – 2022-11-13 + +### Fixed +- Crypt crashes when Sodium not installed + [#641](https://github.com/the-djmaze/snappymail/pull/641) + [#657](https://github.com/the-djmaze/snappymail/pull/657) + [#663](https://github.com/the-djmaze/snappymail/pull/663) + [#664](https://github.com/the-djmaze/snappymail/pull/664) + [#668](https://github.com/the-djmaze/snappymail/pull/668) + [#669](https://github.com/the-djmaze/snappymail/pull/669) +- Personalised favicon not working - default Snappymail favicon showing + [#665](https://github.com/the-djmaze/snappymail/pull/665) + +### Nextcloud +- v23 ContentSecurityPolicy versions issue + [#666](https://github.com/the-djmaze/snappymail/pull/666) + + +## 2.21.0 – 2022-11-11 + +### Added +- Put messagelist top bar buttons also in dropdown +- Allow setting additional Sec-Fetch rules, as discussed by + [#585](https://github.com/the-djmaze/snappymail/pull/585) +- Light/Dark favicon.svg + [#643](https://github.com/the-djmaze/snappymail/pull/643) +- Allow an account name/label + [#571](https://github.com/the-djmaze/snappymail/pull/571) + +### Changed +- Moved ServiceRemoteAutoLogin to plugin/extension +- Moved ServiceExternalSso to plugin/extension +- Moved ServiceExternalLogin to plugin/extension +- Renamed ManageSieveClient to SieveClient +- New Net/Imap/Smtp/Sieve Settings object system which allows + setting SSL options per domain and verify_certificate by default +- Update plugins to use new Net/Imap/Smtp/Sieve Settings object +- Removed message double-click to full screen + [#638](https://github.com/the-djmaze/snappymail/pull/638) + +### Fixed +- ldap-identities-plugin by @cm-schl + [#647](https://github.com/the-djmaze/snappymail/pull/647) +- OpenSSL v3 ciphers issue + [#641](https://github.com/the-djmaze/snappymail/pull/641) + +### Nextcloud +- Style PopupsNextcloudFiles view +- Link to internal files in composer + + +## 2.20.6 – 2022-11-08 + +### Fixed +- ?admin login failed + [#642](https://github.com/the-djmaze/snappymail/pull/642) +- Resolve PHP 8.2 Creation of dynamic property is deprecated + + +## 2.20.5 – 2022-11-08 + +### Nextcloud +- Improved workaround for Nextcloud Content-Security-Policy bug + Safari [#631](https://github.com/the-djmaze/snappymail/issues/631) + Edge [#633](https://github.com/the-djmaze/snappymail/issues/633) + Reported [#35013](https://github.com/nextcloud/server/issues/35013) + + +## 2.20.4 – 2022-11-07 + +### Fixed +- Nextcloud no-embed use iframe mode failed + +### Nextcloud +- Workaround Nextcloud Content-Security-Policy bug + Safari [#631](https://github.com/the-djmaze/snappymail/issues/631) + Edge [#633](https://github.com/the-djmaze/snappymail/issues/633) + Reported [#35013](https://github.com/nextcloud/server/issues/35013) + + +## 2.20.3 – 2022-11-07 + +### Added +- Throw decrypt errors + [#632](https://github.com/the-djmaze/snappymail/issues/632) + +### Changed +- Better multiple WYSIWYG registration system (not finished) +- Better handling of admin token cookie + +### Fixed +- Cookie “name” has been rejected because it is already expired. + [#636](https://github.com/the-djmaze/snappymail/issues/636) +- Content-Security-Policy 'strict-dynamic' was missing + +### Nextcloud +- Better handling of Content-Security-Policy + [#631](https://github.com/the-djmaze/snappymail/issues/631) + [#633](https://github.com/the-djmaze/snappymail/issues/633) +- Nextcloud 23 Error Call to undefined method useStrictDynamic() + [#634](https://github.com/the-djmaze/snappymail/issues/634) +- Use snappymail icon as favicon-mask.svg instead default nextcloud logo + [#635](https://github.com/the-djmaze/snappymail/issues/635) + + +## 2.20.2 – 2022-11-05 + +### Added +- Add more search operators (i.e. copy lots of Gmail ones) + [#625](https://github.com/the-djmaze/snappymail/issues/625) + +### Changed +- Some CSS borders to var(--border-color) + +### Fixed +- pgpDecrypt() using MailVelope the decrypt message was not green +- Shift + F in search bar resulted in forwarding message + [#624](https://github.com/the-djmaze/snappymail/issues/624) + +### Nextcloud +- auto login mechanism not working anymore + [#627](https://github.com/the-djmaze/snappymail/issues/627) + + +## 2.20.1 – 2022-11-04 + +### Added +- Added CSS --dialog-border-clr and --dialog-border-radius +- Show lock (lock) glyph in messagelist for encrypted messages + +### Fixed +- Decrypt failed when OpenPGP.js not loaded + +### Nextcloud +- Now integrate with Nextcloud by default, but keep iframe option available +- Better theme integration with Nextcloud +- Use Nextcloud 18+ IEventDispatcher +- Solve Nextcloud 25 CSS issues + [#620](https://github.com/the-djmaze/snappymail/issues/620) +- PutinICS does is not working for all calendar events + [#622](https://github.com/the-djmaze/snappymail/issues/622) +- Update readme by @cm-schl + [#617](https://github.com/the-djmaze/snappymail/issues/617) + + +## 2.20.0 – 2022-11-03 + +### Added +- Strip mailchimp tracking + +### Changed +- Use some PHP typed properties +- Move bootstrap @less variables to CSS var() +- Improved theme styling + +### Fixed +- CSS --dropdown-menu-background-color should be --dropdown-menu-bg-color + +### Nextcloud +- Disable Nextcloud Impersonate check due to login/logout complications + [#561](https://github.com/the-djmaze/snappymail/issues/561) +- Improved theme integration and be compatible with Breeze Dark + + +## 2.19.7 – 2022-11-02 + +### Added +- Make it clear that you are on the admin panel login screen +- Force PHP opcache_invalidate due to upgrade error reports "Missing version directory" + +### Fixed +- Switching user (impersonate plugin) keeps old Email logged in + [#561](https://github.com/the-djmaze/snappymail/issues/561) +- PGP Decryption / Encryption Failures + [#600](https://github.com/the-djmaze/snappymail/issues/600) +- Undefined constant "OCA\SnappyMail\Util\RAINLOOP_APP_LIBRARIES_PATH + [#601](https://github.com/the-djmaze/snappymail/issues/601) +- Cannot access admin panel + [#602](https://github.com/the-djmaze/snappymail/issues/602) +- Wont show my emails + [#604](https://github.com/the-djmaze/snappymail/issues/604) +- Return type of MailSo\Base\StreamFilters\LineEndings::filter + [#610](https://github.com/the-djmaze/snappymail/issues/610) +- Create .pgp directory was missing + +### Security +- Logger leaked some passwords + +## 2.19.6 – 2022-10-31 + +### Added +- Put sign and encrypt options in composer dropdown menu and simplify te two existing buttons with a glyph +- Filter scripts UI let user understand which filter is active + [#590](https://github.com/the-djmaze/snappymail/issues/590) + +### Fixed +- Method 'GetRequest' not found in \MailSo\Base\Http + [#585](https://github.com/the-djmaze/snappymail/issues/585) + +### Changed +- Base Domain setup enhancements +- Cleanup MailSo MailClient using __call() +- Domain settings handling and store as JSON instead of ini +- Some JavaScript changes +- When try to login IMAP/SMTP/SIEVE but STARTTLS is required, force STARTTLS +- Embed admin panel into Nextcloud (with autologin, no need for separate login) +- Don't set default_domain in Nextcloud when already set + +### Removed +- Nextcloud dark mode, it is incomplete + +### Deprecated +- nothing +## 2.21.0 – 2022-11-11 + +### Added +- Put messagelist top bar buttons also in dropdown +- Allow setting additional Sec-Fetch rules, as discussed by #585 +- Light/Dark favicon.svg #643 +- Allow an account name/label #571 + +### Changed +- Moved ServiceRemoteAutoLogin to plugin/extension +- Moved ServiceExternalSso to plugin/extension +- Moved ServiceExternalLogin to plugin/extension +- Renamed ManageSieveClient to SieveClient +- New Net/Imap/Smtp/Sieve Settings object system which allows + setting SSL options per domain and verify_certificate by default +- Update plugins to use new Net/Imap/Smtp/Sieve Settings object +- Removed message double-click to full screen #638 + +### Fixed +- ldap-identities-plugin by @cm-schl + [#647](https://github.com/the-djmaze/snappymail/pull/647) +- OpenSSL v3 ciphers issue #641 + +### Nextcloud +- Style PopupsNextcloudFiles view +- Link to internal files in composer + + +## 2.20.6 – 2022-11-08 + +### Fixed +- ?admin login failed + [#642](https://github.com/the-djmaze/snappymail/pull/642) +- Resolve PHP 8.2 Creation of dynamic property is deprecated + + +## 2.20.5 – 2022-11-08 + +### Nextcloud +- Improved workaround for Nextcloud Content-Security-Policy bug + Safari [#631](https://github.com/the-djmaze/snappymail/issues/631) + Edge [#633](https://github.com/the-djmaze/snappymail/issues/633) + Reported [#35013](https://github.com/nextcloud/server/issues/35013) + + +## 2.20.4 – 2022-11-07 + +### Fixed +- Nextcloud no-embed use iframe mode failed + +### Nextcloud +- Workaround Nextcloud Content-Security-Policy bug + Safari [#631](https://github.com/the-djmaze/snappymail/issues/631) + Edge [#633](https://github.com/the-djmaze/snappymail/issues/633) + Reported [#35013](https://github.com/nextcloud/server/issues/35013) + + +## 2.20.3 – 2022-11-07 + +### Added +- Throw decrypt errors + [#632](https://github.com/the-djmaze/snappymail/issues/632) + +### Changed +- Better multiple WYSIWYG registration system (not finished) +- Better handling of admin token cookie + +### Fixed +- Cookie “name” has been rejected because it is already expired. + [#636](https://github.com/the-djmaze/snappymail/issues/636) +- Content-Security-Policy 'strict-dynamic' was missing + +### Nextcloud +- Better handling of Content-Security-Policy + [#631](https://github.com/the-djmaze/snappymail/issues/631) + [#633](https://github.com/the-djmaze/snappymail/issues/633) +- Nextcloud 23 Error Call to undefined method useStrictDynamic() + [#634](https://github.com/the-djmaze/snappymail/issues/634) +- Use snappymail icon as favicon-mask.svg instead default nextcloud logo + [#635](https://github.com/the-djmaze/snappymail/issues/635) + + +## 2.20.2 – 2022-11-05 + +### Added +- Add more search operators (i.e. copy lots of Gmail ones) + [#625](https://github.com/the-djmaze/snappymail/issues/625) + +### Changed +- Some CSS borders to var(--border-color) + +### Fixed +- pgpDecrypt() using MailVelope the decrypt message was not green +- Shift + F in search bar resulted in forwarding message + [#624](https://github.com/the-djmaze/snappymail/issues/624) + +### Nextcloud +- auto login mechanism not working anymore + [#627](https://github.com/the-djmaze/snappymail/issues/627) + + +## 2.20.1 – 2022-11-04 + +### Added +- Added CSS --dialog-border-clr and --dialog-border-radius +- Show lock (lock) glyph in messagelist for encrypted messages + +### Fixed +- Decrypt failed when OpenPGP.js not loaded + +### Nextcloud +- Now integrate with Nextcloud by default, but keep iframe option available +- Better theme integration with Nextcloud +- Use Nextcloud 18+ IEventDispatcher +- Solve Nextcloud 25 CSS issues + [#620](https://github.com/the-djmaze/snappymail/issues/620) +- PutinICS does is not working for all calendar events + [#622](https://github.com/the-djmaze/snappymail/issues/622) +- Update readme by @cm-schl + [#617](https://github.com/the-djmaze/snappymail/issues/617) + + +## 2.20.0 – 2022-11-03 + +### Added +- Strip mailchimp tracking + +### Changed +- Use some PHP typed properties +- Move bootstrap @less variables to CSS var() +- Improved theme styling + +### Fixed +- CSS --dropdown-menu-background-color should be --dropdown-menu-bg-color + +### Nextcloud +- Disable Nextcloud Impersonate check due to login/logout complications + [#561](https://github.com/the-djmaze/snappymail/issues/561) +- Improved theme integration and be compatible with Breeze Dark + + +## 2.19.7 – 2022-11-02 + +### Added +- Make it clear that you are on the admin panel login screen +- Force PHP opcache_invalidate due to upgrade error reports "Missing version directory" + +### Fixed +- Switching user (impersonate plugin) keeps old Email logged in + [#561](https://github.com/the-djmaze/snappymail/issues/561) +- PGP Decryption / Encryption Failures + [#600](https://github.com/the-djmaze/snappymail/issues/600) +- Undefined constant "OCA\SnappyMail\Util\RAINLOOP_APP_LIBRARIES_PATH + [#601](https://github.com/the-djmaze/snappymail/issues/601) +- Cannot access admin panel + [#602](https://github.com/the-djmaze/snappymail/issues/602) +- Wont show my emails + [#604](https://github.com/the-djmaze/snappymail/issues/604) +- Return type of MailSo\Base\StreamFilters\LineEndings::filter + [#610](https://github.com/the-djmaze/snappymail/issues/610) +- Create .pgp directory was missing + +### Security +- Logger leaked some passwords + +## 2.19.6 – 2022-10-31 + +### Added +- Put sign and encrypt options in composer dropdown menu and simplify te two existing buttons with a glyph +- Filter scripts UI let user understand which filter is active + [#590](https://github.com/the-djmaze/snappymail/issues/590) + +### Fixed +- Method 'GetRequest' not found in \MailSo\Base\Http + [#585](https://github.com/the-djmaze/snappymail/issues/585) + +### Changed +- Base Domain setup enhancements +- Cleanup MailSo MailClient using __call() +- Domain settings handling and store as JSON instead of ini +- Some JavaScript changes +- When try to login IMAP/SMTP/SIEVE but STARTTLS is required, force STARTTLS +- Embed admin panel into Nextcloud (with autologin, no need for separate login) +- Don't set default_domain in Nextcloud when already set + +### Removed +- Nextcloud dark mode, it is incomplete + +### Deprecated +- nothing diff --git a/integrations/owncloud/snappymail/INSTALL b/integrations/owncloud/snappymail/INSTALL new file mode 100644 index 000000000..e199b596b --- /dev/null +++ b/integrations/owncloud/snappymail/INSTALL @@ -0,0 +1,17 @@ +************************************************************************ +* +* ownCloud - SnappyMail Webmail package +* +* @author SnappyMail Team, Nextgen-Networks (@nextgen-networks), Tab Fitts (@tabp0le), Pierre-Alain Bandinelli (@pierre-alain-b) +* +************************************************************************ + +REQUIREMENTS: +- ownCloud version 10 and above + +INSTALL & CONFIGURATION: +Start within ownCloud, and click on the "+ Apps" button in the upper-left corner dropdown menu: +Then, enable the SnappyMail plugin that is in the "Social & communication" section. +After a quick wait, SnappyMail is installed. Even if it is really attractive, it is too soon to click on the newly appeared "Email" icon in the apps list. You should configure SnappyMail before using it (which makes some sense, doesn'it): go to ownCloud admin panel (upper-right corner dropdown menu) and go to "Additionnal settings". There click on the "Go to SnappyMail Webmail admin panel". +In the SnappyMail admin prompt, the default login is "admin" and the default password will be generated in "[nextcloud-data]/app_snappymail/_data_/_default_/admin_password.txt". No need to advise you to change it once in the admin panel! +This is it, you are now free to configure SnappyMail as you wish. One important point is the Domains section when you will set up the IMAP/SMTP parameters that shall be associated with the email adresses of your users. diff --git a/integrations/owncloud/snappymail/README.md b/integrations/owncloud/snappymail/README.md new file mode 100644 index 000000000..dd64fad96 --- /dev/null +++ b/integrations/owncloud/snappymail/README.md @@ -0,0 +1,97 @@ +# snappymail-owncloud + +snappymail-owncloud is a plugin for ownCloud to use the excellent SnappyMail webmail (https://snappymail.eu/). + +Thank you to all contributors to SnappyMail for ownCloud: +- RainLoop Team, who initiated it +- [pierre-alain-b](https://github.com/pierre-alain-b/rainloop-owncloud) +- Tab Fitts (@tabp0le) +- Nextgen Networks (@nextgen-networks) +- [All testers of issue 96](https://github.com/the-djmaze/snappymail/issues/96) + +## How to Install + +Start within ownCloud as user with administrator rights and click on the "+ Apps" button in the upper-right corner dropdown menu: + +![Image1](https://raw.githubusercontent.com/the-djmaze/snappymail/master/integrations/owncloud/screenshots/help_a1.png) + +Then, enable the SnappyMail plugin that you will find in the "Social & communication" section: + +![Image2](https://raw.githubusercontent.com/the-djmaze/snappymail/master/integrations/owncloud/screenshots/help_a2.png) + +After a quick wait, SnappyMail is installed. Now you should configure it before use: open the ownCloud admin panel (upper-right corner dropdown menu -> Settings) and go to "Additional settings" under the "Administration" section. There, click on the "Go to SnappyMail Webmail admin panel" link. + +![Image3](https://raw.githubusercontent.com/the-djmaze/snappymail/master/integrations/owncloud/screenshots/owncloud-admin.png) + +To enter SnappyMail admin area, you must be ownCloud admin (so you get logged in automatically) or else use the admin login credentials. +The default login is "admin" and the default password will be generated in `[owncloud-data]/app_snappymail/_data_/_default_/admin_password.txt`. Don't forget to change it once in the admin panel! + +From that point, all instance-wide SnappyMail settings can be tweaked as you wish. One important point is the "Domains" section where you should set up the IMAP/SMTP parameters that will be associated with the email adresses of your users. Basically, if a user of the ownCloud instance starts SnappyMail and puts "firstname@domain.tld" as an email address, then SnappyMail should know how to connect to the IMAP & SMTP of domain.tld. You can fill in this information in the "Domains" section of the SnappyMail admin settings. For more information how to configure an automatic login for your ownCloud users see [How to auto-connect to SnappyMail?](#how-to-auto-connect-to-snappymail) + +![grafik](https://user-images.githubusercontent.com/63400209/199767908-fbef0f50-ecb7-47ae-9ac1-771959d4b7f5.png) + +![grafik](https://user-images.githubusercontent.com/63400209/199768097-7bd939a7-56d0-47ba-b481-aeac08776fb4.png) + + +## SnappyMail Settings, Where Are They? + +SnappyMail for ownCloud is highly configurable. But settings are available in multiple places and this can be misleading for first-time users. + +### SnappyMail admin settings +SnappyMail admin settings can be reached only by the ownCloud administrator. Open the ownCloud admin panel ("Admin" in the upper-right corner dropdown menu) and go to "Additionnal settings". There, click on the "Go to SnappyMail Webmail admin panel" link. Alternatively, you may use the following link: https://path.to.owncloud/index.php/apps/snappymail/?admin. + +SnappyMail admin settings include all settings that will apply to all SnappyMail users (default login rules, branding, management of plugins, security rules and domains). + +### SnappyMail user settings +Each user of SnappyMail can also change user-specific behaviors in the SnappyMail user settings. SnappyMail user settings are found within SnappyMail by clicking on the user button (in the upper-right corner of SnappyMail) and then choosing "Settings" in the dropdown menu. + +SnappyMail user settings include management of contacts, of email accounts, of folders, appearance and OpenPGP. + +### The specificity of SnappyMail user accounts +The plugin passes the login information of the user to the SnappyMail app which then creates and manages the user accounts. Accounts in SnappyMail are based soley on the authenticated email accounts, and do not take into account the owncloud user which created them in the first place. If two or more ownCloud users have the same email account in additional settings, they will in fact share the same 'email account' in SnappyMail including any additional email accounts that they may have added subsequently to their main account. +This is to be kept in mind for the use case where multiple users shall have the same email account but may be also tempted to add additionnal acounts to their SnappyMail. + +## How to auto-connect to SnappyMail? + +### Default Domain +As already said SnappyMail uses the domain part (@example.com) to choose the IMAP/SMTP server to use. If in the following settings the username passed to SnappyMail does not contain a domain, the "default domain" is added to this username. In this way SnappyMail can lookup the "Domain" configuration to use (IMAP, SMTP, SIEVE server ecc.). +Example: if the username `john` is passed to SnappyMail, the "default domain" `example.com` would be added to the username basing on your configuration. So SnappyMail would try to login the user with the username `john@example.com`. + +You can configure the "default domain" and connected settings in the SnappyMail Admin Panel under the menu "Login". + +### Auto-connect options +The ownCloud administrator can choose how SnappyMail tries to automatically login when a user clicks on the icon of SnappyMail within ownCloud. There are different options that can be found in the ownCloud "Settings -> Administration -> Additional settings": + +#### Option 1: Users will login manually, or define credentials in their personal settings for automatic logins. +If the user sets his credentials for the mailbox in his personal account under "Settings -> Additional settings", these credentials are used by SnappyMail to login. +If no personal credentials are defined the user is prompted by SnappyMail to insert his credentials every time he tries to open the SnappyMail App within ownCloud. + +#### Option 2: Attempt to automatically login users with their ownCloud username and password, or user-defined credentials, if set. +If the user sets his credentials for the mailbox in his personal account under "Settings -> Additional settings", these credentials are used by SnappyMail to login. +If no personal credentials are defined the ownCloud username and password is used by SnappyMail to login (eventually adding the [default domain](#default-domain)). + +If your IMAP server only accepts usernames without a domain (for example the ldap username of your user) the automatic addition of the "default domain" would block your users from logging in to your IMAP server - but on the other side it is needed by SnappyMail to determine the server settings to use. In such a case you must configure SnappyMail to strip off the domain part before sending the credentials to your IMAP server. This is done by entering to the SnappyMail Admin Panel -> Domains -> clicking on your default domain -> flagging the checkbox "Use short login" under IMAP and SMTP. + +#### Option 3: Attempt to automatically login users with their ownCloud email and password, or user-defined credentials, if set. +If the user sets his credentials for the mailbox in his personal account under "Settings -> Additional settings", these credentials are used by SnappyMail to login. +If no personal credentials are defined the mail address of the ownCloud user and his password are used by SnappyMail to login. SnappyMail will lookup the "Domain" settings for a configuration that meets the domain part of the mail address passed as username. + +### Auto-connection for all ownCloud users +If your ownCloud users base is synchronized with an email system, then it is possible that ownCloud credentials could be used right away to access the centralized email system. In the SnappyMail admin settings, the ownCloud administrator can then tick the "Automatically login with ownCloud/ownCloud user credentials" checkbox. + +Beware, if you tick this box, all ownCloud users will *not* be able to use the override it with the setting below. + +### Auto-connection for one user at a time +Except if the above setting is activated, any ownCloud user can have ownCloud and SnappyMail keep in mind the default email/password to connect to SnappyMail. There, logging in ownCloud is sufficient to then access SnappyMail within ownCloud. + +To fill in the default email address and password to use, each ownCloud user should go in the personal settings: choose "Settings" in the upper-right corner dropdown menu. Under "Personal" select the "Additional settings" section where you can find the "SnappyMail Webmail" settings. You can also use this direct link: https://path.to.owncloud/settings/user/additional. + + +## How to Activate SnappyMail Logging and then Find Logs + +You can activate SnappyMail logging here: `/path/to/owncloud/data/appdata_snappymail/_data_/_default_/configs/application.ini` +``` +[logs] +enable = On +``` +Logs are then available in `/path/to/owncloud/data/appdata_snappymail/_data_/_default_/logs/` diff --git a/integrations/owncloud/snappymail/appinfo/info.xml b/integrations/owncloud/snappymail/appinfo/info.xml new file mode 100644 index 000000000..84ce9cb7f --- /dev/null +++ b/integrations/owncloud/snappymail/appinfo/info.xml @@ -0,0 +1,76 @@ + + + snappymail + SnappyMail + SnappyMail Webmail + 2.24.4 + agpl + SnappyMail, RainLoop Team, Nextgen-Networks, Tab Fitts, Nathan Kinkade, Pierre-Alain Bandinelli + + SnappyMail + + https://github.com/the-djmaze/snappymail/blob/master/integrations/owncloud/snappymail/README.md + https://github.com/the-djmaze/snappymail/wiki + + integration + office + search + social + https://raw.githubusercontent.com/the-djmaze/snappymail/master/integrations/owncloud/screenshots/inbox.jpg + https://snappymail.eu + https://github.com/the-djmaze/snappymail/discussions + https://github.com/the-djmaze/snappymail/tree/master/integrations/owncloud + https://github.com/the-djmaze/snappymail/issues + + + mbstring + zlib + + + + + OCA\SnappyMail\Settings\AdminSettings + OCA\SnappyMail\Settings\PersonalSettings + + + + Email + snappymail.page.index + logo-white-64x64.png + 4 + + + diff --git a/integrations/owncloud/snappymail/appinfo/routes.php b/integrations/owncloud/snappymail/appinfo/routes.php new file mode 100644 index 000000000..5304f9869 --- /dev/null +++ b/integrations/owncloud/snappymail/appinfo/routes.php @@ -0,0 +1,41 @@ + [ + [ + 'name' => 'page#index', + 'url' => '/', + 'verb' => 'GET' + ], + [ + 'name' => 'page#indexPost', + 'url' => '/', + 'verb' => 'POST' + ], + [ + 'name' => 'page#appGet', + 'url' => '/run/', + 'verb' => 'GET' + ], + [ + 'name' => 'page#appPost', + 'url' => '/run/', + 'verb' => 'POST' + ], + [ + 'name' => 'fetch#setPersonal', + 'url' => '/fetch/personal.php', + 'verb' => 'POST' + ], + [ + 'name' => 'fetch#setAdmin', + 'url' => '/fetch/admin.php', + 'verb' => 'POST' + ], + [ + 'name' => 'fetch#upgrade', + 'url' => '/fetch/upgrade', + 'verb' => 'POST' + ] + ] +]; diff --git a/integrations/owncloud/snappymail/css/embed.css b/integrations/owncloud/snappymail/css/embed.css new file mode 100644 index 000000000..150a27fe9 --- /dev/null +++ b/integrations/owncloud/snappymail/css/embed.css @@ -0,0 +1,124 @@ +/* +This stylesheet is used when SnappyMail runs in embed mode. +*/ +#content.app-snappymail { + max-height: 100%; +} +#content #rl-app { + position: relative; + min-width: 100%; + min-height: 100%; +} + +.squire-wysiwyg { + min-width: 100%; + min-height: 100%; +} + +#V-AdminPane .btn-logout { + display: none; +} + +#rl-app select, +#rl-app input +{ + min-height: auto; + height: auto; + margin: 0; + padding: 3px; +} +#rl-app .select, #rl-app select { + padding-right: 1.5em !important; +} + +#rl-app button.btn:not(.button-vue) { + min-height: auto; + height: auto; + margin: 0; + padding: 4px 12px; +} + +#rl-app .form-horizontal .control-group > :not(label) +{ + margin-left: 20px; +} + +#rl-app .LoginView .fontastic + input { + padding-left: 30px; +} + +#rl-app .loading::after { + display: none; +} + +#rl-app .squire-plain, #rl-app .squire-wysiwyg { + font-size: 13px; + height: 100%; + line-height: 16px; + min-height: 200px; +} + +#rl-app tbody tr:hover { + background-color: inherit; +} + +#rl-app table { + white-space: inherit; +} + +body > header ul { + margin: 0; +} + +#rl-app h3 { + color: inherit; +} + +.messageListItem * { + cursor: pointer; +} + +/** + * Firefox < 98 + * https://github.com/the-djmaze/snappymail/issues/673 + */ +#rl-app dialog.polyfill { + margin-top: 50px; + max-height: calc(100vh - 60px); +} + +/** + * hampoelz + * https://github.com/the-djmaze/snappymail/issues/96#issuecomment-1279783076 + */ + +.messageList { + margin: 0 5px 0 0; +} + +a.selectable { + margin: 2px; + height: 38px !important; + line-height: 38px !important; + border-radius: var(--border-radius-pill); +} + +a.selectable::after { + display: block; + margin: 0 !important; + top: 50%; + transform: translateY(-50%); +} + +.btn { + border: initial !important; +} + +@media print { + #body-user #header { + display: none; + } + #content { + padding-top: 0; + } +} diff --git a/integrations/owncloud/snappymail/css/style.css b/integrations/owncloud/snappymail/css/style.css new file mode 100644 index 000000000..88f73b2f7 --- /dev/null +++ b/integrations/owncloud/snappymail/css/style.css @@ -0,0 +1,6 @@ +/* +Empty style sheet! +Only needed to give you the opportunity to theme the owncloud part +of the snappymail app with the theming system integrated in ownCoud +if the snappymail app is activated. +*/ diff --git a/integrations/owncloud/snappymail/img/favicon-touch.png b/integrations/owncloud/snappymail/img/favicon-touch.png new file mode 100644 index 000000000..78ab30b38 Binary files /dev/null and b/integrations/owncloud/snappymail/img/favicon-touch.png differ diff --git a/integrations/owncloud/snappymail/img/favicon.ico b/integrations/owncloud/snappymail/img/favicon.ico new file mode 100644 index 000000000..ce6462649 Binary files /dev/null and b/integrations/owncloud/snappymail/img/favicon.ico differ diff --git a/integrations/owncloud/snappymail/img/logo-64x64.png b/integrations/owncloud/snappymail/img/logo-64x64.png new file mode 100644 index 000000000..78ab30b38 Binary files /dev/null and b/integrations/owncloud/snappymail/img/logo-64x64.png differ diff --git a/integrations/owncloud/snappymail/img/logo-white-64x64.png b/integrations/owncloud/snappymail/img/logo-white-64x64.png new file mode 100644 index 000000000..1bca3e09a Binary files /dev/null and b/integrations/owncloud/snappymail/img/logo-white-64x64.png differ diff --git a/integrations/owncloud/snappymail/js/snappymail.js b/integrations/owncloud/snappymail/js/snappymail.js new file mode 100644 index 000000000..f3aae6f49 --- /dev/null +++ b/integrations/owncloud/snappymail/js/snappymail.js @@ -0,0 +1,107 @@ +/** + * Nextcloud - SnappyMail mail plugin + * + * @author RainLoop Team, Nextgen-Networks (@nextgen-networks), Tab Fitts (@tabp0le), Pierre-Alain Bandinelli (@pierre-alain-b), SnappyMail + * + * Based initially on https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud/rainloop-app + */ + +// Do the following things once the document is fully loaded. +document.onreadystatechange = () => { + if (document.readyState === 'complete') { + watchIFrameTitle(); + let form = document.querySelector('form.snappymail'); + form && SnappyMailFormHelper(form); + } +}; + +// The SnappyMail application is already configured to modify the element +// of its root document with the number of unread messages in the inbox. +// However, its document is the SnappyMail iframe. This function sets up a +// Mutation Observer to watch the <title> element of the iframe for changes in +// the unread message count and propagates that to the parent <title> element, +// allowing the unread message count to be displayed in the NC tab's text when +// the SnappyMail app is selected. +function watchIFrameTitle() { + let iframe = document.getElementById('rliframe'); + if (!iframe) { + return; + } + let target = iframe.contentDocument.getElementsByTagName('title')[0]; + let config = { + characterData: true, + childList: true, + subtree: true + }; + let observer = new MutationObserver(mutations => { + let title = mutations[0].target.innerText; + if (title) { + let matches = title.match(/\(([0-9]+)\)/); + if (matches) { + document.title = '('+ matches[1] + ') ' + t('snappymail', 'Email') + ' - Nextcloud'; + } else { + document.title = t('snappymail', 'Email') + ' - Nextcloud'; + } + } + }); + observer.observe(target, config); +} + +function SnappyMailFormHelper(oForm) +{ + try + { + var + oSubmit = document.getElementById('snappymail-save-button'), + sSubmitValue = oSubmit.textContent, + oDesc = oForm.querySelector('.snappymail-result-desc') + ; + + oForm.addEventListener('submit', oEvent => { + oEvent.preventDefault(); + + oForm.classList.add('snappymail-fetch') + oForm.classList.remove('snappymail-error') + oForm.classList.remove('snappymail-success') + + oDesc.textContent = ''; + oSubmit.textContent = '...'; + + let data = new FormData(oForm); + data.set('appname', 'snappymail'); + + fetch(OC.filePath('snappymail', 'fetch', oForm.getAttribute('action')), { + mode: 'same-origin', + cache: 'no-cache', + redirect: 'error', + referrerPolicy: 'no-referrer', + credentials: 'same-origin', + method: 'POST', + headers: {}, + body: data + }) + .then(response => response.json()) + .then(oData => { + let bResult = 'success' === oData?.status; + oForm.classList.remove('snappymail-fetch'); + oSubmit.textContent = sSubmitValue; + if (oData?.Message) { + oDesc.textContent = t('snappymail', oData.Message); + } + if (bResult) { + oForm.classList.add('snappymail-success'); + } else { + oForm.classList.add('snappymail-error'); + if ('' === oDesc.textContent) { + oDesc.textContent = t('snappymail', 'Error'); + } + } + }); + + return false; + }); + } + catch(e) { + console.error(e); + } +} diff --git a/integrations/owncloud/snappymail/l10n/en_GB.js b/integrations/owncloud/snappymail/l10n/en_GB.js new file mode 100644 index 000000000..dc856193f --- /dev/null +++ b/integrations/owncloud/snappymail/l10n/en_GB.js @@ -0,0 +1,9 @@ +OC.L10N.register( + "snappymail", + { + "Email" : "Email", + "Error" : "Error", + "Save" : "Save", + "Password" : "Password" +}, +"nplurals=2; plural=(n != 1);"); diff --git a/integrations/owncloud/snappymail/l10n/en_GB.json b/integrations/owncloud/snappymail/l10n/en_GB.json new file mode 100644 index 000000000..98a2adb74 --- /dev/null +++ b/integrations/owncloud/snappymail/l10n/en_GB.json @@ -0,0 +1,7 @@ +{ "translations": { + "Email" : "Email", + "Error" : "Error", + "Save" : "Save", + "Password" : "Password" +},"pluralForm" :"nplurals=2; plural=(n != 1);" +} \ No newline at end of file diff --git a/integrations/owncloud/snappymail/lib/AppInfo/Application.php b/integrations/owncloud/snappymail/lib/AppInfo/Application.php new file mode 100644 index 000000000..6eb04652c --- /dev/null +++ b/integrations/owncloud/snappymail/lib/AppInfo/Application.php @@ -0,0 +1,106 @@ +<?php + +namespace OCA\SnappyMail\AppInfo; + +use OCA\SnappyMail\Util\SnappyMailHelper; +use OCA\SnappyMail\Controller\FetchController; +use OCA\SnappyMail\Controller\PageController; +use OCA\SnappyMail\Search\Provider; + +use OCP\AppFramework\App; +use OCP\IL10N; +use OCP\IUser; +use OCP\User\Events\PostLoginEvent; +use OCP\User\Events\BeforeUserLoggedOutEvent; +use OCP\IContainer; + +class Application extends App +{ + public const APP_ID = 'snappymail'; + + public function __construct(array $urlParams = []) + { + parent::__construct(self::APP_ID, $urlParams); + + $container = $this->getContainer(); + $server = $container->getServer(); + + /** + * Controllers + *//* + $container->registerService( + 'PageController', function(IContainer $c) { + return new PageController( + $c->query('AppName'), + $c->query('Request') + ); + } + ); + + $container->registerService( + 'FetchController', function(IContainer $c) { + return new FetchController( + $c->query('AppName'), + $c->query('Request'), + $c->getServer()->getAppManager(), + $c->query('ServerContainer')->getConfig(), + $c->query(IL10N::class) + ); + } + ); + + /** + * Utils + *//* + $container->registerService( + 'SnappyMailHelper', function(IContainer $c) { + return new SnappyMailHelper(); + } + ); +*/ +// $container->registerSearchProvider(Provider::class); + } +/* + public function boot(IBootContext $context): void + { + if (!\is_dir(\rtrim(\trim(\OC::$server->getSystemConfig()->getValue('datadirectory', '')), '\\/') . '/appdata_snappymail')) { + return; + } + + $dispatcher = $context->getAppContainer()->query('OCP\EventDispatcher\IEventDispatcher'); + $dispatcher->addListener(PostLoginEvent::class, function (PostLoginEvent $Event) { + $config = \OC::$server->getConfig(); + // Only store the user's password in the current session if they have + // enabled auto-login using ownCloud username or email address. + if ($config->getAppValue('snappymail', 'snappymail-autologin', false) + || $config->getAppValue('snappymail', 'snappymail-autologin-with-email', false)) { + $sUID = $Event->getUser()->getUID(); + \OC::$server->getSession()['snappymail-nc-uid'] = $sUID; + \OC::$server->getSession()['snappymail-password'] = SnappyMailHelper::encodePassword($Event->getPassword(), $sUID); + } + }); + + $dispatcher->addListener(BeforeUserLoggedOutEvent::class, function (BeforeUserLoggedOutEvent $Event) { + \OC::$server->getSession()['snappymail-password'] = ''; + SnappyMailHelper::loadApp(); + \RainLoop\Api::Actions()->Logout(true); + }); + + // https://github.com/nextcloud/impersonate/issues/179 + // https://github.com/nextcloud/impersonate/pull/180 + $class = 'OCA\Impersonate\Events\BeginImpersonateEvent'; + if (\class_exists($class)) { + $dispatcher->addListener($class, function ($Event) { + \OC::$server->getSession()['snappymail-password'] = ''; + SnappyMailHelper::loadApp(); + \RainLoop\Api::Actions()->Logout(true); + }); + $dispatcher->addListener('OCA\Impersonate\Events\EndImpersonateEvent', function ($Event) { + \OC::$server->getSession()['snappymail-password'] = ''; + SnappyMailHelper::loadApp(); + \RainLoop\Api::Actions()->Logout(true); + }); + } + } +*/ +} diff --git a/integrations/owncloud/snappymail/lib/ContentSecurityPolicy.php b/integrations/owncloud/snappymail/lib/ContentSecurityPolicy.php new file mode 100644 index 000000000..f144f835c --- /dev/null +++ b/integrations/owncloud/snappymail/lib/ContentSecurityPolicy.php @@ -0,0 +1,53 @@ +<?php + +namespace OCA\SnappyMail; + +class ContentSecurityPolicy extends \OCP\AppFramework\Http\ContentSecurityPolicy { + + /** @var bool Whether inline JS snippets are allowed */ + protected $inlineScriptAllowed = false; + /** @var bool Whether eval in JS scripts is allowed */ + protected $evalScriptAllowed = true; + /** @var bool Whether strict-dynamic should be set */ +// protected $strictDynamicAllowed = true; // NC24+ + /** @var bool Whether inline CSS is allowed */ + protected $inlineStyleAllowed = true; + + function __construct() { + $CSP = \RainLoop\Api::getCSP(); + + $this->allowedScriptDomains = \array_unique(\array_merge($this->allowedScriptDomains, $CSP->script)); + $this->allowedScriptDomains = \array_diff($this->allowedScriptDomains, ["'unsafe-inline'", "'unsafe-eval'"]); + + // Nextcloud only sets 'strict-dynamic' when browserSupportsCspV3() ? + \method_exists($this, 'useStrictDynamic') + ? $this->useStrictDynamic(true) // NC24+ + : $this->addAllowedScriptDomain("'strict-dynamic'"); + + $this->allowedImageDomains = \array_unique(\array_merge($this->allowedImageDomains, $CSP->img)); + + $this->allowedStyleDomains = \array_unique(\array_merge($this->allowedStyleDomains, $CSP->style)); + $this->allowedStyleDomains = \array_diff($this->allowedStyleDomains, ["'unsafe-inline'"]); + + $this->allowedFrameDomains = \array_unique(\array_merge($this->allowedFrameDomains, $CSP->frame)); + +// $this->reportTo = \array_unique(\array_merge($this->reportTo, $CSP->report_to)); + } + + public function getSnappyMailNonce() { + static $sNonce; + if (!$sNonce) { +/* + $cspManager = \OC::$server->getContentSecurityPolicyNonceManager(); + $sNonce = $cspManager->getNonce() ?: \SnappyMail\UUID::generate(); + if (\method_exists($cspManager, 'browserSupportsCspV3') && !$cspManager->browserSupportsCspV3()) { + $this->addAllowedScriptDomain("'nonce-{$sNonce}'"); + } +*/ + $sNonce = \SnappyMail\UUID::generate(); + $this->addAllowedScriptDomain("'nonce-{$sNonce}'"); + } + return $sNonce; + } + +} diff --git a/integrations/owncloud/snappymail/lib/Controller/FetchController.php b/integrations/owncloud/snappymail/lib/Controller/FetchController.php new file mode 100644 index 000000000..df8c8dabe --- /dev/null +++ b/integrations/owncloud/snappymail/lib/Controller/FetchController.php @@ -0,0 +1,132 @@ +<?php + +namespace OCA\SnappyMail\Controller; + +use OCA\SnappyMail\Util\SnappyMailHelper; + +use OCP\App\IAppManager; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\JSONResponse; +use OCP\IConfig; +use OCP\IL10N; +use OCP\IRequest; + +class FetchController extends Controller { + private $config; + private $appManager; + + public function __construct(string $appName, IRequest $request, IAppManager $appManager, IConfig $config, IL10N $l) { + parent::__construct($appName, $request); + $this->config = $config; + $this->appManager = $appManager; + $this->l = $l; + } + + public function upgrade(): JSONResponse { + $error = 'Upgrade failed'; + try { + SnappyMailHelper::loadApp(); + if (SnappyMail\Upgrade::core()) { + return new JSONResponse([ + 'status' => 'success', + 'Message' => $this->l->t('Upgraded successfully') + ]); + } + } catch (Exception $e) { + $error .= ': ' . $e->getMessage(); + } + return new JSONResponse([ + 'status' => 'error', + 'Message' => $error + ]); + } + + public function setAdmin(): JSONResponse { + try { + $sUrl = ''; + $sPath = ''; + + if (isset($_POST['appname']) && 'snappymail' === $_POST['appname']) { + $this->config->setAppValue('snappymail', 'snappymail-autologin', + isset($_POST['snappymail-autologin']) ? '1' === $_POST['snappymail-autologin'] : false); + $this->config->setAppValue('snappymail', 'snappymail-autologin-with-email', + isset($_POST['snappymail-autologin']) ? '2' === $_POST['snappymail-autologin'] : false); + $this->config->setAppValue('snappymail', 'snappymail-no-embed', isset($_POST['snappymail-no-embed'])); + } else { + return new JSONResponse([ + 'status' => 'error', + 'Message' => $this->l->t('Invalid argument(s)') + ]); + } + + if (!empty($_POST['import-rainloop'])) { + $result = SnappyMailHelper::importRainLoop(); + return new JSONResponse([ + 'status' => 'success', + 'Message' => \implode("\n", $result) + ]); + } + + SnappyMailHelper::loadApp(); + $debug = !empty($_POST['snappymail-debug']); + $oConfig = \RainLoop\Api::Config(); + if ($debug != $oConfig->Get('debug', 'enable', false)) { + $oConfig->Set('debug', 'enable', $debug); + $oConfig->Save(); + } + + return new JSONResponse([ + 'status' => 'success', + 'Message' => $this->l->t('Saved successfully') + ]); + } catch (Exception $e) { + return new JSONResponse([ + 'status' => 'error', + 'Message' => $e->getMessage() + ]); + } + } + + /** + * @NoAdminRequired + */ + public function setPersonal(): JSONResponse { + try { + + if (isset($_POST['appname'], $_POST['snappymail-password'], $_POST['snappymail-email']) && 'snappymail' === $_POST['appname']) { + $sUser = \OC::$server->getUserSession()->getUser()->getUID(); + + $sPostEmail = $_POST['snappymail-email']; + $this->config->setUserValue($sUser, 'snappymail', 'snappymail-email', $sPostEmail); + + $sPass = $_POST['snappymail-password']; + if ('******' !== $sPass) { + require_once $this->appManager->getAppPath('snappymail').'/lib/Util/SnappyMailHelper.php'; + + $this->config->setUserValue($sUser, 'snappymail', 'snappymail-password', + $sPass ? SnappyMailHelper::encodePassword($sPass, \md5($sPostEmail)) : ''); + } + + $sEmail = $this->config->getUserValue($sUser, 'snappymail', 'snappymail-email', ''); + } else { + return new JSONResponse([ + 'status' => 'error', + 'Message' => $this->l->t('Invalid argument(s)'), + 'Email' => $sEmail + ]); + } + + return new JSONResponse([ + 'status' => 'success', + 'Message' => $this->l->t('Saved successfully'), + 'Email' => $sEmail + ]); + } catch (Exception $e) { + return new JSONResponse([ + 'status' => 'error', + 'Message' => $e->getMessage() + ]); + } + } +} + diff --git a/integrations/owncloud/snappymail/lib/Controller/PageController.php b/integrations/owncloud/snappymail/lib/Controller/PageController.php new file mode 100644 index 000000000..e3617b9c3 --- /dev/null +++ b/integrations/owncloud/snappymail/lib/Controller/PageController.php @@ -0,0 +1,117 @@ +<?php + +namespace OCA\SnappyMail\Controller; + +use OCA\SnappyMail\Util\SnappyMailHelper; +use OCA\SnappyMail\ContentSecurityPolicy; + +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\TemplateResponse; + +class PageController extends Controller +{ + /** + * @NoAdminRequired + * @NoCSRFRequired + */ + public function index() + { + $config = \OC::$server->getConfig(); + + $bAdmin = false; + if (!empty($_SERVER['QUERY_STRING'])) { + SnappyMailHelper::loadApp(); + $bAdmin = \RainLoop\Api::Config()->Get('security', 'admin_panel_key', 'admin') == $_SERVER['QUERY_STRING']; + if (!$bAdmin) { + SnappyMailHelper::startApp(true); + } + } + + if (!$bAdmin && $config->getAppValue('snappymail', 'snappymail-no-embed')) { + \OC::$server->getNavigationManager()->setActiveEntry('snappymail'); + \OCP\Util::addScript('snappymail', 'snappymail'); + \OCP\Util::addStyle('snappymail', 'style'); + SnappyMailHelper::startApp(); + $response = new TemplateResponse('snappymail', 'index', [ + 'snappymail-iframe-url' => SnappyMailHelper::normalizeUrl(SnappyMailHelper::getAppUrl()) + . (empty($_GET['target']) ? '' : "#{$_GET['target']}") + ]); + $csp = new ContentSecurityPolicy(); + $csp->addAllowedFrameDomain("'self'"); + $response->setContentSecurityPolicy($csp); + return $response; + } + + \OC::$server->getNavigationManager()->setActiveEntry('snappymail'); + + \OCP\Util::addStyle('snappymail', 'embed'); + + SnappyMailHelper::startApp(); + $oConfig = \RainLoop\Api::Config(); + $oActions = $bAdmin ? new \RainLoop\ActionsAdmin() : \RainLoop\Api::Actions(); + $oHttp = \MailSo\Base\Http::SingletonInstance(); + $oServiceActions = new \RainLoop\ServiceActions($oHttp, $oActions); + $sAppJsMin = $oConfig->Get('debug', 'javascript', false) ? '' : '.min'; + $sAppCssMin = $oConfig->Get('debug', 'css', false) ? '' : '.min'; + $sLanguage = $oActions->GetLanguage(false); + + $csp = new ContentSecurityPolicy(); + $sNonce = $csp->getSnappyMailNonce(); + + $params = [ + 'Admin' => $bAdmin ? 1 : 0, + 'LoadingDescriptionEsc' => \htmlspecialchars($oConfig->Get('webmail', 'loading_description', 'SnappyMail'), ENT_QUOTES|ENT_IGNORE, 'UTF-8'), + 'BaseTemplates' => \RainLoop\Utils::ClearHtmlOutput($oServiceActions->compileTemplates($bAdmin)), + 'BaseAppBootScript' => \file_get_contents(APP_VERSION_ROOT_PATH.'static/js'.($sAppJsMin ? '/min' : '').'/boot'.$sAppJsMin.'.js'), + 'BaseAppBootScriptNonce' => $sNonce, + 'BaseLanguage' => $oActions->compileLanguage($sLanguage, $bAdmin), + 'BaseAppBootCss' => \file_get_contents(APP_VERSION_ROOT_PATH.'static/css/boot'.$sAppCssMin.'.css'), + 'BaseAppThemeCssLink' => $oActions->ThemeLink($bAdmin), + 'BaseAppThemeCss' => \preg_replace( + '/\\s*([:;{},]+)\\s*/s', + '$1', + $oActions->compileCss($oActions->GetTheme($bAdmin), $bAdmin) + ) + ]; + +// \OCP\Util::addScript('snappymail', '../app/snappymail/v/'.APP_VERSION.'/static/js'.($sAppJsMin ? '/min' : '').'/boot'.$sAppJsMin); + + // ownCloud html encodes, so addHeader('style') is not possible +// \OCP\Util::addHeader('style', ['id'=>'app-boot-css'], \file_get_contents(APP_VERSION_ROOT_PATH.'static/css/boot'.$sAppCssMin.'.css')); + \OCP\Util::addHeader('link', ['type'=>'text/css','rel'=>'stylesheet','href'=>\RainLoop\Utils::WebStaticPath('css/'.($bAdmin?'admin':'app').$sAppCssMin.'.css')], ''); +// \OCP\Util::addHeader('style', ['id'=>'app-theme-style','data-href'=>$params['BaseAppThemeCssLink']], $params['BaseAppThemeCss']); + + $response = new TemplateResponse('snappymail', 'index_embed', $params); + + $response->setContentSecurityPolicy($csp); + + return $response; + } + + /** + * @NoAdminRequired + * @NoCSRFRequired + */ + public function appGet() + { + SnappyMailHelper::startApp(true); + } + + /** + * @NoAdminRequired + * @NoCSRFRequired + */ + public function appPost() + { + SnappyMailHelper::startApp(true); + } + + /** + * @NoAdminRequired + * @NoCSRFRequired + */ + public function indexPost() + { + SnappyMailHelper::startApp(true); + } +} diff --git a/integrations/owncloud/snappymail/lib/Search/Provider.php b/integrations/owncloud/snappymail/lib/Search/Provider.php new file mode 100644 index 000000000..7b9b63157 --- /dev/null +++ b/integrations/owncloud/snappymail/lib/Search/Provider.php @@ -0,0 +1,129 @@ +<?php + +declare(strict_types=1); + +namespace OCA\SnappyMail\Search; + +use OCA\SnappyMail\AppInfo\Application; +use OCA\SnappyMail\Util\SnappyMailHelper; +use OCP\IDateTimeFormatter; +use OCP\IL10N; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\Search\IProvider; +use OCP\Search\ISearchQuery; +use OCP\Search\SearchResult; +use OCP\Search\SearchResultEntry; + +/** + * https://docs.nextcloud.com/server/latest/developer_manual/digging_deeper/search.html#search-providers + */ +class Provider implements IProvider +{ + /** @var IL10N */ + private $l10n; + + /** @var IURLGenerator */ + private $urlGenerator; + + public function __construct(IL10N $l10n, IURLGenerator $urlGenerator) + { + $this->l10n = $l10n; + $this->urlGenerator = $urlGenerator; + } + + public function getId(): string + { + return Application::APP_ID; + } + + public function getName(): string + { + return 'SnappyMail'; +// return $this->l10n->t('Mails'); + } + + public function getOrder(string $route, array $routeParameters): int + { + if (0 === \strpos($route, Application::APP_ID . '.')) { + // Active app, prefer Mail results + return -1; + } + return 20; + } + + public function search(IUser $user, ISearchQuery $query): SearchResult + { + $result = []; + if (2 > \strlen(\trim($query->getTerm()))) { + return SearchResult::complete($this->getName(), $result); + } + SnappyMailHelper::startApp(); + $oActions = \RainLoop\Api::Actions(); +// $oAccount = $oActions->getMainAccountFromToken(false); // Issue: when account switched, wrong email is shown + $oAccount = $oActions->getAccountFromToken(false); + $iCursor = (int) $query->getCursor(); + $iLimit = $query->getLimit(); + if ($oAccount) { + $oConfig = $oActions->Config(); + + $oParams = new \MailSo\Mail\MessageListParams; + $oParams->sFolderName = 'INBOX'; // or \All ? + $oParams->sSearch = $query->getTerm(); + $oParams->oCacher = ($oConfig->Get('cache', 'enable', true) && $oConfig->Get('cache', 'server_uids', false)) + ? $oActions->Cacher($oAccount) : null; + $oParams->bUseSortIfSupported = !!$oConfig->Get('labs', 'use_imap_sort', true); +// $oParams->bUseThreads = $oConfig->Get('labs', 'use_imap_thread', false); +// $oParams->bHideDeleted = false; +// $oParams->sSort = (string) $aValues['Sort']; +// ISearchQuery::SORT_DATE_DESC == $query->getSortOrder(): int; + $oParams->iOffset = $iCursor; + $oParams->iLimit = $iLimit; +// $oParams->iPrevUidNext = 0, // used to check for new messages +// $oParams->iThreadUid = 0; + + $oMailClient = $oActions->MailClient(); + if (!$oMailClient->IsLoggined()) { + $oAccount->ImapConnectAndLoginHelper($oActions->Plugins(), $oMailClient->ImapClient(), $oConfig); + } + + // instanceof \MailSo\Mail\MessageCollection + $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 { + $baseURL .= '#'; + } + $search = \rawurlencode($oParams->sSearch); + +// $MessageCollection->totalEmails; + foreach ($MessageCollection as $Message) { + // $Message instanceof \MailSo\Mail\Message + $result[] = new SearchResultEntry( + // thumbnailUrl + '', + // title + $Message->Subject(), + // subline + $Message->From()->ToString(), + // resourceUrl /index.php/apps/snappymail/#/mailbox/INBOX/p2/text=an&unseen + $baseURL . '/mailbox/INBOX/m' . $Message->Uid() . '/' . $search, + // icon + 'icon-mail', + // rounded + false + ); + } + } else { + \error_log('SnappyMail not logged in to use unified search'); + } + + if ($iLimit > \count($result)) { + return SearchResult::complete($this->getName(), $result); + } + return SearchResult::paginated($this->getName(), $result, $iCursor + $iLimit); + } +} diff --git a/integrations/owncloud/snappymail/lib/Settings/AdminSettings.php b/integrations/owncloud/snappymail/lib/Settings/AdminSettings.php new file mode 100644 index 000000000..c55adf025 --- /dev/null +++ b/integrations/owncloud/snappymail/lib/Settings/AdminSettings.php @@ -0,0 +1,77 @@ +<?php +namespace OCA\SnappyMail\Settings; + +use OCA\SnappyMail\Util\SnappyMailHelper; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\IConfig; +use OCP\Settings\ISettings; + +class AdminSettings implements ISettings +{ + private $config; + + public function __construct(IConfig $config) + { + $this->config = $config; + } + + public function getPanel() + { + \OCA\SnappyMail\Util\SnappyMailHelper::loadApp(); + + $keys = [ + 'snappymail-autologin', + 'snappymail-autologin-with-email', + 'snappymail-no-embed' + ]; + $parameters = []; + foreach ($keys as $k) { + $v = $this->config->getAppValue('snappymail', $k); + $parameters[$k] = $v; + } + $uid = \OC::$server->getUserSession()->getUser()->getUID(); + if (\OC_User::isAdminUser($uid)) { +// $parameters['snappymail-admin-panel-link'] = SnappyMailHelper::getAppUrl().'?admin'; + SnappyMailHelper::loadApp(); + $parameters['snappymail-admin-panel-link'] = + \OC::$server->getURLGenerator()->linkToRoute('snappymail.page.index') + . '?' . \RainLoop\Api::Config()->Get('security', 'admin_panel_key', 'admin'); + } + + $oConfig = \RainLoop\Api::Config(); + $passfile = APP_PRIVATE_DATA . 'admin_password.txt'; + $sPassword = ''; + if (\is_file($passfile)) { + $sPassword = \file_get_contents($passfile); + $parameters['snappymail-admin-panel-link'] .= '#/security'; + } + $parameters['snappymail-admin-password'] = $sPassword; + + $parameters['can-import-rainloop'] = $sPassword && \is_dir( + \rtrim(\trim(\OC::$server->getSystemConfig()->getValue('datadirectory', '')), '\\/') + . '/rainloop-storage' + ); + + $parameters['snappymail-debug'] = $oConfig->Get('debug', 'enable', false); + + // Check for owncloud plugin update, if so then update + foreach (\SnappyMail\Repository::getPackagesList()['List'] as $plugin) { + if ('owncloud' == $plugin['id'] && $plugin['canBeUpdated']) { + \SnappyMail\Repository::installPackage('plugin', 'owncloud'); + } + } + + \OCP\Util::addScript('snappymail', 'snappymail'); + return new TemplateResponse('snappymail', 'admin-local', $parameters); + } + + public function getSectionID() + { + return 'additional'; + } + + public function getPriority() + { + return 50; + } +} diff --git a/integrations/owncloud/snappymail/lib/Settings/PersonalSettings.php b/integrations/owncloud/snappymail/lib/Settings/PersonalSettings.php new file mode 100644 index 000000000..310beb17b --- /dev/null +++ b/integrations/owncloud/snappymail/lib/Settings/PersonalSettings.php @@ -0,0 +1,37 @@ +<?php +namespace OCA\SnappyMail\Settings; + +use OCP\AppFramework\Http\TemplateResponse; +use OCP\IConfig; +use OCP\Settings\ISettings; + +class PersonalSettings implements ISettings +{ + private $config; + + public function __construct(IConfig $config) + { + $this->config = $config; + } + + public function getPanel() + { + $uid = \OC::$server->getUserSession()->getUser()->getUID(); + $parameters = [ + 'snappymail-email' => $this->config->getUserValue($uid, 'snappymail', 'snappymail-email'), + 'snappymail-password' => $this->config->getUserValue($uid, 'snappymail', 'snappymail-password') ? '******' : '' + ]; + \OCP\Util::addScript('snappymail', 'snappymail'); + return new TemplateResponse('snappymail', 'personal_settings', $parameters, ''); + } + + public function getSectionID() + { + return 'additional'; + } + + public function getPriority() + { + return 50; + } +} diff --git a/integrations/owncloud/snappymail/lib/Util/SnappyMailHelper.php b/integrations/owncloud/snappymail/lib/Util/SnappyMailHelper.php new file mode 100644 index 000000000..08fbfd809 --- /dev/null +++ b/integrations/owncloud/snappymail/lib/Util/SnappyMailHelper.php @@ -0,0 +1,278 @@ +<?php + +namespace OCA\SnappyMail\Util; + +class SnappyMailHelper +{ + + public static function loadApp() : void + { + if (\class_exists('RainLoop\\Api')) { + return; + } + + // ownCloud the default spl_autoload_register() not working + \spl_autoload_register(function($sClassName){ + $file = SNAPPYMAIL_LIBRARIES_PATH . \strtolower(\strtr($sClassName, '\\', DIRECTORY_SEPARATOR)) . '.php'; + if (\is_file($file)) { + include_once $file; + } + }); + + $_ENV['SNAPPYMAIL_OWNCLOUD'] = true; // Obsolete + $_ENV['SNAPPYMAIL_INCLUDE_AS_API'] = true; + +// define('APP_VERSION', '0.0.0'); +// define('APP_INDEX_ROOT_PATH', __DIR__ . DIRECTORY_SEPARATOR); +// include APP_INDEX_ROOT_PATH.'snappymail/v/'.APP_VERSION.'/include.php'; +// define('APP_DATA_FOLDER_PATH', \rtrim(\trim(\OC::$server->getSystemConfig()->getValue('datadirectory', '')), '\\/').'/appdata_snappymail/'); + + $app_dir = \dirname(\dirname(__DIR__)) . '/app'; + require_once $app_dir . '/index.php'; + + // https://github.com/the-djmaze/snappymail/issues/790#issuecomment-1366527884 + if (!file_exists($app_dir . '/.htaccess') && file_exists($app_dir . '/_htaccess')) { + rename($app_dir . '/_htaccess', $app_dir . '/.htaccess'); + if (!file_exists(APP_VERSION_ROOT_PATH . '/app/.htaccess') && file_exists(APP_VERSION_ROOT_PATH . '/app/_htaccess')) { + rename(APP_VERSION_ROOT_PATH . '/app/_htaccess', APP_VERSION_ROOT_PATH . '/app/.htaccess'); + } + if (!file_exists(APP_VERSION_ROOT_PATH . '/static/.htaccess') && file_exists(APP_VERSION_ROOT_PATH . '/static/_htaccess')) { + rename(APP_VERSION_ROOT_PATH . '/static/_htaccess', APP_VERSION_ROOT_PATH . '/static/.htaccess'); + } + } + + $oConfig = \RainLoop\Api::Config(); + $bSave = false; + + if (!$oConfig->Get('webmail', 'app_path')) { + $oConfig->Set('webmail', 'app_path', \OC::$server->getAppManager()->getAppWebPath('snappymail') . '/app/'); + $bSave = true; + } + + if (!\is_dir(APP_PLUGINS_PATH . 'owncloud')) { + \SnappyMail\Repository::installPackage('plugin', 'owncloud'); + $oConfig->Set('plugins', 'enable', true); + $aList = \SnappyMail\Repository::getEnabledPackagesNames(); + $aList[] = 'owncloud'; + $oConfig->Set('plugins', 'enabled_list', \implode(',', \array_unique($aList))); +// $oConfig->Set('webmail', 'theme', 'ownCloud@custom'); + $bSave = true; + } + + $sPassword = $oConfig->Get('security', 'admin_password'); + if ('12345' == $sPassword || !$sPassword) { + $sPassword = \substr(\base64_encode(\random_bytes(16)), 0, 12); + $oConfig->SetPassword($sPassword); + \RainLoop\Utils::saveFile(APP_PRIVATE_DATA . 'admin_password.txt', $sPassword . "\n"); + $bSave = true; + } + + // Pre-configure domain + $ocConfig = \OC::$server->getConfig(); + if ($ocConfig->getAppValue('snappymail', 'snappymail-autologin', false) + || $ocConfig->getAppValue('snappymail', 'snappymail-autologin-with-email', false) + ) { + $oProvider = \RainLoop\Api::Actions()->DomainProvider(); + $oDomain = $oProvider->Load('owncloud'); + if (!$oDomain) { +// $oDomain = \RainLoop\Model\Domain::fromIniArray('owncloud', []); + $oDomain = new \RainLoop\Model\Domain('owncloud'); + $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::NONE; + $oDomain->SetConfig( + 'localhost', 143, $iSecurityType, true, + true, 'localhost', 4190, $iSecurityType, + 'localhost', 25, $iSecurityType, true, true, false, false, + ''); + $oProvider->Save($oDomain); + if (!$oConfig->Get('login', 'default_domain', '')) { + $oConfig->Set('login', 'default_domain', 'owncloud'); + $bSave = true; + } + } + } + + $bSave && $oConfig->Save(); + } + + public static function startApp(bool $handle = false) : void + { + static::loadApp(); + + try { + $oActions = \RainLoop\Api::Actions(); + $oConfig = \RainLoop\Api::Config(); + if (isset($_GET[$oConfig->Get('security', 'admin_panel_key', 'admin')])) { + if ($oConfig->Get('security', 'allow_admin_panel', true) + && \OC_User::isAdminUser(\OC::$server->getUserSession()->getUser()->getUID()) + && !$oActions->IsAdminLoggined(false) + ) { + $sRand = \MailSo\Base\Utils::Sha1Rand(); + if ($oActions->Cacher(null, true)->Set(\RainLoop\KeyPathHelper::SessionAdminKey($sRand), \time())) { + $sToken = \RainLoop\Utils::EncodeKeyValuesQ(array('token', $sRand)); +// $oActions->setAdminAuthToken($sToken); + \RainLoop\Utils::SetCookie('smadmin', $sToken); + } + } + } else { + $doLogin = !$oActions->getMainAccountFromToken(false); + $aCredentials = static::getLoginCredentials(); +/* + // NC25+ workaround for Impersonate plugin + // https://github.com/the-djmaze/snappymail/issues/561#issuecomment-1301317723 + // https://github.com/nextcloud/server/issues/34935#issuecomment-1302145157 + require \OC::$SERVERROOT . '/version.php'; +// \OC\SystemConfig +// file_get_contents(\OC::$SERVERROOT . 'config/config.php'); +// $CONFIG['version'] + if (24 < $OC_Version[0]) { + $ocSession = \OC::$server->getSession(); + $ocSession->reopen(); + if (!$doLogin && $ocSession['snappymail-uid'] && $ocSession['snappymail-uid'] != $aCredentials[0]) { + // UID changed, Impersonate plugin probably active + $oActions->Logout(true); + $doLogin = true; + } + $ocSession->set('snappymail-uid', $aCredentials[0]); + } +*/ + if ($doLogin && $aCredentials[1] && $aCredentials[2]) { + $oActions->Logger()->AddSecret($aCredentials[2]); + $oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2], false); + if ($oAccount) { + $oActions->Plugins()->RunHook('login.success', array($oAccount)); + $oActions->SetAuthToken($oAccount); + } + } + } + } catch (\Throwable $e) { + // Ignore login failure + } + + if ($handle) { + \header_remove('Content-Security-Policy'); + \RainLoop\Service::Handle(); + exit; + } + } + + public static function getLoginCredentials() : array + { + $sEmail = ''; + $sPassword = ''; + $config = \OC::$server->getConfig(); + $sUID = \OC::$server->getUserSession()->getUser()->getUID(); + $ocSession = \OC::$server->getSession(); + // Only use the user's password in the current session if they have + // enabled auto-login using ownCloud username or email address. + if ($ocSession['snappymail-nc-uid'] == $sUID) { + if ($config->getAppValue('snappymail', 'snappymail-autologin', false)) { + $sEmail = $sUID; + $sPassword = $ocSession['snappymail-password']; + } else if ($config->getAppValue('snappymail', 'snappymail-autologin-with-email', false)) { + $sEmail = $config->getUserValue($sUID, 'settings', 'email', ''); + $sPassword = $ocSession['snappymail-password']; + } + if ($sPassword) { + $sPassword = static::decodePassword($sPassword, $sUID); + } + } + + // If the user has set credentials for SnappyMail in their personal + // settings, override everything before and use those instead. + $sCustomEmail = $config->getUserValue($sUID, 'snappymail', 'snappymail-email', ''); + if ($sCustomEmail) { + $sEmail = $sCustomEmail; + $sPassword = $config->getUserValue($sUID, 'snappymail', 'snappymail-password', ''); + if ($sPassword) { + $sPassword = static::decodePassword($sPassword, \md5($sEmail)); + } + } + return [$sUID, $sEmail, $sPassword ?: '']; + } + + public static function getAppUrl() : string + { + return \OC::$server->getURLGenerator()->linkToRoute('snappymail.page.appGet'); + } + + public static function normalizeUrl(string $sUrl) : string + { + $sUrl = \rtrim(\trim($sUrl), '/\\'); + if ('.php' !== \strtolower(\substr($sUrl, -4))) { + $sUrl .= '/'; + } + + return $sUrl; + } + + public static function encodePassword(string $sPassword, string $sSalt) : string + { + static::loadApp(); + return \SnappyMail\Crypt::EncryptUrlSafe($sPassword, $sSalt); + } + + public static function decodePassword(string $sPassword, string $sSalt)/* : mixed */ + { + static::loadApp(); + return \SnappyMail\Crypt::DecryptUrlSafe($sPassword, $sSalt); + } + + // Imports data from RainLoop + public static function importRainLoop() : array + { + $result = []; + + $dir = \rtrim(\trim(\OC::$server->getSystemConfig()->getValue('datadirectory', '')), '\\/'); + $dir_snappy = $dir . '/appdata_snappymail/'; + $dir_rainloop = $dir . '/rainloop-storage'; + $rainloop_plugins = []; + if (\is_dir($dir_rainloop)) { + \is_dir($dir_snappy) || \mkdir($dir_snappy, 0755, true); + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($dir_rainloop, \RecursiveDirectoryIterator::SKIP_DOTS), + \RecursiveIteratorIterator::SELF_FIRST + ); + foreach ($iterator as $item) { + $target = $dir_snappy . $iterator->getSubPathname(); + if (\preg_match('@/plugins/([^/])@', $target, $match)) { + $rainloop_plugins[$match[1]] = $match[1]; + } else if (!\strpos($target, '/cache/')) { + if ($item->isDir()) { + \is_dir($target) || \mkdir($target, 0755, true); + } else if (\file_exists($target)) { + $result[] = "skipped: {$target}"; + } else { + \copy($item, $target); + $result[] = "copied : {$target}"; + } + } + } + } + +// $password = APP_PRIVATE_DATA . 'admin_password.txt'; +// \is_file($password) && \unlink($password); + + static::loadApp(); + + // Attempt to install same plugins as RainLoop + if ($rainloop_plugins) { + foreach (\SnappyMail\Repository::getPackagesList()['List'] as $plugin) { + if (\in_array($plugin['id'], $rainloop_plugins)) { + $result[] = "install plugin : {$plugin['id']}"; + \SnappyMail\Repository::installPackage('plugin', $plugin['id']); + unset($rainloop_plugins[$plugin['id']]); + } + } + foreach ($rainloop_plugins as $plugin) { + $result[] = "skipped plugin : {$plugin}"; + } + } + + $oConfig = \RainLoop\Api::Config(); +// $oConfig->Set('webmail', 'theme', 'ownCloud@custom'); + $oConfig->Save(); + + return $result; + } + +} diff --git a/integrations/owncloud/snappymail/templates/admin-local.php b/integrations/owncloud/snappymail/templates/admin-local.php new file mode 100644 index 000000000..749befd18 --- /dev/null +++ b/integrations/owncloud/snappymail/templates/admin-local.php @@ -0,0 +1,64 @@ +<div class="section"> + <form class="snappymail" action="admin.php" method="post"> + <input type="hidden" name="requesttoken" value="<?php echo $_['requesttoken'] ?>" id="requesttoken"> + <fieldset class="personalblock"> + <h2><?php echo($l->t('SnappyMail Webmail')); ?></h2> + <br /> + <?php if ($_['snappymail-admin-panel-link']) { ?> + <p> + <a href="<?php echo $_['snappymail-admin-panel-link'] ?>" style="text-decoration: underline"> + <?php echo($l->t('Go to SnappyMail Webmail admin panel')); ?> + </a> + <?php if ($_['snappymail-admin-password']) { ?> + <br/> + Username: admin<br/> + Temporary password: <?php echo $_['snappymail-admin-password']; ?> + <?php } ?> + </p> + <br /> + <?php } ?> + <p> + <div style="display: flex;"> + <input type="radio" id="snappymail-noautologin" name="snappymail-autologin" value="0" <?php if (!$_['snappymail-autologin']&&!$_['snappymail-autologin-with-email']) echo 'checked="checked"'; ?> /> + <label style="margin: auto 5px;" for="snappymail-noautologin"> + <?php echo($l->t('Users will login manually, or define credentials in their personal settings for automatic logins.')); ?> + </label> + </div> + <div style="display: flex;"> + <input type="radio" id="snappymail-autologin" name="snappymail-autologin" value="1" <?php if ($_['snappymail-autologin']) echo 'checked="checked"'; ?> /> + <label style="margin: auto 5px;" for="snappymail-autologin"> + <?php echo($l->t('Attempt to automatically login users with their ownCloud username and password, or user-defined credentials, if set.')); ?> + </label> + </div> + <div style="display: flex;"> + <input type="radio" id="snappymail-autologin-with-email" name="snappymail-autologin" value="2" <?php if ($_['snappymail-autologin-with-email']) echo 'checked="checked"'; ?> /> + <label style="margin: auto 5px;" for="snappymail-autologin-with-email"> + <?php echo($l->t('Attempt to automatically login users with their ownCloud email and password, or user-defined credentials, if set.')); ?> + </label> + </div> + </p> + <br /> + <p> + <input id="snappymail-no-embed" name="snappymail-no-embed" type="checkbox" class="checkbox" <?php if ($_['snappymail-no-embed']) echo 'checked="checked"'; ?>> + <label for="snappymail-no-embed">Don't fully integrate in ownCloud, use in iframe</label> + </p> + <br /> + <p> + <input id="snappymail-debug" name="snappymail-debug" type="checkbox" class="checkbox" <?php if ($_['snappymail-debug']) echo 'checked="checked"'; ?>> + <label for="snappymail-debug">Debug</label> + </p> + <br /> + <?php if ($_['can-import-rainloop']) { ?> + <p> + <input id="import-rainloop" name="import-rainloop" type="checkbox" class="checkbox"> + <label for="import-rainloop">Import RainLoop data</label> + </p> + <br /> + <?php } ?> + <p> + <button id="snappymail-save-button" name="snappymail-save-button"><?php echo($l->t('Save')); ?></button> + <div class="snappymail-result-desc" style="white-space: pre"></div> + </p> + </fieldset> + </form> +</div> diff --git a/integrations/owncloud/snappymail/templates/index.php b/integrations/owncloud/snappymail/templates/index.php new file mode 100644 index 000000000..f304654fb --- /dev/null +++ b/integrations/owncloud/snappymail/templates/index.php @@ -0,0 +1,3 @@ +<iframe id="rliframe" style="border: none; width: 100%; min-height: 100%; position: relative;" tabindex="-1" frameborder="0" src="<?php echo $_['snappymail-iframe-url']; ?>"></iframe> +<?php +// OCP\Util::addScript('snappymail', 'resize'); diff --git a/integrations/owncloud/snappymail/templates/index_embed.php b/integrations/owncloud/snappymail/templates/index_embed.php new file mode 100644 index 000000000..c51f8e355 --- /dev/null +++ b/integrations/owncloud/snappymail/templates/index_embed.php @@ -0,0 +1,19 @@ +<style id="app-boot-css"><?php echo $_['BaseAppBootCss']; ?></style> +<style id="app-theme-style" data-href="<?php echo $_['BaseAppThemeCssLink']; ?>"><?php echo $_['BaseAppThemeCss']; ?></style> +<div id="rl-app" data-admin="<?php echo $_['Admin']; ?>" spellcheck="false"> + <div id="rl-loading"> + <div id="rl-loading-desc"><?php echo $_['LoadingDescriptionEsc']; ?></div> + <i class="icon-spinner"></i> + </div> + <div id="rl-loading-error" hidden="">An error occurred.<br>Please refresh the page and try again.</div> + <div id="rl-content" hidden=""> + <div id="rl-left"></div> + <div id="rl-right"></div> + </div> + <div id="rl-popups"></div> + <?php echo $_['BaseTemplates']; ?> +</div> +<?php +echo ' + <script nonce="'.$_['BaseAppBootScriptNonce'].'" type="text/javascript">'.$_['BaseAppBootScript'].$_['BaseLanguage'].'</script> +'; diff --git a/integrations/owncloud/snappymail/templates/personal_settings.php b/integrations/owncloud/snappymail/templates/personal_settings.php new file mode 100644 index 000000000..93a86c744 --- /dev/null +++ b/integrations/owncloud/snappymail/templates/personal_settings.php @@ -0,0 +1,21 @@ +<div class="section"> + <form class="snappymail" action="personal.php" method="post"> + <input type="hidden" name="requesttoken" value="<?php echo $_['requesttoken'] ?>" id="requesttoken"> + <fieldset class="personalblock"> + <h2><?php echo $l->t('SnappyMail Webmail'); ?></h2> + <p> + <?php echo $l->t('Enter an email and password to auto-login to SnappyMail.'); ?> + </p> + <p> + <input type="text" id="snappymail-email" name="snappymail-email" + value="<?php echo $_['snappymail-email']; ?>" placeholder="<?php echo($l->t('Email')); ?>" /> + + <input type="password" id="snappymail-password" name="snappymail-password" + value="<?php echo $_['snappymail-password']; ?>" placeholder="<?php echo($l->t('Password')); ?>" /> + + <button id="snappymail-save-button" name="snappymail-save-button"><?php echo($l->t('Save')); ?></button> +   <span class="snappymail-result-desc"></span> + </p> + </fieldset> + </form> +</div> diff --git a/release.php b/release.php index ccd3b1f21..aae2c8b42 100755 --- a/release.php +++ b/release.php @@ -2,7 +2,7 @@ <?php chdir(__DIR__); -$options = getopt('', ['aur','docker','plugins','set-version','skip-gulp','debian','nextcloud','sign','cpanel']); +$options = getopt('', ['aur','docker','plugins','set-version','skip-gulp','debian','nextcloud','owncloud','sign','cpanel']); if (isset($options['plugins'])) { require(__DIR__ . '/build/plugins.php'); @@ -183,6 +183,10 @@ if (isset($options['nextcloud'])) { require(__DIR__ . '/build/nextcloud.php'); } +if (isset($options['owncloud'])) { + require(__DIR__ . '/build/owncloud.php'); +} + if (isset($options['cpanel'])) { require(__DIR__ . '/build/cpanel.php'); } @@ -268,6 +272,10 @@ if (isset($options['sign'])) { passthru('gpg --local-user 1016E47079145542F8BA133548208BA13290F3EB --armor --detach-sign ' .escapeshellarg("{$destPath}snappymail-{$package->version}-nextcloud.tar.gz"), $return_var); } + if (isset($options['owncloud'])) { + passthru('gpg --local-user 1016E47079145542F8BA133548208BA13290F3EB --armor --detach-sign ' + .escapeshellarg("{$destPath}snappymail-{$package->version}-owncloud.tar.gz"), $return_var); + } if (isset($options['cpanel'])) { passthru('gpg --local-user 1016E47079145542F8BA133548208BA13290F3EB --armor --detach-sign ' .escapeshellarg("{$destPath}snappymail-{$package->version}-cpanel.tar.gz"), $return_var);