license

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2022 License: MIT Imports: 15 Imported by: 1

README

license

Build Status Go Report Card Go Doc

License is a library that helps generate licenses that can be validated offline

Generate a license

package main

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"encoding/pem"
	"log"
	"time"

	"github.com/ubogdan/license"
)

func main() {
	// Create basic license Data
	licenseData := license.License{
		ProductName:  "Your Product Name",
		SerialNumber: "Some Serial Number",
		MinVersion:   10000,                               // Valid from v0.0.1
		MaxVersion:   200000000,                           // Valid until v2.0.0
		ValidFrom:    time.Now(),                          // Valid from today
		ValidUntil:   time.Now().Add(30 * 24 * time.Hour), // Valid for 30 days
		Features: []license.Feature{
			{
				Oid:         []int{1, 3, 6, 1, 3, 1, 1},
				Description: "Some Feature",
				Limit:       5,
			},
		},
	}

	signer, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		log.Fatalf("Failed to generate key: %v", err)
	}

	// Generate license
	licenseBytes, err := license.CreateLicense(&licenseData, signer)
	if err != nil {
		log.Fatalf("Failed to create license: %v", err)
	}

	data := pem.EncodeToMemory(&pem.Block{
		Type:  "LICENSE",
		Bytes: licenseBytes,
	})

	log.Printf("License: %s", string(data))
}

Verify a license

package main

import (
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"log"
	"time"

	"github.com/ubogdan/license"
)

const (
	productName = "Your Product Name"
	version     = "1.2.3"
)

func main() {
	// Read license data from file
	pemData, err := ioutil.ReadFile("/etc/product_name/license.pem")
	if err != nil {
		log.Fatalf("Failed to read license: %v", err)
	}

	pemBlock, r := pem.Decode(pemData)
	if pemBlock == nil {
		log.Fatalf("Failed to decode license: %v", r)
	}

	publicDer, err := hex.DecodeString("YOUR_PUBLIC_KEY_HEX")
	if err != nil {
		log.Fatalf("Failed to decode public key: %v", err)
	}

	publicEcc, err := x509.ParsePKIXPublicKey(publicDer)
	if err != nil {
		log.Printf("Failed to parse public key: %v", err)
	}

	ver, err := license.NewVersion(version)
	if err != nil {
		log.Fatalf("Failed to parse version: %v", err)
	}

	snValidator := func(product, serial string, validFrom, validUntil, minVersion, maxVersion int64) error {
		if product != productName {
			return errors.New("invalid product name")
		}

		if validFrom > time.Now().Unix() {
			return errors.New("license is not valid yet")
		}

		if validUntil < time.Now().Unix() {
			return errors.New("license is expired")
		}

		if minVersion > int64(ver) || int64(ver) > maxVersion {
			return errors.New("invalid version")
		}

		// Validate serial number here

		return nil
	}

	license, err := license.Load(pemBlock.Bytes, publicEcc, snValidator)
	if err != nil {
		log.Fatalf("Failed to load license: %v", err)
	}

	log.Printf("License: %v", license)
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CreateLicense

func CreateLicense(template *License, key crypto.Signer) ([]byte, error)

CreateLicense generate a license using a private key.

Types

type Customer

type Customer struct {
	Name               string `asn1:"optional,tag:0" json:"name,omitempty"`
	Country            string `asn1:"optional,tag:1" json:"country,omitempty"`
	City               string `asn1:"optional,tag:2" json:"city,omitempty"`
	Organization       string `asn1:"optional,tag:3" json:"organization,omitempty"`
	OrganizationalUnit string `asn1:"optional,tag:4" json:"organizational_unit,omitempty"`
}

Customer godoc.

type Feature

type Feature struct {
	Oid         asn1.ObjectIdentifier `json:"-"`
	Description string                `asn1:"-" json:"description"`
	Expire      int64                 `asn1:"optional,tag:1"`
	Limit       int64                 `asn1:"optional,tag:2"`
}

Feature godoc.

type License

type License struct {
	ProductName  string    `json:"product"`
	SerialNumber string    `json:"serial"`
	Customer     Customer  `json:"customer"`
	ValidFrom    time.Time `json:"valid_from,omitempty"`
	ValidUntil   time.Time `json:"valid_until,omitempty"`
	MinVersion   Version   `json:"min_version,omitempty"`
	MaxVersion   Version   `json:"max_version,omitempty"`
	Features     []Feature `json:"features"`
}

License godoc.

func Load

func Load(asn1Data []byte, publicKey interface{}, validator ValidateSN) (*License, error)

Load a license from asn encoded byte data.

type ValidateSN

type ValidateSN func(product, serial string, validFrom, validUntil, minVersion, maxVersion int64) error

ValidateSN godoc.

type Version added in v0.1.1

type Version int64

Version lazy semver implementation.

func NewVersion added in v0.1.1

func NewVersion(v string) (Version, error)

NewVersion semantic version to integer valid format XXXX.XXXX.XXXX.

func (Version) String added in v0.1.1

func (ver Version) String() string

String convert version integer to string.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL