package golicense import ( "crypto/hmac" "crypto/sha256" "encoding/base64" "encoding/json" "errors" "time" ) var ( secret = []byte("superDuperSecret123!") ErrorHmacMismatch = errors.New("checksum mismatch - not a valid license key") ) type Data struct { Feature1 bool Feature2 int ValidTill time.Time CreatedAt time.Time } type Envelope struct { Data Data Checksum []byte } func (e *Envelope) String() (string, error) { d, err := json.Marshal(e) if err != nil { return "", err } str := base64.StdEncoding.EncodeToString(d) return str, nil } func New(feature1 bool, feature2 int, expire int) (*Envelope, error) { d := Data{ Feature1: feature1, Feature2: feature2, ValidTill: time.Now().AddDate(0, 0, expire), } e := Envelope{ Data: d, } db, err := json.Marshal(&d) if err != nil { return nil, err } hmac := hmac.New(sha256.New, secret) hmac.Write(db) dh := hmac.Sum(nil) e.Checksum = dh return &e, nil } func Verify(in string) (*Envelope, error) { d, err := base64.StdEncoding.DecodeString(in) if err != nil { return nil, err } var e Envelope if err := json.Unmarshal(d, &e); err != nil { return nil, err } db, err := json.Marshal(e.Data) if err != nil { return nil, err } hm := hmac.New(sha256.New, secret) hm.Write(db) dh := hm.Sum(nil) if !hmac.Equal(e.Checksum, dh) { return nil, ErrorHmacMismatch } return &e, nil }