X-Git-Url: https://vaikene.ee/gitweb/gitweb.cgi?p=evaf;a=blobdiff_plain;f=www%2Fpswgen04.html;fp=www%2Fpswgen04.html;h=df82cb0b946a970ac9d1335fee64c395576e05c1;hp=0000000000000000000000000000000000000000;hb=368818c22af812ac35f5ff69423522dbd54d37ed;hpb=3352f7acc232104985807b9f470cb12bcb2b47c2 diff --git a/www/pswgen04.html b/www/pswgen04.html new file mode 100644 index 0000000..df82cb0 --- /dev/null +++ b/www/pswgen04.html @@ -0,0 +1,306 @@ + + + + + + eVaf Tutorial - 04 - Generator Module + + + + + + + + + +

eVaf Tutorial

+ +

04 - Generator Module

+ +

Now we are going to implement all the classes declared in the module.h. Create the module.cpp file + in the src/apps/PswGen/Generator directory. We obviously include the module.h header file, but also + the QtCore header file for any non-GUI Qt classes.

+ +
/**
+ * @file src/apps/PswGen/Generator/module.cpp
+ */
+
+#include "module.h"
+
+#include <QtCore>
+ +

All the eVaf modules need to include version information. This is common for all the modules and we can simply + copy existing version info files from another eVaf module:

+ +
evaf/src/apps/PswGen/Generator $ cp ../../../plugins/SdiWindow/version.{h,rc} .
+ +

The version.h file contains version information for the module. The version.rc is for Windows + builds only and embeds the same version information into the dll or exe file. Modify the copied version.h + file for our new module. The version.rc file uses the values from the version.h and does not + need to be touched.

+ +
/**
+ * @file src/apps/PswGen/Generator/version.h
+ */
+#ifndef __PSWGEN_GENERATOR_VERSION_H
+#define __PSWGEN_GENERATOR_VERSION_H
+
+#include <version_rc.h>
+
+/**
+ * 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             "PswGen\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      "PswGen.dll\0"
+
+/**
+ * Description of the module/library (shall end with \0)
+ */
+#define VER_FILE_DESCRIPTION_STR         "Module that generates strong passwords using MD5 hashes.\0"
+
+#endif // version.h
+ +

Then include the version info file in the module.cpp file and use the VER_EXPORT_VERSION_INFO() macro + to export version information from the module. This macro defines a public function that all the eVaf modules export and + is used to collect version information from them. In your modules you only need to modify the version.h file and then + use the VER_EXPORT_VERSION_INFO() macro once somewhere in your code.

+ +
#include "version.h"
+
+VER_EXPORT_VERSION_INFO()
+ +

We make our life easier with several using namespace keywords:

+ +
using namespace eVaf;
+using namespace eVaf::PswGen;
+using namespace eVaf::PswGen::Generator;
+ +

The Module class needs to instantiate the iGenerator interface in the constructor. We also need to set + the QObject's name property to the name of the plugin by combining the name of the module with the name of the class. + While the application would work without the name property, it makes our life much easier if the name property is set.

+ +

Finally, we output an info message telling that the object was created. Every eVaf module and class is expected to + output info messages when they are created, destroyed, initialized or destroyed.

+ +
Module::Module()
+    : Plugins::iPlugin()
+{
+    setObjectName(QString("%1.%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__));
+
+    mGenerator = new Internal::GeneratorImpl;
+
+    EVAF_INFO("%s created", qPrintable(objectName()));
+}
+ +

The EVAF_INFO macro comes from the Common/iLogger header file ane we need to include it:

+ +
#include <Common/iLogger>
+ +

The destructor should delete the iGenerator interface object, which we created in the constructor. The common + rule is that any resources allocated in the constructor shall be released in the destructor, preferrably in the opposite + order, ie. the first resource allocated in the constructor is released last in the destructor. + +

Module::~Module()
+{
+    delete mGenerator;
+
+    EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+ +

We also need to implement init() and done() functions, which are used to initialize and finalize modules. + They are similar to the constructor and destructor with two major differences:

+
    +
  1. The init() function can fail and return false to indicate a failure. eVaf does not use exceptions and + this is the only way for a module to fail without terminating the whole application. A failed module will be disabled + and the rest of the application can still run if it can.
  2. +
  3. eVaf modules are loaded in two steps. At first, all the modules are created, which means that all the objects + are constructed. Only then will eVaf call init() functions meaning that when the init() function is + called, all the modules are already loaded and instantiated. Interfaces and resources from other modules that might be not + available when the object is created, are available when the init() function is called.
  4. +
+ +

The rule for init() and done() functions is the same than for constructors and destructors -- any resource + allocated in the init() function shall be released in the done() function and preferrably in the opposite + order.

+ +

This simple module needs no extra resources to be allocated and our init() and done() functions can be + the following:

+ +
bool Module::init(QString const & args)
+{
+    Q_UNUSED(args);
+
+    EVAF_INFO("%s initialized", qPrintable(objectName()));
+
+    return true;
+}
+
+void Module::done()
+{
+    EVAF_INFO("%s finalized", qPrintable(objectName()));
+}
+ +

We continue by implementing the iGenerator interface. There are no resources to be allocated in the constructor + and we just set the QObject's name property and output the info message.

+ +

We also register the iGenerator interface in the global registry so that other modules can query for it and + use our interface. This is done by using the Common::iRegistry interface, which we need to include:

+ +
#include <Common/iRegistry>
+ +

The GeneratorImpl class was declared in the eVaf::PswGen::Generator::Internal namespace, so we need + another using namespace keyword before the implementation of the class:

+ +
using namespace eVaf::PswGen::Generator::Internal;
+
+GeneratorImpl::GeneratorImpl()
+    : iGenerator()
+{
+    setObjectName(QString("%1.iGenerator").arg(VER_MODULE_NAME_STR));
+
+    Common::iRegistry::instance()->registerInterface("iGenerator", this);
+
+    EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+GeneratorImpl::~GeneratorImpl()
+{
+    EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+ +

Finally, we write the generatePassword function that does the actual job of the module.

+ +

We use the MD5 cryptographic hash function to calculate a hash value over the name and masterPassword values. + The result, which is a binary blob, needs to be convert into something that can be used as a password and we use base 64 encoding + for this and cut the result to the requested length:

+ +
QString GeneratorImpl::generatePassword(QString const & name, QString const & masterPassword, int length, uint flags) const
+{
+    Q_UNUSED(flags);
+
+    QByteArray inputString = QString("%1%2").arg(name).arg(masterPassword).toLatin1();
+    QCryptographicHash hash(QCryptographicHash::Md5);
+    hash.addData(inputString);
+    QByteArray result = hash.result().toBase64();
+    if (length > 0)
+        return result.left(length);
+    else
+        return result;
+}
+ +

We also know now the maximum length of the generated password, which is 24. Go back to the module.h header file and + modify the GeneratorImpl::maxLength() function:

+ +
virtual int maxLength() const { return 24; }
+ +

Here is the final module.cpp file:

+ +
/**
+ * @file src/apps/PswGen/Generator/module.cpp
+ */
+
+#include "module.h"
+#include "version.h"
+
+#include <Common/iLogger>
+#include <Common/iRegistry>
+
+#include <QtCore>
+
+VER_EXPORT_VERSION_INFO()
+Q_EXPORT_PLUGIN2(VER_MODULE_NAME_STR, eVaf::PswGen::Generator::Module)
+
+using namespace eVaf;
+using namespace eVaf::PswGen;
+using namespace eVaf::PswGen::Generator;
+
+Module::Module()
+    : Plugins::iPlugin()
+{
+    setObjectName(QString("%1.%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__));
+
+    mGenerator = new Internal::GeneratorImpl;
+
+    EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+Module::~Module()
+{
+    delete mGenerator;
+
+    EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+
+bool Module::init(QString const & args)
+{
+    Q_UNUSED(args);
+
+    EVAF_INFO("%s initialized", qPrintable(objectName()));
+
+    return true;
+}
+
+void Module::done()
+{
+    EVAF_INFO("%s finalized", qPrintable(objectName()));
+}
+
+using namespace eVaf::PswGen::Generator::Internal;
+
+GeneratorImpl::GeneratorImpl()
+    : iGenerator()
+{
+    setObjectName(QString("%1.iGenerator").arg(VER_MODULE_NAME_STR));
+
+    Common::iRegistry::instance()->registerInterface("iGenerator", this);
+
+    EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+GeneratorImpl::~GeneratorImpl()
+{
+    EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+
+QString GeneratorImpl::generatePassword(QString const & name, QString const & masterPassword, int length, uint flags) const
+{
+    Q_UNUSED(flags);
+
+    QByteArray inputString = QString("%1%2").arg(name).arg(masterPassword).toLatin1();
+    QCryptographicHash hash(QCryptographicHash::Md5);
+    hash.addData(inputString);
+    QByteArray result = hash.result().toBase64();
+    if (length > 0)
+        return result.left(length);
+    else
+        return result;
+}
+ +

Next -- 05 - Building Generator Module.

+ + +