Documentation

Table of Content

 

Basic Concepts

To get started with weweave Commerce, you should understand the following basic concepts behind the platform:

  • weweave Commerce relies on external brokers handling the actual customer selling transactions. For example, weweave uses DNN Store and FastSpring for handling the transactions.
  • There is a order notification API, allowing for external brokers to automatically notify the platform after a successful purchase. When notified, the platform creates an account for your new/recurring customer and tracks the purchase.
  • The focus of the platform is license keys and support tickets.
  • License keys are generated by the platform itself, using an RSA signature method to prevent manipulation. You can check the license keys in your applications easily (see below).
  • License keys can be domain-based and support the following schemes: Trial (valid for 30 days), Lifetime (works forever), Limited (works for one year).
  • Your customers can log in to the platform, generate their license keys and handle their support cases.
  • Administrators can log in to the platform and manage customers, license keys and support tickets.

As of August 2018, the software’s backend and frontend have been separated into two projects: commerce (the backend part) and commerce-www (the frontend part). You’ll probably want to set up both.

 

Building from source

To build weweave Commerce from source, please follow these instructions:

  1. Make sure you have Node.js installed (tested with Node.js v8).
  2. Check out the source code and build it:
    git clone https://github.com/weweave/commerce.git
    cd commerce
    npm install
    npm run build-prod
  3. Update config.json to match your environment (see below).
  4. Check out the frontend, build it and copy the files over to the backend:
    mkdir www
    cd ..
    npm install -g @angular/cli
    git clone https://github.com/weweave/commerce-www.git
    cd commerce-www
    npm install
    ng build --prod
    cp -R dist/commerce-www/* ../commerce/www/
    cd ../commerce
  5. Run the server:
    node dist/server.js
  6. Access the web frontend at port 3000. Default username is “[email protected]”, password is “admin”.
  7. After logging in with the admin account, change the username and password under “Persons” and configure the system further under “Settings”.

 

Using the Docker image

The easiest way of getting weweave Commerce up and running is to use our pre-built Docker images. However, you can of course choose to build from source.

  1. Create a config.json file (see below).
  2. Run the backend image like this (assuming you want to link it with your MySQL container):
    docker run \
    -p 3000:3000 \
    --name commerce \
    --link mysql:mysql \
    -v /tmp/config.json:/usr/src/app/config.json \
    weweave/commerce
  3. Run the frontend image like this:
    docker run \
    -p 8080:80 \
    --name commerce_www \
    weweave/commerce-www
  4. Use a cloud native edge router like Traefik (or nginx or haproxy):
    • Route all incoming requests to /api/ to the backend.
    • Route all other incoming requests to the frontend.
  5. If your frontend is not running at the root path, you must change the base href by setting the frontend’s docker environment variable BASE_HREF.
  6. Access the web frontend at port 8080. Default username is “[email protected]”, password is “admin”.
  7. After logging in with the admin account, change the username and password under “Persons” and configure the system further under “Settings”.

 

Configuration

The settings required on server start are in config.json. Make sure to change this file before starting the server.

{
    "database": {
        "driver": {
            "type": "mysql",
            "host": "mysql",
            "port": 3306,
            "username": "root",
            "password": "root",
            "database": "commerce"
        },
        "logging": ["error", "warn"]
    },
    "basePath": "/",
    "session": {
        "secret": "fkj49l7WwjUtqcfLZKlLA269J28kC4uL",
        "issuer": "https://change.me",
        "lifetime": "12h"
    },
    "importTldListOnStart": true
}

The meaning of these settings are:

  • database: Configure your database type, hostname, port, username, password and schema name. weweave Commerce will create/update the table structure on server start, so it’s sufficient to create an empty database.
  • basePath: If you’re serving the frontend via the backend and commerce is not running at the root path, you will have to adjust the base path here.
  • session: weweave Commerce uses JSON Web Tokens (JWT) for authentication and authorization. It is very important that you change the secret to something unique. If you don’t, your sessions can be manipulated.
  • importTldListOnStart: By setting this to false, you can skip importing the list of top level domains required for domain-bases license key generation. Should be true for production systems. weweave Commerce keeps track of the latest imported version, so the list will only be imported if it’s newer than the already installed list.

More settings can be changed at runtime by logging in with an administrator account and navigating to “Settings”.

Most of these should be self-explaining. Two important settings are the RSA Public and Private Keys for License Key Encoding. These are required for signing your license keys and must be pasted in PEM format here. To generate an RSA public/private key pair, you can use OpenSSL:

  1. Generate a 2048-bit RSA key pair:
    openssl genrsa -des3 -out commerce.pem 2048
  2. Extract the public key and remove the password:
    openssl rsa -in commerce.pem -outform PEM -pubout -out commerce-public.pem
  3. Extract the private key and remove the password:
    openssl rsa -in commerce.pem -out commerce-private.pem -outform PEM
  4. Paste the content of the commerce-private.pem and commerce-public.pem into the corresponding fields.
  5. Keep the private key private! Whoever has it can sign valid license keys for your software with it.

 

Broker Mapping Templates

When a broker sends an order notification to your weweave Commerce instance, it may do that in the broker’s proprietary message format. In order for weweave Commerce to process the order notification, we need to transform the received message into a unique format that weweave Commerce can understand and process.

Commerce integrates object-mapper to achieve this. Please refer to their documentation for information on how to write your JSON-based mapping structure.

The target structure Commerce needs is:

{
    id: <String>,
    customer: {
        firstname: <String>,
        lastname: <String>,
        company: <String>,
        email: <String>,
        country: <String>
    },
    items: [
        {
            id: <String>,
            quantity: <Number>
        }
    ]
}
  • id: A unique order ID generated and provided by the broker.
  • customer: Details about the customer who initiated the order (Commerce performs customer matching using the email address).
  • items: An array of purchased items.
    • id: A unique product variant ID as configured for your product variant and broker.
    • quantity: The quantity your customer has purchased of this product variant.

Please note that XML is automatically transformed into JSON using xml-js using {compact: true} before the transformation using json-mapper-json is applied.

 

Example 1: JSON input
Assume your broker sends an order notification like this (actually, this is how FastSpring sends order notifications):

{
    "id": "XYZ-12345-7890",
    "items": [
        {
            "productName": "wpac-support-ticket",
            "priceTotalUSD": 22.81,
            "quantity": 1
        }
    ],
    "customer": {
        "firstName": "John",
        "lastName": "Doe",
        "company": "",
        "email": "[email protected]"
    }
}

In this case, your mapping template should look like this:

{
    "id": "id",
    "customer.firstName": "customer.firstname",
    "customer.lastName": "customer.lastname",
    "customer.company": "customer.company",
    "customer.email": "customer.email",
    "items[].productName": "items[].id",
    "items[].quantity": "items[].quantity"
}

 

Example 2: XML input
Assume your broker sends an order notification like this:

<?xml version="1.0" encoding="utf-8" ?>
<order-notification>
    <order id="1227037271-23207-250782" is-test="true" is-gift="false">
        <event>
            <event-name>order</event-name>
            <event-date>2017-05-18T13:41:11-06:00</event-date>
        </event>
        <order-status>Test</order-status>
        <order-date>2008-11-18T13:41:11-06:00</order-date>
        <order-item id="1227037271-23207-250782">
            <product id="55305-9">
                <name>DNN Dynamic Roles</name>
            </product>
            <quantity>2</quantity>
            <tax>3.13</tax>
            <total>53.13</total>
            <reginfo />
            <profit>0</profit>
            <affiliate-commission />
            <coupon-code />
        </order-item>
        <customer id="1226354950-348-707099">
            <address>
                <first-name>Joe</first-name>
                <last-name>Goe</last-name>
                <company>DR</company>
                <address1>550 W. Van Buren</address1>
                <address2 />
                <city>Chicago</city>
                <region>IL</region>
                <postal-code>60607</postal-code>
                <country>US</country>
                <phone>312-3255555</phone>
                <email>[email protected]</email>
                <language-chosen>EN</language-chosen>
            </address>
        </customer>
        <referrer>QA Test Account</referrer>
        <custom-referrer />
        <link-location>Unknown</link-location>
        <name-on-card>Test Order</name-on-card>
        <ip>127.0.0.1</ip>
    </order>
</order-notification>

In this case, your mapping template should look like this:

{
    "order-notification.order._attributes.id": "id",
    "order-notification.order.customer.address.first-name._text": "customer.firstname",
    "order-notification.order.customer.address.last-name._text": "customer.lastname",
    "order-notification.order.customer.address.company._text": "customer.company",
    "order-notification.order.customer.address.email._text": "customer.email",
    "order-notification.order.order-item.product._attributes.id": "items[].id",
    "order-notification.order.order-item.quantity._text": "items[].quantity"
}

 

Using the license keys in your applications

We’re working on providing ready-to-use license key validation libraries for common programming languages.

If there is no read-to-use- library for your programming language yet, here’s how to validate a license key manually in the meantime:

  1. Base64-decode the key. You’ll receive a JSON structure like this:
    {
      signature: '...',
      details: '...'
    }

    “details” is a base64-encoded string. “signature” is the RSA-SHA1 signature of the “details” string.

  2. Validate that the the signature of the “details” string matched the “signature” using RSA-SHA1 with your public key.
  3. If valid, base64-decode the “details” string. You’ll receive a JSON structure like this:
    {
      version: 2,
      description: 'License for 3 sites',
      type: '...',
      uuid: '159891d1-91dc-4d24-9c47-8b9c865f7f52',
      onlineVerification: true,
      product: 'DnnDynamicRoles',
      owner: 'Microsoft GmbH & Co. KG',
      issueDate: '2014-08-31',
      expiryDate: '2015-09-01',
      subject: '^(.*\.)?example\.com|mysite\.com|(.*\.)?something\.de$'
    }

The fields in the details JSON have the following meaning:

  • version: Currently, the version is always 2.
  • description: A free text description of what this license is for. You should not interpret this, but you can use it for printing.
  • type: One of the following values: trial | limited | lifetime.
  • uuid: An optional unique license identifier which can be used in combination with online verification.
  • onlineVerification: If true, your software should verify the license key using an online system and the provided UUID.
  • product: The short name of the licenses product as specified by the “Identifier in License Key” setting in your product details.
  • owner: The name of the licensee.
  • issueDate: The date when the license was issued.
  • expiryDate: The date when the license will expire.
  • subject: A regular expression you can use to validate if the current domain name is licensed or not.