-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(go): migrate cert testutil from node repo (#161)
Signed-off-by: Artur Troian <[email protected]>
- Loading branch information
Showing
4 changed files
with
471 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
package testutil | ||
|
||
import ( | ||
"crypto/ecdsa" | ||
"crypto/elliptic" | ||
"crypto/rand" | ||
"crypto/tls" | ||
"crypto/x509" | ||
"crypto/x509/pkix" | ||
"encoding/pem" | ||
"math/big" | ||
"net" | ||
"testing" | ||
"time" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/stretchr/testify/mock" | ||
"github.com/stretchr/testify/require" | ||
|
||
types "github.com/akash-network/akash-api/go/node/cert/v1beta3" | ||
certutils "github.com/akash-network/akash-api/go/node/cert/v1beta3/utils" | ||
clientmocks "github.com/akash-network/akash-api/go/node/client/v1beta2/mocks" | ||
) | ||
|
||
type TestCertificate struct { | ||
Cert []tls.Certificate | ||
Serial big.Int | ||
PEM struct { | ||
Cert []byte | ||
Priv []byte | ||
Pub []byte | ||
} | ||
} | ||
|
||
type certificateOption struct { | ||
domains []string | ||
nbf time.Time | ||
naf time.Time | ||
qclient *clientmocks.QueryClient | ||
} | ||
|
||
type CertificateOption func(*certificateOption) | ||
|
||
func CertificateOptionDomains(domains []string) CertificateOption { | ||
return func(opt *certificateOption) { | ||
opt.domains = domains | ||
} | ||
} | ||
|
||
func CertificateOptionNotBefore(tm time.Time) CertificateOption { | ||
return func(opt *certificateOption) { | ||
opt.nbf = tm | ||
} | ||
} | ||
|
||
func CertificateOptionNotAfter(tm time.Time) CertificateOption { | ||
return func(opt *certificateOption) { | ||
opt.naf = tm | ||
} | ||
} | ||
|
||
func CertificateOptionMocks(val *clientmocks.QueryClient) CertificateOption { | ||
return func(opt *certificateOption) { | ||
opt.qclient = val | ||
} | ||
} | ||
|
||
func Certificate(t testing.TB, addr sdk.Address, opts ...CertificateOption) TestCertificate { | ||
t.Helper() | ||
|
||
opt := &certificateOption{} | ||
|
||
for _, o := range opts { | ||
o(opt) | ||
} | ||
|
||
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
if opt.nbf.IsZero() { | ||
opt.nbf = time.Now() | ||
} | ||
|
||
if opt.naf.IsZero() { | ||
opt.naf = opt.nbf.Add(time.Hour * 24 * 365) | ||
} | ||
|
||
extKeyUsage := []x509.ExtKeyUsage{ | ||
x509.ExtKeyUsageClientAuth, | ||
} | ||
|
||
if len(opt.domains) != 0 { | ||
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageServerAuth) | ||
} | ||
|
||
template := x509.Certificate{ | ||
SerialNumber: new(big.Int).SetInt64(time.Now().UTC().UnixNano()), | ||
Subject: pkix.Name{ | ||
CommonName: addr.String(), | ||
ExtraNames: []pkix.AttributeTypeAndValue{ | ||
{ | ||
Type: certutils.AuthVersionOID, | ||
Value: "v0.0.1", | ||
}, | ||
}, | ||
}, | ||
Issuer: pkix.Name{ | ||
CommonName: addr.String(), | ||
}, | ||
NotBefore: opt.nbf, | ||
NotAfter: opt.naf, | ||
KeyUsage: x509.KeyUsageDataEncipherment | x509.KeyUsageKeyEncipherment, | ||
ExtKeyUsage: extKeyUsage, | ||
BasicConstraintsValid: true, | ||
} | ||
|
||
var ips []net.IP | ||
|
||
for i := len(opt.domains) - 1; i >= 0; i-- { | ||
if ip := net.ParseIP(opt.domains[i]); ip != nil { | ||
ips = append(ips, ip) | ||
opt.domains = append(opt.domains[:i], opt.domains[i+1:]...) | ||
} | ||
} | ||
|
||
if len(opt.domains) != 0 || len(ips) != 0 { | ||
template.PermittedDNSDomainsCritical = true | ||
template.PermittedDNSDomains = opt.domains | ||
template.DNSNames = opt.domains | ||
template.IPAddresses = ips | ||
} | ||
|
||
var certDer []byte | ||
if certDer, err = x509.CreateCertificate(rand.Reader, &template, &template, priv.Public(), priv); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
var keyDer []byte | ||
if keyDer, err = x509.MarshalPKCS8PrivateKey(priv); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
var pubKeyDer []byte | ||
if pubKeyDer, err = x509.MarshalPKIXPublicKey(priv.Public()); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
res := TestCertificate{ | ||
Serial: *template.SerialNumber, | ||
PEM: struct { | ||
Cert []byte | ||
Priv []byte | ||
Pub []byte | ||
}{ | ||
Cert: pem.EncodeToMemory(&pem.Block{ | ||
Type: types.PemBlkTypeCertificate, | ||
Bytes: certDer, | ||
}), | ||
Priv: pem.EncodeToMemory(&pem.Block{ | ||
Type: types.PemBlkTypeECPrivateKey, | ||
Bytes: keyDer, | ||
}), | ||
Pub: pem.EncodeToMemory(&pem.Block{ | ||
Type: types.PemBlkTypeECPublicKey, | ||
Bytes: pubKeyDer, | ||
}), | ||
}, | ||
} | ||
|
||
cert, err := tls.X509KeyPair(res.PEM.Cert, res.PEM.Priv) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
res.Cert = append(res.Cert, cert) | ||
|
||
if opt.qclient != nil { | ||
opt.qclient.On("Certificates", | ||
mock.Anything, | ||
&types.QueryCertificatesRequest{ | ||
Filter: types.CertificateFilter{ | ||
Owner: addr.String(), | ||
Serial: res.Serial.String(), | ||
State: "valid", | ||
}, | ||
}). | ||
Return(&types.QueryCertificatesResponse{ | ||
Certificates: types.CertificatesResponse{ | ||
types.CertificateResponse{ | ||
Certificate: types.Certificate{ | ||
State: types.CertificateValid, | ||
Cert: res.PEM.Cert, | ||
Pubkey: res.PEM.Pub, | ||
}, | ||
Serial: res.Serial.String(), | ||
}, | ||
}, | ||
}, nil) | ||
} | ||
return res | ||
} | ||
|
||
func CertificateRequireEqualResponse(t *testing.T, cert TestCertificate, resp types.CertificateResponse, state types.Certificate_State) { | ||
t.Helper() | ||
|
||
require.Equal(t, state, resp.Certificate.State) | ||
require.Equal(t, cert.PEM.Cert, resp.Certificate.Cert) | ||
require.Equal(t, cert.PEM.Pub, resp.Certificate.Pubkey) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package testutil | ||
|
||
import ( | ||
"crypto/sha256" | ||
"math/rand" | ||
"testing" | ||
|
||
dtypes "github.com/akash-network/akash-api/go/node/deployment/v1beta3" | ||
) | ||
|
||
// sum256Seed provides a consistent sha256 value for initial Deployment.Version | ||
const sum256Seed = "hihi" | ||
|
||
// DefaultDeploymentVersion provides consistent sha256 sum for initial Deployment.Version | ||
var DefaultDeploymentVersion = sha256.Sum256([]byte(sum256Seed)) | ||
|
||
// Deployment generates a dtype.Deployment in state `DeploymentActive` | ||
func Deployment(t testing.TB) dtypes.Deployment { | ||
t.Helper() | ||
return dtypes.Deployment{ | ||
DeploymentID: DeploymentID(t), | ||
State: dtypes.DeploymentActive, | ||
Version: DefaultDeploymentVersion[:], | ||
} | ||
} | ||
|
||
// DeploymentGroup generates a dtype.DepDeploymentGroup in state `GroupOpen` | ||
// with a set of random required attributes | ||
func DeploymentGroup(t testing.TB, did dtypes.DeploymentID, gseq uint32) dtypes.Group { | ||
t.Helper() | ||
return dtypes.Group{ | ||
GroupID: dtypes.MakeGroupID(did, gseq), | ||
State: dtypes.GroupOpen, | ||
GroupSpec: dtypes.GroupSpec{ | ||
Name: Name(t, "dgroup"), | ||
Requirements: PlacementRequirements(t), | ||
Resources: Resources(t), | ||
}, | ||
} | ||
} | ||
|
||
// GroupSpec generator | ||
func GroupSpec(t testing.TB) dtypes.GroupSpec { | ||
t.Helper() | ||
return dtypes.GroupSpec{ | ||
Name: Name(t, "dgroup"), | ||
Requirements: PlacementRequirements(t), | ||
Resources: Resources(t), | ||
} | ||
} | ||
|
||
// DeploymentGroups returns a set of deployment groups generated by DeploymentGroup | ||
func DeploymentGroups(t testing.TB, did dtypes.DeploymentID, gseq uint32) []dtypes.Group { | ||
t.Helper() | ||
count := rand.Intn(5) + 5 // nolint:gosec | ||
vals := make([]dtypes.Group, 0, count) | ||
for i := 0; i < count; i++ { | ||
vals = append(vals, DeploymentGroup(t, did, gseq+uint32(i))) | ||
} | ||
return vals | ||
} |
Oops, something went wrong.