From: Enar Väikene Date: Tue, 26 Jul 2011 12:08:02 +0000 (+0300) Subject: Added the PswStorage module. X-Git-Url: https://vaikene.ee/gitweb/gitweb.cgi?p=evaf;a=commitdiff_plain;h=4a856bc600d1819e01c797881e0591810737c2fd 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. --- 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