Merge branch 'the-djmaze:master' into master

This commit is contained in:
cm-schl 2024-05-28 16:25:25 +02:00 committed by GitHub
commit caf1ee3e2a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 280 additions and 109 deletions

View file

@ -1,3 +1,48 @@
## 2.36.3 2024-05-27
### Changed
- UserAuth prevent plugin errors (like the Nextcloud plugin did)
### Fixed
- Undefined variable $aTokenData
[#1567](https://github.com/the-djmaze/snappymail/issues/1567)
## 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
@ -29,6 +74,9 @@
- 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

View file

@ -141,24 +141,24 @@ RainLoop 1.17 vs SnappyMail
|js/* |RainLoop |Snappy |
|--------------- |--------: |--------: |
|admin.js |2.170.153 | 83.494 |
|app.js |4.207.787 | 436.310 |
|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 | 802.550 |
|TOTAL |8.240.095 | 803.319 |
|js/min/* |RainLoop |Snappy |RL gzip |SM gzip |RL brotli |SM brotli |
|--------------- |--------: |--------: |------: |------: |--------: |--------: |
|admin.min.js | 256.831 | 40.856 | 73.606 | 13.776 | 60.877 | 12.345 |
|app.min.js | 515.367 | 197.511 |139.456 | 67.058 |110.485 | 57.209 |
|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 | 291.963 |358.761 |102.749 |299.485 | 89.041 |
|TOTAL user+sieve |1.217.635 | 333.056 |358.761 |113.074 |299.485 | 98.368 |
|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 68% smaller and faster than traditional RainLoop.

View file

@ -78,6 +78,10 @@ export class AdminSettingsAbout /*extends AbstractViewSettings*/ {
});
}
clearCache() {
Remote.request('AdminClearCache');
}
updateCoreData() {
if (!this.coreUpdating()) {
this.coreUpdating(true);

View file

@ -18,8 +18,6 @@ import { OpenPgpGeneratePopupView } from 'View/Popup/OpenPgpGenerate';
import { SMimeUserStore } from 'Stores/User/SMime';
import { SMimeImportPopupView } from 'View/Popup/SMimeImport';
import Remote from 'Remote/User/Fetch';
export class UserSettingsSecurity extends AbstractViewSettings {
constructor() {
super();
@ -62,9 +60,7 @@ export class UserSettingsSecurity extends AbstractViewSettings {
}
importToOpenPGP() {
OpenPGPUserStore.isSupported() && Remote.request('GetPGPKeys',
(iError, oData) => !iError && oData.Result && OpenPGPUserStore.importKeys(oData.Result)
);
OpenPGPUserStore.loadBackupKeys();
}
importToSMime() {

View file

@ -16,6 +16,8 @@ import { Passphrases } from 'Storage/Passphrases';
import { baseCollator } from 'Common/Translator';
const
loaded = () => !!window.openpgp,
findOpenPGPKey = (keys, query/*, sign*/) =>
keys.find(key =>
key.for(query) || query == key.id || query == key.fingerprint
@ -134,23 +136,36 @@ export const OpenPGPUserStore = new class {
}
loadKeyrings() {
if (window.openpgp) {
loadOpenPgpKeys(publicKeysItem).then(keys => {
if (loaded()) {
loadOpenPgpKeys(publicKeysItem)
.then(keys => {
this.publicKeys(dedup(keys));
console.log('openpgp.js public keys loaded');
});
loadOpenPgpKeys(privateKeysItem).then(keys => {
this.privateKeys(dedup(keys));
console.log('openpgp.js private keys loaded');
})
.finally(() => {
loadOpenPgpKeys(privateKeysItem)
.then(keys => {
this.privateKeys(dedup(keys));
console.log('openpgp.js private keys loaded');
})
.finally(() => {
/*SettingsGet('loadBackupKeys') && */this.loadBackupKeys();
});
});
}
}
loadBackupKeys() {
Remote.request('GetPGPKeys',
(iError, oData) => !iError && oData.Result && this.importKeys(oData.Result)
);
}
/**
* @returns {boolean}
*/
isSupported() {
return !!window.openpgp;
return loaded();
}
importKey(armoredKey) {
@ -158,7 +173,7 @@ export const OpenPGPUserStore = new class {
}
async importKeys(keys) {
if (window.openpgp) {
if (loaded()) {
const privateKeys = this.privateKeys(),
publicKeys = this.publicKeys();
for (const armoredKey of keys) try {
@ -185,7 +200,7 @@ export const OpenPGPUserStore = new class {
keyPair.revocationCertificate
*/
storeKeyPair(keyPair) {
if (window.openpgp) {
if (loaded()) {
openpgp.readKey({armoredKey:keyPair.publicKey}).then(key => {
this.publicKeys.push(new OpenPgpKeyModel(keyPair.publicKey, key));
storeOpenPgpKeys(this.publicKeys, publicKeysItem);

View file

@ -914,10 +914,9 @@ export class ComposePopupView extends AbstractViewPopup {
oLastMessage.headers().valuesByName('autocrypt').forEach(value => {
let autocrypt = new MimeHeaderAutocryptModel(value);
if (autocrypt.addr && autocrypt.keydata) {
PgpUserStore.hasPublicKeyForEmails([autocrypt.addr]).then(result =>
result || PgpUserStore.importKey(autocrypt.pem(), true, true)
// result || showScreenPopup(OpenPgpImportPopupView, [autocrypt.pem()])
);
PgpUserStore.hasPublicKeyForEmails([autocrypt.addr])
|| PgpUserStore.importKey(autocrypt.pem(), true, true)
// || showScreenPopup(OpenPgpImportPopupView, [autocrypt.pem()])
}
});
} break;
@ -1566,6 +1565,10 @@ export class ComposePopupView extends AbstractViewPopup {
params.signed = signed.toString();
params.boundary = signed.boundary;
data = signed;
/*
Object.entries(PgpUserStore.getPublicKeyOfEmails([getEmail(this.from())]) || {})
.forEach(([k,v]) => params.publicKey = v);
*/
} catch (e) {
sign = false;
console.error(e);
@ -1579,6 +1582,7 @@ export class ComposePopupView extends AbstractViewPopup {
// params.signData = data.toString();
params.signFingerprint = signOptions[i][1].fingerprint;
params.signPassphrase = pass;
// params.attachPublicKey = false;
} else {
sign = false;
}
@ -1589,6 +1593,7 @@ export class ComposePopupView extends AbstractViewPopup {
params.sign = 'S/MIME';
// params.signCertificate = identity.smimeCertificate();
// params.signPrivateKey = identity.smimeKey();
// params.attachCertificate = false;
if (identity.smimeKeyEncrypted()) {
const pass = await Passphrases.ask(identity,
i18n('SMIME/PRIVATE_KEY_OF', {EMAIL: identity.email()}),

View file

@ -1,4 +1,4 @@
This app packages SnappyMail <upstream>2.36.1</upstream>.
This app packages SnappyMail <upstream>2.36.3</upstream>.
SnappyMail is a simple, modern, lightweight & fast web-based email client.

View file

@ -4,7 +4,7 @@ RUN mkdir -p /app/code
WORKDIR /app/code
# If you change the extraction below, be sure to test on scaleway
VERSION=2.36.1
VERSION=2.36.3
RUN wget https://github.com/the-djmaze/snappymail/releases/download/v${VERSION}/snappymail-${VERSION}.zip -O /tmp/snappymail.zip && \
unzip /tmp/snappymail.zip -d /app/code && \
rm /tmp/snappymail.zip && \

View file

@ -3,7 +3,7 @@
<id>snappymail</id>
<name>SnappyMail</name>
<summary>SnappyMail Webmail</summary>
<version>2.36.1</version>
<version>2.36.3</version>
<licence>agpl</licence>
<author>SnappyMail, RainLoop Team, Nextgen-Networks, Tab Fitts, Nathan Kinkade, Pierre-Alain Bandinelli</author>
<description><![CDATA[**Lightweight & fast email client.**

View file

@ -1,5 +1,5 @@
{ "translations": {
"Email" : "Helbide elektronikoa",
"Email" : "Posta",
"Error" : "Errorea",
"Invalid argument(s)" : "Argumentu baliogabea(k)",
"Saved successfully" : "Ondo gorde da",
@ -16,4 +16,4 @@
"Enter an email and password to auto-login to SnappyMail." : "Saioa automatikoki hasteko sartu helbide elektronikoa eta pasahitza SnappyMail-en.",
"Password" : "Pasahitza"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
}

View file

@ -53,8 +53,7 @@ class FetchController extends Controller {
$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']));
// DISABLED https://github.com/the-djmaze/snappymail/issues/1420#issuecomment-1933045917
// $this->config->setAppValue('snappymail', 'snappymail-autologin-oidc', isset($_POST['snappymail-autologin-oidc']));
$this->config->setAppValue('snappymail', 'snappymail-autologin-oidc', isset($_POST['snappymail-autologin-oidc']));
} else {
return new JSONResponse([
'status' => 'error',

View file

@ -22,9 +22,8 @@ class AdminSettings implements ISettings
$keys = [
'snappymail-autologin',
'snappymail-autologin-with-email',
'snappymail-no-embed'
// DISABLED https://github.com/the-djmaze/snappymail/issues/1420#issuecomment-1933045917
// 'snappymail-autologin-oidc'
'snappymail-no-embed',
'snappymail-autologin-oidc'
];
$parameters = [];
foreach ($keys as $k) {

View file

@ -91,9 +91,18 @@ class SnappyMailHelper
*/
if ($doLogin && $aCredentials[1] && $aCredentials[2]) {
try {
$oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2]);
if ($oAccount && $oConfig->Get('login', 'sign_me_auto', \RainLoop\Enumerations\SignMeType::DefaultOff) === \RainLoop\Enumerations\SignMeType::DefaultOn) {
$oActions->SetSignMeToken($oAccount);
$ocSession = \OC::$server->getSession();
if ($ocSession->get('is_oidc')) {
$pwd = new \SnappyMail\SensitiveString($aCredentials[1]);
$oAccount = $oActions->LoginProcess($aCredentials[1], $pwd);
if ($oAccount) {
$oActions->SetSignMeToken($oAccount);
}
} else {
$oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2]);
if ($oAccount && $oConfig->Get('login', 'sign_me_auto', \RainLoop\Enumerations\SignMeType::DefaultOff) === \RainLoop\Enumerations\SignMeType::DefaultOn) {
$oActions->SetSignMeToken($oAccount);
}
}
} catch (\Throwable $e) {
// Login failure, reset password to prevent more attempts
@ -140,22 +149,22 @@ class SnappyMailHelper
// If the current user ID is identical to login ID (not valid when using account switching),
// this has the second priority.
if ($ocSession['snappymail-nc-uid'] == $sUID) {
/*
// If OpenID Connect (OIDC) is enabled and used for login, use this.
// https://apps.nextcloud.com/apps/oidc_login
// DISABLED https://github.com/the-djmaze/snappymail/issues/1420#issuecomment-1933045917
if ($config->getAppValue('snappymail', 'snappymail-autologin-oidc', false)) {
if ($ocSession->get('is_oidc')) {
// IToken->getPassword() ???
if ($sAccessToken = $ocSession->get('oidc_access_token')) {
return [$sUID, 'oidc@nextcloud', $sAccessToken];
$sEmail = $config->getUserValue($sUID, 'settings', 'email');
return [$sUID, $sEmail, $sAccessToken];
}
\SnappyMail\Log::debug('Nextcloud', 'OIDC access_token missing');
} else {
\SnappyMail\Log::debug('Nextcloud', 'No OIDC login');
}
}
*/
// Only use the user's password in the current session if they have
// enabled auto-login using Nextcloud username or email address.
$sEmail = '';

View file

@ -38,15 +38,15 @@
</div>
</p>
<br />
<!-- DISABLED https://github.com/the-djmaze/snappymail/issues/1420#issuecomment-1933045917
<p>
<input id="snappymail-autologin-oidc" name="snappymail-autologin-oidc" type="checkbox" class="checkbox" <php if ($_['snappymail-autologin-oidc']) echo 'checked="checked"'; ?>>
<input id="snappymail-autologin-oidc" name="snappymail-autologin-oidc" type="checkbox" class="checkbox" <?php if ($_['snappymail-autologin-oidc']) echo 'checked="checked"'; ?>>
<label for="snappymail-autologin-oidc">
<php echo($l->t('Attempt to automatically login with OIDC when active')); ?>
<?php echo($l->t('Attempt to automatically login with OIDC when active')); ?>
</label>
</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">

View file

@ -20,7 +20,7 @@ return "SnappyMail Webmail is a browser-based multilingual IMAP client with an a
# script_snappymail_versions()
sub script_snappymail_versions
{
return ( "2.36.1" );
return ( "2.36.3" );
}
sub script_snappymail_version_desc

View file

@ -3,7 +3,7 @@
"title": "SnappyMail",
"description": "Simple, modern & fast web-based email client",
"private": true,
"version": "2.36.1",
"version": "2.36.3",
"homepage": "https://snappymail.eu",
"author": {
"name": "DJ Maze",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

Before After
Before After

View file

@ -10,8 +10,8 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
NAME = 'Avatars',
AUTHOR = 'SnappyMail',
URL = 'https://snappymail.eu/',
VERSION = '1.16',
RELEASE = '2024-03-12',
VERSION = '1.17',
RELEASE = '2024-05-26',
REQUIRED = '2.25.0',
CATEGORY = 'Contacts',
LICENSE = 'MIT',
@ -304,6 +304,7 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
$sDomain = \preg_replace('/^(.+\\.)?(paypal\\.[a-z][a-z])$/D', 'paypal.com', $sDomain);
$sDomain = \preg_replace('/^facebookmail.com$/D', 'facebook.com', $sDomain);
$sDomain = \preg_replace('/^dhlparcel.nl$/D', 'dhl.com', $sDomain);
$sDomain = \preg_replace('/^amazon.nl$/D', 'amazon.com', $sDomain);
$sDomain = \preg_replace('/^.+\\.([^.]+\\.[^.]+)$/D', '$1', $sDomain);
return $sDomain;
}

View file

@ -4,11 +4,11 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = 'Nextcloud',
VERSION = '2.35',
RELEASE = '2024-03-29',
VERSION = '2.36.2',
RELEASE = '2024-05-27',
CATEGORY = 'Integrations',
DESCRIPTION = 'Integrate with Nextcloud v20+',
REQUIRED = '2.36.0';
REQUIRED = '2.36.2';
public function Init() : void
{
@ -35,13 +35,12 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin
$this->addTemplate('templates/PopupsNextcloudFiles.html');
$this->addTemplate('templates/PopupsNextcloudCalendars.html');
/*
$this->addHook('login.credentials.step-2', 'loginCredentials2');
$this->addHook('login.credentials', 'loginCredentials');
// $this->addHook('login.credentials.step-2', 'loginCredentials2');
// $this->addHook('login.credentials', 'loginCredentials');
$this->addHook('imap.before-login', 'beforeLogin');
$this->addHook('smtp.before-login', 'beforeLogin');
$this->addHook('sieve.before-login', 'beforeLogin');
*/
} else {
\SnappyMail\Log::debug('Nextcloud', 'NOT integrated');
// \OC::$server->getConfig()->getAppValue('snappymail', 'snappymail-no-embed');
@ -73,23 +72,24 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin
public function loginCredentials(string &$sEmail, string &$sLogin, ?string &$sPassword = null) : void
{
$ocUser = \OC::$server->getUserSession()->getUser();
$sEmail = $ocUser->getEMailAddress() ?: $oc->user->getPrimaryEMailAddress();
$sLogin = $ocUser->getUID();
/**
* This has an issue.
* When user changes email address, all settings are gone as the new
* _data_/_default_/storage/{domain}/{local-part} is used
*/
// $ocUser = \OC::$server->getUserSession()->getUser();
// $sEmail = $ocUser->getEMailAddress() ?: $ocUser->getPrimaryEMailAddress() ?: $sEmail;
}
public function loginCredentials2(string &$sEmail, ?string &$sPassword = null) : void
{
$ocUser = \OC::$server->getUserSession()->getUser();
$sEmail = $ocUser->getEMailAddress() ?: $oc->user->getPrimaryEMailAddress();
$sEmail = $ocUser->getEMailAddress() ?: $ocUser->getPrimaryEMailAddress() ?: $sEmail;
}
public function beforeLogin(\RainLoop\Model\Account $oAccount, \MailSo\Net\NetClient $oClient, \MailSo\Net\ConnectSettings $oSettings) : void
{
$oSettings->username = \OC::$server->getUserSession()->getUser()->getUID();
/*
// https://apps.nextcloud.com/apps/oidc_login
// DISABLED https://github.com/the-djmaze/snappymail/issues/1420#issuecomment-1933045917
if (\OC::$server->getConfig()->getAppValue('snappymail', 'snappymail-autologin-oidc', false)
&& \OC::$server->getSession()->get('is_oidc')
// && $oClient->supportsAuthType('OAUTHBEARER') // v2.28
@ -100,7 +100,6 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin
\array_unshift($oSettings->SASLMechanisms, 'OAUTHBEARER');
}
}
*/
}
/*
@ -244,7 +243,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin
}
if (!$sEmail) {
$sEmail = $ocUser->getEMailAddress();
// ?: $oc->user->getPrimaryEMailAddress();
// ?: $ocUser->getPrimaryEMailAddress();
}
/*
if ($config->getAppValue('snappymail', 'snappymail-autologin-oidc', false)) {

View file

@ -6,8 +6,8 @@ class ProxyAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
NAME = 'Proxy Auth',
AUTHOR = 'Philipp',
URL = 'https://www.mundhenk.org/',
VERSION = '0.3',
RELEASE = '2024-03-27',
VERSION = '0.4',
RELEASE = '2024-05-26',
REQUIRED = '2.36.1',
CATEGORY = 'Login',
LICENSE = 'MIT',
@ -118,7 +118,7 @@ class ProxyAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
if ($sProxyRequest) {
/* create master user login from remote user header and settings */
$sEmail = $sRemoteUser . $sMasterSeparator . $sMasterUser;
$sPassword = \trim($this->Config()->getDecrypted('plugin', 'master_password', ''));
$sPassword = new \SnappyMail\SensitiveString(\trim($this->Config()->getDecrypted('plugin', 'master_password', '')));
try
{

View file

@ -11,11 +11,11 @@
ForwardProxyAuth = () => {
if (auto_login) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/?UserHeaderSet", true);
xhr.open("GET", "?UserHeaderSet", true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
window.location.href = "/?ProxyAuth";
window.location.href = "?ProxyAuth";
}
};

View file

@ -11,16 +11,27 @@
dateRegEx = /(TZID=(?<tz>[^:]+):)?(?<year>[0-9]{4})(?<month>[0-9]{2})(?<day>[0-9]{2})T(?<hour>[0-9]{2})(?<minute>[0-9]{2})(?<second>[0-9]{2})(?<utc>Z?)/,
parseDate = str => {
let parts = dateRegEx.exec(str)?.groups,
options = {dateStyle: 'long', timeStyle: 'short'};
options = {dateStyle: 'long', timeStyle: 'short'},
date = (parts ? new Date(
parseInt(parts.year, 10),
parseInt(parts.month, 10) - 1,
parseInt(parts.day, 10),
parseInt(parts.hour, 10),
parseInt(parts.minute, 10),
parseInt(parts.second, 10)
) : new Date(str));
parts?.tz && (options.timeZone = parts.tz);
return (parts ? new Date(
parseInt(parts.year, 10),
parseInt(parts.month, 10) - 1,
parseInt(parts.day, 10),
parseInt(parts.hour, 10),
parseInt(parts.minute, 10),
parseInt(parts.second, 10)
) : new Date(str)).format(options);
try {
return date.format(options);
} catch (e) {
console.error(e);
if (options.timeZone) {
// TODO: handle messy vtimezones
// VTIMEZONEs[options.timeZone];
options.timeZone = undefined;
return date.format(options);
}
}
};
attachmentsPlace.after(Element.fromHTML(`

View file

@ -192,11 +192,18 @@ class SmtpClient extends \MailSo\Net\NetClient
{
$sRequest = '';
if (\str_starts_with($type, 'SCRAM-')) {
// RFC 5802
// RFC 5802 send "client-first-message" and receive "server-first-message"
$sRequest = $SASL->authenticate($sLogin, $sPassword, $sResult);
$this->logMask($sRequest);
$sResult = $this->sendRequestWithCheck($sRequest, 334);
// RFC 5802 send "client-final-message" and receive "server-final-message"
$sRequest = $SASL->challenge($sResult);
$this->logMask($sRequest);
$sResult = $this->sendRequestWithCheck($sRequest, 334);
$SASL->verify($sResult);
// Now end the authentication
$sRequest = '';
$this->sendRequestWithCheck($sRequest, 235);
} else switch ($type) {
// RFC 4616
case 'PLAIN':

View file

@ -264,14 +264,15 @@ class Actions
}
if ($oAccount) {
$oDomain = $oAccount->Domain();
$sLine = \str_replace('{imap:login}', $oAccount->ImapUser(), $sLine);
$sLine = \str_replace('{imap:host}', $oDomain->ImapSettings()->host, $sLine);
$sLine = \str_replace('{imap:port}', $oDomain->ImapSettings()->port, $sLine);
$sLine = \str_replace('{smtp:login}', $oAccount->SmtpUser(), $sLine);
$sLine = \str_replace('{smtp:host}', $oDomain->SmtpSettings()->host, $sLine);
$sLine = \str_replace('{smtp:port}', $oDomain->SmtpSettings()->port, $sLine);
$oDomain = $oAccount->Domain();
if ($oDomain) {
$sLine = \str_replace('{imap:host}', $oDomain->ImapSettings()->host, $sLine);
$sLine = \str_replace('{imap:port}', $oDomain->ImapSettings()->port, $sLine);
$sLine = \str_replace('{smtp:host}', $oDomain->SmtpSettings()->host, $sLine);
$sLine = \str_replace('{smtp:port}', $oDomain->SmtpSettings()->port, $sLine);
}
}
$aClear['/\{imap:([^}]*)\}/i'] = 'imap';

View file

@ -1145,7 +1145,25 @@ trait Messages
}
}
}
/*
// OpenPGP https://github.com/the-djmaze/snappymail/issues/1587
$sPublicKey = $this->GetActionParam('publicKey', '');
if ($sPublicKey) {
$oMessage->Attachments()->append(
new \MailSo\Mime\Attachment(
\fopen("data://text/plain,{$sPublicKey}", 'r'),
'OpenPGP_'.\md5($sPublicKey).'.asc',
\strlen($sPublicKey),
false,
false,
'',
array(),
'',
'application/pgp-keys'
)
);
}
*/
foreach ($aFoundDataURL as $sCidHash => $sDataUrlString) {
$aMatch = array();
$sCID = '<'.$sCidHash.'>';
@ -1171,9 +1189,29 @@ trait Messages
$oPassphrase = new \SnappyMail\SensitiveString($this->GetActionParam('signPassphrase', ''));
// GnuPG
$sFingerprint = $this->GetActionParam('signFingerprint', '');
if ($sFingerprint) {
$GPG = $this->GnuPG();
/*
// https://github.com/the-djmaze/snappymail/issues/1587
if ($this->GetActionParam('attachPublicKey', false)) {
$sPublicKey = $GPG->export($sFingerprint);
$oMessage->Attachments()->append(
new \MailSo\Mime\Attachment(
\fopen("data://text/plain,{$sPublicKey}", 'r'),
"OpenPGP_0x{$sFingerprint}.asc",
\strlen($sPublicKey),
false,
false,
'',
array(),
'',
'application/pgp-keys'
)
);
}
*/
$oBody = $oMessage->GetRootPart();
$resource = $oBody->ToStream();
@ -1225,6 +1263,24 @@ trait Messages
}
}
}
/*
// https://github.com/the-djmaze/snappymail/issues/1587
if ($sCertificate && $this->GetActionParam('attachCertificate', false)) {
$oMessage->Attachments()->append(
new \MailSo\Mime\Attachment(
\fopen("data://text/plain,{$sCertificate}", 'r'),
'certificate.pem',
\strlen($sCertificate),
false,
false,
'',
array(),
'',
'application/pem-certificate-chain'
)
);
}
*/
if ($sCertificate && $sPrivateKey) {
$oBody = $oMessage->GetRootPart();

View file

@ -37,7 +37,11 @@ trait UserAuth
{
$sEmail = \SnappyMail\IDN::emailToAscii(\MailSo\Base\Utils::Trim($sEmail));
$this->Plugins()->RunHook('login.credentials.step-1', array(&$sEmail));
$sNewEmail = $sEmail;
$this->Plugins()->RunHook('login.credentials.step-1', array(&$sNewEmail));
if ($sNewEmail) {
$sEmail = $sNewEmail;
}
$oDomain = null;
$oDomainProvider = $this->DomainProvider();
@ -98,9 +102,13 @@ trait UserAuth
}
}
$sPassword = (string) $oPassword;
$this->Plugins()->RunHook('login.credentials.step-2', array(&$sEmail, &$sPassword));
$sNewEmail = $sEmail;
$sPassword = $oPassword->getValue();
$this->Plugins()->RunHook('login.credentials.step-2', array(&$sNewEmail, &$sPassword));
$this->logMask($sPassword);
if ($sNewEmail) {
$sEmail = $sNewEmail;
}
$sImapUser = $sEmail;
$sSmtpUser = $sEmail;
@ -112,15 +120,18 @@ trait UserAuth
$sSmtpUser = $oDomain->SmtpSettings()->fixUsername($sSmtpUser);
}
$this->Plugins()->RunHook('login.credentials', array(&$sEmail, &$sImapUser, &$sPassword, &$sSmtpUser));
$sNewEmail = $sEmail;
$sNewImapUser = $sImapUser;
$sNewSmtpUser = $sSmtpUser;
$this->Plugins()->RunHook('login.credentials', array(&$sNewEmail, &$sNewImapUser, &$sPassword, &$sNewSmtpUser));
$oPassword->setValue($sPassword);
return [
'email' => $sEmail,
'email' => $sNewEmail ?: $sEmail,
'domain' => $oDomain,
'imapUser' => $sImapUser,
'smtpUser' => $sSmtpUser,
'imapUser' => $sNewImapUser ?: $sImapUser,
'smtpUser' => $sNewSmtpUser ?: $sSmtpUser,
'pass' => $oPassword
];
}
@ -342,8 +353,8 @@ trait UserAuth
$aResult = \SnappyMail\Crypt::DecryptUrlSafe($sSignMeToken, 'signme');
if (isset($aResult['e'], $aResult['u']) && \SnappyMail\UUID::isValid($aResult['u'])) {
if (!isset($aResult['c'])) {
$aTokenData['c'] = \array_key_last($aTokenData);
$aTokenData['d'] = \end($aTokenData);
$aResult['c'] = \array_key_last($aResult);
$aResult['d'] = \end($aResult);
}
return $aResult;
}

View file

@ -96,7 +96,7 @@ class Application extends \RainLoop\Config\AbstractConfig
{
// Workarounds for the changed application structure
if ('webmail' === $sSectionKey) {
if ('language_admin' === $sSectionKey) {
if ('language_admin' === $sParamKey) {
$sSectionKey = 'admin_panel';
$sParamKey = 'language';
}
@ -137,6 +137,16 @@ class Application extends \RainLoop\Config\AbstractConfig
$sParamKey = 'json_response_write_limit';
}
}
if ('language' === $sParamKey) {
$aLang = \SnappyMail\L10n::getLanguages('admin_panel' === $sSectionKey);
$sLanguage = \strtr($mParamValue, '_', '-');
if (!\in_array($sLanguage, $aLang)) {
if (\str_contains($sLanguage, '-')) {
$sLanguage = \strtok($sLanguage, '-');
}
}
$mParamValue = \in_array($sLanguage, $aLang) ? $sLanguage : 'en';
}
parent::Set($sSectionKey, $sParamKey, $mParamValue);
}

View file

@ -21,7 +21,7 @@ abstract class Account implements \JsonSerializable
private ?SensitiveString $oSmtpPass = null;
private Domain $oDomain;
private ?Domain $oDomain = null;
public function Email() : string
{
@ -49,7 +49,7 @@ abstract class Account implements \JsonSerializable
// return $this->sSmtpUser ?: $this->sEmail ?: $this->sImapUser;
}
public function Domain() : Domain
public function Domain() : ?Domain
{
return $this->oDomain;
}

View file

@ -38,7 +38,7 @@
"LABEL_ALLOW_THEMES_ON_SETTINGS": "Permitir personalização da interface nas definições",
"LABEL_ALLOW_BACKGROUND_ON_SETTINGS": "Permitir alterar a imagem de fundo nas definições",
"LABEL_SHOW_THUMBNAILS": "Mostrar miniaturas (anexos)",
"LEGEND_MAIN": "Prinicpal",
"LEGEND_MAIN": "Principal",
"LABEL_ATTACHMENT_SIZE_LIMIT": "Tamanho limite dos anexos",
"LABEL_ALLOW_ADDITIONAL_ACCOUNTS": "Permitir contas adicionais",
"LABEL_ALLOW_IDENTITIES": "Permitir múltiplas identidades",

View file

@ -140,7 +140,7 @@
"MENU_VIEW_ORIGINAL": "Mostrar original",
"HTML_VIEW": "Ver mensagem em HTML",
"PLAIN_VIEW": "Ver mensagem em texto simples",
"SWAP_COLORS": "Swap default (background)color",
"SWAP_COLORS": "Trocar a cor (de fundo) predefinida",
"MENU_DOWNLOAD_ORIGINAL": "Transferir como ficheiro .eml",
"MENU_FILTER_SIMILAR": "Filtrar mensagens semelhantes a esta",
"MENU_PRINT": "Imprimir",
@ -283,7 +283,7 @@
"VERIFY": "Validar",
"GOOD_SIGNATURE": "Boa assinatura de %USER%",
"ERROR": "Erro %TYPE%: %ERROR%",
"CREATE_SELF_SIGNED": "Criar auto-assinado",
"CREATE_SELF_SIGNED": "Criar autoassinado",
"VALID_UNTIL": "Válido até",
"PRIVATE_KEY": "Chave privada",
"CHANGE_PASS": "Alterar frase secreta",
@ -328,13 +328,13 @@
"SELECT_ACTION_VACATION_MESSAGE": "Mensagem de férias",
"SELECT_ACTION_DISCARD": "Descartar",
"SELECT_FIELD_RECIPIENTS": "Destinatários (Para ou Cc)",
"SELECT_FIELD_HEADER": "Cebeçalho",
"SELECT_FIELD_HEADER": "Cabeçalho",
"SELECT_FIELD_BODY": "Corpo",
"SELECT_FIELD_SIZE": "Tamanho",
"SELECT_TYPE_CONTAINS": "Contém",
"SELECT_TYPE_NOT_CONTAINS": "Não contém",
"SELECT_TYPE_MATCHES": "Corresponde (* e ? suportados)",
"SELECT_TYPE_NOT_MATCHES": "Não correponde (* e ? suportados)",
"SELECT_TYPE_NOT_MATCHES": "Não corresponde (* e ? suportados)",
"SELECT_TYPE_REGEXP": "RegExp",
"SELECT_TYPE_NOT_REGEXP": "Diferente de RegExp",
"SELECT_TYPE_EQUAL_TO": "Igual a",
@ -358,10 +358,10 @@
"POPUPS_SIEVE_SCRIPT": {
"TITLE_CREATE": "Criar script",
"TITLE_EDIT": "Editar script",
"BUTTON_ADD_FILTER": "Adiscionar um filtro",
"BUTTON_ADD_FILTER": "Adicionar um filtro",
"BUTTON_RAW_SCRIPT": "Usar um script de utilizador personalizado",
"CAPABILITY_LABEL": "Capacidades",
"CHANGES_NEED_TO_BE_SAVED_DESC": "Estas alterações têm que ser guardadas no sevidor."
"CHANGES_NEED_TO_BE_SAVED_DESC": "Estas alterações têm que ser guardadas no servidor."
},
"POPUPS_SYSTEM_FOLDERS": {
"TITLE_SYSTEM_FOLDERS": "Escolha as pastas de sistema",
@ -426,7 +426,7 @@
},
"SETTINGS_FILTERS": {
"SIMPLE": "Simples",
"ADVANCED": "Advançado",
"ADVANCED": "Avançado",
"BUTTON_ADD_SCRIPT": "Adicionar um script",
"SUBNAME_MOVE_TO": "Mover para \"%FOLDER%\"",
"SUBNAME_FORWARD_TO": "Encaminhar para \"%EMAIL%\"",
@ -449,7 +449,7 @@
"LAYOUT_HORIZONTAL_SPLIT": "Separação horizontal",
"SHOW_NEXT_MESSAGE": "Mostrar a próxima mensagem quando (re)mover a mensagem atual",
"EDITOR": "Editor de texto padrão",
"EDITOR_HTML": "Html",
"EDITOR_HTML": "HTML",
"EDITOR_PLAIN": "Texto simples",
"VIEW_OPTIONS": "Ver opções",
"USE_PREVIEW_PANE": "Use o painel de pré-visualização",
@ -591,7 +591,7 @@
"DomainAlreadyExists": "O domínio já existe",
"DomainNotAllowed": "Este domínio não é permitido",
"AccountNotAllowed": "Esta conta não é permitida",
"CryptKeyError": "Your login passphrase has changed",
"CryptKeyError": "A sua palavra-passe de autenticação foi alterada",
"ContactsSyncError": "Erro na sincronização de contactos",
"CantGetMessageList": "Não é possível obter a lista de mensagens",
"CantGetMessage": "Não é possível obter a mensagem",
@ -611,7 +611,7 @@
"CantDeleteFolder": "Não é possível eliminar a pasta",
"CantDeleteNonEmptyFolder": "Não é possível eliminar pastas com conteúdos",
"CantSubscribeFolder": "Não é possível subscrever a esta pasta",
"CantUnsubscribeFolder": "Não é possível anular a subsrição desta pasta",
"CantUnsubscribeFolder": "Não é possível anular a subscrição desta pasta",
"DemoSendMessageError": "Por motivos de segurança, esta conta de demonstração não tem permissão para enviar mensagens para endereços de e-mail externos!",
"DemoAccountError": "Por motivos de segurança, esta conta não tem permissão de executar esta ação!",
"AccountAlreadyExists": "Esta conta já existe",