Compare commits

...

8 Commits

Author SHA1 Message Date
e77a67a3de feat: load env from file 2023-03-09 13:29:05 +01:00
d815b12719 feat: update README 2023-03-08 12:17:48 +01:00
7660cc57fd feat: writer test full coverage 2023-03-05 15:00:53 +01:00
25526ac993 feat: cmd add some tests 2023-03-05 15:00:37 +01:00
0bf26d2019 feat: fix force error after delete directory 2023-03-05 00:10:46 +01:00
b049c6a779 fix lint 2023-03-05 00:07:48 +01:00
0bf7b63286 feat: test coverage more than 85% 2023-03-05 00:05:00 +01:00
89136cae59 feat: test coverage more than 80% 2023-03-05 00:04:41 +01:00
8 changed files with 239 additions and 33 deletions

View File

@@ -8,7 +8,7 @@ I had some trouble during TLS communication between both of my gRPC server and c
## TODO:
- [ ] Create intermediate authority to sign certificates on behalf CA to add more security. If intermediate is hacked then you can revoke from CA and generate new intermediates keeping CA isolated from beeing hacked.
- [ ] Complete tests
- ~~[x] Complete tests~~
## Configuration
If you are on `dev` environment, like I've been doing, you must create `.env` file similar as `.env.example` in this repo:
@@ -59,6 +59,23 @@ Then you can just run
go run main.go
```
## tests
Just simply run make command and watch coverage results on `cover.html` within `coverage`
```shell
make test-coverage
rm -rf coverage
mkdir coverage
go test -v -coverprofile coverage/cover.out ./...
=== RUN TestCredentialsFromKeyWithPasswd
--- PASS: TestCredentialsFromKeyWithPasswd (0.37s)
=== RUN TestCredentialsFromKeyWithPasswdError
--- PASS: TestCredentialsFromKeyWithPasswdError (0.46s)
PASS
coverage: 90.9% of statements
ok gitea.urkob.com/urko/go-grpc-certificate/pkg/credentials 0.839s coverage: 90.9% of statements
go tool cover -html coverage/cover.out -o coverage/cover.html
```
## goreportcard
```bash
make goreportcard

View File

