diff --git a/docs/man/_index.md b/docs/man/_index.md index 01c439fd..93ec4f79 100644 --- a/docs/man/_index.md +++ b/docs/man/_index.md @@ -45,5 +45,5 @@ command: - keyring - in-memory - file - default: keyring + default: file --- diff --git a/otdfctl-source.zip b/otdfctl-source.zip new file mode 100644 index 00000000..6554ae36 Binary files /dev/null and b/otdfctl-source.zip differ diff --git a/pkg/profiles/profileConfig.go b/pkg/profiles/profileConfig.go index 1c5eac5d..525ac7b5 100644 --- a/pkg/profiles/profileConfig.go +++ b/pkg/profiles/profileConfig.go @@ -47,8 +47,8 @@ func NewProfileStore(newStore NewStoreInterface, profileName string, endpoint st Endpoint: u.String(), TlsNoVerify: tlsNoVerify, Attributes: make(map[string]interface{}), // Empty map for flexible attributes - CreatedAt: time.Now(), // Set creation time - UpdatedAt: time.Now(), // Set initial update time + CreatedAt: time.Now().UTC(), // Set creation time + UpdatedAt: time.Now().UTC(), // Set initial update time Version: URNNamespaceTemplate, // Set profile version to URN-based namespace template }, } @@ -74,7 +74,7 @@ func (p *ProfileStore) Get() error { // Save saves the current profile configuration to storage and updates UpdatedAt timestamp func (p *ProfileStore) Save() error { - p.config.UpdatedAt = time.Now() + p.config.UpdatedAt = time.Now().UTC() return p.store.Set(p.config) } diff --git a/pkg/profiles/storeFile.go b/pkg/profiles/storeFile.go index acb7095c..e88d5feb 100644 --- a/pkg/profiles/storeFile.go +++ b/pkg/profiles/storeFile.go @@ -12,6 +12,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "time" "github.com/zalando/go-keyring" @@ -32,8 +33,8 @@ type FileMetadata struct { } // Generates a safe, hashed filename from namespace and key -func hashNamespaceAndKey(namespace, key string) string { - hash := sha256.Sum256([]byte(namespace + "_" + key)) +func hashNamespaceAndKey(namespace string, key string) string { + hash := sha256.Sum256([]byte(namespace + ":" + key)) return hex.EncodeToString(hash[:]) } @@ -67,8 +68,9 @@ var NewFileStore NewStoreInterface = func(namespace string, key string) StoreInt panic(fmt.Sprintf("unable to delete temp file in profiles directory %s: please ensure delete permissions are granted", baseDir)) } - // Generate the filename from namespace and key, hashed for uniqueness - fileName := hashNamespaceAndKey(namespace, key) + // Generate the filename hashed for uniqueness + // Note: other stores use the config.AppName, but want to rely on something more resilient like the namespace + fileName := hashNamespaceAndKey(URNNamespaceTemplate, key) filePath := filepath.Join(baseDir, fileName+".enc") return &FileStore{ @@ -137,7 +139,8 @@ func (f *FileStore) Delete() error { return err } - metadataFilePath := f.filePath + ".nfo" + // Remove the extension from filePath and add .nfo for the metadata file + metadataFilePath := strings.TrimSuffix(f.filePath, filepath.Ext(f.filePath)) + ".nfo" return os.Remove(metadataFilePath) } @@ -184,7 +187,12 @@ func encryptData(key, data []byte) ([]byte, error) { return nil, err } - return aesGCM.Seal(nonce, nonce, data, nil), nil + // Encrypt the data with a separate destination buffer + ciphertext := aesGCM.Seal(nil, nonce, data, nil) + + // Prepend the nonce to the ciphertext + result := append(nonce, ciphertext...) + return result, nil } // decryptData decrypts data using AES-GCM @@ -222,13 +230,13 @@ func (f *FileStore) SaveMetadata(profileName string) error { return err } - metadataFilePath := f.filePath + ".nfo" + metadataFilePath := strings.TrimSuffix(f.filePath, filepath.Ext(f.filePath)) + ".nfo" return os.WriteFile(metadataFilePath, data, 0600) } // LoadMetadata loads and parses metadata from a .nfo file func (f *FileStore) LoadMetadata() (*FileMetadata, error) { - metadataFilePath := f.filePath + ".nfo" + metadataFilePath := strings.TrimSuffix(f.filePath, filepath.Ext(f.filePath)) + ".nfo" data, err := os.ReadFile(metadataFilePath) if err != nil { return nil, err diff --git a/profiles/28856c51db8aa53701d8f4d56c6717d45db7589900cded46a03519223b5ae337.enc b/profiles/28856c51db8aa53701d8f4d56c6717d45db7589900cded46a03519223b5ae337.enc new file mode 100644 index 00000000..eeff6611 --- /dev/null +++ b/profiles/28856c51db8aa53701d8f4d56c6717d45db7589900cded46a03519223b5ae337.enc @@ -0,0 +1 @@ +6ÖîR6™JhÉÔ´fNG²V+õ䉄ÎñOngßóX/æ¶||°ÐKÊ#œ¸µx <—.›ì‡ÎùɵÞãn˜âÏÊòÈCÍέ-ý}éP rVX \ No newline at end of file diff --git a/profiles/28856c51db8aa53701d8f4d56c6717d45db7589900cded46a03519223b5ae337.nfo b/profiles/28856c51db8aa53701d8f4d56c6717d45db7589900cded46a03519223b5ae337.nfo new file mode 100644 index 00000000..a78cc69b --- /dev/null +++ b/profiles/28856c51db8aa53701d8f4d56c6717d45db7589900cded46a03519223b5ae337.nfo @@ -0,0 +1,6 @@ +{ + "profile_name": "global", + "created_at": "2024-11-10T13:43:20-05:00", + "encryption_alg": "AES-256-GCM", + "version": "urn:opentdf:otdfctl:profile:v1" +} \ No newline at end of file diff --git a/profiles/68a82505269f56ac68f350b94eb58d2e3150c18cf2684a8a00a7d8b65b203eef.enc b/profiles/68a82505269f56ac68f350b94eb58d2e3150c18cf2684a8a00a7d8b65b203eef.enc new file mode 100644 index 00000000..8aad530b Binary files /dev/null and b/profiles/68a82505269f56ac68f350b94eb58d2e3150c18cf2684a8a00a7d8b65b203eef.enc differ diff --git a/profiles/68a82505269f56ac68f350b94eb58d2e3150c18cf2684a8a00a7d8b65b203eef.nfo b/profiles/68a82505269f56ac68f350b94eb58d2e3150c18cf2684a8a00a7d8b65b203eef.nfo new file mode 100644 index 00000000..f716649a --- /dev/null +++ b/profiles/68a82505269f56ac68f350b94eb58d2e3150c18cf2684a8a00a7d8b65b203eef.nfo @@ -0,0 +1,6 @@ +{ + "profile_name": "profile-test", + "created_at": "2024-11-10T13:44:18-05:00", + "encryption_alg": "AES-256-GCM", + "version": "urn:opentdf:otdfctl:profile:v1" +} \ No newline at end of file