diff --git a/.eslintrc.js b/.eslintrc.js index 6c8cbc1ce..93b9fc12e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -3,7 +3,7 @@ module.exports = { // extends: ['eslint:recommended', 'plugin:prettier/recommended'], extends: ['eslint:recommended'], parserOptions: { - ecmaVersion: 6, + ecmaVersion: 11, sourceType: 'module' }, env: { @@ -35,7 +35,9 @@ module.exports = { // vendors/bootstrap/bootstrap.native.js 'BSN': "readonly", // Mailvelope - 'mailvelope': "readonly" + 'mailvelope': "readonly", + // Punycode + 'IDN': "readonly" }, // http://eslint.org/docs/rules/ rules: { diff --git a/CHANGELOG.md b/CHANGELOG.md index cdb6b5e8a..75af20962 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,399 @@ +## 2.36.2 – 2024-05-26 + +### Added +- "copy to" action in menu's for + [#1559](https://github.com/the-djmaze/snappymail/issues/1559) +- Log signal info for + [#1569](https://github.com/the-djmaze/snappymail/issues/1569) +- OpenPGP.js automatically import backup keys from server + +### Changed +- Improved "remember me" cookie handling +- Update Basque by @Thadah +- Update Portuguese by @ner00 + +### Fixed +- "Account already exists" + [#1561](https://github.com/the-djmaze/snappymail/issues/1561) +- Properly escape path separator in tar.php file list regex by @sevmonster + [#1562](https://github.com/the-djmaze/snappymail/pull/1562) +- Prevent mkdir() error + [#1565](https://github.com/the-djmaze/snappymail/issues/1565) +- SCRAM Exception when trying to log in to SMTP + [#1575](https://github.com/the-djmaze/snappymail/issues/1575) +- Error when redirected back to instance after Gmail OAuth + [#1580](https://github.com/the-djmaze/snappymail/issues/1580) +- Uncaught TypeError: hasPublicKeyForEmails(...).then is not a function + [#1589](https://github.com/the-djmaze/snappymail/issues/1589) +- Undefined variable $sFilename +- GPG/PGP exec() return false handling + +### Nextcloud +- OIDC login active again by @avinash-0007 + [#1572](https://github.com/the-djmaze/snappymail/pull/1572) + + +## 2.36.1 – 2024-04-23 + +### Added +- Autoconfig detect through DNS SRV (RFC 6186 & 8314) and disable MX +- Have I Been Pwned class to check breached passwords and email addresses +- Handle RFC 5987 in Content-Disposition header +- Ignore text/x-amp-html +- Show SMTP error to user + [#1521](https://github.com/the-djmaze/snappymail/issues/1521) +- OAuth2 for login using gmail (and others) + +### Changed +- logMask all AUTHENTICATE requests +- ErrorTip use white-space: pre +- Simplify LoginProcess handling +- ES2020 everywhere (require Safari 13.1) +- Modified Squire to be more in line with v2.2.8 +- CSS set min-width for .attachmentParent and .flagParent to line them up +- cPanel use extension login-cpanel instead of login-remote +- Improved login credentials handling +- Speedup Knockout a bit +- Update Belarusian by @spoooyders +- Update Chinese by @mayswind +- Update French by @hguilbert +- Update Polish by @tinola +- Update Portuguese by @ner00 + +### Fixed +- Content encoding and type detection in JavaScript could fail due to case-sensitivity. +- Extensions set logger failed +- GnuPG check open_basedir and if shell_exec is disabled + [#1385](https://github.com/the-djmaze/snappymail/issues/1385) + [#1496](https://github.com/the-djmaze/snappymail/issues/1496) + [#1555](https://github.com/the-djmaze/snappymail/issues/1555) +- Hide pagination when search result has no messages +- Prevent mbstring error before setup.php +- Prevent MessagesPerPage Infinity + [#1540](https://github.com/the-djmaze/snappymail/issues/1540) +- Reseal CryptKey failed + [#1543](https://github.com/the-djmaze/snappymail/issues/1543) + +### Nextcloud +- Add an occ command to set up the login settings + [#1552](https://github.com/the-djmaze/snappymail/issues/1552) + + +## 2.36.0 – 2024-03-18 + +### Added +- Allow setting the supported THREAD algorithm +- Icon to system folders +- Remove remembered password after 15 minutes of inactivity + [#1142](https://github.com/the-djmaze/snappymail/issues/1142) +- Swap background and text color for unreadable text on dark background + [#1486](https://github.com/the-djmaze/snappymail/issues/1486) +- Generate TOTP code at ?Admin -> Security + [#1501](https://github.com/the-djmaze/snappymail/issues/1501) +- Button to change S/MIME private key passphrase + [#1505](https://github.com/the-djmaze/snappymail/issues/1505) +- Belarusian by @spoooyders + [#1512](https://github.com/the-djmaze/snappymail/pull/1512) +- Log some domain idn_to_ascii issues + [#1513](https://github.com/the-djmaze/snappymail/pull/1513) + +### Changed +- On folder/mailbox rename, also rename all children instead of reloading all +- Seal MainAccount CryptKey and on error ask old login passphrase to reseal key. +- Moved cache drivers outside core into extensions +- Sieve always allow fileinto INBOX + [#1510](https://github.com/the-djmaze/snappymail/issues/1510) +- Moved application.ini `sieve_auth_plain_initial` to per domain config +- Languages use rfc5646, by using the shortest ISO 639 code by default +- Update French by @hguilbert +- Update Portuguese by @ner00 + +### Fixed +- On folder/mailbox rename, the old fullName must be removed from cache +- On folder/mailbox rename, the checkable option was not renamed +- Sort accounts drag & drop +- S/MIME encrypted and opaque signed not visible + [#1450](https://github.com/the-djmaze/snappymail/issues/1450) +- Wrong last UID of thread + [#1507](https://github.com/the-djmaze/snappymail/issues/1507) +- Creation of dynamic property SnappyMail\DAV\Client::$HTTP + [#1509](https://github.com/the-djmaze/snappymail/issues/1509) +- "Download as ZIP" fails for messages + [#1514](https://github.com/the-djmaze/snappymail/issues/1514) +- SMTP "Authentication failed" when IMAP uses `shortLogin` and SMTP not + [#1517](https://github.com/the-djmaze/snappymail/issues/1517) + + +## 2.35.4 – 2024-03-16 + +### Added +- \SnappyMail\IDN::toAscii() + +### Changed +- OpenPGP.js to v5.11.1 +- punycode.js lowercase domain names +- application.ini `login_lowercase` removed and now configurable per domain JSON `lowerLogin` +- Update Portuguese by @ner00 + +### Fixed +- Raise JS TypeEroor "toLowerCase" after update + [#1491](https://github.com/the-djmaze/snappymail/issues/1491) +- Call to undefined function shell_exec + [#1496](https://github.com/the-djmaze/snappymail/issues/1496) +- Download attachments as ZIP doesn't work for PGP encrypted mail + [#1499](https://github.com/the-djmaze/snappymail/issues/1499) +- Importing or downloading a PGP public key attachment from a PGP encrypted message doesn't work + [#1500](https://github.com/the-djmaze/snappymail/issues/1500) +- VCard PHP Notice: Undefined index: ENCODING + +### Nextcloud +- Changed stored password handling +- Can't login from nextcloud with 2.35.3 bug Nextcloud + [#1490](https://github.com/the-djmaze/snappymail/issues/1490) + + +## 2.35.3 – 2024-03-12 + +### Added +- GnuPG can be disabled +- Missing strings for localization inside identity popup (Cryptography > S/MIME) + [#1458](https://github.com/the-djmaze/snappymail/issues/1458) +- Automatically verify PGP and S/MIME signed messages +- TNEFDecoder for + [#1012](https://github.com/the-djmaze/snappymail/discussions/1012) +- RTF to HTML converter for + [#1012](https://github.com/the-djmaze/snappymail/discussions/1012) +- Polyfill for PHP ctype + [#1250](https://github.com/the-djmaze/snappymail/issues/1250) + +### Changed +- `new Error()` to `Error()` +- Reduce KnockoutJS footprint by removing unused code +- CSS reposition rainloopErrorTip location +- Improved error handling on PGP and S/MIME decrypt +- Improved OpenPGP.js import keys +- Use Identity S/MIME key and certificate from server instead of POST +- application.ini `[webmail]language_admin` to `[admin_panel]language` +- application.ini `[security]admin_panel_host` to `[admin_panel]host` +- application.ini `[security]admin_panel_key` to `[admin_panel]key` +- Drop deprecated Domain::SetConfig() +- Internationalized domain names are now handled as punycode +- Cacher->Get() can now return NULL +- Update French by @hguilbert +- Update Polish by @tinola +- Update Portuguese by @ner00 + +### Fixed +- Handling of Internationalized Domain Names in several areas +- Decrypt error message +- Stalwart ManageSieve Error 352 when getting Filters + [#1455](https://github.com/the-djmaze/snappymail/issues/1455) +- Nextcloud V25+ theme slightly broken + [#1463](https://github.com/the-djmaze/snappymail/issues/1463) +- PGP decryption fails with "Not armored text" + [#1462](https://github.com/the-djmaze/snappymail/issues/1462) +- AUTH_BASIC falling through as AUTH_BEARER; change AUTH_BEARER to a different value + [#1461](https://github.com/the-djmaze/snappymail/issues/1461) +- SetPassword expects \SnappyMail\SensitiveString +- Crash on importing corrupt OpenPGP keys +- Crash on old browsers instead of showing error +- Ignore popups on logoutReload() + [#1467](https://github.com/the-djmaze/snappymail/pull/1467) +- Custom SASLMechanisms fail in IMAP when the connection is secure + [#1484](https://github.com/the-djmaze/snappymail/pull/1484) + + +## 2.35.2 – 2024-02-27 + +### Added +- GnuPG error handling +- Missing strings for localization inside identity popup (Cryptography > S/MIME) + [#1458](https://github.com/the-djmaze/snappymail/issues/1458) + +### Changed +- Update Portuguese by @ner00 + +### Fixed +- Drop support for gnupg PECL extension as it fails with "no passphrase" issues +- Error 352 when getting Filters + [#1455](https://github.com/the-djmaze/snappymail/issues/1455) + +### Nextcloud +- SetPassword(): Argument #1 must be of type SensitiveString, string given + [#1456](https://github.com/the-djmaze/snappymail/issues/1456) + + +## 2.35.1 – 2024-02-26 + +### Added +- Search functionality in Admin -> Config +- Cache S/MIME passphrases when "remember" is checked +- Import S/MIME certificate popup +- pre-verify S/MIME opaque signed messages so we have a body to view +- Sort PGP keys and S/MIME certificates on email address +- Optionally use existing private key to generate S/MIME certificate + +### Changed +- Better handling to detect which PGP or S/MIME sign/encrypt to use +- Improved StorageType handling +- Cleanup and improved Capa handling +- OPEN_PGP should be OPENPGP as it is one word +- Use get_debug_type() instead of gettype() +- Require OpenSSL due to S/MIME +- AbstractProvider::IsActive() is now an abstract method and must be defined in child class +- Make better use of SnappyMail\SensitiveString +- Update Polish translation by @tinola + +### Fixed +- Verify S/MIME signatures got broken allong the way while implementing this +- Generate S/MIME self-signed certificate failed to keep existing private key +- MIME parser RegExp didn't escape boundary which caused issues +- TypeError: b64Encode(...).match(...) is null on saving compose draft +- Fix timestampToString() for future dates + + +## 2.35.0 – 2024-02-20 + +### Added +- S/MIME support + [#259](https://github.com/the-djmaze/snappymail/issues/259) + +### Changed +- Disable IMAP METADATA by default (hardly used) +- Update Polish translation by @tinola +- Rename CSS .openpgp-control to .crypto-control +- Renamed some methods in PHP + +### Fixed +- When moving a folder/mailbox check for parent delimiter +- Mask `passphrase` in the logs for PHP < 8.2 +- Added some missing translations +- Sign messages using PGP +- Check for CONDSTORE or QRESYNC to get the HIGHESTMODSEQ +- Unable to login on certain IMAP server since 2.34.2 + [#1438](https://github.com/the-djmaze/snappymail/issues/1438) + +### Nextcloud +- Save as .eml + [#1425](https://github.com/the-djmaze/snappymail/issues/1425) + + +## 2.34.2 – 2024-02-14 + +### Fixed +- Message was sent but not saved to sent items folder + [#1432](https://github.com/the-djmaze/snappymail/issues/1432) +- Login with scram failed + [#1433](https://github.com/the-djmaze/snappymail/issues/1433) + + +## 2.34.1 – 2024-02-13 + +### Added +- Autocrypt support + [#342](https://github.com/the-djmaze/snappymail/issues/342) +- Load the mailboxes/folders of all namespaces (other users, global, shared, etc.) +- Load keys from server into OpenPGP.js + [#973](https://github.com/the-djmaze/snappymail/issues/973) +- Import PGP Keys from remote key servers +- Sort Inbox Folders with Unread Messages First + [#1427](https://github.com/the-djmaze/snappymail/issues/1427) +- Define JMAP FolderModel.myRights +- Identity Management: add identity display name + [#1405](https://github.com/the-djmaze/snappymail/issues/1405) +- Identity Management: add per-identity "sent" folder + [#1404](https://github.com/the-djmaze/snappymail/issues/1404) +- Some support for JSON-LD / Structured Email + [#1422](https://github.com/the-djmaze/snappymail/issues/1422) +- Domain Autoconfig and Microsoft's autodiscover (and also as extension/plugin) +- View MMS messages that are received via email + [#1294](https://github.com/the-djmaze/snappymail/issues/1294) +- Draft code for S/MIME + [#259](https://github.com/the-djmaze/snappymail/issues/259) + +### Changed +- Many OpenPGP improvements + [#89](https://github.com/the-djmaze/snappymail/issues/89) +- Allow CSP connect-src CORS for keys.openpgp.org to directly fetch PGP keys +- Improved handling of visible folders +- KnockoutJS Replace some ko.exportSymbol('*') in favour of ko['*'] +- KnockoutJS use Symbol for isObservableArray() +- Simplify generating folderListVisible +- Drop the bSearchSecretWords param from logger +- Transparent background for text + [#1412](https://github.com/the-djmaze/snappymail/issues/1412) +- Enable OpenPGP.js by default at install +- Added folder edit popup for improved IMAP ACL Support + [#157](https://github.com/the-djmaze/snappymail/issues/157) +- Process all IMAP namespaces +- Update Polish by @tinola +- Update Portuguese by @ner00 + +### Fixed +- Make time_zone a select list due to PEBKAC +- Workaround Outlook generated double spacing + [#1415](https://github.com/the-djmaze/snappymail/issues/1415) +- HTML Parser is not picking up the full Unsubscribe URL in the attached text file + [#1225](https://github.com/the-djmaze/snappymail/issues/1225) +- Contacts - it auto "Select All", after entry delete + [#1411](https://github.com/the-djmaze/snappymail/issues/1411) +- Message header parsing issue + [#1403](https://github.com/the-djmaze/snappymail/issues/1403) +- apple-touch-icon should not be transparent + [#1408](https://github.com/the-djmaze/snappymail/issues/1408) +- Creation of dynamic property is deprecated + [#1409](https://github.com/the-djmaze/snappymail/issues/1409) +- Ask/send readReceipt was broken +- OpenPGP public key can not be removed anymore after importing private key of subkey + [#1384](https://github.com/the-djmaze/snappymail/issues/1384) +- KnockoutJS failed to output text '0' +- JavaScript friendlySize() failed on 0 +- Workaround Dovecot `PREAUTH [CAPABILITY (null)]` issue +- Workaround disabled ACL could cause "Disconnected: Too many invalid IMAP commands" + +### Nextcloud +- Save multiple as .eml + [#1425](https://github.com/the-djmaze/snappymail/issues/1425) +- Disabled support for Nextcloud OpenID Connect + [#1420](https://github.com/the-djmaze/snappymail/issues/1420) + + +## 2.33.0 – 2024-01-22 + +### Added +- Feature to use the SQLite AddressBook per login account instead of global (on by default). +- Return all fetched messages headers in JSON. + +### Changed +- Docker hub use Alpine linux 3.18.5 and PHP 8.2 +- Some InvalidArgumentException to the better suited ValueError +- Removed some unused KnockoutJS code +- KnockoutJS drop unused rateLimit method +- Cleanup some data-bind="" +- Drop the disabled KnockoutJS twoWayBindings +- Drop support for KnockoutJS _ko_property_writers and for two-way binding they must be observables +- Login form use method="POST" to prevent uri exposure when javascript fails +- Merge code to generate MIME PGP parts and MIME Plain parts +- SMTP sendRequestWithCheck for future support of RFC's +- Cleanup mime header handling + +### Fixed +- Sorting not supported since 2.32.0 + [#1373](https://github.com/the-djmaze/snappymail/issues/1373) +- FILE_ON_SAVING_ERROR is not defined + [#1379](https://github.com/the-djmaze/snappymail/issues/1379) +- Saving EML files with same subject result in only saving latest email + [#1381](https://github.com/the-djmaze/snappymail/issues/1381) +- Some Sieve parser issues +- Handling of RainLoop Sieve script +- Sieve rfc5429 RejectCommand and ErejectCommand +- KnockoutJS title:value was removed, use attr:{title:value} +- dataBaseUpgrade() always runs on sqlite and pgsql +- Message was sent but not saved to sent items folder + [#1397](https://github.com/the-djmaze/snappymail/issues/1397) +- DKIM `pass` detection sometimes failed + + ## 2.32.0 – 2023-12-26 ### Added diff --git a/README.md b/README.md index 8291c7ac9..1ee87f77c 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ This fork of RainLoop has the following changes: * Admin uses password_hash/password_verify * Auth failed attempts written to syslog * Added Fail2ban instructions -* ES2018 +* ES2020 * PHP 7.4+ required * PHP mbstring extension required * PHP replaced pclZip with PharData and ZipArchive @@ -140,28 +140,28 @@ RainLoop 1.17 vs SnappyMail |js/* |RainLoop |Snappy | |--------------- |--------: |--------: | -|admin.js |2.170.153 | 80.370 | -|app.js |4.207.787 | 408.429 | -|boot.js | 868.735 | 4.142 | -|libs.js | 658.812 | 193.230 | -|sieve.js | 0 | 85.085 | +|admin.js |2.170.153 | 83.494 | +|app.js |4.207.787 | 437.079 | +|boot.js | 868.735 | 4.147 | +|libs.js | 658.812 | 193.716 | +|sieve.js | 0 | 84.598 | |polyfills.js | 334.608 | 0 | |serviceworker.js | 0 | 285 | -|TOTAL |8.240.095 | 771.541 | +|TOTAL |8.240.095 | 803.319 | |js/min/* |RainLoop |Snappy |RL gzip |SM gzip |RL brotli |SM brotli | |--------------- |--------: |--------: |------: |------: |--------: |--------: | -|admin.min.js | 256.831 | 39.285 | 73.606 | 13.183 | 60.877 | 11.806 | -|app.min.js | 515.367 | 186.270 |139.456 | 63.111 |110.485 | 54.218 | -|boot.min.js | 84.659 | 2.084 | 26.998 | 1.202 | 23.643 | 1.003 | -|libs.min.js | 584.772 | 93.401 |180.901 | 34.765 |155.182 | 31.194 | -|sieve.min.js | 0 | 41.316 | 0 | 10.364 | 0 | 9.352 | +|admin.min.js | 256.831 | 40.856 | 73.606 | 13.776 | 60.877 | 12.345 | +|app.min.js | 515.367 | 197.782 |139.456 | 67.143 |110.485 | 57.251 | +|boot.min.js | 84.659 | 2.087 | 26.998 | 1.204 | 23.643 | 1.002 | +|libs.min.js | 584.772 | 92.365 |180.901 | 34.487 |155.182 | 30.830 | +|sieve.min.js | 0 | 41.093 | 0 | 10.325 | 0 | 9.327 | |polyfills.min.js | 32.837 | 0 | 11.406 | 0 | 10.175 | 0 | -|TOTAL user |1.217.635 | 281.755 |358.761 | 99.078 |299.485 | 86.415 | -|TOTAL user+sieve |1.217.635 | 323.071 |358.761 |109.442 |299.485 | 95.767 | -|TOTAL admin | 959.099 | 134.770 |292.911 | 49.150 |249.877 | 44.003 | +|TOTAL user |1.217.635 | 292.234 |358.761 |102.834 |299.485 | 89.083 | +|TOTAL user+sieve |1.217.635 | 333.327 |358.761 |113.159 |299.485 | 98.410 | +|TOTAL admin | 959.099 | 135.308 |292.911 | 49.467 |249.877 | 44.177 | -For a user it is around 69% smaller and faster than traditional RainLoop. +For a user it is around 68% smaller and faster than traditional RainLoop. ### CSS changes @@ -188,12 +188,12 @@ For a user it is around 69% smaller and faster than traditional RainLoop. |css/* |RainLoop |Snappy |RL gzip |SM gzip |SM brotli | |------------ |-------: |------: |------: |------: |--------: | -|app.css | 340.331 | 84.484 | 46.946 | 17.627 | 15.110 | -|app.min.css | 274.947 | 67.910 | 39.647 | 15.541 | 13.547 | +|app.css | 340.331 | 84.629 | 46.946 | 17.652 | 15.127 | +|app.min.css | 274.947 | 67.995 | 39.647 | 15.562 | 13.568 | |boot.css | | 1.326 | | 664 | 545 | |boot.min.css | | 1.071 | | 590 | 474 | -|admin.css | | 30.641 | | 7.028 | 6.111 | -|admin.min.css | | 24.742 | | 6.352 | 5.599 | +|admin.css | | 30.528 | | 7.001 | 6.088 | +|admin.min.css | | 24.652 | | 6.325 | 5.574 | ### PGP RainLoop uses the old OpenPGP.js v2 @@ -207,7 +207,7 @@ See https://github.com/the-djmaze/openpgpjs for development |OpenPGP |RainLoop |Snappy |RL gzip |SM gzip |RL brotli |SM brotli | |--------------- |--------: |--------: |------: |-------: |--------: |--------: | -|openpgp.min.js | 330.742 | 541.176 |102.388 | 168.266 | 84.241 | 138.278 | +|openpgp.min.js | 330.742 | 546.309 |102.388 | 169.249 | 84.241 | 138.751 | |openpgp.worker | 1.499 | | 824 | | 695 | | @@ -224,5 +224,3 @@ Still TODO: |ckeditor | ? | 520.035 | ? | 155.916 | CKEditor including the 7 asset requests (css,language,plugins,icons) is 633.46 KB / 180.47 KB (gzip). - -To use the old CKEditor, you must install the plugin. diff --git a/SECURITY.md b/SECURITY.md index 02ef3170f..1b43a988f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,15 +6,15 @@ Currently due to the fast development only the latest version receives security | Version | Supported | | -------- | --------- | -| 2.13.x | ✔ | -| < 2.13.0 | ❌ | +| 2.30.x | ✔ | +| < 2.30.0 | ❌ | ## Reporting a Vulnerability Please report security issues or vulnerabilities as an encrypted email to [security@snappymail.eu](mailto:security@snappymail.eu). Your report should be detailed enough with clear steps to reproduce and classify the found vulnerability. -You can find the PGP public key below and on the major public keyservers like [pgp.key-server.io](https://pgp.key-server.io). +You can find the PGP public key below and on the major public keyservers like [keys.openpgp.org](https://keys.openpgp.org). ``` -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: Type: 255-bit EdDSA diff --git a/dev/App/Abstract.js b/dev/App/Abstract.js index 113c7dbc7..1e545bbf9 100644 --- a/dev/App/Abstract.js +++ b/dev/App/Abstract.js @@ -3,6 +3,8 @@ import ko from 'ko'; import { logoutLink } from 'Common/Links'; import { i18nToNodes, initOnStartOrLangChange } from 'Common/Translator'; +import { arePopupsVisible } from 'Knoin/Knoin'; + import { LanguageStore } from 'Stores/Language'; import { initThemes } from 'Stores/Theme'; @@ -18,6 +20,7 @@ export class AbstractApp { } logoutReload(url) { + arePopupsVisible(false); url = url || logoutLink(); if (location.href !== url) { setTimeout(() => location.href = url, 100); diff --git a/dev/App/Admin.js b/dev/App/Admin.js index fb970bffc..91440875c 100644 --- a/dev/App/Admin.js +++ b/dev/App/Admin.js @@ -1,6 +1,6 @@ import 'External/ko'; -import { Settings, SettingsGet } from 'Common/Globals'; +import { SettingsGet, SettingsAdmin } from 'Common/Globals'; import { initThemes } from 'Stores/Theme'; import Remote from 'Remote/Admin/Fetch'; @@ -11,6 +11,8 @@ import { LoginAdminScreen } from 'Screen/Admin/Login'; import { startScreens } from 'Knoin/Knoin'; import { AbstractApp } from 'App/Abstract'; +import { AskPopupView } from 'View/Popup/Ask'; + export class AdminApp extends AbstractApp { constructor() { super(Remote); @@ -23,7 +25,8 @@ export class AdminApp extends AbstractApp { } start() { - if (!Settings.app('adminAllowed')) { +// if (!Settings.app('adminAllowed')) { + if (!SettingsAdmin('allowed')) { rl.route.root(); setTimeout(() => location.href = '/', 1); } else if (SettingsGet('Auth')) { @@ -34,3 +37,16 @@ export class AdminApp extends AbstractApp { } } } + +AskPopupView.credentials = function(sAskDesc, btnText) { + return new Promise(resolve => { + this.showModal([ + sAskDesc, + view => resolve({username:view.username(), password:view.passphrase()}), + () => resolve(null), + true, + 3, + btnText + ]); + }); +}; diff --git a/dev/App/User.js b/dev/App/User.js index b18f8a5d9..31babbbb7 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -1,8 +1,8 @@ import 'External/User/ko'; import { SMAudio } from 'Common/Audio'; -import { isArray, pInt } from 'Common/Utils'; -import { mailToHelper, setLayoutResizer, dropdownsDetectVisibility } from 'Common/UtilsUser'; +import { pInt } from 'Common/Utils'; +import { mailToHelper, setLayoutResizer, dropdownsDetectVisibility, loadAccountsAndIdentities } from 'Common/UtilsUser'; import { FolderType, @@ -33,9 +33,9 @@ import { SettingsUserStore } from 'Stores/User/Settings'; import { NotificationUserStore } from 'Stores/User/Notification'; import { AccountUserStore } from 'Stores/User/Account'; import { ContactUserStore } from 'Stores/User/Contact'; -import { IdentityUserStore } from 'Stores/User/Identity'; import { FolderUserStore } from 'Stores/User/Folder'; import { PgpUserStore } from 'Stores/User/Pgp'; +import { SMimeUserStore } from 'Stores/User/SMime'; import { MessagelistUserStore } from 'Stores/User/Messagelist'; import { ThemeStore, initThemes } from 'Stores/Theme'; import { LanguageStore } from 'Stores/Language'; @@ -43,9 +43,6 @@ import { MessageUserStore } from 'Stores/User/Message'; import Remote from 'Remote/User/Fetch'; -import { AccountModel } from 'Model/Account'; -import { IdentityModel } from 'Model/Identity'; - import { LoginUserScreen } from 'Screen/User/Login'; import { MailBoxUserScreen } from 'Screen/User/MailBox'; import { SettingsUserScreen } from 'Screen/User/Settings'; @@ -89,6 +86,8 @@ export class AppUser extends AbstractApp { this.folderList = FolderUserStore.folderList; this.messageList = MessagelistUserStore; + + this.ask = AskPopupView; } /** @@ -139,31 +138,6 @@ export class AppUser extends AbstractApp { } } - accountsAndIdentities() { - AccountUserStore.loading(true); - IdentityUserStore.loading(true); - - Remote.request('AccountsAndIdentities', (iError, oData) => { - AccountUserStore.loading(false); - IdentityUserStore.loading(false); - - if (!iError) { - let items = oData.Result.Accounts; - AccountUserStore(isArray(items) - ? items.map(oValue => new AccountModel(oValue.email, oValue.name)) - : [] - ); - AccountUserStore.unshift(new AccountModel(SettingsGet('mainEmail'), '', false)); - - items = oData.Result.Identities; - IdentityUserStore(isArray(items) - ? items.map(identityData => IdentityModel.reviveFromJson(identityData)) - : [] - ); - } - }); - } - /** * @param {string} folder * @param {Array=} list = [] @@ -216,9 +190,7 @@ export class AppUser extends AbstractApp { setRefreshFoldersInterval(pInt(SettingsGet('CheckMailInterval'))); - ContactUserStore.init(); - - this.accountsAndIdentities(); + loadAccountsAndIdentities(); setTimeout(() => { const cF = FolderUserStore.currentFolderFullName(); @@ -247,6 +219,7 @@ export class AppUser extends AbstractApp { setInterval(reloadTime, 60000); PgpUserStore.init(); + SMimeUserStore.loadCertificates(); setTimeout(() => mailToHelper(SettingsGet('mailToEmail')), 500); @@ -267,7 +240,6 @@ export class AppUser extends AbstractApp { console.error(e); } }); - } else { startScreens([LoginUserScreen]); } @@ -278,3 +250,50 @@ export class AppUser extends AbstractApp { showScreenPopup(ComposePopupView, params); } } + +AskPopupView.password = function(sAskDesc, btnText, ask) { + return new Promise(resolve => { + this.showModal([ + sAskDesc, + view => resolve({ + password:view.passphrase(), + username:/*ask & 2 ? */view.username(), + remember:/*ask & 4 ? */view.remember() + }), + () => resolve(null), + true, + ask || 1, + btnText + ]); + }); +}; + +AskPopupView.cryptkey = () => new Promise(resolve => { + const fn = () => AskPopupView.showModal([ + i18n('CRYPTO/ASK_CRYPTKEY_PASS'), + view => { + let pass = view.passphrase(); + if (pass) { + Remote.post('ResealCryptKey', null, { + passphrase: pass + }).then(response => { + resolve(response?.Result); + }).catch(e => { + if (111 === e.code) { + fn(); + } else { + console.error(e); + resolve(null); + } + }); + } else { + resolve(null); + } + }, + () => resolve(null), + true, + 1, + i18n('CRYPTO/DECRYPT') + ]); + fn(); +}); diff --git a/dev/Common/Enums.js b/dev/Common/Enums.js index 028d2a700..cb3df4817 100644 --- a/dev/Common/Enums.js +++ b/dev/Common/Enums.js @@ -50,6 +50,7 @@ Notifications = { ConnectionError: 104, DomainNotAllowed: 109, AccountNotAllowed: 110, + CryptKeyError: 111, ContactsSyncError: 140, @@ -95,7 +96,6 @@ Notifications = { JsonParse: 952, // JsonTimeout: 953, - UnknownNotification: 998, UnknownError: 999, // Admin diff --git a/dev/Common/File.js b/dev/Common/File.js index 0c793a92d..38b1f917b 100644 --- a/dev/Common/File.js +++ b/dev/Common/File.js @@ -1,7 +1,7 @@ /* eslint key-spacing: 0 */ /* eslint quote-props: 0 */ -import { arrayLength } from 'Common/Utils'; +import { arrayLength, pInt } from 'Common/Utils'; export const RFC822 = 'message/rfc822'; @@ -30,6 +30,8 @@ const p7c: app+'pkcs7-mime', p7m: app+'pkcs7-mime', p7s: app+'pkcs7-signature', + p12: app+'pkcs12', + pfx: app+'x-pkcs12', torrent: app+'x-bittorrent', // scripts @@ -136,7 +138,7 @@ export const FileInfo = { getContentType: fileName => { fileName = lowerCase(fileName); if ('winmail.dat' === fileName) { - return app + 'ms-tnef'; + return app + 'vnd.ms-tnef'; } let ext = fileName.split('.').pop(); if (/^(txt|text|def|list|in|ini|log|sql|cfg|conf)$/.test(ext)) @@ -164,7 +166,7 @@ export const FileInfo = { */ getType: (ext, mimeType) => { ext = lowerCase(ext); - mimeType = lowerCase(mimeType).replace('csv/plain', 'text/csv'); + mimeType = lowerCase(mimeType).replace('csv/plain', 'text/csv').replace('x-',''); let key = ext + mimeType; if (cache[key]) { @@ -173,7 +175,7 @@ export const FileInfo = { let result = FileType.Unknown; const mimeTypeParts = mimeType.split('/'), - type = mimeTypeParts[1].replace('x-','').replace('-compressed',''), + type = mimeTypeParts[1].replace('-compressed',''), match = str => mimeType.includes(str), archive = /^(zip|7z|tar|rar|gzip|bzip|bzip2)$/; @@ -205,9 +207,8 @@ export const FileInfo = { case 'pdf' == type || 'pdf' == ext: result = FileType.Pdf; break; - case [app+'pgp-signature', app+'pgp-keys'].includes(mimeType) - || ['asc', 'pem', 'ppk'].includes(ext) - || [app+'pkcs7-signature'].includes(mimeType) || 'p7s' == ext: + case [app+'pgp-signature', app+'pgp-keys', exts.p7m, exts.p7s, exts.p12, exts.pfx].includes(mimeType) + || ['asc', 'pem', 'ppk', 'p7s', 'p7m', 'p12', 'pfx'].includes(ext): result = FileType.Certificate; break; case match(msOffice+'.wordprocessingml') || match(openDoc+'.text') || match('vnd.ms-word') @@ -273,8 +274,8 @@ export const FileInfo = { }, friendlySize: bytes => { - bytes = parseInt(bytes, 10) || 0; - let i = Math.floor(Math.log(bytes) / Math.log(1024)); + bytes = pInt(bytes); + let i = bytes ? Math.floor(Math.log(bytes) / Math.log(1024)) : 0; return (bytes / Math.pow(1024, i)).toFixed(2>i ? 0 : 1) + ' ' + sizes[i]; } diff --git a/dev/Common/Folders.js b/dev/Common/Folders.js index cbba0390d..e7d42e2c7 100644 --- a/dev/Common/Folders.js +++ b/dev/Common/Folders.js @@ -1,5 +1,6 @@ import { RFC822 } from 'Common/File'; import { getFolderInboxName, getFolderFromCacheList } from 'Common/Cache'; +import { baseCollator } from 'Common/Translator'; import { isArray, arrayLength } from 'Common/Utils'; import { SettingsUserStore } from 'Stores/User/Settings'; import { FolderUserStore } from 'Stores/User/Folder'; @@ -27,7 +28,7 @@ setRefreshFoldersInterval = minutes => { sortFolders = folders => { try { - let collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'}); + let collator = baseCollator(true); folders.sort((a, b) => a.isInbox() ? -1 : (b.isInbox() ? 1 : collator.compare(a.fullName, b.fullName)) ); diff --git a/dev/Common/Globals.js b/dev/Common/Globals.js index 4d86df9dc..105660c31 100644 --- a/dev/Common/Globals.js +++ b/dev/Common/Globals.js @@ -15,6 +15,7 @@ export const Settings = rl.settings, SettingsGet = Settings.get, + SettingsAdmin = name => (SettingsGet('Admin') || {})[name], SettingsCapa = name => name && !!(SettingsGet('Capa') || {})[name], dropdowns = [], diff --git a/dev/Common/Html.js b/dev/Common/Html.js index 063caaab7..27e59a2e1 100644 --- a/dev/Common/Html.js +++ b/dev/Common/Html.js @@ -1,5 +1,5 @@ import { createElement } from 'Common/Globals'; -import { forEachObjectEntry, pInt } from 'Common/Utils'; +import { forEachObjectEntry, isArray, pInt } from 'Common/Utils'; import { SettingsUserStore } from 'Stores/User/Settings'; const @@ -207,7 +207,9 @@ export const bqLevel = parseInt(SettingsUserStore.maxBlockquotesLevel()), result = { - hasExternals: false + hasExternals: false, + tracking: false, + linkedData: [] }, findAttachmentByCid = cId => oAttachments.findByCid(cId), @@ -269,12 +271,15 @@ export const // Not supported by