fix: unescape exec before pass this arg to wordexp
Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
		@ -9,6 +9,7 @@
 | 
				
			|||||||
#include "propertiesForwarder.h"
 | 
					#include "propertiesForwarder.h"
 | 
				
			||||||
#include "dbus/instanceadaptor.h"
 | 
					#include "dbus/instanceadaptor.h"
 | 
				
			||||||
#include "launchoptions.h"
 | 
					#include "launchoptions.h"
 | 
				
			||||||
 | 
					#include "desktopentry.h"
 | 
				
			||||||
#include <QUuid>
 | 
					#include <QUuid>
 | 
				
			||||||
#include <QStringList>
 | 
					#include <QStringList>
 | 
				
			||||||
#include <QList>
 | 
					#include <QList>
 | 
				
			||||||
@ -197,7 +198,8 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL
 | 
				
			|||||||
            sendErrorReply(QDBusError::Failed, msg);
 | 
					            sendErrorReply(QDBusError::Failed, msg);
 | 
				
			||||||
            return {};
 | 
					            return {};
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        execStr = toString(Actions.value());
 | 
					
 | 
				
			||||||
 | 
					        execStr = Actions.value().toString();
 | 
				
			||||||
        if (execStr.isEmpty()) {
 | 
					        if (execStr.isEmpty()) {
 | 
				
			||||||
            QString msg{"maybe entry actions's format is invalid, abort launch."};
 | 
					            QString msg{"maybe entry actions's format is invalid, abort launch."};
 | 
				
			||||||
            qWarning() << msg;
 | 
					            qWarning() << msg;
 | 
				
			||||||
@ -733,13 +735,21 @@ void ApplicationService::resetEntry(DesktopEntry *newEntry) noexcept
 | 
				
			|||||||
    emit scaleFactorChanged();
 | 
					    emit scaleFactorChanged();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringList &fields)
 | 
					QStringList ApplicationService::unescapeExecArgs(const QString &str) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    LaunchTask task;
 | 
					    auto unescapedStr = unescape(str, true);
 | 
				
			||||||
    auto deleter = [](wordexp_t *word) { wordfree(word); };
 | 
					    if (unescapedStr.isEmpty()) {
 | 
				
			||||||
 | 
					        qWarning() << "unescape Exec failed.";
 | 
				
			||||||
 | 
					        return {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto deleter = [](wordexp_t *word) {
 | 
				
			||||||
 | 
					        wordfree(word);
 | 
				
			||||||
 | 
					        delete word;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    std::unique_ptr<wordexp_t, decltype(deleter)> words{new (std::nothrow) wordexp_t{0, nullptr, 0}, deleter};
 | 
					    std::unique_ptr<wordexp_t, decltype(deleter)> words{new (std::nothrow) wordexp_t{0, nullptr, 0}, deleter};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (auto ret = wordexp(str.toLocal8Bit().constData(), words.get(), WRDE_SHOWERR); ret != 0) {
 | 
					    if (auto ret = wordexp(unescapedStr.toLocal8Bit(), words.get(), WRDE_SHOWERR); ret != 0) {
 | 
				
			||||||
        if (ret != 0) {
 | 
					        if (ret != 0) {
 | 
				
			||||||
            QString errMessage;
 | 
					            QString errMessage;
 | 
				
			||||||
            switch (ret) {
 | 
					            switch (ret) {
 | 
				
			||||||
@ -771,6 +781,14 @@ LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringLis
 | 
				
			|||||||
    for (int i = 0; i < words->we_wordc; ++i) {
 | 
					    for (int i = 0; i < words->we_wordc; ++i) {
 | 
				
			||||||
        execList.emplace_back(words->we_wordv[i]);
 | 
					        execList.emplace_back(words->we_wordv[i]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return execList;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringList &fields) noexcept
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    LaunchTask task;
 | 
				
			||||||
 | 
					    auto execList = unescapeExecArgs(str);
 | 
				
			||||||
    task.LaunchBin = execList.first();
 | 
					    task.LaunchBin = execList.first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QRegularExpression re{"%[fFuUickdDnNvm]"};
 | 
					    QRegularExpression re{"%[fFuUickdDnNvm]"};
 | 
				
			||||||
 | 
				
			|||||||
@ -5,25 +5,25 @@
 | 
				
			|||||||
#ifndef APPLICATIONSERVICE_H
 | 
					#ifndef APPLICATIONSERVICE_H
 | 
				
			||||||
#define APPLICATIONSERVICE_H
 | 
					#define APPLICATIONSERVICE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <QObject>
 | 
					#include "applicationmanager1service.h"
 | 
				
			||||||
#include <QDBusObjectPath>
 | 
					 | 
				
			||||||
#include <QMap>
 | 
					 | 
				
			||||||
#include <QString>
 | 
					 | 
				
			||||||
#include <QDBusUnixFileDescriptor>
 | 
					 | 
				
			||||||
#include <QSharedPointer>
 | 
					 | 
				
			||||||
#include <QUuid>
 | 
					 | 
				
			||||||
#include <QTextStream>
 | 
					 | 
				
			||||||
#include <QDBusContext>
 | 
					 | 
				
			||||||
#include <QFile>
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
#include <utility>
 | 
					 | 
				
			||||||
#include "applicationmanagerstorage.h"
 | 
					#include "applicationmanagerstorage.h"
 | 
				
			||||||
#include "dbus/applicationmanager1service.h"
 | 
					#include "dbus/applicationmanager1service.h"
 | 
				
			||||||
#include "dbus/instanceservice.h"
 | 
					#include "dbus/instanceservice.h"
 | 
				
			||||||
#include "global.h"
 | 
					 | 
				
			||||||
#include "desktopentry.h"
 | 
					 | 
				
			||||||
#include "dbus/jobmanager1service.h"
 | 
					#include "dbus/jobmanager1service.h"
 | 
				
			||||||
#include "applicationmanager1service.h"
 | 
					#include "desktopentry.h"
 | 
				
			||||||
 | 
					#include "global.h"
 | 
				
			||||||
 | 
					#include <QDBusContext>
 | 
				
			||||||
 | 
					#include <QDBusObjectPath>
 | 
				
			||||||
 | 
					#include <QDBusUnixFileDescriptor>
 | 
				
			||||||
 | 
					#include <QFile>
 | 
				
			||||||
 | 
					#include <QMap>
 | 
				
			||||||
 | 
					#include <QObject>
 | 
				
			||||||
 | 
					#include <QSharedPointer>
 | 
				
			||||||
 | 
					#include <QString>
 | 
				
			||||||
 | 
					#include <QTextStream>
 | 
				
			||||||
 | 
					#include <QUuid>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <utility>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QString getDeepinWineScaleFactor(const QString &appId) noexcept;
 | 
					QString getDeepinWineScaleFactor(const QString &appId) noexcept;
 | 
				
			||||||
double getScaleFactor() noexcept;
 | 
					double getScaleFactor() noexcept;
 | 
				
			||||||
@ -70,8 +70,8 @@ public:
 | 
				
			|||||||
    [[nodiscard]] bool terminal() const noexcept;
 | 
					    [[nodiscard]] bool terminal() const noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // FIXME:
 | 
					    // FIXME:
 | 
				
			||||||
    // This property should implement with fuse guarded $XDG_CONFIG_HOME/autostart/.
 | 
					    // This property should implement with fuse guarded
 | 
				
			||||||
    // Current implementation has some problems,
 | 
					    // $XDG_CONFIG_HOME/autostart/. Current implementation has some problems,
 | 
				
			||||||
    Q_PROPERTY(bool AutoStart READ isAutoStart WRITE setAutoStart NOTIFY autostartChanged)
 | 
					    Q_PROPERTY(bool AutoStart READ isAutoStart WRITE setAutoStart NOTIFY autostartChanged)
 | 
				
			||||||
    [[nodiscard]] bool isAutoStart() const noexcept;
 | 
					    [[nodiscard]] bool isAutoStart() const noexcept;
 | 
				
			||||||
    void setAutoStart(bool autostart) noexcept;
 | 
					    void setAutoStart(bool autostart) noexcept;
 | 
				
			||||||
@ -119,6 +119,9 @@ public:
 | 
				
			|||||||
    void resetEntry(DesktopEntry *newEntry) noexcept;
 | 
					    void resetEntry(DesktopEntry *newEntry) noexcept;
 | 
				
			||||||
    void detachAllInstance() noexcept;
 | 
					    void detachAllInstance() noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [[nodiscard]] LaunchTask unescapeExec(const QString &str, const QStringList &fields) noexcept;
 | 
				
			||||||
 | 
					    [[nodiscard]] static QStringList unescapeExecArgs(const QString &str) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private Q_SLOTS:
 | 
					private Q_SLOTS:
 | 
				
			||||||
    void onGlobalScaleFactorChanged() noexcept;
 | 
					    void onGlobalScaleFactorChanged() noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -165,7 +168,6 @@ private:
 | 
				
			|||||||
    DesktopFile m_desktopSource;
 | 
					    DesktopFile m_desktopSource;
 | 
				
			||||||
    QSharedPointer<DesktopEntry> m_entry{nullptr};
 | 
					    QSharedPointer<DesktopEntry> m_entry{nullptr};
 | 
				
			||||||
    QMap<QDBusObjectPath, QSharedPointer<InstanceService>> m_Instances;
 | 
					    QMap<QDBusObjectPath, QSharedPointer<InstanceService>> m_Instances;
 | 
				
			||||||
    [[nodiscard]] LaunchTask unescapeExec(const QString &str, const QStringList &fields);
 | 
					 | 
				
			||||||
    [[nodiscard]] QVariant findEntryValue(const QString &group,
 | 
					    [[nodiscard]] QVariant findEntryValue(const QString &group,
 | 
				
			||||||
                                          const QString &valueKey,
 | 
					                                          const QString &valueKey,
 | 
				
			||||||
                                          EntryValueType type,
 | 
					                                          EntryValueType type,
 | 
				
			||||||
 | 
				
			|||||||
@ -236,7 +236,7 @@ std::optional<DesktopEntry::Value> DesktopEntry::value(const QString &groupKey,
 | 
				
			|||||||
    return *it;
 | 
					    return *it;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QString unescape(const QString &str) noexcept
 | 
					QString unescape(const QString &str, bool shellMode) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QString unescapedStr;
 | 
					    QString unescapedStr;
 | 
				
			||||||
    for (qsizetype i = 0; i < str.size(); ++i) {
 | 
					    for (qsizetype i = 0; i < str.size(); ++i) {
 | 
				
			||||||
@ -270,10 +270,13 @@ QString unescape(const QString &str) noexcept
 | 
				
			|||||||
            unescapedStr.append(';');
 | 
					            unescapedStr.append(';');
 | 
				
			||||||
            ++i;
 | 
					            ++i;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case 's':
 | 
					        case 's': {
 | 
				
			||||||
 | 
					            if (shellMode) {  // for wordexp
 | 
				
			||||||
 | 
					                unescapedStr.append('\\');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            unescapedStr.append(' ');
 | 
					            unescapedStr.append(' ');
 | 
				
			||||||
            ++i;
 | 
					            ++i;
 | 
				
			||||||
            break;
 | 
					        } break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -296,6 +299,7 @@ QString toString(const DesktopEntry::Value &value) noexcept
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto unescapedStr = unescape(str);
 | 
					    auto unescapedStr = unescape(str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (hasNonAsciiAndControlCharacters(unescapedStr)) {
 | 
					    if (hasNonAsciiAndControlCharacters(unescapedStr)) {
 | 
				
			||||||
        return {};
 | 
					        return {};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -137,7 +137,7 @@ bool operator==(const DesktopFile &lhs, const DesktopFile &rhs);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool operator!=(const DesktopFile &lhs, const DesktopFile &rhs);
 | 
					bool operator!=(const DesktopFile &lhs, const DesktopFile &rhs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QString unescape(const QString &str) noexcept;
 | 
					QString unescape(const QString &str, bool shellMode = false) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QString toLocaleString(const QStringMap &localeMap, const QLocale &locale) noexcept;
 | 
					QString toLocaleString(const QStringMap &localeMap, const QLocale &locale) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										47
									
								
								tests/ut_escapeexec.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								tests/ut_escapeexec.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "dbus/applicationservice.h"
 | 
				
			||||||
 | 
					#include <gtest/gtest.h>
 | 
				
			||||||
 | 
					#include <QString>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(UnescapeExec, blankSpace)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QList<std::pair<QString, QList<QString>>> testCases{
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            R"(/usr/bin/hello\sworld --arg1=val1 -h --str="rrr ggg bbb")",
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "/usr/bin/hello world",
 | 
				
			||||||
 | 
					                "--arg1=val1",
 | 
				
			||||||
 | 
					                "-h",
 | 
				
			||||||
 | 
					                "--str=rrr ggg bbb",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            R"("/usr/bin/hello world" a b -- "c d")",
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "/usr/bin/hello world",
 | 
				
			||||||
 | 
					                "a",
 | 
				
			||||||
 | 
					                "b",
 | 
				
			||||||
 | 
					                "--",
 | 
				
			||||||
 | 
					                "c d",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            R"("/usr/bin/hello\t\nworld" a b -- c d)",
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "/usr/bin/hello\t\nworld",
 | 
				
			||||||
 | 
					                "a",
 | 
				
			||||||
 | 
					                "b",
 | 
				
			||||||
 | 
					                "--",
 | 
				
			||||||
 | 
					                "c",
 | 
				
			||||||
 | 
					                "d",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (auto &testCase : testCases) {
 | 
				
			||||||
 | 
					        EXPECT_EQ(ApplicationService::unescapeExecArgs(testCase.first), testCase.second);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user