On Sun, Jun 18, 2017 at 07:56:48PM +0200, Enrico Forestieri wrote: > On Sun, Jun 18, 2017 at 06:47:14PM +0200, Jürgen Spitzmüller wrote: > > > I don't know how the needauth thing works, but out "Do not ask again" > > mechanism is per-document on the given machine only. > > I already proposed this approach in another thread.
Here is a patch extended such that the status of the toolbar button is recorded in the document but always asks for permission, allowing to not be asked again for the current document on the current machine. This would be a format change, though. -- Enrico
diff --git a/lib/ui/stdtoolbars.inc b/lib/ui/stdtoolbars.inc index 9da37ecf75..794325665a 100644 --- a/lib/ui/stdtoolbars.inc +++ b/lib/ui/stdtoolbars.inc @@ -103,6 +103,7 @@ ToolbarSet Item "Update" "buffer-update" Item "View master document" "master-buffer-view" Item "Update master document" "master-buffer-update" + Item "Allow running external programs" "buffer-toggle-shell-escape" Item "Enable Forward/Reverse Search" "buffer-toggle-output-sync" Separator StickyPopupMenu "view-others" "View other formats" diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 61b89200c1..7329ffe3c2 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -2613,6 +2613,11 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag) break; } + case LFUN_BUFFER_TOGGLE_SHELL_ESCAPE: { + flag.setOnOff(params().shell_escape); + break; + } + case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC: { flag.setOnOff(params().output_sync); break; @@ -2888,6 +2893,11 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) params().compressed = !params().compressed; break; + case LFUN_BUFFER_TOGGLE_SHELL_ESCAPE: + undo().recordUndoBufferParams(CursorData()); + params().shell_escape = !params().shell_escape; + break; + case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC: undo().recordUndoBufferParams(CursorData()); params().output_sync = !params().output_sync; diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index 38ca643400..3d4b3dca3e 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -459,6 +459,7 @@ BufferParams::BufferParams() html_css_as_file = false; display_pixel_ratio = 1.0; + shell_escape = false; output_sync = false; use_refstyle = true; use_minted = false; @@ -1094,6 +1095,8 @@ string BufferParams::readToken(Lexer & lex, string const & token, } else if (token == "\\html_latex_end") { lex.eatLine(); html_latex_end = lex.getString(); + } else if (token == "\\shell_escape") { + lex >> shell_escape; } else if (token == "\\output_sync") { lex >> output_sync; } else if (token == "\\output_sync_macro") { @@ -1254,6 +1257,7 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n'; os << "\\graphics " << graphics_driver << '\n'; os << "\\default_output_format " << default_output_format << '\n'; + os << "\\shell_escape " << shell_escape << '\n'; os << "\\output_sync " << output_sync << '\n'; if (!output_sync_macro.empty()) os << "\\output_sync_macro \"" << output_sync_macro << "\"\n"; diff --git a/src/BufferParams.h b/src/BufferParams.h index 9f20ce14c6..aa33b9a61e 100644 --- a/src/BufferParams.h +++ b/src/BufferParams.h @@ -535,6 +535,8 @@ public: std::string html_latex_end; /// bool html_css_as_file; + /// allow the LaTeX backend to run external programs + bool shell_escape; /// generate output usable for reverse/forward search bool output_sync; /// custom LaTeX macro from user instead our own diff --git a/src/Converter.cpp b/src/Converter.cpp index 6e10b18704..00085692c6 100644 --- a/src/Converter.cpp +++ b/src/Converter.cpp @@ -279,20 +279,31 @@ OutputParams::FLAVOR Converters::getFlavor(Graph::EdgePath const & path, } -bool Converters::checkAuth(Converter const & conv, string const & doc_fname) +bool Converters::checkAuth(Converter const & conv, string const & doc_fname, + bool use_shell_escape) { - if (!conv.need_auth()) + if (!conv.latex()) + use_shell_escape = false; + if (!conv.need_auth() && !use_shell_escape) return true; - const docstring security_warning = bformat( + string conv_command = conv.command(); + bool const has_shell_escape = contains(conv_command, "-shell-escape"); + size_t const token_pos = conv_command.find("$$"); + bool const has_token = token_pos != string::npos; + string const command = use_shell_escape && !has_shell_escape + ? (has_token ? conv_command.insert(token_pos, "-shell-escape ") + : conv_command.append(" -shell-escape")) + : conv_command; + docstring const security_warning = bformat( _("<p>The requested operation requires the use of a converter from " "%2$s to %3$s:</p>" "<blockquote><p><tt>%1$s</tt></p></blockquote>" "<p>This external program can execute arbitrary commands on your " "system, including dangerous ones, if instructed to do so by a " "maliciously crafted .lyx document.</p>"), - from_utf8(conv.command()), from_utf8(conv.from()), + from_utf8(command), from_utf8(conv.from()), from_utf8(conv.to())); - if (lyxrc.use_converter_needauth_forbidden) { + if (lyxrc.use_converter_needauth_forbidden && !use_shell_escape) { frontend::Alert::error( _("An external converter is disabled for security reasons"), security_warning + _( @@ -302,7 +313,7 @@ bool Converters::checkAuth(Converter const & conv, string const & doc_fname) "Forbid needauth converters</i>.)"), false); return false; } - if (!lyxrc.use_converter_needauth) + if (!lyxrc.use_converter_needauth && !use_shell_escape) return true; static const docstring security_title = _("An external converter requires your authorization"); @@ -459,7 +470,8 @@ bool Converters::convert(Buffer const * buffer, "tmpfile.out")); } - if (!checkAuth(conv, buffer ? buffer->absFileName() : string())) + if (!checkAuth(conv, buffer ? buffer->absFileName() : string(), + buffer && buffer->params().shell_escape)) return false; if (conv.latex()) { @@ -470,6 +482,9 @@ bool Converters::convert(Buffer const * buffer, command = subst(command, token_from, ""); command = subst(command, token_latex_encoding, buffer->params().encoding().latexName()); + if (buffer->params().shell_escape + && !contains(command, "-shell-escape")) + command += " -shell-escape "; LYXERR(Debug::FILES, "Running " << command); if (!runLaTeX(*buffer, command, runparams, errorList)) return false; diff --git a/src/Converter.h b/src/Converter.h index 1ea73279b2..1963980c4f 100644 --- a/src/Converter.h +++ b/src/Converter.h @@ -193,8 +193,14 @@ public: /// 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); + /// is disabled; user is prompted otherwise. + /// However, if use_shell_escape is true and a LaTeX backend is + /// going to be executed, both lyxrc.use_converter_needauth and + /// lyxrc.use_converter_needauth_forbidden are ignored, because in + /// this case the backend has to be executed and LyX will add the + /// -shell-escape option, so that user consent is always needed. + bool checkAuth(Converter const & conv, std::string const & doc_fname, + bool use_shell_escape = false); private: /// diff --git a/src/FuncCode.h b/src/FuncCode.h index 7949bce41a..33249b4635 100644 --- a/src/FuncCode.h +++ b/src/FuncCode.h @@ -473,6 +473,8 @@ enum FuncCode LFUN_BUFFER_ZOOM, // daniel, 20161028 LFUN_TOOLBAR_MOVABLE, // daniel, 20160712 LFUN_FONT_CROSSOUT, // uwestoehr 20170404 + LFUN_BUFFER_TOGGLE_SHELL_ESCAPE,// ef 20170618 + // 370 LFUN_LASTACTION // end of the table }; diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index c068db9bea..2b8b6ecbb4 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -780,6 +780,17 @@ void LyXAction::init() { LFUN_BUFFER_TOGGLE_COMPRESSION, "buffer-toggle-compression", Noop, Buffer }, /*! + * \var lyx::FuncCode lyx::LFUN_BUFFER_TOGGLE_SHELL_ESCAPE + * \li Action: Toggles consent to run external programs by the LaTeX backend. + * \li Notion: When toggled on, the -shell-escape option is added to the + command that runs a LaTeX backend. + * \li Syntax: buffer-toggle-shell-escape + * \li Origin: ef, 18 June 2017 + * \endvar + */ + { LFUN_BUFFER_TOGGLE_SHELL_ESCAPE, "buffer-toggle-shell-escape", Noop, System }, + +/*! * \var lyx::FuncCode lyx::LFUN_BUFFER_TOGGLE_OUTPUT_SYNC * \li Action: Toggles including of resources for forward/reverse search of the given document. * \li Notion: When toggled on, SyncTeX is invoked for PDF, while srcltx package diff --git a/src/frontends/qt4/GuiDocument.cpp b/src/frontends/qt4/GuiDocument.cpp index 8d09e591a2..1390122611 100644 --- a/src/frontends/qt4/GuiDocument.cpp +++ b/src/frontends/qt4/GuiDocument.cpp @@ -792,6 +792,8 @@ GuiDocument::GuiDocument(GuiView & lv) connect(outputModule->mathoutCB, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor())); + connect(outputModule->shellescapeCB, SIGNAL(clicked()), + this, SLOT(change_adaptor())); connect(outputModule->outputsyncCB, SIGNAL(clicked()), this, SLOT(change_adaptor())); connect(outputModule->synccustomCB, SIGNAL(editTextChanged(QString)), @@ -3115,6 +3117,8 @@ void GuiDocument::applyView() bool const nontexfonts = fontModule->osFontsCB->isChecked(); bp_.useNonTeXFonts = nontexfonts; + bp_.shell_escape = outputModule->shellescapeCB->isChecked(); + bp_.output_sync = outputModule->outputsyncCB->isChecked(); bp_.output_sync_macro = fromqstr(outputModule->synccustomCB->currentText()); @@ -3733,6 +3737,7 @@ void GuiDocument::paramsToDialog() index = 0; outputModule->defaultFormatCO->setCurrentIndex(index); + outputModule->shellescapeCB->setChecked(bp_.shell_escape); outputModule->outputsyncCB->setChecked(bp_.output_sync); outputModule->synccustomCB->setEditText(toqstr(bp_.output_sync_macro)); diff --git a/src/frontends/qt4/ui/OutputUi.ui b/src/frontends/qt4/ui/OutputUi.ui index 2bcf0f15cb..e5157a1501 100644 --- a/src/frontends/qt4/ui/OutputUi.ui +++ b/src/frontends/qt4/ui/OutputUi.ui @@ -80,7 +80,7 @@ </layout> </widget> </item> - <item row="4" column="0"> + <item row="5" column="0"> <widget class="QGroupBox" name="savingGB"> <property name="title"> <string>LyX Format</string> @@ -106,6 +106,25 @@ </widget> </item> <item row="1" column="0"> + <widget class="QGroupBox" name="shellescapeCB"> + <property name="toolTip"> + <string>Calls the LaTeX backend with the -shell-escape option</string> + </property> + <property name="title"> + <string>&Allow running external programs</string> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="0"> <widget class="QGroupBox" name="outputsyncCB"> <property name="toolTip"> <string>Enable forward/reverse search between editor and output (e.g., SyncTeX)</string> @@ -150,7 +169,7 @@ </layout> </widget> </item> - <item row="2" column="0"> + <item row="3" column="0"> <widget class="QGroupBox" name="xhtmlGB"> <property name="title"> <string>XHTML Output Options</string> @@ -269,7 +288,7 @@ </layout> </widget> </item> - <item row="5" column="0"> + <item row="6" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum>