File indexing completed on 2024-05-19 04:59:15

0001 /* ============================================================
0002 * FlashCookieManager plugin for Falkon
0003 * Copyright (C) 2014-2018 S. Razi Alavizadeh <s.r.alavizadeh@gmail.com>
0004 * Copyright (C) 2017-2018 David Rosca <nowrep@gmail.com>
0005 *
0006 * This program is free software: you can redistribute it and/or modify
0007 * it under the terms of the GNU General Public License as published by
0008 * the Free Software Foundation, either version 3 of the License, or
0009 * (at your option) any later version.
0010 *
0011 * This program is distributed in the hope that it will be useful,
0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 * GNU General Public License for more details.
0015 *
0016 * You should have received a copy of the GNU General Public License
0017 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018 * ============================================================ */
0019 #include "fcm_plugin.h"
0020 #include "browserwindow.h"
0021 #include "pluginproxy.h"
0022 #include "mainapplication.h"
0023 #include "fcm_dialog.h"
0024 #include "abstractbuttoninterface.h"
0025 #include "tabbedwebview.h"
0026 #include "fcm_notification.h"
0027 #include "datapaths.h"
0028 #include "../config.h"
0029 #include "statusbar.h"
0030 #include "navigationbar.h"
0031 
0032 #include <QTimer>
0033 #include <QSettings>
0034 #include <QDir>
0035 #include <QMenu>
0036 
0037 #if defined(Q_OS_WIN) || defined(Q_OS_OS2)
0038 #include <QProcessEnvironment>
0039 #endif
0040 
0041 const int refreshInterval = 60 * 1000;
0042 
0043 class FCM_Button : public AbstractButtonInterface
0044 {
0045     Q_OBJECT
0046 public:
0047     explicit FCM_Button(QObject *parent = nullptr)
0048         : AbstractButtonInterface(parent)
0049     {
0050     }
0051 
0052     QString id() const override
0053     {
0054         return QSL("fcm-icon");
0055     }
0056 
0057     QString name() const override
0058     {
0059         return tr("Flash Cookie Manager button");
0060     }
0061 };
0062 
0063 FCM_Plugin::FCM_Plugin()
0064     : QObject()
0065 {
0066 }
0067 
0068 void FCM_Plugin::init(InitState state, const QString &settingsPath)
0069 {
0070     m_settingsPath = settingsPath;
0071 
0072     connect(mApp->plugins(), &PluginProxy::mainWindowCreated, this, &FCM_Plugin::mainWindowCreated);
0073     connect(mApp->plugins(), &PluginProxy::mainWindowDeleted, this, &FCM_Plugin::mainWindowDeleted);
0074 
0075     m_timer = new QTimer(this);
0076     m_timer->setInterval(refreshInterval);
0077     connect(m_timer, &QTimer::timeout, this, &FCM_Plugin::autoRefresh);
0078 
0079     // start timer if needed
0080     startStopTimer();
0081 
0082     if (state == StartupInitState && readSettings().value(QL1S("deleteAllOnStartExit")).toBool()) {
0083         loadFlashCookies();
0084 
0085         removeAllButWhitelisted();
0086     }
0087 
0088     if (state == LateInitState) {
0089         const auto windows = mApp->windows();
0090         for (BrowserWindow* window : windows) {
0091             mainWindowCreated(window);
0092         }
0093     }
0094 }
0095 
0096 void FCM_Plugin::unload()
0097 {
0098     if (m_fcmDialog) {
0099         m_fcmDialog->close();
0100     }
0101 
0102     if (mApp->isClosing() && readSettings().value(QL1S("deleteAllOnStartExit")).toBool()) {
0103         removeAllButWhitelisted();
0104     }
0105 
0106     const auto windows = mApp->windows();
0107     for (BrowserWindow* window : windows) {
0108         mainWindowDeleted(window);
0109     }
0110 
0111     delete m_fcmDialog;
0112 }
0113 
0114 bool FCM_Plugin::testPlugin()
0115 {
0116     return (QString::fromLatin1(Qz::VERSION) == QLatin1String(FALKON_VERSION));
0117 }
0118 
0119 void FCM_Plugin::showSettings(QWidget* parent)
0120 {
0121     Q_UNUSED(parent)
0122 
0123     showFlashCookieManager();
0124     m_fcmDialog->showPage(2);
0125 }
0126 
0127 void FCM_Plugin::populateExtensionsMenu(QMenu* menu)
0128 {
0129     auto* showFCM = new QAction(QIcon(QSL(":/flashcookiemanager/data/flash-cookie-manager.png")), tr("Flash Cookie Manager"), menu);
0130     connect(showFCM, &QAction::triggered, this, &FCM_Plugin::showFlashCookieManager);
0131     menu->addAction(showFCM);
0132 }
0133 
0134 void FCM_Plugin::setFlashCookies(const QList<FlashCookie> &flashCookies)
0135 {
0136     m_flashCookies = flashCookies;
0137 }
0138 
0139 QList<FlashCookie> FCM_Plugin::flashCookies()
0140 {
0141     if (m_flashCookies.isEmpty()) {
0142         loadFlashCookies();
0143     }
0144     return m_flashCookies;
0145 }
0146 
0147 QStringList FCM_Plugin::newCookiesList()
0148 {
0149     return m_newCookiesList;
0150 }
0151 
0152 void FCM_Plugin::clearNewOrigins()
0153 {
0154     m_newCookiesList.clear();
0155 }
0156 
0157 void FCM_Plugin::clearCache()
0158 {
0159     m_flashCookies.clear();
0160 }
0161 
0162 bool FCM_Plugin::isBlacklisted(const FlashCookie &flashCookie)
0163 {
0164     return readSettings().value(QL1S("flashCookiesBlacklist")).toStringList().contains(flashCookie.origin);
0165 }
0166 
0167 bool FCM_Plugin::isWhitelisted(const FlashCookie &flashCookie)
0168 {
0169     return readSettings().value(QL1S("flashCookiesWhitelist")).toStringList().contains(flashCookie.origin);
0170 }
0171 
0172 void FCM_Plugin::removeAllButWhitelisted()
0173 {
0174     for (const FlashCookie &flashCookie : std::as_const(m_flashCookies)) {
0175         if (isWhitelisted(flashCookie)) {
0176             continue;
0177         }
0178 
0179         removeCookie(flashCookie);
0180     }
0181 }
0182 
0183 QString FCM_Plugin::sharedObjectDirName() const
0184 {
0185     if (flashPlayerDataPath().contains(QL1S("macromedia"), Qt::CaseInsensitive) ||
0186             !flashPlayerDataPath().contains(QL1S("/.gnash"), Qt::CaseInsensitive)) {
0187         return QLatin1String(QL1S("/#SharedObjects/"));
0188     }
0189     else {
0190         return QLatin1String(QL1S("/SharedObjects/"));
0191     }
0192 }
0193 
0194 QString FCM_Plugin::flashPlayerDataPath() const
0195 {
0196     return DataPaths::currentProfilePath() + QSL("/Pepper Data/Shockwave Flash/WritableRoot/");
0197 }
0198 
0199 QVariantHash FCM_Plugin::readSettings() const
0200 {
0201     if (m_settingsHash.isEmpty()) {
0202         m_settingsHash.insert(QL1S("autoMode"), QVariant(false));
0203         m_settingsHash.insert(QL1S("deleteAllOnStartExit"), QVariant(false));
0204         m_settingsHash.insert(QL1S("notification"), QVariant(false));
0205         m_settingsHash.insert(QL1S("flashCookiesWhitelist"), QVariant());
0206         m_settingsHash.insert(QL1S("flashCookiesBlacklist"), QVariant());
0207 
0208         QSettings settings(m_settingsPath + QL1S("/extensions.ini"), QSettings::IniFormat);
0209         settings.beginGroup(QL1S("FlashCookieManager"));
0210         QVariantHash::iterator i = m_settingsHash.begin();
0211         while (i != m_settingsHash.end()) {
0212             *i = settings.value(i.key(), i.value());
0213             ++i;
0214         }
0215 
0216         settings.endGroup();
0217     }
0218 
0219     return m_settingsHash;
0220 }
0221 
0222 void FCM_Plugin::writeSettings(const QVariantHash &hashSettings)
0223 {
0224     m_settingsHash = hashSettings;
0225 
0226     QSettings settings(m_settingsPath + QL1S(QL1S("/extensions.ini")), QSettings::IniFormat);
0227     settings.beginGroup(QL1S("FlashCookieManager"));
0228     QVariantHash::const_iterator i = m_settingsHash.constBegin();
0229     while (i != m_settingsHash.constEnd()) {
0230         settings.setValue(i.key(), i.value());
0231         ++i;
0232     }
0233 
0234     settings.endGroup();
0235 
0236     startStopTimer();
0237 }
0238 
0239 void FCM_Plugin::removeCookie(const FlashCookie &flashCookie)
0240 {
0241     if (m_flashCookies.contains(flashCookie)) {
0242         m_flashCookies.removeOne(flashCookie);
0243         if (QFile(flashCookie.path + QL1C('/') + flashCookie.name).remove()) {
0244             QDir dir(flashCookie.path);
0245             dir.rmpath(flashCookie.path);
0246         }
0247     }
0248 }
0249 
0250 void FCM_Plugin::autoRefresh()
0251 {
0252     if (m_fcmDialog && m_fcmDialog->isVisible()) {
0253         return;
0254     }
0255 
0256     QList<FlashCookie> oldflashCookies = m_flashCookies;
0257     loadFlashCookies();
0258     QStringList newCookieList;
0259 
0260     for (const FlashCookie &flashCookie : std::as_const(m_flashCookies)) {
0261         if (isBlacklisted(flashCookie)) {
0262             removeCookie(flashCookie);
0263             continue;
0264         }
0265 
0266         if (isWhitelisted(flashCookie)) {
0267             continue;
0268         }
0269 
0270         bool newCookie = true;
0271         for (const FlashCookie &oldFlashCookie : std::as_const(oldflashCookies)) {
0272             if (QString(oldFlashCookie.path + oldFlashCookie.name) ==
0273                     QString(flashCookie.path + flashCookie.name)) {
0274                 newCookie = false;
0275                 break;
0276             }
0277         }
0278 
0279         if (newCookie) {
0280             newCookieList << flashCookie.path + QL1C('/') + flashCookie.name;
0281         }
0282     }
0283 
0284     if (!newCookieList.isEmpty() && readSettings().value(QL1S("notification")).toBool()) {
0285         m_newCookiesList << newCookieList;
0286         BrowserWindow* window = mApp->getWindow();
0287         if (!window) {
0288             return;
0289         }
0290         TabbedWebView* weView = window->weView();
0291         if (!weView) {
0292             return;
0293         }
0294 
0295         auto* notif = new FCM_Notification(this, newCookieList.size());
0296         weView->addNotification(notif);
0297     }
0298 }
0299 
0300 void FCM_Plugin::showFlashCookieManager()
0301 {
0302     if (!m_fcmDialog) {
0303         m_fcmDialog = new FCM_Dialog(this);
0304     }
0305 
0306     m_fcmDialog->refreshView();
0307     m_fcmDialog->showPage(0);
0308     m_fcmDialog->show();
0309     m_fcmDialog->raise();
0310 }
0311 
0312 void FCM_Plugin::mainWindowCreated(BrowserWindow *window)
0313 {
0314     window->statusBar()->addButton(createStatusBarIcon(window));
0315     window->navigationBar()->addToolButton(createStatusBarIcon(window));
0316 }
0317 
0318 void FCM_Plugin::mainWindowDeleted(BrowserWindow *window)
0319 {
0320     if (!window) {
0321         return;
0322     }
0323 
0324     if (m_fcmDialog && m_fcmDialog->parent() == window) {
0325         m_fcmDialog->setParent(nullptr);
0326     }
0327 
0328     window->statusBar()->removeButton(m_statusBarIcons.value(window));
0329     window->navigationBar()->removeToolButton(m_statusBarIcons.value(window));
0330 
0331     delete m_statusBarIcons.value(window);
0332     m_statusBarIcons.remove(window);
0333 }
0334 
0335 void FCM_Plugin::startStopTimer()
0336 {
0337     if (readSettings().value(QL1S("autoMode")).toBool()) {
0338         if (!m_timer->isActive()) {
0339             if (m_flashCookies.isEmpty()) {
0340                 loadFlashCookies();
0341             }
0342 
0343             m_timer->start();
0344         }
0345     }
0346     else {
0347         m_timer->stop();
0348     }
0349 }
0350 
0351 AbstractButtonInterface* FCM_Plugin::createStatusBarIcon(BrowserWindow* mainWindow)
0352 {
0353     if (m_statusBarIcons.contains(mainWindow)) {
0354         return m_statusBarIcons.value(mainWindow);
0355     }
0356 
0357     auto* icon = new FCM_Button(this);
0358     icon->setIcon(QIcon(QSL(":/flashcookiemanager/data/flash-cookie-manager.png")));
0359     icon->setTitle(tr("Flash Cookie Manager"));
0360     icon->setToolTip(tr("Show Flash Cookie Manager"));
0361     connect(icon, &AbstractButtonInterface::clicked, this, &FCM_Plugin::showFlashCookieManager);
0362 
0363     m_statusBarIcons.insert(mainWindow, icon);
0364 
0365     return icon;
0366 }
0367 
0368 void FCM_Plugin::loadFlashCookies()
0369 {
0370     m_flashCookies.clear();
0371     loadFlashCookies(flashPlayerDataPath());
0372 }
0373 
0374 void FCM_Plugin::loadFlashCookies(QString path)
0375 {
0376     QDir solDir(path);
0377     QStringList entryList = solDir.entryList();
0378     entryList.removeAll(QL1S("."));
0379     entryList.removeAll(QL1S(".."));
0380 
0381     for (QString entry : std::as_const(entryList)) {
0382         if (path.endsWith(QL1S("#SharedObjects")) && entry == QL1S("#AppContainer")) {
0383             // specific to IE and Windows
0384             continue;
0385         }
0386 
0387         path.replace(QL1C('\\'), QL1C('/'));
0388         QFileInfo entryInfo(path + QL1C('/') + entry);
0389         if (entryInfo.isDir()) {
0390             loadFlashCookies(entryInfo.filePath());
0391         }
0392         else if (entryInfo.isFile() && entryInfo.suffix() == QL1S("sol")) {
0393             insertFlashCookie(entryInfo.filePath());
0394         }
0395     }
0396 }
0397 
0398 void FCM_Plugin::insertFlashCookie(const QString &path)
0399 {
0400     QFile solFile(path);
0401     if (!solFile.open(QFile::ReadOnly)) {
0402         return;
0403     }
0404 
0405     QByteArray file = solFile.readAll();
0406     for (int i = 0; i < file.size(); ++i) {
0407         if (!((file.at(i) >= 'a' && file.at(i) <= 'z') || (file.at(i) >= 'A' && file.at(i) <= 'Z') ||
0408               (file.at(i) >= '0' && file.at(i) <= '9'))) {
0409             file[i] = ' ';
0410         }
0411     }
0412 
0413     QString fileStr = QString(QString::fromUtf8(file));
0414     fileStr = fileStr.split(QL1C('.'), Qt::SkipEmptyParts).join(QL1S("\n"));
0415 
0416     QFileInfo solFileInfo(solFile);
0417 
0418     FlashCookie flashCookie;
0419     flashCookie.contents = fileStr;
0420     flashCookie.name = solFileInfo.fileName();
0421     flashCookie.path = solFileInfo.canonicalPath();
0422     flashCookie.size = (int)solFile.size();
0423     flashCookie.lastModification = solFileInfo.lastModified();
0424     flashCookie.origin = extractOriginFrom(path);
0425 
0426     m_flashCookies << flashCookie;
0427 }
0428 
0429 QString FCM_Plugin::extractOriginFrom(const QString &path)
0430 {
0431     QString origin = path;
0432     if (path.startsWith(flashPlayerDataPath() + sharedObjectDirName())) {
0433         origin.remove(flashPlayerDataPath() + sharedObjectDirName());
0434         if (origin.indexOf(QL1C('/')) != -1) {
0435             origin.remove(0, origin.indexOf(QL1C('/')) + 1);
0436         }
0437     }
0438     else if (path.startsWith(flashPlayerDataPath() + QL1S("/macromedia.com/support/flashplayer/sys/"))) {
0439         origin.remove(flashPlayerDataPath() + QL1S("/macromedia.com/support/flashplayer/sys/"));
0440         if (origin == QL1S("settings.sol")) {
0441             return tr("!default");
0442         }
0443         else if (origin.startsWith(QL1C('#'))) {
0444             origin.remove(0, 1);
0445         }
0446     }
0447     else {
0448         origin.clear();
0449     }
0450 
0451     int index = origin.indexOf(QL1C('/'));
0452     if (index == -1) {
0453         return tr("!other");
0454     }
0455     origin.remove(index, origin.size());
0456     if (origin == QL1S("localhost") || origin == QL1S("local")) {
0457         origin = QL1S("!localhost");
0458     }
0459 
0460     return origin;
0461 }
0462 
0463 #include "fcm_plugin.moc"