Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

UltraLight Software Registration Control

0.00/5 (No votes)
10 Apr 2012 1  
Add this control to your app to require users to register so you can collect email addreses

Introduction

Here's a simple WPF control which will check to see if an installed app is “registered”. If not, it will prompt the user for an email address and then email a software key to the user (to ensure a valid email address) all with no Website Required!

Background

Suppose you have written a little app and you're happy distributing it as freeware but you'd really like to know who was actually using it. You don't want to spend a time creating a website and adding the infrastructure of a “real” registration system.

Here's a way to do it which can be included in your app. You don't need a website at all and you'll collect the email addresses of people who use your app. The control relies on the fact that any computer can be an email sender and can send email via any email account as long as it has the credentials. In this example, I am using gmail.

When your user starts your application, they will see a dialog like this:

When the user keys in his/her email address, the application creates the key and acts as the email client to generate the email and send it to the user. The user enters the key and the application verifies that it matches the key it generated internally. If it does, it is stored in a file (in users/username/AppData) so the user doesn't need to reenter the key.

As an added feature, the key generation algorithm incorporates the creation date/time of the folder containing the .exe file which is most likely the installation date/time of the application. This prevents a user from posting an email/key combination which can be shared by all—every installation requires a different key.

I call this "UltraLight" because it trades off some degree of robustness in favor of simplicity.

A possible source of problems is gmail. If there are lots of registrations coming to gmail from all over the world, gmail's anti-span sender may block the account and I'll have to change the code to fix it. I have reviewed gmail's rules and don't think there is any violation but you should probably review them as well here

If you are expecting lots of registrations, you should choose an email service which will give you better control (and may not be free).

A real strength of this approach is that because the key is actually generated by the client, it can utilize data which is unique to the client machine without sending it anywhere (which would be a privacy issue). In this case, I use the installation date to generate the key but I don't send the date anywhere, just the key. This means I can store the registration email/key on the client machine in clear text without a security issue.

As the code is written, it is all or nothing; the unregistered user can't start the program. With some minor modification, your app could offer degraded operation to the unregistered user instead.

Using the code

In order to use the source code, you need to follow the steps below. To try it out, just download and run the .EXE file and send yourself a registration key via my gmail account (“SendKey3145”).

To adapt the control for your own application:

  1. Create an email account for your app on GMail. This is the account which will send out the registration emails to your users.

  2. Send yourself an email to make sure the account is working.

  3. Include the following code near the beginning of your program, I put it in the MainWindow constructor:

    if (!RegistrationWindow.IsRegistered())
    {
        RegistrationWindow rw = new RegistrationWindow();
        if (rw.ShowDialog() != true)
        {
            this.Close();
            return;
        }
    }
  1. If you want “degraded” operation for unregistered users, don't close the window but instead, check for RegistrationWindow.IsRegistered() anywhere in your program to enable features.

  2. Edit the source code to include the gmail account name and password. Also, edit the privacy statement, email body, etc.

  3. BE SURE TO OBFUSCATE! Otherwise your application will include your email account name and password in clear text for anyone with a disassembler.

  4. When your users use your application, it will send them the registration key via the gmail account.

  5. You can log on to the gmail account at any time and see the registration messages which have been sent out and use the email addresses appropriately.

Points of Interest

How to send mail: This is pretty straightforward using the SmtpClient object -- just set up all the parameters and call Send.

public void SendMail(string toMail, string subject, string body)
{
    var fromAddress = new MailAddress(senderEmailAddress, senderEmailFrom);
    var toAddress = new MailAddress(toMail, toMail);
    
    var smtp = new SmtpClient
    {
        Host = "smtp.gmail.com",
        Port = 587,
        EnableSsl = true,
        DeliveryMethod = SmtpDeliveryMethod.Network,
        UseDefaultCredentials = false,
        Credentials = new NetworkCredential(fromAddress.Address, senderEmailPassword),
        Timeout = 10000
    };
    var message = new MailMessage(fromAddress, toAddress){Subject = subject,Body = 
    try
    {
        this.Cursor = Cursors.Wait;
        smtp.Send(message);
        this.Cursor = Cursors.Arrow;
        MessageBox.Show("Registration key requested.  Check your email (and junk email)  key.");
    }
    catch (Exception e)
    {
        this.Cursor = Cursors.Arrow;
        MessageBox.Show("Email request failed: " + e.Message);
    }
}

How to store/retrieve data in AppData: This was a bit tricky, the MSDN documentation is obscure and the various answers on the web are often in conflict. The trick is that if you are using VS 2010 (I am using VS Professional), if you right-click the project file and select "Properties", then go to the "Settings" tab, VS will do most of the work for you. You will need to edit the Settings.Settings file (back on the solution explorer under "Properties" and add the keys you intend to use. If you don't the program will throw an unhelpful XmlParser exception if you access a key which is not already in the file. I have put try-catch blocks around the accesses. You'll also need to edit "AssemblyInfo.cs" file and put in reasonble AssemblyCompany, AssemblyProduct, and AssemblyVersion values as these are used in creating the file folders under the AppData folder.

private static void SetEmailAndKey(string email, string key)
{
    try
    {
        Properties.Settings.Default["RegistrationEmail"] = email;
        Properties.Settings.Default["RegistrationKey"] = key;
        Properties.Settings.Default.Save();
    }
    catch (Exception e)
    {
        MessageBox.Show("Failure writing app configuration file.  " + e.Message);// debug the configuration file setup
    }
}
private static void GetEmailAndKey(out string email, out string key)
{
    try
    {
        email = (string)Properties.Settings.Default["RegistrationEmail"];
        key = (string)Properties.Settings.Default["RegistrationKey"];
    }
    catch (Exception e)
    {
        email = "";
        key = "";
        MessageBox.Show("Failure reading app configuration file.  "+e.Message);// just  the configuration file setup
    }
}

How to get the file installation date: I thought that using the file installation date would be useful but after installation, an .exe file still carries its own creation date. Using the creation date of the containing folder seems to do the trick and would allow the user to change versions without having to change keys.

static public DateTime InstallationDate
{
    get
    {
        string codeBase = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
        UriBuilder uri = new UriBuilder(codeBase);
        string path = Uri.UnescapeDataString(uri.Path);
        string directory = System.IO.Path.GetDirectoryName(path);
        return System.IO.File.GetCreationTime(directory);
    }
}

How (not) to generate a software key: There's not much point in being cryptic in a program when you distribute the source code and I suggest you replace this one with something a bit more sophisticated. The important thing to follow is that the software key is some mangling of the input string which contains the email address and some additional local information. I pass in a concatenation of the email address and the intallation date/time.

string calculatedKey = CreateKey(email + InstallationDate.ToLongTimeString());
public static string CreateKey(string inputString)
{
    int i = 0;
    foreach (char c in inputString)
    {
        i += (int)c;
    }
    return i.ToString();
}

History

Initial revision: 4/9/12.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here