commit
56c31260ea
@ -0,0 +1,11 @@
|
||||
workspace:
|
||||
base: /go
|
||||
path: src/github.com/drone/go-license
|
||||
|
||||
pipeline:
|
||||
build:
|
||||
image: golang
|
||||
commands:
|
||||
- go get golang.org/x/crypto/ed25519
|
||||
- go install ./...
|
||||
- go test -v ./...
|
@ -0,0 +1,5 @@
|
||||
*.out
|
||||
*.txt
|
||||
id_ed25519
|
||||
id_ed25519.pub
|
||||
license.txt
|
@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2018, Drone.IO Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@ -0,0 +1,61 @@
|
||||
// Copyright 2018 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/drone/go-license/license"
|
||||
"github.com/drone/go-license/license/licenseutil"
|
||||
)
|
||||
|
||||
var month = time.Hour * 24 * 31
|
||||
|
||||
var (
|
||||
in = flag.String("in", "id_ed25519", "")
|
||||
out = flag.String("out", "license.txt", "")
|
||||
iss = flag.String("iss", "", "")
|
||||
cus = flag.String("cus", "", "")
|
||||
sub = flag.String("sub", "", "")
|
||||
typ = flag.String("typ", "", "")
|
||||
lim = flag.Int("lim", 0, "")
|
||||
exp = flag.Duration("exp", month, "")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
privateKey, err := licenseutil.ReadPrivateKey(*in)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
license := &license.License{
|
||||
Iss: *iss,
|
||||
Cus: *cus,
|
||||
Sub: *sub,
|
||||
Typ: *typ,
|
||||
Lim: *lim,
|
||||
Exp: time.Now().UTC().Add(*exp),
|
||||
Iat: time.Now().UTC(),
|
||||
}
|
||||
|
||||
encoded, err := license.Encode(privateKey)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(*out, encoded, 0644)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
// Copyright 2018 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
var out = flag.String("out", "id_ed25519", "")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
publicKeyHex, privateKeyHex := base64.StdEncoding.EncodeToString(publicKey),
|
||||
base64.StdEncoding.EncodeToString(privateKey)
|
||||
|
||||
err = ioutil.WriteFile(*out, []byte(privateKeyHex), 0644)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(*out+".pub", []byte(publicKeyHex), 0644)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
// Copyright 2018 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/drone/go-license/license"
|
||||
"github.com/drone/go-license/license/licenseutil"
|
||||
)
|
||||
|
||||
var (
|
||||
pub = flag.String("pub", "id_ed25519.pub", "")
|
||||
file = flag.String("file", "license.txt", "")
|
||||
addr = flag.String("addr", "http://localhost:9000", "")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
publicKey, err := licenseutil.ReadPublicKey(*pub)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
l, err := license.DecodeFile(*file, publicKey)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
json.NewEncoder(buf).Encode(l)
|
||||
|
||||
res, err := http.Post(*addr, "application/json", buf)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
io.Copy(os.Stdout, res.Body)
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
// Copyright 2018 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/drone/go-license/license"
|
||||
"github.com/drone/go-license/license/licenseutil"
|
||||
)
|
||||
|
||||
var monthly = time.Hour * 24 * 30
|
||||
|
||||
var (
|
||||
addr = flag.String("addr", ":9000", "")
|
||||
renewal = flag.Duration("dur", monthly, "")
|
||||
signer = flag.String("signer", "id_ed25519", "")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
http.HandleFunc("/", handler)
|
||||
http.ListenAndServe(*addr, nil)
|
||||
}
|
||||
|
||||
func handler(w http.ResponseWriter, r *http.Request) {
|
||||
l := new(license.License)
|
||||
err := json.NewDecoder(r.Body).Decode(l)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO verify the License.Cus (customer id) is valid
|
||||
// and in good standing prior to issuing a new license.
|
||||
|
||||
l.Exp = time.Now().UTC().Add(*renewal)
|
||||
|
||||
privateKey, err := licenseutil.ReadPrivateKey(*signer)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
encoded, err := l.Encode(privateKey)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Write(encoded)
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
// Copyright 2018 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/drone/go-license/license"
|
||||
"github.com/drone/go-license/license/licenseutil"
|
||||
)
|
||||
|
||||
var (
|
||||
pub = flag.String("pub", "id_ed25519.pub", "")
|
||||
file = flag.String("file", "license.txt", "")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
publicKey, err := licenseutil.ReadPublicKey(*pub)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
l, err := license.DecodeFile(*file, publicKey)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
enc.Encode(l)
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
// Copyright 2018 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package license
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidSignature indicates the license signature is invalid.
|
||||
ErrInvalidSignature = errors.New("Invalid signature")
|
||||
|
||||
// ErrMalformedLicense indicates the license file is malformed.
|
||||
ErrMalformedLicense = errors.New("Malformed License")
|
||||
)
|
||||
|
||||
// License defines a software license key.
|
||||
type License struct {
|
||||
Iss string `json:"iss,omitempty"` // Issued By
|
||||
Cus string `json:"cus,omitempty"` // Customer ID
|
||||
Sub string `json:"sub,omitempty"` // Subscriber ID
|
||||
Typ string `json:"typ,omitempty"` // License Type
|
||||
Lim int `json:"lim,omitempty"` // License Limit (e.g. Seats)
|
||||
Iat time.Time `json:"iat,omitempty"` // Issued At
|
||||
Exp time.Time `json:"exp,omitempty"` // Expires At
|
||||
Dat json.RawMessage `json:"dat,omitempty"` // Metadata
|
||||
}
|
||||
|
||||
// Expired returns true if the license is expired.
|
||||
func (l *License) Expired() bool {
|
||||
return l.Exp.IsZero() == false && time.Now().After(l.Exp)
|
||||
}
|
||||
|
||||
// Encode generates returns a PEM encoded license key that is
|
||||
// signed with the ed25519 private key.
|
||||
func (l *License) Encode(privateKey ed25519.PrivateKey) ([]byte, error) {
|
||||
msg, err := json.Marshal(l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sig := ed25519.Sign(privateKey, msg)
|
||||
buf := new(bytes.Buffer)
|
||||
buf.Write(sig)
|
||||
buf.Write(msg)
|
||||
|
||||
block := &pem.Block{
|
||||
Type: "LICENSE KEY",
|
||||
Bytes: buf.Bytes(),
|
||||
}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
}
|
||||
|
||||
// Decode decodes the PEM encoded license key and verifies
|
||||
// the content signature using the ed25519 public key.
|
||||
func Decode(data []byte, publicKey ed25519.PublicKey) (*License, error) {
|
||||
block, _ := pem.Decode(data)
|
||||
if block == nil || len(block.Bytes) < ed25519.SignatureSize {
|
||||
return nil, ErrMalformedLicense
|
||||
}
|
||||
|
||||
sig := block.Bytes[:ed25519.SignatureSize]
|
||||
msg := block.Bytes[ed25519.SignatureSize:]
|
||||
|
||||
verified := ed25519.Verify(publicKey, msg, sig)
|
||||
if !verified {
|
||||
return nil, ErrInvalidSignature
|
||||
}
|
||||
out := new(License)
|
||||
err := json.Unmarshal(msg, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// DecodeFile decodes the PEM encoded license file and verifies
|
||||
// the content signature using the ed25519 public key.
|
||||
func DecodeFile(path string, publicKey ed25519.PublicKey) (*License, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Decode([]byte(data), publicKey)
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
// Copyright 2018 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package license
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/drone/go-license/license/licenseutil"
|
||||
)
|
||||
|
||||
func TestExpired(t *testing.T) {
|
||||
license := &License{}
|
||||
if license.Expired() {
|
||||
t.Errorf("Expect zero value expiration to never expire")
|
||||
}
|
||||
|
||||
license = &License{}
|
||||
license.Exp = time.Now().Add(time.Hour)
|
||||
if license.Expired() == true {
|
||||
t.Errorf("Expect license is not expired")
|
||||
}
|
||||
|
||||
license = &License{}
|
||||
license.Exp = time.Now().Add(time.Hour * -1)
|
||||
if license.Expired() == false {
|
||||
t.Errorf("Expect license is expired")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecode(t *testing.T) {
|
||||
privateKey, err := licenseutil.ReadPrivateKey("licenseutil/testdata/id_ed25519")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
publicKey, err := licenseutil.ReadPublicKey("licenseutil/testdata/id_ed25519.pub")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
license := &License{
|
||||
Iss: "Acme, Inc",
|
||||
Cus: "cus_CxoyqaC4p4Hjl0",
|
||||
Sub: "sub_A4l9XkCxyZPcS2",
|
||||
Typ: "trial",
|
||||
Lim: 50,
|
||||
Iat: time.Now().UTC(),
|
||||
Exp: time.Now().Add(time.Hour).UTC(),
|
||||
}
|
||||
encoded, err := license.Encode(privateKey)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
decoded, err := Decode(encoded, publicKey)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if got, want := decoded.Cus, license.Cus; got != want {
|
||||
t.Errorf("Want license Cus %v, got %v", want, got)
|
||||
}
|
||||
if got, want := decoded.Exp, license.Exp; got != want {
|
||||
t.Errorf("Want license Exp %v, got %v", want, got)
|
||||
}
|
||||
if got, want := decoded.Iat, license.Iat; got != want {
|
||||
t.Errorf("Want license Iat %v, got %v", want, got)
|
||||
}
|
||||
if got, want := decoded.Iss, license.Iss; got != want {
|
||||
t.Errorf("Want license Iss %v, got %v", want, got)
|
||||
}
|
||||
if got, want := decoded.Lim, license.Lim; got != want {
|
||||
t.Errorf("Want license Lim %v, got %v", want, got)
|
||||
}
|
||||
if got, want := decoded.Sub, license.Sub; got != want {
|
||||
t.Errorf("Want license Sub %v, got %v", want, got)
|
||||
}
|
||||
if got, want := decoded.Typ, license.Typ; got != want {
|
||||
t.Errorf("Want license Sub %v, got %v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeFile(t *testing.T) {
|
||||
publicKey, err := licenseutil.ReadPublicKey("licenseutil/testdata/id_ed25519.pub")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
decoded, err := DecodeFile("licenseutil/testdata/license.txt", publicKey)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if got, want := decoded.Cus, "cus_CxoyqaC4p4Hjl0"; got != want {
|
||||
t.Errorf("Want license Cus %v, got %v", want, got)
|
||||
}
|
||||
if got, want := decoded.Sub, "sub_A4l9XkCxyZPcS2"; got != want {
|
||||
t.Errorf("Want license Exp %v, got %v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeFile_InvalidSignature(t *testing.T) {
|
||||
publicKey, err := licenseutil.ReadPublicKey("licenseutil/testdata/id_ed25519.pub")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = DecodeFile("licenseutil/testdata/license_invalid_signature.txt", publicKey)
|
||||
if err != ErrInvalidSignature {
|
||||
t.Errorf("Expected invalid signature error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeFile_InvalidEncoding(t *testing.T) {
|
||||
publicKey, err := licenseutil.ReadPublicKey("licenseutil/testdata/id_ed25519.pub")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = DecodeFile("licenseutil/testdata/license_invalid_encoding.txt", publicKey)
|
||||
if err != ErrMalformedLicense {
|
||||
t.Errorf("Expected invalid signature error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeFile_InvalidJson(t *testing.T) {
|
||||
publicKey, err := licenseutil.ReadPublicKey("licenseutil/testdata/id_ed25519.pub")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = DecodeFile("licenseutil/testdata/license_invalid_json.txt", publicKey)
|
||||
if err != ErrMalformedLicense {
|
||||
t.Errorf("Expected invalid signature error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeFile_PathError(t *testing.T) {
|
||||
publicKey, err := licenseutil.ReadPublicKey("licenseutil/testdata/id_ed25519.pub")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = DecodeFile("path/does/not/exist", publicKey)
|
||||
if _, ok := err.(*os.PathError); !ok {
|
||||
t.Errorf("Expect path error")
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
// Copyright 2018 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package licenseutil
|
||||
|
||||
//go:generate license-keygen -out testdata/id_ed25519
|
||||
//go:generate license-create -in testdata/id_ed25519 -out testdata/license.txt -cus cus_CxoyqaC4p4Hjl0 -sub sub_A4l9XkCxyZPcS2
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"io/ioutil"
|
||||
|
||||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
// ReadPublicKey reads a base64-encoded public key file.
|
||||
func ReadPublicKey(path string) (ed25519.PublicKey, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return DecodePublicKey(data)
|
||||
}
|
||||
|
||||
// ReadPrivateKey reads a base64-encoded private key file.
|
||||
func ReadPrivateKey(path string) (ed25519.PrivateKey, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return DecodePrivateKey(data)
|
||||
}
|
||||
|
||||
// DecodePublicKey decodes a base64-encoded private key.
|
||||
func DecodePublicKey(data []byte) (ed25519.PublicKey, error) {
|
||||
decoded, err := decode(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ed25519.PublicKey(decoded), nil
|
||||
}
|
||||
|
||||
// DecodePrivateKey decodes a base64-encoded private key.
|
||||
func DecodePrivateKey(data []byte) (ed25519.PrivateKey, error) {
|
||||
decoded, err := decode(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ed25519.PrivateKey(decoded), nil
|
||||
}
|
||||
|
||||
func decode(b []byte) ([]byte, error) {
|
||||
enc := base64.StdEncoding
|
||||
buf := make([]byte, enc.DecodedLen(len(b)))
|
||||
n, err := enc.Decode(buf, b)
|
||||
return buf[:n], err
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
// Copyright 2018 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package licenseutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
func TestReadKeyPair(t *testing.T) {
|
||||
publicKey, err := ReadPublicKey("testdata/id_ed25519.pub")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
privateKey, err := ReadPrivateKey("testdata/id_ed25519")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
msg := []byte("hello world")
|
||||
sig := ed25519.Sign(privateKey, msg)
|
||||
if !ed25519.Verify(publicKey, msg, sig) {
|
||||
t.Errorf("Cannot sign and verify. Are keys malformed?")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadPublicKey_NotFound(t *testing.T) {
|
||||
_, err := ReadPublicKey("does/not/exist")
|
||||
if _, ok := err.(*os.PathError); !ok {
|
||||
t.Errorf("Expect path error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadPrivateKey_NotFound(t *testing.T) {
|
||||
_, err := ReadPrivateKey("does/not/exist")
|
||||
if _, ok := err.(*os.PathError); !ok {
|
||||
t.Errorf("Expect path error")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue