/* This file is part of the KDE project SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "workerintegration.h" #include "config-dolphin.h" #include "dolphinmainwindow.h" #include "dolphinpackageinstaller.h" #include "dolphinviewcontainer.h" #include #include #include #include #include #include #include using namespace Admin; /** Free file-local functions */ namespace { /** @returns the translated name of the actAsAdminAction. */ QString actionName() { return i18nc("@action:inmenu", "Act as Administrator"); }; /** @returns the default keyboard shortcut of the actAsAdminAction. */ QKeySequence actionDefaultShortcut() { return Qt::CTRL | Qt::SHIFT | Qt::ALT | Qt::Key_A; }; /** @returns whether any worker for the protocol "admin" is available. */ bool isWorkerInstalled() { return KProtocolInfo::isKnownProtocol(QStringLiteral("admin")); } } void Admin::guideUserTowardsInstallingAdminWorker() { if (!isWorkerInstalled()) { std::cout << qPrintable( xi18nc("@info:shell", "Dolphin requires %1 to manage system-controlled files, but it is not installed." "Press %2 to install %1 or %3 to cancel.", ADMIN_WORKER_PACKAGE_NAME, QKeySequence{Qt::Key_Enter}.toString(QKeySequence::NativeText), QKeySequence{Qt::CTRL | Qt::Key_C}.toString(QKeySequence::NativeText))); std::cin.ignore(); /// Installing admin worker DolphinPackageInstaller adminWorkerInstaller{ADMIN_WORKER_PACKAGE_NAME, QUrl(QStringLiteral("appstream://org.kde.kio.admin")), isWorkerInstalled}; QObject::connect(&adminWorkerInstaller, &KJob::result, [](KJob *job) { if (job->error()) { std::cout << qPrintable(job->errorString()) << std::endl; exit(1); } }); adminWorkerInstaller.exec(); } } void Admin::guideUserTowardsUsingAdminWorker() { KuitSetup *kuitSetup = &Kuit::setupForDomain("dolphin"); kuitSetup->setTagPattern(QStringLiteral("numberedlist"), QStringList{}, Kuit::RichText, ki18nc("tag-format-pattern rich", "
    %1
")); kuitSetup->setTagPattern(QStringLiteral("numbereditem"), QStringList{}, Kuit::RichText, ki18nc("tag-format-pattern rich", "
  • %1
  • ")); KMessageBox::information( nullptr, xi18nc("@info", "Make use of your administrator rights in Dolphin:" "Navigate to the file or folder you want to change." "Activate the \"%1\" action either under Open Menu|More|View or Menu Bar|View." "Default shortcut: %2" "After authorization you can manage files as an administrator.", actionName(), actionDefaultShortcut().toString(QKeySequence::NativeText)), i18nc("@title:window", "How to Administrate"), "", KMessageBox::WindowModal); } QString Admin::warningMessage() { return xi18nc( "@info", "You are about to use administrator privileges. While acting as an administrator you can change or replace any file or folder on this system. " "This includes items which are critical for this system to function.You are able to delete every users' data on this " "computer and to break this installation beyond repair. Adding just one letter in a folder or file name or its contents can " "render a system unbootable.There is probably not going to be another warning even if you are about to break this " "system.You might want to backup files and folders before proceeding."); } namespace { /** The only WorkerIntegration object that is ever constructed. It is only ever accessed directly from within this file. */ WorkerIntegration *instance = nullptr; } WorkerIntegration::WorkerIntegration(DolphinMainWindow *parent, QAction *actAsAdminAction) : QObject{parent} , m_actAsAdminAction{actAsAdminAction} { Q_CHECK_PTR(parent); Q_CHECK_PTR(actAsAdminAction); connect(parent, &DolphinMainWindow::urlChanged, this, &WorkerIntegration::updateActAsAdminAction); connect(actAsAdminAction, &QAction::triggered, this, &WorkerIntegration::toggleActAsAdmin); } void WorkerIntegration::createActAsAdminAction(KActionCollection *actionCollection, DolphinMainWindow *dolphinMainWindow) { Q_ASSERT(!instance /* We never want to construct more than one instance, however in automatic testing sometimes multiple DolphinMainWindows are created, so this assert is diluted to accommodate for that: */ || instance->parent() != dolphinMainWindow); if (isWorkerInstalled()) { QAction *actAsAdminAction = actionCollection->addAction(QStringLiteral("act_as_admin")); actAsAdminAction->setText(actionName()); actAsAdminAction->setIcon(QIcon::fromTheme(QStringLiteral("system-switch-user"))); actAsAdminAction->setCheckable(true); actionCollection->setDefaultShortcut(actAsAdminAction, actionDefaultShortcut()); instance = new WorkerIntegration(dolphinMainWindow, actAsAdminAction); } } QAction *WorkerIntegration::FriendAccess::actAsAdminAction() { return instance->m_actAsAdminAction; } void WorkerIntegration::toggleActAsAdmin() { auto dolphinMainWindow = static_cast(parent()); QUrl url = dolphinMainWindow->activeViewContainer()->urlNavigator()->locationUrl(); if (url.scheme() == QStringLiteral("admin")) { url.setScheme(QStringLiteral("file")); dolphinMainWindow->changeUrl(url); return; } else if (url.scheme() != QStringLiteral("file")) { return; } bool risksAccepted = !KMessageBox::shouldBeShownContinue(warningDontShowAgainName); if (!risksAccepted) { KMessageDialog warningDialog{KMessageDialog::QuestionTwoActions, warningMessage(), dolphinMainWindow}; warningDialog.setCaption(i18nc("@title:window", "Risks of Acting as an Administrator")); warningDialog.setIcon(QIcon::fromTheme(QStringLiteral("security-low"))); warningDialog.setButtons(KGuiItem{i18nc("@action:button", "I Understand and Accept These Risks"), QStringLiteral("data-warning")}, KStandardGuiItem::cancel()); warningDialog.setDontAskAgainText(i18nc("@option:check", "Do not warn me about these risks again")); risksAccepted = warningDialog.exec() != 4 /* Cancel */; if (warningDialog.isDontAskAgainChecked()) { KMessageBox::saveDontShowAgainContinue(warningDontShowAgainName); } if (!risksAccepted) { updateActAsAdminAction(); // Uncheck the action return; } } url.setScheme(QStringLiteral("admin")); dolphinMainWindow->changeUrl(url); } void WorkerIntegration::updateActAsAdminAction() { if (instance) { const QString currentUrlScheme = static_cast(instance->parent())->activeViewContainer()->url().scheme(); if (currentUrlScheme == QStringLiteral("file")) { instance->m_actAsAdminAction->setEnabled(true); instance->m_actAsAdminAction->setChecked(false); } else if (currentUrlScheme == QStringLiteral("admin")) { instance->m_actAsAdminAction->setEnabled(true); instance->m_actAsAdminAction->setChecked(true); } else { instance->m_actAsAdminAction->setEnabled(false); } } } #include "moc_workerintegration.cpp"