Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring and increasing code coverage #18

Merged
merged 31 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
5ce3e90
implement crypto services
MGTheTrain Nov 20, 2024
fdbb6da
consider descriptive file names
MGTheTrain Nov 20, 2024
b37a82b
Merge branch 'main' into feature/secure-file-storage
MGTheTrain Nov 20, 2024
381c493
add missing character
MGTheTrain Nov 20, 2024
22558e2
add help target
MGTheTrain Nov 20, 2024
ec663c2
merge main
MGTheTrain Nov 21, 2024
09ffbb8
Merge branch 'main' into feature/secure-file-storage
MGTheTrain Nov 21, 2024
129e97b
consider userId as input argument and fix Upload(...) logic
MGTheTrain Nov 21, 2024
92f3ab7
rename variable
MGTheTrain Nov 21, 2024
3cd7a0c
fail fast
MGTheTrain Nov 21, 2024
ecde810
rename struct
MGTheTrain Nov 21, 2024
6f12014
modify comment
MGTheTrain Nov 21, 2024
99537f0
remove obsolete members variables in test contexts
MGTheTrain Nov 21, 2024
eee3031
properly format the error message using %v
MGTheTrain Nov 21, 2024
fa4e5e4
remove test db setup and cleanup fro TestMain
MGTheTrain Nov 21, 2024
c66e3cb
modify connector tests
MGTheTrain Nov 21, 2024
39dfe69
remove obsolete comments
MGTheTrain Nov 21, 2024
11ad9ae
update and validate member variables of CryptoKeyMeta struct
MGTheTrain Nov 21, 2024
3309bb3
remove redundant check
MGTheTrain Nov 21, 2024
b46fafd
modify signatures in VaultConnector and corresponding test
MGTheTrain Nov 21, 2024
a95f095
remove obsolete comments
MGTheTrain Nov 21, 2024
f9c1c90
modify Upload(...) signature
MGTheTrain Nov 21, 2024
aca7dc0
rename interfaces and structs
MGTheTrain Nov 21, 2024
730a8c1
add an integration test for CryptoKeyUploadService's Upload(...) method
MGTheTrain Nov 21, 2024
f63cff4
refactor connector tests
MGTheTrain Nov 21, 2024
6acdf16
refactor persistence layer integration tests
MGTheTrain Nov 21, 2024
b2c3a37
remove enum, modify Download(...) signature and logic
MGTheTrain Nov 21, 2024
c85f473
increase code coverage on key services
MGTheTrain Nov 21, 2024
40449ed
fix linter findings
MGTheTrain Nov 21, 2024
7da7a1c
add folder dedicated to helpers for e.g. mocks, DB setup
MGTheTrain Nov 21, 2024
e2adaff
refactor db context helper to consider unique database names
MGTheTrain Nov 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,43 @@ SCRIPT_DIR = "scripts"
.PHONY: format-and-lint run-unit-tests run-integration-tests \
spin-up-integration-test-docker-containers \
shut-down-integration-test-docker-containers \
spin-up-docker-containers shut-down-docker-containers

spin-up-docker-containers shut-down-docker-containers help

# Help target to list all available targets
help:
@echo "Available Makefile targets:"
@echo " format-and-lint - Run the format and linting script"
@echo " run-unit-tests - Run the unit tests"
@echo " run-integration-tests - Run the integration tests"
@echo " spin-up-integration-test-docker-containers - Spin up Docker containers for integration tests (Postgres, Azure Blob Storage)"
@echo " shut-down-integration-test-docker-containers - Shut down Docker containers for integration tests"
@echo " spin-up-docker-containers - Spin up Docker containers with internal containerized applications"
@echo " shut-down-docker-containers - Shut down the application Docker containers"

# Run the format and lint script
format-and-lint:
@cd $(SCRIPT_DIR) && ./format-and-lint.sh

# Run unit tests
run-unit-tests:
@cd $(SCRIPT_DIR) && ./run-test.sh -u

