File indexing completed on 2024-05-26 16:08:01

0001 /*
0002  *  SPDX-FileCopyrightText: 2013 Alejandro Fiestas Olivares <afiestas@kde.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #include "createaccountjob.h"
0007 
0008 #include "core.h"
0009 #include "kaccountsuiplugin.h"
0010 #include "uipluginsmanager.h"
0011 
0012 #include <QDebug>
0013 #include <QDir>
0014 #include <QPluginLoader>
0015 
0016 #include <Accounts/AccountService>
0017 #include <Accounts/Manager>
0018 
0019 #include <SignOn/AuthSession>
0020 #include <SignOn/Identity>
0021 
0022 #include <KLocalizedString>
0023 
0024 namespace KAccounts
0025 {
0026 
0027 CreateAccountJob::CreateAccountJob(QObject *parent)
0028     : CreateAccountJob(QString(), parent)
0029 {
0030 }
0031 
0032 CreateAccountJob::CreateAccountJob(const QString &providerName, QObject *parent)
0033     : KJob(parent)
0034     , m_providerName(providerName)
0035     , m_manager(new Accounts::Manager(this))
0036 {
0037 }
0038 
0039 void CreateAccountJob::start()
0040 {
0041     qDebug() << m_providerName;
0042     QMetaObject::invokeMethod(this, "processSession");
0043 }
0044 
0045 void CreateAccountJob::processSession()
0046 {
0047     m_account = m_manager->createAccount(m_providerName);
0048     Accounts::Service service;
0049     if (m_account->services().size() == 1) {
0050         service = m_account->services().at(0);
0051     }
0052     m_accInfo = new Accounts::AccountService(m_account, service, this);
0053 
0054     const QString pluginName = m_account->provider().pluginName();
0055     qDebug() << "Looking for plugin" << pluginName;
0056     if (!pluginName.isEmpty()) {
0057         loadPluginAndShowDialog(pluginName);
0058     } else {
0059         SignOn::IdentityInfo info;
0060         info.setCaption(m_providerName);
0061         info.setAccessControlList({QStringLiteral("*")});
0062         info.setType(SignOn::IdentityInfo::Application);
0063         info.setStoreSecret(true);
0064 
0065         m_identity = SignOn::Identity::newIdentity(info, this);
0066         m_identity->storeCredentials();
0067 
0068         connect(m_identity, &SignOn::Identity::info, this, &CreateAccountJob::info);
0069         connect(m_identity, &SignOn::Identity::error, [=](const SignOn::Error &err) {
0070             qDebug() << "Error storing identity:" << err.message();
0071         });
0072 
0073         QVariantMap data = m_accInfo->authData().parameters();
0074         data.insert(QStringLiteral("Embedded"), false);
0075 
0076         SignOn::SessionData sessionData(data);
0077         SignOn::AuthSessionP session = m_identity->createSession(m_accInfo->authData().method());
0078         qDebug() << "Starting auth session with" << m_accInfo->authData().method();
0079         connect(session, &SignOn::AuthSession::error, this, &CreateAccountJob::sessionError);
0080         connect(session, &SignOn::AuthSession::response, this, &CreateAccountJob::sessionResponse);
0081 
0082         session->process(sessionData, m_accInfo->authData().mechanism());
0083     }
0084 }
0085 
0086 void CreateAccountJob::loadPluginAndShowDialog(const QString &pluginName)
0087 {
0088     KAccountsUiPlugin *ui = KAccounts::UiPluginsManager::pluginForName(pluginName);
0089 
0090     if (!ui) {
0091         qDebug() << "Plugin could not be loaded";
0092         pluginError(i18nc("The %1 is for plugin name, eg. Could not load UI plugin", "Could not load %1 plugin, please check your installation", pluginName));
0093         return;
0094     }
0095 
0096     connect(ui, &KAccountsUiPlugin::success, this, &CreateAccountJob::pluginFinished, Qt::UniqueConnection);
0097     connect(ui, &KAccountsUiPlugin::error, this, &CreateAccountJob::pluginError, Qt::UniqueConnection);
0098     connect(ui, &KAccountsUiPlugin::canceled, this, &CreateAccountJob::pluginCancelled, Qt::UniqueConnection);
0099     connect(ui, &KAccountsUiPlugin::startAuthSession, this, &CreateAccountJob::startAuthSession, Qt::UniqueConnection);
0100 
0101     ui->setProviderName(m_providerName);
0102     ui->init(KAccountsUiPlugin::NewAccountDialog);
0103 }
0104 
0105 void CreateAccountJob::startAuthSession(const QVariantMap &data)
0106 {
0107     SignOn::IdentityInfo info;
0108     info.setCaption(m_providerName);
0109     info.setAccessControlList({QStringLiteral("*")});
0110     info.setType(SignOn::IdentityInfo::Application);
0111     info.setStoreSecret(true);
0112 
0113     m_identity = SignOn::Identity::newIdentity(info, this);
0114     m_identity->storeCredentials();
0115 
0116     connect(m_identity, &SignOn::Identity::info, this, &CreateAccountJob::info);
0117     connect(m_identity, &SignOn::Identity::error, [=](const SignOn::Error &err) {
0118         qDebug() << "Error storing identity:" << err.message();
0119     });
0120 
0121     auto i = data.constBegin();
0122     while (i != data.constEnd()) {
0123         m_account->setValue(i.key(), i.value());
0124         ++i;
0125     }
0126 
0127     m_account->syncAndBlock();
0128 
0129     QVariantMap authData = m_accInfo->authData().parameters();
0130     authData.insert(QStringLiteral("Embedded"), false);
0131 
0132     SignOn::SessionData sessionData(authData);
0133     SignOn::AuthSessionP session = m_identity->createSession(m_accInfo->authData().method());
0134     qDebug() << "Starting auth session with" << m_accInfo->authData().method();
0135     connect(session, &SignOn::AuthSession::error, this, &CreateAccountJob::sessionError);
0136     connect(session, &SignOn::AuthSession::response, this, &CreateAccountJob::sessionResponse);
0137 
0138     session->process(sessionData, m_accInfo->authData().mechanism());
0139 }
0140 
0141 void CreateAccountJob::pluginFinished(const QString &screenName, const QString &secret, const QVariantMap &data)
0142 {
0143     // Set up the new identity
0144     SignOn::IdentityInfo info;
0145     info.setStoreSecret(true);
0146     info.setUserName(screenName);
0147     info.setSecret(secret, true);
0148     info.setCaption(m_providerName);
0149     info.setAccessControlList(QStringList(QStringLiteral("*")));
0150     info.setType(SignOn::IdentityInfo::Application);
0151 
0152     const auto keys = data.keys();
0153     for (const QString &key : keys) {
0154         // If a key with __service/ prefix exists and its value is false,
0155         // add it to m_disabledServices which will later be used for disabling
0156         // the services contained in that list
0157         if (key.startsWith(QLatin1String("__service/")) && !data.value(key).toBool()) {
0158             m_disabledServices << key.mid(10);
0159         }
0160         m_account->setValue(key, data.value(key).toString());
0161     }
0162 
0163     m_identity = SignOn::Identity::newIdentity(info, this);
0164     connect(m_identity, &SignOn::Identity::info, this, &CreateAccountJob::info);
0165 
0166     m_done = true;
0167 
0168     connect(m_identity, &SignOn::Identity::credentialsStored, m_identity, &SignOn::Identity::queryInfo);
0169     m_identity->storeCredentials();
0170 }
0171 
0172 void CreateAccountJob::pluginError(const QString &error)
0173 {
0174     if (error.isEmpty()) {
0175         setError(-1);
0176     } else {
0177         setError(KJob::UserDefinedError);
0178     }
0179     setErrorText(error);
0180     // Delete the dialog
0181     emitResult();
0182 }
0183 
0184 void CreateAccountJob::pluginCancelled()
0185 {
0186     setError(KJob::KilledJobError);
0187     setErrorText(i18n("Cancelled by user"));
0188 
0189     emitResult();
0190 }
0191 
0192 void CreateAccountJob::sessionResponse(const SignOn::SessionData & /*data*/)
0193 {
0194     qDebug() << "Received session response";
0195 
0196     m_done = true;
0197     m_identity->queryInfo();
0198 }
0199 
0200 void CreateAccountJob::info(const SignOn::IdentityInfo &info)
0201 {
0202     qDebug() << "Info:";
0203     qDebug() << "\tId:" << info.id();
0204     qDebug() << "\tcaption:" << info.caption();
0205     qDebug() << "\towner:" << info.owner();
0206     qDebug() << "\tuserName:" << info.userName();
0207 
0208     if (!m_done) {
0209         return;
0210     }
0211 
0212     m_account->selectService();
0213 
0214     if (m_account->displayName().isEmpty()) {
0215         if (info.userName().isEmpty()) {
0216             // info.userName() can be empty, see bug#414219
0217             m_account->setDisplayName(QStringLiteral("%1%2").arg(info.caption()).arg(info.id()));
0218         } else {
0219             m_account->setDisplayName(info.userName());
0220         }
0221     }
0222     m_account->setValue(QStringLiteral("username"), info.userName());
0223     m_account->setCredentialsId(info.id());
0224 
0225     Accounts::AuthData authData = m_accInfo->authData();
0226     m_account->setValue(QStringLiteral("auth/mechanism"), authData.mechanism());
0227     m_account->setValue(QStringLiteral("auth/method"), authData.method());
0228 
0229     QString base = QStringLiteral("auth/");
0230     base.append(authData.method());
0231     base.append(QLatin1Char('/'));
0232     base.append(authData.mechanism());
0233     base.append(QLatin1Char('/'));
0234 
0235     QVariantMap data = authData.parameters();
0236     QMapIterator<QString, QVariant> i(data);
0237     while (i.hasNext()) {
0238         i.next();
0239         m_account->setValue(base + i.key(), i.value());
0240     }
0241 
0242     const Accounts::ServiceList services = m_account->services();
0243     for (const Accounts::Service &service : services) {
0244         m_account->selectService(service);
0245         m_account->setEnabled(m_disabledServices.contains(service.name()) ? false : true);
0246     }
0247 
0248     m_account->selectService();
0249     m_account->setEnabled(true);
0250     m_account->sync();
0251     connect(m_account, &Accounts::Account::synced, this, &CreateAccountJob::emitResult);
0252 }
0253 
0254 void CreateAccountJob::sessionError(const SignOn::Error &signOnError)
0255 {
0256     if (error()) {
0257         // Guard against SignOn sending two error() signals
0258         return;
0259     }
0260     qWarning() << "Error:";
0261     qWarning() << "\t" << signOnError.message();
0262 
0263     setError(KJob::UserDefinedError);
0264     setErrorText(i18n("There was an error while trying to process the request: %1", signOnError.message()));
0265     emitResult();
0266 }
0267 
0268 void CreateAccountJob::setProviderName(const QString &name)
0269 {
0270     if (m_providerName != name) {
0271         m_providerName = name;
0272         Q_EMIT providerNameChanged();
0273     }
0274 }
0275 
0276 };