From 0b6132897101c4cd1618c79049d5685c5e9874fa Mon Sep 17 00:00:00 2001 From: dsc Date: Wed, 3 Jul 2019 05:13:51 +0200 Subject: [PATCH] Detect tails, support data persistence Co-authored-by: Thotbot Co-authored-by: Selsta --- Logger.cpp | 4 ++ images/tails-grey.png | Bin 0 -> 7873 bytes main.cpp | 41 +++++++++---- main.qml | 6 ++ monero-wallet-gui.pro | 6 +- pages/settings/SettingsInfo.qml | 35 +++++++++++ qml.qrc | 1 + src/qt/TailsOS.cpp | 100 ++++++++++++++++++++++++++++++++ src/qt/TailsOS.h | 23 ++++++++ src/qt/mime.cpp | 70 ---------------------- src/qt/mime.h | 36 ------------ src/qt/utils.cpp | 73 ++++++++++++++++++++++- src/qt/utils.h | 5 ++ 13 files changed, 277 insertions(+), 123 deletions(-) create mode 100644 images/tails-grey.png create mode 100644 src/qt/TailsOS.cpp create mode 100644 src/qt/TailsOS.h delete mode 100644 src/qt/mime.cpp delete mode 100644 src/qt/mime.h diff --git a/Logger.cpp b/Logger.cpp index f2e34552..ad356bcb 100644 --- a/Logger.cpp +++ b/Logger.cpp @@ -34,6 +34,7 @@ #include #include "Logger.h" +#include "src/qt/TailsOS.h" #include "wallet/api/wallet2_api.h" // default log path by OS (should be writable) @@ -66,6 +67,9 @@ const QString getLogPath(const QString logPath) { const QFileInfo fi(logPath); + if(TailsOS::detect() && TailsOS::usePersistence) + return QDir::homePath() + "/Persistent/Monero/logs/" + defaultLogName; + if(!logPath.isEmpty() && !fi.isDir()) return fi.absoluteFilePath(); else { diff --git a/images/tails-grey.png b/images/tails-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..b2e18e42c5739f0336f3195634814ef389b0898b GIT binary patch literal 7873 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 Zr(dh{hEyLqu=h`96GL-@a=r6W{{=&6D!>2$ literal 0 HcmV?d00001 diff --git a/main.cpp b/main.cpp index a41b3c75..939b78f2 100644 --- a/main.cpp +++ b/main.cpp @@ -64,7 +64,7 @@ #include "MainApp.h" #include "qt/ipc.h" #include "qt/utils.h" -#include "qt/mime.h" +#include "src/qt/TailsOS.h" #include "src/qt/KeysFiles.h" #include "src/qt/MoneroSettings.h" #include "qt/prices.h" @@ -83,6 +83,7 @@ bool isAndroid = false; bool isWindows = false; bool isMac = false; bool isLinux = false; +bool isTails = false; bool isDesktop = false; bool isOpenGL = true; @@ -102,6 +103,7 @@ int main(int argc, char *argv[]) bool isWindows = true; #elif defined(Q_OS_LINUX) bool isLinux = true; + bool isTails = TailsOS::detect(); #elif defined(Q_OS_MAC) bool isMac = true; #endif @@ -123,25 +125,40 @@ int main(int argc, char *argv[]) // qDebug() << "High DPI auto scaling - enabled"; //#endif + MainApp app(argc, argv); + + app.setApplicationName("monero-core"); + app.setOrganizationDomain("getmonero.org"); + app.setOrganizationName("monero-project"); + + // Ask to enable Tails OS persistence mode, it affects: + // - Log file location + // - QML Settings file location (monero-core.conf) + // - Default wallets path + // Target directory is: ~/Persistent/Monero + if (isTails) { + if (!TailsOS::detectDataPersistence()) + TailsOS::showDataPersistenceDisabledWarning(); + else + TailsOS::askPersistence(); + } + QString moneroAccountsDir; #if defined(Q_OS_WIN) || defined(Q_OS_IOS) QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation); #else QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::HomeLocation); #endif - if (!moneroAccountsRootDir.empty()) { + + if(isTails && TailsOS::usePersistence){ + moneroAccountsDir = QDir::homePath() + "/Persistent/Monero/wallets"; + } else if (!moneroAccountsRootDir.empty()) { moneroAccountsDir = moneroAccountsRootDir.at(0) + "/Monero/wallets"; } else { qCritical() << "Error: accounts root directory could not be set"; return 1; } - MainApp app(argc, argv); - - app.setApplicationName("monero-core"); - app.setOrganizationDomain("getmonero.org"); - app.setOrganizationName("monero-project"); - #if defined(Q_OS_LINUX) if (isDesktop) app.setWindowIcon(QIcon(":/images/appicon.ico")); #endif @@ -174,9 +191,8 @@ int main(int argc, char *argv[]) } qWarning().noquote() << "app startd" << "(log: " + logPath + ")"; -#ifdef Q_OS_LINUX + // Desktop entry registerXdgMime(app); -#endif IPC *ipc = new IPC(&app); QStringList posArgs = parser.positionalArguments(); @@ -317,6 +333,8 @@ int main(int argc, char *argv[]) engine.rootContext()->setContextProperty("walletLogPath", logPath); + engine.rootContext()->setContextProperty("tailsUsePersistence", TailsOS::usePersistence); + // Exclude daemon manager from IOS #ifndef Q_OS_IOS const QStringList arguments = (QStringList) QCoreApplication::arguments().at(0); @@ -330,7 +348,7 @@ int main(int argc, char *argv[]) engine.rootContext()->setContextProperty("isIOS", isIOS); engine.rootContext()->setContextProperty("isAndroid", isAndroid); engine.rootContext()->setContextProperty("isOpenGL", isOpenGL); - engine.rootContext()->setContextProperty("isLinux", isLinux); + engine.rootContext()->setContextProperty("isTails", isTails); engine.rootContext()->setContextProperty("screenWidth", geo.width()); engine.rootContext()->setContextProperty("screenHeight", geo.height()); @@ -354,6 +372,7 @@ int main(int argc, char *argv[]) accountName = "My monero Account"; engine.rootContext()->setContextProperty("defaultAccountName", accountName); + engine.rootContext()->setContextProperty("homePath", QDir::homePath()); engine.rootContext()->setContextProperty("applicationDirectory", QApplication::applicationDirPath()); engine.rootContext()->setContextProperty("idealThreadCount", QThread::idealThreadCount()); diff --git a/main.qml b/main.qml index 1655456c..25536f79 100644 --- a/main.qml +++ b/main.qml @@ -1349,6 +1349,12 @@ ApplicationWindow { MoneroSettings { id: persistentSettings + fileName: { + if(isTails && tailsUsePersistence) + return homePath + "/Persistent/Monero/monero-core.conf"; + return ""; + } + property string language property string locale property string account_name diff --git a/monero-wallet-gui.pro b/monero-wallet-gui.pro index d832ee12..97286b05 100644 --- a/monero-wallet-gui.pro +++ b/monero-wallet-gui.pro @@ -65,12 +65,12 @@ HEADERS += \ MainApp.h \ src/qt/FutureScheduler.h \ src/qt/ipc.h \ - src/qt/mime.h \ src/qt/KeysFiles.h \ src/qt/utils.h \ src/qt/prices.h \ src/qt/macoshelper.h \ src/qt/MoneroSettings.h + src/qt/TailsOS.h SOURCES += main.cpp \ filter.cpp \ @@ -101,11 +101,11 @@ SOURCES += main.cpp \ MainApp.cpp \ src/qt/FutureScheduler.cpp \ src/qt/ipc.cpp \ - src/qt/mime.cpp \ src/qt/KeysFiles.cpp \ src/qt/utils.cpp \ src/qt/prices.cpp \ - src/qt/MoneroSettings.cpp + src/qt/MoneroSettings.cpp \ + src/qt/TailsOS.cpp CONFIG(DISABLE_PASS_STRENGTH_METER) { HEADERS -= src/zxcvbn-c/zxcvbn.h diff --git a/pages/settings/SettingsInfo.qml b/pages/settings/SettingsInfo.qml index 938bd122..80e6a129 100644 --- a/pages/settings/SettingsInfo.qml +++ b/pages/settings/SettingsInfo.qml @@ -326,6 +326,41 @@ Rectangle { font.pixelSize: 14 text: isOpenGL ? "OpenGL" : "Low graphics mode" } + + Rectangle { + visible: isTails + height: 1 + Layout.topMargin: 2 + Layout.bottomMargin: 2 + Layout.fillWidth: true + color: MoneroComponents.Style.dividerColor + opacity: MoneroComponents.Style.dividerOpacity + } + + Rectangle { + visible: isTails + height: 1 + Layout.topMargin: 2 + Layout.bottomMargin: 2 + Layout.fillWidth: true + color: MoneroComponents.Style.dividerColor + opacity: MoneroComponents.Style.dividerOpacity + } + + MoneroComponents.TextBlock { + visible: isTails + Layout.fillWidth: true + font.pixelSize: 14 + text: qsTr("Tails: ") + translationManager.emptyString + } + + MoneroComponents.TextBlock { + visible: isTails + Layout.fillWidth: true + color: MoneroComponents.Style.dimmedFontColor + font.pixelSize: 14 + text: tailsUsePersistence ? qsTr("persistent") + translationManager.emptyString : qsTr("persistence disabled") + translationManager.emptyString; + } } // Copy info to clipboard diff --git a/qml.qrc b/qml.qrc index 3bced000..29f68f1a 100644 --- a/qml.qrc +++ b/qml.qrc @@ -251,5 +251,6 @@ images/copy.svg images/edit.svg images/arrow-right-in-circle-outline-medium-white.svg + images/tails-grey.png diff --git a/src/qt/TailsOS.cpp b/src/qt/TailsOS.cpp new file mode 100644 index 00000000..df2fa92b --- /dev/null +++ b/src/qt/TailsOS.cpp @@ -0,0 +1,100 @@ +#include +#include +#include +#include + +#include "TailsOS.h" +#include "utils.h" + +bool TailsOS::usePersistence = false; +QString TailsOS::tailsPathData = QString("/live/persistence/TailsData_unlocked/"); + +bool TailsOS::detect() +{ + if (!fileExists("/etc/os-release")) + return false; + + QByteArray data = fileOpen("/etc/os-release"); + QRegularExpression re("TAILS_PRODUCT_NAME=\"Tails\""); + QRegularExpressionMatch os_match = re.match(data); + bool matched = os_match.hasMatch(); + +#ifdef QT_DEBUG + if (matched) + qDebug() << "Tails OS detected"; +#endif + + return matched; +} + +bool TailsOS::detectDataPersistence() +{ + return QDir(QDir::homePath() + "/Persistent").exists(); +} + +bool TailsOS::detectDotPersistence() +{ + return QDir(tailsPathData + "dotfiles").exists(); +} + +void TailsOS::showDataPersistenceDisabledWarning() +{ + QMessageBox msgBox; + msgBox.setText(QObject::tr("Warning: persistence disabled")); + msgBox.setWindowTitle(QObject::tr("Warning: persistence disabled")); + msgBox.setInformativeText( + QObject::tr("Monero GUI has detected that Tails persistence is " + "currently disabled. Any configurations you make inside " + "the Monero GUI will not be saved." + "\n\n" + "In addition, make sure to not save your wallet on the " + "filesystem, as it will be lost at shutdown." + "\n\n" + "To enable Tails persistence, setup an encrypted volume " + "and restart Tails. To gain a startup menu item, " + "enable the Tails \"dotfiles\" feature.")); + + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setDefaultButton(QMessageBox::Ok); + msgBox.setIconPixmap(QPixmap(":/images/tails-grey.png")); + msgBox.exec(); +} + +void TailsOS::askPersistence() +{ + QMessageBox msgBox; + msgBox.setWindowTitle(QObject::tr("Monero GUI")); + msgBox.setText(QObject::tr("Use Tails persistence?")); + msgBox.setInformativeText( + QObject::tr("Persist wallet files and configuration on the encrypted volume?" + "\n\n" + "In addition, you can enable Tails dotfiles persistence " + "to gain a start menu entry.\n")); + + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + msgBox.setIconPixmap(QPixmap(":/images/tails-grey.png")); + TailsOS::usePersistence = (msgBox.exec() == QMessageBox::Yes); +} + +void TailsOS::persistXdgMime(QString filePath, QString data) +{ + QFileInfo file(filePath); + QString tailsPath = tailsPathData + "dotfiles/.local/share/applications/"; + + // write to persistent volume +#ifdef QT_DEBUG + qDebug() << "Writing xdg mime: " << tailsPath + file.fileName(); +#endif + + QDir().mkpath(tailsPath); // ensure directory exists + fileWrite(tailsPath + file.fileName(), data); + + // write to current session +#ifdef QT_DEBUG + qDebug() << "Writing xdg mime: " << file.filePath(); +#endif + + QDir().mkpath(file.path()); // ensure directory exists + fileWrite(file.filePath(), data); +} diff --git a/src/qt/TailsOS.h b/src/qt/TailsOS.h new file mode 100644 index 00000000..05d5ebd1 --- /dev/null +++ b/src/qt/TailsOS.h @@ -0,0 +1,23 @@ +#ifndef TAILSOS_H +#define TAILSOS_H + +#include + + +class TailsOS +{ +public: + TailsOS(); + static bool detect(); + static bool detectDataPersistence(); + static bool detectDotPersistence(); + + static void showDataPersistenceDisabledWarning(); + static void askPersistence(); + static void persistXdgMime(QString filePath, QString data); + + static bool usePersistence; + static QString tailsPathData; +}; + +#endif // TAILSOS_H diff --git a/src/qt/mime.cpp b/src/qt/mime.cpp deleted file mode 100644 index 6daf4de6..00000000 --- a/src/qt/mime.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2014-2019, The Monero Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be -// used to endorse or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include -#include -#include -#include - -#include "mime.h" -#include "utils.h" - -void registerXdgMime(QApplication &app){ - // MacOS handled via Info.plist - // Windows handled in the installer by rbrunner7 - - QString xdg = QString( - "[Desktop Entry]\n" - "Name=Monero GUI\n" - "GenericName=Monero-GUI\n" - "X-GNOME-FullName=Monero-GUI\n" - "Comment=Monero GUI\n" - "Keywords=Monero;\n" - "Exec=%1 %u\n" - "Terminal=false\n" - "Type=Application\n" - "Icon=monero\n" - "Categories=Network;GNOME;Qt;\n" - "MimeType=x-scheme-handler/monero;x-scheme-handler/moneroseed\n" - "StartupNotify=true\n" - "X-GNOME-Bugzilla-Bugzilla=GNOME\n" - "X-GNOME-UsesNotifications=true\n" - ).arg(app.applicationFilePath()); - - QString appPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); - QString filePath = QString("%1/monero-gui.desktop").arg(appPath); - - qDebug() << QString("Writing %1").arg(filePath); - QFile file(filePath); - if(file.open(QIODevice::WriteOnly)){ - QTextStream out(&file); out << xdg << endl; - file.close(); - } - else - file.close(); -} diff --git a/src/qt/mime.h b/src/qt/mime.h deleted file mode 100644 index b79d43a3..00000000 --- a/src/qt/mime.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2014-2019, The Monero Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be -// used to endorse or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef MIME_H -#define MIME_H - -#include - -void registerXdgMime(QApplication &app); - -#endif // MIME_H diff --git a/src/qt/utils.cpp b/src/qt/utils.cpp index 2407a50e..4418a050 100644 --- a/src/qt/utils.cpp +++ b/src/qt/utils.cpp @@ -27,15 +27,35 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include +#include "src/qt/TailsOS.h" #include "utils.h" bool fileExists(QString path) { QFileInfo check_file(path); - if (check_file.exists() && check_file.isFile()) + return check_file.exists() && check_file.isFile(); +} + +QByteArray fileOpen(QString path) { + QFile file(path); + if(!file.open(QFile::ReadOnly | QFile::Text)) + return QByteArray(); + + QByteArray data = file.readAll(); + file.close(); + return data; +} + +bool fileWrite(QString path, QString data) { + QFile file(path); + if(file.open(QIODevice::WriteOnly)){ + QTextStream out(&file); out << data << endl; + file.close(); return true; - else - return false; + } + + return false; } QString getAccountName(){ @@ -47,6 +67,53 @@ QString getAccountName(){ return accountName; } +QString xdgMime(QApplication &app){ + return QString( + "[Desktop Entry]\n" + "Name=Monero GUI\n" + "GenericName=Monero-GUI\n" + "X-GNOME-FullName=Monero-GUI\n" + "Comment=Monero GUI\n" + "Keywords=Monero;\n" + "Exec=%1 %u\n" + "Terminal=false\n" + "Type=Application\n" + "Icon=monero\n" + "Categories=Network;GNOME;Qt;\n" + "MimeType=x-scheme-handler/monero;x-scheme-handler/moneroseed\n" + "StartupNotify=true\n" + "X-GNOME-Bugzilla-Bugzilla=GNOME\n" + "X-GNOME-UsesNotifications=true\n" + ).arg(app.applicationFilePath()); +} + +void registerXdgMime(QApplication &app){ +#ifdef Q_OS_LINUX + // Register desktop entry + // - MacOS handled via Info.plist + // - Windows handled in the installer by rbrunner7 + // - Linux written to `QStandardPaths::ApplicationsLocation` + // - Tails written to persistent dotfiles + QString mime = xdgMime(app); + QString appPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); + QString filePath = QString("%1/monero-gui.desktop").arg(appPath); + + if (TailsOS::detect() && TailsOS::detectDotPersistence() && TailsOS::usePersistence) { + TailsOS::persistXdgMime(filePath, mime); + return; + } + + QFileInfo file(filePath); + QDir().mkpath(file.path()); // ensure directory exists + +#ifdef QT_DEBUG + qDebug() << "Writing xdg mime: " << filePath; +#endif + + fileWrite(filePath, mime); +#endif +} + QString randomUserAgent(){ QStringList urand; urand << "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1" diff --git a/src/qt/utils.h b/src/qt/utils.h index c18ffdc1..f48dff97 100644 --- a/src/qt/utils.h +++ b/src/qt/utils.h @@ -31,9 +31,14 @@ #include #include +#include bool fileExists(QString path); +QByteArray fileOpen(QString path); +bool fileWrite(QString path, QString data); QString getAccountName(); +QString xdgMime(QApplication &app); +void registerXdgMime(QApplication &app); const static QRegExp reURI = QRegExp("^\\w+:\\/\\/([\\w+\\-?\\-_\\-=\\-&]+)"); QString randomUserAgent();