Next: 04 - Generator Module, Previous: 02 - Preparations

eVaf Tutorial

03 - Generator Module

In this section we write the Generator module. According to the specification, the Generator module has to generate strong passwords in such a way that by feeding the module with the same input data we always get the same password.

iGenerator interface

We start by defining the interface for the module and create the file igenerator.h in the src/apps/PswGen/Generator directory:

/**
 * @file src/apps/PswGen/Generator/igenerator.h
 */
#ifndef __PSWGEN_GENERATOR_IGENERATOR_H
#  define __PSWGEN_GENERATOR_IGENERATOR_H

#endif // igenerator.h

We need to include some Qt header files -- QObject is almost always needed and QString we need for input data and generated passwords:

#include <QObject>
#include <QString>

To avoid potential name collisions with other existing or future modules, we use the eVaf::PswGen namespace for this application:

namespace eVaf {
namespace PswGen {

} // namespace eVaf::PswGen
} // namespace eVaf

We call the interface class iGenerator. For pure abstract classes I personally prefer using the struct keyword, but class works as well if you remember to add the public keyword to make methods in the class public.

struct iGenerator
{

};

We add functionality to the interface and according to the specification we need two functions -- one that generates passwords and another that returns the maximum length of the password:

virtual QString generatePassword(QString const & name, QString const & masterPassword, int length, uint flags = 0) const = 0;

virtual int maxLength() const = 0;

I am training myself to use the style of writing declarations like "QString const &", which refers to a non-mutable QString object similar to "int maxLength() const", which is a function that does not modify the object's data members. Feel free to use the traditional way of writing "const QString &" if this looks weird to you.

We use the Q_DECLARE_INTERFACE macro to add Qt meta-data to the interface. eVaf interfaces are type-casted using the qobject_cast<>() template function and it requires meta-data to verify type and version of the interface. The Q_DECLARE_INTERFACE macro has to be outside of any namespaces and we add it to the end of the file:

Q_DECLARE_INTERFACE(eVaf::PswGen::iGenerator, "eVaf.PswGen.iGenerator/1.0")

This is pretty much all we need to add to the iGenerator interface and here is the final file:

/**
 * @file src/apps/PswGen/Generator/igenerator.h
 */

#ifndef __PSWGEN_GENERATOR_IGENERATOR_H
#  define __PSWGEN_GENERATOR_IGENERATOR_H

#include <QObject>
#include <QString>

namespace eVaf {
namespace PswGen {

/// Password generator interface.
struct iGenerator
{
    /// Generates a strong password
    virtual QString generatePassword(QString const & name, QString const & masterPassword, int length, uint flags = 0) const = 0;

    /// Returns the maximum length of generated passwords
    virtual int maxLength() const = 0;

};

} // namespace eVaf::PswGen
} // namespace eVaf

Q_DECLARE_INTERFACE(eVaf::PswGen::iGenerator, "eVaf.PswGen.iGenerator/1.0")

#endif // igenerator.h

As a final touch, we create a file called iGenerator with the following content:

#include "igenerator.h"

With this file in place other modules can use #include "Generator/iGenerator" instead of #include "Generator/igenerator.h" similar to other eVaf and Qt include files.

Generator module

Now we write the Generator module itself. The module class has to be derived from the Plugins::iPlugin interface class with or without the Plugins::iPluginFactory factory class.

The Plugins::iPluginFactory factory class should be used when more than one plugins are implemented by the same module. The factory class takes care of creating individual plugins whenever they are instantiated. This module implements only one plugin and we opt to the implementation without the factory class.

Create the module.h header file in the src/apps/PswGen/Generator directory:

/**
 * @file src/apps/PswGen/Generator/module.h
 */
#ifndef __PSWGEN_GENERATOR_MODULE_H
#  define __PSWGEN_GENERATOR_MODULE_H

#endif // module.h

As this is a simple module, we define all our class in this single header file. This includes the implementation of the iGenerator interface and also the plugin itself. Se we need to include header files for the iGenerator and iPlugin interfaces:

#include "igenerator.h"
#include <Plugins/iPlugin>

We are going to put every public class in this module into the eVaf::PswGen::Generator namespace and private classes into the eVaf::PswGen::Generator::Private namespace:

namespace eVaf {
namespace PswGen {

/// Module that generates strong passwords using cryptographic methods
namespace Generator {

/// Internal implementation of the Generator module
namespace Internal {

} // namespace eVaf::PswGen::Generator::Internal
} // namespace eVaf::PswGen::Generator
} // namespace eVaf::PswGen
} // namespace eVaf

We call the class that implements the module simply Module. This is a public class and goes into the eVaf::PswGen::Generator namespace.

class Module : public Plugins::iPlugin
{
    Q_OBJECT

public:

    Module();

    virtual ~Module();

}

The iPlugin interface has three pure virtual methods that we need to implement in our class -- init(), done() and isReady(). Since this simple module is always ready, we can return always true in the isReady() function. More complex modules can use a private mReady variable, which they set to true once all the initialization is done.

virtual bool init(QString const & args);

virtual void done();

virtual bool isReady() const { return true; }

We need the iGenerator interface object in this module and add it to the private members section:

private: // Members

    /// iGenerator interface instance
    Internal::GeneratorImpl * mGenerator;

As the Internal::GeneratorImpl class is not declared yet, we need to add this forward declaration before the Module class:

namespace Internal {
    class GeneratorImpl;
} // namespace eVaf::PswGen::Generator::Internal

Then we can move forward and implement the iGenerator interface, which we already happened to call GeneratorImpl. This class goes into the eVaf::PswGen::Generator::Internal namespace.

The GeneratorImpl class needs to be derived both from QObject and from iGenerator. We also have to use the Q_INTERFACES macro to include Qt meta-data for the iGenerator interface:

class GeneratorImpl : public QObject, public iGenerator
{
    Q_OBJECT
    Q_INTERFACES(eVaf::PswGen::iGenerator)

public:

    GeneratorImpl();

    virtual ~GeneratorImpl();

    virtual QString generatePassword(QString const & name, QString const & masterPassword, int length, uint flags = 0) const;

    virtual int maxLength() const;
};

Here is the final module.h file:

/**
 * @file src/apps/PswGen/Generator/module.h
 */

#ifndef __PSWGEN_GENERATOR_MODULE_H
#  define __PSWGEN_GENERATOR_MODULE_H

#include "igenerator.h"

#include <Plugins/iPlugin>

#include <QObject>
#include <QString>

namespace eVaf {
namespace PswGen {

/// Module that generates strong passwords using cryptographic methods
namespace Generator {

/// Internal implementation of the Generator module
namespace Internal {
    class GeneratorImpl;
} // namespace eVaf::PswGen::Generator::Internal

/// Plugins::iPlugin interface implementation.
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 true; }

private: // Members

    /// iGenerator interface instance
    Internal::GeneratorImpl * mGenerator;
};

namespace Internal {

/// iGenerator interface implementation.
class GeneratorImpl : public QObject, public iGenerator
{
    Q_OBJECT
    Q_INTERFACES(eVaf::PswGen::iGenerator)

public:

    GeneratorImpl();

    virtual ~GeneratorImpl();

    virtual QString generatePassword(QString const & name, QString const & masterPassword, int length, uint flags = 0) const;

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

} // namespace eVaf::PswGen::Generator::Internal

} // namespace eVaf::PswGen::Generator
} // namespace eVaf::PswGen
} // namespace eVaf

#endif // module.h

Continue implementing the Generator Module.