]> git.lyx.org Git - features.git/commitdiff
Add 'needauth' option to converters that need explicit user authorization.
authorTommaso Cucinotta <tommaso@lyx.org>
Sat, 5 Nov 2016 00:00:44 +0000 (01:00 +0100)
committerTommaso Cucinotta <tommaso@lyx.org>
Tue, 22 Nov 2016 22:54:58 +0000 (23:54 +0100)
Addressing #10481.

This patch adds the new 'needauth' option for converters launching
external programs that are capable of running arbitrary code on behalf
of the user. These converters won't be run unless the user gives explicit
authorization, which is asked on-demand when the converter is about to
be run (question is not asked if the file is cached and calling the
converter is not needed).

The user prompt has a 3rd button so that he/she's not prompted again
for (any converter over) the same document (identified through
buffer->absFileName()).

Two preference options are added:

lyxrc.use_converter_needauth_forbidden disables any converter with
the 'needauth' option, which is meant to force user to an explicit
action via the preferences pane, before being able to use advanced
converters that can potentially bring security threats;

lyxrc.use_converter_needauth enables prompting the user for 'needauth'
converters, or bypasses the check if not enabled, falling back to the
previous behavior.

So, the first option is for maximum security, the second is for
maximum usability.

24 files changed:
lib/configure.py
src/Buffer.cpp
src/Buffer.h
src/Converter.cpp
src/Converter.h
src/LyXRC.cpp
src/LyXRC.h
src/factory.cpp
src/frontends/qt4/GuiExternal.cpp
src/frontends/qt4/GuiPrefs.cpp
src/frontends/qt4/GuiPrefs.h
src/frontends/qt4/ui/PrefConvertersUi.ui
src/graphics/GraphicsCache.cpp
src/graphics/GraphicsCache.h
src/graphics/GraphicsCacheItem.cpp
src/graphics/GraphicsCacheItem.h
src/graphics/GraphicsConverter.cpp
src/graphics/GraphicsConverter.h
src/graphics/GraphicsLoader.cpp
src/graphics/GraphicsLoader.h
src/graphics/PreviewImage.cpp
src/graphics/PreviewImage.h
src/graphics/PreviewLoader.cpp
src/insets/RenderGraphic.cpp

