Blog archive
RSS

Blog

The Payeezy Payment Plugin can be used a normal credit card processor.  If your merchant account has Transarmor Tokenization, it send the customer's credit card directly to First Data instead of your server, thereby reducing your exposure to PCI.  The only information your server will ever see is the token representing the customer's card.

 

Configuration

To set up the plugin, first install it like any other NopCommerce plugin.  You can use a different merchant account for every store on your site or you can set one default merchant account and have it be used for each store.  The plugin comes preconfigured with a sandbox account:

Store:  Change which store to configure.  The Default Store Settings will apply to any store that doesn't have it's own unique values.

Transaction Mode:  Authorize means the payment is only authorized and not captured immediately.  The store admin must Capture the payment on the order details screen.

Merchant Token/JS Token:  These will be provided by BitShift Web Solutions after you purchase the license and register your merchant account with First Data.

Transarmor Token: Your 4 character transarmor token.  If you don't put anything here, the plugin will take in the credit card number and process it when the order is confirmed by the customer.

Validate tokens immediately: If checked, the card will be validated on the payment form.  Otherwise the token is verified as a valid card when the order is confirmed.

Additional fee / percentage: Optional

 

Saved Cards

If you use Transarmor, your customers can choose to save their card details on your site to speed up future purchases.  Make sure to go to Widgets and enable the Payeezy widget.  This will add a menu item to the customer's account page where they can enter new cards or delete existing ones.  Only the card's token value is stored on your site.  The actual card details are secured on the Payeezy servers.

TransArmor Tokenization is a service provided by FirstData that allows you to store a credit card on FirstData's servers.  When a transaction is processed, FirstData will return a token representing the card.  The payment plugin can save this token and submit it instead of the card info on future transactions.  This enables two key features that have been added to the plugin:  card saving and recurring transactions.

If card saving is enabled in the plugin, any time a customer makes a purchase on your site, their info will be saved in the database along with the token instead of their card number.  On subsequent purchases, the customer will see their saved cards and have the option to use one instead of entering in new info.

Recurring billing can also be enabled.  The card info will be saved and the store owner can processes recurring transactions manually.  Automatic recurring transactions will still not be possible until FirstData adds them to the API.  Both options require TransArmor Tokenization to be enabled in the FirstData merchant account admin screen as seen below:

If you are using the demo version of First Data, you can make up any 4 digit token to test out the new features.  Your production account will require a specific 4 digit code that will be provided to you by First Data.

So you're ready to distribute license keys to customers that buy your plugins, but how do the plugins know that a license key is valid?  It's actually pretty easy.  The following code handles most of the work:

public bool IsLicensed(string host)
{
    var keys = GetAll();

    foreach (var key in keys)
    {
        try
        {
            string decryptedKey = _encryptionService.DecryptText(key.LicenseKey, Constants.LicenseKeySeed);
            string licensedHost = decryptedKey.Substring(1);
            if (decryptedKey[0] == 'U')
            {
                if (host == licensedHost || host == "www." + licensedHost)
                    return true;
            }
            else if (decryptedKey[0] == 'D')
            {
                if (host.EndsWith(licensedHost))
                    return true;
            }
        }
        catch { }
    }

    return false;
} 

The GetAll() function is just getting all of the license keys that the customer has purchased and saved within your plugin (I add a small CRUD table to my config page).  You want to allow them to store multiple keys because they could have multiple stores touching this plugin.  The host is passed into this function and is usually grabbed through HttpContext.Current.Request.Url.Host.

Constants.LicenseKeySeed is the same exact string as what you put into the ProductKey on your store.

License Key Plugin 01/09/2013

The License Key plugin is something I knew I had to write once I decided to start selling my First Data payment plugin.  The FirstData plugin uses a license key to verify if the store it is running on has paid for the full use.  It does this by decrypting the license key with a secret key.  The resulting string is then a letter to indicate if it's good for a single URL or the full domain followed by the URL it's enabled for.  An example for my website would be "Dbitshiftweb.com" which means the license is good for any subdomain of bitshiftweb.com.

The hassle comes in when someone decides to purchase the plugin, they expect to be able to use it right away.  They don't want to wait for me to get home from my day job so that I can create their encrypted key.  The License Key plugin solves this by subscribing to the OrderPaidEvent in NopCommerce.  Once someone completes an order that has 1 or more products that require keys, the license plugin will take their info, generate the keys, and email them immediately.  It also places them in the order notes for future reference.

I'm releasing the full source code for this plugin to the entire NopCommerce community and will explain how it works here.  You can download the plugin from it's product page here.  The plugin has 3 major areas:  The encryption key for each product, the configuration page, and generating licenses when an order is paid.

Product Key

Each plugin you will sell needs its own unique Product Key that will be used in encryption/decryption.  If you didn't use a unique key, someone could purchase Plugin A and then use the same license for Plugin B without paying you.

