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.
@@ -1,109 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require_relative '../lib/keeper_secrets_manager'
4
-
5
- # This example demonstrates folder hierarchy functionality in the Ruby SDK
6
-
7
- begin
8
- # Initialize client (assumes KSM_CONFIG environment variable is set)
9
- client = KeeperSecretsManager.new
10
-
11
- puts "=== Folder Hierarchy Demo ==="
12
- puts ""
13
-
14
- # Get all folders
15
- folders = client.get_folders
16
- puts "Found #{folders.length} folders"
17
- puts ""
18
-
19
- # Get folder manager for advanced operations
20
- fm = client.folder_manager
21
-
22
- # Build and display folder tree
23
- puts "Folder Tree Structure:"
24
- puts "-" * 40
25
- fm.print_tree
26
- puts ""
27
-
28
- # Demonstrate path retrieval
29
- if folders.any?
30
- first_folder = folders.first
31
- path = client.get_folder_path(first_folder.uid)
32
- puts "Path to '#{first_folder.name}': #{path}"
33
-
34
- # Show ancestors
35
- ancestors = fm.get_ancestors(first_folder.uid)
36
- if ancestors.any?
37
- puts "Ancestors of '#{first_folder.name}':"
38
- ancestors.each { |a| puts " - #{a.name}" }
39
- else
40
- puts "No ancestors (root folder or orphan)"
41
- end
42
-
43
- # Show descendants
44
- descendants = fm.get_descendants(first_folder.uid)
45
- if descendants.any?
46
- puts "Descendants of '#{first_folder.name}':"
47
- descendants.each { |d| puts " - #{d.name}" }
48
- else
49
- puts "No descendants (leaf folder)"
50
- end
51
- end
52
-
53
- puts ""
54
-
55
- # Find folder by name
56
- puts "Searching for folders:"
57
- puts "-" * 40
58
-
59
- # Example: Find a folder named "Personal"
60
- personal = client.find_folder_by_name("Personal")
61
- if personal
62
- puts "Found folder 'Personal' with UID: #{personal.uid}"
63
- puts "Path: #{client.get_folder_path(personal.uid)}"
64
- else
65
- puts "No folder named 'Personal' found"
66
- end
67
-
68
- # Get all records organized by folder
69
- puts ""
70
- puts "Records by Folder:"
71
- puts "-" * 40
72
-
73
- response = client.get_secrets
74
-
75
- # Group records by folder
76
- records_by_folder = {}
77
- root_records = []
78
-
79
- response.records.each do |record|
80
- if record.folder_uid && !record.folder_uid.empty?
81
- records_by_folder[record.folder_uid] ||= []
82
- records_by_folder[record.folder_uid] << record
83
- else
84
- root_records << record
85
- end
86
- end
87
-
88
- # Display root records
89
- if root_records.any?
90
- puts "Root Records (no folder):"
91
- root_records.each { |r| puts " - #{r.title}" }
92
- puts ""
93
- end
94
-
95
- # Display records in each folder
96
- folders.each do |folder|
97
- folder_records = records_by_folder[folder.uid]
98
- if folder_records && folder_records.any?
99
- path = client.get_folder_path(folder.uid)
100
- puts "Records in '#{path}':"
101
- folder_records.each { |r| puts " - #{r.title}" }
102
- puts ""
103
- end
104
- end
105
-
106
- rescue => e
107
- puts "Error: #{e.message}"
108
- puts e.backtrace.first(5).join("\n")
109
- end
@@ -1,176 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'keeper_secrets_manager'
4
- require 'base64'
5
- require 'json'
6
-
7
- puts "=== Keeper Secrets Manager Ruby SDK Full Demo ==="
8
- puts "This demonstrates all working features of the Ruby SDK"
9
- puts "=" * 60
10
-
11
- # Load configuration
12
- config_file = File.join(File.dirname(__FILE__), '..', 'config.base64')
13
- unless File.exist?(config_file)
14
- puts "ERROR: config.base64 not found"
15
- exit 1
16
- end
17
-
18
- config_base64 = File.read(config_file).strip
19
- config_json = Base64.decode64(config_base64)
20
- config_data = JSON.parse(config_json)
21
-
22
- # Initialize SDK
23
- storage = KeeperSecretsManager::Storage::InMemoryStorage.new(config_data)
24
- secrets_manager = KeeperSecretsManager.new(config: storage)
25
-
26
- # 1. Authentication Test
27
- puts "\n1. AUTHENTICATION"
28
- puts " ✅ Successfully authenticated with Keeper servers"
29
- puts " ✅ Using ECDSA signatures"
30
- puts " ✅ AES-GCM encryption active"
31
-
32
- # 2. List existing records
33
- puts "\n2. READING RECORDS"
34
- records = secrets_manager.get_secrets
35
- puts " Found #{records.length} Secrets Manager compatible record(s)"
36
-
37
- if records.any?
38
- records.each_with_index do |record, i|
39
- puts "\n Record ##{i + 1}:"
40
- puts " - Title: #{record.title}"
41
- puts " - UID: #{record.uid}"
42
- puts " - Type: #{record.type}"
43
- end
44
- end
45
-
46
- # 3. List folders
47
- puts "\n3. LISTING FOLDERS"
48
- folders = secrets_manager.get_folders
49
- puts " Found #{folders.length} folder(s)"
50
-
51
- if folders.any?
52
- puts "\n Available folders:"
53
- folders.first(5).each do |folder|
54
- puts " - #{folder.name} (#{folder.uid})"
55
- end
56
- puts " ... and #{folders.length - 5} more" if folders.length > 5
57
- end
58
-
59
- # 4. Create a test record
60
- puts "\n4. CREATING RECORDS"
61
- target_folder = folders.find { |f| f.uid == 'khq76ez6vkTRj3MqUiEGRg' }
62
-
63
- if target_folder
64
- puts " Using folder: #{target_folder.name}"
65
-
66
- test_record = {
67
- 'type' => 'login',
68
- 'title' => "Ruby SDK Demo #{Time.now.strftime('%Y-%m-%d %H:%M')}",
69
- 'fields' => [
70
- { 'type' => 'login', 'value' => ['demo@example.com'] },
71
- { 'type' => 'password', 'value' => ['DemoPass123!'] },
72
- { 'type' => 'url', 'value' => ['https://example.com'] },
73
- { 'type' => 'text', 'label' => 'Custom Field', 'value' => ['Custom Value'] }
74
- ],
75
- 'notes' => "Created by Ruby SDK demo at #{Time.now}",
76
- 'custom' => [
77
- { 'type' => 'text', 'label' => 'Environment', 'value' => ['Production'] },
78
- { 'type' => 'text', 'label' => 'API Key', 'value' => ['demo-api-key-123'] }
79
- ]
80
- }
81
-
82
- options = KeeperSecretsManager::Dto::CreateOptions.new
83
- options.folder_uid = target_folder.uid
84
-
85
- begin
86
- record_uid = secrets_manager.create_secret(test_record, options)
87
- puts " ✅ Successfully created record: #{record_uid}"
88
-
89
- # 5. Notation examples
90
- puts "\n5. KEEPER NOTATION"
91
-
92
- # Try with existing records
93
- if records.any?
94
- first_record = records.first
95
- puts " Testing with existing record: #{first_record.title}"
96
-
97
- title = secrets_manager.get_notation("keeper://#{first_record.uid}/title")
98
- puts " ✅ Title via notation: #{title}"
99
-
100
- type = secrets_manager.get_notation("keeper://#{first_record.uid}/type")
101
- puts " ✅ Type via notation: #{type}"
102
- else
103
- puts " ⚠️ No existing records to test notation with"
104
- end
105
-
106
- rescue => e
107
- puts " ❌ Error creating record: #{e.message}"
108
- end
109
- else
110
- puts " ❌ Target folder not found"
111
- end
112
-
113
- # 6. Dynamic field access
114
- puts "\n6. DYNAMIC FIELD ACCESS (JavaScript-style)"
115
- if records.any?
116
- record = records.first
117
- puts " Record: #{record.title}"
118
-
119
- # Try common field accessors
120
- if record.respond_to?(:login)
121
- puts " ✅ record.login = #{record.login}"
122
- end
123
-
124
- if record.respond_to?(:password)
125
- puts " ✅ record.password = [hidden]"
126
- end
127
-
128
- if record.respond_to?(:url)
129
- puts " ✅ record.url = #{record.url}"
130
- end
131
-
132
- # Custom fields
133
- puts " ✅ Dynamic field access via method_missing"
134
- else
135
- puts " Creating example record to demonstrate..."
136
- example = KeeperSecretsManager::Dto::KeeperRecord.new(
137
- 'title' => 'Example Record',
138
- 'fields' => [
139
- { 'type' => 'login', 'value' => ['user@example.com'] },
140
- { 'type' => 'password', 'value' => ['secret123'] }
141
- ]
142
- )
143
-
144
- puts " ✅ example.login = #{example.login}"
145
- puts " ✅ example.password = [hidden]"
146
-
147
- # Set new field using set_field method
148
- example.set_field('api_key', 'new-api-key-456')
149
- puts " ✅ example.get_field_value_single('api_key') = new-api-key-456 (dynamically added)"
150
- end
151
-
152
- # 7. Storage options
153
- puts "\n7. STORAGE OPTIONS"
154
- puts " ✅ InMemoryStorage - Currently in use"
155
- puts " ✅ FileStorage - Save config to disk"
156
- puts " ✅ EnvironmentStorage - Use environment variables"
157
-
158
- # 8. Summary
159
- puts "\n" + "=" * 60
160
- puts "SUMMARY: Ruby SDK Features"
161
- puts "=" * 60
162
- puts "✅ Authentication & Encryption working correctly"
163
- puts "✅ Read operations fully functional"
164
- puts "✅ Folder listing from dedicated endpoint"
165
- puts "✅ Record creation working"
166
- puts "✅ Dynamic, JavaScript-style DTOs"
167
- puts "✅ Keeper notation support"
168
- puts "✅ Multiple storage backends"
169
- puts "✅ Ruby 2.7+ compatible"
170
-
171
- puts "\n📝 Notes:"
172
- puts "- Client version currently using 'mr' prefix (temporary)"
173
- puts "- Will change to 'mb' after registration with Keeper"
174
- puts "- Some folders may show decryption errors (expected for certain folder types)"
175
-
176
- puts "\n🎉 The Ruby SDK is ready for use!"
@@ -1,176 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # First, we need to add the SDK to Ruby's load path
4
- sdk_path = '/Users/mustinov/Source/secrets-manager/sdk/ruby/lib'
5
- $LOAD_PATH.unshift(sdk_path) unless $LOAD_PATH.include?(sdk_path)
6
-
7
- # Now we can require the SDK
8
- require 'keeper_secrets_manager'
9
-
10
- # Your token from Keeper
11
- TOKEN = 'US:3cJU7J7Wea97u4BauFmT2Aeeib3jciyYnqAyNryDDvE'
12
-
13
- # Initialize the SDK
14
- puts "Initializing Keeper SDK..."
15
- sm = KeeperSecretsManager.new(token: TOKEN)
16
-
17
- # Alternative: Use in-memory storage to reuse credentials
18
- # storage = KeeperSecretsManager::Storage::InMemoryStorage.new
19
- # sm = KeeperSecretsManager.new(token: TOKEN, config: storage)
20
- #
21
- # After first use, you can connect without token:
22
- # sm = KeeperSecretsManager.new(config: storage)
23
-
24
- puts "\n=== Step 1: List All Secrets ==="
25
- begin
26
- secrets = sm.get_secrets()
27
- puts "Found #{secrets.length} secrets:"
28
- secrets.each do |secret|
29
- puts " - #{secret.title} (UID: #{secret.uid})"
30
- end
31
- rescue => e
32
- puts "Error: #{e.message}"
33
- puts "Make sure to replace TOKEN with your actual Keeper token!"
34
- exit 1
35
- end
36
-
37
- # Save a secret UID for later tests
38
- if secrets.any?
39
- test_secret_uid = secrets.first.uid
40
- puts "\nUsing secret '#{secrets.first.title}' for testing"
41
- end
42
-
43
- puts "\n=== Step 2: Get Secret Details ==="
44
- if test_secret_uid
45
- secret = sm.get_secrets([test_secret_uid]).first
46
- puts "Title: #{secret.title}"
47
- puts "Type: #{secret.type}"
48
- puts "Fields:"
49
- secret.fields.each do |field|
50
- puts " - #{field['type']}: #{field['value'].first rescue 'N/A'}"
51
- end
52
- end
53
-
54
- puts "\n=== Step 3: Test Notation ==="
55
- if test_secret_uid
56
- # Test notation to get password
57
- notation = "keeper://#{test_secret_uid}/field/password"
58
- begin
59
- password = sm.get_notation(notation)
60
- puts "Password via notation: [HIDDEN]"
61
- rescue => e
62
- puts "No password field found"
63
- end
64
- end
65
-
66
- puts "\n=== Step 4: List Folders ==="
67
- folders = sm.get_folders()
68
- puts "Found #{folders.length} folders:"
69
- folders.each do |folder|
70
- puts " - #{folder.name} (UID: #{folder.uid})"
71
- end
72
-
73
- # Save folder UID for record creation
74
- if folders.any?
75
- test_folder_uid = folders.first.uid
76
- puts "\nWill use folder '#{folders.first.name}' for new records"
77
- end
78
-
79
- puts "\n=== Step 5: Create New Secret ==="
80
- if test_folder_uid
81
- new_record = KeeperSecretsManager::Dto::KeeperRecord.new(
82
- title: "Test Record - #{Time.now.strftime('%Y-%m-%d %H:%M')}",
83
- type: 'login',
84
- fields: [
85
- { 'type' => 'login', 'value' => ['testuser@example.com'] },
86
- { 'type' => 'password', 'value' => ['MySecurePassword123!'] },
87
- { 'type' => 'url', 'value' => ['https://example.com'] }
88
- ],
89
- notes: 'Created by Ruby SDK test'
90
- )
91
-
92
- options = KeeperSecretsManager::Dto::CreateOptions.new
93
- options.folder_uid = test_folder_uid
94
-
95
- begin
96
- new_uid = sm.create_secret(new_record, options)
97
- puts "Created new secret with UID: #{new_uid}"
98
- created_uid = new_uid
99
- rescue => e
100
- puts "Could not create record: #{e.message}"
101
- end
102
- else
103
- puts "No folders found - skipping record creation"
104
- end
105
-
106
- puts "\n=== Step 6: Update Secret ==="
107
- if defined?(created_uid) && created_uid
108
- # Fetch the created record
109
- record = sm.get_secrets([created_uid]).first
110
-
111
- # Update password
112
- record.set_field('password', 'UpdatedPassword456!')
113
- record.notes = "Updated at #{Time.now}"
114
-
115
- sm.update_secret(record)
116
- puts "Updated secret successfully"
117
- end
118
-
119
- puts "\n=== Step 7: File Operations ==="
120
- if defined?(created_uid) && created_uid
121
- # Create a test file
122
- test_content = "This is a test file created at #{Time.now}"
123
- File.write('test_upload.txt', test_content)
124
-
125
- # Upload file
126
- file_data = File.read('test_upload.txt', mode: 'rb')
127
- file_uid = sm.upload_file(created_uid, 'test_upload.txt', file_data)
128
- puts "Uploaded file with UID: #{file_uid}"
129
-
130
- # Download file
131
- downloaded = sm.download_file(file_uid)
132
- puts "Downloaded file: #{downloaded['name']} (#{downloaded['size']} bytes)"
133
-
134
- # Save downloaded file
135
- File.write('test_download.txt', downloaded['data'], mode: 'wb')
136
- puts "Saved to test_download.txt"
137
-
138
- # Cleanup
139
- File.delete('test_upload.txt') if File.exist?('test_upload.txt')
140
- File.delete('test_download.txt') if File.exist?('test_download.txt')
141
- end
142
-
143
- puts "\n=== Step 8: Test TOTP ==="
144
- # Look for a record with TOTP
145
- totp_found = false
146
- secrets.each do |secret|
147
- begin
148
- totp_url = sm.get_notation("keeper://#{secret.uid}/field/oneTimeCode")
149
- if totp_url && totp_url.start_with?('otpauth://')
150
- puts "Found TOTP in '#{secret.title}'"
151
- params = KeeperSecretsManager::TOTP.parse_url(totp_url)
152
- code = KeeperSecretsManager::TOTP.generate_code(params['secret'])
153
- puts "Current TOTP code: #{code}"
154
- totp_found = true
155
- break
156
- end
157
- rescue
158
- # No TOTP in this record
159
- end
160
- end
161
- puts "No TOTP fields found in any records" unless totp_found
162
-
163
- puts "\n=== Step 9: Cleanup ==="
164
- if defined?(created_uid) && created_uid
165
- print "Delete test record? (y/n): "
166
- response = gets.chomp.downcase
167
- if response == 'y'
168
- sm.delete_secret([created_uid])
169
- puts "Deleted test record"
170
- else
171
- puts "Kept test record"
172
- end
173
- end
174
-
175
- puts "\n=== Testing Complete! ==="
176
- puts "All basic operations tested successfully"
@@ -1,162 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # Add the Ruby SDK to the load path
4
- $LOAD_PATH.unshift('/Users/mustinov/Source/secrets-manager/sdk/ruby/lib')
5
-
6
- # Load the SDK
7
- require 'keeper_secrets_manager'
8
- require 'logger'
9
-
10
- # Enable debug logging
11
- logger = Logger.new(STDOUT)
12
- logger.level = Logger::DEBUG
13
-
14
- begin
15
- # Connect to Keeper
16
- puts "Connecting to Keeper..."
17
- # IMPORTANT: Replace with your own configuration
18
- # You can get a one-time token from: https://keepersecurity.com/secrets-manager
19
- #
20
- # Option 1: Use one-time token
21
- # token = 'US:YOUR_ONE_TIME_TOKEN_HERE'
22
- # sm = KeeperSecretsManager.from_token(token)
23
- #
24
- # Option 2: Use base64 config from environment or file
25
- config_base64 = ENV['KSM_CONFIG_BASE64'] || 'YOUR_BASE64_CONFIG_HERE'
26
- storage_from_b64 = KeeperSecretsManager::Storage::InMemoryStorage.new(config_base64)
27
- sm = KeeperSecretsManager.new(config: storage_from_b64, logger: logger)
28
-
29
- # Alternative: Use in-memory storage to save credentials after first use
30
- # storage = KeeperSecretsManager::Storage::InMemoryStorage.new
31
- # sm = KeeperSecretsManager.new(token: TOKEN, config: storage)
32
- #
33
- # For subsequent connections (no token needed):
34
- # sm = KeeperSecretsManager.new(config: storage)
35
-
36
- # Get all secrets
37
- puts "\nFetching secrets..."
38
- response = sm.get_secrets(full_response: true)
39
- secrets = response.records
40
-
41
- # Display results
42
- puts "\nFound #{secrets.length} secrets:"
43
- puts "Found #{response.folders.length} folders:"
44
-
45
- # Show folder structure
46
- if response.folders.any?
47
- puts "\nFolder structure:"
48
- response.folders.each do |folder|
49
- puts " - #{folder.name} (#{folder.uid})"
50
- end
51
- end
52
-
53
- # Show secrets with their folders and all fields
54
- puts "\nShowing first 5 secrets with all fields:"
55
- puts "=" * 80
56
- secrets.first(500).each_with_index do |secret, i|
57
- folder_info = secret.folder_uid && !secret.folder_uid.empty? ? " [in folder: #{secret.folder_uid}]" : " [in root]"
58
- puts "\n#{i+1}. #{secret.title}#{folder_info}"
59
- puts " Type: #{secret.type}"
60
- puts " UID: #{secret.uid}"
61
-
62
- # Show all fields
63
- if secret.fields && secret.fields.any?
64
- puts " Fields:"
65
- secret.fields.each do |field|
66
- field_type = field['type'] || 'unknown'
67
- field_label = field['label'] || field_type
68
-
69
- # Get the value(s)
70
- values = field['value'] || []
71
- values = [values] unless values.is_a?(Array)
72
-
73
- # Format based on field type
74
- case field_type
75
- when 'password', 'secret', 'pinCode', 'securityQuestion'
76
- # Hide sensitive data
77
- display_values = values.map { |v| '********' }
78
- when 'privateKey'
79
- # Show first/last few characters of private keys
80
- display_values = values.map do |v|
81
- if v && v.length > 20
82
- "#{v[0..10]}...#{v[-10..-1]}"
83
- else
84
- v
85
- end
86
- end
87
- when 'fileRef'
88
- # Show file reference info
89
- display_values = values.map { |v| "File: #{v}" }
90
- else
91
- # Show full value for non-sensitive fields
92
- display_values = values
93
- end
94
-
95
- # Print field info
96
- if display_values.length == 1
97
- puts " - #{field_label} (#{field_type}): #{display_values.first}"
98
- elsif display_values.length > 1
99
- puts " - #{field_label} (#{field_type}):"
100
- display_values.each { |v| puts " • #{v}" }
101
- else
102
- puts " - #{field_label} (#{field_type}): [empty]"
103
- end
104
- end
105
- else
106
- puts " No fields"
107
- end
108
-
109
- # Show custom fields if any
110
- if secret.custom && secret.custom.any?
111
- puts " Custom fields:"
112
- secret.custom.each do |custom_field|
113
- puts " - #{custom_field['label']}: #{custom_field['value']}"
114
- end
115
- end
116
-
117
- # Show files if any
118
- if secret.files && secret.files.any?
119
- puts " Files:"
120
- secret.files.each do |file|
121
- file_name = file['title'] || file['name'] || 'unnamed'
122
- file_size = file['size'] || 0
123
- file_uid = file['fileUid'] || file['uid']
124
- puts " - #{file_name} (#{file_size} bytes) [UID: #{file_uid}]"
125
-
126
- # Download the file if it's small (under 1MB for demo)
127
- if file_size < 1_000_000 && file_uid
128
- begin
129
- puts " Downloading..."
130
- downloaded_file = sm.download_file(file)
131
-
132
- # Save to downloads folder
133
- download_dir = "downloads"
134
- Dir.mkdir(download_dir) unless Dir.exist?(download_dir)
135
-
136
- safe_filename = File.basename(downloaded_file['name'] || file_name)
137
- file_path = File.join(download_dir, safe_filename)
138
- File.binwrite(file_path, downloaded_file['data'])
139
-
140
- puts " ✅ Saved to: #{file_path}"
141
- rescue => e
142
- puts " ❌ Download failed: #{e.message}"
143
- end
144
- elsif file_size >= 1_000_000
145
- puts " ⚠️ File too large for demo (>1MB)"
146
- end
147
- end
148
- end
149
- end
150
-
151
- puts "\n" + "=" * 80
152
- puts "\nTotal: #{secrets.length} secrets (showing first #{[secrets.length, 500].min})"
153
- puts "\nSuccess! The Ruby SDK is working correctly."
154
-
155
- rescue => e
156
- puts "\nError: #{e.message}"
157
- puts "\nTroubleshooting:"
158
- puts "1. Make sure you replaced TOKEN with your actual Keeper token"
159
- puts "2. Token format should be: US:xxxxxxxxxxxxx (or EU:xxxxx for Europe)"
160
- puts "3. Tokens are one-time use - get a new one if this fails"
161
- puts "4. Check that the SDK path is correct: /Users/mustinov/Source/secrets-manager/sdk/ruby/lib"
162
- end