index a11050fb915ae5d0fe6d0bf852f72c193c8032a2..b282a284eddce139ce25ee9493c5318a6c58fd88 100644 (file)
@@ -749,8 +749,8 @@ def checkConverterEntries():
         rc_entry = [r'''\converter latex      lyx        "%% -f $$i $$o"       ""
 \converter latexclipboard lyx        "%% -fixedenc utf8 -f $$i $$o"    ""
 \converter literate   lyx        "%% -n -m noweb -f $$i $$o"   ""
-\converter sweave   lyx        "%% -n -m sweave -f $$i $$o"    ""
-\converter knitr   lyx        "%% -n -m knitr -f $$i $$o"      ""'''], not_found = 'tex2lyx')
+\converter sweave   lyx        "%% -n -m sweave -f $$i $$o"    "needauth"
+\converter knitr   lyx        "%% -n -m knitr -f $$i $$o"      "needauth"'''], not_found = 'tex2lyx')
     if path == '':
         logger.warning("Failed to find tex2lyx on your system.")
 
@@ -763,24 +763,24 @@ def checkConverterEntries():
 \converter literate   dviluatex     "%%"       ""'''])
     #
     checkProg('a Sweave -> LaTeX converter', ['Rscript --verbose --no-save --no-restore $$s/scripts/lyxsweave.R $$p$$i $$p$$o $$e $$r'],
-        rc_entry = [r'''\converter sweave   latex      "%%"    ""
-\converter sweave   pdflatex   "%%"    ""
-\converter sweave   xetex      "%%"    ""
-\converter sweave   luatex     "%%"    ""
-\converter sweave   dviluatex  "%%"    ""'''])
+        rc_entry = [r'''\converter sweave   latex      "%%"    "needauth"
+\converter sweave   pdflatex   "%%"    "needauth"
+\converter sweave   xetex      "%%"    "needauth"
+\converter sweave   luatex     "%%"    "needauth"
+\converter sweave   dviluatex  "%%"    "needauth"'''])
     #
     checkProg('a knitr -> LaTeX converter', ['Rscript --verbose --no-save --no-restore $$s/scripts/lyxknitr.R $$p$$i $$p$$o $$e $$r'],
-        rc_entry = [r'''\converter knitr   latex      "%%"     ""
-\converter knitr   pdflatex   "%%"     ""
-\converter knitr   xetex      "%%"     ""
-\converter knitr   luatex     "%%"     ""
-\converter knitr   dviluatex  "%%"     ""'''])
+        rc_entry = [r'''\converter knitr   latex      "%%"     "needauth"
+\converter knitr   pdflatex   "%%"     "needauth"
+\converter knitr   xetex      "%%"     "needauth"
+\converter knitr   luatex     "%%"     "needauth"
+\converter knitr   dviluatex  "%%"     "needauth"'''])
     #
     checkProg('a Sweave -> R/S code converter', ['Rscript --verbose --no-save --no-restore $$s/scripts/lyxstangle.R $$i $$e $$r'], 
-        rc_entry = [ r'\converter sweave      r      "%%"    ""' ])
+        rc_entry = [ r'\converter sweave      r      "%%"    "needauth"' ])
     #
     checkProg('a knitr -> R/S code converter', ['Rscript --verbose --no-save --no-restore $$s/scripts/lyxknitr.R $$p$$i $$p$$o $$e $$r tangle'],
-        rc_entry = [ r'\converter knitr      r      "%%"    ""' ])
+        rc_entry = [ r'\converter knitr      r      "%%"    "needauth"' ])
     #
     checkProg('an HTML -> LaTeX converter', ['html2latex $$i', 'gnuhtml2latex',
         'htmltolatex -input $$i -output $$o', 'htmltolatex.jar -input $$i -output $$o'],
index 8efa53bb4c55af72628d5fefdc6204924b4ff522..4facf09479d4e33037a57f09737bfcedfe06db2b 100644 (file)
@@ -79,6 +79,7 @@
 #include "mathed/MathMacroTemplate.h"
 #include "mathed/MathSupport.h"
 
+#include "graphics/GraphicsCache.h"
 #include "graphics/PreviewLoader.h"
 
 #include "frontends/alert.h"
@@ -421,8 +422,8 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_,
          ignore_parent(false),  toc_backend(owner), macro_lock(false), timestamp_(0),
          checksum_(0), wa_(0),  gui_(0), undo_(*owner), bibinfo_cache_valid_(false),
          bibfile_cache_valid_(false), cite_labels_valid_(false), preview_error_(false),
-         inset(0), preview_loader_(0), cloned_buffer_(cloned_buffer), clone_list_(0),
-         doing_export(false), parent_buffer(0),
+         inset(0), preview_loader_(0), cloned_buffer_(cloned_buffer),
+         clone_list_(0), doing_export(false), parent_buffer(0),
          word_count_(0), char_count_(0), blank_count_(0)
 {
        if (!cloned_buffer_) {
index 477a8ac8adb55419abb3f89f4c40a5be068e9849..0cb70266374682815ac5f271ff957329c09e62d6 100644 (file)
@@ -74,6 +74,7 @@ class FileNameList;
 
 namespace graphics {
 class PreviewLoader;
+class Cache;
 }
 
 
@@ -587,6 +588,8 @@ public:
        void updatePreviews() const;
        /// Remove any previewed LaTeX snippets associated with this buffer
        void removePreviews() const;
+       ///
+       graphics::Cache & graphicsCache() const;
 
        /// Our main text (inside the top InsetText)
        Text & text() const;
index 58e486e67d3dde4b2fe6aad4de2ba1ca2a5f9a96..a2e5e9be4938d50760f818528af4a11c46d93fb6 100644 (file)
@@ -21,6 +21,7 @@
 #include "Format.h"
 #include "Language.h"
 #include "LaTeX.h"
+#include "LyXRC.h"
 #include "Mover.h"
 
 #include "frontends/alert.h"
@@ -100,7 +101,7 @@ Converter::Converter(string const & f, string const & t,
                     string const & c, string const & l)
        : from_(f), to_(t), command_(c), flags_(l),
          From_(0), To_(0), latex_(false), xml_(false),
-         need_aux_(false), nice_(false)
+         need_aux_(false), nice_(false), need_auth_(false)
 {}
 
 
@@ -128,6 +129,8 @@ void Converter::readFlags()
                        parselog_ = flag_value;
                else if (flag_name == "nice")
                        nice_ = true;
+               else if (flag_name == "needauth")
+                       need_auth_ = true;
        }
        if (!result_dir_.empty() && result_file_.empty())
                result_file_ = "index." + formats.extension(to_);
@@ -275,6 +278,49 @@ OutputParams::FLAVOR Converters::getFlavor(Graph::EdgePath const & path,
 }
 
 
+bool Converters::checkAuth(Converter const & conv, string const & doc_fname)
+{
+       if (!conv.need_auth())
+               return true;
+       if (lyxrc.use_converter_needauth_forbidden) {
+               frontend::Alert::warning(
+                       _("Potentially harmful external converters disabled"),
+                       _("Requested operation needs use of a potentially harmful external converter program,"
+                         "which is forbidden by default.\nThese converters are tagged by the 'needauth' option. "
+                         "In order to unlock execution of these converters,\nplease, go to "
+                         "Preferences->File Handling->Converters and uncheck "
+                         "Security->Forbid needauth converters."), true);
+               return false;
+       }
+       if (!lyxrc.use_converter_needauth)
+               return true;
+       static const docstring security_title = _("Launch of external converter needs user authorization");
+       static const char security_warning[] = "LyX is about to run converter '%1$s' which is launching an external program "
+               "that normally acts as a picture/format converter. However, this external program is known to be able to "
+               "execute arbitrary actions on the system on behalf of the user, including dangerous ones such as deleting "
+               "files, if instructed to do so by a maliciously crafted .lyx document.\n\nWould you like to run the converter?\n\n"
+               "ANSWER RUN ONLY IF YOU TRUST THE ORIGIN/SENDER OF THE LYX DOCUMENT!";
+       int choice;
+       if (!doc_fname.empty()) {
+               LYXERR(Debug::FILES, "looking up: " << doc_fname);
+               if (auth_files_.find(doc_fname) == auth_files_.end()) {
+                       choice = frontend::Alert::prompt(security_title,
+                               bformat(_(security_warning), from_utf8(conv.command())),
+                               0, 0, _("Do &NOT run"), _("&Run"), _("&Always run for this document"));
+                       if (choice == 2)
+                               auth_files_.insert(doc_fname);
+               } else {
+                       choice = 1;
+               }
+       } else {
+               choice = frontend::Alert::prompt(security_title,
+                       bformat(_(security_warning), from_utf8(conv.command())),
+                       0, 0, _("Do &NOT run"), _("&Run"));
+       }
+       return choice != 0;
+}
+
+
 bool Converters::convert(Buffer const * buffer,
                         FileName const & from_file, FileName const & to_file,
                         FileName const & orig_from,
@@ -402,6 +448,9 @@ bool Converters::convert(Buffer const * buffer,
                                                   "tmpfile.out"));
                }
 
+               if (!checkAuth(conv, buffer->absFileName()))
+                       return false;
+
                if (conv.latex()) {
                        run_latex = true;
                        string command = conv.command();
index c9c44238efb8b75ce2eff3f9c11a012c8fdd5029..10f88fec8837c37e8173ee39f47216601b39517f 100644 (file)
@@ -69,6 +69,8 @@ public:
        bool xml() const { return xml_; }
        ///
        bool need_aux() const { return need_aux_; }
+       /// Return whether or not the needauth option is set for this converter
+       bool need_auth() const { return need_auth_; }
        ///
        bool nice() const { return nice_; }
        ///
@@ -77,6 +79,7 @@ public:
        std::string const result_file() const { return result_file_; }
        ///
        std::string const parselog() const { return parselog_; }
+
 private:
        ///
        trivstring from_;
@@ -101,6 +104,8 @@ private:
        bool need_aux_;
        /// we need a "nice" file from the backend, c.f. OutputParams.nice.
        bool nice_;
+       /// Use of this converter needs explicit user authorization
+       bool need_auth_;
        /// If the converter put the result in a directory, then result_dir
        /// is the name of the directory
        trivstring result_dir_;
@@ -181,6 +186,16 @@ public:
        const_iterator end() const { return converterlist_.end(); }
        ///
        void buildGraph();
+
+       /// Check whether converter conv is authorized to be run for elements
+       /// within document doc_fname.
+       /// The check succeeds for safe converters, whilst for those potentially
+       /// able to execute arbitrary code, tagged with the 'needauth' option,
+       /// authorization is: always denied if lyxrc.use_converter_needauth_forbidden
+       /// is enabled; always allowed if the lyxrc.use_converter_needauth
+       /// is disabled; user is prompted otherwise
+       bool checkAuth(Converter const & conv, std::string const & doc_fname);
+
 private:
        ///
        FormatList const
@@ -210,6 +225,8 @@ private:
                  bool copy);
        ///
        Graph G_;
+       /// set of document files authorized for external conversion
+       std::set<std::string> auth_files_;
 };
 
 /// The global instance.
