From bd0551b22076b82a6d49e9f7a2b2e0c90a1b2326 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Fri, 05 Feb 2016 07:25:27 -0500
Subject: [PATCH] Secure also downloads of addressbook exports, managesieve script exports and Enigma keys exports

---
 program/lib/Roundcube/rcube_message.php |  152 ++++++++++++++++++++++++++------------------------
 1 files changed, 80 insertions(+), 72 deletions(-)

diff --git a/program/lib/Roundcube/rcube_message.php b/program/lib/Roundcube/rcube_message.php
index cb958eb..d065ac3 100644
--- a/program/lib/Roundcube/rcube_message.php
+++ b/program/lib/Roundcube/rcube_message.php
@@ -69,26 +69,27 @@
      *
      * Provide a uid, and parse message structure.
      *
-     * @param string $uid    The message UID.
-     * @param string $folder Folder name
+     * @param string $uid     The message UID.
+     * @param string $folder  Folder name
+     * @param bool   $is_safe Security flag
      *
      * @see self::$app, self::$storage, self::$opt, self::$parts
      */
-    function __construct($uid, $folder = null)
+    function __construct($uid, $folder = null, $is_safe = false)
     {
         // decode combined UID-folder identifier
         if (preg_match('/^\d+-.+/', $uid)) {
             list($uid, $folder) = explode('-', $uid, 2);
         }
 
-        $this->uid  = $uid;
-        $this->app  = rcube::get_instance();
+        $this->uid     = $uid;
+        $this->app     = rcube::get_instance();
         $this->storage = $this->app->get_storage();
         $this->folder  = strlen($folder) ? $folder : $this->storage->get_folder();
-        $this->storage->set_options(array('all_headers' => true));
 
         // Set current folder
         $this->storage->set_folder($this->folder);
+        $this->storage->set_options(array('all_headers' => true));
 
         $this->headers = $this->storage->get_message($uid);
 
@@ -96,19 +97,19 @@
             return;
         }
 
-        $this->mime = new rcube_mime($this->headers->charset);
-
+        $this->mime    = new rcube_mime($this->headers->charset);
         $this->subject = $this->headers->get('subject');
         list(, $this->sender) = each($this->mime->decode_address_list($this->headers->from, 1));
 
-        $this->set_safe((intval($_GET['_safe']) || $_SESSION['safe_messages'][$this->folder.':'.$uid]));
+        $this->set_safe($is_safe || $_SESSION['safe_messages'][$this->folder.':'.$uid]);
         $this->opt = array(
             'safe'        => $this->is_safe,
             'prefer_html' => $this->app->config->get('prefer_html'),
             'get_url'     => $this->app->url(array(
                     'action' => 'get',
                     'mbox'   => $this->folder,
-                    'uid'    => $uid))
+                    'uid'    => $uid),
+                false, false, true)
         );
 
         if (!empty($this->headers->structure)) {
@@ -322,11 +323,12 @@
      * Determine if the message contains a HTML part. This must to be
      * a real part not an attachment (or its part)
      *
-     * @param bool $enriched Enables checking for text/enriched parts too
+     * @param bool               $enriched Enables checking for text/enriched parts too
+     * @param rcube_message_part &$part    Reference to the part if found
      *
      * @return bool True if a HTML is available, False if not
      */
-    function has_html_part($enriched = false)
+    public function has_html_part($enriched = false, &$part = null)
     {
         // check all message parts
         foreach ($this->mime_parts as $part) {
@@ -360,6 +362,8 @@
             }
         }
 
+        $part = null;
+
         return false;
     }
 
@@ -367,9 +371,11 @@
      * Determine if the message contains a text/plain part. This must to be
      * a real part not an attachment (or its part)
      *
+     * @param rcube_message_part &$part Reference to the part if found
+     *
      * @return bool True if a plain text part is available, False if not
      */
-    function has_text_part()
+    public function has_text_part(&$part = null)
     {
         // check all message parts
         foreach ($this->mime_parts as $part) {
@@ -399,52 +405,58 @@
             }
         }
 
+        $part = null;
+
         return false;
     }
 
     /**
      * Return the first HTML part of this message
      *
+     * @param rcube_message_part &$part    Reference to the part if found
+     * @param bool               $enriched Enables checking for text/enriched parts too
+     *
      * @return string HTML message part content
      */