@@ -27,9 +27,9 @@ var envConfig struct {
var writer pkgio.WriterIface
func intEnvConfig(isProd bool) {
if !isProd {
err := godotenv.Load(util.RootDir() + "/.env")
func intEnvConfig(envFilePath string) {
if envFilePath != "" {
err := godotenv.Load(envFilePath)
if err != nil {
log.Fatalf("environment variable ENV is empty and an error occurred while loading the .env file: %s\n", err)
}
@@ -87,32 +87,59 @@ var rootCmd = &cobra.Command{
log.Fatalf("rootCA.WithClientCert: %s", err)
}
exportPem("root-ca.pem", rootCA.PEM())
exportPem("root-key.pem", rootCA.Key())
outputPath, err := exportPem("root-ca.pem", rootCA.PEM())
if err != nil {
log.Fatalf("exportPem: %s\n", err)
}
log.Printf("file created successfully: %s\n", outputPath)
exportPem("client-cert.pem", clientCert.PEM())
exportPem("client-key.pem", clientCert.Key())
outputPath, err = exportPem("root-key.pem", rootCA.Key())
if err != nil {
log.Fatalf("exportPem: %s\n", err)
}
log.Printf("file created successfully: %s\n", outputPath)
outputPath, err = exportPem("client-cert.pem", clientCert.PEM())
if err != nil {
log.Fatalf("exportPem: %s\n", err)
}
log.Printf("file created successfully: %s\n", outputPath)
outputPath, err = exportPem("client-key.pem", clientCert.Key())
if err != nil {
log.Fatalf("exportPem: %s\n", err)
}
log.Printf("file created successfully: %s\n", outputPath)
},
}
func getExtKeyUsage(intKeyUsageSlice []int) []x509.ExtKeyUsage {
extKeyUsage := make([]x509.ExtKeyUsage, len(intKeyUsageSlice))
if intKeyUsageSlice == nil || len(intKeyUsageSlice) <= 0 {
return []x509.ExtKeyUsage{}
}
extKeyUsage := make([]x509.ExtKeyUsage, 0, len(intKeyUsageSlice))
for _, v := range intKeyUsageSlice {
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsage(v))
}
return extKeyUsage
}
func exportPem(filename string, data []byte) {
func exportPem(filename string, data []byte) (string, error) {
outputPath, err := writer.WriteFile(filename, data)
if err != nil {
log.Fatalf("rootCA.WithClientCert: %s", err)
return "", fmt.Errorf("rootCA.WithClientCert: %s", err)
}
log.Printf("file created successfully: %s\n", outputPath)
return outputPath, nil
}
func init() {
intEnvConfig(false)
envFile := ""
if os.Getenv("ENV") != "prod" {
envFile = "./.env"
}
intEnvConfig(envFile)
cobra.OnInitialize(initConfig)
}

View File

@@ -1,7 +1,62 @@
package cmd
import "testing"
import (
"crypto/x509"
"log"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/urkob/go-cert-gen/internal/io"
)
func TestExecute(t *testing.T) {
Execute()
}
func Test_getExtKeyUsage(t *testing.T) {
intKeyUsageSlice := make([]int, 0, 1)
intKeyUsageSlice = append(intKeyUsageSlice, int(x509.ExtKeyUsageClientAuth))
keyUsage := getExtKeyUsage(intKeyUsageSlice)
assert.Len(t, keyUsage, len(intKeyUsageSlice))
assert.Equal(t, keyUsage[0], x509.ExtKeyUsageClientAuth)
intKeyUsageSlice = make([]int, 0)
keyUsage = getExtKeyUsage(intKeyUsageSlice)
assert.Len(t, keyUsage, 0)
keyUsage = getExtKeyUsage(nil)
assert.Len(t, keyUsage, 0)
}
var testFile = "test-file.txt"
func init() {
wd, err := os.Getwd()
if err != nil {
log.Fatalf("os.Getwd: %s\n", err)
}
writer = io.NewWriter(wd)
}
func Test_exportPem(t *testing.T) {
defer func() {
os.Remove(testFile)
err := os.Remove(testFile)
require.NoError(t, err)
}()
data := []byte("test data")
outputPath, err := exportPem(testFile, data)
require.NoError(t, err)
require.NotEmpty(t, outputPath)
}
func Test_exportPemError(t *testing.T) {
data := []byte("test data")
outputPath, err := exportPem("", data)
require.Error(t, err)
require.Empty(t, outputPath)
}

View File

@@ -83,6 +83,12 @@ func Test_newRootCA(t *testing.T) {
require.Greater(t, len(keyPEM), 0)
}
func Test_newRootCAError(t *testing.T) {
_, _, err := newRootCA(&ca.CaConfig{})
require.Error(t, err)
}
func Test_parseCertificate(t *testing.T) {
caPEM, _, err := newRootCA(&rootTestConfig)
require.NoError(t, err)
@@ -126,3 +132,12 @@ func Test_rootCA_WithClientCert(t *testing.T) {
require.NotNil(t, clientSrv.PEM())
require.Greater(t, len(clientSrv.PEM()), 0)
}
func Test_rootCA_WithClientCertEror(t *testing.T) {
rootCert := rootCA{
caPEM: nil,
}
_, err := rootCert.WithClientCert(&clientTestConfig)
require.Error(t, err)
}

View File

@@ -2,6 +2,7 @@ package io
import (
"fmt"
"log"
"os"
"gitlab.com/urkob/go-cert-gen/pkg/io"
@@ -11,22 +12,33 @@ type writer struct {
dirPath string
}
// WriteFile writes file into `w writer` directory.
// Returns outputPath and error
func (w writer) WriteFile(filename string, data []byte) (string, error) {
if filename == "" {
return "", fmt.Errorf("filename cannot be empty")
}
if w.dirPath == "" {
return "", fmt.Errorf("export directory cannot be empty")
}
if err := os.MkdirAll(w.dirPath, 0o755); err != nil {
return "", err
}
log.Println("to write file")
outputPath := w.dirPath + "/" + filename
if err := os.WriteFile(outputPath, data, 0o600); err != nil {
return "", err
}
log.Println("file written")
return outputPath, nil
}
func NewWriter(dirPath string) io.WriterIface {
return newWriter(dirPath)
}
func newWriter(dirPath string) *writer {
return &writer{
dirPath: dirPath,
}

View File

@@ -0,0 +1,94 @@
package io
import (
"io/fs"
"log"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var (
testWriterPath = "testPath"
testWriterPathError = "test Path, @:ººººº\\/.Ç*⁺´+"
testFileContent = []byte("test data")
testFileName = "test-file.txt"
workingDir = ""
)
func deleteAllDirs() error {
return os.RemoveAll(testWriterPath)
}
func init() {
err := deleteAllDirs()
if err != nil {
log.Fatalln("deleteAllDirs: ", err)
}
workingDir, err = os.Getwd()
if err != nil {
log.Fatalln("os.Getwd: ", err)
}
}
func Test_newWriter(t *testing.T) {
w := newWriter(testWriterPath)
require.NotNil(t, w)
}
func TestNewWriter(t *testing.T) {
w := NewWriter(testWriterPath)
require.NotNil(t, w)
}
func Test_writer_WriteFile(t *testing.T) {
err := deleteAllDirs()
require.NoError(t, err)
defer func(t *testing.T) {
err := deleteAllDirs()
require.NoError(t, err)
}(t)
w := newWriter(testWriterPath)
wgot, err := w.WriteFile(testFileName, testFileContent)
require.NoError(t, err)
btsReaded, err := os.ReadFile(wgot)
require.NoError(t, err)
require.NotEmpty(t, btsReaded)
require.Equal(t, string(btsReaded), string(testFileContent))
}
func Test_writer_WriteFileError(t *testing.T) {
err := deleteAllDirs()
require.NoError(t, err)
defer func(t *testing.T) {
err := deleteAllDirs()
require.NoError(t, err)
}(t)
w := newWriter("")
_, err = w.WriteFile(testFileName, testFileContent)
assert.Error(t, err)
w = newWriter(testWriterPath)
_, err = w.WriteFile("", testFileContent)
require.Error(t, err)
err = os.MkdirAll(testWriterPath, fs.ModeDir)
require.NoError(t, err, "mkdir should not throw error")
err = os.MkdirAll(testWriterPath+"/"+testFileName, fs.ModeDir)
require.NoError(t, err)
_, err = w.WriteFile(testFileName, nil)
assert.Error(t, err)
w = newWriter(testWriterPathError)
_, err = w.WriteFile(testFileName, testFileContent)
require.Error(t, err)
}

View File

@@ -29,26 +29,10 @@ type Subject struct {
PostalCode string
}
/*
var (
subjectKeyId = []byte{1, 2, 3, 4, 6}
extKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}
keyUsage = x509.KeyUsageDigitalSignature
)
func NewDefaultConfig() *ClientCertConfig {
return &ClientCertConfig{
Serial: big.NewInt(12321),
Subject: Subject{
Organization: "",
Country: "",
Province: "",
Locality: "",
StreetAddress: "",
PostalCode: "",
},
Duration: time.Duration(time.Hour * 24 * 365),
SubjectKeyId: subjectKeyId,
ExtKeyUsage: extKeyUsage,
KeyUsage: keyUsage,
}
}
*/

View File

@@ -1,5 +1,7 @@
package io
type WriterIface interface {
// WriteFile writes file into `w writer` directory.
// Returns outputPath and error
WriteFile(filename string, data []byte) (string, error)
}