index fe3b0423480a1cbe1681b941111b1734531293fa..355e0651192bf8d3822ddb2a21130884b9093a75 100644 (file)
@@ -189,6 +189,8 @@ LexerKeyword lyxrcTags[] = {
        { "\\thesaurusdir_path", LyXRC::RC_THESAURUSDIRPATH },
        { "\\ui_file", LyXRC::RC_UIFILE },
        { "\\use_converter_cache", LyXRC::RC_USE_CONVERTER_CACHE },
+       { "\\use_converter_needauth", LyXRC::RC_USE_CONVERTER_NEEDAUTH },
+       { "\\use_converter_needauth_forbidden", LyXRC::RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN },
        { "\\use_lastfilepos", LyXRC::RC_USELASTFILEPOS },
        { "\\use_pixmap_cache", LyXRC::RC_USE_PIXMAP_CACHE },
        { "\\use_qimage", LyXRC::RC_USE_QIMAGE },
@@ -316,6 +318,8 @@ void LyXRC::setDefaults()
        preview_hashed_labels  = false;
        preview_scale_factor = 1.0;
        use_converter_cache = true;
+       use_converter_needauth_forbidden = true;
+       use_converter_needauth = true;
        use_system_colors = false;
        use_tooltip = true;
        use_pixmap_cache = false;
@@ -1112,6 +1116,12 @@ LyXRC::ReturnValues LyXRC::read(Lexer & lexrc, bool check_format)
                case RC_USE_CONVERTER_CACHE:
                        lexrc >> use_converter_cache;
                        break;
+               case RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN:
+                       lexrc >> use_converter_needauth_forbidden;
+                       break;
+               case RC_USE_CONVERTER_NEEDAUTH:
+                       lexrc >> use_converter_needauth;
+                       break;
                case RC_CONVERTER_CACHE_MAXAGE:
                        lexrc >> converter_cache_maxage;
                        break;
@@ -1593,6 +1603,24 @@ void LyXRC::write(ostream & os, bool ignore_system_lyxrc, string const & name) c
                if (tag != RC_LAST)
                        break;
 
+       case RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN:
+               if (ignore_system_lyxrc ||
+                   use_converter_needauth_forbidden != system_lyxrc.use_converter_needauth_forbidden) {
+                       os << "\\use_converter_needauth_forbidden "
+                          << convert<string>(use_converter_needauth_forbidden) << '\n';
+               }
+               if (tag != RC_LAST)
+                       break;
+
+       case RC_USE_CONVERTER_NEEDAUTH:
+               if (ignore_system_lyxrc ||
+                   use_converter_needauth != system_lyxrc.use_converter_needauth) {
+                       os << "\\use_converter_needauth "
+                          << convert<string>(use_converter_needauth) << '\n';
+               }
+               if (tag != RC_LAST)
+                       break;
+
        case RC_CONVERTER_CACHE_MAXAGE:
                if (ignore_system_lyxrc ||
                    converter_cache_maxage != system_lyxrc.converter_cache_maxage) {
@@ -2833,6 +2861,8 @@ void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
        case LyXRC::RC_USER_EMAIL:
        case LyXRC::RC_USER_NAME:
        case LyXRC::RC_USE_CONVERTER_CACHE:
+       case LyXRC::RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN:
+       case LyXRC::RC_USE_CONVERTER_NEEDAUTH:
        case LyXRC::RC_USE_SYSTEM_COLORS:
        case LyXRC::RC_USE_TOOLTIP:
        case LyXRC::RC_USE_PIXMAP_CACHE:
@@ -2925,6 +2955,14 @@ string const LyXRC::getDescription(LyXRCTags tag)
        case RC_CONVERTER:
                break;
 
+       case RC_CONVERTER_NEEDAUTH_FORBIDDEN:
+               str = _("Forbid use of external converters with 'needauth' option to prevent undesired effects.");
+               break;
+
+       case RC_CONVERTER_NEEDAUTH:
+               str = _("Ask user before calling external converters with 'needauth' option to prevent undesired effects.");
+               break;
+
        case RC_COPIER:
                break;
 
index 7b50ce0a56e9b218cee1ee9304c43207798bacbe..010e957153ef06a4a8a0ee3ac99c17cb64dca051 100644 (file)
@@ -167,6 +167,8 @@ public:
                RC_USER_EMAIL,
                RC_USER_NAME,
                RC_USE_CONVERTER_CACHE,
+               RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN,
+               RC_USE_CONVERTER_NEEDAUTH,
                RC_USE_SYSTEM_COLORS,
                RC_USE_TOOLTIP,
                RC_USE_PIXMAP_CACHE,
@@ -443,6 +445,12 @@ public:
        std::string texinputs_prefix;
        /// Use the cache for file converters?
        bool use_converter_cache;
+       /// Forbid use of external converters with 'needauth' option
+       bool use_converter_needauth_forbidden;
+       /// Ask user before calling external converters with 'needauth' option
+       bool use_converter_needauth;
+       /// Apply hardening when calling external converters
+       bool use_converter_wrappers;
        /// The maximum age of cache files in seconds
        unsigned int converter_cache_maxage;
        /// Sort layouts alphabetically
index a03f88fa2838900d71da17959df81bcd4d2afc1d..9fdc37da625b8432861c2ce93b19c0d926762c2d 100644 (file)
@@ -591,7 +591,7 @@ Inset * readInset(Lexer & lex, Buffer * buf)
                                return 0;
                }
                inset->setBuffer(*buf);
-       } else { 
+       } else {
                // FIXME This branch should be made to use inset codes
                // as the preceding branch does. Unfortunately, that
                // will take some doing. It requires converting the
index 2e7b6f633c91f3b73d030b3efa6594cbb24ed54e..e031f53eb1760fbbfc68e3ba8aa8bbc4fb0150d9 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "GuiExternal.h"
 
+#include "Buffer.h"
 #include "FuncRequest.h"
 #include "support/gettext.h"
 #include "Length.h"
index dd59dbfe64f822f214ec8c74682cc81f7c627a8f..ee43b4fdabd6ed32597ab01462b6ef8b4b3e8613 100644 (file)
@@ -1610,6 +1610,10 @@ PrefConverters::PrefConverters(GuiPreferences * form)
                this, SIGNAL(changed()));
        connect(maxAgeLE, SIGNAL(textEdited(QString)),
                this, SIGNAL(changed()));
