From 4a856bc600d1819e01c797881e0591810737c2fd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Enar=20V=C3=A4ikene?= Date: Tue, 26 Jul 2011 15:08:02 +0300 Subject: [PATCH] Added the PswStorage module. This module stores data for password generation and allows lookups using the name of the password. The module also acts as an item model for auto-completion of the name field. --- src/apps/PswGen/CMakeLists.txt | 2 +- src/apps/PswGen/Storage/CMakeLists.txt | 39 ++++ src/apps/PswGen/Storage/iStorage | 1 + src/apps/PswGen/Storage/istorage.h | 133 ++++++++++++++ src/apps/PswGen/Storage/lib.h | 30 +++ src/apps/PswGen/Storage/module.cpp | 241 +++++++++++++++++++++++++ src/apps/PswGen/Storage/module.h | 156 ++++++++++++++++ src/apps/PswGen/Storage/version.h | 60 ++++++ src/apps/PswGen/Storage/version.rc | 54 ++++++ 9 files changed, 715 insertions(+), 1 deletion(-) create mode 100644 src/apps/PswGen/Storage/CMakeLists.txt create mode 100644 src/apps/PswGen/Storage/iStorage create mode 100644 src/apps/PswGen/Storage/istorage.h create mode 100644 src/apps/PswGen/Storage/lib.h create mode 100644 src/apps/PswGen/Storage/module.cpp create mode 100644 src/apps/PswGen/Storage/module.h create mode 100644 src/apps/PswGen/Storage/version.h create mode 100644 src/apps/PswGen/Storage/version.rc diff --git a/src/apps/PswGen/CMakeLists.txt b/src/apps/PswGen/CMakeLists.txt index 64a26c5..c7c1db5 100644 --- a/src/apps/PswGen/CMakeLists.txt +++ b/src/apps/PswGen/CMakeLists.txt @@ -2,4 +2,4 @@ set(eVaf_INCLUDE ${eVaf_INCLUDE} ${CMAKE_SOURCE_DIR}/src/apps/PswGen) add_subdirectory(GUI) add_subdirectory(Generator) -#add_subdirectory(Storage) +add_subdirectory(Storage) diff --git a/src/apps/PswGen/Storage/CMakeLists.txt b/src/apps/PswGen/Storage/CMakeLists.txt new file mode 100644 index 0000000..13722c3 --- /dev/null +++ b/src/apps/PswGen/Storage/CMakeLists.txt @@ -0,0 +1,39 @@ +# Name of the target +set(TARGET PswStorage) + +# Qt modules +set(QT_USE_QTSQL TRUE) +set(QT_DONT_USE_QTGUI TRUE) +include(${QT_USE_FILE}) + +# Needed for exporting symbols +add_definitions(-DPSWGEN_STORAGE_LIBRARY) + +# Include files +include_directories(${eVaf_INCLUDE}) + +# Required eVaf libraries +set(eVaf_LIBRARIES CommonLib PluginsLib) + +# Source files +set(SRCS + module.cpp +) + +# Header files for the meta-object compiler +set(MOC_HDRS + module.h +) + +# Version info resource file for Windows builds +if(WIN32) + set(SRCS ${SRCS} version.rc) +endif(WIN32) + +qt4_wrap_cpp(MOC_SRCS ${MOC_HDRS}) + +add_library(${TARGET} SHARED ${SRCS} ${MOC_SRCS}) + +target_link_libraries(${TARGET} ${QT_LIBRARIES} ${eVaf_LIBRARIES}) + +install(TARGETS ${TARGET} DESTINATION bin) diff --git a/src/apps/PswGen/Storage/iStorage b/src/apps/PswGen/Storage/iStorage new file mode 100644 index 0000000..2e4711c --- /dev/null +++ b/src/apps/PswGen/Storage/iStorage @@ -0,0 +1 @@ +#include "istorage.h" diff --git a/src/apps/PswGen/Storage/istorage.h b/src/apps/PswGen/Storage/istorage.h new file mode 100644 index 0000000..6560553 --- /dev/null +++ b/src/apps/PswGen/Storage/istorage.h @@ -0,0 +1,133 @@ +/** + * @file PswGen/Storage/istorage.h + * @brief Interface for password storage modules + * @author Enar Vaikene + * + * Copyright (c) 2011 Enar Vaikene + * + * This file is part of the eVaf C++ cross-platform application development framework. + * + * This file can be used under the terms of the GNU General Public License + * version 3.0 as published by the Free Software Foundation and appearing in + * the file LICENSE included in the packaging of this file. Please review the + * the following information to ensure the GNU General Public License version + * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html. + * + * Alternatively, this file may be used in accordance with the Commercial License + * Agreement provided with the Software. + */ + +#ifndef __PSWGEN_STORAGE_ISTORAGE_H +# define __PSWGEN_STORAGE_ISTORAGE_H + +#include "lib.h" + +#include +#include +#include +#include + +class QAbstractItemModel; + +namespace eVaf { +namespace PswGen { + +namespace Storage { + +/** + * Data stored for every password. + */ +class PSWGEN_STORAGE_EXPORT Data : public QSharedData +{ +public: + + Data() + : QSharedData() + , mModified(false) + , mLength(0) + , mFlags(0) + {} + + Data(int l, uint f = 0) + : QSharedData() + , mModified(false) + , mLength(l) + , mFlags(f) + {} + + /// Length of the generated password + inline int length() const { return mLength; } + inline void setLength(int value) + { + if (mLength != value) { + mLength = value; + mModified = true; + } + } + + /// Optional flags for the password generator + inline uint flags() const { return mFlags; } + inline void setFlags(uint value) + { + if (mFlags != value) { + mFlags = value; + mModified = true; + } + } + + /// Flag indicating that some fields are modified + bool modified() const { return mModified; } + + /// Resets the modified flag + void reset() { mModified = false; } + + +private: + + bool mModified; + int mLength; + uint mFlags; + +}; + +} // eVaf::PswGen::Storage + +/** + * Password storage interface. + * + * This interface is used to store options that were used to generate strong passwords. + */ +struct iStorage +{ + + /** + * Saves the data record + * @param name Name of the password + * @param data Data for the password + * @return True if ok; false if failed + */ + virtual bool save(QString const & name, QExplicitlySharedDataPointer data) = 0; + + /** + * Returns a data record by the name + * @param name Name of the password + * @return Shared data pointer of the stored data record or invalid if not found + */ + virtual QExplicitlySharedDataPointer query(QString const & name) const = 0; + + /** + * Returns an item model with the names of all the stored passwords + * + * This function returns an item model with the names of all the stored passwords. Use the item + * model for auto completion. + */ + virtual QAbstractItemModel * autoCompletionModel() = 0; + +}; + +} // namespace eVaf::PswGen +} // namespace eVaf + +Q_DECLARE_INTERFACE(eVaf::PswGen::iStorage, "eVaf.PswGen.iStorage/1.0") + +#endif // istorage.h diff --git a/src/apps/PswGen/Storage/lib.h b/src/apps/PswGen/Storage/lib.h new file mode 100644 index 0000000..2dbfa67 --- /dev/null +++ b/src/apps/PswGen/Storage/lib.h @@ -0,0 +1,30 @@ +/** + * @file PswGen/Storage/lib.h + * @author Enar Vaikene + * + * Copyright (c) 2011 Enar Vaikene + * + * This file is part of the eVaf C++ cross-platform application development framework. + * + * This file can be used under the terms of the GNU General Public License + * version 3.0 as published by the Free Software Foundation and appearing in + * the file LICENSE included in the packaging of this file. Please review the + * the following information to ensure the GNU General Public License version + * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html. + * + * Alternatively, this file may be used in accordance with the Commercial License + * Agreement provided with the Software. + */ + +#ifndef __PSWGEN_STORAGE_LIB_H +# define __PSWGEN_STORAGE_LIB_H + +#include + +#if defined(PSWGEN_STORAGE_LIBRARY) +# define PSWGEN_STORAGE_EXPORT Q_DECL_EXPORT +#else +# define PSWGEN_STORAGE_EXPORT Q_DECL_IMPORT +#endif + +#endif // libgen.h diff --git a/src/apps/PswGen/Storage/module.cpp b/src/apps/PswGen/Storage/module.cpp new file mode 100644 index 0000000..b0fd6af --- /dev/null +++ b/src/apps/PswGen/Storage/module.cpp @@ -0,0 +1,241 @@ +/** + * @file PswGen/Storage/module.cpp + * @brief Implementation of the iStorage interface + * @author Enar Vaikene + * + * Copyright (c) 2011 Enar Vaikene + * + * This file is part of the eVaf C++ cross-platform application development framework. + * + * This file can be used under the terms of the GNU General Public License + * version 3.0 as published by the Free Software Foundation and appearing in + * the file LICENSE included in the packaging of this file. Please review the + * the following information to ensure the GNU General Public License version + * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html. + * + * Alternatively, this file may be used in accordance with the Commercial License + * Agreement provided with the Software. + */ + +#include "module.h" +#include "version.h" + +#include +#include +#include +#include + +#include +#include + +VER_EXPORT_VERSION_INFO() +Q_EXPORT_PLUGIN2(VER_MODULE_NAME_STR, eVaf::PswGen::Storage::Module) + +using namespace eVaf; +using namespace eVaf::PswGen; +using namespace eVaf::PswGen::Storage; + +//------------------------------------------------------------------- + +Module::Module() + : Plugins::iPlugin() + , mReady(false) +{ + setObjectName(QString("%1.%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__)); + + mStorage = new Internal::StorageImpl; + + EVAF_INFO("%s created", qPrintable(objectName())); +} + +Module::~Module() +{ + delete mStorage; + + EVAF_INFO("%s destroyed", qPrintable(objectName())); +} + +bool Module::init(QString const & args) +{ + Q_UNUSED(args); + + if (!mStorage->init()) + return false; + + mReady = true; + + EVAF_INFO("%s initialized", qPrintable(objectName())); + + return true; +} + +void Module::done() +{ + mReady = false; + + mStorage->done(); + + EVAF_INFO("%s finalized", qPrintable(objectName())); +} + + +//------------------------------------------------------------------- + +using namespace eVaf::PswGen::Storage::Internal; + +char const * const StorageImpl::DbConnectionName = "PswGenDB"; + +char const * const StorageImpl::DbName = "PswGen.sqlite"; + +StorageImpl::StorageImpl() + : QAbstractListModel() +{ + setObjectName(QString("%1.iGenerator").arg(VER_MODULE_NAME_STR)); + + EVAF_INFO("%s created", qPrintable(objectName())); +} + +StorageImpl::~StorageImpl() +{ + EVAF_INFO("%s destroyed", qPrintable(objectName())); +} + +bool StorageImpl::init() +{ + EVAF_INFO("%s initialized", qPrintable(objectName())); + + // Open the database + if (!QSqlDatabase::contains(DbConnectionName)) { + // No database connection yet + mDb = QSqlDatabase::addDatabase("QSQLITE", DbConnectionName); + mDb.setDatabaseName(Common::iEnv::instance()->dataRootDir() + DbName); + if (!mDb.open()) { + QSqlError err = mDb.lastError(); + EVAF_ERROR("Failed to open database : %s", qPrintable(err.text())); + return false; + } + } + else { + // Database connection already exists + mDb = QSqlDatabase::database(DbConnectionName); + } + + // Create tables if necessary + if (!createTables()) + return false; + + // Load data + if (!loadData()) + return false; + + /// Register our interface + Common::iRegistry::instance()->registerInterface("iStorage", this); + + return true; +} + +void StorageImpl::done() +{ + mData.clear(); + EVAF_INFO("%s finalized", qPrintable(objectName())); +} + +bool StorageImpl::save(QString const & name, QExplicitlySharedDataPointer data) +{ + EVAF_TEST_X(data, "Data cannot be null"); + EVAF_TEST_X(!name.isEmpty(), "Name cannot be empty"); + + // Is it an update or a new data record? + if (mData.constFind(name) != mData.constEnd()) { + // This is an update + if (data->modified()) { + QSqlQuery q(mDb); + if (!q.exec(QString("UPDATE data SET length = \'%1\', flags = \'%2\' WHERE name = \'%3\';").arg(data->length()).arg(data->flags()).arg(name))) { + QSqlError err = mDb.lastError(); + EVAF_ERROR("Failed to update \'%s\' : %s", qPrintable(name), qPrintable(err.text())); + return false; + } + } + } + else { + // Store to the database + QSqlQuery q(mDb); + if (!q.exec(QString("INSERT INTO data (name, length, flags) VALUES ('\%1\', %2, %3);").arg(name).arg(data->length()).arg(int(data->flags())))) { + QSqlError err = mDb.lastError(); + EVAF_ERROR("Failed to insert \'%s\' : %s", qPrintable(name), qPrintable(err.text())); + return false; + } + + // Store also into the local hash + mData.insert(name, data); + + // Reset the model + reset(); + } + + data->reset(); + + return true; +} + +QExplicitlySharedDataPointer StorageImpl::query(QString const & name) const +{ + QMap >::const_iterator it = mData.constFind(name); + if (it != mData.constEnd()) + return it.value(); + else + return QExplicitlySharedDataPointer(); +} + +QVariant StorageImpl::data(QModelIndex const & index, int role) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= mData.size() || index.column() != 0) + return QVariant(); + + if (role == Qt::EditRole || role == Qt::DisplayRole) + return mData.keys().at(index.row()); + + return QVariant(); +} + +bool StorageImpl::createTables() +{ + QSqlQuery q(mDb); + if (!q.exec("SELECT name FROM sqlite_master WHERE type=\'table\' AND name=\'data\';")) { + QSqlError err = mDb.lastError(); + EVAF_ERROR("Failed to query database : %s", qPrintable(err.text())); + return false; + } + + if (q.isActive() && q.isSelect() && q.first()) + return true; // We already have a table called 'data' + + // Create the 'data' table + if (!q.exec("CREATE TABLE data (name text primary key not null, length integer, flags integer);")) { + QSqlError err = mDb.lastError(); + EVAF_ERROR("Failed to create table \'data\' : %s", qPrintable(err.text())); + return false; + } + + return true; +} + +bool StorageImpl::loadData() +{ + QSqlQuery q(mDb); + if (!q.exec("SELECT name, length, flags FROM data;")) { + QSqlError err = mDb.lastError(); + EVAF_ERROR("Failed to query database : %s", qPrintable(err.text())); + return false; + } + + while (q.next()) { + QString name = q.value(0).toString(); + QExplicitlySharedDataPointer data(new Storage::Data(q.value(1).toInt(), uint(q.value(2).toInt()))); + mData.insert(name, data); + } + + reset(); + + return true; +} diff --git a/src/apps/PswGen/Storage/module.h b/src/apps/PswGen/Storage/module.h new file mode 100644 index 0000000..ae784e9 --- /dev/null +++ b/src/apps/PswGen/Storage/module.h @@ -0,0 +1,156 @@ +/** + * @file PswGen/Storage/module.h + * @brief Implementation of the iStorage interface + * @author Enar Vaikene + * + * Copyright (c) 2011 Enar Vaikene + * + * This file is part of the eVaf C++ cross-platform application development framework. + * + * This file can be used under the terms of the GNU General Public License + * version 3.0 as published by the Free Software Foundation and appearing in + * the file LICENSE included in the packaging of this file. Please review the + * the following information to ensure the GNU General Public License version + * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html. + * + * Alternatively, this file may be used in accordance with the Commercial License + * Agreement provided with the Software. + */ + +#ifndef __PSWGEN_STORAGE_MODULE_H +# define __PSWGEN_STORAGE_MODULE_H + +#include "istorage.h" + +#include + +#include +#include +#include +#include +#include + + +namespace eVaf { +namespace PswGen { + +/// Module that stores options for strong passwords +namespace Storage { + +/// Internal implementation of the Storage module +namespace Internal { + class StorageImpl; +} // namespace eVaf::PswGen::Storage::Internal + +/** + * Module implementing the iStorage interface. + */ +class Module : public Plugins::iPlugin +{ + Q_OBJECT + +public: + + Module(); + + virtual ~Module(); + + virtual bool init(QString const & args); + + virtual void done(); + + virtual bool isReady() const { return mReady; } + + +private: // Members + + /// Flag indicating that the module is ready + bool mReady; + + /// iStorage interface instance + Internal::StorageImpl * mStorage; + +}; + + +namespace Internal { + +/** + * iStorage interface implementation. + * + * Implements the iStorage interface using a simple file storage. + */ + +class StorageImpl : public QAbstractListModel, public iStorage +{ + Q_OBJECT + Q_INTERFACES(eVaf::PswGen::iStorage) + +public: + + StorageImpl(); + + virtual ~StorageImpl(); + + bool init(); + + void done(); + + /* + iStorage interface + */ + + virtual bool save(QString const & name, QExplicitlySharedDataPointer data); + + virtual QExplicitlySharedDataPointer query(QString const & name) const; + + virtual QAbstractItemModel * autoCompletionModel() { return this; } + + /* + QAbstractListModel methods + */ + + virtual int rowCount(QModelIndex const & parent) const { return mData.count(); } + + virtual QVariant data(QModelIndex const & index, int role = Qt::DisplayRole) const; + + +private: // Members + + /// Name of the database connection + static char const * const DbConnectionName; + + /// Name of the database file without path + static char const * const DbName; + + /// Database connection + QSqlDatabase mDb; + + /// List of name/data pairs + QMap > mData; + + +private: // Methods + + /** + * Creates database tables if necessary + * @return True if ok; false if failed + */ + bool createTables(); + + /** + * Loads data from the database + * @return True if ok; false if failed + */ + bool loadData(); + +}; + +} // namespace eVaf::PswGen::Storage::Internal + + +} // namespace eVaf::PswGen::Storage +} // namespace eVaf::PswGen +} // namespace eVaf + +#endif // module.h diff --git a/src/apps/PswGen/Storage/version.h b/src/apps/PswGen/Storage/version.h new file mode 100644 index 0000000..33eaa3d --- /dev/null +++ b/src/apps/PswGen/Storage/version.h @@ -0,0 +1,60 @@ +/** + * @file PswGen/Storage/version.h + * @brief Version information for eVaf modules + * @author Enar Vaikene + * + * Copyright (c) 2011 Enar Vaikene + * + * This file is part of the eVaf C++ cross-platform application development framework. + * + * This file can be used under the terms of the GNU General Public License + * version 3.0 as published by the Free Software Foundation and appearing in + * the file LICENSE included in the packaging of this file. Please review the + * the following information to ensure the GNU General Public License version + * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html. + * + * Alternatively, this file may be used in accordance with the Commercial License + * Agreement provided with the Software. + */ + +#ifndef __PSWGEN_STORAGE_VERSION_H +#define __PSWGEN_STORAGE_VERSION_H + +#include + +/** + * Module/library version number in the form major,minor,release,build + */ +#define VER_FILE_VERSION 0,1,1,1 + +/** + * Module/library version number in the string format (shall end with \0) + */ +#define VER_FILE_VERSION_STR "0.1.1.1\0" + +/** + * Module/library name (shall end with \0) + */ +#define VER_MODULE_NAME_STR "PswStorage\0" + +/** + * Module type (see version_rc.h for all the types) + */ +#define VER_MODULE_TYPE MT_GENERIC + +/** + * Module type in the string format (see version_rc for all the types) + */ +#define VER_MODULE_TYPE_STR MT_GENERIC + +/** + * Original file name for windows (shall end with \0) + */ +#define VER_ORIGINAL_FILE_NAME_STR "PswStorage.dll\0" + +/** + * Description of the module/library (shall end with \0) + */ +#define VER_FILE_DESCRIPTION_STR "Module that stores data for generating strong passwords.\0" + +#endif // version.h diff --git a/src/apps/PswGen/Storage/version.rc b/src/apps/PswGen/Storage/version.rc new file mode 100644 index 0000000..33672fb --- /dev/null +++ b/src/apps/PswGen/Storage/version.rc @@ -0,0 +1,54 @@ +/** + * @file PswGen/Generator/version.rc + * @brief Windows resource file with module/library version information. + * @author Enar Vaikene + * + * Copyright (c) 2011 Enar Vaikene + * + * This file is part of the eVaf C++ cross-platform application development framework. + * + * This file can be used under the terms of the GNU General Public License + * version 3.0 as published by the Free Software Foundation and appearing in + * the file LICENSE included in the packaging of this file. Please review the + * the following information to ensure the GNU General Public License version + * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html. + * + * Alternatively, this file may be used in accordance with the Commercial License + * Agreement provided with the Software. + */ + +#include "version.h" +#include +#include + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VER_FILE_VERSION + PRODUCTVERSION VER_PRODUCT_VERSION + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0x0L + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", VER_COMPANY_NAME_STR + VALUE "FileDescription", VER_FILE_DESCRIPTION_STR + VALUE "FileVersion", VER_FILE_VERSION_STR + VALUE "LegalCopyright", VER_LEGAL_COPYRIGHT_STR + VALUE "OriginalFilename", VER_ORIGINAL_FILE_NAME_STR + VALUE "ProductName", VER_PRODUCT_NAME_STR + VALUE "ProductVersion", VER_PRODUCT_VERSION_STR + VALUE "Build Date", VER_PRODUCT_DATE_STR + VALUE "Module Name", VER_MODULE_NAME_STR + VALUE "Module Type", VER_MODULE_TYPE_STR + END + END + END -- 2.45.0