keeper_secrets_manager 17.0.3
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 +7 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +49 -0
- data/Gemfile +13 -0
- data/LICENSE +21 -0
- data/README.md +305 -0
- data/Rakefile +30 -0
- data/examples/basic_usage.rb +139 -0
- data/examples/config_string_example.rb +99 -0
- data/examples/debug_secrets.rb +84 -0
- data/examples/demo_list_secrets.rb +182 -0
- data/examples/download_files.rb +100 -0
- data/examples/flexible_records_example.rb +94 -0
- data/examples/folder_hierarchy_demo.rb +109 -0
- data/examples/full_demo.rb +176 -0
- data/examples/my_test_standalone.rb +176 -0
- data/examples/simple_test.rb +162 -0
- data/examples/storage_examples.rb +126 -0
- data/lib/keeper_secrets_manager/config_keys.rb +27 -0
- data/lib/keeper_secrets_manager/core.rb +1231 -0
- data/lib/keeper_secrets_manager/crypto.rb +348 -0
- data/lib/keeper_secrets_manager/dto/payload.rb +152 -0
- data/lib/keeper_secrets_manager/dto.rb +221 -0
- data/lib/keeper_secrets_manager/errors.rb +79 -0
- data/lib/keeper_secrets_manager/field_types.rb +152 -0
- data/lib/keeper_secrets_manager/folder_manager.rb +114 -0
- data/lib/keeper_secrets_manager/keeper_globals.rb +59 -0
- data/lib/keeper_secrets_manager/notation.rb +354 -0
- data/lib/keeper_secrets_manager/notation_enhancements.rb +67 -0
- data/lib/keeper_secrets_manager/storage.rb +254 -0
- data/lib/keeper_secrets_manager/totp.rb +140 -0
- data/lib/keeper_secrets_manager/utils.rb +196 -0
- data/lib/keeper_secrets_manager/version.rb +3 -0
- data/lib/keeper_secrets_manager.rb +38 -0
- metadata +82 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4c8972e0c2423186c5359c666369d46c3f4b4e600d2d8043d1d82c9e35415fdb
|
4
|
+
data.tar.gz: f0ce862b79e0d2aab3a5d2f7da349f6f843b6ce3384de6c713427d8d57cd1ab1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e08af6212050dbe119413eedee86d031e02b8f585c0e43e35e21ef5a5857cc468fdfcb5411039f508b64787521c654edae6d6728fe1f1853488275163cd4a062
|
7
|
+
data.tar.gz: 68be3a8220c8799676410c40f69f9284bf3e19b705d85ff94f27c3764c76cef814d6e9462deef1563a31620da0b6c911227906dcbf26a0abd39f723603e751bb
|
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.3.8
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [17.0.3] - 2025-06-25
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
- Cleaned up directory structure
|
12
|
+
- Removed development and debug files from distribution
|
13
|
+
- Professional gem organization
|
14
|
+
|
15
|
+
## [17.0.2] - 2025-06-25
|
16
|
+
|
17
|
+
### Security
|
18
|
+
- Removed hardcoded credentials from example files
|
19
|
+
- Updated all examples to use environment variables or placeholders
|
20
|
+
|
21
|
+
## [17.0.1] - 2025-06-25
|
22
|
+
|
23
|
+
### Fixed
|
24
|
+
- Added missing files to gem package (folder_manager, notation_enhancements, totp)
|
25
|
+
|
26
|
+
## [17.0.0] - 2025-06-25
|
27
|
+
|
28
|
+
### Added
|
29
|
+
- Initial release of Keeper Secrets Manager Ruby SDK
|
30
|
+
- Full compatibility with Keeper Secrets Manager API
|
31
|
+
- Dynamic record handling with JavaScript-style flexibility
|
32
|
+
- Support for all field types (login, password, url, host, etc.)
|
33
|
+
- File upload and download capabilities
|
34
|
+
- Folder management and hierarchy operations
|
35
|
+
- CRUD operations for records and folders
|
36
|
+
- Multiple storage backends (file, in-memory, environment, caching)
|
37
|
+
- Notation support for field access
|
38
|
+
- TOTP support (optional, requires base32 gem)
|
39
|
+
- Comprehensive error handling
|
40
|
+
- Ruby 2.6+ compatibility
|
41
|
+
|
42
|
+
### Security
|
43
|
+
- Zero-knowledge encryption using AES-GCM
|
44
|
+
- Secure key management
|
45
|
+
- SSL certificate verification
|
46
|
+
|
47
|
+
### Notes
|
48
|
+
- Version 17.0.0 to align with other Keeper SDKs
|
49
|
+
- No runtime dependencies (base32 is optional)
|
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify gem dependencies in keeper_secrets_manager.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :development, :test do
|
7
|
+
gem 'rspec', '~> 3.12'
|
8
|
+
gem 'rake', '~> 13.0'
|
9
|
+
gem 'simplecov', '~> 0.22'
|
10
|
+
gem 'webmock', '~> 3.18'
|
11
|
+
gem 'rubocop', '~> 1.12.0'
|
12
|
+
gem 'yard', '~> 0.9'
|
13
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Keeper Security, Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,305 @@
|
|
1
|
+
# Keeper Secrets Manager Ruby SDK
|
2
|
+
|
3
|
+
The Ruby SDK for Keeper Secrets Manager provides a flexible, dynamic interface for accessing and managing secrets stored in Keeper's zero-knowledge vault.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
- **Ruby 2.7+ Compatible**: Works with Chef, Puppet, and modern Ruby applications
|
8
|
+
- **Dynamic Record Handling**: JavaScript-style flexible records with no rigid class hierarchies
|
9
|
+
- **Minimal Dependencies**: Uses only Ruby standard library (no external runtime dependencies)
|
10
|
+
- **Comprehensive Crypto**: Full encryption/decryption support using OpenSSL
|
11
|
+
- **Multiple Storage Options**: In-memory, file-based, environment variables, and caching
|
12
|
+
- **Notation Support**: Access specific fields using `keeper://` URI notation
|
13
|
+
- **Field Helpers**: Optional convenience methods for common field types
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem 'keeper_secrets_manager'
|
21
|
+
```
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
|
25
|
+
```bash
|
26
|
+
$ bundle install
|
27
|
+
```
|
28
|
+
|
29
|
+
Or install it yourself as:
|
30
|
+
|
31
|
+
```bash
|
32
|
+
$ gem install keeper_secrets_manager
|
33
|
+
```
|
34
|
+
|
35
|
+
## Quick Start
|
36
|
+
|
37
|
+
### Initialize with One-Time Token
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
require 'keeper_secrets_manager'
|
41
|
+
|
42
|
+
# Initialize with one-time token
|
43
|
+
token = "US:ONE_TIME_TOKEN_HERE"
|
44
|
+
secrets_manager = KeeperSecretsManager.from_token(token)
|
45
|
+
|
46
|
+
# Retrieve secrets
|
47
|
+
records = secrets_manager.get_secrets
|
48
|
+
records.each do |record|
|
49
|
+
puts "#{record.title}: #{record.get_field_value_single('login')}"
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
### Initialize with Existing Configuration
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
# From config file
|
57
|
+
secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')
|
58
|
+
|
59
|
+
# From environment (reads KSM_* variables)
|
60
|
+
config = KeeperSecretsManager::Storage::EnvironmentStorage.new('KSM_')
|
61
|
+
secrets_manager = KeeperSecretsManager.new(config: config)
|
62
|
+
```
|
63
|
+
|
64
|
+
## Dynamic Record Creation
|
65
|
+
|
66
|
+
The Ruby SDK uses a flexible, JavaScript-style approach to records:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
# Create record with hash syntax
|
70
|
+
record = KeeperSecretsManager::Dto::KeeperRecord.new(
|
71
|
+
title: 'My Server',
|
72
|
+
type: 'login',
|
73
|
+
fields: [
|
74
|
+
{ 'type' => 'login', 'value' => ['admin'] },
|
75
|
+
{ 'type' => 'password', 'value' => ['SecurePass123!'] },
|
76
|
+
{ 'type' => 'url', 'value' => ['https://example.com'] },
|
77
|
+
{
|
78
|
+
'type' => 'host',
|
79
|
+
'value' => [{ 'hostName' => '192.168.1.1', 'port' => '22' }],
|
80
|
+
'label' => 'SSH Server'
|
81
|
+
}
|
82
|
+
],
|
83
|
+
custom: [
|
84
|
+
{ 'type' => 'text', 'label' => 'Environment', 'value' => ['Production'] }
|
85
|
+
]
|
86
|
+
)
|
87
|
+
|
88
|
+
# Dynamic field access
|
89
|
+
puts record.login # => "admin"
|
90
|
+
record.password = 'NewPassword123!'
|
91
|
+
|
92
|
+
# Set complex fields
|
93
|
+
record.set_field('address', {
|
94
|
+
'street1' => '123 Main St',
|
95
|
+
'city' => 'New York',
|
96
|
+
'state' => 'NY',
|
97
|
+
'zip' => '10001'
|
98
|
+
})
|
99
|
+
```
|
100
|
+
|
101
|
+
## Notation Support
|
102
|
+
|
103
|
+
Access specific field values using Keeper notation:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
# Get password from record
|
107
|
+
password = secrets_manager.get_notation("keeper://RECORD_UID/field/password")
|
108
|
+
|
109
|
+
# Get specific property from complex field
|
110
|
+
hostname = secrets_manager.get_notation("keeper://RECORD_UID/field/host[hostName]")
|
111
|
+
port = secrets_manager.get_notation("keeper://RECORD_UID/field/host[port]")
|
112
|
+
|
113
|
+
# Get custom field by label
|
114
|
+
env = secrets_manager.get_notation("keeper://RECORD_UID/custom_field/Environment")
|
115
|
+
|
116
|
+
# Access by record title
|
117
|
+
url = secrets_manager.get_notation("keeper://My Login/field/url")
|
118
|
+
```
|
119
|
+
|
120
|
+
## Field Type Helpers
|
121
|
+
|
122
|
+
Optional convenience methods for creating typed fields:
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
# Using field helpers
|
126
|
+
fields = [
|
127
|
+
KeeperSecretsManager::FieldTypes::Helpers.login('username'),
|
128
|
+
KeeperSecretsManager::FieldTypes::Helpers.password('SecurePass123!'),
|
129
|
+
KeeperSecretsManager::FieldTypes::Helpers.host(
|
130
|
+
hostname: '192.168.1.100',
|
131
|
+
port: 22
|
132
|
+
),
|
133
|
+
KeeperSecretsManager::FieldTypes::Helpers.name(
|
134
|
+
first: 'John',
|
135
|
+
last: 'Doe',
|
136
|
+
middle: 'Q'
|
137
|
+
)
|
138
|
+
]
|
139
|
+
|
140
|
+
record = KeeperSecretsManager::Dto::KeeperRecord.new(
|
141
|
+
title: 'Server with Helpers',
|
142
|
+
type: 'login',
|
143
|
+
fields: fields.map(&:to_h)
|
144
|
+
)
|
145
|
+
```
|
146
|
+
|
147
|
+
## Storage Options
|
148
|
+
|
149
|
+
### In-Memory Storage
|
150
|
+
```ruby
|
151
|
+
storage = KeeperSecretsManager::Storage::InMemoryStorage.new
|
152
|
+
```
|
153
|
+
|
154
|
+
### File Storage
|
155
|
+
```ruby
|
156
|
+
storage = KeeperSecretsManager::Storage::FileStorage.new('keeper_config.json')
|
157
|
+
```
|
158
|
+
|
159
|
+
### Environment Variables
|
160
|
+
```ruby
|
161
|
+
# Reads from KSM_* environment variables (read-only)
|
162
|
+
storage = KeeperSecretsManager::Storage::EnvironmentStorage.new('KSM_')
|
163
|
+
```
|
164
|
+
|
165
|
+
### Caching Storage
|
166
|
+
```ruby
|
167
|
+
# Wrap any storage with caching (600 second TTL)
|
168
|
+
base_storage = KeeperSecretsManager::Storage::FileStorage.new('config.json')
|
169
|
+
storage = KeeperSecretsManager::Storage::CachingStorage.new(base_storage, 600)
|
170
|
+
```
|
171
|
+
|
172
|
+
## CRUD Operations
|
173
|
+
|
174
|
+
### Create Record
|
175
|
+
```ruby
|
176
|
+
record = KeeperSecretsManager::Dto::KeeperRecord.new(
|
177
|
+
title: 'New Record',
|
178
|
+
type: 'login',
|
179
|
+
fields: [
|
180
|
+
{ 'type' => 'login', 'value' => ['user'] },
|
181
|
+
{ 'type' => 'password', 'value' => ['pass'] }
|
182
|
+
]
|
183
|
+
)
|
184
|
+
|
185
|
+
record_uid = secrets_manager.create_secret(record)
|
186
|
+
```
|
187
|
+
|
188
|
+
### Update Record
|
189
|
+
```ruby
|
190
|
+
# Get existing record
|
191
|
+
record = secrets_manager.get_secret_by_title("My Record")
|
192
|
+
|
193
|
+
# Update fields
|
194
|
+
record.set_field('password', 'NewPassword123!')
|
195
|
+
record.notes = "Updated on #{Time.now}"
|
196
|
+
|
197
|
+
# Save changes
|
198
|
+
secrets_manager.update_secret(record)
|
199
|
+
```
|
200
|
+
|
201
|
+
### Delete Records
|
202
|
+
```ruby
|
203
|
+
# Delete single record
|
204
|
+
secrets_manager.delete_secret('RECORD_UID')
|
205
|
+
|
206
|
+
# Delete multiple records
|
207
|
+
secrets_manager.delete_secret(['UID1', 'UID2', 'UID3'])
|
208
|
+
```
|
209
|
+
|
210
|
+
### Folder Operations
|
211
|
+
```ruby
|
212
|
+
# Get all folders
|
213
|
+
folders = secrets_manager.get_folders
|
214
|
+
|
215
|
+
# Create folder
|
216
|
+
folder_uid = secrets_manager.create_folder('New Folder', parent_uid: 'PARENT_UID')
|
217
|
+
|
218
|
+
# Update folder
|
219
|
+
secrets_manager.update_folder(folder_uid, 'Renamed Folder')
|
220
|
+
|
221
|
+
# Delete folder
|
222
|
+
secrets_manager.delete_folder(folder_uid, force: true)
|
223
|
+
|
224
|
+
# Folder hierarchy features
|
225
|
+
fm = secrets_manager.folder_manager
|
226
|
+
|
227
|
+
# Build folder tree structure
|
228
|
+
tree = fm.build_folder_tree
|
229
|
+
|
230
|
+
# Get folder path from root
|
231
|
+
path = secrets_manager.get_folder_path(folder_uid) # "Parent/Child/Grandchild"
|
232
|
+
|
233
|
+
# Find folder by name
|
234
|
+
folder = secrets_manager.find_folder_by_name("Finance")
|
235
|
+
folder = secrets_manager.find_folder_by_name("Finance", parent_uid: "parent_uid")
|
236
|
+
|
237
|
+
# Get folder relationships
|
238
|
+
ancestors = fm.get_ancestors(folder_uid) # [parent, grandparent, ...]
|
239
|
+
descendants = fm.get_descendants(folder_uid) # [children, grandchildren, ...]
|
240
|
+
|
241
|
+
# Print folder tree to console
|
242
|
+
fm.print_tree
|
243
|
+
```
|
244
|
+
|
245
|
+
## Error Handling
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
begin
|
249
|
+
records = secrets_manager.get_secrets
|
250
|
+
rescue KeeperSecretsManager::AuthenticationError => e
|
251
|
+
puts "Authentication failed: #{e.message}"
|
252
|
+
rescue KeeperSecretsManager::NetworkError => e
|
253
|
+
puts "Network error: #{e.message}"
|
254
|
+
rescue KeeperSecretsManager::Error => e
|
255
|
+
puts "General error: #{e.message}"
|
256
|
+
end
|
257
|
+
```
|
258
|
+
|
259
|
+
## Configuration
|
260
|
+
|
261
|
+
The SDK can be configured through various options:
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
secrets_manager = KeeperSecretsManager.new(
|
265
|
+
config: storage,
|
266
|
+
hostname: 'keepersecurity.eu', # EU datacenter
|
267
|
+
verify_ssl_certs: true, # Verify SSL certificates
|
268
|
+
logger: Logger.new(STDOUT), # Custom logger
|
269
|
+
log_level: Logger::DEBUG # Log level
|
270
|
+
)
|
271
|
+
```
|
272
|
+
|
273
|
+
## Development
|
274
|
+
|
275
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
|
276
|
+
|
277
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
278
|
+
|
279
|
+
## Testing
|
280
|
+
|
281
|
+
```bash
|
282
|
+
# Run all tests
|
283
|
+
bundle exec rake spec
|
284
|
+
|
285
|
+
# Run unit tests only
|
286
|
+
bundle exec rake unit
|
287
|
+
|
288
|
+
# Run with coverage
|
289
|
+
bundle exec rake coverage
|
290
|
+
|
291
|
+
# Run linter
|
292
|
+
bundle exec rubocop
|
293
|
+
```
|
294
|
+
|
295
|
+
## Contributing
|
296
|
+
|
297
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Keeper-Security/secrets-manager.
|
298
|
+
|
299
|
+
## License
|
300
|
+
|
301
|
+
The gem is available as open source under the terms of the MIT License.
|
302
|
+
|
303
|
+
## Support
|
304
|
+
|
305
|
+
For support, please visit https://docs.keeper.io/secrets-manager/ or contact sm@keepersecurity.com
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
|
6
|
+
task default: :spec
|
7
|
+
|
8
|
+
desc 'Run unit tests only'
|
9
|
+
RSpec::Core::RakeTask.new(:unit) do |t|
|
10
|
+
t.pattern = 'spec/**/unit/*_spec.rb'
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'Run integration tests only'
|
14
|
+
RSpec::Core::RakeTask.new(:integration) do |t|
|
15
|
+
t.pattern = 'spec/**/integration/*_spec.rb'
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'Run all tests with coverage'
|
19
|
+
task :coverage do
|
20
|
+
ENV['COVERAGE'] = 'true'
|
21
|
+
Rake::Task['spec'].invoke
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Run RuboCop'
|
25
|
+
task :rubocop do
|
26
|
+
sh 'bundle exec rubocop'
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'Run all quality checks'
|
30
|
+
task ci: [:rubocop, :spec]
|
@@ -0,0 +1,139 @@
|
|
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
|
@@ -0,0 +1,99 @@
|
|
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"
|