From 7639e418dd2ddff663ab07c5673d0614c05c9405 Mon Sep 17 00:00:00 2001 From: Marvin Gajek Date: Wed, 20 Nov 2024 09:36:52 +0100 Subject: [PATCH 01/14] rename service interfaces --- internal/domain/blobs/contract.go | 12 ++++++------ internal/domain/keys/contract.go | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/internal/domain/blobs/contract.go b/internal/domain/blobs/contract.go index d24a792..88912c1 100644 --- a/internal/domain/blobs/contract.go +++ b/internal/domain/blobs/contract.go @@ -1,14 +1,14 @@ package blobs -// BlobUploadService defines methods for uploading blobs. -type BlobUploadService interface { +// IBlobUploadService defines methods for uploading blobs. +type IBlobUploadService interface { // Upload handles the upload of blobs from the specified file paths. // It returns a slice of Blob for the uploaded blobs and any error encountered during the upload process. Upload(filePaths []string) ([]*BlobMeta, error) } -// BlobMetadataService defines methods for retrieving Blob and deleting a blob along with its metadata. -type BlobMetadataService interface { +// IBlobMetadataService defines methods for retrieving Blob and deleting a blob along with its metadata. +type IBlobMetadataService interface { // List retrieves all blobs' metadata considering a query filter when set. // It returns a slice of Blob and any error encountered during the retrieval. List(query *BlobMetaQuery) ([]*BlobMeta, error) @@ -22,8 +22,8 @@ type BlobMetadataService interface { DeleteByID(blobID string) error } -// BlobDownloadService defines methods for downloading blobs. -type BlobDownloadService interface { +// IBlobDownloadService defines methods for downloading blobs. +type IBlobDownloadService interface { // Download retrieves a blob by its ID and name. // It returns the Blob, the file data as a byte slice, and any error encountered during the download process. Download(blobID, blobName string) (*BlobMeta, []byte, error) diff --git a/internal/domain/keys/contract.go b/internal/domain/keys/contract.go index ac5db35..b794013 100644 --- a/internal/domain/keys/contract.go +++ b/internal/domain/keys/contract.go @@ -10,15 +10,15 @@ const ( Symmetric // Symmetric key (e.g., AES) ) -// CryptKeyUploadService defines methods for uploading cryptographic keys. -type CryptKeyUploadService interface { +// ICryptKeyUploadService defines methods for uploading cryptographic keys. +type ICryptKeyUploadService interface { // Upload uploads cryptographic keys from specified file paths. // It returns a slice of CryptoKeyMeta and any error encountered during the upload process. Upload(filePaths []string) ([]*CryptoKeyMeta, error) } -// CryptoKeyMetadataService defines methods for managing cryptographic key metadata and deleting keys. -type CryptoKeyMetadataService interface { +// ICryptoKeyMetadataService defines methods for managing cryptographic key metadata and deleting keys. +type ICryptoKeyMetadataService interface { // List retrieves all cryptographic keys metadata considering a query filter when set. // It returns a slice of CryptoKeyMeta and any error encountered during the retrieval process. List(query *CryptoKeyQuery) ([]*CryptoKeyMeta, error) @@ -32,15 +32,15 @@ type CryptoKeyMetadataService interface { DeleteByID(keyID string) error } -// CryptoKeyDownloadService defines methods for downloading cryptographic keys. -type CryptoKeyDownloadService interface { +// ICryptoKeyDownloadService defines methods for downloading cryptographic keys. +type ICryptoKeyDownloadService interface { // Download retrieves a cryptographic key by its ID and type. // It returns the CryptoKeyMeta, the key data as a byte slice, and any error encountered during the download process. Download(keyID string, keyType KeyType) (*CryptoKeyMeta, []byte, error) } // KeyOperations defines methods for cryptographic key management, encryption, signing, and PKCS#11 operations. -type CryptoKeyOperationService interface { +type ICryptoKeyOperationService interface { // --- Key Generation --- From d9af11896bf63bfdc1119ca22ea3f9f209eb4077 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 Nov 2024 09:04:02 +0000 Subject: [PATCH 02/14] modify Download(...) signature --- internal/domain/blobs/contract.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/domain/blobs/contract.go b/internal/domain/blobs/contract.go index 88912c1..3d3f962 100644 --- a/internal/domain/blobs/contract.go +++ b/internal/domain/blobs/contract.go @@ -1,5 +1,7 @@ package blobs +import "bytes" + // IBlobUploadService defines methods for uploading blobs. type IBlobUploadService interface { // Upload handles the upload of blobs from the specified file paths. @@ -25,6 +27,6 @@ type IBlobMetadataService interface { // IBlobDownloadService defines methods for downloading blobs. type IBlobDownloadService interface { // Download retrieves a blob by its ID and name. - // It returns the Blob, the file data as a byte slice, and any error encountered during the download process. - Download(blobID, blobName string) (*BlobMeta, []byte, error) + // It returns the file data as a byte slice, and any error encountered during the download process. + Download(blobID, blobName string) (*bytes.Buffer, error) } From 0de251c2c0e49d36ff5461f6788fa07c061f3b74 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 Nov 2024 09:04:14 +0000 Subject: [PATCH 03/14] Implement services with persistence and infrastructure layer dependencies for dependency injection --- internal/app/services/blob.go | 119 ++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/internal/app/services/blob.go b/internal/app/services/blob.go index 90a51e1..2db619e 100644 --- a/internal/app/services/blob.go +++ b/internal/app/services/blob.go @@ -1,8 +1,127 @@ package services +import ( + "bytes" + "crypto_vault_service/internal/domain/blobs" + "crypto_vault_service/internal/infrastructure/connector" + "crypto_vault_service/internal/persistence/repository" + "fmt" +) + +// BlobUploadService implements the BlobUploadService interface for handling blob uploads type BlobUploadService struct { + BlobConnector connector.BlobConnector + BlobRepository repository.BlobRepository +} + +// NewBlobUploadService creates a new instance of BlobUploadService +func NewBlobUploadService(blobConnector connector.BlobConnector, blobRepository repository.BlobRepository) *BlobUploadService { + return &BlobUploadService{ + BlobConnector: blobConnector, + BlobRepository: blobRepository, + } +} + +// Upload handles the upload of blobs and stores their metadata in the database. +func (s *BlobUploadService) Upload(filePaths []string) ([]*blobs.BlobMeta, error) { + // Use the BlobConnector to upload the files to Azure Blob Storage + uploadedBlobs, err := s.BlobConnector.Upload(filePaths) + if err != nil { + return nil, fmt.Errorf("failed to upload blobs: %w", err) + } + + // Store the metadata in the database using the BlobRepository + for _, blob := range uploadedBlobs { + err := s.BlobRepository.Create(blob) + 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 the metadata of uploaded blobs + return uploadedBlobs, nil } + +// BlobMetadataService implements the BlobMetadataService interface for retrieving and deleting blob metadata type BlobMetadataService struct { + BlobConnector connector.BlobConnector + BlobRepository repository.BlobRepository +} + +// NewBlobMetadataService creates a new instance of BlobMetadataService +func NewBlobMetadataService(blobRepository repository.BlobRepository, blobConnector connector.BlobConnector) *BlobMetadataService { + return &BlobMetadataService{ + BlobConnector: blobConnector, + BlobRepository: blobRepository, + } +} + +// 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 + + // TBD + + return blobsList, 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) + if err != nil { + return nil, fmt.Errorf("failed to retrieve blob metadata by ID '%s': %w", blobID, err) + } + return blob, 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) + if err != nil { + return fmt.Errorf("failed to retrieve blob metadata by ID '%s' for deletion: %w", blobID, err) + } + + // Delete the blob from Blob Storage using the BlobConnector + err = s.BlobRepository.DeleteById(blobID) + if err != nil { + return fmt.Errorf("failed to delete blob metadata by ID '%s': %w", blobID, err) + } + + // Now, delete the actual blob from the Blob Storage + err = s.BlobConnector.Delete(blob.ID, blob.Name) + if err != nil { + return fmt.Errorf("failed to delete blob '%s' from Blob Storage: %w", blob.Name, err) + } + + return nil +} + +// BlobDownloadService implements the BlobDownloadService interface for downloading blobs type BlobDownloadService struct { + BlobConnector connector.BlobConnector +} + +// NewBlobDownloadService creates a new instance of BlobDownloadService +func NewBlobDownloadService(blobConnector connector.BlobConnector) *BlobDownloadService { + return &BlobDownloadService{ + BlobConnector: blobConnector, + } +} + +// Download retrieves a blob's content by its ID and name +func (s *BlobDownloadService) Download(blobID, blobName string) (*bytes.Buffer, error) { + // Retrieve the blob metadata from the BlobRepository to ensure it exists + // Here you might want to consider validating the blob's existence. + blob, err := s.BlobConnector.Download(blobID, blobName) + if err != nil { + return nil, fmt.Errorf("failed to download blob '%s': %w", blobName, err) + } + + // Return the metadata and content of the downloaded blob + return blob, nil } From 952eefd07f792a66766de6a457d953458633886d Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 Nov 2024 12:14:14 +0000 Subject: [PATCH 04/14] rename varible and check in Upload(...) method --- internal/app/services/blob.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/internal/app/services/blob.go b/internal/app/services/blob.go index 2db619e..930a992 100644 --- a/internal/app/services/blob.go +++ b/internal/app/services/blob.go @@ -25,13 +25,18 @@ func NewBlobUploadService(blobConnector connector.BlobConnector, blobRepository // Upload handles the upload of blobs and stores their metadata in the database. func (s *BlobUploadService) Upload(filePaths []string) ([]*blobs.BlobMeta, error) { // Use the BlobConnector to upload the files to Azure Blob Storage - uploadedBlobs, err := s.BlobConnector.Upload(filePaths) + blobMeta, err := s.BlobConnector.Upload(filePaths) if err != nil { return nil, fmt.Errorf("failed to upload blobs: %w", err) } + // If no blobs are uploaded, return early + if len(blobMeta) == 0 { + return nil, fmt.Errorf("no blobs uploaded") + } + // Store the metadata in the database using the BlobRepository - for _, blob := range uploadedBlobs { + for _, blob := range blobMeta { err := s.BlobRepository.Create(blob) if err != nil { // Rollback any previously uploaded blobs if the metadata fails to store @@ -41,7 +46,7 @@ func (s *BlobUploadService) Upload(filePaths []string) ([]*blobs.BlobMeta, error } // Return the metadata of uploaded blobs - return uploadedBlobs, nil + return blobMeta, nil } // BlobMetadataService implements the BlobMetadataService interface for retrieving and deleting blob metadata From 2e20acfd2db8497ff040715d80e11256a38c364f Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 Nov 2024 12:15:17 +0000 Subject: [PATCH 05/14] rename variable --- internal/infrastructure/connector/blob.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/infrastructure/connector/blob.go b/internal/infrastructure/connector/blob.go index 3e58b39..99e8d58 100644 --- a/internal/infrastructure/connector/blob.go +++ b/internal/infrastructure/connector/blob.go @@ -51,7 +51,7 @@ func NewAzureBlobConnector(connectionString string, containerName string) (*Azur // Upload uploads multiple files to Azure Blob Storage and returns their metadata. func (abc *AzureBlobConnector) Upload(filePaths []string) ([]*blobs.BlobMeta, error) { - var uploadedBlobs []*blobs.BlobMeta + var blobMeta []*blobs.BlobMeta blobID := uuid.New().String() // Iterate through all file paths and upload each file @@ -60,7 +60,7 @@ func (abc *AzureBlobConnector) Upload(filePaths []string) ([]*blobs.BlobMeta, er file, err := os.Open(filePath) if err != nil { err = fmt.Errorf("failed to open file '%s': %w", filePath, err) - abc.rollbackUploadedBlobs(uploadedBlobs) // Rollback previously uploaded blobs + abc.rollbackUploadedBlobs(blobMeta) // Rollback previously uploaded blobs return nil, err } // Ensure file is closed after processing @@ -70,7 +70,7 @@ func (abc *AzureBlobConnector) Upload(filePaths []string) ([]*blobs.BlobMeta, er fileInfo, err := file.Stat() if err != nil { err = fmt.Errorf("failed to stat file '%s': %w", filePath, err) - abc.rollbackUploadedBlobs(uploadedBlobs) + abc.rollbackUploadedBlobs(blobMeta) return nil, err } @@ -79,7 +79,7 @@ func (abc *AzureBlobConnector) Upload(filePaths []string) ([]*blobs.BlobMeta, er _, err = buf.ReadFrom(file) if err != nil { err = fmt.Errorf("failed to read file '%s': %w", filePath, err) - abc.rollbackUploadedBlobs(uploadedBlobs) + abc.rollbackUploadedBlobs(blobMeta) return nil, err } @@ -103,18 +103,18 @@ func (abc *AzureBlobConnector) Upload(filePaths []string) ([]*blobs.BlobMeta, er _, err = abc.Client.UploadBuffer(context.Background(), abc.ContainerName, fullBlobName, buf.Bytes(), nil) if err != nil { err = fmt.Errorf("failed to upload blob '%s': %w", fullBlobName, err) - abc.rollbackUploadedBlobs(uploadedBlobs) + abc.rollbackUploadedBlobs(blobMeta) return nil, err } log.Printf("Blob '%s' uploaded successfully.\n", blob.Name) // Add the successfully uploaded blob to the list - uploadedBlobs = append(uploadedBlobs, blob) + blobMeta = append(blobMeta, blob) } // Return the list of blobs after successful upload. - return uploadedBlobs, nil + return blobMeta, nil } // rollbackUploadedBlobs deletes the blobs that were uploaded successfully before the error occurred From a9dbfae171c89a3cbe715071a17354cdb19c2e61 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 Nov 2024 12:34:36 +0000 Subject: [PATCH 06/14] add unit tests for blob service implementations --- go.mod | 1 + go.sum | 2 + .../app/services/blob_services_mock_test.go | 158 ++++++++++++++++++ test/unit/app/services/mocks.go | 57 +++++++ 4 files changed, 218 insertions(+) create mode 100644 test/unit/app/services/blob_services_mock_test.go create mode 100644 test/unit/app/services/mocks.go diff --git a/go.mod b/go.mod index d9e3ad3..705aedf 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,7 @@ require ( github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.12.0 // indirect diff --git a/go.sum b/go.sum index b2e4476..9fd06fa 100644 --- a/go.sum +++ b/go.sum @@ -96,6 +96,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= diff --git a/test/unit/app/services/blob_services_mock_test.go b/test/unit/app/services/blob_services_mock_test.go new file mode 100644 index 0000000..6589475 --- /dev/null +++ b/test/unit/app/services/blob_services_mock_test.go @@ -0,0 +1,158 @@ +package services + +import ( + "bytes" + "crypto_vault_service/internal/app/services" + "crypto_vault_service/internal/domain/blobs" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBlobUploadService_Upload(t *testing.T) { + // Prepare mock dependencies + mockBlobConnector := new(MockBlobConnector) + mockBlobRepository := new(MockBlobRepository) + + // Initialize the service with mock dependencies + service := services.NewBlobUploadService(mockBlobConnector, mockBlobRepository) + + // Test case 1: Successful upload and metadata storage + t.Run("successfully uploads blobs and stores metadata", func(t *testing.T) { + // Define the test file paths + filePaths := []string{"file1.txt", "file2.txt"} + + // Define mock return values + mockBlobMeta := []*blobs.BlobMeta{ + {Name: "file1.txt", ID: "1"}, + {Name: "file2.txt", ID: "2"}, + } + + // Setup expectations for the mock BlobConnector + mockBlobConnector.On("Upload", filePaths).Return(mockBlobMeta, nil) + + // Setup expectations for the mock BlobRepository + mockBlobRepository.On("Create", mockBlobMeta[0]).Return(nil) + mockBlobRepository.On("Create", mockBlobMeta[1]).Return(nil) + + // Call the method under test + uploadedBlobs, err := service.Upload(filePaths) + + // Assert the results + assert.NoError(t, err) + assert.Equal(t, mockBlobMeta, uploadedBlobs) + + // Assert that the expectations were met + mockBlobConnector.AssertExpectations(t) + mockBlobRepository.AssertExpectations(t) + }) + + // Test case 2: Failed upload (BlobConnector returns error) + t.Run("fails when BlobConnector returns error", func(t *testing.T) { + // Define the test file paths + filePaths := []string{"file1.txt"} + + // Setup expectations for the mock BlobConnector + mockBlobConnector.On("Upload", filePaths).Return([]*blobs.BlobMeta(nil), fmt.Errorf("upload failed")) + + // Call the method under test + uploadedBlobs, err := service.Upload(filePaths) + + // Assert the results + assert.Error(t, err) + assert.Nil(t, uploadedBlobs) + + // Assert that the expectations were met + mockBlobConnector.AssertExpectations(t) + mockBlobRepository.AssertExpectations(t) + }) + + // Test case 3: Failed metadata storage (BlobRepository returns error) + t.Run("fails when BlobRepository returns error", func(t *testing.T) { + // Define the test file paths + filePaths := []string{"file1.txt"} + + // Define mock return values + mockBlobMeta := []*blobs.BlobMeta{ + {Name: "file1.txt", ID: "1"}, + } + + // Setup expectations for the mock BlobConnector + mockBlobConnector.On("Upload", filePaths).Return(mockBlobMeta, nil) + + // Setup expectations for the mock BlobRepository + mockBlobRepository.On("Create", mockBlobMeta[0]).Return(fmt.Errorf("failed to store metadata")) + + // Call the method under test + uploadedBlobs, err := service.Upload(filePaths) + + // Assert the results + assert.Error(t, err) + assert.Nil(t, uploadedBlobs) + + // Assert that the expectations were met + mockBlobConnector.AssertExpectations(t) + mockBlobRepository.AssertExpectations(t) + }) +} + +func TestBlobMetadataService(t *testing.T) { + // Prepare mock dependencies + mockBlobConnector := new(MockBlobConnector) + mockBlobRepository := new(MockBlobRepository) + + // Initialize the service with mock dependencies + metadataService := services.NewBlobMetadataService(mockBlobRepository, mockBlobConnector) + + // Test case 1: Successfully retrieve blob metadata by ID + t.Run("successfully retrieves blob metadata by ID", func(t *testing.T) { + blobID := "1" + mockBlobMeta := &blobs.BlobMeta{ + ID: "1", + Name: "file1.txt", + } + + // Setup expectations for the mock BlobRepository + mockBlobRepository.On("GetById", blobID).Return(mockBlobMeta, nil) + + // Call the method under test + blob, err := metadataService.GetByID(blobID) + + // Assert the results + assert.NoError(t, err) + assert.Equal(t, mockBlobMeta, blob) + + // Assert that the expectations were met + mockBlobRepository.AssertExpectations(t) + }) +} + +func TestBlobDownloadService(t *testing.T) { + // Prepare mock dependencies + mockBlobConnector := new(MockBlobConnector) + + // Initialize the service with mock dependencies + downloadService := services.NewBlobDownloadService(mockBlobConnector) + + // Test case 1: Successfully download a blob + t.Run("successfully downloads a blob", func(t *testing.T) { + blobID := "1" + blobName := "file1.txt" + mockContent := &bytes.Buffer{} + mockContent.WriteString("file content") + + // Setup expectations for the mock BlobConnector to return the content + mockBlobConnector.On("Download", blobID, blobName).Return(mockContent, nil) + + // Call the method under test + downloadedBlob, err := downloadService.Download(blobID, blobName) + + // Assert the results + assert.NoError(t, err) + assert.Equal(t, mockContent, downloadedBlob) + + // Assert that the expectations were met + mockBlobConnector.AssertExpectations(t) + }) +} diff --git a/test/unit/app/services/mocks.go b/test/unit/app/services/mocks.go new file mode 100644 index 0000000..6029f4d --- /dev/null +++ b/test/unit/app/services/mocks.go @@ -0,0 +1,57 @@ +package services + +import ( + "bytes" + "crypto_vault_service/internal/domain/blobs" + + "github.com/stretchr/testify/mock" +) + +// MockBlobConnector is a mock for the BlobConnector interface +type MockBlobConnector struct { + mock.Mock +} + +func (m *MockBlobConnector) Upload(filePaths []string) ([]*blobs.BlobMeta, error) { + args := m.Called(filePaths) + return args.Get(0).([]*blobs.BlobMeta), args.Error(1) +} + +func (m *MockBlobConnector) Delete(blobID, blobName string) error { + args := m.Called(blobID, blobName) + return args.Error(0) +} + +func (m *MockBlobConnector) Download(blobID, blobName string) (*bytes.Buffer, error) { + args := m.Called(blobID, blobName) + return args.Get(0).(*bytes.Buffer), args.Error(1) +} + +// MockBlobRepository is a mock for the BlobRepository interface +type MockBlobRepository struct { + mock.Mock +} + +// Create mocks the Create method of the BlobRepository interface +func (m *MockBlobRepository) Create(blob *blobs.BlobMeta) error { + args := m.Called(blob) + return args.Error(0) +} + +// GetById mocks the GetById method of the BlobRepository interface +func (m *MockBlobRepository) GetById(blobID string) (*blobs.BlobMeta, error) { + args := m.Called(blobID) + return args.Get(0).(*blobs.BlobMeta), args.Error(1) +} + +// UpdateById mocks the UpdateById method of the BlobRepository interface +func (m *MockBlobRepository) UpdateById(blob *blobs.BlobMeta) error { + args := m.Called(blob) + return args.Error(0) +} + +// DeleteById mocks the DeleteById method of the BlobRepository interface +func (m *MockBlobRepository) DeleteById(blobID string) error { + args := m.Called(blobID) + return args.Error(0) +} From 22111e41c949500484465a2be2a16e5bb6cc4605 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 Nov 2024 13:08:53 +0000 Subject: [PATCH 07/14] utilize env vars to setup test databases with either sqlite or psql drivers --- ..._in_memory_test.go => blob_sqlite_test.go} | 42 +++++++++++++------ ...y_in_memory_test.go => key_sqlite_test.go} | 36 +++++++++++----- .../persistence/repository/test_context.go | 36 ++++++++++++++-- 3 files changed, 87 insertions(+), 27 deletions(-) rename test/integration/persistence/repository/{blob_in_memory_test.go => blob_sqlite_test.go} (80%) rename test/integration/persistence/repository/{key_in_memory_test.go => key_sqlite_test.go} (79%) diff --git a/test/integration/persistence/repository/blob_in_memory_test.go b/test/integration/persistence/repository/blob_sqlite_test.go similarity index 80% rename from test/integration/persistence/repository/blob_in_memory_test.go rename to test/integration/persistence/repository/blob_sqlite_test.go index a1cacba..328bc00 100644 --- a/test/integration/persistence/repository/blob_in_memory_test.go +++ b/test/integration/persistence/repository/blob_sqlite_test.go @@ -3,6 +3,8 @@ package repository import ( "crypto_vault_service/internal/domain/blobs" "crypto_vault_service/internal/domain/keys" + "fmt" + "os" "testing" "time" @@ -11,8 +13,12 @@ import ( "gorm.io/gorm" ) -// TestBlobRepository_Create tests the Create method of GormBlobRepository -func TestBlobRepository_Create(t *testing.T) { +// TestBlobInSqliteRepository_Create tests the Create method of GormBlobRepository +func TestBlobInSqliteRepository_Create(t *testing.T) { + err := os.Setenv("DB_TYPE", "sqlite") + if err != nil { + fmt.Println("Error setting environment variable:", err) + } // Set up test context ctx := setupTestDB(t) defer teardownTestDB(t, ctx) @@ -41,7 +47,7 @@ func TestBlobRepository_Create(t *testing.T) { } // Call the Create method - err := ctx.BlobRepo.Create(blob) + err = ctx.BlobRepo.Create(blob) assert.NoError(t, err, "Create should not return an error") // Verify the blob is created and exists in DB @@ -52,8 +58,12 @@ func TestBlobRepository_Create(t *testing.T) { assert.Equal(t, blob.Name, createdBlob.Name, "Name should match") } -// TestBlobRepository_GetById tests the GetById method of GormBlobRepository -func TestBlobRepository_GetById(t *testing.T) { +// TestBlobInSqliteRepository_GetById tests the GetById method of GormBlobRepository +func TestBlobInSqliteRepository_GetById(t *testing.T) { + err := os.Setenv("DB_TYPE", "sqlite") + if err != nil { + fmt.Println("Error setting environment variable:", err) + } // Set up test context ctx := setupTestDB(t) defer teardownTestDB(t, ctx) @@ -82,7 +92,7 @@ func TestBlobRepository_GetById(t *testing.T) { } // Create the blob in DB - err := ctx.BlobRepo.Create(blob) + err = ctx.BlobRepo.Create(blob) assert.NoError(t, err, "Create should not return an error") // Get the blob by ID @@ -92,8 +102,12 @@ func TestBlobRepository_GetById(t *testing.T) { assert.Equal(t, blob.ID, fetchedBlob.ID, "ID should match") } -// TestBlobRepository_UpdateById tests the UpdateById method of GormBlobRepository -func TestBlobRepository_UpdateById(t *testing.T) { +// TestBlobInSqliteRepository_UpdateById tests the UpdateById method of GormBlobRepository +func TestBlobInSqliteRepository_UpdateById(t *testing.T) { + err := os.Setenv("DB_TYPE", "sqlite") + if err != nil { + fmt.Println("Error setting environment variable:", err) + } // Set up test context ctx := setupTestDB(t) defer teardownTestDB(t, ctx) @@ -122,7 +136,7 @@ func TestBlobRepository_UpdateById(t *testing.T) { } // Create the blob in DB - err := ctx.BlobRepo.Create(blob) + err = ctx.BlobRepo.Create(blob) assert.NoError(t, err) // Update the blob's name @@ -137,8 +151,12 @@ func TestBlobRepository_UpdateById(t *testing.T) { assert.Equal(t, "updated-blob-name", updatedBlob.Name, "Name should be updated") } -// TestBlobRepository_DeleteById tests the DeleteById method of GormBlobRepository -func TestBlobRepository_DeleteById(t *testing.T) { +// TestBlobInSqliteRepository_DeleteById tests the DeleteById method of GormBlobRepository +func TestBlobInSqliteRepository_DeleteById(t *testing.T) { + err := os.Setenv("DB_TYPE", "sqlite") + if err != nil { + fmt.Println("Error setting environment variable:", err) + } // Set up test context ctx := setupTestDB(t) defer teardownTestDB(t, ctx) @@ -167,7 +185,7 @@ func TestBlobRepository_DeleteById(t *testing.T) { } // Create the blob in DB - err := ctx.BlobRepo.Create(blob) + err = ctx.BlobRepo.Create(blob) assert.NoError(t, err) // Delete the blob diff --git a/test/integration/persistence/repository/key_in_memory_test.go b/test/integration/persistence/repository/key_sqlite_test.go similarity index 79% rename from test/integration/persistence/repository/key_in_memory_test.go rename to test/integration/persistence/repository/key_sqlite_test.go index bc0209c..3ded172 100644 --- a/test/integration/persistence/repository/key_in_memory_test.go +++ b/test/integration/persistence/repository/key_sqlite_test.go @@ -2,6 +2,8 @@ package repository import ( "crypto_vault_service/internal/domain/keys" + "fmt" + "os" "testing" "time" @@ -10,8 +12,12 @@ import ( "gorm.io/gorm" ) -// TestCryptoKeyRepository_Create tests the Create method of GormCryptoKeyRepository -func TestCryptoKeyRepository_Create(t *testing.T) { +// TestCryptoKeySqliteRepository_Create tests the Create method of GormCryptoKeyRepository +func TestCryptoKeySqliteRepository_Create(t *testing.T) { + err := os.Setenv("DB_TYPE", "sqlite") + if err != nil { + fmt.Println("Error setting environment variable:", err) + } // Set up test context ctx := setupTestDB(t) defer teardownTestDB(t, ctx) @@ -26,7 +32,7 @@ func TestCryptoKeyRepository_Create(t *testing.T) { } // Create the cryptographic key in DB - err := ctx.CryptoKeyRepo.Create(cryptographicKey) + err = ctx.CryptoKeyRepo.Create(cryptographicKey) assert.NoError(t, err, "Create should not return an error") // Verify the cryptographic key is created and exists in DB @@ -37,8 +43,12 @@ func TestCryptoKeyRepository_Create(t *testing.T) { assert.Equal(t, cryptographicKey.Type, createdKey.Type, "Type should match") } -// TestCryptoKeyRepository_GetByID tests the GetByID method of GormCryptoKeyRepository -func TestCryptoKeyRepository_GetByID(t *testing.T) { +// TestCryptoKeySqliteRepository_GetByID tests the GetByID method of GormCryptoKeyRepository +func TestCryptoKeySqliteRepository_GetByID(t *testing.T) { + err := os.Setenv("DB_TYPE", "sqlite") + if err != nil { + fmt.Println("Error setting environment variable:", err) + } // Set up test context ctx := setupTestDB(t) defer teardownTestDB(t, ctx) @@ -53,7 +63,7 @@ func TestCryptoKeyRepository_GetByID(t *testing.T) { } // Create the cryptographic key in DB - err := ctx.CryptoKeyRepo.Create(cryptographicKey) + err = ctx.CryptoKeyRepo.Create(cryptographicKey) assert.NoError(t, err, "Create should not return an error") // Get the cryptographic key by ID @@ -63,8 +73,12 @@ func TestCryptoKeyRepository_GetByID(t *testing.T) { assert.Equal(t, cryptographicKey.ID, fetchedKey.ID, "ID should match") } -// TestCryptoKeyRepository_UpdateByID tests the UpdateByID method of GormCryptoKeyRepository -func TestCryptoKeyRepository_UpdateByID(t *testing.T) { +// TestCryptoKeySqliteRepository_UpdateByID tests the UpdateByID method of GormCryptoKeyRepository +func TestCryptoKeySqliteRepository_UpdateByID(t *testing.T) { + err := os.Setenv("DB_TYPE", "sqlite") + if err != nil { + fmt.Println("Error setting environment variable:", err) + } // Set up test context ctx := setupTestDB(t) defer teardownTestDB(t, ctx) @@ -79,7 +93,7 @@ func TestCryptoKeyRepository_UpdateByID(t *testing.T) { } // Create the cryptographic key in DB - err := ctx.CryptoKeyRepo.Create(cryptographicKey) + err = ctx.CryptoKeyRepo.Create(cryptographicKey) assert.NoError(t, err, "Create should not return an error") // Update the cryptographic key's type @@ -94,8 +108,8 @@ func TestCryptoKeyRepository_UpdateByID(t *testing.T) { assert.Equal(t, "ECDSA", updatedKey.Type, "Type should be updated") } -// TestCryptoKeyRepository_DeleteByID tests the DeleteByID method of GormCryptoKeyRepository -func TestCryptoKeyRepository_DeleteByID(t *testing.T) { +// TestCryptoKeySqliteRepository_DeleteByID tests the DeleteByID method of GormCryptoKeyRepository +func TestCryptoKeySqliteRepository_DeleteByID(t *testing.T) { // Set up test context ctx := setupTestDB(t) defer teardownTestDB(t, ctx) diff --git a/test/integration/persistence/repository/test_context.go b/test/integration/persistence/repository/test_context.go index e984ac5..235269f 100644 --- a/test/integration/persistence/repository/test_context.go +++ b/test/integration/persistence/repository/test_context.go @@ -5,8 +5,10 @@ import ( "crypto_vault_service/internal/domain/keys" "crypto_vault_service/internal/persistence/repository" "fmt" + "os" "testing" + "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" ) @@ -21,10 +23,36 @@ type TestContext struct { // Setup function to initialize the test DB and repositories func setupTestDB(t *testing.T) *TestContext { var err error - // Set up an in-memory SQLite database for testing - db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) - if err != nil { - t.Fatalf("Failed to setup DB: %v", err) + var db *gorm.DB + + // Check for the DB type to use (SQLite in-memory or PostgreSQL) + dbType := os.Getenv("DB_TYPE") + if dbType == "" { + // Default to SQLite in-memory if DB_TYPE is not set + dbType = "sqlite" + } + + switch dbType { + case "postgres": + // Setup PostgreSQL connection + dsn := os.Getenv("POSTGRES_DSN") // Example: "user=username dbname=test sslmode=disable" + if dsn == "" { + t.Fatalf("POSTGRES_DSN environment variable is not set") + } + db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) + if err != nil { + t.Fatalf("Failed to connect to PostgreSQL: %v", err) + } + + case "sqlite": + // Setup SQLite in-memory connection + db, err = gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) + if err != nil { + t.Fatalf("Failed to connect to SQLite: %v", err) + } + + default: + t.Fatalf("Unsupported DB_TYPE value: %s", dbType) } // Migrate the schema for Blob and CryptoKey From 10c85fc3a2e619b4515c7becac07fd809f60ddda Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 Nov 2024 13:31:55 +0000 Subject: [PATCH 08/14] ensure blobs databases is created --- .../persistence/repository/test_context.go | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/test/integration/persistence/repository/test_context.go b/test/integration/persistence/repository/test_context.go index 235269f..52a6cfe 100644 --- a/test/integration/persistence/repository/test_context.go +++ b/test/integration/persistence/repository/test_context.go @@ -35,15 +35,44 @@ func setupTestDB(t *testing.T) *TestContext { switch dbType { case "postgres": // Setup PostgreSQL connection - dsn := os.Getenv("POSTGRES_DSN") // Example: "user=username dbname=test sslmode=disable" + dsn := "user=postgres password=postgres host=localhost port=5432 sslmode=disable" if dsn == "" { t.Fatalf("POSTGRES_DSN environment variable is not set") } + db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) if err != nil { t.Fatalf("Failed to connect to PostgreSQL: %v", err) } + // Check if the `blobs` database exists + sqlDB, err := db.DB() + if err != nil { + t.Fatalf("Failed to get raw DB connection: %v", err) + } + + // Query to check if the `blobs` database exists + var dbExists bool + err = sqlDB.QueryRow("SELECT 1 FROM pg_database WHERE datname = 'blobs'").Scan(&dbExists) + if err != nil { + if err.Error() != "sql: no rows in result set" { + t.Fatalf("Failed to check if database exists: %v", err) + } + // The database does not exist, create it + _, err = sqlDB.Exec("CREATE DATABASE blobs") + if err != nil { + t.Fatalf("Failed to create database: %v", err) + } + fmt.Println("Database 'blobs' created successfully.") + } + + // Now, open a connection to the `blobs` database + dsn = "user=postgres password=postgres host=localhost port=5432 dbname=blobs sslmode=disable" + db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) + if err != nil { + t.Fatalf("Failed to connect to PostgreSQL database 'blobs': %v", err) + } + case "sqlite": // Setup SQLite in-memory connection db, err = gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) From 48988131b8e25dc166050e9749b528e258799666 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 Nov 2024 13:33:47 +0000 Subject: [PATCH 09/14] add test with psql gorm driver --- .../persistence/repository/blob_psql_test.go | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 test/integration/persistence/repository/blob_psql_test.go diff --git a/test/integration/persistence/repository/blob_psql_test.go b/test/integration/persistence/repository/blob_psql_test.go new file mode 100644 index 0000000..2b627a6 --- /dev/null +++ b/test/integration/persistence/repository/blob_psql_test.go @@ -0,0 +1,196 @@ +package repository + +import ( + "crypto_vault_service/internal/domain/blobs" + "crypto_vault_service/internal/domain/keys" + "fmt" + "os" + "testing" + "time" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "gorm.io/gorm" +) + +// TestBlobPsqlRepository_Create tests the Create method of GormBlobRepository +func TestBlobPsqlRepository_Create(t *testing.T) { + err := os.Setenv("DB_TYPE", "postgres") + if err != nil { + fmt.Println("Error setting environment variable:", err) + } + // Set up test context + ctx := setupTestDB(t) + defer teardownTestDB(t, ctx) + + // Create a valid CryptoKey object + cryptographicKey := keys.CryptoKeyMeta{ + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID + } + + // Create a test Blob object with valid UUIDs and required fields + blob := &blobs.BlobMeta{ + ID: uuid.New().String(), // Generate valid UUID + UploadTime: time.Now(), + UserID: uuid.New().String(), // Generate valid UUID for UserID + Name: "test-blob", + Size: 1024, + Type: "text", + IsEncrypted: false, + IsSigned: true, + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set + } + + // Call the Create method + err = ctx.BlobRepo.Create(blob) + assert.NoError(t, err, "Create should not return an error") + + // Verify the blob is created and exists in DB + var createdBlob blobs.BlobMeta + err = ctx.DB.First(&createdBlob, "id = ?", blob.ID).Error + assert.NoError(t, err, "Failed to find created blob") + assert.Equal(t, blob.ID, createdBlob.ID, "ID should match") + assert.Equal(t, blob.Name, createdBlob.Name, "Name should match") +} + +// TestBlobPsqlRepository_GetById tests the GetById method of GormBlobRepository +func TestBlobPsqlRepository_GetById(t *testing.T) { + err := os.Setenv("DB_TYPE", "postgres") + if err != nil { + fmt.Println("Error setting environment variable:", err) + } + // Set up test context + ctx := setupTestDB(t) + defer teardownTestDB(t, ctx) + + // Create a valid CryptoKey object + cryptographicKey := keys.CryptoKeyMeta{ + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID + } + + // Create a test Blob object with valid UUIDs and required fields + blob := &blobs.BlobMeta{ + ID: uuid.New().String(), // Generate valid UUID + UploadTime: time.Now(), + UserID: cryptographicKey.UserID, // Link to valid UserID from CryptoKey + Name: "test-blob", + Size: 1024, + Type: "text", + IsEncrypted: false, + IsSigned: true, + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set + } + + // Create the blob in DB + err = ctx.BlobRepo.Create(blob) + assert.NoError(t, err, "Create should not return an error") + + // Get the blob by ID + fetchedBlob, err := ctx.BlobRepo.GetById(blob.ID) + assert.NoError(t, err, "GetById should not return an error") + assert.NotNil(t, fetchedBlob, "Fetched blob should not be nil") + assert.Equal(t, blob.ID, fetchedBlob.ID, "ID should match") +} + +// TestBlobPsqlRepository_UpdateById tests the UpdateById method of GormBlobRepository +func TestBlobPsqlRepository_UpdateById(t *testing.T) { + err := os.Setenv("DB_TYPE", "postgres") + if err != nil { + fmt.Println("Error setting environment variable:", err) + } + // Set up test context + ctx := setupTestDB(t) + defer teardownTestDB(t, ctx) + + // Create a valid CryptoKey object + cryptographicKey := keys.CryptoKeyMeta{ + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID + } + + // Create a test Blob object with valid UUIDs and required fields + blob := &blobs.BlobMeta{ + ID: uuid.New().String(), // Generate valid UUID + UploadTime: time.Now(), + UserID: uuid.New().String(), // Generate valid UUID for UserID + Name: "test-blob", + Size: 1024, + Type: "text", + IsEncrypted: false, + IsSigned: true, + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set + } + + // Create the blob in DB + err = ctx.BlobRepo.Create(blob) + assert.NoError(t, err) + + // Update the blob's name + blob.Name = "updated-blob-name" + err = ctx.BlobRepo.UpdateById(blob) + assert.NoError(t, err) + + // Verify the blob is updated + var updatedBlob blobs.BlobMeta + err = ctx.DB.First(&updatedBlob, "id = ?", blob.ID).Error + assert.NoError(t, err) + assert.Equal(t, "updated-blob-name", updatedBlob.Name, "Name should be updated") +} + +// TestBlobPsqlRepository_DeleteById tests the DeleteById method of GormBlobRepository +func TestBlobPsqlRepository_DeleteById(t *testing.T) { + // Set up test context + ctx := setupTestDB(t) + defer teardownTestDB(t, ctx) + + // Create a valid CryptoKey object + cryptographicKey := keys.CryptoKeyMeta{ + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID + } + + // Create a test Blob object with valid UUIDs and required fields + blob := &blobs.BlobMeta{ + ID: uuid.New().String(), // Generate valid UUID + UploadTime: time.Now(), + UserID: uuid.New().String(), // Generate valid UUID for UserID + Name: "test-blob", + Size: 1024, + Type: "text", + IsEncrypted: false, + IsSigned: true, + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set + } + + // Create the blob in DB + err := ctx.BlobRepo.Create(blob) + assert.NoError(t, err) + + // Delete the blob + err = ctx.BlobRepo.DeleteById(blob.ID) + assert.NoError(t, err) + + // Verify the blob is deleted + var deletedBlob blobs.BlobMeta + err = ctx.DB.First(&deletedBlob, "id = ?", blob.ID).Error + assert.Error(t, err, "Blob should be deleted") + assert.Equal(t, gorm.ErrRecordNotFound, err, "Error should be 'record not found'") +} From 946aa08145a0ed22b3fb1e2a4397945ce845199c Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 Nov 2024 14:08:40 +0000 Subject: [PATCH 10/14] add domain dedicated to crypto key operations --- internal/app/services/crypto.go | 5 +++ internal/app/services/key.go | 2 - internal/domain/crypto/contracts.go | 69 +++++++++++++++++++++++++++++ internal/domain/keys/contract.go | 68 ---------------------------- 4 files changed, 74 insertions(+), 70 deletions(-) create mode 100644 internal/app/services/crypto.go create mode 100644 internal/domain/crypto/contracts.go diff --git a/internal/app/services/crypto.go b/internal/app/services/crypto.go new file mode 100644 index 0000000..bb5f4ff --- /dev/null +++ b/internal/app/services/crypto.go @@ -0,0 +1,5 @@ +package services + +// CryptoKeyOperationService implements the ICryptoKeyOperationService interface for local cryptographic key management, encryption, signing, and PKCS#11 operations. +type CryptoKeyOperationService struct { +} diff --git a/internal/app/services/key.go b/internal/app/services/key.go index edaca67..09db71e 100644 --- a/internal/app/services/key.go +++ b/internal/app/services/key.go @@ -6,5 +6,3 @@ type CryptoKeyMetadataService struct { } type CryptoKeyDownloadService struct { } -type CryptoKeyOperationService struct { -} diff --git a/internal/domain/crypto/contracts.go b/internal/domain/crypto/contracts.go new file mode 100644 index 0000000..f0d9fff --- /dev/null +++ b/internal/domain/crypto/contracts.go @@ -0,0 +1,69 @@ +package crypto + +// ICryptoKeyOperationService defines methods for local cryptographic key management, encryption, signing, and PKCS#11 operations. +type ICryptoKeyOperationService interface { + + // --- Key Generation --- + + // GenerateKey generates a cryptographic key of the specified type and size (e.g., AES, RSA, ECDSA). + // It returns the generated key as a byte slice and any error encountered during the key generation. + GenerateKey(keyType string, keySize int) ([]byte, error) + + // --- Key Storage and Retrieval --- + + // SaveKey saves a cryptographic key to a specified file. + // It returns any error encountered during the saving process. + SaveKey(key []byte, filename string) error + + // LoadKey loads a cryptographic key from a specified file. + // It returns the loaded key as a byte slice and any error encountered during the loading process. + LoadKey(filename string) ([]byte, error) + + // --- Encryption and Decryption (Symmetric algorithms like AES) --- + + // EncryptWithSymmetricKey encrypts data using a symmetric key (e.g., AES). + // It returns the encrypted data as a byte slice and any error encountered during encryption. + EncryptWithSymmetricKey(plainText []byte, key []byte) ([]byte, error) + + // DecryptWithSymmetricKey decrypts data using a symmetric key (e.g., AES). + // It returns the decrypted data as a byte slice and any error encountered during decryption. + DecryptWithSymmetricKey(cipherText []byte, key []byte) ([]byte, error) + + // --- Asymmetric Encryption (RSA, ECDSA, PKCS#11) --- + + // EncryptWithPublicKey encrypts data with a public key using asymmetric encryption algorithms (e.g., RSA, ECDSA). + // It optionally supports PKCS#11 hardware tokens for key storage. + // It returns the encrypted data as a byte slice and any error encountered during encryption. + EncryptWithPublicKey(plainText []byte, publicKey interface{}) ([]byte, error) + + // DecryptWithPrivateKey decrypts data with a private key using asymmetric encryption algorithms (e.g., RSA, ECDSA). + // It optionally supports PKCS#11 hardware tokens for key storage. + // It returns the decrypted data as a byte slice and any error encountered during decryption. + DecryptWithPrivateKey(cipherText []byte, privateKey interface{}) ([]byte, error) + + // --- Signing and Verification (For RSA, ECDSA) --- + + // SignWithPrivateKey signs a message using a private key with asymmetric algorithms (e.g., RSA, ECDSA). + // It optionally supports PKCS#11 hardware tokens for key storage. + // It returns the signature and any error encountered during the signing process. + SignWithPrivateKey(message []byte, privateKey interface{}) ([]byte, error) + + // VerifyWithPublicKey verifies a signature using a public key with asymmetric algorithms (e.g., RSA, ECDSA). + // It optionally supports PKCS#11 hardware tokens for key storage. + // It returns true if the signature is valid, false otherwise, and any error encountered during the verification process. + VerifyWithPublicKey(message []byte, signature []byte, publicKey interface{}) (bool, error) + + // --- PKCS#11 Operations --- + + // InitializeToken initializes a PKCS#11 token in the specified hardware slot. + // It returns any error encountered during the initialization. + InitializeToken(slot string) error + + // AddKeyToToken adds a cryptographic key to a PKCS#11 token. + // It returns any error encountered during the addition of the key. + AddKeyToToken() error + + // DeleteKeyFromToken deletes a cryptographic key from a PKCS#11 token by its type and label. + // It returns any error encountered during the deletion of the key. + DeleteKeyFromToken(objectType, objectLabel string) error +} diff --git a/internal/domain/keys/contract.go b/internal/domain/keys/contract.go index b794013..5f83e61 100644 --- a/internal/domain/keys/contract.go +++ b/internal/domain/keys/contract.go @@ -38,71 +38,3 @@ type ICryptoKeyDownloadService interface { // It returns the CryptoKeyMeta, the key data as a byte slice, and any error encountered during the download process. Download(keyID string, keyType KeyType) (*CryptoKeyMeta, []byte, error) } - -// KeyOperations defines methods for cryptographic key management, encryption, signing, and PKCS#11 operations. -type ICryptoKeyOperationService interface { - - // --- Key Generation --- - - // GenerateKey generates a cryptographic key of the specified type and size (e.g., AES, RSA, ECDSA). - // It returns the generated key as a byte slice and any error encountered during the key generation. - GenerateKey(keyType string, keySize int) ([]byte, error) - - // --- Key Storage and Retrieval --- - - // SaveKey saves a cryptographic key to a specified file. - // It returns any error encountered during the saving process. - SaveKey(key []byte, filename string) error - - // LoadKey loads a cryptographic key from a specified file. - // It returns the loaded key as a byte slice and any error encountered during the loading process. - LoadKey(filename string) ([]byte, error) - - // --- Encryption and Decryption (Symmetric algorithms like AES) --- - - // EncryptWithSymmetricKey encrypts data using a symmetric key (e.g., AES). - // It returns the encrypted data as a byte slice and any error encountered during encryption. - EncryptWithSymmetricKey(plainText []byte, key []byte) ([]byte, error) - - // DecryptWithSymmetricKey decrypts data using a symmetric key (e.g., AES). - // It returns the decrypted data as a byte slice and any error encountered during decryption. - DecryptWithSymmetricKey(cipherText []byte, key []byte) ([]byte, error) - - // --- Asymmetric Encryption (RSA, ECDSA, PKCS#11) --- - - // EncryptWithPublicKey encrypts data with a public key using asymmetric encryption algorithms (e.g., RSA, ECDSA). - // It optionally supports PKCS#11 hardware tokens for key storage. - // It returns the encrypted data as a byte slice and any error encountered during encryption. - EncryptWithPublicKey(plainText []byte, publicKey interface{}) ([]byte, error) - - // DecryptWithPrivateKey decrypts data with a private key using asymmetric encryption algorithms (e.g., RSA, ECDSA). - // It optionally supports PKCS#11 hardware tokens for key storage. - // It returns the decrypted data as a byte slice and any error encountered during decryption. - DecryptWithPrivateKey(cipherText []byte, privateKey interface{}) ([]byte, error) - - // --- Signing and Verification (For RSA, ECDSA) --- - - // SignWithPrivateKey signs a message using a private key with asymmetric algorithms (e.g., RSA, ECDSA). - // It optionally supports PKCS#11 hardware tokens for key storage. - // It returns the signature and any error encountered during the signing process. - SignWithPrivateKey(message []byte, privateKey interface{}) ([]byte, error) - - // VerifyWithPublicKey verifies a signature using a public key with asymmetric algorithms (e.g., RSA, ECDSA). - // It optionally supports PKCS#11 hardware tokens for key storage. - // It returns true if the signature is valid, false otherwise, and any error encountered during the verification process. - VerifyWithPublicKey(message []byte, signature []byte, publicKey interface{}) (bool, error) - - // --- PKCS#11 Operations --- - - // InitializeToken initializes a PKCS#11 token in the specified hardware slot. - // It returns any error encountered during the initialization. - InitializeToken(slot string) error - - // AddKeyToToken adds a cryptographic key to a PKCS#11 token. - // It returns any error encountered during the addition of the key. - AddKeyToToken() error - - // DeleteKeyFromToken deletes a cryptographic key from a PKCS#11 token by its type and label. - // It returns any error encountered during the deletion of the key. - DeleteKeyFromToken(objectType, objectLabel string) error -} From b9bf6ddc7d16881283a722abc180c6f168822898 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 Nov 2024 14:38:45 +0000 Subject: [PATCH 11/14] utilize byte slice ([]byte) instead of *bytes.Buffer --- internal/app/services/blob.go | 4 ++-- internal/domain/blobs/contract.go | 4 +--- internal/domain/keys/contract.go | 2 +- internal/infrastructure/connector/blob.go | 6 +++--- internal/infrastructure/connector/key.go | 3 +-- .../infrastructure/connector/az_blob_test.go | 5 ++++- test/unit/app/services/blob_services_mock_test.go | 8 +++----- test/unit/app/services/mocks.go | 10 +++++++--- 8 files changed, 22 insertions(+), 20 deletions(-) diff --git a/internal/app/services/blob.go b/internal/app/services/blob.go index 930a992..7993125 100644 --- a/internal/app/services/blob.go +++ b/internal/app/services/blob.go @@ -1,7 +1,6 @@ package services import ( - "bytes" "crypto_vault_service/internal/domain/blobs" "crypto_vault_service/internal/infrastructure/connector" "crypto_vault_service/internal/persistence/repository" @@ -24,6 +23,7 @@ func NewBlobUploadService(blobConnector connector.BlobConnector, blobRepository // Upload handles the upload of blobs and stores their metadata in the database. func (s *BlobUploadService) Upload(filePaths []string) ([]*blobs.BlobMeta, error) { + // Use the BlobConnector to upload the files to Azure Blob Storage blobMeta, err := s.BlobConnector.Upload(filePaths) if err != nil { @@ -119,7 +119,7 @@ func NewBlobDownloadService(blobConnector connector.BlobConnector) *BlobDownload } // Download retrieves a blob's content by its ID and name -func (s *BlobDownloadService) Download(blobID, blobName string) (*bytes.Buffer, error) { +func (s *BlobDownloadService) Download(blobID, blobName string) ([]byte, error) { // Retrieve the blob metadata from the BlobRepository to ensure it exists // Here you might want to consider validating the blob's existence. blob, err := s.BlobConnector.Download(blobID, blobName) diff --git a/internal/domain/blobs/contract.go b/internal/domain/blobs/contract.go index 3d3f962..19d976b 100644 --- a/internal/domain/blobs/contract.go +++ b/internal/domain/blobs/contract.go @@ -1,7 +1,5 @@ package blobs -import "bytes" - // IBlobUploadService defines methods for uploading blobs. type IBlobUploadService interface { // Upload handles the upload of blobs from the specified file paths. @@ -28,5 +26,5 @@ type IBlobMetadataService interface { type IBlobDownloadService interface { // Download retrieves a blob by its ID and name. // It returns the file data as a byte slice, and any error encountered during the download process. - Download(blobID, blobName string) (*bytes.Buffer, error) + Download(blobID, blobName string) ([]byte, error) } diff --git a/internal/domain/keys/contract.go b/internal/domain/keys/contract.go index 5f83e61..97fb1c4 100644 --- a/internal/domain/keys/contract.go +++ b/internal/domain/keys/contract.go @@ -36,5 +36,5 @@ type ICryptoKeyMetadataService interface { type ICryptoKeyDownloadService interface { // Download retrieves a cryptographic key by its ID and type. // It returns the CryptoKeyMeta, the key data as a byte slice, and any error encountered during the download process. - Download(keyID string, keyType KeyType) (*CryptoKeyMeta, []byte, error) + Download(keyID string, keyType KeyType) ([]byte, error) } diff --git a/internal/infrastructure/connector/blob.go b/internal/infrastructure/connector/blob.go index 99e8d58..8593453 100644 --- a/internal/infrastructure/connector/blob.go +++ b/internal/infrastructure/connector/blob.go @@ -19,7 +19,7 @@ type BlobConnector interface { // Upload uploads multiple files to Blob Storage and returns their metadata. Upload(filePaths []string) ([]*blobs.BlobMeta, error) // Download retrieves a blob's content by its ID and name, and returns the data as a stream. - Download(blobId, blobName string) (*bytes.Buffer, error) + Download(blobId, blobName string) ([]byte, error) // Delete deletes a blob from Blob Storage by its ID and Name, and returns any error encountered. Delete(blobId, blobName string) error } @@ -130,7 +130,7 @@ func (abc *AzureBlobConnector) rollbackUploadedBlobs(blobs []*blobs.BlobMeta) { } // Download retrieves a blob's content by its ID and name, and returns the data as a stream. -func (abc *AzureBlobConnector) Download(blobId, blobName string) (*bytes.Buffer, error) { +func (abc *AzureBlobConnector) Download(blobId, blobName string) ([]byte, error) { ctx := context.Background() // Construct the full blob path by combining blob ID and name @@ -159,7 +159,7 @@ func (abc *AzureBlobConnector) Download(blobId, blobName string) (*bytes.Buffer, } // Return the buffer containing the downloaded data - return &downloadedData, nil + return downloadedData.Bytes(), nil } // Delete deletes a blob from Azure Blob Storage by its ID and Name, and returns any error encountered. diff --git a/internal/infrastructure/connector/key.go b/internal/infrastructure/connector/key.go index 2918f13..90c437b 100644 --- a/internal/infrastructure/connector/key.go +++ b/internal/infrastructure/connector/key.go @@ -1,7 +1,6 @@ package connector import ( - "bytes" "crypto_vault_service/internal/domain/keys" ) @@ -11,7 +10,7 @@ type VaultConnector interface { Upload(filePaths []string) ([]*keys.CryptoKeyMeta, error) // Download retrieves a blob's content by its ID and name, and returns the data as a stream. - Download(blobId, blobName string) (*bytes.Buffer, error) + Download(blobId, blobName string) ([]byte, error) // // Rotate() diff --git a/test/integration/infrastructure/connector/az_blob_test.go b/test/integration/infrastructure/connector/az_blob_test.go index a03e171..d7085f9 100644 --- a/test/integration/infrastructure/connector/az_blob_test.go +++ b/test/integration/infrastructure/connector/az_blob_test.go @@ -71,8 +71,11 @@ func TestDownload(t *testing.T) { downloadedData, err := abc.Download(blob.ID, blob.Name) require.NoError(t, err) + // Convert *bytes.Buffer to []byte + downloadedBytes := downloadedData + // Assert that the downloaded content is the same as the original file content - assert.Equal(t, string(testContent), downloadedData.String()) + assert.Equal(t, testContent, downloadedBytes) // testContent should be []byte // Clean up the test file err = os.Remove(testFilePath) diff --git a/test/unit/app/services/blob_services_mock_test.go b/test/unit/app/services/blob_services_mock_test.go index 6589475..bfedaa1 100644 --- a/test/unit/app/services/blob_services_mock_test.go +++ b/test/unit/app/services/blob_services_mock_test.go @@ -1,7 +1,6 @@ package services import ( - "bytes" "crypto_vault_service/internal/app/services" "crypto_vault_service/internal/domain/blobs" "fmt" @@ -139,10 +138,9 @@ func TestBlobDownloadService(t *testing.T) { t.Run("successfully downloads a blob", func(t *testing.T) { blobID := "1" blobName := "file1.txt" - mockContent := &bytes.Buffer{} - mockContent.WriteString("file content") + mockContent := []byte("file content") - // Setup expectations for the mock BlobConnector to return the content + // Setup expectations for the mock BlobConnector to return the content as []byte mockBlobConnector.On("Download", blobID, blobName).Return(mockContent, nil) // Call the method under test @@ -150,7 +148,7 @@ func TestBlobDownloadService(t *testing.T) { // Assert the results assert.NoError(t, err) - assert.Equal(t, mockContent, downloadedBlob) + assert.Equal(t, mockContent, downloadedBlob) // Assert equality of byte slices // Assert that the expectations were met mockBlobConnector.AssertExpectations(t) diff --git a/test/unit/app/services/mocks.go b/test/unit/app/services/mocks.go index 6029f4d..2153caa 100644 --- a/test/unit/app/services/mocks.go +++ b/test/unit/app/services/mocks.go @@ -1,8 +1,8 @@ package services import ( - "bytes" "crypto_vault_service/internal/domain/blobs" + "fmt" "github.com/stretchr/testify/mock" ) @@ -22,9 +22,13 @@ func (m *MockBlobConnector) Delete(blobID, blobName string) error { return args.Error(0) } -func (m *MockBlobConnector) Download(blobID, blobName string) (*bytes.Buffer, error) { +func (m *MockBlobConnector) Download(blobID, blobName string) ([]byte, error) { args := m.Called(blobID, blobName) - return args.Get(0).(*bytes.Buffer), args.Error(1) + data, ok := args.Get(0).([]byte) + if !ok { + return nil, fmt.Errorf("expected []byte, but got %T", args.Get(0)) + } + return data, args.Error(1) } // MockBlobRepository is a mock for the BlobRepository interface From 54bc801d810495d0998de352011583a27529b32f Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 Nov 2024 14:52:53 +0000 Subject: [PATCH 12/14] remove ExpiresAt property --- internal/domain/blobs/query.go | 9 ++--- internal/domain/keys/model.go | 1 - internal/domain/keys/query.go | 5 ++- .../persistence/repository/blob_psql_test.go | 36 +++++++++---------- .../repository/blob_sqlite_test.go | 36 +++++++++---------- .../persistence/repository/key_sqlite_test.go | 36 +++++++++---------- test/unit/domain/blobs/blob_test.go | 6 ++-- test/unit/domain/keys/key_test.go | 10 ++---- 8 files changed, 58 insertions(+), 81 deletions(-) diff --git a/internal/domain/blobs/query.go b/internal/domain/blobs/query.go index 8677c87..7f45331 100644 --- a/internal/domain/blobs/query.go +++ b/internal/domain/blobs/query.go @@ -19,8 +19,8 @@ type BlobMetaQuery struct { Offset int `validate:"omitempty,min=0"` // Offset is optional but should be 0 or greater for pagination // Sorting properties - SortBy string `validate:"omitempty,oneof=ID Type CreatedAt ExpiresAt"` // SortBy is optional but can be one of the fields to sort by - SortOrder string `validate:"omitempty,oneof=asc desc"` // SortOrder is optional, default is ascending ('asc'), can also be 'desc' + SortBy string `validate:"omitempty,oneof=ID Type CreatedAt"` // SortBy is optional but can be one of the fields to sort by + SortOrder string `validate:"omitempty,oneof=asc desc"` // SortOrder is optional, default is ascending ('asc'), can also be 'desc' } // NewBlobMetaQuery creates a BlobMetaQuery with default values. @@ -49,11 +49,6 @@ func (b *BlobMetaQuery) Validate() error { return fmt.Errorf("Validation failed: %v", validationErrors) } - // Custom validation logic: Check that ExpiresAt (if exists) is after CreatedAt - if !b.UploadTime.IsZero() && b.UploadTime.After(time.Now()) { - return fmt.Errorf("UploadTime cannot be in the future") - } - // Return nil if no validation errors are found return nil } diff --git a/internal/domain/keys/model.go b/internal/domain/keys/model.go index 03a4433..7bb2ffc 100644 --- a/internal/domain/keys/model.go +++ b/internal/domain/keys/model.go @@ -12,7 +12,6 @@ type CryptoKeyMeta struct { ID string `gorm:"primaryKey" validate:"required,uuid4"` // ID is required and must be a valid UUID Type string `validate:"required,oneof=AES RSA ECDSA"` // Type is required and must be one of the listed types CreatedAt time.Time `validate:"required"` // CreatedAt is required - ExpiresAt time.Time `validate:"required,gtefield=CreatedAt"` // ExpiresAt is required and must be after CreatedAt UserID string `gorm:"index" validate:"required,uuid4"` // UserID is required and must be a valid UUID } diff --git a/internal/domain/keys/query.go b/internal/domain/keys/query.go index eb4067e..eb3a16d 100644 --- a/internal/domain/keys/query.go +++ b/internal/domain/keys/query.go @@ -11,15 +11,14 @@ import ( type CryptoKeyQuery struct { Type string `validate:"omitempty,oneof=AES RSA ECDSA"` // Type is optional but if provided, must be one of the listed types (AES, RSA, ECDSA) CreatedAt time.Time `validate:"omitempty,gtefield=CreatedAt"` // CreatedAt is optional, but can be used for filtering - ExpiresAt time.Time `validate:"omitempty,gtefield=CreatedAt"` // ExpiresAt is optional, but can be used for filtering // Pagination properties Limit int `validate:"omitempty,min=1"` // Limit is optional but if provided, should be at least 1 Offset int `validate:"omitempty,min=0"` // Offset is optional but should be 0 or greater for pagination // Sorting properties - SortBy string `validate:"omitempty,oneof=ID Type CreatedAt ExpiresAt"` // SortBy is optional but can be one of the fields to sort by - SortOrder string `validate:"omitempty,oneof=asc desc"` // SortOrder is optional, default is ascending ('asc'), can also be 'desc' + SortBy string `validate:"omitempty,oneof=ID Type CreatedAt"` // SortBy is optional but can be one of the fields to sort by + SortOrder string `validate:"omitempty,oneof=asc desc"` // SortOrder is optional, default is ascending ('asc'), can also be 'desc' } // New function to create a CryptoKeyQuery with default values diff --git a/test/integration/persistence/repository/blob_psql_test.go b/test/integration/persistence/repository/blob_psql_test.go index 2b627a6..da71601 100644 --- a/test/integration/persistence/repository/blob_psql_test.go +++ b/test/integration/persistence/repository/blob_psql_test.go @@ -25,11 +25,10 @@ func TestBlobPsqlRepository_Create(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields @@ -70,11 +69,10 @@ func TestBlobPsqlRepository_GetById(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields @@ -114,11 +112,10 @@ func TestBlobPsqlRepository_UpdateById(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields @@ -159,11 +156,10 @@ func TestBlobPsqlRepository_DeleteById(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields diff --git a/test/integration/persistence/repository/blob_sqlite_test.go b/test/integration/persistence/repository/blob_sqlite_test.go index 328bc00..00eadea 100644 --- a/test/integration/persistence/repository/blob_sqlite_test.go +++ b/test/integration/persistence/repository/blob_sqlite_test.go @@ -25,11 +25,10 @@ func TestBlobInSqliteRepository_Create(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields @@ -70,11 +69,10 @@ func TestBlobInSqliteRepository_GetById(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields @@ -114,11 +112,10 @@ func TestBlobInSqliteRepository_UpdateById(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields @@ -163,11 +160,10 @@ func TestBlobInSqliteRepository_DeleteById(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields diff --git a/test/integration/persistence/repository/key_sqlite_test.go b/test/integration/persistence/repository/key_sqlite_test.go index 3ded172..4295472 100644 --- a/test/integration/persistence/repository/key_sqlite_test.go +++ b/test/integration/persistence/repository/key_sqlite_test.go @@ -24,11 +24,10 @@ func TestCryptoKeySqliteRepository_Create(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := &keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create the cryptographic key in DB @@ -55,11 +54,10 @@ func TestCryptoKeySqliteRepository_GetByID(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := &keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "RSA", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "RSA", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create the cryptographic key in DB @@ -85,11 +83,10 @@ func TestCryptoKeySqliteRepository_UpdateByID(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := &keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create the cryptographic key in DB @@ -116,11 +113,10 @@ func TestCryptoKeySqliteRepository_DeleteByID(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := &keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - ExpiresAt: time.Now().Add(24 * time.Hour), // Valid ExpiresAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + CreatedAt: time.Now(), // Valid CreatedAt time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create the cryptographic key in DB diff --git a/test/unit/domain/blobs/blob_test.go b/test/unit/domain/blobs/blob_test.go index 530681c..5c8e147 100644 --- a/test/unit/domain/blobs/blob_test.go +++ b/test/unit/domain/blobs/blob_test.go @@ -32,7 +32,7 @@ func NewBlobValidationTests() *BlobValidationTests { HashAlgorithm: "SHA256", IsEncrypted: true, IsSigned: false, - CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: uuid.New().String()}, + CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", CreatedAt: time.Now(), UserID: uuid.New().String()}, KeyID: uuid.New().String(), } @@ -47,7 +47,7 @@ func NewBlobValidationTests() *BlobValidationTests { HashAlgorithm: "SHA256", IsEncrypted: true, IsSigned: false, - CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: uuid.New().String()}, + CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", CreatedAt: time.Now(), UserID: uuid.New().String()}, KeyID: uuid.New().String(), } @@ -62,7 +62,7 @@ func NewBlobValidationTests() *BlobValidationTests { HashAlgorithm: "SHA256", IsEncrypted: true, IsSigned: false, - CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: uuid.New().String()}, + CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", CreatedAt: time.Now(), UserID: uuid.New().String()}, KeyID: uuid.New().String(), } diff --git a/test/unit/domain/keys/key_test.go b/test/unit/domain/keys/key_test.go index 4fa85e2..211fad3 100644 --- a/test/unit/domain/keys/key_test.go +++ b/test/unit/domain/keys/key_test.go @@ -16,8 +16,7 @@ func TestCryptoKeyValidation(t *testing.T) { ID: uuid.New().String(), // Valid UUID Type: "AES", // Valid Type CreatedAt: time.Now(), - ExpiresAt: time.Now().Add(time.Hour * 24), // Valid ExpiresAt - UserID: uuid.New().String(), // Valid UserID + UserID: uuid.New().String(), // Valid UserID } // Validate the valid CryptoKey @@ -29,8 +28,7 @@ func TestCryptoKeyValidation(t *testing.T) { ID: "", // Invalid empty ID Type: "InvalidType", // Invalid Type CreatedAt: time.Now(), - ExpiresAt: time.Now().Add(-time.Hour * 24), // Invalid ExpiresAt (before CreatedAt) - UserID: "invalid-user-id", // Invalid UserID + UserID: "invalid-user-id", // Invalid UserID } // Validate the invalid CryptoKey @@ -38,7 +36,6 @@ func TestCryptoKeyValidation(t *testing.T) { assert.NotNil(t, err, "Expected validation errors for invalid CryptoKey") assert.Contains(t, err.Error(), "Field: ID, Tag: required") assert.Contains(t, err.Error(), "Field: Type, Tag: oneof") - assert.Contains(t, err.Error(), "Field: ExpiresAt, Tag: gtefield") } // TestCryptoKeyValidations tests the validation edge cases for CryptoKey @@ -48,8 +45,7 @@ func TestCryptoKeyValidations(t *testing.T) { ID: uuid.New().String(), // Valid UUID Type: "AES", // Valid Type CreatedAt: time.Now(), - ExpiresAt: time.Now().Add(time.Hour * 24), // Valid ExpiresAt - UserID: "", // Invalid empty UserID + UserID: "", // Invalid empty UserID } err := invalidKey.Validate() From 815b35174af524345ff266f983823e8e8707ab06 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 Nov 2024 15:03:33 +0000 Subject: [PATCH 13/14] rename property --- internal/domain/blobs/model.go | 2 +- internal/domain/blobs/query.go | 20 ++-- internal/domain/keys/model.go | 8 +- internal/domain/keys/query.go | 16 +-- internal/infrastructure/connector/blob.go | 10 +- .../persistence/repository/blob_psql_test.go | 112 +++++++++--------- .../repository/blob_sqlite_test.go | 112 +++++++++--------- .../persistence/repository/key_sqlite_test.go | 32 ++--- test/unit/domain/blobs/blob_test.go | 12 +- test/unit/domain/keys/key_test.go | 24 ++-- 10 files changed, 174 insertions(+), 174 deletions(-) diff --git a/internal/domain/blobs/model.go b/internal/domain/blobs/model.go index ec9ca70..0fe6ae2 100644 --- a/internal/domain/blobs/model.go +++ b/internal/domain/blobs/model.go @@ -11,7 +11,7 @@ import ( // BlobMeta represents metadata on the actual blob metadata being stored type BlobMeta struct { ID string `gorm:"primaryKey" validate:"required,uuid4"` // ID is required and must be a valid UUID - UploadTime time.Time `validate:"required"` // UploadTime is required + DateTimeCreated time.Time `validate:"required"` // DateTimeCreated is required UserID string `validate:"required,uuid4"` // UserID is required and must be a valid UUID Name string `validate:"required,min=1,max=255"` // Name is required, and its length must be between 1 and 255 characters Size int64 `validate:"required,min=1"` // Size must be greater than 0 diff --git a/internal/domain/blobs/query.go b/internal/domain/blobs/query.go index 7f45331..33f3f23 100644 --- a/internal/domain/blobs/query.go +++ b/internal/domain/blobs/query.go @@ -9,27 +9,27 @@ import ( // BlobMetaQuery represents metadata on the actual blob being stored. type BlobMetaQuery struct { - UploadTime time.Time `validate:"required"` // UploadTime is required - Name string `validate:"required,min=1,max=255"` // Name is required and its length must be between 1 and 255 characters - Size int64 `validate:"required,min=1"` // Size must be greater than 0 - Type string `validate:"required,min=1,max=50"` // Type is required, and its length must be between 1 and 50 characters + DateTimeCreated time.Time `validate:"required"` // DateTimeCreated is required + Name string `validate:"required,min=1,max=255"` // Name is required and its length must be between 1 and 255 characters + Size int64 `validate:"required,min=1"` // Size must be greater than 0 + Type string `validate:"required,min=1,max=50"` // Type is required, and its length must be between 1 and 50 characters // Pagination properties Limit int `validate:"omitempty,min=1"` // Limit is optional but if provided, should be at least 1 Offset int `validate:"omitempty,min=0"` // Offset is optional but should be 0 or greater for pagination // Sorting properties - SortBy string `validate:"omitempty,oneof=ID Type CreatedAt"` // SortBy is optional but can be one of the fields to sort by - SortOrder string `validate:"omitempty,oneof=asc desc"` // SortOrder is optional, default is ascending ('asc'), can also be 'desc' + SortBy string `validate:"omitempty,oneof=ID Type DateTimeCreated"` // SortBy is optional but can be one of the fields to sort by + SortOrder string `validate:"omitempty,oneof=asc desc"` // SortOrder is optional, default is ascending ('asc'), can also be 'desc' } // NewBlobMetaQuery creates a BlobMetaQuery with default values. func NewBlobMetaQuery() *BlobMetaQuery { return &BlobMetaQuery{ - Limit: 10, // Default limit to 10 results per page - Offset: 0, // Default offset to 0 for pagination - SortBy: "CreatedAt", // Default sort by CreatedAt - SortOrder: "asc", // Default sort order ascending + Limit: 10, // Default limit to 10 results per page + Offset: 0, // Default offset to 0 for pagination + SortBy: "DateTimeCreated", // Default sort by DateTimeCreated + SortOrder: "asc", // Default sort order ascending } } diff --git a/internal/domain/keys/model.go b/internal/domain/keys/model.go index 7bb2ffc..bba959f 100644 --- a/internal/domain/keys/model.go +++ b/internal/domain/keys/model.go @@ -9,10 +9,10 @@ import ( // CryptoKeyMeta represents the encryption key entity type CryptoKeyMeta struct { - ID string `gorm:"primaryKey" validate:"required,uuid4"` // ID is required and must be a valid UUID - Type string `validate:"required,oneof=AES RSA ECDSA"` // Type is required and must be one of the listed types - CreatedAt time.Time `validate:"required"` // CreatedAt is required - UserID string `gorm:"index" validate:"required,uuid4"` // UserID is required and must be a valid UUID + ID string `gorm:"primaryKey" validate:"required,uuid4"` // ID is required and must be a valid UUID + Type string `validate:"required,oneof=AES RSA ECDSA"` // Type is required and must be one of the listed types + DateTimeCreated time.Time `validate:"required"` // DateTimeCreated is required + UserID string `gorm:"index" validate:"required,uuid4"` // UserID is required and must be a valid UUID } // Validate for validating CryptoKeyMeta struct diff --git a/internal/domain/keys/query.go b/internal/domain/keys/query.go index eb3a16d..5a897f9 100644 --- a/internal/domain/keys/query.go +++ b/internal/domain/keys/query.go @@ -9,25 +9,25 @@ import ( // CryptoKeyQuery represents the parameters used to query encryption keys. type CryptoKeyQuery struct { - Type string `validate:"omitempty,oneof=AES RSA ECDSA"` // Type is optional but if provided, must be one of the listed types (AES, RSA, ECDSA) - CreatedAt time.Time `validate:"omitempty,gtefield=CreatedAt"` // CreatedAt is optional, but can be used for filtering + Type string `validate:"omitempty,oneof=AES RSA ECDSA"` // Type is optional but if provided, must be one of the listed types (AES, RSA, ECDSA) + DateTimeCreated time.Time `validate:"omitempty,gtefield=DateTimeCreated"` // DateTimeCreated is optional, but can be used for filtering // Pagination properties Limit int `validate:"omitempty,min=1"` // Limit is optional but if provided, should be at least 1 Offset int `validate:"omitempty,min=0"` // Offset is optional but should be 0 or greater for pagination // Sorting properties - SortBy string `validate:"omitempty,oneof=ID Type CreatedAt"` // SortBy is optional but can be one of the fields to sort by - SortOrder string `validate:"omitempty,oneof=asc desc"` // SortOrder is optional, default is ascending ('asc'), can also be 'desc' + SortBy string `validate:"omitempty,oneof=ID Type DateTimeCreated"` // SortBy is optional but can be one of the fields to sort by + SortOrder string `validate:"omitempty,oneof=asc desc"` // SortOrder is optional, default is ascending ('asc'), can also be 'desc' } // New function to create a CryptoKeyQuery with default values func NewCryptoKeyQuery() *CryptoKeyQuery { return &CryptoKeyQuery{ - Limit: 10, // Default limit to 10 results per page - Offset: 0, // Default offset to 0 for pagination - SortBy: "CreatedAt", // Default sort by CreatedAt - SortOrder: "asc", // Default sort order ascending + Limit: 10, // Default limit to 10 results per page + Offset: 0, // Default offset to 0 for pagination + SortBy: "DateTimeCreated", // Default sort by DateTimeCreated + SortOrder: "asc", // Default sort order ascending } } diff --git a/internal/infrastructure/connector/blob.go b/internal/infrastructure/connector/blob.go index 8593453..7d263b9 100644 --- a/internal/infrastructure/connector/blob.go +++ b/internal/infrastructure/connector/blob.go @@ -88,11 +88,11 @@ func (abc *AzureBlobConnector) Upload(filePaths []string) ([]*blobs.BlobMeta, er // Create a Blob object for metadata (Fill in missing fields) blob := &blobs.BlobMeta{ - ID: blobID, - Name: fileInfo.Name(), - Size: fileInfo.Size(), - Type: fileExt, - UploadTime: time.Now(), // Set the current time + ID: blobID, + Name: fileInfo.Name(), + Size: fileInfo.Size(), + Type: fileExt, + DateTimeCreated: time.Now(), // Set the current time } // Construct the full blob name (ID and Name) diff --git a/test/integration/persistence/repository/blob_psql_test.go b/test/integration/persistence/repository/blob_psql_test.go index da71601..a61474a 100644 --- a/test/integration/persistence/repository/blob_psql_test.go +++ b/test/integration/persistence/repository/blob_psql_test.go @@ -25,24 +25,24 @@ func TestBlobPsqlRepository_Create(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + DateTimeCreated: time.Now(), // Valid DateTimeCreated time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID - UploadTime: time.Now(), - UserID: uuid.New().String(), // Generate valid UUID for UserID - Name: "test-blob", - Size: 1024, - Type: "text", - IsEncrypted: false, - IsSigned: true, - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + ID: uuid.New().String(), // Generate valid UUID + DateTimeCreated: time.Now(), + UserID: uuid.New().String(), // Generate valid UUID for UserID + Name: "test-blob", + Size: 1024, + Type: "text", + IsEncrypted: false, + IsSigned: true, + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set } // Call the Create method @@ -69,24 +69,24 @@ func TestBlobPsqlRepository_GetById(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + DateTimeCreated: time.Now(), // Valid DateTimeCreated time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID - UploadTime: time.Now(), - UserID: cryptographicKey.UserID, // Link to valid UserID from CryptoKey - Name: "test-blob", - Size: 1024, - Type: "text", - IsEncrypted: false, - IsSigned: true, - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + ID: uuid.New().String(), // Generate valid UUID + DateTimeCreated: time.Now(), + UserID: cryptographicKey.UserID, // Link to valid UserID from CryptoKey + Name: "test-blob", + Size: 1024, + Type: "text", + IsEncrypted: false, + IsSigned: true, + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set } // Create the blob in DB @@ -112,24 +112,24 @@ func TestBlobPsqlRepository_UpdateById(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + DateTimeCreated: time.Now(), // Valid DateTimeCreated time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID - UploadTime: time.Now(), - UserID: uuid.New().String(), // Generate valid UUID for UserID - Name: "test-blob", - Size: 1024, - Type: "text", - IsEncrypted: false, - IsSigned: true, - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + ID: uuid.New().String(), // Generate valid UUID + DateTimeCreated: time.Now(), + UserID: uuid.New().String(), // Generate valid UUID for UserID + Name: "test-blob", + Size: 1024, + Type: "text", + IsEncrypted: false, + IsSigned: true, + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set } // Create the blob in DB @@ -156,24 +156,24 @@ func TestBlobPsqlRepository_DeleteById(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + DateTimeCreated: time.Now(), // Valid DateTimeCreated time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID - UploadTime: time.Now(), - UserID: uuid.New().String(), // Generate valid UUID for UserID - Name: "test-blob", - Size: 1024, - Type: "text", - IsEncrypted: false, - IsSigned: true, - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + ID: uuid.New().String(), // Generate valid UUID + DateTimeCreated: time.Now(), + UserID: uuid.New().String(), // Generate valid UUID for UserID + Name: "test-blob", + Size: 1024, + Type: "text", + IsEncrypted: false, + IsSigned: true, + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set } // Create the blob in DB diff --git a/test/integration/persistence/repository/blob_sqlite_test.go b/test/integration/persistence/repository/blob_sqlite_test.go index 00eadea..af0c787 100644 --- a/test/integration/persistence/repository/blob_sqlite_test.go +++ b/test/integration/persistence/repository/blob_sqlite_test.go @@ -25,24 +25,24 @@ func TestBlobInSqliteRepository_Create(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + DateTimeCreated: time.Now(), // Valid DateTimeCreated time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID - UploadTime: time.Now(), - UserID: uuid.New().String(), // Generate valid UUID for UserID - Name: "test-blob", - Size: 1024, - Type: "text", - IsEncrypted: false, - IsSigned: true, - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + ID: uuid.New().String(), // Generate valid UUID + DateTimeCreated: time.Now(), + UserID: uuid.New().String(), // Generate valid UUID for UserID + Name: "test-blob", + Size: 1024, + Type: "text", + IsEncrypted: false, + IsSigned: true, + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set } // Call the Create method @@ -69,24 +69,24 @@ func TestBlobInSqliteRepository_GetById(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + DateTimeCreated: time.Now(), // Valid DateTimeCreated time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID - UploadTime: time.Now(), - UserID: cryptographicKey.UserID, // Link to valid UserID from CryptoKey - Name: "test-blob", - Size: 1024, - Type: "text", - IsEncrypted: false, - IsSigned: true, - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + ID: uuid.New().String(), // Generate valid UUID + DateTimeCreated: time.Now(), + UserID: cryptographicKey.UserID, // Link to valid UserID from CryptoKey + Name: "test-blob", + Size: 1024, + Type: "text", + IsEncrypted: false, + IsSigned: true, + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set } // Create the blob in DB @@ -112,24 +112,24 @@ func TestBlobInSqliteRepository_UpdateById(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + DateTimeCreated: time.Now(), // Valid DateTimeCreated time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID - UploadTime: time.Now(), - UserID: uuid.New().String(), // Generate valid UUID for UserID - Name: "test-blob", - Size: 1024, - Type: "text", - IsEncrypted: false, - IsSigned: true, - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + ID: uuid.New().String(), // Generate valid UUID + DateTimeCreated: time.Now(), + UserID: uuid.New().String(), // Generate valid UUID for UserID + Name: "test-blob", + Size: 1024, + Type: "text", + IsEncrypted: false, + IsSigned: true, + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set } // Create the blob in DB @@ -160,24 +160,24 @@ func TestBlobInSqliteRepository_DeleteById(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + DateTimeCreated: time.Now(), // Valid DateTimeCreated time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create a test Blob object with valid UUIDs and required fields blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID - UploadTime: time.Now(), - UserID: uuid.New().String(), // Generate valid UUID for UserID - Name: "test-blob", - Size: 1024, - Type: "text", - IsEncrypted: false, - IsSigned: true, - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + ID: uuid.New().String(), // Generate valid UUID + DateTimeCreated: time.Now(), + UserID: uuid.New().String(), // Generate valid UUID for UserID + Name: "test-blob", + Size: 1024, + Type: "text", + IsEncrypted: false, + IsSigned: true, + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set } // Create the blob in DB diff --git a/test/integration/persistence/repository/key_sqlite_test.go b/test/integration/persistence/repository/key_sqlite_test.go index 4295472..ce38524 100644 --- a/test/integration/persistence/repository/key_sqlite_test.go +++ b/test/integration/persistence/repository/key_sqlite_test.go @@ -24,10 +24,10 @@ func TestCryptoKeySqliteRepository_Create(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := &keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + DateTimeCreated: time.Now(), // Valid DateTimeCreated time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create the cryptographic key in DB @@ -54,10 +54,10 @@ func TestCryptoKeySqliteRepository_GetByID(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := &keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "RSA", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + 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 } // Create the cryptographic key in DB @@ -83,10 +83,10 @@ func TestCryptoKeySqliteRepository_UpdateByID(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := &keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + DateTimeCreated: time.Now(), // Valid DateTimeCreated time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create the cryptographic key in DB @@ -113,10 +113,10 @@ func TestCryptoKeySqliteRepository_DeleteByID(t *testing.T) { // Create a valid CryptoKey object cryptographicKey := &keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - CreatedAt: time.Now(), // Valid CreatedAt time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), // Generate valid UUID for ID + Type: "AES", // Example key type + DateTimeCreated: time.Now(), // Valid DateTimeCreated time + UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create the cryptographic key in DB diff --git a/test/unit/domain/blobs/blob_test.go b/test/unit/domain/blobs/blob_test.go index 5c8e147..63b3908 100644 --- a/test/unit/domain/blobs/blob_test.go +++ b/test/unit/domain/blobs/blob_test.go @@ -23,7 +23,7 @@ func NewBlobValidationTests() *BlobValidationTests { // Create valid and invalid test data validBlob := blobs.BlobMeta{ ID: uuid.New().String(), - UploadTime: time.Now(), + DateTimeCreated: time.Now(), UserID: uuid.New().String(), Name: "test_blobs.txt", Size: 12345, @@ -32,13 +32,13 @@ func NewBlobValidationTests() *BlobValidationTests { HashAlgorithm: "SHA256", IsEncrypted: true, IsSigned: false, - CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", CreatedAt: time.Now(), UserID: uuid.New().String()}, + CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", DateTimeCreated: time.Now(), UserID: uuid.New().String()}, KeyID: uuid.New().String(), } invalidBlob := blobs.BlobMeta{ ID: "", // Invalid empty ID - UploadTime: time.Now(), + DateTimeCreated: time.Now(), UserID: "invalid-uuid", // Invalid UserID Name: "test_blobs.txt", Size: -12345, // Invalid Size (negative) @@ -47,13 +47,13 @@ func NewBlobValidationTests() *BlobValidationTests { HashAlgorithm: "SHA256", IsEncrypted: true, IsSigned: false, - CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", CreatedAt: time.Now(), UserID: uuid.New().String()}, + CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", DateTimeCreated: time.Now(), UserID: uuid.New().String()}, KeyID: uuid.New().String(), } invalidBlob2 := blobs.BlobMeta{ ID: uuid.New().String(), - UploadTime: time.Now(), + DateTimeCreated: time.Now(), UserID: uuid.New().String(), Name: "", // Invalid empty Name Size: 12345, @@ -62,7 +62,7 @@ func NewBlobValidationTests() *BlobValidationTests { HashAlgorithm: "SHA256", IsEncrypted: true, IsSigned: false, - CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", CreatedAt: time.Now(), UserID: uuid.New().String()}, + CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", DateTimeCreated: time.Now(), UserID: uuid.New().String()}, KeyID: uuid.New().String(), } diff --git a/test/unit/domain/keys/key_test.go b/test/unit/domain/keys/key_test.go index 211fad3..aa69695 100644 --- a/test/unit/domain/keys/key_test.go +++ b/test/unit/domain/keys/key_test.go @@ -13,10 +13,10 @@ import ( func TestCryptoKeyValidation(t *testing.T) { // Valid CryptoKey validKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Valid UUID - Type: "AES", // Valid Type - CreatedAt: time.Now(), - UserID: uuid.New().String(), // Valid UserID + ID: uuid.New().String(), // Valid UUID + Type: "AES", // Valid Type + DateTimeCreated: time.Now(), + UserID: uuid.New().String(), // Valid UserID } // Validate the valid CryptoKey @@ -25,10 +25,10 @@ func TestCryptoKeyValidation(t *testing.T) { // Invalid CryptoKey (empty ID, invalid Type, expired) invalidKey := keys.CryptoKeyMeta{ - ID: "", // Invalid empty ID - Type: "InvalidType", // Invalid Type - CreatedAt: time.Now(), - UserID: "invalid-user-id", // Invalid UserID + ID: "", // Invalid empty ID + Type: "InvalidType", // Invalid Type + DateTimeCreated: time.Now(), + UserID: "invalid-user-id", // Invalid UserID } // Validate the invalid CryptoKey @@ -42,10 +42,10 @@ func TestCryptoKeyValidation(t *testing.T) { func TestCryptoKeyValidations(t *testing.T) { // Test missing UserID (should fail) invalidKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Valid UUID - Type: "AES", // Valid Type - CreatedAt: time.Now(), - UserID: "", // Invalid empty UserID + ID: uuid.New().String(), // Valid UUID + Type: "AES", // Valid Type + DateTimeCreated: time.Now(), + UserID: "", // Invalid empty UserID } err := invalidKey.Validate() From 312520dc803ff7754a71df87bd9c0b798ad215ee Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 Nov 2024 15:10:02 +0000 Subject: [PATCH 14/14] remove IsEncrypted or IsSigned properties due to encryption or signing behavior being inferred from the EncryptionAlgorithm and HashAlgorithm --- docs/diagrams/erd.mmd | 7 ++---- internal/domain/blobs/model.go | 2 -- .../persistence/repository/blob_psql_test.go | 23 ++++++++----------- .../repository/blob_sqlite_test.go | 8 ------- test/unit/domain/blobs/blob_test.go | 6 ----- 5 files changed, 11 insertions(+), 35 deletions(-) diff --git a/docs/diagrams/erd.mmd b/docs/diagrams/erd.mmd index ffa33c0..774f779 100644 --- a/docs/diagrams/erd.mmd +++ b/docs/diagrams/erd.mmd @@ -2,14 +2,13 @@ erDiagram CRYPTOGRAPHIC_KEY { string id PK string type - datetime created_at - datetime expires_at + datetime date_time_created string user_id FK } BLOB { string id PK - datetime upload_time + datetime date_time_created string user_id FK string key_id FK string name @@ -17,8 +16,6 @@ erDiagram string type string encryption_algorithm string hash_algorithm - bool is_encrypted - bool is_signed } CRYPTOGRAPHIC_KEY ||--o| BLOB : "associated with" diff --git a/internal/domain/blobs/model.go b/internal/domain/blobs/model.go index 0fe6ae2..1fa4ac9 100644 --- a/internal/domain/blobs/model.go +++ b/internal/domain/blobs/model.go @@ -18,8 +18,6 @@ type BlobMeta struct { Type string `validate:"required,min=1,max=50"` // Type is required, and its length must be between 1 and 50 characters EncryptionAlgorithm string `validate:"omitempty,oneof=AES RSA ECDSA"` // EncryptionAlgorithm is optional and must be one of the listed algorithms HashAlgorithm string `validate:"omitempty,oneof=SHA256 SHA512 MD5"` // HashAlgorithm is optional and must be one of the listed algorithms - IsEncrypted bool `validate:"-"` // IsEncrypted is required (true/false) - IsSigned bool `validate:"-"` // IsSigned is required (true/false) CryptoKey keys.CryptoKeyMeta `gorm:"foreignKey:KeyID" validate:"required"` // CryptoKey is required KeyID string `validate:"omitempty,uuid4"` // KeyID is optional and must be a valid UUID } diff --git a/test/integration/persistence/repository/blob_psql_test.go b/test/integration/persistence/repository/blob_psql_test.go index a61474a..5d90cd6 100644 --- a/test/integration/persistence/repository/blob_psql_test.go +++ b/test/integration/persistence/repository/blob_psql_test.go @@ -39,8 +39,6 @@ func TestBlobPsqlRepository_Create(t *testing.T) { Name: "test-blob", Size: 1024, Type: "text", - IsEncrypted: false, - IsSigned: true, CryptoKey: cryptographicKey, // Set the CryptoKey KeyID: cryptographicKey.ID, // Ensure ID is set } @@ -83,10 +81,9 @@ func TestBlobPsqlRepository_GetById(t *testing.T) { Name: "test-blob", Size: 1024, Type: "text", - IsEncrypted: false, - IsSigned: true, - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set } // Create the blob in DB @@ -126,10 +123,9 @@ func TestBlobPsqlRepository_UpdateById(t *testing.T) { Name: "test-blob", Size: 1024, Type: "text", - IsEncrypted: false, - IsSigned: true, - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set } // Create the blob in DB @@ -170,10 +166,9 @@ func TestBlobPsqlRepository_DeleteById(t *testing.T) { Name: "test-blob", Size: 1024, Type: "text", - IsEncrypted: false, - IsSigned: true, - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + + CryptoKey: cryptographicKey, // Set the CryptoKey + KeyID: cryptographicKey.ID, // Ensure ID is set } // Create the blob in DB diff --git a/test/integration/persistence/repository/blob_sqlite_test.go b/test/integration/persistence/repository/blob_sqlite_test.go index af0c787..f8a8ebd 100644 --- a/test/integration/persistence/repository/blob_sqlite_test.go +++ b/test/integration/persistence/repository/blob_sqlite_test.go @@ -39,8 +39,6 @@ func TestBlobInSqliteRepository_Create(t *testing.T) { Name: "test-blob", Size: 1024, Type: "text", - IsEncrypted: false, - IsSigned: true, CryptoKey: cryptographicKey, // Set the CryptoKey KeyID: cryptographicKey.ID, // Ensure ID is set } @@ -83,8 +81,6 @@ func TestBlobInSqliteRepository_GetById(t *testing.T) { Name: "test-blob", Size: 1024, Type: "text", - IsEncrypted: false, - IsSigned: true, CryptoKey: cryptographicKey, // Set the CryptoKey KeyID: cryptographicKey.ID, // Ensure ID is set } @@ -126,8 +122,6 @@ func TestBlobInSqliteRepository_UpdateById(t *testing.T) { Name: "test-blob", Size: 1024, Type: "text", - IsEncrypted: false, - IsSigned: true, CryptoKey: cryptographicKey, // Set the CryptoKey KeyID: cryptographicKey.ID, // Ensure ID is set } @@ -174,8 +168,6 @@ func TestBlobInSqliteRepository_DeleteById(t *testing.T) { Name: "test-blob", Size: 1024, Type: "text", - IsEncrypted: false, - IsSigned: true, CryptoKey: cryptographicKey, // Set the CryptoKey KeyID: cryptographicKey.ID, // Ensure ID is set } diff --git a/test/unit/domain/blobs/blob_test.go b/test/unit/domain/blobs/blob_test.go index 63b3908..137e413 100644 --- a/test/unit/domain/blobs/blob_test.go +++ b/test/unit/domain/blobs/blob_test.go @@ -30,8 +30,6 @@ func NewBlobValidationTests() *BlobValidationTests { Type: "text", EncryptionAlgorithm: "AES", HashAlgorithm: "SHA256", - IsEncrypted: true, - IsSigned: false, CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", DateTimeCreated: time.Now(), UserID: uuid.New().String()}, KeyID: uuid.New().String(), } @@ -45,8 +43,6 @@ func NewBlobValidationTests() *BlobValidationTests { Type: "text", EncryptionAlgorithm: "AES", HashAlgorithm: "SHA256", - IsEncrypted: true, - IsSigned: false, CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", DateTimeCreated: time.Now(), UserID: uuid.New().String()}, KeyID: uuid.New().String(), } @@ -60,8 +56,6 @@ func NewBlobValidationTests() *BlobValidationTests { Type: "text", EncryptionAlgorithm: "AES", HashAlgorithm: "SHA256", - IsEncrypted: true, - IsSigned: false, CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", DateTimeCreated: time.Now(), UserID: uuid.New().String()}, KeyID: uuid.New().String(), }