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"