X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserPC.git;a=blobdiff_plain;f=src%2Fdatabases%2FCookiesDatabase.cpp;fp=src%2Fdatabases%2FCookiesDatabase.cpp;h=adc4f1ba2c108362e59bbcda99276a54c0e4f219;hp=0000000000000000000000000000000000000000;hb=cd1c3d0483b9026736fdcb151d90dda872d8a400;hpb=588db73b94af7b596b0e532f4557aa8b6c41f5c3 diff --git a/src/databases/CookiesDatabase.cpp b/src/databases/CookiesDatabase.cpp new file mode 100644 index 0000000..adc4f1b --- /dev/null +++ b/src/databases/CookiesDatabase.cpp @@ -0,0 +1,377 @@ +/* + * Copyright © 2022 Soren Stoutner . + * + * This file is part of Privacy Browser PC . + * + * Privacy Browser PC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Privacy Browser PC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Privacy Browser PC. If not, see . + */ + +// Application headers. +#include "CookiesDatabase.h" + +// Define the private static schema constants. +const int CookiesDatabase::SCHEMA_VERSION = 0; + +// Define the public static database constants. +const QString CookiesDatabase::CONNECTION_NAME = "cookies_database"; +const QString CookiesDatabase::COOKIES_TABLE = "cookies"; + +// Define the public static database field names. +const QString CookiesDatabase::_ID = "_id"; +const QString CookiesDatabase::DOMAIN = "domain"; +const QString CookiesDatabase::NAME = "name"; +const QString CookiesDatabase::PATH = "path"; +const QString CookiesDatabase::EXPIRATION_DATE = "expiration_date"; +const QString CookiesDatabase::HTTP_ONLY = "http_only"; +const QString CookiesDatabase::SECURE = "secure"; +const QString CookiesDatabase::VALUE = "value"; + +// Construct the class. +CookiesDatabase::CookiesDatabase() {} + +void CookiesDatabase::addDatabase() +{ + // Add the cookies database. + QSqlDatabase cookiesDatabase = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), CONNECTION_NAME); + + // Set the database name. + cookiesDatabase.setDatabaseName(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/cookies.db"); + + // Open the database. + if (cookiesDatabase.open()) // Opening the database succeeded. + { + // Check to see if the cookies table already exists. + if (cookiesDatabase.tables().contains(COOKIES_TABLE)) // The cookies table exists. + { + // Query the database schema version. + QSqlQuery schemaVersionQuery = cookiesDatabase.exec(QStringLiteral("PRAGMA user_version")); + + // Move to the first record. + schemaVersionQuery.first(); + + // Get the current schema versin. + int currentSchemaVersion = schemaVersionQuery.value(0).toInt(); + + // Check to see if the schema has been updated. + if (currentSchemaVersion < SCHEMA_VERSION) + { + // Run the schema update code. + switch (currentSchemaVersion) + { + // Upgrade code here. + } + + // Update the schema version. + cookiesDatabase.exec("PRAGMA user_version = " + QString::number(SCHEMA_VERSION)); + } + } + else // The cookies table does not exist. + { + // Instantiate a create table query. + QSqlQuery createTableQuery(cookiesDatabase); + + // Prepare the create table query. + createTableQuery.prepare("CREATE TABLE " + COOKIES_TABLE + "(" + + _ID + " INTEGER PRIMARY KEY, " + + DOMAIN + " TEXT NOT NULL, " + + NAME + " TEXT NOT NULL, " + + PATH + " TEXT NOT NULL, " + + EXPIRATION_DATE + " TEXT, " + + HTTP_ONLY + " INTEGER NOT NULL DEFAULT 0, " + + SECURE + " INTEGER NOT NULL DEFAULT 0, " + + VALUE + " TEXT NOT NULL)" + ); + + // Execute the query. + if (!createTableQuery.exec()) + { + // Log any errors. + qDebug().noquote().nospace() << "Error creating table: " << cookiesDatabase.lastError(); + } + + // Set the schema version. + cookiesDatabase.exec("PRAGMA user_version = " + QString::number(SCHEMA_VERSION)); + } + } + else // Opening the database failed. + { + // Write the last database error message to the debug output. + qDebug().noquote().nospace() << "Error opening database: " << cookiesDatabase.lastError(); + } +} + +void CookiesDatabase::addCookie(const QNetworkCookie &cookie) +{ + // Get a handle for the cookies database. + QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME); + + // Check to see if the cookie already exists in the database. + if (isDurable(cookie)) // The cookie already exists. + { + // Update the existing cookie. + updateCookie(cookie); + } + else // The cookie doesn't already exist. + { + // Instantiate an add cookie query. + QSqlQuery addCookieQuery(cookiesDatabase); + + // Prepare the add cookie query. + addCookieQuery.prepare("INSERT INTO " + COOKIES_TABLE + " (" + DOMAIN + ", " + NAME + ", " + PATH + ", " + EXPIRATION_DATE + ", " + HTTP_ONLY + ", " + SECURE + ", " + VALUE + ") " + "VALUES (:domain, :name, :path, :expiration_date, :http_only, :secure, :value)" + ); + + // Bind the values. + addCookieQuery.bindValue(":domain", cookie.domain()); + addCookieQuery.bindValue(":name", QString(cookie.name())); + addCookieQuery.bindValue(":path", cookie.path()); + addCookieQuery.bindValue(":expiration_date", cookie.expirationDate()); + addCookieQuery.bindValue(":http_only", cookie.isHttpOnly()); + addCookieQuery.bindValue(":secure", cookie.isSecure()); + addCookieQuery.bindValue(":value", QString(cookie.value())); + + // Execute the query. + addCookieQuery.exec(); + } +} + +void CookiesDatabase::deleteAllCookies() +{ + // Get a handle for the cookies database. + QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME); + + // Instantiate a delete all cookies query. + QSqlQuery deleteAllCookiesQuery(cookiesDatabase); + + // Prepare the delete all cookies query. + deleteAllCookiesQuery.prepare("DELETE FROM " + COOKIES_TABLE); + + // Execute the query. + deleteAllCookiesQuery.exec(); +} + +void CookiesDatabase::deleteCookie(const QNetworkCookie &cookie) +{ + // Get a handle for the cookies database. + QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME); + + // Instantiate a delete cookie query. + QSqlQuery deleteCookieQuery(cookiesDatabase); + + // Prepare the delete cookie query. + deleteCookieQuery.prepare("DELETE FROM " + COOKIES_TABLE + " WHERE " + DOMAIN + " = :domain AND " + NAME + " = :name AND " + PATH + " = :path"); + + // Bind the values. + deleteCookieQuery.bindValue(":domain", cookie.domain()); + deleteCookieQuery.bindValue(":name", QString(cookie.name())); + deleteCookieQuery.bindValue(":path", cookie.path()); + + // Execute the query. + deleteCookieQuery.exec(); +} + +QList* CookiesDatabase::getCookies() +{ + // Get a handle for the cookies database. + QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME); + + // Instantiate a cookies query. + QSqlQuery cookiesQuery(cookiesDatabase); + + // Set the query to be forward only. + cookiesQuery.setForwardOnly(true); + + // Prepare the cookies query. + cookiesQuery.prepare("SELECT * FROM " + COOKIES_TABLE); + + // Execute the query. + cookiesQuery.exec(); + + // Create a cookie list. + QList *cookieListPointer = new QList; + + // Populate the cookie list. + while (cookiesQuery.next()) + { + // Create a cookie. + QNetworkCookie *cookiePointer = new QNetworkCookie(); + + // Populate the cookie. + cookiePointer->setDomain(cookiesQuery.value(DOMAIN).toString()); + cookiePointer->setName(cookiesQuery.value(NAME).toString().toUtf8()); + cookiePointer->setPath(cookiesQuery.value(PATH).toString()); + cookiePointer->setExpirationDate(QDateTime::fromString(cookiesQuery.value(EXPIRATION_DATE).toString(), Qt::ISODate)); + cookiePointer->setHttpOnly(cookiesQuery.value(HTTP_ONLY).toBool()); + cookiePointer->setSecure(cookiesQuery.value(SECURE).toBool()); + cookiePointer->setValue(cookiesQuery.value(VALUE).toString().toUtf8()); + + // Add the cookie to the list. + cookieListPointer->append(cookiePointer); + } + + // Return the cookie list. + return cookieListPointer; +} + +bool CookiesDatabase::isDurable(const QNetworkCookie &cookie) +{ + // Get a handle for the cookies database. + QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME); + + // Instantiate an is durable query. + QSqlQuery isDurableQuery(cookiesDatabase); + + // Set the query to be forward only. + isDurableQuery.setForwardOnly(true); + + // Prepare the is durable query. + isDurableQuery.prepare("SELECT " + _ID + " FROM " + COOKIES_TABLE + " WHERE " + DOMAIN + " = :domain AND " + NAME + " = :name AND " + PATH + " = :path"); + + // Bind the values. + isDurableQuery.bindValue(":domain", cookie.domain()); + isDurableQuery.bindValue(":name", QString(cookie.name())); + isDurableQuery.bindValue(":path", cookie.path()); + + // Execute the query. + isDurableQuery.exec(); + + // Move to the first entry. + isDurableQuery.first(); + + // Return the status of the cookie in the database. + return (isDurableQuery.isValid()); +} + +bool CookiesDatabase::isUpdate(const QNetworkCookie &cookie) +{ + // Get a handle for the cookies database. + QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME); + + // Instantiate an is update query. + QSqlQuery isUpdateQuery(cookiesDatabase); + + // Prepare the is update query. + isUpdateQuery.prepare("SELECT " + EXPIRATION_DATE + " , " + HTTP_ONLY + " , " + SECURE + " , " + VALUE + " FROM " + COOKIES_TABLE + " WHERE " + DOMAIN + " = :domain AND " + + NAME + " = :name AND " + PATH + " = :path"); + + // Bind the values. + isUpdateQuery.bindValue(":domain", cookie.domain()); + isUpdateQuery.bindValue(":name", QString(cookie.name())); + isUpdateQuery.bindValue(":path", cookie.path()); + + // Execute the query. + isUpdateQuery.exec(); + + // Move to the first entry. + isUpdateQuery.first(); + + // Check to see if the cookie exists. + if (isUpdateQuery.isValid()) // The cookie exists in the database. + { + // Check to see if the cookie data has changed. + if ((QDateTime::fromString(isUpdateQuery.value(0).toString(), Qt::ISODate) != cookie.expirationDate()) || + (isUpdateQuery.value(1).toBool() != cookie.isHttpOnly()) || + (isUpdateQuery.value(2).toBool() != cookie.isSecure()) || + (isUpdateQuery.value(3).toString().toUtf8() != cookie.value())) // The cookies data has changed. + { + qDebug() << "The durable cookie data has changed."; + + // Return true. + return true; + } + else // The cookie data has not changed. + { + qDebug() << "The durable cookie data is unchanged."; + + // Return false. + return false; + } + } + else // The cookie does not exist in the database. + { + // Return false. + return false; + } +} + +void CookiesDatabase::updateCookie(const QNetworkCookie &cookie) +{ + // Get a handle for the cookies database. + QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME); + + // Create the update cookie query. + QSqlQuery updateCookieQuery(cookiesDatabase); + + // Prepare the edit cookie query. + updateCookieQuery.prepare("UPDATE " + COOKIES_TABLE + " SET " + EXPIRATION_DATE + " = :expiration_date , " + HTTP_ONLY + " = :http_only , " + SECURE + " = :secure , " + + VALUE + " = :value WHERE " + DOMAIN + " = :domain AND " + NAME + " = :name AND " + PATH + " = :path"); + + // Bind the values. + updateCookieQuery.bindValue(":domain", cookie.domain()); + updateCookieQuery.bindValue(":name", QString(cookie.name())); + updateCookieQuery.bindValue(":path", cookie.path()); + updateCookieQuery.bindValue(":expiration_date", cookie.expirationDate()); + updateCookieQuery.bindValue(":http_only", cookie.isHttpOnly()); + updateCookieQuery.bindValue(":secure", cookie.isSecure()); + updateCookieQuery.bindValue(":value", QString(cookie.value())); + + // Execute the query. + updateCookieQuery.exec(); +} + +void CookiesDatabase::updateCookie(const QNetworkCookie &oldCookie, const QNetworkCookie &newCookie) +{ + // Get a handle for the cookies database. + QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME); + + // Create the old cookie query. + QSqlQuery oldCookieQuery(cookiesDatabase); + + // Set the query to be forward only. + oldCookieQuery.setForwardOnly(true); + + // Prepare the old cookie query. + oldCookieQuery.prepare("SELECT " + _ID + " FROM " + COOKIES_TABLE + " WHERE " + DOMAIN + " = :domain AND " + NAME + " = :name AND " + PATH + " = :path"); + + // Bind the values. + oldCookieQuery.bindValue(":domain", oldCookie.domain()); + oldCookieQuery.bindValue(":name", QString(oldCookie.name())); + oldCookieQuery.bindValue(":path", oldCookie.path()); + + // Execute the query. + oldCookieQuery.exec(); + + // Move to the first entry. + oldCookieQuery.first(); + + // Create the update cookie query. + QSqlQuery updateCookieQuery(cookiesDatabase); + + // Prepare the update cookie query. + updateCookieQuery.prepare("UPDATE " + COOKIES_TABLE + " SET " + DOMAIN + " = :domain , " + NAME + " = :name , " + PATH + " = :path , " + EXPIRATION_DATE + " = :expiration_date , " + + HTTP_ONLY + " = :http_only , " + SECURE + " = :secure , " + VALUE + " = :value WHERE " + _ID + " = :id"); + + // Bind the values. + updateCookieQuery.bindValue(":id", oldCookieQuery.value(0).toLongLong()); + updateCookieQuery.bindValue(":domain", newCookie.domain()); + updateCookieQuery.bindValue(":name", QString(newCookie.name())); + updateCookieQuery.bindValue(":path", newCookie.path()); + updateCookieQuery.bindValue(":expiration_date", newCookie.expirationDate()); + updateCookieQuery.bindValue(":http_only", newCookie.isHttpOnly()); + updateCookieQuery.bindValue(":secure", newCookie.isSecure()); + updateCookieQuery.bindValue(":value", QString(newCookie.value())); + + // Execute the query. + updateCookieQuery.exec(); +}