mirror of
https://github.com/unidoc/unioffice.git
synced 2025-04-25 13:48:53 +08:00
gooxml: add support for verifying versions and license
This commit is contained in:
parent
801388a119
commit
665d3a281d
185
license.go
Normal file
185
license.go
Normal file
@ -0,0 +1,185 @@
|
||||
// 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"
|
||||
"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 {
|
||||
s = strings.Replace(s, "\r", "", -1)
|
||||
s = strings.Replace(s, "\n", "", -1)
|
||||
|
||||
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{}
|
||||
}
|
15
license_test.go
Normal file
15
license_test.go
Normal file
@ -0,0 +1,15 @@
|
||||
// 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_test
|
||||
|
||||
import "testing"
|
||||
import "baliance.com/gooxml"
|
||||
|
||||
func TestOpenSourceLicense(t *testing.T) {
|
||||
gooxml.GetLicense()
|
||||
}
|
16
licensetype_string.go
Normal file
16
licensetype_string.go
Normal file
@ -0,0 +1,16 @@
|
||||
// Code generated by "stringer -type=LicenseType"; DO NOT EDIT.
|
||||
|
||||
package gooxml
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _LicenseType_name = "LicenseTypeInvalidLicenseTypeAGPLLicenseTypeCommercial"
|
||||
|
||||
var _LicenseType_index = [...]uint8{0, 18, 33, 54}
|
||||
|
||||
func (i LicenseType) String() string {
|
||||
if i >= LicenseType(len(_LicenseType_index)-1) {
|
||||
return fmt.Sprintf("LicenseType(%d)", i)
|
||||
}
|
||||
return _LicenseType_name[_LicenseType_index[i]:_LicenseType_index[i+1]]
|
||||
}
|
20
update-version.sh
Executable file
20
update-version.sh
Executable file
@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
cat << __EOF > version.go
|
||||
// Copyright `date +%Y` 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 "time"
|
||||
|
||||
// ReleaseDate is the release date of the source code for licensing purposes.
|
||||
var ReleaseDate = time.Date(`date +%Y`,`date +%_m`,`date +%_d`,0,0,0,0,time.UTC)
|
||||
|
||||
__EOF
|
||||
goimports -w version.go
|
13
version.go
Normal file
13
version.go
Normal file
@ -0,0 +1,13 @@
|
||||
// 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 "time"
|
||||
|
||||
// ReleaseDate is the release date of the source code for licensing purposes.
|
||||
var ReleaseDate = time.Date(2017, 9, 30, 0, 0, 0, 0, time.UTC)
|
Loading…
x
Reference in New Issue
Block a user