-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from MGTheTrain/feature/secure-file-storage
Feature/secure file storage
- Loading branch information
Showing
15 changed files
with
347 additions
and
4 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package contracts | ||
|
||
import ( | ||
"crypto_vault_service/internal/domain/model" | ||
"mime/multipart" | ||
) | ||
|
||
// BlobManagement defines methods for managing blob operations. | ||
type BlobManagement interface { | ||
// Upload handles the upload of a blob from a multipart form. | ||
// Returns the created Blob metadata and any error encountered. | ||
Upload(form *multipart.Form) (*model.Blob, error) | ||
|
||
// Download retrieves a blob by its ID, returning the metadata and file data. | ||
// Returns the Blob metadata, file data as a byte slice, and any error. | ||
Download(blobId string) (*model.Blob, []byte, error) | ||
|
||
// Delete removes a blob by its ID. | ||
// Returns any error encountered. | ||
Delete(blobId string) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package contracts | ||
|
||
import ( | ||
"crypto_vault_service/internal/domain/model" | ||
"mime/multipart" | ||
) | ||
|
||
// KeyManagement defines methods for managing cryptographic key operations. | ||
type KeyManagement interface { | ||
// Upload handles the upload of a cryptographic key from a multipart form. | ||
// Returns the created key metadata and any error encountered. | ||
Upload(form *multipart.Form) (*model.CryptographicKey, error) | ||
|
||
// Download retrieves a cryptographic key by its ID, returning the metadata and key data. | ||
// Returns the key metadata, key data as a byte slice, and any error. | ||
Download(keyId string) (*model.CryptographicKey, []byte, error) | ||
|
||
// Delete removes a cryptographic key by its ID. | ||
// Returns any error encountered. | ||
Delete(keyId string) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package contracts | ||
|
||
// KeyOperations defines methods for key management, encryption, signing, and PKCS#11 operations. | ||
type KeyOperations interface { | ||
|
||
// ---Key generation--- | ||
|
||
// GenerateKey generates keys for specified type and size (e.g., AES, RSA, ECDSA) | ||
GenerateKey(keyType string, keySize int) ([]byte, error) | ||
|
||
// ---Key storage and retrieval--- | ||
|
||
// SaveKey saves a key to a file | ||
SaveKey(key []byte, filename string) error | ||
// LoadKey loads a key from a file | ||
LoadKey(filename string) ([]byte, error) | ||
|
||
// ---Encryption and Decryption (Symmetric algorithms like AES)--- | ||
|
||
// EncryptWithSymmetricKey encrypts data with symmetric keys (e.g. AES) | ||
EncryptWithSymmetricKey(plainText []byte, key []byte) ([]byte, error) | ||
// DecryptWithSymmetricKey decrypts data with symmetric keys (e.g. AES) | ||
DecryptWithSymmetricKey(cipherText []byte, key []byte) ([]byte, error) | ||
|
||
// ---Asymmetric Encryption (RSA, ECDSA, PKCS#11)--- | ||
|
||
// EncryptWithPublicKey encrypts with public key using asymmetric algorithms (RSA, ECDSA) and optionally a PKCS#11 interface | ||
EncryptWithPublicKey(plainText []byte, publicKey interface{}) ([]byte, error) | ||
// DecryptWithPrivateKey decrypt with private key using asymmetric algorithms (RSA, ECDSA) and optionally a PKCS#11 interface | ||
DecryptWithPrivateKey(cipherText []byte, privateKey interface{}) ([]byte, error) | ||
|
||
// ---Signing and Verification (For RSA, ECDSA)--- | ||
|
||
// SignWithPrivateKey signs message with private key using asymmetric algorithms (RSA, ECDSA) and optionally a PKCS#11 interface | ||
SignWithPrivateKey(message []byte, privateKey interface{}) ([]byte, error) | ||
// VerifyWithPublicKey verifies signatures with public key using asymmetric algorithms (RSA, ECDSA) and optionally a PKCS#11 interface | ||
VerifyWithPublicKey(message []byte, signature []byte, publicKey interface{}) (bool, error) | ||
|
||
// ---PKCS#11 Operations--- | ||
|
||
// InitializeToken initializes PKCS#11 token in the specified slot | ||
InitializeToken(slot string) error | ||
// AddKeyToToken adds key to the PKCS#11 token | ||
AddKeyToToken() error | ||
// DeleteKeyFromToken deletes key from PKCS#11 token by type and label | ||
DeleteKeyFromToken(objectType, objectLabel string) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package contracts | ||
|
||
import ( | ||
"crypto_vault_service/internal/domain/model" | ||
) | ||
|
||
// MetadataManagement defines the methods for managing Blob and CryptographicKey metadata | ||
type MetadataManagement interface { | ||
// ---CRUD operations for Blob metadata--- | ||
|
||
// CreateBlob creates a new blob | ||
CreateBlob(blob *model.Blob) (*model.Blob, error) | ||
// GetBlob retrieves blob by ID | ||
GetBlob(blobID string) (*model.Blob, error) | ||
// UpdateBlob updates a blob's metadata | ||
UpdateBlob(blobID string, updates *model.Blob) (*model.Blob, error) | ||
// DeleteBlob deletes a blob by ID | ||
DeleteBlob(blobID string) error | ||
|
||
// ---CRUD operations for CryptographicKey metadata--- | ||
|
||
// CreateCryptographicKey creates a new cryptographic key | ||
CreateCryptographicKey(key *model.CryptographicKey) (*model.CryptographicKey, error) | ||
// GetCryptographicKey retrieves cryptographic key by ID | ||
GetCryptographicKey(keyID string) (*model.CryptographicKey, error) | ||
// UpdateCryptographicKey updates cryptographic key metadata | ||
UpdateCryptographicKey(keyID string, updates *model.CryptographicKey) (*model.CryptographicKey, error) | ||
// DeleteCryptographicKey deletes a cryptographic key by ID | ||
DeleteCryptographicKey(keyID string) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package contracts | ||
|
||
// PoC with OpenFGA required for signatures | ||
|
||
// PermissionManagement Interface | ||
type PermissionManagement interface { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package model | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
"github.com/go-playground/validator/v10" | ||
) | ||
|
||
// Blob represents metadata on the actual blob being stored | ||
type Blob struct { | ||
BlobID string `gorm:"primaryKey" validate:"required,uuid4"` // BlobID is required and must be a valid UUID | ||
BlobStoragePath string `validate:"required"` // BlobStoragePath is required | ||
UploadTime time.Time `validate:"required"` // UploadTime is required | ||
UserID string `validate:"required,uuid4"` // UserID is required and must be a valid UUID | ||
BlobName string `validate:"required,min=1,max=255"` // BlobName is required, and its length must be between 1 and 255 characters | ||
BlobSize int `validate:"required,min=1"` // BlobSize must be greater than 0 | ||
BlobType string `validate:"required,min=1,max=50"` // BlobType 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) | ||
CryptographicKey CryptographicKey `gorm:"foreignKey:KeyID" validate:"required"` // CryptographicKey is required | ||
KeyID string `validate:"omitempty,uuid4"` // KeyID is optional and must be a valid UUID | ||
} | ||
|
||
// Validate for validating Blob struct | ||
func (b *Blob) Validate() error { | ||
// Initialize the validator | ||
validate := validator.New() | ||
|
||
// Validate the struct | ||
err := validate.Struct(b) | ||
if err != nil { | ||
// If validation fails, return a formatted error | ||
var validationErrors []string | ||
for _, err := range err.(validator.ValidationErrors) { | ||
validationErrors = append(validationErrors, fmt.Sprintf("Field: %s, Tag: %s", err.Field(), err.Tag())) | ||
} | ||
return fmt.Errorf("Validation failed: %v", validationErrors) | ||
} | ||
return nil // Return nil if validation passes | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package model | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
"github.com/go-playground/validator/v10" | ||
) | ||
|
||
// CryptographicKey represents the encryption key entity | ||
type CryptographicKey struct { | ||
KeyID string `gorm:"primaryKey" validate:"required,uuid4"` // KeyID is required and must be a valid UUID | ||
KeyType string `validate:"required,oneof=AES RSA ECDSA"` // KeyType 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 | ||
} | ||
|
||
// Validate for validating CryptographicKey struct | ||
func (k *CryptographicKey) Validate() error { | ||
// Initialize the validator | ||
validate := validator.New() | ||
|
||
// Validate the struct | ||
err := validate.Struct(k) | ||
if err != nil { | ||
// If validation fails, return a formatted error | ||
var validationErrors []string | ||
for _, err := range err.(validator.ValidationErrors) { | ||
validationErrors = append(validationErrors, fmt.Sprintf("Field: %s, Tag: %s", err.Field(), err.Tag())) | ||
} | ||
return fmt.Errorf("Validation failed: %v", validationErrors) | ||
} | ||
return nil // Return nil if validation passes | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package model | ||
|
||
import ( | ||
"crypto_vault_service/internal/domain/model" | ||
"testing" | ||
"time" | ||
|
||
"github.com/google/uuid" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
// TestBlobValidation tests the Validator method for Blob | ||
func TestBlobValidation(t *testing.T) { | ||
// Valid Blob | ||
validBlob := model.Blob{ | ||
BlobID: uuid.New().String(), // Valid UUID | ||
BlobStoragePath: "/path/to/blob", | ||
UploadTime: time.Now(), | ||
UserID: uuid.New().String(), // Valid UUID | ||
BlobName: "test_blob.txt", | ||
BlobSize: 12345, | ||
BlobType: "text", | ||
EncryptionAlgorithm: "AES", | ||
HashAlgorithm: "SHA256", | ||
IsEncrypted: true, | ||
IsSigned: false, // Explicitly set to false | ||
CryptographicKey: model.CryptographicKey{KeyID: uuid.New().String(), KeyType: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: uuid.New().String()}, | ||
KeyID: uuid.New().String(), // Use valid UUID here | ||
} | ||
|
||
// Validate the valid Blob | ||
err := validBlob.Validate() | ||
assert.Nil(t, err, "Expected no validation errors for valid Blob") | ||
|
||
// Invalid Blob (empty BlobID, invalid BlobSize) | ||
invalidBlob := model.Blob{ | ||
BlobID: "", // Invalid empty BlobID | ||
BlobStoragePath: "/path/to/blob", | ||
UploadTime: time.Now(), | ||
UserID: "invalid-uuid", // Invalid UserID | ||
BlobName: "test_blob.txt", | ||
BlobSize: -12345, // Invalid BlobSize (negative) | ||
BlobType: "text", | ||
EncryptionAlgorithm: "AES", | ||
HashAlgorithm: "SHA256", | ||
IsEncrypted: true, | ||
IsSigned: false, | ||
CryptographicKey: model.CryptographicKey{KeyID: uuid.New().String(), KeyType: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: uuid.New().String()}, | ||
KeyID: uuid.New().String(), // Use valid UUID | ||
} | ||
|
||
// Validate the invalid Blob | ||
err = invalidBlob.Validate() | ||
assert.NotNil(t, err, "Expected validation errors for invalid Blob") | ||
assert.Contains(t, err.Error(), "Field: BlobID, Tag: required") | ||
assert.Contains(t, err.Error(), "Field: BlobSize, Tag: min") | ||
assert.Contains(t, err.Error(), "Field: UserID, Tag: uuid4") | ||
} | ||
|
||
// TestBlobValidationEdgeCases tests validation edge cases for Blob | ||
func TestBlobValidationEdgeCases(t *testing.T) { | ||
// Test missing BlobName (should fail) | ||
invalidBlob := model.Blob{ | ||
BlobID: uuid.New().String(), // Valid UUID | ||
BlobStoragePath: "/path/to/blob", | ||
UploadTime: time.Now(), | ||
UserID: uuid.New().String(), // Valid UUID | ||
BlobName: "", // Invalid empty BlobName | ||
BlobSize: 12345, | ||
BlobType: "text", | ||
EncryptionAlgorithm: "AES", | ||
HashAlgorithm: "SHA256", | ||
IsEncrypted: true, | ||
IsSigned: false, | ||
CryptographicKey: model.CryptographicKey{KeyID: uuid.New().String(), KeyType: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: uuid.New().String()}, | ||
KeyID: uuid.New().String(), | ||
} | ||
|
||
err := invalidBlob.Validate() | ||
assert.NotNil(t, err, "Expected validation error for missing BlobName") | ||
assert.Contains(t, err.Error(), "Field: BlobName, Tag: required") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package model | ||
|
||
import ( | ||
"crypto_vault_service/internal/domain/model" | ||
"testing" | ||
"time" | ||
|
||
"github.com/google/uuid" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
// TestCryptographicKeyValidation tests the Validator method for CryptographicKey | ||
func TestCryptographicKeyValidation(t *testing.T) { | ||
// Valid CryptographicKey | ||
validKey := model.CryptographicKey{ | ||
KeyID: uuid.New().String(), // Valid UUID | ||
KeyType: "AES", // Valid KeyType | ||
CreatedAt: time.Now(), | ||
ExpiresAt: time.Now().Add(time.Hour * 24), // Valid ExpiresAt | ||
UserID: uuid.New().String(), // Valid UserID | ||
} | ||
|
||
// Validate the valid CryptographicKey | ||
err := validKey.Validate() | ||
assert.Nil(t, err, "Expected no validation errors for valid CryptographicKey") | ||
|
||
// Invalid CryptographicKey (empty KeyID, invalid KeyType, expired) | ||
invalidKey := model.CryptographicKey{ | ||
KeyID: "", // Invalid empty KeyID | ||
KeyType: "InvalidType", // Invalid KeyType | ||
CreatedAt: time.Now(), | ||
ExpiresAt: time.Now().Add(-time.Hour * 24), // Invalid ExpiresAt (before CreatedAt) | ||
UserID: "invalid-user-id", // Invalid UserID | ||
} | ||
|
||
// Validate the invalid CryptographicKey | ||
err = invalidKey.Validate() | ||
assert.NotNil(t, err, "Expected validation errors for invalid CryptographicKey") | ||
assert.Contains(t, err.Error(), "Field: KeyID, Tag: required") | ||
assert.Contains(t, err.Error(), "Field: KeyType, Tag: oneof") | ||
assert.Contains(t, err.Error(), "Field: ExpiresAt, Tag: gtefield") | ||
} | ||
|
||
// TestCryptographicKeyValidations tests the validation edge cases for CryptographicKey | ||
func TestCryptographicKeyValidations(t *testing.T) { | ||
// Test missing UserID (should fail) | ||
invalidKey := model.CryptographicKey{ | ||
KeyID: uuid.New().String(), // Valid UUID | ||
KeyType: "AES", // Valid KeyType | ||
CreatedAt: time.Now(), | ||
ExpiresAt: time.Now().Add(time.Hour * 24), // Valid ExpiresAt | ||
UserID: "", // Invalid empty UserID | ||
} | ||
|
||
err := invalidKey.Validate() | ||
assert.NotNil(t, err, "Expected validation error for missing UserID") | ||
assert.Contains(t, err.Error(), "Field: UserID, Tag: required") | ||
} |