unioffice/license.go

187 lines
4.6 KiB
Go

// Copyright 2017 Baliance. All rights reserved.
//
// Use of this source code is governed by the terms of the Affero GNU General
// Public License version 3.0 as published by the Free Software Foundation and
// appearing in the file LICENSE included in the packaging of this file. A
// commercial license can be purchased by contacting sales@baliance.com.
package gooxml
import (
"bytes"
"compress/gzip"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"io"
"log"
"regexp"
"strings"
"time"
)
// OpenSourceLicense is the AGPL open source license. It is installed by default
// if no license has previously been installed.
const OpenSourceLicense = `
H4sIAAAAAAAC_xzJsU7DQAwA0J2vqDynks--y9nZ
2RAMLQubfeegDKRR2kogxL8jkN72vuHZPgImeNli
PZwu973F4fUaOwxwWt5Xu933v86Fqjfnlq1mKWzU
SXzEwCKoqWc0sREtvCYlsdlV2b12CwqyntVk7orZ
eTQRtMhMoonHaDh3DMsYVEir10JzbV3CW1FmyrM4
wQCPn9uy2225rDABI-Ix0ZHTGXH69wYDPC0t1muc
v7aAKf08_AYAAP__z2E3oN8A`
var license *License
const pubKeyHex = `305c300d06092a864886f70d0101010500034b003048024100b87eafb6c07499eb97cc9d3565ecf3168196301907c841addc665086bb3ed8eb12d9da26cafa96450146da8bd0ccf155fcacc686955ef0302fa44aa3ec89417b0203010001`
var pubKey *rsa.PublicKey
func init() {
pubKeyBytes, err := hex.DecodeString(pubKeyHex)
if err != nil {
log.Fatalf("error reading key: %s", err)
}
pkRaw, err := x509.ParsePKIXPublicKey(pubKeyBytes)
if err != nil {
log.Fatalf("error reading key: %s", err)
}
pubKey = pkRaw.(*rsa.PublicKey)
}
// LicenseType is the type of license
//go:generate stringer -type=LicenseType
type LicenseType byte
// LicenseType constants
const (
LicenseTypeInvalid LicenseType = iota
LicenseTypeAGPL
LicenseTypeCommercial
)
// License holds the gooxml license information.
type License struct {
Name string
Signature string `json:",omitempty"`
Expiration time.Time
LicenseType LicenseType
}
// Sign signs a license with a private key, setting the license's signature
// value
func (l *License) Sign(privKey *rsa.PrivateKey) error {
l.Signature = ""
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
if err := enc.Encode(l); err != nil {
return err
}
hashed := sha256.Sum256(buf.Bytes())
signature, err := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA256, hashed[:])
if err != nil {
return err
}
l.Signature = hex.EncodeToString(signature)
return nil
}
// Verify verifies a license by checking the license content and signature
// against a public key.
func (l License) Verify(pubKey *rsa.PublicKey) error {
cp := l
cp.Signature = ""
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
if err := enc.Encode(cp); err != nil {
return err
}
sig, err := hex.DecodeString(l.Signature)
if err != nil {
return err
}
hashed := sha256.Sum256(buf.Bytes())
err = rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, hashed[:], sig)
return err
}
func (l License) String() string {
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
enc.Encode(l)
return buf.String()
}
// Encoded returns a base64 encoded version of the license for use with
// InstallLicense.
func (l License) Encoded() string {
buf := bytes.Buffer{}
w := base64.NewEncoder(base64.RawURLEncoding, &buf)
gz, _ := gzip.NewWriterLevel(w, gzip.BestCompression)
enc := json.NewEncoder(gz)
enc.Encode(l)
gz.Close()
rsp := bytes.Buffer{}
const maxLen = 40
raw := buf.Bytes()
for i := 0; i < buf.Len(); i += maxLen {
rsp.Write(raw[i : i+maxLen])
rsp.WriteByte('\r')
rsp.WriteByte('\n')
}
return rsp.String()
}
// InstallLicense installs a license, returning an error if the license is
// invalid or expired. Expiration checks the ReleaseDate variable in version.go.
func InstallLicense(s string) error {
re := regexp.MustCompile("\\s")
s = re.ReplaceAllString(s, "")
var r io.Reader
r = strings.NewReader(s)
r = base64.NewDecoder(base64.RawURLEncoding, r)
r, err := gzip.NewReader(r)
if err != nil {
return err
}
dec := json.NewDecoder(r)
l := &License{}
if err := dec.Decode(l); err != nil {
return err
}
// check signature
if err := l.Verify(pubKey); err != nil {
return errors.New("license validatin error")
}
if l.Expiration.Before(ReleaseDate) {
return errors.New("license expired")
}
license = l
return nil
}
// GetLicense returns the current license. This can be used by commercial
// customers to assist in ensuring that their license hasn't expired.
func GetLicense() License {
if license == nil {
if err := InstallLicense(OpenSourceLicense); err != nil {
log.Printf("open source license error: %s", err)
}
}
if license != nil {
return *license
}
return License{}
}