We handle this by subscribing to the AdminTabStripCreated event which will let you know whenever someone loads up any admin page with a tab strip. 

public void HandleEvent(AdminTabStripCreated eventMessage)
{
    if (eventMessage.TabStripName == "product-edit")
    {
        ProductKeyController controller = new ProductKeyController(_productService, _genericAttributeService, _permissionService);
        
        string html = controller.GetProductKey();
        eventMessage.ItemFactory.Add().Text(_localizationService.GetResource("BitShift.Plugin.Misc.LicenseKey")).Content(html);
    }
}

You have to make sure you check the TabStripName because you'll get called for all tabstrips in the entire admin site.  We're calling the ProductKeyController manually which means we need to pass in its constructor arguments ourself.  It's outside of the normal MVC lifecycle so we don't get the benefit of dependency injection here.  We get the HTML and add it to the tabstrip.

public string GetProductKey()
{
    if (ControllerContext == null)
    {
        ControllerContext context = new ControllerContext(System.Web.HttpContext.Current.Request.RequestContext, this);
        ControllerContext = context;
    }

    var model = new ProductKeyModel();

    int productId = Convert.ToInt32(ControllerContext.RequestContext.RouteData.Values["id"]);
    var product = _productService.GetProductById(productId);
    model.ProductKey = product.GetAttribute(Constants.LicenseKeyAttribute); return this.RenderPartialViewToString("BitShift.Plugin.Misc.Licenses.Views.EditProductKey", model); } 

Since the ControllerContext will most likely not be loaded, we need to nudge it along.  We'll also figure out what our product id is based on the RouteData in the URL.  After that it's just a matter of looking up what our existing product key is for this product and passing it to the View.  Since we are returning the View as a string instead of ActionResult, we use the RenderPartialViewToString method.

@model BitShift.Plugin.Misc.Licenses.Models.ProductKeyModel

<table class="adminContent">
    <tr>
        <td class="adminTitle">
            @Html.NopLabelFor(model => model.ProductKey):
        </td>
        <td class="adminData">
            @Html.EditorFor(model => model.ProductKey)
            <span id="licensekey-save" class="t-button">@T("Admin.Common.Save")</span>
            <span id="licensekey-message" style="color:#009900"></span>
        </td>
    </tr>
</table>

<script type="text/javascript">
    $(document).ready(function () {
        $("#licensekey-save").click(function () {
            $("#licensekey-message").html("");
            var model = {id: $("#Id").val(), productKey: $("#ProductKey").val() };
            $.post("@(Url.RouteUrl("Plugin.Misc.Licenses.SaveKey"))", model, function() {
                $("#licensekey-message").html("@T("BitShift.Plugin.Misc.LicenseKey.Saved")");
            });
        });
    });
</script>

The View is pretty simple.  It's just a single field for our ProductKey and then a jQuery function to post it back to our ProductKeyController when we want to save it. 

public void SaveKey(int id, string productKey)
{
    if (!_permissionService.Authorize(StandardPermissionProvider.ManageProducts))
        return;

    var product = _productService.GetProductById(id);
    _genericAttributeService.SaveAttribute(product, Constants.LicenseKeyAttribute, productKey); } 

The SaveKey function just takes in the new key and adds it to the products Attributes.

Configuration

To configure the plugin, you just need to determine what Product Attributes will designate your URL mode and Domain mode.  This is how the plugin will recognize what products should get a license key when they are ordered. 

This page also has a tool to create a license key manually.  You can use this for occassions where the customer makes a typo and you need to create a new key.

Generating Licenses

The meat of the plugin happens when a customer orders an item that needs a license.  The LicenseService will loop through all of the OrderItems and determine if any use our Url or Domain attributes.  If they do, it will pull the value the customer entered and the ProductKey for that product and encrypt them together to create the license key.  If there is at least 1 license key generated, they will be added to the OrderNotes and also email directly to the customer using a MessageTemplate that was created when the LicenseKey plugin was installed.

A future blog post will detail how your other plugins should decrypt the license key and verify that is valid for where they are installed.

First Data requires 4 distinct pieces of info to accept transactions from your store: Gateway ID, Password, Key ID, and HMAC.

If you are testing out the plugin, the first step is to register for a demo account with First Data here

Once you are in, click Administration at the top right, then Terminals.  Select the Terminal with ECOMM in the name.

 

In the middle of this form, you will see Password.  You might have to click Generate to get one.  This is the password field for the plugin and the Gateway ID is here, too. It's important to note that the Password is separate from the username/password you used to log in.

Click on the API Access tab and generate a new HMAC Key.  The Key ID is on this page, also.  Click Update at the bottom to save the HMAC.

You'll have to do it again if you are using the Production version.  The demo info will only work in Sandbox mode and the Production info will only work if Sandbox is turned off.

If you have any other questions don't hesitate to use the contact form.