# Run integration tests
run-integration-tests:
@cd $(SCRIPT_DIR) && ./run-test.sh -i

# Spin up Docker containers for integration tests
spin-up-integration-test-docker-containers:
docker-compose up -d postgres azure-blob-storage

# Shut down Docker containers for integration tests
shut-down-integration-test-docker-containers:
docker-compose down postgres azure-blob-storage -v

# Spin up Docker containers with internal containerized applications
spin-up-docker-containers:
docker-compose up -d --build

# Shut down Docker containers with internal containerized applications
shut-down-docker-containers:
docker-compose down -v
docker-compose down -v
4 changes: 2 additions & 2 deletions cmd/crypto-vault-cli/internal/commands/aes-commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func EncryptAESCmd(cmd *cobra.Command, args []string) {
log.Fatalf("Error: input, output, and keyDir flags are required\n")
}

aes := &cryptography.AESCrypto{}
aes := &cryptography.AES{}

// Generate AES Key
key, err := aes.GenerateKey(keySize)
Expand Down Expand Up @@ -85,7 +85,7 @@ func DecryptAESCmd(cmd *cobra.Command, args []string) {
log.Fatalf("Error reading encrypted file: %v\n", err)
}

aes := &cryptography.AESCrypto{}
aes := &cryptography.AES{}

