Skip to content

Commit

Permalink
Release Joomla! 4.4.7
Browse files Browse the repository at this point in the history
  • Loading branch information
bembelimen committed Aug 19, 2024
1 parent 51032f6 commit bbfe0e0
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 45 deletions.
9 changes: 9 additions & 0 deletions administrator/components/com_users/src/Model/UserModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,15 @@ public function save($data)
}
}

// Unset the username if it should not be overwritten
if (
!$my->authorise('core.manage', 'com_users')
&& (int) $user->id === (int) $my->id
&& !ComponentHelper::getParams('com_users')->get('change_login_name')
) {
unset($data['username']);
}

// Bind the data.
if (!$user->bind($data)) {
$this->setError($user->getError());
Expand Down
2 changes: 1 addition & 1 deletion administrator/manifests/files/joomla.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<authorUrl>www.joomla.org</authorUrl>
<copyright>(C) 2019 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<version>4.4.7-rc2-dev</version>
<version>4.4.7</version>
<creationDate>2024-08</creationDate>
<description>FILES_JOOMLA_XML_DESCRIPTION</description>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ private function _sendEmail($data, $contact, $emailCopyToSender)
$mailer->addRecipient($contact->email_to);
$mailer->setReplyTo($templateData['email'], $templateData['name']);
$mailer->addTemplateData($templateData);
$mailer->addUnsafeTags(['name', 'email', 'body', 'customfields']);
$sent = $mailer->send();

// If we are supposed to copy the sender, do so.
Expand Down
1 change: 1 addition & 0 deletions components/com_users/src/Model/RegistrationModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ public function register($temp)
$mailer = new MailTemplate($mailtemplate, $app->getLanguage()->getTag());
$mailer->addTemplateData($data);
$mailer->addRecipient($data['email']);
$mailer->addUnsafeTags(['username', 'password_clear', 'name']);
$return = $mailer->send();
} catch (\Exception $exception) {
try {
Expand Down
6 changes: 5 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
"type": "vcs",
"url": "https://github.com/joomla-backports/json-api-php.git",
"no-api": true
},
{
"type": "vcs",
"url": "https://github.com/joomla-framework/security-filter.git"
}
],
"autoload": {
Expand All @@ -54,7 +58,7 @@
"joomla/database": "^2.1.1",
"joomla/di": "^2.0.1",
"joomla/event": "^2.0.2",
"joomla/filter": "^2.0.4",
"joomla/filter": "dev-2x-outputfilter-case as 2.0.5",
"joomla/filesystem": "^2.0.2",
"joomla/http": "^2.0.4",
"joomla/input": "^2.0.4",
Expand Down
41 changes: 26 additions & 15 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 54 additions & 10 deletions libraries/src/Mail/MailTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ class MailTemplate
*/
protected $data = [];

/**
*
* @var string[]
* @since 4.4.7
*/
protected $unsafe_tags = [];

/**
*
* @var string[]
Expand Down Expand Up @@ -174,6 +181,20 @@ public function addTemplateData($data)
$this->data = array_merge($this->data, $data);
}

/**
* Mark tags as unsafe to ensure escaping in HTML mails
*
* @param array $tags Tag names
*
* @return void
*
* @since 4.4.7
*/
public function addUnsafeTags($tags)
{
$this->unsafe_tags = array_merge($this->unsafe_tags, array_map('strtoupper', $tags));
}

/**
* Render and send the mail
*
Expand Down Expand Up @@ -234,7 +255,7 @@ public function send()

$mailStyle = $config->get('mail_style', 'plaintext');
$plainBody = $this->replaceTags(Text::_($mail->body), $this->data);
$htmlBody = $this->replaceTags(Text::_($mail->htmlbody), $this->data);
$htmlBody = $this->replaceTags(Text::_($mail->htmlbody), $this->data, true);

if ($mailStyle === 'plaintext' || $mailStyle === 'both') {
// If the Plain template is empty try to convert the HTML template to a Plain text
Expand All @@ -255,7 +276,7 @@ public function send()

// If HTML body is empty try to convert the Plain template to html
if (!$htmlBody) {
$htmlBody = nl2br($plainBody, false);
$htmlBody = nl2br($this->replaceTags(Text::_($mail->body), $this->data, true), false);
}

$htmlBody = MailHelper::convertRelativeToAbsoluteUrls($htmlBody);
Expand Down Expand Up @@ -315,17 +336,23 @@ public function send()
/**
* Replace tags with their values recursively
*
* @param string $text The template to process
* @param array $tags An associative array to replace in the template
* @param string $text The template to process
* @param array $tags An associative array to replace in the template
* @param bool $isHtml Is the text an HTML text and requires escaping
*
* @return string Rendered mail template
*
* @since 4.0.0
*/
protected function replaceTags($text, $tags)
protected function replaceTags($text, $tags, $isHtml = false)
{
foreach ($tags as $key => $value) {
if (is_array($value)) {
// If the value is NULL, replace with an empty string. NULL itself throws notices
if (\is_null($value)) {
$value = '';
}

if (\is_array($value)) {
$matches = [];
$pregKey = preg_quote(strtoupper($key), '/');

Expand All @@ -334,11 +361,23 @@ protected function replaceTags($text, $tags)
$replacement = '';

foreach ($value as $name => $subvalue) {
if (is_array($subvalue) && $name == $matches[1][$i]) {
if (\is_array($subvalue) && $name == $matches[1][$i]) {
$subvalue = implode("\n", $subvalue);

// Escape if necessary
if ($isHtml && \in_array(strtoupper($key), $this->unsafe_tags, true)) {
$subvalue = htmlspecialchars($subvalue, ENT_QUOTES, 'UTF-8');
}

$replacement .= implode("\n", $subvalue);
} elseif (is_array($subvalue)) {
$replacement .= $this->replaceTags($matches[1][$i], $subvalue);
} elseif (is_string($subvalue) && $name == $matches[1][$i]) {
} elseif (\is_array($subvalue)) {
$replacement .= $this->replaceTags($matches[1][$i], $subvalue, $isHtml);
} elseif (\is_string($subvalue) && $name == $matches[1][$i]) {
// Escape if necessary
if ($isHtml && \in_array(strtoupper($key), $this->unsafe_tags, true)) {
$subvalue = htmlspecialchars($subvalue, ENT_QUOTES, 'UTF-8');
}

$replacement .= $subvalue;
}
}
Expand All @@ -347,6 +386,11 @@ protected function replaceTags($text, $tags)
}
}
} else {
// Escape if necessary
if ($isHtml && \in_array(strtoupper($key), $this->unsafe_tags, true)) {
$value = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}

$text = str_replace('{' . strtoupper($key) . '}', $value, $text);
}
}
Expand Down
46 changes: 36 additions & 10 deletions libraries/src/Pagination/Pagination.php
Original file line number Diff line number Diff line change
Expand Up @@ -663,20 +663,44 @@ protected function _buildDataObject()
{
$data = new \stdClass();

// Build the additional URL parameters string.
$params = '';
// Platform defaults
$defaultUrlParams = [
'format' => 'WORD',
'option' => 'WORD',
'view' => 'WORD',
'layout' => 'WORD',
'tpl' => 'CMD',
'id' => 'INT',
'Itemid' => 'INT',
];

// Prepare the routes
$params = [];

// Use platform defaults if parameter doesn't already exist.
foreach ($defaultUrlParams as $param => $filter) {
$value = $this->app->input->get($param, null, $filter);

if ($value === null) {
continue;
}

$params[$param] = $value;
}

if (!empty($this->additionalUrlParams)) {
foreach ($this->additionalUrlParams as $key => $value) {
$params .= '&' . $key . '=' . $value;
$params[$key] = $value;
}
}

$params = http_build_query($params);

$data->all = new PaginationObject(Text::_('JLIB_HTML_VIEW_ALL'), $this->prefix);

if (!$this->viewall) {
$data->all->base = '0';
$data->all->link = Route::_($params . '&' . $this->prefix . 'limitstart=');
$data->all->link = Route::_('index.php?' . $params . '&' . $this->prefix . 'limitstart=');
}

// Set the start and previous data objects.
Expand All @@ -687,9 +711,9 @@ protected function _buildDataObject()
$page = ($this->pagesCurrent - 2) * $this->limit;

if ($this->hideEmptyLimitstart) {
$data->start->link = Route::_($params . '&' . $this->prefix . 'limitstart=');
$data->start->link = Route::_('index.php?' . $params . '&' . $this->prefix . 'limitstart=');
} else {
$data->start->link = Route::_($params . '&' . $this->prefix . 'limitstart=0');
$data->start->link = Route::_('index.php?' . $params . '&' . $this->prefix . 'limitstart=0');
}

$data->start->base = '0';
Expand All @@ -698,7 +722,7 @@ protected function _buildDataObject()
if ($page === 0 && $this->hideEmptyLimitstart) {
$data->previous->link = $data->start->link;
} else {
$data->previous->link = Route::_($params . '&' . $this->prefix . 'limitstart=' . $page);
$data->previous->link = Route::_('index.php?' . $params . '&' . $this->prefix . 'limitstart=' . $page);
}
}

Expand All @@ -711,9 +735,9 @@ protected function _buildDataObject()
$end = ($this->pagesTotal - 1) * $this->limit;

$data->next->base = $next;
$data->next->link = Route::_($params . '&' . $this->prefix . 'limitstart=' . $next);
$data->next->link = Route::_('index.php?' . $params . '&' . $this->prefix . 'limitstart=' . $next);
$data->end->base = $end;
$data->end->link = Route::_($params . '&' . $this->prefix . 'limitstart=' . $end);
$data->end->link = Route::_('index.php?' . $params . '&' . $this->prefix . 'limitstart=' . $end);
}

$data->pages = [];
Expand All @@ -730,7 +754,9 @@ protected function _buildDataObject()
if ($offset === 0 && $this->hideEmptyLimitstart) {
$data->pages[$i]->link = $data->start->link;
} else {
$data->pages[$i]->link = Route::_($params . '&' . $this->prefix . 'limitstart=' . $offset);
$data->pages[$i]->link = Route::_(
'index.php?' . $params . '&' . $this->prefix . 'limitstart=' . $offset
);
}
} else {
$data->pages[$i]->active = true;
Expand Down
4 changes: 2 additions & 2 deletions libraries/src/Uri/Uri.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,9 @@ public static function isInternal($url)
// @see UriTest
if (
empty($host) && strpos($uri->path, 'index.php') === 0
|| !empty($host) && preg_match('#' . preg_quote(static::base(), '#') . '#', $base)
|| !empty($host) && preg_match('#^' . preg_quote(static::base(), '#') . '#', $base)
|| !empty($host) && $host === static::getInstance(static::base())->host && strpos($uri->path, 'index.php') !== false
|| !empty($host) && $base === $host && preg_match('#' . preg_quote($base, '#') . '#', static::base())
|| !empty($host) && $base === $host && preg_match('#^' . preg_quote($base, '#') . '#', static::base())
) {
return true;
}
Expand Down
Loading

0 comments on commit bbfe0e0

Please sign in to comment.