-    function first_html_part()
+    public function first_html_part(&$part = null, $enriched = false)
     {
-        // check all message parts
-        foreach ($this->mime_parts as $pid => $part) {
-            if ($part->mimetype == 'text/html') {
-                return $this->get_part_body($pid, true);
+        if ($this->has_html_part($enriched, $part)) {
+            $body = $this->get_part_body($part->mime_id, true);
+
+            if ($part->mimetype == 'text/enriched') {
+                $body = rcube_enriched::to_html($body);
             }
+
+            return $body;
         }
     }
 
     /**
-     * Return the first text part of this message
+     * Return the first text part of this message.
+     * If there's no text/plain part but $strict=true and text/html part
+     * exists, it will be returned in text/plain format.
      *
-     * @param rcube_message_part $part Reference to the part if found
+     * @param rcube_message_part &$part  Reference to the part if found
+     * @param bool               $strict Check only text/plain parts
+     *
      * @return string Plain text message/part content
      */
-    function first_text_part(&$part=null)
+    public function first_text_part(&$part = null, $strict = false)
     {
         // no message structure, return complete body
-        if (empty($this->parts))
+        if (empty($this->parts)) {
             return $this->body;
-
-        // check all message parts
-        foreach ($this->mime_parts as $mime_id => $part) {
-            if ($part->mimetype == 'text/plain') {
-                return $this->get_part_body($mime_id, true);
-            }
-            else if ($part->mimetype == 'text/html') {
-                $out = $this->get_part_body($mime_id, true);
-
-                // create instance of html2text class
-                $txt = new rcube_html2text($out);
-                return $txt->get_text();
-            }
         }
 
-        $part = null;
-        return null;
+        if ($this->has_text_part($part)) {
+            return $this->get_part_body($part->mime_id, true);
+        }
+
+        if (!$strict && ($body = $this->first_html_part($part, true))) {
+            // create instance of html2text class
+            $h2t  = new rcube_html2text($body);
+            return $h2t->get_text();
+        }
     }
 
     /**
@@ -466,6 +478,28 @@
                 if (in_array($part, (array)$att_part->parts)) {
                     return true;
                 }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * In a multipart/encrypted encrypted message,
+     * find the encrypted message payload part.
+     *
+     * @return rcube_message_part
+     */
+    public function get_multipart_encrypted_part()
+    {
+        foreach ($this->mime_parts as $mime_id => $mpart) {
+            if ($mpart->mimetype == 'multipart/encrypted') {
+                $this->pgp_mime = true;
+            }
+            if ($this->pgp_mime && ($mpart->mimetype == 'application/octet-stream' ||
+                    (!empty($mpart->filename) && $mpart->filename != 'version.txt'))) {
+                $this->encrypted_part = $mime_id;
+                return $mpart;
             }
         }
 
@@ -663,24 +697,16 @@
                 $mail_part      = &$structure->parts[$i];
                 $primary_type   = $mail_part->ctype_primary;
                 $secondary_type = $mail_part->ctype_secondary;
+                $part_mimetype  = $mail_part->mimetype;
 
-                // real content-type of message/rfc822
-                if ($mail_part->real_mimetype) {
-                    $part_orig_mimetype = $mail_part->mimetype;
-                    $part_mimetype = $mail_part->real_mimetype;
-                    list($primary_type, $secondary_type) = explode('/', $part_mimetype);
-                }
-                else {
-                    $part_mimetype = $part_orig_mimetype = $mail_part->mimetype;
-                }
-
-                // multipart/alternative
-                if ($primary_type == 'multipart') {
+                // multipart/alternative or message/rfc822
+                if ($primary_type == 'multipart' || $part_mimetype == 'message/rfc822') {
                     $this->parse_structure($mail_part, true);
 
                     // list message/rfc822 as attachment as well (mostly .eml)
-                    if ($part_orig_mimetype == 'message/rfc822' && !empty($mail_part->filename))
+                    if ($primary_type == 'message' && !empty($mail_part->filename)) {
                         $this->attachments[] = $mail_part;
+                    }
                 }
                 // part text/[plain|html] or delivery status
                 else if ((($part_mimetype == 'text/plain' || $part_mimetype == 'text/html') && $mail_part->disposition != 'attachment') ||
@@ -691,8 +717,9 @@
                         array('object' => $this, 'structure' => $mail_part,
                             'mimetype' => $part_mimetype, 'recursive' => true));
 
-                    if ($plugin['abort'])
+                    if ($plugin['abort']) {
                         continue;
+                    }
 
                     if ($part_mimetype == 'text/html' && $mail_part->size) {
                         $this->got_html_part = true;
@@ -714,14 +741,6 @@
                     if (!empty($mail_part->filename)) {
                         $this->attachments[] = $mail_part;
                     }
-                }
-                // part message/*
-                else if ($primary_type == 'message') {
-                    $this->parse_structure($mail_part, true);
-
-                    // list as attachment as well (mostly .eml)
-                    if (!empty($mail_part->filename))
-                        $this->attachments[] = $mail_part;
                 }
                 // ignore "virtual" protocol parts
                 else if ($primary_type == 'protocol') {
@@ -753,21 +772,14 @@
 
                     // part belongs to a related message and is linked
                     if (preg_match('/^multipart\/(related|relative)/', $mimetype)
-                        && ($mail_part->headers['content-id'] || $mail_part->headers['content-location'])) {
+                        && ($mail_part->headers['content-id'] || $mail_part->headers['content-location'])
+                    ) {
                         if ($mail_part->headers['content-id'])
                             $mail_part->content_id = preg_replace(array('/^</', '/>$/'), '', $mail_part->headers['content-id']);
                         if ($mail_part->headers['content-location'])
                             $mail_part->content_location = $mail_part->headers['content-base'] . $mail_part->headers['content-location'];
 
                         $this->inline_parts[] = $mail_part;
-                    }
-                    // attachment encapsulated within message/rfc822 part needs further decoding (#1486743)
-                    else if ($part_orig_mimetype == 'message/rfc822') {
-                        $this->parse_structure($mail_part, true);
-
-                        // list as attachment as well (mostly .eml)
-                        if (!empty($mail_part->filename))
-                            $this->attachments[] = $mail_part;
                     }
                     // regular attachment with valid content type
                     // (content-type name regexp according to RFC4288.4.2)
@@ -783,10 +795,6 @@
 
                         $this->attachments[] = $mail_part;
                     }
-                }
-                // attachment part as message/rfc822 (#1488026)
-                else if ($mail_part->mimetype == 'message/rfc822') {
-                    $this->parse_structure($mail_part);
                 }
                 // calendar part not marked as attachment (#1490325)
                 else if ($part_mimetype == 'text/calendar') {

--
Gitblit v1.9.1