Detect tails, support data persistence

Co-authored-by: Thotbot <thotbot@protonmail.com>
Co-authored-by: Selsta <selsta@sent.at>
This commit is contained in:
dsc 2019-07-03 05:13:51 +02:00
parent cfec9dde96
commit 0b61328971
No known key found for this signature in database
GPG Key ID: 7BBC83D7A8810AAB
13 changed files with 277 additions and 123 deletions

View File

@ -34,6 +34,7 @@
#include <QDebug>
#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 {

BIN
images/tails-grey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -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());

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -251,5 +251,6 @@
<file>images/copy.svg</file>
<file>images/edit.svg</file>
<file>images/arrow-right-in-circle-outline-medium-white.svg</file>
<file>images/tails-grey.png</file>
</qresource>
</RCC>

100
src/qt/TailsOS.cpp Normal file
View File

@ -0,0 +1,100 @@
#include <QRegExp>
#include <QMessageBox>
#include <QPixmap>
#include <QTranslator>
#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);
}

23
src/qt/TailsOS.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef TAILSOS_H
#define TAILSOS_H
#include <QApplication>
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

View File

@ -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 <QtCore>
#include <QApplication>
#include <QFile>
#include <QTextStream>
#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();
}

View File

@ -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 <QApplication>
void registerXdgMime(QApplication &app);
#endif // MIME_H

View File

@ -27,15 +27,35 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtCore>
#include <QApplication>
#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"

View File

@ -31,9 +31,14 @@
#include <QtCore>
#include <QRegExp>
#include <QApplication>
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();