File indexing completed on 2024-04-14 05:43:20

0001 /*
0002  * SPDX-License-Identifier: GPL-3.0-or-later
0003  * SPDX-FileCopyrightText: 2019 Bhushan Shah <bshah@kde.org>
0004  * SPDX-FileCopyrightText: 2020-2021 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
0005  * SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
0006  */
0007 
0008 #include <QCommandLineParser>
0009 #include <QQmlApplicationEngine>
0010 #include <QQuickStyle>
0011 #include <QtQml>
0012 #include <QUrl>
0013 
0014 #ifdef Q_OS_ANDROID
0015 #include <QGuiApplication>
0016 #else
0017 #include <QApplication>
0018 #endif
0019 
0020 #include <KLocalizedContext>
0021 #include <KLocalizedString>
0022 
0023 #include "app/cli.h"
0024 #include "app/keysmith.h"
0025 #include "app/vms.h"
0026 #include "model/accounts.h"
0027 #include "model/input.h"
0028 #include "validators/countervalidator.h"
0029 #include "validators/datetimevalidator.h"
0030 #include "validators/issuervalidator.h"
0031 #include "validators/secretvalidator.h"
0032 
0033 #include "keysmith-features.h"
0034 #include "version.h"
0035 
0036 /*
0037  * Integrate QML debugging/profiling support, conditional on building Keysmith in Debug mode.
0038  * NDEBUG is defined by the C standard and automatically set by CMake during a Release type build, hence the double negative.
0039  */
0040 #ifndef NDEBUG
0041 #include <QQmlDebuggingEnabler>
0042 static QQmlDebuggingEnabler enabler;
0043 #endif
0044 
0045 #ifdef ENABLE_DBUS_INTERFACE
0046 #include <KDBusService>
0047 #endif
0048 
0049 Q_DECL_EXPORT int main(int argc, char *argv[])
0050 {
0051 #ifdef Q_OS_ANDROID
0052     QGuiApplication app(argc, argv);
0053     QQuickStyle::setStyle(QStringLiteral("org.kde.breeze"));
0054 #else
0055     QApplication app(argc, argv);
0056     if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) {
0057         QQuickStyle::setStyle(QStringLiteral("org.kde.desktop"));
0058     }
0059 #endif
0060 
0061     KLocalizedString::setApplicationDomain("keysmith");
0062 
0063     QCoreApplication::setOrganizationName(QStringLiteral("KDE"));
0064     QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org"));
0065     QCoreApplication::setApplicationName(QStringLiteral("keysmith"));
0066     QCoreApplication::setApplicationVersion(KEYSMITH_VERSION_STRING);
0067     QGuiApplication::setApplicationDisplayName(i18nc("@title", "Keysmith"));
0068 
0069     QCommandLineParser cliParser;
0070 
0071     // default/boilerplate options handled entirely via command line
0072     const auto helpOption = cliParser.addHelpOption();
0073     const auto versionOption = cliParser.addVersionOption();
0074 
0075     bool parseOk = app::Proxy::parseCommandLine(cliParser, QCoreApplication::arguments());
0076 
0077     /*
0078      * First check for pure command line options and handle these.
0079      * If any are found, the application should not bother with an UI.
0080      */
0081 
0082     if (cliParser.isSet(helpOption)) {
0083         int ret = parseOk ? 0 : 1;
0084         cliParser.showHelp(ret);
0085         return ret; // just to be explicit: showHelp() is documented to call exit()
0086     }
0087 
0088     if (cliParser.isSet(versionOption)) {
0089         cliParser.showVersion();
0090         return 0; // just to be explicit: showVersion() is documented to call exit()
0091     }
0092 
0093     app::Proxy proxy(&app);
0094 
0095 #ifdef ENABLE_DBUS_INTERFACE
0096     KDBusService service(KDBusService::Unique);
0097     QObject::connect(&service, &KDBusService::activateRequested, &proxy, &app::Proxy::handleDBusActivation);
0098 #endif
0099 
0100     QQmlApplicationEngine engine;
0101     engine.rootContext()->setContextObject(new KLocalizedContext(&engine));
0102 
0103     qmlRegisterUncreatableType<app::AddAccountViewModel>("Keysmith.Application", 1, 0, "AddAccountViewModel",
0104         QStringLiteral("Should be automatically provided through Keysmith.Application.Navigation signals")
0105     );
0106     qmlRegisterUncreatableType<app::RenameAccountViewModel>("Keysmith.Application", 1, 0, "RenameAccountViewModel",
0107         QStringLiteral("Should be automatically provided through Keysmith.Navigation signals")
0108     );
0109     qmlRegisterUncreatableType<app::ErrorViewModel>("Keysmith.Application", 1, 0, "ErrorViewModel",
0110         QStringLiteral("Should be automatically provided through Keysmith.Navigation signals")
0111     );
0112     qmlRegisterUncreatableType<app::SetupPasswordViewModel>("Keysmith.Application", 1, 0, "SetupPasswordViewModel",
0113         QStringLiteral("Should be automatically provided through Keysmith.Navigation signals")
0114     );
0115     qmlRegisterUncreatableType<app::UnlockAccountsViewModel>("Keysmith.Application", 1, 0, "UnlockAccountsViewModel",
0116         QStringLiteral("Should be automatically provided through Keysmith.Navigation signals")
0117     );
0118     qmlRegisterUncreatableType<app::AccountsOverviewViewModel>("Keysmith.Application", 1, 0, "AccountsOverviewViewModel",
0119         QStringLiteral("Should be automatically provided through Keysmith.Navigation signals")
0120     );
0121     qmlRegisterUncreatableType<app::Navigation>("Keysmith.Application", 1, 0, "Navigation",
0122         QStringLiteral("Use the Keysmith singleton to obtain a Navigation")
0123     );
0124 
0125     qmlRegisterUncreatableType<model::SimpleAccountListModel>("Keysmith.Models", 1, 0, "AccountListModel",
0126         QStringLiteral("Use the Keysmith singleton to obtain an AccountListModel")
0127     );
0128     qmlRegisterUncreatableType<model::PasswordRequest>("Keysmith.Models", 1, 0, "PasswordRequestModel",
0129         QStringLiteral("Use the Keysmith singleton to obtain an PasswordRequestModel")
0130     );
0131     qmlRegisterUncreatableType<model::AccountView>("Keysmith.Models", 1, 0, "Account",
0132         QStringLiteral("Use an AccountListModel from the Keysmith singleton to obtain an Account")
0133     );
0134     qmlRegisterType<model::AccountInput>("Keysmith.Models", 1, 0, "ValidatedAccountInput");
0135     qmlRegisterType<model::SortedAccountsListModel>("Keysmith.Models", 1, 0, "SortedAccountListModel");
0136     qmlRegisterType<model::AccountNameValidator>("Keysmith.Validators", 1, 0, "AccountNameValidator");
0137     qmlRegisterType<validators::EpochValidator>("Keysmith.Validators", 1, 0, "TOTPEpochValidator");
0138     qmlRegisterType<validators::IssuerValidator>("Keysmith.Validators", 1, 0, "AccountIssuerValidator");
0139     qmlRegisterType<validators::Base32Validator>("Keysmith.Validators", 1, 0, "Base32SecretValidator");
0140     qmlRegisterType<validators::UnsignedLongValidator>("Keysmith.Validators", 1, 0, "HOTPCounterValidator");
0141     qmlRegisterSingletonType<app::Keysmith>("Keysmith.Application", 1, 0, "Keysmith", [&proxy](QQmlEngine *qml, QJSEngine *js) -> QObject *
0142     {
0143         Q_UNUSED(js);
0144 
0145         auto app = new app::Keysmith(new app::Navigation(qml));
0146         proxy.enable(app);
0147         return app;
0148     });
0149     qmlRegisterSingletonType<app::CommandLineOptions>("Keysmith.Application", 1, 0, "CommandLine", [parseOk, &cliParser](QQmlEngine *qml, QJSEngine *js) -> QObject *
0150     {
0151         Q_UNUSED(qml);
0152         Q_UNUSED(js);
0153 
0154         return new app::CommandLineOptions(cliParser, parseOk);
0155     });
0156 
0157     engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
0158     if (engine.rootObjects().isEmpty()) {
0159         return -1;
0160     }
0161     proxy.proxy(cliParser, parseOk);
0162     return app.exec();
0163 }