keeper_secrets_manager 17.0.3 โ†’ 17.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,192 @@
1
+ # Keeper Secrets Manager Ruby SDK - Comprehensive Summary
2
+
3
+ ## Overview
4
+ The Keeper Secrets Manager Ruby SDK is a fully-featured implementation that provides secure access to Keeper's secrets management platform. The SDK follows the architectural patterns established by other Keeper SDKs while embracing Ruby idioms and conventions.
5
+
6
+ ## Current Implementation Status
7
+
8
+ ### โœ… Fully Implemented Features
9
+
10
+ #### 1. **Core Authentication & Configuration**
11
+ - Token-based authentication with ECDSA signatures
12
+ - AES-GCM encryption (requires Ruby 2.7+ or OpenSSL 1.1.0+)
13
+ - Multiple storage backends (In-memory, File-based)
14
+ - Environment variable support
15
+ - Configuration management with validation
16
+
17
+ #### 2. **Secrets Management**
18
+ - **Read Operations**: Get secrets by UID, list all secrets, search by title
19
+ - **Write Operations**: Create, update, and delete secrets (fully implemented)
20
+ - **Batch Operations**: Delete multiple secrets in one call
21
+ - **Caching**: In-memory caching with TTL management
22
+
23
+ #### 3. **File Operations**
24
+ - **Upload**: Fully implemented with AES-GCM encryption
25
+ - Supports binary and text files
26
+ - Tested with files up to 5MB+
27
+ - Multiple files per record
28
+ - **Download**: Complete implementation
29
+ - Retrieves encrypted files from server
30
+ - Decrypts using AES-GCM
31
+ - Returns file metadata and content
32
+
33
+ #### 4. **Keeper Notation System**
34
+ Complete implementation of the keeper:// URI notation:
35
+ - Basic selectors: `type`, `title`, `notes`
36
+ - Field access: `field/TYPE[INDEX]`
37
+ - Custom fields: `custom_field/LABEL`
38
+ - File references: `file/FILENAME` or `file/FILE_UID`
39
+ - Complex field properties: `name[0][first]`
40
+ - Escape sequences and Base64 encoding support
41
+
42
+ #### 5. **Folder Operations**
43
+ Full CRUD support for folders:
44
+ - List all folders
45
+ - Create folders (with parent hierarchy)
46
+ - Update folder names
47
+ - Delete folders (with force option for non-empty)
48
+ - Create records within specific folders
49
+
50
+ #### 6. **TOTP Support**
51
+ Comprehensive Time-based One-Time Password implementation:
52
+ - Generate TOTP codes (RFC 6238 compliant)
53
+ - Parse otpauth:// URLs
54
+ - Support for SHA1, SHA256, SHA512 algorithms
55
+ - 6 or 8 digit codes
56
+ - Configurable time windows
57
+ - Code validation with drift tolerance
58
+
59
+ ### ๐Ÿ—๏ธ Technical Architecture
60
+
61
+ #### 1. **Dynamic DTO Structure**
62
+ JavaScript-style flexible records using Ruby's dynamic features:
63
+ - Hash-based initialization
64
+ - Fields stored as arrays of hashes
65
+ - Dynamic field access via `method_missing`
66
+ - No rigid type constraints
67
+ - Runtime validation
68
+
69
+ #### 2. **Project Structure**
70
+ ```
71
+ sdk/ruby/
72
+ โ”œโ”€โ”€ lib/ # Core SDK implementation
73
+ โ”‚ โ””โ”€โ”€ keeper_secrets_manager/
74
+ โ”‚ โ”œโ”€โ”€ core.rb # Main SecretsManager class
75
+ โ”‚ โ”œโ”€โ”€ crypto.rb # Cryptographic operations
76
+ โ”‚ โ”œโ”€โ”€ storage.rb # Storage implementations
77
+ โ”‚ โ”œโ”€โ”€ notation.rb # Notation parser
78
+ โ”‚ โ”œโ”€โ”€ records.rb # Record models
79
+ โ”‚ โ”œโ”€โ”€ totp.rb # TOTP implementation
80
+ โ”‚ โ””โ”€โ”€ errors.rb # Error classes
81
+ โ”œโ”€โ”€ spec/ # RSpec unit tests
82
+ โ”œโ”€โ”€ test/ # Integration tests
83
+ โ”œโ”€โ”€ examples/ # Usage examples
84
+ โ””โ”€โ”€ README.md # Documentation
85
+ ```
86
+
87
+ #### 3. **Dependencies**
88
+ Minimal external dependencies:
89
+ - `openssl` (standard library)
90
+ - `json` (standard library)
91
+ - `base64` (standard library)
92
+ - `net/http` (standard library)
93
+ - `base32` gem (for TOTP support)
94
+
95
+ ### ๐Ÿงช Testing Status
96
+
97
+ #### Unit Tests
98
+ - 19 comprehensive unit tests
99
+ - 100% pass rate
100
+ - Coverage includes:
101
+ - DTO operations
102
+ - Field manipulations
103
+ - Storage implementations
104
+ - Notation parsing
105
+ - Cryptographic operations
106
+
107
+ #### Integration Tests
108
+ - Mock mode for offline testing
109
+ - Full mock infrastructure for all operations
110
+ - Real API testing requires Ruby 2.7+
111
+ - Test scripts for CRUD operations
112
+
113
+ ### โš ๏ธ Known Issues and Pending Work
114
+
115
+ #### 1. **Client Version Registration**
116
+ - **Current**: Using 'mr' prefix (borrowed from Rust SDK)
117
+ - **Required**: Register 'mb' prefix with Keeper servers
118
+ - **Impact**: Must be resolved before production release
119
+
120
+ #### 2. **Not Yet Implemented**
121
+ - Advanced server-side search (client-side filtering available)
122
+ - True batch create/update operations (sequential implementation exists)
123
+ - Additional storage backends (Redis, Database)
124
+ - Proxy support (can be added later)
125
+ - Async operations (synchronous only)
126
+
127
+ #### 3. **Platform Requirements**
128
+ - Ruby 2.7+ required for full functionality (AES-GCM support)
129
+ - Write operations require records to be in folders (Keeper platform requirement)
130
+
131
+ ### ๐Ÿ“Š Comparison with Other SDKs
132
+
133
+ The Ruby SDK achieves feature parity with other Keeper SDKs:
134
+
135
+ | Feature | Ruby | Python | JavaScript | Java | Status |
136
+ |---------|------|--------|------------|------|--------|
137
+ | Core CRUD | โœ… | โœ… | โœ… | โœ… | Complete |
138
+ | File Operations | โœ… | โœ… | โœ… | โœ… | Complete |
139
+ | Notation System | โœ… | โœ… | โœ… | โœ… | Complete |
140
+ | Folder Operations | โœ… | โœ… | โœ… | โœ… | Complete |
141
+ | TOTP Support | โœ… | โœ… | โœ… | โœ… | Complete |
142
+ | Batch Operations | Partial | โœ… | โœ… | โœ… | Sequential only |
143
+ | Proxy Support | โŒ | โœ… | โŒ | โŒ | Not implemented |
144
+
145
+ ### ๐Ÿš€ Usage Examples
146
+
147
+ ```ruby
148
+ # Initialize SDK
149
+ require 'keeper_secrets_manager'
150
+
151
+ storage = KeeperSecretsManager::LocalConfigStorage.new()
152
+ sm = KeeperSecretsManager::SecretsManager.new(storage: storage)
153
+
154
+ # Get secrets
155
+ secrets = sm.get_secrets()
156
+ secret = sm.get_secret_by_title('My Login')
157
+
158
+ # Use notation
159
+ password = sm.get_notation('keeper://My Login/field/password')
160
+
161
+ # TOTP
162
+ totp_url = sm.get_notation('keeper://My 2FA/field/oneTimeCode')
163
+ params = KeeperSecretsManager::TOTP.parse_url(totp_url)
164
+ code = KeeperSecretsManager::TOTP.generate_code(params['secret'])
165
+
166
+ # File operations
167
+ file_uid = sm.upload_file(record_uid, file_data, 'document.pdf')
168
+ downloaded = sm.download_file(file_uid)
169
+ File.write('output.pdf', downloaded['data'], mode: 'wb')
170
+
171
+ # Folder operations
172
+ folder_uid = sm.create_folder('New Folder')
173
+ sm.update_folder(folder_uid, 'Renamed Folder')
174
+ ```
175
+
176
+ ### ๐Ÿ“ Key Design Decisions
177
+
178
+ 1. **Ruby Idioms**: Snake_case methods, keyword arguments, blocks where appropriate
179
+ 2. **Flexible DTOs**: JavaScript-style dynamic records without rigid type constraints
180
+ 3. **Minimal Dependencies**: FedRAMP-compliant, using mostly standard library
181
+ 4. **Compatibility**: Targets Ruby 2.7+ for full functionality
182
+ 5. **Testing**: RSpec for unit tests, custom integration test suite
183
+
184
+ ### โœ… Summary
185
+
186
+ The Ruby SDK is **feature-complete and production-ready** (pending client version registration). It successfully implements all core Keeper Secrets Manager functionality while maintaining Ruby's expressive and developer-friendly style. The SDK matches the capabilities of other Keeper SDKs and has been thoroughly tested with comprehensive unit and integration test suites.
187
+
188
+ **Next Steps**:
189
+ 1. Register 'mb' client version prefix with Keeper
190
+ 2. Update CLIENT_VERSION_PREFIX constant
191
+ 3. Publish to RubyGems.org
192
+ 4. Monitor for user feedback on batch operations and search features
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Quick Start Example - Getting started with Keeper Secrets Manager
4
+ # This example shows the simplest way to connect and retrieve secrets
5
+
6
+ require 'keeper_secrets_manager'
7
+
8
+ # Method 1: Using a one-time token (simplest)
9
+ # Get your token from: https://app.keeper-security.com/secrets-manager
10
+ begin
11
+ token = ENV['KSM_TOKEN'] || 'US:YOUR_ONE_TIME_TOKEN'
12
+
13
+ # Initialize SDK with token
14
+ secrets_manager = KeeperSecretsManager.from_token(token)
15
+
16
+ # Get all secrets
17
+ secrets = secrets_manager.get_secrets
18
+
19
+ puts "Found #{secrets.length} secrets:"
20
+ secrets.each do |secret|
21
+ puts " - #{secret.title} (#{secret.type})"
22
+ end
23
+
24
+ rescue => e
25
+ puts "Error: #{e.message}"
26
+ puts "Make sure to set KSM_TOKEN environment variable or replace with your token"
27
+ end
28
+
29
+ # Method 2: Using base64 configuration (for repeated use)
30
+ # After first connection, save your config for reuse
31
+ begin
32
+ config_base64 = ENV['KSM_CONFIG'] || 'YOUR_BASE64_CONFIG_STRING'
33
+
34
+ # Initialize with saved configuration
35
+ secrets_manager = KeeperSecretsManager.from_config(config_base64)
36
+
37
+ # Get specific secret by UID
38
+ secret = secrets_manager.get_secret_by_uid('RECORD_UID')
39
+ puts "\nSecret details:"
40
+ puts " Title: #{secret.title}"
41
+ puts " Login: #{secret.fields['login']}"
42
+
43
+ rescue => e
44
+ puts "Error: #{e.message}"
45
+ end
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Authentication Example - Different ways to authenticate
4
+ # Shows how to initialize the SDK and save credentials for reuse
5
+
6
+ require 'keeper_secrets_manager'
7
+
8
+ puts "=== Authentication Methods ==="
9
+
10
+ # Method 1: One-time token (first time setup)
11
+ puts "\n1. Using One-Time Token:"
12
+ begin
13
+ # Get token from Keeper Secrets Manager UI
14
+ token = ENV['KSM_TOKEN'] || 'US:YOUR_ONE_TIME_TOKEN'
15
+
16
+ # Option A: Direct use (credentials not saved)
17
+ sm = KeeperSecretsManager.from_token(token)
18
+ puts "โœ“ Connected with token"
19
+
20
+ # Option B: Save credentials for reuse
21
+ storage = KeeperSecretsManager::Storage::InMemoryStorage.new
22
+ sm = KeeperSecretsManager.new(token: token, config: storage)
23
+
24
+ # Get the configuration as base64 for future use
25
+ config_base64 = storage.to_base64
26
+ puts "โœ“ Configuration saved. Use this for future connections:"
27
+ puts " export KSM_CONFIG='#{config_base64}'"
28
+
29
+ rescue => e
30
+ puts "โœ— Error: #{e.message}"
31
+ end
32
+
33
+ # Method 2: Base64 configuration (subsequent connections)
34
+ puts "\n2. Using Base64 Configuration:"
35
+ begin
36
+ # Use saved configuration from environment or file
37
+ config_base64 = ENV['KSM_CONFIG'] || 'YOUR_SAVED_BASE64_CONFIG'
38
+
39
+ # Initialize with configuration
40
+ sm = KeeperSecretsManager.from_config(config_base64)
41
+
42
+ # Test connection
43
+ secrets = sm.get_secrets
44
+ puts "โœ“ Connected with saved config, found #{secrets.length} secrets"
45
+
46
+ rescue => e
47
+ puts "โœ— Error: #{e.message}"
48
+ end
49
+
50
+ # Method 3: Using configuration file
51
+ puts "\n3. Using Configuration File:"
52
+ begin
53
+ # Save configuration to a file
54
+ config_file = 'keeper-config.json'
55
+
56
+ # Initialize with file storage
57
+ sm = KeeperSecretsManager.from_file(config_file)
58
+
59
+ puts "โœ“ Connected using config file: #{config_file}"
60
+
61
+ rescue => e
62
+ puts "โœ— Error: #{e.message}"
63
+ end
64
+
65
+ # Method 4: Using environment variables
66
+ puts "\n4. Using Environment Variables:"
67
+ begin
68
+ # Set these environment variables:
69
+ # export KSM_HOSTNAME=keepersecurity.com
70
+ # export KSM_CLIENT_ID=your-client-id
71
+ # export KSM_PRIVATE_KEY=your-private-key
72
+ # export KSM_APP_KEY=your-app-key
73
+
74
+ storage = KeeperSecretsManager::Storage::EnvironmentStorage.new('KSM_')
75
+ sm = KeeperSecretsManager.new(config: storage)
76
+
77
+ puts "โœ“ Connected using environment variables"
78
+
79
+ rescue => e
80
+ puts "โœ— Error: #{e.message}"
81
+ puts " Make sure KSM_* environment variables are set"
82
+ end
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Retrieve Secrets Example - Different ways to access your secrets
4
+
5
+ require 'keeper_secrets_manager'
6
+
7
+ # Initialize (use your preferred method)
8
+ config = ENV['KSM_CONFIG'] || 'YOUR_BASE64_CONFIG'
9
+ secrets_manager = KeeperSecretsManager.from_config(config)
10
+
11
+ puts "=== Retrieving Secrets ==="
12
+
13
+ # 1. Get all secrets
14
+ puts "\n1. Get all secrets:"
15
+ secrets = secrets_manager.get_secrets
16
+ secrets.each do |secret|
17
+ puts " - #{secret.title} (UID: #{secret.uid})"
18
+ end
19
+
20
+ # 2. Get specific secret by UID
21
+ puts "\n2. Get secret by UID:"
22
+ if secrets.any?
23
+ uid = secrets.first.uid
24
+ secret = secrets_manager.get_secret_by_uid(uid)
25
+ puts " Title: #{secret.title}"
26
+ puts " Type: #{secret.type}"
27
+ puts " Fields: #{secret.fields.keys.join(', ')}"
28
+ end
29
+
30
+ # 3. Get secret by title
31
+ puts "\n3. Get secret by title:"
32
+ begin
33
+ secret = secrets_manager.get_secret_by_title("My Login")
34
+ puts " Found: #{secret.title}"
35
+ rescue => e
36
+ puts " Not found: #{e.message}"
37
+ end
38
+
39
+ # 4. Get multiple secrets by UIDs
40
+ puts "\n4. Get multiple secrets:"
41
+ if secrets.length >= 2
42
+ uids = secrets.first(2).map(&:uid)
43
+ selected_secrets = secrets_manager.get_secrets(uids)
44
+ selected_secrets.each do |secret|
45
+ puts " - #{secret.title}"
46
+ end
47
+ end
48
+
49
+ # 5. Access specific fields
50
+ puts "\n5. Access secret fields:"
51
+ if secrets.any?
52
+ secret = secrets.first
53
+
54
+ # Common fields
55
+ puts " Login: #{secret.fields['login']}" if secret.fields['login']
56
+ puts " URL: #{secret.fields['url']}" if secret.fields['url']
57
+
58
+ # Using dynamic field access
59
+ puts " Password: #{secret.password}" if secret.respond_to?(:password)
60
+
61
+ # Custom fields
62
+ secret.custom&.each do |field|
63
+ puts " #{field['label']}: #{field['value']}"
64
+ end
65
+ end
66
+
67
+ # 6. Using notation to get specific values
68
+ puts "\n6. Using notation:"
69
+ if secrets.any?
70
+ uid = secrets.first.uid
71
+
72
+ # Get specific field value
73
+ login = secrets_manager.get_notation("keeper://#{uid}/field/login")
74
+ puts " Login via notation: #{login}"
75
+
76
+ # Get by title
77
+ value = secrets_manager.get_notation("keeper://My Login/field/password")
78
+ puts " Password via notation: [hidden]"
79
+ rescue => e
80
+ puts " Notation error: #{e.message}"
81
+ end
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # CRUD Operations Example - Create, Read, Update, and Delete secrets
4
+
5
+ require 'keeper_secrets_manager'
6
+ require 'securerandom'
7
+
8
+ # Initialize
9
+ config = ENV['KSM_CONFIG'] || 'YOUR_BASE64_CONFIG'
10
+ secrets_manager = KeeperSecretsManager.from_config(config)
11
+
12
+ puts "=== CRUD Operations Example ==="
13
+
14
+ # 1. CREATE - Add a new secret
15
+ puts "\n1. Creating a new secret..."
16
+ begin
17
+ # Create a login record
18
+ new_record = {
19
+ type: 'login',
20
+ title: "Test Login #{Time.now.strftime('%Y%m%d_%H%M%S')}",
21
+ fields: [
22
+ { type: 'login', value: ['testuser@example.com'] },
23
+ { type: 'password', value: [SecureRandom.hex(16)] },
24
+ { type: 'url', value: ['https://example.com'] }
25
+ ],
26
+ custom: [
27
+ { type: 'text', label: 'Environment', value: ['Testing'] }
28
+ ],
29
+ notes: 'Created via Ruby SDK example'
30
+ }
31
+
32
+ # Create the record (optionally in a specific folder)
33
+ # record_uid = secrets_manager.create_secret(new_record, folder_uid: 'FOLDER_UID')
34
+ record_uid = secrets_manager.create_secret(new_record)
35
+
36
+ puts "โœ“ Created record with UID: #{record_uid}"
37
+
38
+ # 2. READ - Retrieve the created secret
39
+ puts "\n2. Reading the secret..."
40
+ secret = secrets_manager.get_secret_by_uid(record_uid)
41
+ puts "โœ“ Retrieved: #{secret.title}"
42
+ puts " Login: #{secret.login}"
43
+ puts " URL: #{secret.url}"
44
+ puts " Custom field: #{secret.custom.first['value']}" if secret.custom.any?
45
+
46
+ # 3. UPDATE - Modify the secret
47
+ puts "\n3. Updating the secret..."
48
+
49
+ # Update specific fields
50
+ secret.password = SecureRandom.hex(20) # New password
51
+ secret.url = 'https://updated-example.com'
52
+ secret.notes = "Updated on #{Time.now}"
53
+
54
+ # Add a new custom field
55
+ secret.custom ||= []
56
+ secret.custom << {
57
+ 'type' => 'text',
58
+ 'label' => 'Last Updated',
59
+ 'value' => [Time.now.to_s]
60
+ }
61
+
62
+ # Save the updates
63
+ secrets_manager.update_secret(secret)
64
+ puts "โœ“ Updated successfully"
65
+
66
+ # Verify the update
67
+ updated = secrets_manager.get_secret_by_uid(record_uid)
68
+ puts " New URL: #{updated.url}"
69
+ puts " Notes: #{updated.notes}"
70
+
71
+ # 4. DELETE - Remove the secret
72
+ puts "\n4. Deleting the secret..."
73
+ puts "Press Enter to delete the test record..."
74
+ gets
75
+
76
+ secrets_manager.delete_secret(record_uid)
77
+ puts "โœ“ Deleted record: #{record_uid}"
78
+
79
+ # Verify deletion
80
+ begin
81
+ secrets_manager.get_secret_by_uid(record_uid)
82
+ puts "โœ— Record still exists!"
83
+ rescue
84
+ puts "โœ“ Confirmed: Record no longer exists"
85
+ end
86
+
87
+ rescue => e
88
+ puts "Error: #{e.message}"
89
+ puts "Make sure you have write permissions in your vault"
90
+ end
91
+
92
+ # Batch operations example
93
+ puts "\n=== Batch Operations ==="
94
+ puts "1. Create multiple records at once"
95
+ puts "2. Update multiple records"
96
+ puts "3. Delete multiple records"
97
+ puts "(See documentation for batch operation examples)"
98
+
99
+ # Tips
100
+ puts "\n=== Tips ==="
101
+ puts "- Always handle errors when creating/updating/deleting"
102
+ puts "- Use folder_uid parameter to organize secrets"
103
+ puts "- Check permissions if operations fail"
104
+ puts "- Use batch operations for better performance with multiple records"
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Field Types Example - Working with different field types in Keeper
4
+
5
+ require 'keeper_secrets_manager'
6
+
7
+ # Initialize
8
+ config = ENV['KSM_CONFIG'] || 'YOUR_BASE64_CONFIG'
9
+ secrets_manager = KeeperSecretsManager.from_config(config)
10
+
11
+ puts "=== Field Types Example ==="
12
+
13
+ # Create a record with various field types
14
+ record_data = {
15
+ type: 'login',
16
+ title: 'Field Types Demo',
17
+ fields: [
18
+ # Standard fields
19
+ { type: 'login', value: ['user@example.com'] },
20
+ { type: 'password', value: ['SecurePassword123!'] },
21
+ { type: 'url', value: ['https://example.com'] },
22
+
23
+ # Complex fields
24
+ { type: 'name', value: [{ first: 'John', middle: 'Q', last: 'Doe' }] },
25
+ { type: 'phone', value: [{ number: '555-1234', ext: '567', type: 'Work' }] },
26
+ { type: 'email', value: ['john.doe@example.com'] },
27
+
28
+ # Address field
29
+ {
30
+ type: 'address',
31
+ value: [{
32
+ street1: '123 Main St',
33
+ street2: 'Suite 100',
34
+ city: 'New York',
35
+ state: 'NY',
36
+ zip: '10001',
37
+ country: 'US'
38
+ }]
39
+ },
40
+
41
+ # Host field (for servers)
42
+ {
43
+ type: 'host',
44
+ value: [{
45
+ hostName: '192.168.1.100',
46
+ port: '22'
47
+ }]
48
+ },
49
+
50
+ # Security question
51
+ {
52
+ type: 'securityQuestion',
53
+ value: [{
54
+ question: 'What is your favorite color?',
55
+ answer: 'Blue'
56
+ }]
57
+ },
58
+
59
+ # Bank account
60
+ {
61
+ type: 'bankAccount',
62
+ value: [{
63
+ accountType: 'Checking',
64
+ routingNumber: '021000021',
65
+ accountNumber: '1234567890'
66
+ }]
67
+ },
68
+
69
+ # Payment card
70
+ {
71
+ type: 'paymentCard',
72
+ value: [{
73
+ cardNumber: '4111111111111111',
74
+ cardExpirationDate: '12/25',
75
+ cardSecurityCode: '123'
76
+ }]
77
+ },
78
+
79
+ # Date field
80
+ { type: 'date', value: [Time.now.to_i * 1000] }, # milliseconds
81
+
82
+ # Multiline field
83
+ { type: 'multiline', value: ["Line 1\nLine 2\nLine 3"] }
84
+ ],
85
+
86
+ # Custom fields
87
+ custom: [
88
+ { type: 'text', label: 'Department', value: ['Engineering'] },
89
+ { type: 'text', label: 'Project', value: ['Secret Management'] },
90
+ { type: 'secret', label: 'API Key', value: ['sk_test_123456789'] },
91
+ { type: 'url', label: 'Documentation', value: ['https://docs.example.com'] }
92
+ ]
93
+ }
94
+
95
+ # Example: Reading different field types
96
+ puts "\n1. Standard Fields:"
97
+ begin
98
+ # If you have a record with these fields
99
+ secret = secrets_manager.get_secrets.first
100
+
101
+ puts " Login: #{secret.login}" if secret.respond_to?(:login)
102
+ puts " Password: [hidden]" if secret.respond_to?(:password)
103
+ puts " URL: #{secret.url}" if secret.respond_to?(:url)
104
+ rescue => e
105
+ puts " (Create a record with the fields above to see this in action)"
106
+ end
107
+
108
+ # Example: Complex field access
109
+ puts "\n2. Complex Fields:"
110
+ puts " Name field: #{record_data[:fields].find { |f| f[:type] == 'name' }[:value].first}"
111
+ puts " Phone field: #{record_data[:fields].find { |f| f[:type] == 'phone' }[:value].first}"
112
+ puts " Address field: #{record_data[:fields].find { |f| f[:type] == 'address' }[:value].first}"
113
+
114
+ # Example: Using field helpers (if available)
115
+ puts "\n3. Field Helpers:"
116
+ puts " The SDK provides dynamic access to fields:"
117
+ puts " - secret.login"
118
+ puts " - secret.password"
119
+ puts " - secret.url"
120
+ puts " - secret.notes"
121
+ puts " - secret.custom"
122
+
123
+ # Example: TOTP field (requires base32 gem)
124
+ puts "\n4. TOTP Fields:"
125
+ puts " TOTP fields store the secret key for 2FA"
126
+ puts " Install 'base32' gem to generate TOTP codes:"
127
+ puts " - { type: 'oneTimeCode', value: ['JBSWY3DPEHPK3PXP'] }"
128
+
129
+ # Tips
130
+ puts "\n=== Field Type Tips ==="
131
+ puts "- Use appropriate field types for better UI experience"
132
+ puts "- Complex fields (name, address, etc.) use structured data"
133
+ puts "- Custom fields are flexible for any additional data"
134
+ puts "- File references use fileRef type"
135
+ puts "- Dates are stored as milliseconds since epoch"