diff --git a/main/main.cpp b/main/main.cpp index 2743402..2ec6614 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1,72 +1,77 @@ /* SPDX-FileCopyrightText: 2014-2023 Anne Jan Brouwer SPDX-FileCopyrightText: 2023 g10 Code GmbH SPDX-FileContributor: Sune Stolborg Vuorela SPDX-License-Identifier: GPL-3.0-or-later */ #include "firsttimedialog.h" #include "mainwindow.h" #include #include #include #include #include #include #include #include /** * @brief main * @param argc * @param argv * @return */ #include int main(int argc, char *argv[]) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); #endif // allow darkmode #if defined(Q_OS_WIN) if (!qEnvironmentVariableIsSet("QT_QPA_PLATFORM")) { qputenv("QT_QPA_PLATFORM", "windows:darkmode=1"); } #endif QApplication app(argc, argv); KLocalizedString::setApplicationDomain("gpgpass"); Q_INIT_RESOURCE(resources); QCoreApplication::setOrganizationName(QStringLiteral("GnuPG")); QCoreApplication::setOrganizationDomain(QStringLiteral("gnupg.org")); QCoreApplication::setApplicationName(QStringLiteral("GnuPGPass")); QCoreApplication::setApplicationVersion(QString::fromUtf8(GPGPASS_VERSION_STRING)); QApplication::setWindowIcon(QIcon(QStringLiteral(":/artwork/64-gpgpass.png"))); QGuiApplication::setDesktopFileName(QStringLiteral("org.gnupg.gpgpass.desktop")); MainWindow w; // ensure KIconThemes is loaded for rcc icons KIconLoader::global()->hasIcon(QString{}); KColorSchemeManager m; FirstTimeDialog d(&w, w.pass()); QSettings s; - if (!s.value(QStringLiteral("setup"), false).toBool() && d.wouldDoSomething()) { - d.show(); + if (!s.value(QStringLiteral("setup"), false).toBool()) { + if (d.wouldDoSomething()) { + d.show(); + } else { + d.doInitialSettings(); + w.show(); + } } else { w.show(); } return app.exec(); } diff --git a/src/firsttimedialog.cpp b/src/firsttimedialog.cpp index f515513..6566748 100644 --- a/src/firsttimedialog.cpp +++ b/src/firsttimedialog.cpp @@ -1,202 +1,206 @@ /* SPDX-FileCopyrightText: 2023 g10 Code GmbH SPDX-FileContributor: Sune Stolborg Vuorela SPDX-License-Identifier: GPL-3.0-or-later */ #include "firsttimedialog.h" #include "qdebug.h" #include #include #include #include #include #include #include "gpgmehelpers.h" #include "settings.h" #include "ui_keygenwidget.h" #include #include #include #include DialogState::DialogState(Pass &p) : pass(p) { } QList DialogState::privateKeys() const { auto job = protocol->keyListJob(); std::vector keys; auto result = job->exec(QStringList(), true, keys); if (!isSuccess(result.error())) { return {}; } QList users; for (const auto &key : keys) { UserInfo ui; ui.created = QDateTime::fromSecsSinceEpoch(key.subkey(0).creationTime()); ui.key_id = fromGpgmeCharStar(key.keyID()); ui.name = createCombinedNameString(key.userID(0)); ui.validity = key.userID(0).validityAsString(); ui.expiry = QDateTime::fromSecsSinceEpoch(key.subkey(0).expirationTime()); ui.have_secret = key.hasSecret(); users.append(ui); } return users; } FirstTimeDialog::FirstTimeDialog(QWidget *mainWindow, Pass &pass) : m_mainWindow(mainWindow) , m_state(pass) { setWindowTitle(i18n("GnuPG Password Manager setup")); setPage(Intro, new IntroPage(m_state)); setPage(KeyGen, new KeyGenPage(m_state)); setPage(Done, new DonePage()); QTransform rotate; rotate.rotate(-90); setPixmap(QWizard::WatermarkPixmap, QPixmap(QLatin1String(":/artwork/gnupg-logo-320x100tr.png")).transformed(rotate)); setPixmap(QWizard::LogoPixmap, QPixmap(QLatin1String(":/artwork/64-gpgpass.png"))); setStartId(Intro); } +void FirstTimeDialog::doInitialSettings() { + QSettings s; + s.setValue(QStringLiteral("setup"), true); + if (Settings::getAutoclearSeconds() < 5) + Settings::setAutoclearSeconds(10); + if (Settings::getAutoclearPanelSeconds() < 5) + Settings::setAutoclearPanelSeconds(10); + Settings::setPassTemplate(QStringLiteral("login\nurl")); +} + void FirstTimeDialog::done(int i) { if (i == QDialog::DialogCode::Accepted) { - QSettings s; - s.setValue(QStringLiteral("setup"), true); - if (Settings::getAutoclearSeconds() < 5) - Settings::setAutoclearSeconds(10); - if (Settings::getAutoclearPanelSeconds() < 5) - Settings::setAutoclearPanelSeconds(10); - Settings::setPassTemplate(QStringLiteral("login\nurl")); + doInitialSettings(); m_mainWindow->show(); } QWizard::done(i); } bool FirstTimeDialog::wouldDoSomething() const { return m_state.privateKeys().isEmpty(); } int FirstTimeDialog::nextId() const { switch (currentId()) { case Intro: if (m_state.privateKeys().isEmpty()) { return KeyGen; } else { return Done; } case KeyGen: return Done; default: return -1; } return -1; }; IntroPage::IntroPage(DialogState &s) : m_state(s) { QVBoxLayout *lay = new QVBoxLayout(); lay->addWidget(new QLabel(i18n("Welcome to GnuPG Password manager"))); setTitle(i18n("Welcome")); setSubTitle(i18n("Setting up")); setLayout(lay); } KeyGenPage::KeyGenPage(DialogState &s) : m_state(s) { setTitle(i18n("Generate keys")); setSubTitle(i18n("Generate keys")); m_ui = std::make_unique(); m_ui->setupUi(this); m_ui->spinner->hide(); m_ui->generateButton->setEnabled(false); m_ui->message->hide(); m_ui->email->setValidator( new QRegularExpressionValidator(QRegularExpression(QRegularExpression::anchoredPattern(QStringLiteral(R"(\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b)")), QRegularExpression::CaseInsensitiveOption))); connect(m_ui->generateButton, &QPushButton::clicked, this, &KeyGenPage::startKeyGen); connect(m_ui->email, &QLineEdit::textChanged, this, &KeyGenPage::checkEntries); connect(m_ui->name, &QLineEdit::textChanged, this, &KeyGenPage::checkEntries); } void KeyGenPage::startKeyGen() { m_ui->email->setEnabled(false); m_ui->name->setEnabled(false); m_ui->generateButton->setEnabled(false); m_ui->includeComment->setEnabled(false); m_ui->spinner->show(); auto job = m_state.protocol->quickJob(); connect(job, &QGpgME::QuickJob::result, this, [this](auto &&result, const QString &log, auto &&logResult) { if (isSuccess(result)) { Q_EMIT this->completeChanged(); this->m_ui->spinner->hide(); this->m_ui->message->show(); this->m_ui->message->setText(i18n("Key generated")); } else { this->m_ui->message->setText(fromGpgmeCharStar(result.asString())); this->m_ui->message->show(); } Q_UNUSED(log); Q_UNUSED(logResult); }); QString uid; if (m_ui->includeComment->isChecked()) { uid = QStringLiteral("%1 (PasswordManager) <%2>"); } else { uid = QStringLiteral("%1 <%2>"); } job->startCreate(uid.arg(m_ui->name->text(), m_ui->email->text()), "future-default"); } void KeyGenPage::checkEntries() { auto emailValidator = m_ui->email->validator(); bool enable = false; if (emailValidator) { auto email = m_ui->email->text(); int i = 0; if (emailValidator->validate(email, i) == QValidator::Acceptable) { qDebug() << "email valid"; enable = m_ui->name->text().size() > 4; } else { qDebug() << "email invalid"; } } else { qDebug() << "no email validator"; // TODO_REMOV enable = true; } m_ui->generateButton->setEnabled(enable); } KeyGenPage::~KeyGenPage() = default; bool KeyGenPage::isComplete() const { return !m_state.privateKeys().isEmpty(); } DonePage::DonePage() { setTitle(i18n("Setup done")); setSubTitle(i18n("Thanks")); setFinalPage(true); } diff --git a/src/firsttimedialog.h b/src/firsttimedialog.h index a5d59a3..cd88ec0 100644 --- a/src/firsttimedialog.h +++ b/src/firsttimedialog.h @@ -1,75 +1,76 @@ /* SPDX-FileCopyrightText: 2023 g10 Code GmbH SPDX-FileContributor: Sune Stolborg Vuorela SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef FIRSTTIMEDIALOG_H #define FIRSTTIMEDIALOG_H #include "usersdialog.h" #include #include #include class Ui_KeyGenWidget; class DialogState : public QObject { Q_OBJECT public: explicit DialogState(Pass &p); QList privateKeys() const; QGpgME::Protocol *protocol = QGpgME::openpgp(); QString storePath; Pass &pass; }; class FirstTimeDialog : public QWizard { enum Pages { Intro, KeyGen, Done }; Q_OBJECT public: FirstTimeDialog(QWidget *mainWindow, Pass &pass); int nextId() const override; void done(int i) override; bool wouldDoSomething() const; + void doInitialSettings(); private: QWidget *m_mainWindow; DialogState m_state; }; class IntroPage : public QWizardPage { Q_OBJECT public: explicit IntroPage(DialogState &s); private: DialogState &m_state; }; class KeyGenPage : public QWizardPage { Q_OBJECT public: explicit KeyGenPage(DialogState &s); bool isComplete() const override; ~KeyGenPage(); private Q_SLOTS: void startKeyGen(); void checkEntries(); private: DialogState &m_state; std::unique_ptr m_ui; }; class DonePage : public QWizardPage { public: DonePage(); }; #endif // FIRSTTIMEDIALOG_H