+       connect(needauthForbiddenCB, SIGNAL(toggled(bool)),
+               this, SIGNAL(changed()));
+       connect(needauthCB, SIGNAL(toggled(bool)),
+               this, SIGNAL(changed()));
 
        converterED->setValidator(new NoNewLineValidator(converterED));
        converterFlagED->setValidator(new NoNewLineValidator(converterFlagED));
@@ -1621,6 +1625,8 @@ PrefConverters::PrefConverters(GuiPreferences * form)
 void PrefConverters::applyRC(LyXRC & rc) const
 {
        rc.use_converter_cache = cacheCB->isChecked();
+       rc.use_converter_needauth_forbidden = needauthForbiddenCB->isChecked();
+       rc.use_converter_needauth = needauthCB->isChecked();
        rc.converter_cache_maxage = int(widgetToDouble(maxAgeLE) * 86400.0);
 }
 
@@ -1628,6 +1634,8 @@ void PrefConverters::applyRC(LyXRC & rc) const
 void PrefConverters::updateRC(LyXRC const & rc)
 {
        cacheCB->setChecked(rc.use_converter_cache);
+       needauthForbiddenCB->setChecked(rc.use_converter_needauth_forbidden);
+       needauthCB->setChecked(rc.use_converter_needauth);
        QString max_age;
        doubleToWidget(maxAgeLE, (double(rc.converter_cache_maxage) / 86400.0), 'g', 6);
        updateGui();
@@ -1788,6 +1796,12 @@ void PrefConverters::on_cacheCB_stateChanged(int state)
 }
 
 