decryptedData, err := aes.Decrypt(encryptedData, key)
if err != nil {
Expand Down
18 changes: 9 additions & 9 deletions cmd/crypto-vault-cli/internal/commands/ecdsa-commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ func SignECCCmd(cmd *cobra.Command, args []string) {
}

// ECC implementation
ECCrypto := &cryptography.ECCrypto{}
EC := &cryptography.EC{}
var privateKey *ecdsa.PrivateKey
var publicKey *ecdsa.PublicKey
var err error

// Generate new ECC keys if no private key is provided
privateKey, publicKey, err = ECCrypto.GenerateKeys(elliptic.P256())
privateKey, publicKey, err = EC.GenerateKeys(elliptic.P256())
if err != nil {
log.Fatalf("Error generating ECC keys: %v\n", err)
}
Expand All @@ -44,7 +44,7 @@ func SignECCCmd(cmd *cobra.Command, args []string) {
}

// Sign the file content (hash the content before signing)
signature, err := ECCrypto.Sign(fileContent, privateKey)
signature, err := EC.Sign(fileContent, privateKey)
if err != nil {
log.Fatalf("Error signing file content: %v\n", err)
}
Expand All @@ -57,7 +57,7 @@ func SignECCCmd(cmd *cobra.Command, args []string) {
if privateKey != nil && keyDir != "" {
privateKeyFilePath := fmt.Sprintf("%s/%s-private_key.pem", keyDir, uniqueID.String())

err = ECCrypto.SavePrivateKeyToFile(privateKey, privateKeyFilePath)
err = EC.SavePrivateKeyToFile(privateKey, privateKeyFilePath)
if err != nil {
log.Fatalf("Error saving private key: %v\n", err)
}
Expand All @@ -66,7 +66,7 @@ func SignECCCmd(cmd *cobra.Command, args []string) {

if publicKey != nil && keyDir != "" {
publicKeyFilePath := fmt.Sprintf("%s/%s-public_key.pem", keyDir, uniqueID.String())
err = ECCrypto.SavePublicKeyToFile(publicKey, publicKeyFilePath)
err = EC.SavePublicKeyToFile(publicKey, publicKeyFilePath)
if err != nil {
log.Fatalf("Error saving public key: %v\n", err)
}
Expand All @@ -76,7 +76,7 @@ func SignECCCmd(cmd *cobra.Command, args []string) {
// Save the signature to a file in the data folder (optional, based on the input file)
if keyDir != "" {
signatureFilePath := fmt.Sprintf("%s/%s-signature.sig", keyDir, uniqueID.String())
err = ECCrypto.SaveSignatureToFile(signatureFilePath, signature)
err = EC.SaveSignatureToFile(signatureFilePath, signature)
if err != nil {
log.Fatalf("Error saving signature: %v\n", err)
}
Expand All @@ -91,15 +91,15 @@ func VerifyECCCmd(cmd *cobra.Command, args []string) {
signatureFile, _ := cmd.Flags().GetString("signature") // Path to signature file

// ECC implementation
ECCrypto := &cryptography.ECCrypto{}
EC := &cryptography.EC{}
var publicKey *ecdsa.PublicKey
var err error

// Read the public key
if publicKeyPath == "" {
log.Fatalf("Public key is required for ECC signature verification.\n")
} else {
publicKey, err = ECCrypto.ReadPublicKey(publicKeyPath, elliptic.P256())
publicKey, err = EC.ReadPublicKey(publicKeyPath, elliptic.P256())
if err != nil {
log.Fatalf("Error reading public key: %v\n", err)
}
Expand All @@ -124,7 +124,7 @@ func VerifyECCCmd(cmd *cobra.Command, args []string) {
}

// Verify the signature
valid, err := ECCrypto.Verify(fileContent, signature, publicKey)
valid, err := EC.Verify(fileContent, signature, publicKey)
if err != nil {
log.Fatalf("Error verifying signature: %v\n", err)
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/crypto-vault-cli/internal/commands/rsa-commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func EncryptRSACmd(cmd *cobra.Command, args []string) {
// Generate RSA keys if no public key is provided
var publicKey *rsa.PublicKey
var err error
rsa := &cryptography.RSACrypto{}
rsa := &cryptography.RSA{}

uniqueID := uuid.New()
// Generate RSA keys
Expand Down Expand Up @@ -78,7 +78,7 @@ func DecryptRSACmd(cmd *cobra.Command, args []string) {
// Generate RSA keys if no private key is provided
var privateKey *rsa.PrivateKey
var err error
rsa := &cryptography.RSACrypto{}
rsa := &cryptography.RSA{}
if privateKeyPath == "" {
// Generate RSA keys
privKey, _, genErr := rsa.GenerateKeys(2048)
Expand Down
7 changes: 4 additions & 3 deletions docs/diagrams/erd.mmd
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
erDiagram
CRYPTOGRAPHIC_KEY {
CRYPTO_KEY_META {
string id PK
string algorithm
string type
datetime date_time_created
string user_id FK
}

BLOB {
BLOB_META {
string id PK
datetime date_time_created
string user_id FK
Expand All @@ -18,4 +19,4 @@ erDiagram
string hash_algorithm
}

CRYPTOGRAPHIC_KEY ||--o| BLOB : "associated with"
CRYPTO_KEY_META ||--o| BLOB_META : "associated with"
28 changes: 13 additions & 15 deletions internal/app/services/blob_services.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,27 @@ func NewBlobUploadService(blobConnector connector.BlobConnector, blobRepository
func (s *BlobUploadService) Upload(filePaths []string, userId string) ([]*blobs.BlobMeta, error) {

// Use the BlobConnector to upload the files to Azure Blob Storage
blobMeta, err := s.BlobConnector.Upload(filePaths, userId)
blobMetas, err := s.BlobConnector.Upload(filePaths, userId)
if err != nil {
return nil, fmt.Errorf("failed to upload blobs: %w", err)
}

// If no blobs are uploaded, return early
if len(blobMeta) == 0 {
if len(blobMetas) == 0 {
return nil, fmt.Errorf("no blobs uploaded")
}

// Store the metadata in the database using the BlobRepository
for _, blob := range blobMeta {
err := s.BlobRepository.Create(blob)
for _, blobMeta := range blobMetas {
err := s.BlobRepository.Create(blobMeta)
if err != nil {
// Rollback any previously uploaded blobs if the metadata fails to store
// (you can call delete method to handle this as needed)
return nil, fmt.Errorf("failed to store metadata for blob '%s': %w", blob.Name, err)
return nil, fmt.Errorf("failed to store metadata for blob '%s': %w", blobMeta.Name, err)
}
}

// Return the metadata of uploaded blobs
return blobMeta, nil
return blobMetas, nil
}

// BlobMetadataService implements the BlobMetadataService interface for retrieving and deleting blob metadata
Expand All @@ -66,27 +65,27 @@ func NewBlobMetadataService(blobRepository repository.BlobRepository, blobConnec
// List retrieves all blobs' metadata considering a query filter
func (s *BlobMetadataService) List(query *blobs.BlobMetaQuery) ([]*blobs.BlobMeta, error) {
// Assuming BlobRepository has a method to query metadata, you can adapt to GORM queries.
var blobsList []*blobs.BlobMeta
var blobMetas []*blobs.BlobMeta

// TBD

return blobsList, nil
return blobMetas, nil
}

// GetByID retrieves a blob's metadata by its unique ID
func (s *BlobMetadataService) GetByID(blobID string) (*blobs.BlobMeta, error) {
// Retrieve the blob metadata using the BlobRepository
blob, err := s.BlobRepository.GetById(blobID)
blobMeta, err := s.BlobRepository.GetById(blobID)
if err != nil {
return nil, fmt.Errorf("failed to retrieve blob metadata by ID '%s': %w", blobID, err)
}
return blob, nil
return blobMeta, nil
}

// DeleteByID deletes a blob and its associated metadata by ID
func (s *BlobMetadataService) DeleteByID(blobID string) error {
// Retrieve the blob metadata to ensure it exists
blob, err := s.BlobRepository.GetById(blobID)
blobMeta, err := s.BlobRepository.GetById(blobID)
if err != nil {
return fmt.Errorf("failed to retrieve blob metadata by ID '%s' for deletion: %w", blobID, err)
}
Expand All @@ -98,9 +97,9 @@ func (s *BlobMetadataService) DeleteByID(blobID string) error {
}

// Now, delete the actual blob from the Blob Storage
err = s.BlobConnector.Delete(blob.ID, blob.Name)
err = s.BlobConnector.Delete(blobMeta.ID, blobMeta.Name)
if err != nil {
return fmt.Errorf("failed to delete blob '%s' from Blob Storage: %w", blob.Name, err)
return fmt.Errorf("failed to delete blob '%s' from Blob Storage: %w", blobMeta.Name, err)
}

return nil
Expand All @@ -127,6 +126,5 @@ func (s *BlobDownloadService) Download(blobID, blobName string) ([]byte, error)
return nil, fmt.Errorf("failed to download blob '%s': %w", blobName, err)
}

// Return the metadata and content of the downloaded blob
return blob, nil
}
56 changes: 8 additions & 48 deletions internal/app/services/key_services.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,51 +5,26 @@ import (
"crypto_vault_service/internal/infrastructure/connector"
"crypto_vault_service/internal/persistence/repository"
"fmt"
"time"

"github.com/google/uuid"
)

type CryptKeyUploadService struct {
type CryptoKeyUploadService struct {
VaultConnector connector.VaultConnector
CryptoKeyRepo repository.CryptoKeyRepository
}

func (s *CryptKeyUploadService) Upload(filePaths []string) ([]*keys.CryptoKeyMeta, error) {
func (s *CryptoKeyUploadService) Upload(filePath, userId, keyType, keyAlgorihm string) (*keys.CryptoKeyMeta, error) {
// Step 1: Upload files to blob storage
userId := uuid.New().String()
blobMeta, err := s.VaultConnector.Upload(filePaths, userId)
keyMeta, err := s.VaultConnector.Upload(filePath, userId, keyType, keyAlgorihm)
if err != nil {
return nil, fmt.Errorf("failed to upload files: %w", err)
}

// Step 2: Store the metadata in the database
var keyMetas []*keys.CryptoKeyMeta
for _, blob := range blobMeta {
// Map Blob metadata to CryptoKey metadata
keyMeta := &keys.CryptoKeyMeta{
ID: uuid.New().String(), // Generate valid UUID for ID
Type: "RSA", // Example key type
DateTimeCreated: time.Now(), // Valid DateTimeCreated time
UserID: uuid.New().String(), // Generate valid UUID for UserID
}

// Validate CryptoKeyMeta
if err := keyMeta.Validate(); err != nil {
return nil, fmt.Errorf("invalid key metadata: %w", err)
}

// Save metadata to DB
if err := s.CryptoKeyRepo.Create(blob); err != nil {
return nil, fmt.Errorf("failed to create metadata for key of type %s: %w", keyMeta.Type, err)
}

// Append to list
keyMetas = append(keyMetas, keyMeta)
if err := s.CryptoKeyRepo.Create(keyMeta); err != nil {
return nil, fmt.Errorf("failed to create metadata for key of type %s: %w", keyMeta.Type, err)
}

// Return metadata
return keyMetas, nil
return keyMeta, nil
}

// CryptoKeyMetadataService manages cryptographic key metadata.
Expand All @@ -59,7 +34,6 @@ type CryptoKeyMetadataService struct {

// List retrieves all cryptographic key metadata based on a query.
func (s *CryptoKeyMetadataService) List(query *keys.CryptoKeyQuery) ([]*keys.CryptoKeyMeta, error) {
// For now, let's just retrieve all metadata from the database
var keyMetas []*keys.CryptoKeyMeta
// TBD

Expand All @@ -68,7 +42,6 @@ func (s *CryptoKeyMetadataService) List(query *keys.CryptoKeyQuery) ([]*keys.Cry

// GetByID retrieves the metadata of a cryptographic key by its ID.
func (s *CryptoKeyMetadataService) GetByID(keyID string) (*keys.CryptoKeyMeta, error) {
// Retrieve the metadata from the database
keyMeta, err := s.CryptoKeyRepo.GetByID(keyID)
if err != nil {
return nil, fmt.Errorf("failed to retrieve key metadata: %w", err)
Expand All @@ -93,24 +66,11 @@ type CryptoKeyDownloadService struct {
}

// Download retrieves a cryptographic key by its ID and type.
func (s *CryptoKeyDownloadService) Download(keyID string, keyType keys.KeyType) ([]byte, error) {
blobName := "" // Declare the variable outside the blocks

if keyType == keys.AsymmetricPublic {
blobName = "asymmetric-public-key" // Assign to the already declared variable
} else if keyType == keys.AsymmetricPrivate {
blobName = "asymmetric-private-key" // Assign to the already declared variable
} else if keyType == keys.Symmetric {
blobName = "symmetric-key" // Assign to the already declared variable
} else {
return nil, fmt.Errorf("unsupported key type: %v", keyType)
}

blobData, err := s.VaultConnector.Download(keyID, blobName)
func (s *CryptoKeyDownloadService) Download(keyID, keyType string) ([]byte, error) {
blobData, err := s.VaultConnector.Download(keyID, keyType)
if err != nil {
return nil, fmt.Errorf("failed to download key from blob storage: %w", err)
}

// Return the metadata and the downloaded content (as a byte slice)
return blobData, nil
}
2 changes: 1 addition & 1 deletion internal/domain/blobs/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ func (b *BlobMeta) Validate() error {
}
return fmt.Errorf("Validation failed: %v", validationErrors)
}
return nil // Return nil if validation passes
return nil
}
1 change: 0 additions & 1 deletion internal/domain/blobs/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,5 @@ func (b *BlobMetaQuery) Validate() error {
return fmt.Errorf("Validation failed: %v", validationErrors)
}

// Return nil if no validation errors are found
return nil
}
Loading
Loading