mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-11-04 03:18:49 +03:00
Merge branch 'master' into advisory-fix-1
This commit is contained in:
commit
2bfa7ce673
11 changed files with 2699 additions and 2734 deletions
|
|
@ -99,9 +99,6 @@ RUN set -eux; \
|
|||
# mysql
|
||||
RUN docker-php-ext-install pdo_mysql
|
||||
|
||||
# opcache
|
||||
RUN docker-php-ext-install opcache
|
||||
|
||||
# postgres
|
||||
RUN set -eux; \
|
||||
apk add --no-cache postgresql-libs; \
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ if (isset($options['plugins'])) {
|
|||
require(ROOT_DIR . '/build/plugins.php');
|
||||
}
|
||||
|
||||
$gulp = trim(`which gulp`);
|
||||
$gulp = trim(shell_exec('which gulp'));
|
||||
if (!$gulp) {
|
||||
exit('gulp not installed, run as root: npm install --global gulp-cli');
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ $options['aur'] = isset($options['aur']);
|
|||
|
||||
// Docker build
|
||||
$options['docker'] = isset($options['docker']);
|
||||
if ($options['docker'] && !($docker = trim(`which docker`))) {
|
||||
if ($options['docker'] && !($docker = trim(shell_exec('which docker')))) {
|
||||
exit('docker not found');
|
||||
}
|
||||
if ($options['docker'] && $options['aur']) {
|
||||
|
|
@ -60,7 +60,7 @@ if (!isset($options['skip-gulp'])) {
|
|||
|
||||
$cmddir = escapeshellcmd(ROOT_DIR) . '/snappymail/v/0.0.0/static';
|
||||
|
||||
if ($gzip = trim(`which gzip`)) {
|
||||
if ($gzip = trim(shell_exec('which gzip'))) {
|
||||
echo "\x1b[33;1m === Gzip *.js and *.css === \x1b[0m\n";
|
||||
passthru("{$gzip} -k --best {$cmddir}/js/*.js");
|
||||
passthru("{$gzip} -k --best {$cmddir}/js/min/*.js");
|
||||
|
|
@ -70,7 +70,7 @@ if (!isset($options['skip-gulp'])) {
|
|||
unlink(ROOT_DIR . '/snappymail/v/0.0.0/static/js/min/boot.min.js.gz');
|
||||
}
|
||||
|
||||
if ($brotli = trim(`which brotli`)) {
|
||||
if ($brotli = trim(shell_exec('which brotli'))) {
|
||||
echo "\x1b[33;1m === Brotli *.js and *.css === \x1b[0m\n";
|
||||
passthru("{$brotli} -k --best {$cmddir}/js/*.js");
|
||||
passthru("{$brotli} -k --best {$cmddir}/js/min/*.js");
|
||||
|
|
@ -188,7 +188,7 @@ file_put_contents("{$destPath}core.json", '{
|
|||
// Arch User Repository
|
||||
if ($options['aur']) {
|
||||
// extension_loaded('blake2')
|
||||
if (!function_exists('b2sum') && $b2sum = trim(`which b2sum`)) {
|
||||
if (!function_exists('b2sum') && $b2sum = trim(shell_exec('which b2sum'))) {
|
||||
function b2sum($file) {
|
||||
$file = escapeshellarg($file);
|
||||
exec("b2sum --binary {$file} 2>&1", $output, $exitcode);
|
||||
|
|
|
|||
|
|
@ -43,10 +43,11 @@
|
|||
"dependencies": {
|
||||
"@rollup/plugin-node-resolve": "^13.1.3",
|
||||
"@rollup/plugin-replace": "^3.0.1",
|
||||
"@rollup/plugin-terser": "^1.0.2",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"del": "^6.0.0",
|
||||
"eslint": "^7.32.0",
|
||||
"gulp": "^5.0.0",
|
||||
"gulp": "^5.0.1",
|
||||
"gulp-append-prepend": "^1.0.9",
|
||||
"gulp-cached": "^1.1.1",
|
||||
"gulp-clean-css": "^4.3.0",
|
||||
|
|
@ -64,7 +65,6 @@
|
|||
"gulp-terser": "^2.1.0",
|
||||
"rollup": "^2.56.3",
|
||||
"rollup-plugin-external-globals": "^0.6.1",
|
||||
"rollup-plugin-includepaths": "^0.2.4",
|
||||
"rollup-plugin-terser": "^7.0.2"
|
||||
"rollup-plugin-includepaths": "^0.2.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,14 +136,12 @@ class HeaderCollection extends \MailSo\Base\Collection
|
|||
$sHeadersValue = \rtrim($sHeadersValue);
|
||||
}
|
||||
|
||||
if ('=?' === \substr(\ltrim($sHeadersValue), 0, 2)) {
|
||||
$sHeadersValue = \ltrim($sHeadersValue);
|
||||
}
|
||||
|
||||
if ('=?' === \substr($sHeadersValue, 0, 2)) {
|
||||
$sValue .= $sHeadersValue;
|
||||
// RFC 5322 unfolding removes the line break and keeps the folding
|
||||
// whitespace; RFC 2047 6.2 drops it only between two encoded words.
|
||||
if ('=?' === \substr(\ltrim($sHeadersValue), 0, 2) && '?=' === \substr($sValue, -2)) {
|
||||
$sValue .= \ltrim($sHeadersValue);
|
||||
} else {
|
||||
$sValue .= "\n".$sHeadersValue;
|
||||
$sValue .= ' '.\ltrim($sHeadersValue);
|
||||
}
|
||||
} else {
|
||||
if (null !== $sName) {
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ class ServiceActions
|
|||
$sData = empty($this->aPaths[1]) ? '' : $this->aPaths[1];
|
||||
if ($sData
|
||||
&& $this->Config()->Get('labs', 'use_local_proxy_for_external_images', false)
|
||||
&& $this->oActions->getAccountFromToken()
|
||||
&& $this->oActions->getMainAccountFromToken()
|
||||
) {
|
||||
$this->oActions->verifyCacheByKey($sData);
|
||||
$sUrl = \MailSo\Base\Utils::UrlSafeBase64Decode($sData);
|
||||
|
|
|
|||
|
|
@ -434,7 +434,7 @@ abstract class Base
|
|||
public function agent()
|
||||
{
|
||||
// $home = \escapeshellarg($this->options['homedir']);
|
||||
// echo `gpg-agent --daemon --homedir $home 2>&1`;
|
||||
// echo \shell_exec('gpg-agent --daemon --homedir $home 2>&1');
|
||||
}
|
||||
|
||||
protected function getPassphrase($key)
|
||||
|
|
@ -487,7 +487,7 @@ abstract class Base
|
|||
|
||||
protected static function findBinary($name) : ?string
|
||||
{
|
||||
$binary = \function_exists('shell_exec') ? \trim((string) `which $name`) : '';
|
||||
$binary = \function_exists('shell_exec') ? \trim((string) \shell_exec('which $name')) : '';
|
||||
if ($binary && \RainLoop\Utils::inOpenBasedir($binary) && \is_executable($binary)) {
|
||||
return $binary;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class SMIME extends Base
|
|||
// How to use gpgme-json ?
|
||||
$this->binary = static::findBinary('gpgsm');
|
||||
|
||||
$info = \preg_replace('/\R +/', ' ', `$this->binary --version`);
|
||||
$info = \preg_replace('/\R +/', ' ', \shell_exec("{$this->binary} --version"));
|
||||
if (\preg_match('/gpgsm.+([0-9]+\\.[0-9]+\\.[0-9]+)/', $info, $match)) {
|
||||
$this->version = $match[1];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,16 +39,7 @@ class Response
|
|||
$this->request_uri = $request_uri;
|
||||
$this->final_uri = $request_uri;
|
||||
$this->status = (int) $status;
|
||||
if (\function_exists('gzinflate') && isset($this->headers['content-encoding'])
|
||||
&& (false !== \stripos($this->headers['content-encoding'], 'gzip'))) {
|
||||
$this->body = \gzinflate(\substr($body, 10, -4));
|
||||
if (false === $this->body) {
|
||||
$err = \error_get_last() ?: ['message' => 'gzinflate failed'];
|
||||
throw new \RuntimeException("{$err['message']} for {$request_uri}");
|
||||
}
|
||||
} else {
|
||||
$this->body = $body;
|
||||
}
|
||||
$this->body = $body;
|
||||
}
|
||||
|
||||
function __get($k)
|
||||
|
|
@ -56,6 +47,20 @@ class Response
|
|||
return \property_exists($this, $k) ? $this->$k : null;
|
||||
}
|
||||
|
||||
public function decoded()/*: string|false*/
|
||||
{
|
||||
$body = $this->body;
|
||||
if (\function_exists('gzinflate') && isset($this->headers['content-encoding'])
|
||||
&& (false !== \stripos($this->headers['content-encoding'], 'gzip'))) {
|
||||
$body = \gzinflate(\substr($body, 10, -4));
|
||||
if (false === $body) {
|
||||
$err = \error_get_last() ?: ['message' => 'gzinflate failed'];
|
||||
throw new \RuntimeException("{$err['message']} for {$request_uri}");
|
||||
}
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns string, array or null
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ class OpenSSL
|
|||
}
|
||||
$input = $tmp;
|
||||
}
|
||||
`openssl asn1parse -in $input->filename()`
|
||||
\shell_exec('openssl asn1parse -in $input->filename()');
|
||||
}
|
||||
*/
|
||||
public function decrypt(/*string|Temporary*/ $input) : ?string
|
||||
|
|
|
|||
51
test/header-unfold.php
Normal file
51
test/header-unfold.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
// Run with: php test/header-unfold.php
|
||||
// RFC 5322 unfolding keeps the folding whitespace; RFC 2047 drops only the
|
||||
// whitespace BETWEEN two encoded words. A plain word followed by a folded
|
||||
// encoded word lost its space: "de vos\r\n =?utf-8?Q?=C3=A9quipements?="
|
||||
// was shown as "voséquipements" (Symfony Mailer folds subjects this way).
|
||||
define('APP_VERSION', 'test');
|
||||
spl_autoload_register(static function (string $class): void {
|
||||
if (str_starts_with($class, 'SnappyMail\\')) {
|
||||
$file = dirname(__DIR__).'/snappymail/v/0.0.0/app/libraries/snappymail/'.strtolower(str_replace('\\', '/', substr($class, 11))).'.php';
|
||||
} else {
|
||||
$file = dirname(__DIR__).'/snappymail/v/0.0.0/app/libraries/'.str_replace('\\', '/', $class).'.php';
|
||||
}
|
||||
if (is_file($file)) {
|
||||
require_once $file;
|
||||
}
|
||||
});
|
||||
|
||||
function check(bool $condition, string $message): void
|
||||
{
|
||||
if (!$condition) {
|
||||
throw new RuntimeException($message);
|
||||
}
|
||||
}
|
||||
|
||||
function subject(string $raw): string
|
||||
{
|
||||
$headers = new \MailSo\Mime\HeaderCollection("Subject: {$raw}\r\nX-Next: 1\r\n");
|
||||
return (string) $headers->ValueByName('Subject');
|
||||
}
|
||||
|
||||
$cases = [
|
||||
// plain word, then a folded encoded word: the space stays
|
||||
"Traiter les =?utf-8?Q?vuln=C3=A9rabilit=C3=A9s?= de vos\r\n =?utf-8?Q?=C3=A9quipements?= : plan de =?utf-8?Q?rem=C3=A9diation?= et\r\n checklist =?utf-8?Q?sign=C3=A9e?="
|
||||
=> 'Traiter les vulnérabilités de vos équipements : plan de remédiation et checklist signée',
|
||||
// two encoded words split across lines: no space between them (RFC 2047 §6.2)
|
||||
"=?utf-8?Q?r=C3=A9pon?=\r\n =?utf-8?Q?se?=" => 'réponse',
|
||||
"=?utf-8?B?w6l0w6k=?=\r\n\t=?utf-8?B?IGZpbg==?=" => 'été fin',
|
||||
// encoded word, then a folded plain word: the space stays
|
||||
"=?utf-8?Q?r=C3=A9union?=\r\n demain" => 'réunion demain',
|
||||
// no encoding at all
|
||||
"Hello\r\n world" => 'Hello world',
|
||||
];
|
||||
foreach ($cases as $raw => $want) {
|
||||
// exact: a fold is one space, never two ("et checklist" ended up in replies)
|
||||
$got = subject($raw);
|
||||
check($got === $want, "got [{$got}], want [{$want}]");
|
||||
}
|
||||
|
||||
echo "header-unfold: ".count($cases)." checks OK\n";
|
||||
Loading…
Add table
Add a link
Reference in a new issue