+void PrefConverters::on_needauthForbiddenCB_toggled(bool checked)
+{
+       needauthCB->setEnabled(!checked);
+}
+
+
 /////////////////////////////////////////////////////////////////////
 //
 // FormatValidator
index 1b37b323e3d01d57176709c653a1b389239f1818..612ffe6bd472c98420b41f0cfa2188c1d510fa90 100644 (file)
@@ -334,6 +334,7 @@ private Q_SLOTS:
        void removeConverter();
        void changeConverter();
        void on_cacheCB_stateChanged(int state);
+       void on_needauthForbiddenCB_toggled(bool);
 
 private:
        void updateButtons();
index 3fe6b9b8ce6d41f9fcf3f4e3de5fb4d1f4c10525..7e4a1b3244c392ed5a69ff00ce031db10b831051 100644 (file)
      </layout>
     </widget>
    </item>
+   <item row="2" column="0" >
+    <widget class="QGroupBox" name="securityGB" >
+     <property name="title" >
+      <string>Security</string>
+     </property>
+     <layout class="QGridLayout" >
+      <property name="margin" >
+       <number>9</number>
+      </property>
+      <property name="spacing" >
+       <number>6</number>
+      </property>
+      <item row="0" column="0" >
+       <layout class="QHBoxLayout" >
+        <property name="margin" >
+         <number>0</number>
+        </property>
+        <property name="spacing" >
+         <number>6</number>
+        </property>
+        <item>
+         <widget class="QCheckBox" name="needauthForbiddenCB" >
+          <property name="text" >
+           <string>&amp;Forbid use of needauth converters</string>
+          </property>
+          <property name="toolTip">
+           <string>When enabled, use of converters with the 'needauth' option is forbidden.</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QCheckBox" name="needauthCB" >
+          <property name="text" >
+           <string>Use need&amp;auth option</string>
+          </property>
+          <property name="toolTip">
+           <string>When enabled, ask user before launching any external converter with the 'needauth' option.</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
   </layout>
  </widget>
  <tabstops>
index a51f2322fd6b112bcab0f68f33b8c9a0ea62cebd..a3b8ebd3a9e835fbb106ba26586211532f0c057f 100644 (file)
@@ -101,7 +101,7 @@ vector<string> const & Cache::loadableFormats() const
 }
 
 
-void Cache::add(FileName const & file) const
+void Cache::add(FileName const & file, FileName const & doc_file) const
 {
        // Is the file in the cache already?
        if (inCache(file)) {
@@ -110,7 +110,7 @@ void Cache::add(FileName const & file) const
                return;
        }
 
-       pimpl_->cache[file] = ItemPtr(new CacheItem(file));
+       pimpl_->cache[file] = ItemPtr(new CacheItem(file, doc_file));
 }
 
 
index 66cfc85bf6e490160b1b91886b80425fd2781cd2..0fd1dd0102a1945eb990c32140f79d7a4c2a2018 100644 (file)
@@ -46,7 +46,7 @@ public:
        std::vector<std::string> const & loadableFormats() const;
 
        /// Add a graphics file to the cache.
-       void add(support::FileName const & file) const;
+       void add(support::FileName const & file, support::FileName const & doc_file) const;
 
        /// Remove a file from the cache.
        void remove(support::FileName const & file) const;
index ea59173eff79bc93588ed18373b7c167965f4a68..c698168dee0c22a67e47eb7528e07b0f02d9a12f 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "GraphicsCacheItem.h"
 
+#include "Buffer.h"
 #include "GraphicsCache.h"
 #include "GraphicsConverter.h"
 #include "GraphicsImage.h"
