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.
- checksums.yaml +4 -4
- data/DEVELOPER_SETUP.md +0 -0
- data/MANUAL_TESTING_GUIDE.md +332 -0
- data/RUBY_SDK_COMPLETE_DOCUMENTATION.md +354 -0
- data/RUBY_SDK_COMPREHENSIVE_SUMMARY.md +192 -0
- data/examples/01_quick_start.rb +45 -0
- data/examples/02_authentication.rb +82 -0
- data/examples/03_retrieve_secrets.rb +81 -0
- data/examples/04_create_update_delete.rb +104 -0
- data/examples/05_field_types.rb +135 -0
- data/examples/06_files.rb +137 -0
- data/examples/07_folders.rb +145 -0
- data/examples/08_notation.rb +103 -0
- data/examples/09_totp.rb +100 -0
- data/examples/README.md +89 -0
- data/lib/keeper_secrets_manager/version.rb +1 -1
- metadata +15 -12
- data/examples/basic_usage.rb +0 -139
- data/examples/config_string_example.rb +0 -99
- data/examples/debug_secrets.rb +0 -84
- data/examples/demo_list_secrets.rb +0 -182
- data/examples/download_files.rb +0 -100
- data/examples/flexible_records_example.rb +0 -94
- data/examples/folder_hierarchy_demo.rb +0 -109
- data/examples/full_demo.rb +0 -176
- data/examples/my_test_standalone.rb +0 -176
- data/examples/simple_test.rb +0 -162
- data/examples/storage_examples.rb +0 -126
data/examples/basic_usage.rb
DELETED
@@ -1,139 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require_relative '../lib/keeper_secrets_manager'
|
4
|
-
|
5
|
-
# Example: Basic usage of Keeper Secrets Manager Ruby SDK
|
6
|
-
|
7
|
-
# Method 1: Initialize with one-time token
|
8
|
-
# token = "US:ONE_TIME_TOKEN_HERE"
|
9
|
-
# secrets_manager = KeeperSecretsManager.from_token(token)
|
10
|
-
|
11
|
-
# Method 2: Initialize with existing config
|
12
|
-
config = KeeperSecretsManager::Storage::InMemoryStorage.new({
|
13
|
-
'hostname' => 'keepersecurity.com',
|
14
|
-
'clientId' => 'your-client-id',
|
15
|
-
'privateKey' => 'your-private-key-base64',
|
16
|
-
'appKey' => 'your-app-key-base64'
|
17
|
-
})
|
18
|
-
secrets_manager = KeeperSecretsManager.new(config: config)
|
19
|
-
|
20
|
-
# Get all secrets
|
21
|
-
begin
|
22
|
-
records = secrets_manager.get_secrets
|
23
|
-
puts "Found #{records.length} records"
|
24
|
-
|
25
|
-
records.each do |record|
|
26
|
-
puts "\nRecord: #{record.title}"
|
27
|
-
puts " Type: #{record.type}"
|
28
|
-
puts " UID: #{record.uid}"
|
29
|
-
|
30
|
-
# Access fields dynamically
|
31
|
-
if record.get_field('login')
|
32
|
-
puts " Login: #{record.get_field_value_single('login')}"
|
33
|
-
end
|
34
|
-
|
35
|
-
if record.get_field('password')
|
36
|
-
puts " Password: [HIDDEN]"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
rescue => e
|
40
|
-
puts "Error: #{e.message}"
|
41
|
-
end
|
42
|
-
|
43
|
-
# Get specific record by UID
|
44
|
-
begin
|
45
|
-
record_uid = "RECORD_UID_HERE"
|
46
|
-
records = secrets_manager.get_secrets([record_uid])
|
47
|
-
|
48
|
-
if records.any?
|
49
|
-
record = records.first
|
50
|
-
puts "\nRetrieved record: #{record.title}"
|
51
|
-
end
|
52
|
-
rescue => e
|
53
|
-
puts "Error retrieving record: #{e.message}"
|
54
|
-
end
|
55
|
-
|
56
|
-
# Get record by title
|
57
|
-
begin
|
58
|
-
record = secrets_manager.get_secret_by_title("My Login")
|
59
|
-
if record
|
60
|
-
puts "\nFound record by title: #{record.uid}"
|
61
|
-
|
62
|
-
# Access custom fields
|
63
|
-
record.custom.each do |field|
|
64
|
-
puts " Custom field '#{field['label']}': #{field['value'].first}"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
rescue => e
|
68
|
-
puts "Error: #{e.message}"
|
69
|
-
end
|
70
|
-
|
71
|
-
# Use notation to access specific field values
|
72
|
-
begin
|
73
|
-
# Get password field from a record
|
74
|
-
password = secrets_manager.get_notation("keeper://RECORD_UID/field/password")
|
75
|
-
puts "\nPassword from notation: [HIDDEN]"
|
76
|
-
|
77
|
-
# Get specific property from complex field
|
78
|
-
hostname = secrets_manager.get_notation("keeper://RECORD_UID/field/host[hostName]")
|
79
|
-
puts "Hostname: #{hostname}"
|
80
|
-
|
81
|
-
# Get custom field
|
82
|
-
custom_value = secrets_manager.get_notation("keeper://RECORD_UID/custom_field/My Label")
|
83
|
-
puts "Custom field value: #{custom_value}"
|
84
|
-
rescue => e
|
85
|
-
puts "Notation error: #{e.message}"
|
86
|
-
end
|
87
|
-
|
88
|
-
# Create a new record
|
89
|
-
begin
|
90
|
-
new_record = KeeperSecretsManager::Dto::KeeperRecord.new(
|
91
|
-
title: 'New Server Login',
|
92
|
-
type: 'login',
|
93
|
-
fields: [
|
94
|
-
{ 'type' => 'login', 'value' => ['admin'] },
|
95
|
-
{ 'type' => 'password', 'value' => ['SecurePass123!'] },
|
96
|
-
{ 'type' => 'url', 'value' => ['https://example.com'] },
|
97
|
-
{ 'type' => 'host',
|
98
|
-
'value' => [{ 'hostName' => '192.168.1.100', 'port' => '22' }],
|
99
|
-
'label' => 'SSH Connection' }
|
100
|
-
],
|
101
|
-
notes: 'Created by Ruby SDK'
|
102
|
-
)
|
103
|
-
|
104
|
-
# Create the record
|
105
|
-
# record_uid = secrets_manager.create_secret(new_record)
|
106
|
-
# puts "\nCreated new record: #{record_uid}"
|
107
|
-
rescue => e
|
108
|
-
puts "Error creating record: #{e.message}"
|
109
|
-
end
|
110
|
-
|
111
|
-
# Update existing record
|
112
|
-
begin
|
113
|
-
# Get record to update
|
114
|
-
record = secrets_manager.get_secret_by_title("Test Record")
|
115
|
-
|
116
|
-
if record
|
117
|
-
# Update fields
|
118
|
-
record.set_field('password', 'NewPassword123!')
|
119
|
-
record.notes = "Updated at #{Time.now}"
|
120
|
-
|
121
|
-
# Save changes
|
122
|
-
# secrets_manager.update_secret(record)
|
123
|
-
# puts "\nRecord updated successfully"
|
124
|
-
end
|
125
|
-
rescue => e
|
126
|
-
puts "Error updating record: #{e.message}"
|
127
|
-
end
|
128
|
-
|
129
|
-
# Working with folders
|
130
|
-
begin
|
131
|
-
folders = secrets_manager.get_folders
|
132
|
-
puts "\nFound #{folders.length} folders"
|
133
|
-
|
134
|
-
folders.each do |folder|
|
135
|
-
puts " Folder: #{folder.name} (#{folder.uid})"
|
136
|
-
end
|
137
|
-
rescue => e
|
138
|
-
puts "Error retrieving folders: #{e.message}"
|
139
|
-
end
|
@@ -1,99 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
# Add the Ruby SDK to the load path
|
4
|
-
|
5
|
-
require_relative '../lib/keeper_secrets_manager'
|
6
|
-
require 'json'
|
7
|
-
require 'base64'
|
8
|
-
|
9
|
-
puts "=== Using Keeper SDK with Config String ==="
|
10
|
-
|
11
|
-
# Example 1: JSON config string
|
12
|
-
puts "\n1. Using JSON config string"
|
13
|
-
puts "-" * 40
|
14
|
-
|
15
|
-
# This would come from your secure configuration
|
16
|
-
json_config = {
|
17
|
-
"hostname" => "keepersecurity.com",
|
18
|
-
"clientId" => "YOURCLIENTID",
|
19
|
-
"appKey" => "YOURAPPKEYBASE64",
|
20
|
-
"privateKey" => "YOURPRIVATEKEYBASE64",
|
21
|
-
"appOwnerPublicKey" => "YOUROWNERPUBLICKEYBASE64",
|
22
|
-
"serverPublicKeyId" => "7"
|
23
|
-
}.to_json
|
24
|
-
|
25
|
-
begin
|
26
|
-
# Initialize with JSON string - NO TOKEN NEEDED!
|
27
|
-
storage = KeeperSecretsManager::Storage::InMemoryStorage.new(json_config)
|
28
|
-
sm = KeeperSecretsManager.new(config: storage)
|
29
|
-
puts "ā Would connect with pre-configured credentials (if real credentials were provided)"
|
30
|
-
rescue => e
|
31
|
-
puts "ā Expected error with dummy credentials: #{e.message}"
|
32
|
-
end
|
33
|
-
|
34
|
-
# Example 2: Base64 encoded config
|
35
|
-
puts "\n2. Using Base64 encoded config"
|
36
|
-
puts "-" * 40
|
37
|
-
|
38
|
-
# Encode the config as base64 (like KSM_CONFIG environment variable)
|
39
|
-
base64_config = Base64.strict_encode64(json_config)
|
40
|
-
puts "Base64 config: #{base64_config[0..50]}..."
|
41
|
-
|
42
|
-
begin
|
43
|
-
# Initialize with base64 string - NO TOKEN NEEDED!
|
44
|
-
storage = KeeperSecretsManager::Storage::InMemoryStorage.new(base64_config)
|
45
|
-
sm = KeeperSecretsManager.new(config: storage)
|
46
|
-
puts "ā Would connect with base64 config (if real credentials were provided)"
|
47
|
-
rescue => e
|
48
|
-
puts "ā Expected error with dummy credentials: #{e.message}"
|
49
|
-
end
|
50
|
-
|
51
|
-
# Example 3: Using environment variable
|
52
|
-
puts "\n3. Using KSM_CONFIG environment variable"
|
53
|
-
puts "-" * 40
|
54
|
-
|
55
|
-
# Set environment variable (normally done outside the script)
|
56
|
-
ENV['KSM_CONFIG'] = base64_config
|
57
|
-
|
58
|
-
begin
|
59
|
-
# SDK automatically checks for KSM_CONFIG - NO TOKEN OR CONFIG NEEDED!
|
60
|
-
sm = KeeperSecretsManager.new()
|
61
|
-
puts "ā Would connect with environment variable (if real credentials were provided)"
|
62
|
-
rescue => e
|
63
|
-
puts "ā Expected error with dummy credentials: #{e.message}"
|
64
|
-
end
|
65
|
-
|
66
|
-
# Example 4: Real workflow - first time with token, then reuse
|
67
|
-
puts "\n4. Real workflow example"
|
68
|
-
puts "-" * 40
|
69
|
-
|
70
|
-
# First time - use token to get credentials
|
71
|
-
puts "First connection with token:"
|
72
|
-
puts "sm = KeeperSecretsManager.new(token: 'US:YOUR_TOKEN')"
|
73
|
-
puts "config_to_save = sm.config.to_json"
|
74
|
-
puts "# Save config_to_save securely"
|
75
|
-
|
76
|
-
puts "\nSubsequent connections:"
|
77
|
-
puts "saved_config = load_from_secure_storage()"
|
78
|
-
puts "storage = KeeperSecretsManager::Storage::InMemoryStorage.new(saved_config)"
|
79
|
-
puts "sm = KeeperSecretsManager.new(config: storage) # No token needed!"
|
80
|
-
|
81
|
-
# Example 5: What the config looks like
|
82
|
-
puts "\n5. Config structure"
|
83
|
-
puts "-" * 40
|
84
|
-
puts "After successful token authentication, the config contains:"
|
85
|
-
puts JSON.pretty_generate({
|
86
|
-
"clientId" => "Base64 encoded client ID (hash of token)",
|
87
|
-
"appKey" => "Base64 encoded AES key for encryption",
|
88
|
-
"privateKey" => "Base64 encoded EC private key (DER format)",
|
89
|
-
"appOwnerPublicKey" => "Base64 encoded public key for record creation",
|
90
|
-
"hostname" => "keepersecurity.com (or other region)",
|
91
|
-
"serverPublicKeyId" => "7 (or other key ID)"
|
92
|
-
})
|
93
|
-
|
94
|
-
puts "\n" + "=" * 60
|
95
|
-
puts "Key Points:"
|
96
|
-
puts "- Once you have the config, you never need the token again"
|
97
|
-
puts "- Config can be JSON or base64 encoded"
|
98
|
-
puts "- Store the config securely - it contains your encryption keys!"
|
99
|
-
puts "- The SDK will NOT ask for a token if valid config is provided"
|
data/examples/debug_secrets.rb
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
# Add the Ruby SDK to the load path
|
4
|
-
require_relative '../lib/keeper_secrets_manager'
|
5
|
-
|
6
|
-
# Load the SDK
|
7
|
-
require 'json'
|
8
|
-
|
9
|
-
# Your token
|
10
|
-
TOKEN = ENV['KSM_TOKEN'] || 'US:YOUR_ONE_TIME_TOKEN_HERE'
|
11
|
-
|
12
|
-
puts "=== Debugging Keeper Secrets Manager ==="
|
13
|
-
|
14
|
-
begin
|
15
|
-
# Connect to Keeper with debug logging
|
16
|
-
puts "\n1. Connecting to Keeper..."
|
17
|
-
# Option 1: Use base64 config
|
18
|
-
config_base64 = ENV['KSM_CONFIG_BASE64'] || 'YOUR_BASE64_CONFIG_HERE'
|
19
|
-
storage_from_b64 = KeeperSecretsManager::Storage::InMemoryStorage.new(config_base64)
|
20
|
-
sm = KeeperSecretsManager.new(config: storage_from_b64)
|
21
|
-
# Alternative: Use in-memory storage
|
22
|
-
# storage = KeeperSecretsManager::Storage::InMemoryStorage.new
|
23
|
-
# sm = KeeperSecretsManager.new(token: TOKEN, config: storage)
|
24
|
-
#
|
25
|
-
# The storage now contains the credentials, so you can reuse it:
|
26
|
-
# sm2 = KeeperSecretsManager.new(config: storage) # No token needed!
|
27
|
-
|
28
|
-
# Get all secrets with raw response
|
29
|
-
puts "\n2. Fetching secrets (this calls the internal method)..."
|
30
|
-
|
31
|
-
# Let's look at what the SDK is actually doing internally
|
32
|
-
# Get the raw response to see what's coming from the server
|
33
|
-
response = sm.instance_eval do
|
34
|
-
fetch_and_decrypt_secrets
|
35
|
-
end
|
36
|
-
|
37
|
-
puts "\n3. Response Analysis:"
|
38
|
-
puts " - Total records returned: #{response[:records].length}"
|
39
|
-
puts " - Total folders returned: #{response[:folders].length}"
|
40
|
-
puts " - Warnings: #{response[:warnings]}"
|
41
|
-
|
42
|
-
# Check if there are any records at all
|
43
|
-
if response[:records].empty?
|
44
|
-
puts "\n ā ļø No Secrets Manager-compatible records found!"
|
45
|
-
puts " The warning indicates you have 4 'general' type records."
|
46
|
-
puts " These are not accessible via the Secrets Manager SDK."
|
47
|
-
else
|
48
|
-
puts "\n4. Records found:"
|
49
|
-
response[:records].each_with_index do |record, i|
|
50
|
-
puts " #{i+1}. #{record.title} (Type: #{record.type}, UID: #{record.uid})"
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# Try to get records with specific UIDs from the warning
|
55
|
-
puts "\n5. Attempting to fetch specific UIDs from warning..."
|
56
|
-
warning_uids = ['AwOCl5W2RubtkFSuL72jXg', 'bX7uYVNsujLoPjrvEFA3Rg', 'gSnSFvd_UI9CnK_5kSZ85Q', 'wIT61_GnuBIpUOPxOrgPeQ']
|
57
|
-
|
58
|
-
warning_uids.each do |uid|
|
59
|
-
begin
|
60
|
-
records = sm.get_secrets([uid])
|
61
|
-
if records.any?
|
62
|
-
puts " ā Found: #{uid}"
|
63
|
-
else
|
64
|
-
puts " ā Not accessible: #{uid} (general type)"
|
65
|
-
end
|
66
|
-
rescue => e
|
67
|
-
puts " ā Error fetching #{uid}: #{e.message}"
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
puts "\n6. Summary:"
|
72
|
-
puts " - Your vault contains 'general' type records"
|
73
|
-
puts " - These are legacy Keeper records not designed for API access"
|
74
|
-
puts " - To use Secrets Manager, create records with specific types like:"
|
75
|
-
puts " ⢠login"
|
76
|
-
puts " ⢠databaseCredentials"
|
77
|
-
puts " ⢠sshKeys"
|
78
|
-
puts " ⢠serverCredentials"
|
79
|
-
puts " ⢠etc."
|
80
|
-
|
81
|
-
rescue => e
|
82
|
-
puts "\nError: #{e.message}"
|
83
|
-
puts e.backtrace.first(5).join("\n")
|
84
|
-
end
|
@@ -1,182 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
# This script demonstrates the Ruby SDK by listing all secrets in your vault
|
4
|
-
# It uses the real config.base64 file to connect to Keeper
|
5
|
-
|
6
|
-
require_relative 'lib/keeper_secrets_manager'
|
7
|
-
require 'base64'
|
8
|
-
require 'json'
|
9
|
-
|
10
|
-
puts "=== Keeper Secrets Manager Ruby SDK Demo ==="
|
11
|
-
puts "Connecting to Keeper and listing all secrets..."
|
12
|
-
puts
|
13
|
-
|
14
|
-
begin
|
15
|
-
# Load the real configuration
|
16
|
-
config_file = File.expand_path('config.base64', __dir__)
|
17
|
-
unless File.exist?(config_file)
|
18
|
-
puts "Error: config.base64 not found at #{config_file}"
|
19
|
-
exit 1
|
20
|
-
end
|
21
|
-
|
22
|
-
config_base64 = File.read(config_file).strip
|
23
|
-
config_json = Base64.decode64(config_base64)
|
24
|
-
config_data = JSON.parse(config_json)
|
25
|
-
|
26
|
-
# Display connection info (partial)
|
27
|
-
puts "Configuration loaded:"
|
28
|
-
puts " Hostname: #{config_data['hostname']}"
|
29
|
-
puts " Client ID: #{config_data['clientId'][0..30]}..."
|
30
|
-
puts " Has appKey: #{config_data.key?('appKey')}"
|
31
|
-
puts " Has privateKey: #{config_data.key?('privateKey')}"
|
32
|
-
puts " Has serverPublicKeyId: #{config_data['serverPublicKeyId']}"
|
33
|
-
puts
|
34
|
-
|
35
|
-
# Create storage and SDK instance
|
36
|
-
storage = KeeperSecretsManager::Storage::InMemoryStorage.new(config_data)
|
37
|
-
|
38
|
-
# Enable debug logging
|
39
|
-
require 'logger'
|
40
|
-
logger = Logger.new(STDOUT)
|
41
|
-
logger.level = Logger::DEBUG
|
42
|
-
|
43
|
-
secrets_manager = KeeperSecretsManager.new(config: storage, logger: logger, log_level: Logger::DEBUG)
|
44
|
-
|
45
|
-
# Get all secrets
|
46
|
-
puts "Fetching all secrets..."
|
47
|
-
records = secrets_manager.get_secrets
|
48
|
-
|
49
|
-
if records.empty?
|
50
|
-
puts "\nNo secrets found in the vault."
|
51
|
-
else
|
52
|
-
puts "\nFound #{records.length} secret(s):"
|
53
|
-
puts "-" * 80
|
54
|
-
|
55
|
-
records.each_with_index do |record, index|
|
56
|
-
puts "\n#{index + 1}. #{record.title}"
|
57
|
-
puts " UID: #{record.uid}"
|
58
|
-
puts " Type: #{record.type}"
|
59
|
-
|
60
|
-
# Show fields (hide sensitive values)
|
61
|
-
if record.fields.any?
|
62
|
-
puts " Fields:"
|
63
|
-
record.fields.each do |field|
|
64
|
-
field_type = field['type']
|
65
|
-
field_label = field['label'] ? " (#{field['label']})" : ""
|
66
|
-
|
67
|
-
# Show field info but mask sensitive data
|
68
|
-
case field_type
|
69
|
-
when 'login', 'email'
|
70
|
-
value = record.get_field_value_single(field_type)
|
71
|
-
puts " - #{field_type}#{field_label}: #{value}"
|
72
|
-
when 'password', 'secret', 'privateKey'
|
73
|
-
puts " - #{field_type}#{field_label}: [HIDDEN]"
|
74
|
-
when 'url'
|
75
|
-
values = record.get_field_value(field_type)
|
76
|
-
if values.length == 1
|
77
|
-
puts " - #{field_type}#{field_label}: #{values.first}"
|
78
|
-
else
|
79
|
-
puts " - #{field_type}#{field_label}: #{values.length} URLs"
|
80
|
-
end
|
81
|
-
when 'host'
|
82
|
-
host = record.get_field_value_single(field_type)
|
83
|
-
if host.is_a?(Hash)
|
84
|
-
puts " - #{field_type}#{field_label}: #{host['hostName']}:#{host['port'] || '22'}"
|
85
|
-
end
|
86
|
-
when 'phone'
|
87
|
-
phone = record.get_field_value_single(field_type)
|
88
|
-
if phone.is_a?(Hash)
|
89
|
-
puts " - #{field_type}#{field_label}: #{phone['number']} (#{phone['region']})"
|
90
|
-
end
|
91
|
-
when 'name'
|
92
|
-
name = record.get_field_value_single(field_type)
|
93
|
-
if name.is_a?(Hash)
|
94
|
-
full_name = [name['first'], name['middle'], name['last']].compact.join(' ')
|
95
|
-
puts " - #{field_type}#{field_label}: #{full_name}"
|
96
|
-
end
|
97
|
-
else
|
98
|
-
puts " - #{field_type}#{field_label}: [#{field['value']&.length || 0} value(s)]"
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# Show custom fields
|
104
|
-
if record.custom.any?
|
105
|
-
puts " Custom Fields:"
|
106
|
-
record.custom.each do |field|
|
107
|
-
label = field['label'] || field['type']
|
108
|
-
value_count = field['value']&.length || 0
|
109
|
-
puts " - #{label}: [#{value_count} value(s)]"
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
# Show notes (first 50 chars)
|
114
|
-
if record.notes && !record.notes.empty?
|
115
|
-
notes_preview = record.notes[0..50]
|
116
|
-
notes_preview += "..." if record.notes.length > 50
|
117
|
-
puts " Notes: #{notes_preview}"
|
118
|
-
end
|
119
|
-
|
120
|
-
# Show file count
|
121
|
-
if record.files && record.files.any?
|
122
|
-
puts " Files: #{record.files.length} attachment(s)"
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
puts "\n" + "-" * 80
|
127
|
-
end
|
128
|
-
|
129
|
-
# Get folders
|
130
|
-
puts "\nFetching folders..."
|
131
|
-
folders = secrets_manager.get_folders
|
132
|
-
|
133
|
-
if folders.empty?
|
134
|
-
puts "No folders found."
|
135
|
-
else
|
136
|
-
puts "Found #{folders.length} folder(s):"
|
137
|
-
folders.each do |folder|
|
138
|
-
puts " - #{folder.name} (#{folder.uid})"
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
# Demonstrate notation
|
143
|
-
if records.any?
|
144
|
-
puts "\n" + "=" * 80
|
145
|
-
puts "Notation Examples (using first record):"
|
146
|
-
puts "=" * 80
|
147
|
-
|
148
|
-
first_record = records.first
|
149
|
-
|
150
|
-
# Try various notations
|
151
|
-
notations = [
|
152
|
-
"keeper://#{first_record.uid}/type",
|
153
|
-
"keeper://#{first_record.uid}/title",
|
154
|
-
"keeper://#{first_record.uid}/field/login"
|
155
|
-
]
|
156
|
-
|
157
|
-
notations.each do |notation|
|
158
|
-
begin
|
159
|
-
value = secrets_manager.get_notation(notation)
|
160
|
-
puts "#{notation}"
|
161
|
-
puts " => #{value}"
|
162
|
-
rescue => e
|
163
|
-
puts "#{notation}"
|
164
|
-
puts " => Error: #{e.message}"
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
puts "\nā
SDK is working correctly!"
|
170
|
-
puts "\nCapabilities demonstrated:"
|
171
|
-
puts "- ā Connected to Keeper"
|
172
|
-
puts "- ā Retrieved all secrets"
|
173
|
-
puts "- ā Accessed field values"
|
174
|
-
puts "- ā Listed folders"
|
175
|
-
puts "- ā Notation parsing"
|
176
|
-
|
177
|
-
rescue => e
|
178
|
-
puts "\nā Error: #{e.class} - #{e.message}"
|
179
|
-
puts "\nBacktrace:"
|
180
|
-
puts e.backtrace.first(5).join("\n")
|
181
|
-
exit 1
|
182
|
-
end
|
data/examples/download_files.rb
DELETED
@@ -1,100 +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 'fileutils'
|
9
|
-
|
10
|
-
# Helper method to sanitize filename
|
11
|
-
def sanitize_filename(filename)
|
12
|
-
# Remove or replace invalid characters
|
13
|
-
filename.gsub(/[<>:"|?*\/\\]/, '_').strip
|
14
|
-
end
|
15
|
-
|
16
|
-
begin
|
17
|
-
# Connect to Keeper
|
18
|
-
puts "Connecting to Keeper..."
|
19
|
-
# IMPORTANT: Replace with your own configuration
|
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
|
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)
|
28
|
-
|
29
|
-
# Get all secrets
|
30
|
-
puts "\nFetching secrets..."
|
31
|
-
response = sm.get_secrets(full_response: true)
|
32
|
-
secrets = response.records
|
33
|
-
|
34
|
-
# Find secrets with files
|
35
|
-
secrets_with_files = secrets.select { |s| s.files && s.files.any? }
|
36
|
-
|
37
|
-
if secrets_with_files.empty?
|
38
|
-
puts "\nNo secrets with files found."
|
39
|
-
exit
|
40
|
-
end
|
41
|
-
|
42
|
-
puts "\nFound #{secrets_with_files.length} secrets with files:"
|
43
|
-
|
44
|
-
# Create downloads directory
|
45
|
-
download_dir = "downloads"
|
46
|
-
FileUtils.mkdir_p(download_dir)
|
47
|
-
|
48
|
-
total_files = 0
|
49
|
-
downloaded_files = 0
|
50
|
-
failed_files = 0
|
51
|
-
|
52
|
-
secrets_with_files.each do |secret|
|
53
|
-
puts "\nš #{secret.title} (#{secret.files.length} files)"
|
54
|
-
|
55
|
-
secret.files.each do |file|
|
56
|
-
total_files += 1
|
57
|
-
file_name = file['title'] || file['name'] || 'unnamed'
|
58
|
-
file_size = file['size'] || 0
|
59
|
-
file_uid = file['fileUid'] || file['uid']
|
60
|
-
|
61
|
-
print " - #{file_name} (#{file_size} bytes) ... "
|
62
|
-
|
63
|
-
if file_uid
|
64
|
-
begin
|
65
|
-
# Download the file (pass the whole file object)
|
66
|
-
downloaded_file = sm.download_file(file)
|
67
|
-
|
68
|
-
# Create subdirectory for the secret
|
69
|
-
secret_dir = File.join(download_dir, sanitize_filename(secret.title))
|
70
|
-
FileUtils.mkdir_p(secret_dir)
|
71
|
-
|
72
|
-
# Save the file (sanitize the filename to remove path components)
|
73
|
-
safe_filename = File.basename(downloaded_file['name'] || file_name)
|
74
|
-
file_path = File.join(secret_dir, safe_filename)
|
75
|
-
File.binwrite(file_path, downloaded_file['data'])
|
76
|
-
|
77
|
-
downloaded_files += 1
|
78
|
-
puts "ā
Saved"
|
79
|
-
rescue => e
|
80
|
-
failed_files += 1
|
81
|
-
puts "ā Failed: #{e.message}"
|
82
|
-
end
|
83
|
-
else
|
84
|
-
failed_files += 1
|
85
|
-
puts "ā No file UID"
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
puts "\n" + "=" * 60
|
91
|
-
puts "Download Summary:"
|
92
|
-
puts " Total files: #{total_files}"
|
93
|
-
puts " ā
Downloaded: #{downloaded_files}"
|
94
|
-
puts " ā Failed: #{failed_files}"
|
95
|
-
puts "\nFiles saved to: #{File.expand_path(download_dir)}/"
|
96
|
-
|
97
|
-
rescue => e
|
98
|
-
puts "\nError: #{e.message}"
|
99
|
-
puts e.backtrace
|
100
|
-
end
|
@@ -1,94 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require_relative '../lib/keeper_secrets_manager'
|
4
|
-
|
5
|
-
# Example showing flexible record creation in multiple ways
|
6
|
-
|
7
|
-
# Method 1: Direct hash-based creation (JavaScript-style)
|
8
|
-
record1 = KeeperSecretsManager::Dto::KeeperRecord.new(
|
9
|
-
title: 'My Login',
|
10
|
-
type: 'login',
|
11
|
-
fields: [
|
12
|
-
{ 'type' => 'login', 'value' => ['my_username'] },
|
13
|
-
{ 'type' => 'password', 'value' => ['my_password'] },
|
14
|
-
{ 'type' => 'url', 'value' => ['https://example.com'] },
|
15
|
-
{
|
16
|
-
'type' => 'host',
|
17
|
-
'value' => [{ 'hostName' => '192.168.1.1', 'port' => '8080' }],
|
18
|
-
'label' => 'Custom Host'
|
19
|
-
}
|
20
|
-
],
|
21
|
-
custom: [
|
22
|
-
{
|
23
|
-
'type' => 'phone',
|
24
|
-
'value' => [{ 'region' => 'US', 'number' => '555-1234' }],
|
25
|
-
'label' => 'Work Phone'
|
26
|
-
}
|
27
|
-
],
|
28
|
-
notes: 'Example login record'
|
29
|
-
)
|
30
|
-
|
31
|
-
# Method 2: Using field helpers (optional convenience)
|
32
|
-
record2 = KeeperSecretsManager::Dto::KeeperRecord.new(
|
33
|
-
title: 'My Server',
|
34
|
-
type: 'sshKeys'
|
35
|
-
)
|
36
|
-
|
37
|
-
# Add fields dynamically
|
38
|
-
record2.set_field('login', 'root')
|
39
|
-
record2.set_field('sshKey', {
|
40
|
-
'privateKey' => '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----',
|
41
|
-
'publicKey' => 'ssh-rsa AAAAB3...'
|
42
|
-
})
|
43
|
-
|
44
|
-
# Method 3: Using dynamic accessors (Ruby magic)
|
45
|
-
record3 = KeeperSecretsManager::Dto::KeeperRecord.new(
|
46
|
-
title: 'Dynamic Record',
|
47
|
-
type: 'login'
|
48
|
-
)
|
49
|
-
|
50
|
-
# These create fields dynamically!
|
51
|
-
record3.login = 'john_doe'
|
52
|
-
record3.password = 'secure_pass123'
|
53
|
-
record3.url = 'https://myapp.com'
|
54
|
-
|
55
|
-
# Method 4: Mixing approaches
|
56
|
-
record4 = KeeperSecretsManager::Dto::KeeperRecord.new(
|
57
|
-
title: 'Payment Info',
|
58
|
-
type: 'bankCard'
|
59
|
-
)
|
60
|
-
|
61
|
-
# Use helper for complex field
|
62
|
-
card_field = KeeperSecretsManager::FieldTypes::Helpers.payment_card(
|
63
|
-
number: '4111111111111111',
|
64
|
-
expiration_date: '12/25',
|
65
|
-
security_code: '123',
|
66
|
-
cardholder_name: 'John Doe'
|
67
|
-
)
|
68
|
-
|
69
|
-
# Add to record
|
70
|
-
record4.fields << card_field.to_h
|
71
|
-
|
72
|
-
# Add custom field with any structure
|
73
|
-
record4.set_field('customData', {
|
74
|
-
'someKey' => 'someValue',
|
75
|
-
'nested' => {
|
76
|
-
'data' => 'structure'
|
77
|
-
}
|
78
|
-
}, 'My Custom Data', true) # true = custom field
|
79
|
-
|
80
|
-
# Access field values
|
81
|
-
puts "Login: #{record1.get_field_value_single('login')}"
|
82
|
-
puts "Password field: #{record1.get_field('password')}"
|
83
|
-
puts "All custom fields: #{record1.custom}"
|
84
|
-
|
85
|
-
# Dynamic accessor
|
86
|
-
puts "URL from record3: #{record3.url}"
|
87
|
-
|
88
|
-
# Access complex field values
|
89
|
-
host_field = record1.get_field_value_single('host')
|
90
|
-
puts "Host: #{host_field['hostName']}:#{host_field['port']}" if host_field
|
91
|
-
|
92
|
-
# Convert to hash for API
|
93
|
-
puts "\nRecord as hash for API:"
|
94
|
-
puts record1.to_h.to_json
|