@@ -42,7 +43,7 @@ class CacheItem::Impl : public boost::signals2::trackable {
 public:
 
        ///
-       Impl(FileName const & file);
+       Impl(FileName const & file, FileName const & doc_file);
 
        /**
         *  If no file conversion is needed, then tryDisplayFormat() calls
@@ -93,6 +94,8 @@ public:
 
        /// The filename we refer too.
        FileName const filename_;
+       /// The document filename this graphic item belongs to
+       FileName const & doc_file_;
        ///
        FileMonitor const monitor_;
 
@@ -125,8 +128,8 @@ public:
 };
 
 
-CacheItem::CacheItem(FileName const & file)
-       : pimpl_(new Impl(file))
+CacheItem::CacheItem(FileName const & file, FileName const & doc_file)
+  : pimpl_(new Impl(file,doc_file))
 {}
 
 
@@ -204,8 +207,8 @@ boost::signals2::connection CacheItem::connect(slot_type const & slot) const
 //------------------------------
 
 
-CacheItem::Impl::Impl(FileName const & file)
-       : filename_(file),
+CacheItem::Impl::Impl(FileName const & file, FileName const & doc_file)
+       : filename_(file), doc_file_(doc_file),
          monitor_(file, 2000),
          zipped_(false),
          remove_loaded_file_(false),
@@ -312,11 +315,10 @@ bool CacheItem::Impl::loadImage()
 }
 
 
-static string const findTargetFormat(string const & from)
-{
-       typedef vector<string> FormatList;
-       FormatList const & formats = Cache::get().loadableFormats();
+typedef vector<string> FormatList;
 
+static string const findTargetFormat(FormatList const & formats, string const & from)
+{
         // There must be a format to load from.
        LASSERT(!formats.empty(), return string());
 
@@ -392,7 +394,7 @@ bool CacheItem::Impl::tryDisplayFormat(FileName & filename, string & from)
                LYXERR(Debug::GRAPHICS, "\tCould not determine file format.");
        }
        LYXERR(Debug::GRAPHICS, "\n\tThe file contains " << from << " format data.");
-       to_ = findTargetFormat(from);
+       to_ = findTargetFormat(Cache::get().loadableFormats(), from);
 
        if (from == to_) {
                // No conversion needed!
@@ -438,7 +440,7 @@ void CacheItem::Impl::convertToDisplayFormat()
        // Connect a signal to this->imageConverted and pass this signal to
        // the graphics converter so that we can load the modified file
        // on completion of the conversion process.
-       converter_ = make_unique<Converter>(filename, to_file_base.absFileName(),
+       converter_ = make_unique<Converter>(doc_file_, filename, to_file_base.absFileName(),
                                            from, to_);
        converter_->connect(bind(&Impl::imageConverted, this, _1));
        converter_->startConversion();
index 289b827a4fff15f5049d232e6b278a2d2bbbaa32..ee2348d8fc49b11485a7e9761aca66469f3d0fb7 100644 (file)
@@ -46,7 +46,7 @@ class Converter;
 class CacheItem {
 public:
        ///
-       CacheItem(support::FileName const & file);
+       CacheItem(support::FileName const & file, support::FileName const & doc_file);
        /// Needed for the pimpl
        ~CacheItem();
 
index 67b1580fd93bdc74de103d02a613e7269c8ab78c..55ae24624b0992334b4623a6f9495b04bfb68b7b 100644 (file)
 
 #include "GraphicsConverter.h"
 
+#include "Buffer.h"
 #include "Converter.h"
 #include "Format.h"
+#include "LyXRC.h"
 
+#include "frontends/alert.h"
 #include "support/lassert.h"
 #include "support/convert.h"
 #include "support/debug.h"
@@ -40,7 +43,7 @@ namespace graphics {
 class Converter::Impl : public boost::signals2::trackable {
 public:
        ///
-       Impl(FileName const &, string const &, string const &, string const &);
+       Impl(FileName const &, FileName const &, string const &, string const &, string const &);
 
        ///
        void startConversion();
@@ -59,6 +62,8 @@ public:
        ///
        SignalType finishedConversion;
 
+       ///
+       FileName const & doc_fname_;
        ///
        string script_command_;
        ///
@@ -79,9 +84,10 @@ bool Converter::isReachable(string const & from_format_name,
 }
 
 
-Converter::Converter(FileName const & from_file, string const & to_file_base,
+Converter::Converter(FileName const & doc_fname,
+                    FileName const & from_file, string const & to_file_base,
                     string const & from_format, string const & to_format)
-       : pimpl_(new Impl(from_file, to_file_base, from_format, to_format))
+       : pimpl_(new Impl(doc_fname, from_file, to_file_base, from_format, to_format))
 {}
 
 
@@ -112,17 +118,20 @@ FileName const & Converter::convertedFile() const
 /** Build the conversion script.
  *  The script is output to the stream \p script.
  */
-static void build_script(string const & from_file, string const & to_file_base,
+static void build_script(string const & doc_fname,
+                 string const & from_file, string const & to_file_base,
                  string const & from_format, string const & to_format,
                  ostream & script);
 
 
-Converter::Impl::Impl(FileName const & from_file, string const & to_file_base,
+Converter::Impl::Impl(FileName const & doc_fname,
+                     FileName const & from_file, string const & to_file_base,
                      string const & from_format, string const & to_format)
-       : valid_process_(false), finished_(false)
+       : doc_fname_(doc_fname), valid_process_(false), finished_(false)
 {
        LYXERR(Debug::GRAPHICS, "Converter c-tor:\n"
-               << "\tfrom_file:      " << from_file
+               << "doc_fname:        " << doc_fname
+               << "\n\tfrom_file:    " << from_file
                << "\n\tto_file_base: " << to_file_base
                << "\n\tfrom_format:  " << from_format
                << "\n\tto_format:    " << to_format);
@@ -134,7 +143,7 @@ Converter::Impl::Impl(FileName const & from_file, string const & to_file_base,
 
        // The conversion commands are stored in a stringstream
        ostringstream script;
-       build_script(from_file.toFilesystemEncoding(),
+       build_script(doc_fname_.absFileName(), from_file.toFilesystemEncoding(),
                     to_file_.toFilesystemEncoding(),
                     from_format, to_format, script);
        LYXERR(Debug::GRAPHICS, "\tConversion script:"
@@ -263,7 +272,8 @@ static string const strip_digit(string const & format)
 }
 
 
-static void build_script(string const & from_file,
+static void build_script(string const & doc_fname,
+                 string const & from_file,
                  string const & to_file,
                  string const & from_format,
                  string const & to_format,
@@ -372,6 +382,9 @@ static void build_script(string const & from_file,
                        outfile = tempfile.name().toFilesystemEncoding();
                }
 
+               if (!theConverters().checkAuth(conv, doc_fname))
+                       return;
+
                // Store these names in the python script
                script << "infile = "
                                << quoteName(infile, quote_python) << "\n"
index 2bd0003790abee7a3950a4a0441c234737f08da9..d3d0b8155daf26fcc56329ec50fdb1480f574f9e 100644 (file)
@@ -34,7 +34,8 @@ public:
        /** One Converter per conversion ensures that the (hidden) signal
         *  is always connected to the expected slot.
         */
-       Converter(support::FileName const & from_file, std::string const & to_file_base,
+       Converter(support::FileName const & doc_fname,
+                 support::FileName const & from_file, std::string const & to_file_base,
                  std::string const & from_format, std::string const & to_format);
 
        /// Needed for the pimpl
index 36a6c06d2c12748f2f834612d756c313e984b55d..987a973139088f5a6e763d7fc1e0297fb9957640 100644 (file)
@@ -18,6 +18,7 @@
 #include "GraphicsCache.h"
 
 #include "support/debug.h"
+#include "support/lassert.h"
 #include "support/Timeout.h"
 
 #include "support/bind.h"
@@ -30,6 +31,7 @@ using namespace std;
 using namespace lyx::support;
 
 namespace lyx {
+
 namespace graphics {
 
 
@@ -162,9 +164,10 @@ void LoaderQueue::touch(Cache::ItemPtr const & item)
 typedef std::shared_ptr<Image> ImagePtr;
 
 class Loader::Impl : public boost::signals2::trackable {
+       friend class Loader;
 public:
        ///
-       Impl();
+       Impl(FileName const & doc_file);
        ///
        ~Impl();
        ///
@@ -178,6 +181,8 @@ public:
        ///
        Params const & params() const { return params_; }
 
+       ///
+       FileName doc_file_;
        /// The loading status of the image.
        ImageStatus status_;
        /** Must store a copy of the cached item to ensure that it is not
@@ -211,27 +216,35 @@ private:
 };
 
 
-Loader::Loader()
-       : pimpl_(new Impl)
+Loader::Loader(FileName const & doc_file)
+       : pimpl_(new Impl(doc_file))
 {}
 
 
-Loader::Loader(FileName const & file, bool display)
-       : pimpl_(new Impl)
+Loader::Loader(FileName const & doc_file, FileName const & file, bool display)
+       : pimpl_(new Impl(doc_file))
 {
        reset(file, display);
 }
 
 
-Loader::Loader(FileName const & file, Params const & params)
-       : pimpl_(new Impl)
+Loader::Loader(FileName const & doc_file, FileName const & file, Params const & params)
+       : pimpl_(new Impl(doc_file))
 {
        reset(file, params);
 }
 
 
+Loader::Loader(FileName const & doc_file, Loader const & other)
+       : pimpl_(new Impl(doc_file))
+{
+       Params const & params = other.pimpl_->params();
+       reset(params.filename, params);
+}
+
+
 Loader::Loader(Loader const & other)
-       : pimpl_(new Impl)
+       : pimpl_(new Impl(other.pimpl_->doc_file_))
 {
        Params const & params = other.pimpl_->params();
        reset(params.filename, params);
@@ -246,7 +259,10 @@ Loader::~Loader()
 
 Loader & Loader::operator=(Loader const & other)
 {
+  LASSERT(false, /**/);
        if (this != &other) {
+               delete pimpl_;
+               pimpl_ = new Impl(other.pimpl_->doc_file_);
                Params const & params = other.pimpl_->params();
                reset(params.filename, params);
        }
@@ -359,8 +375,8 @@ Image const * Loader::image() const
 }
 
 
-Loader::Impl::Impl()
-       : status_(WaitingToLoad)
+Loader::Impl::Impl(FileName const & doc_file)
+       : doc_file_(doc_file), status_(WaitingToLoad)
 {
 }
 
@@ -404,7 +420,7 @@ void Loader::Impl::resetFile(FileName const & file)
 
        Cache & gc = Cache::get();
        if (!gc.inCache(file))
-               gc.add(file);
+               gc.add(file, doc_file_);
 
        // We /must/ make a local copy of this.
        cached_item_ = gc.item(file);
index a90bd9696357f6f37d69366322cac949652a35c7..8b97114f60f2a32864a362aeae6c4fca590b0f0f 100644 (file)
@@ -40,13 +40,15 @@ class Params;
 class Loader {
 public:
        /// Must use the reset methods to make this instance usable.
-       Loader();
+       Loader(support::FileName const & doc_file);
        /// The image is not transformed, just displayed as-is.
-       Loader(support::FileName const & file_with_path, bool display = true);
+       Loader(support::FileName const & doc_file, support::FileName const & file_with_path, bool display = true);
        /// The image is transformed before display.
-       Loader(support::FileName const & file_with_path, Params const &);
+       Loader(support::FileName const & doc_file, support::FileName const & file_with_path, Params const &);
        ///
-       Loader(Loader const &);
+       Loader(support::FileName const & doc_file, Loader const &);
+       ///
+       Loader(Loader const & other);
        /// Needed for the pimpl
        ~Loader();
 
@@ -108,7 +110,7 @@ private:
        /// Use the Pimpl idiom to hide the internals.
        class Impl;
        /// The pointer never changes although *pimpl_'s contents may.
-       Impl * const pimpl_;
+       Impl * pimpl_;
 };
 
 } // namespace graphics
index 80e8e2013513575cc8dfc500a7d9f554d70c10b7..da0f1e21ceeb942207dd91152c937ef70a6d10a0 100644 (file)
@@ -99,11 +99,17 @@ Image const * PreviewImage::image() const
 }
 
 
+PreviewLoader & PreviewImage::previewLoader() const
+{
+       return pimpl_->ploader_;
+}
+
+
 PreviewImage::Impl::Impl(PreviewImage & p, PreviewLoader & l,
                         string const & s,
                         FileName const & bf,
                         double af)
-       : parent_(p), ploader_(l), iloader_(bf),
+       : parent_(p), ploader_(l), iloader_(l.buffer().fileName(), bf),
          snippet_(s), ascent_frac_(af)
 {
        iloader_.setDisplayPixelRatio(l.displayPixelRatio());
index 04f1338e1080befd50f7f34af003e1a434e751c3..6b5ac7e66cd1d1e0495a0b84a5aa37570fa7adfd 100644 (file)
@@ -22,6 +22,7 @@ class Dimension;
 
 namespace graphics {
 
+class Cache;
 class PreviewLoader;
 class Image;
 
@@ -49,6 +50,8 @@ public:
        ///
        support::FileName const & filename() const;
 
+       PreviewLoader & previewLoader() const;
+
 private:
        /// Use the Pimpl idiom to hide the internals.
        class Impl;
index e1a47e84390a014880d69b23b41c917eb6c9b473..df025e41534b88d40226d47954988dd9e89918b6 100644 (file)
@@ -74,36 +74,6 @@ FileName const unique_tex_filename(FileName const & bufferpath)
 }
 
 
-lyx::Converter const * setConverter(string const & from)
-{
-       typedef vector<string> FmtList;
-       typedef lyx::graphics::Cache GCache;
-       FmtList const & loadableFormats = GCache::get().loadableFormats();
-       FmtList::const_iterator it = loadableFormats.begin();
-       FmtList::const_iterator const end = loadableFormats.end();
-
-       for (; it != end; ++it) {
-               string const to = *it;
-               if (from == to)
-                       continue;
-
-               lyx::Converter const * ptr = lyx::theConverters().getConverter(from, to);
-               if (ptr)
-                       return ptr;
-       }
-
-       // Show the error only once. This is thread-safe.
-       static nullptr_t no_conv = [&]{
-               LYXERR0("PreviewLoader::startLoading()\n"
-                       << "No converter from \"" << from
-                       << "\" format has been defined.");
-               return nullptr;
-       } ();
-
-       return no_conv;
-}
-
-
 void setAscentFractions(vector<double> & ascent_fractions,
                        FileName const & metrics_file)
 {
@@ -223,6 +193,8 @@ public:
 
        Buffer const & buffer() const { return buffer_; }
 
+       lyx::Converter const * setConverter(string const & from);
+
 private:
        /// Called by the ForkedCall process that generated the bitmap files.
        void finishedGenerating(pid_t, int);
@@ -433,6 +405,35 @@ PreviewLoader::Impl::Impl(PreviewLoader & p, Buffer const & b)
 }
 
 
+lyx::Converter const * PreviewLoader::Impl::setConverter(string const & from)
+{
+       typedef vector<string> FmtList;
+       FmtList const & loadableFormats = graphics::Cache::get().loadableFormats();
+       FmtList::const_iterator it = loadableFormats.begin();
+       FmtList::const_iterator const end = loadableFormats.end();
+
+       for (; it != end; ++it) {
+               string const to = *it;
+               if (from == to)
+                       continue;
+
+               lyx::Converter const * ptr = lyx::theConverters().getConverter(from, to);
+               if (ptr)
+                       return ptr;
+       }
+
+       // Show the error only once. This is thread-safe.
+       static nullptr_t no_conv = [&]{
+               LYXERR0("PreviewLoader::startLoading()\n"
+                       << "No converter from \"" << from
+                       << "\" format has been defined.");
+               return nullptr;
+       } ();
+
+       return no_conv;
+}
+
+
 PreviewLoader::Impl::~Impl()
 {
        delete delay_refresh_;
index 9d9cf31789aeb955d88edc6ac24dc790ee1166ba..7ab14cb63f6fdb5deacc913d83b5c212a944118c 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "insets/Inset.h"
 
+#include "Buffer.h"
 #include "LyX.h"
 #include "LyXRC.h"
 #include "MetricsInfo.h"
@@ -35,6 +36,7 @@ namespace lyx {
 
 
 RenderGraphic::RenderGraphic(Inset const * inset)
+       : loader_(inset->buffer().fileName())
 {
        loader_.connect(bind(&Inset::updateFrontend, inset));
 }