bitwarden-sdk-secrets 0.1.0
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/Rakefile +11 -0
- data/bitwarden-sdk-secrets.gemspec +47 -0
- data/lib/bitwarden-sdk-secrets.rb +56 -0
- data/lib/bitwarden_error.rb +9 -0
- data/lib/bitwarden_lib.rb +35 -0
- data/lib/command_runner.rb +15 -0
- data/lib/extended_schemas/schemas.rb +64 -0
- data/lib/linux-x64/libbitwarden_c.so +0 -0
- data/lib/macos-arm64/libbitwarden_c.dylib +0 -0
- data/lib/macos-x64/libbitwarden_c.dylib +0 -0
- data/lib/projects.rb +116 -0
- data/lib/schemas.rb +3450 -0
- data/lib/secrets.rb +124 -0
- data/lib/version.rb +5 -0
- data/lib/windows-x64/bitwarden_c.dll +0 -0
- data/sig/bitwarden-sdk.rbs +13 -0
- data/sig/bitwarden_settings.rbs +8 -0
- data/sig/command_runner.rbs +4 -0
- data/sig/projects_client.rbs +17 -0
- data/sig/sdk.rbs +3 -0
- data/sig/secrets_client.rbs +18 -0
- metadata +150 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a4a8efa2366ad5c6568ce9ec284857674c1b1730263bd538096a2861031ae833
|
4
|
+
data.tar.gz: 7e15ebee50e29c57357f958f1273fdda182035a490b555510cd95de0f49e14b0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ac31e0a25f1ee16b2db1e2949cca718cd268a4ad0b2f18c28ffee48b1cf3ab5d3855bb771869037f00161255529f8d0715f628197e5309391162bca94e799c79
|
7
|
+
data.tar.gz: 52e926afe59c3d545d0d5441dc2cb356491291a7ffffa6af2ef7a61006dbf6ab3eef8d6662faf87eb1811d4c5eaf17a5a8756627252304868fb3b589ab0070ea
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'bitwarden-sdk-secrets'
|
7
|
+
spec.version = BitwardenSDKSecrets::VERSION
|
8
|
+
spec.authors = ['Bitwarden Inc.']
|
9
|
+
spec.email = ['hello@bitwarden_sdk.com']
|
10
|
+
|
11
|
+
spec.summary = 'Bitwarden Secrets Manager SDK.'
|
12
|
+
spec.description = 'Ruby wrapper for Bitwarden secrets manager SDK.'
|
13
|
+
spec.homepage = 'https://bitwarden.com/products/secrets-manager/'
|
14
|
+
spec.required_ruby_version = '>= 3.0.0'
|
15
|
+
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
17
|
+
spec.metadata['source_code_uri'] = 'https://github.com/bitwarden/sdk'
|
18
|
+
spec.metadata['changelog_uri'] = 'https://github.com/bitwarden/sdk/blob/main/languages/ruby/CHANGELOG.md'
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
spec.files = Dir.chdir(__dir__) do
|
23
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
24
|
+
(File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git Gemfile])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
spec.files += Dir.glob('lib/linux-x64/**/*')
|
29
|
+
spec.files += Dir.glob('lib/macos-x64/**/*')
|
30
|
+
spec.files += Dir.glob('lib/windows-x64/**/*')
|
31
|
+
spec.files += Dir.glob('lib/macos-arm64/**/*')
|
32
|
+
spec.files += Dir.glob('lib/schemas.rb')
|
33
|
+
|
34
|
+
spec.bindir = 'exe'
|
35
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
36
|
+
spec.require_paths = ['lib']
|
37
|
+
|
38
|
+
# Uncomment to register a new dependency of your gem
|
39
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
40
|
+
spec.add_dependency 'dry-struct', '~> 1.6'
|
41
|
+
spec.add_dependency 'dry-types', '~> 1.7'
|
42
|
+
spec.add_dependency 'ffi', '~> 1.15'
|
43
|
+
spec.add_dependency 'json', '~> 2.6'
|
44
|
+
spec.add_dependency 'rake', '~> 13.0'
|
45
|
+
spec.add_dependency 'rubocop', '~> 1.21'
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'dry-types'
|
5
|
+
|
6
|
+
require_relative 'schemas'
|
7
|
+
require_relative 'extended_schemas/schemas'
|
8
|
+
require_relative 'command_runner'
|
9
|
+
require_relative 'bitwarden_lib'
|
10
|
+
require_relative 'bitwarden_error'
|
11
|
+
require_relative 'projects'
|
12
|
+
require_relative 'secrets'
|
13
|
+
|
14
|
+
module BitwardenSDKSecrets
|
15
|
+
class BitwardenSettings
|
16
|
+
attr_accessor :api_url, :identity_url
|
17
|
+
|
18
|
+
def initialize(api_url, identity_url)
|
19
|
+
# if api_url.nil? || identity_url.nil?
|
20
|
+
# raise ArgumentError, "api_url and identity_url cannot be nil"
|
21
|
+
# end
|
22
|
+
|
23
|
+
@api_url = api_url
|
24
|
+
@identity_url = identity_url
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class BitwardenClient
|
29
|
+
attr_reader :bitwarden, :project_client, :secrets_client
|
30
|
+
|
31
|
+
def initialize(bitwarden_settings)
|
32
|
+
client_settings = ClientSettings.new(
|
33
|
+
api_url: bitwarden_settings.api_url,
|
34
|
+
identity_url: bitwarden_settings.identity_url,
|
35
|
+
user_agent: 'Bitwarden RUBY-SDK',
|
36
|
+
device_type: nil
|
37
|
+
)
|
38
|
+
|
39
|
+
@bitwarden = BitwardenLib
|
40
|
+
@handle = @bitwarden.init(client_settings.to_dynamic.compact.to_json)
|
41
|
+
@command_runner = CommandRunner.new(@bitwarden, @handle)
|
42
|
+
@project_client = ProjectsClient.new(@command_runner)
|
43
|
+
@secrets_client = SecretsClient.new(@command_runner)
|
44
|
+
end
|
45
|
+
|
46
|
+
def access_token_login(access_token, state_file = nil)
|
47
|
+
access_token_request = AccessTokenLoginRequest.new(access_token: access_token, state_file: state_file)
|
48
|
+
@command_runner.run(SelectiveCommand.new(access_token_login: access_token_request))
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def free_mem
|
53
|
+
@bitwarden.free_mem(@handle)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ffi'
|
4
|
+
|
5
|
+
module BitwardenSDKSecrets
|
6
|
+
module BitwardenLib
|
7
|
+
extend FFI::Library
|
8
|
+
|
9
|
+
def self.mac_with_intel?
|
10
|
+
`uname -m`.strip == 'x86_64'
|
11
|
+
end
|
12
|
+
|
13
|
+
ffi_lib case RUBY_PLATFORM
|
14
|
+
when /darwin/
|
15
|
+
local_file = if mac_with_intel?
|
16
|
+
File.expand_path('macos-x64/libbitwarden_c.dylib', __dir__)
|
17
|
+
else
|
18
|
+
File.expand_path('macos-arm64/libbitwarden_c.dylib', __dir__)
|
19
|
+
end
|
20
|
+
File.exist?(local_file) ? local_file : File.expand_path('../../../../target/debug/libbitwarden_c.dylib', __dir__)
|
21
|
+
when /linux/
|
22
|
+
local_file = File.expand_path('linux-x64/libbitwarden_c.so', __dir__)
|
23
|
+
File.exist?(local_file) ? local_file : File.expand_path('../../../../target/debug/libbitwarden_c.so', __dir__)
|
24
|
+
when /mswin|mingw/
|
25
|
+
local_file = File.expand_path('windows-x64/bitwarden_c.dll', __dir__)
|
26
|
+
File.exist?(local_file) ? local_file : File.expand_path('../../../../target/debug/bitwarden_c.dll', __dir__)
|
27
|
+
else
|
28
|
+
raise "Unsupported platform: #{RUBY_PLATFORM}"
|
29
|
+
end
|
30
|
+
|
31
|
+
attach_function :init, [:string], :pointer
|
32
|
+
attach_function :run_command, %i[string pointer], :string
|
33
|
+
attach_function :free_mem, [:pointer], :void
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BitwardenSDKSecrets
|
4
|
+
class CommandRunner
|
5
|
+
def initialize(bitwarden_sdk, handle)
|
6
|
+
@bitwarden_sdk = bitwarden_sdk
|
7
|
+
@handle = handle
|
8
|
+
end
|
9
|
+
|
10
|
+
# @param [Dry-Struct] cmd
|
11
|
+
def run(cmd)
|
12
|
+
@bitwarden_sdk.run_command(cmd.to_json, @handle)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
module BitwardenSDKSecrets
|
3
|
+
class SelectiveCommand < Command
|
4
|
+
attribute :password_login, PasswordLoginRequest.optional.default(nil)
|
5
|
+
attribute :api_key_login, APIKeyLoginRequest.optional.default(nil)
|
6
|
+
attribute :access_token_login, AccessTokenLoginRequest.optional.default(nil)
|
7
|
+
attribute :get_user_api_key, SecretVerificationRequest.optional.default(nil)
|
8
|
+
attribute :fingerprint, FingerprintRequest.optional.default(nil)
|
9
|
+
attribute :sync, SyncRequest.optional.default(nil)
|
10
|
+
attribute :secrets, SecretsCommand.optional.default(nil)
|
11
|
+
attribute :projects, ProjectsCommand.optional.default(nil)
|
12
|
+
|
13
|
+
def to_dynamic
|
14
|
+
{
|
15
|
+
"passwordLogin" => password_login&.to_dynamic,
|
16
|
+
"apiKeyLogin" => api_key_login&.to_dynamic,
|
17
|
+
"accessTokenLogin" => access_token_login&.to_dynamic,
|
18
|
+
"getUserApiKey" => get_user_api_key&.to_dynamic,
|
19
|
+
"fingerprint" => fingerprint&.to_dynamic,
|
20
|
+
"sync" => sync&.to_dynamic,
|
21
|
+
"secrets" => secrets&.to_dynamic,
|
22
|
+
"projects" => projects&.to_dynamic,
|
23
|
+
}.compact
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class SelectiveProjectsCommand < ProjectsCommand
|
28
|
+
attribute :get, ProjectGetRequest.optional.default(nil)
|
29
|
+
attribute :create, ProjectCreateRequest.optional.default(nil)
|
30
|
+
attribute :list, ProjectsListRequest.optional.default(nil)
|
31
|
+
attribute :update, ProjectPutRequest.optional.default(nil)
|
32
|
+
attribute :delete, ProjectsDeleteRequest.optional.default(nil)
|
33
|
+
|
34
|
+
def to_dynamic
|
35
|
+
{
|
36
|
+
"get" => get&.to_dynamic,
|
37
|
+
"create" => create&.to_dynamic,
|
38
|
+
"list" => list&.to_dynamic,
|
39
|
+
"update" => update&.to_dynamic,
|
40
|
+
"delete" => delete&.to_dynamic,
|
41
|
+
}.compact
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class SelectiveSecretsCommand < SecretsCommand
|
46
|
+
attribute :get, SecretGetRequest.optional.default(nil)
|
47
|
+
attribute :get_by_ids, SecretsGetRequest.optional.default(nil)
|
48
|
+
attribute :create, SecretCreateRequest.optional.default(nil)
|
49
|
+
attribute :list, SecretIdentifiersRequest.optional.default(nil)
|
50
|
+
attribute :update, SecretPutRequest.optional.default(nil)
|
51
|
+
attribute :delete, SecretsDeleteRequest.optional.default(nil)
|
52
|
+
|
53
|
+
def to_dynamic
|
54
|
+
{
|
55
|
+
"get" => get&.to_dynamic,
|
56
|
+
"getByIds" => get_by_ids&.to_dynamic,
|
57
|
+
"create" => create&.to_dynamic,
|
58
|
+
"list" => list&.to_dynamic,
|
59
|
+
"update" => update&.to_dynamic,
|
60
|
+
"delete" => delete&.to_dynamic,
|
61
|
+
}.compact
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
data/lib/projects.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'bitwarden_error'
|
4
|
+
|
5
|
+
module BitwardenSDKSecrets
|
6
|
+
class ProjectsClient
|
7
|
+
def initialize(command_runner)
|
8
|
+
@command_runner = command_runner
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_project(project_name, organization_id)
|
12
|
+
project_create_request = ProjectCreateRequest.new(
|
13
|
+
project_create_request_name: project_name,
|
14
|
+
organization_id: organization_id
|
15
|
+
)
|
16
|
+
command = create_command(
|
17
|
+
create: project_create_request
|
18
|
+
)
|
19
|
+
response = parse_response(command)
|
20
|
+
|
21
|
+
projects_response = ResponseForProjectResponse.from_json!(response).to_dynamic
|
22
|
+
|
23
|
+
if projects_response.key?('success') && projects_response['success'] == true &&
|
24
|
+
projects_response.key?('data')
|
25
|
+
return projects_response['data']
|
26
|
+
end
|
27
|
+
|
28
|
+
error_response(projects_response)
|
29
|
+
end
|
30
|
+
|
31
|
+
def get(project_id)
|
32
|
+
project_get_request = ProjectGetRequest.new(id: project_id)
|
33
|
+
command = create_command(get: project_get_request)
|
34
|
+
response = parse_response(command)
|
35
|
+
|
36
|
+
projects_response = ResponseForProjectResponse.from_json!(response).to_dynamic
|
37
|
+
|
38
|
+
if projects_response.key?('success') && projects_response['success'] == true &&
|
39
|
+
projects_response.key?('data')
|
40
|
+
return projects_response['data']
|
41
|
+
end
|
42
|
+
|
43
|
+
error_response(projects_response)
|
44
|
+
end
|
45
|
+
|
46
|
+
def list_projects(organization_id)
|
47
|
+
project_list_request = ProjectsListRequest.new(organization_id: organization_id)
|
48
|
+
command = create_command(list: project_list_request)
|
49
|
+
response = parse_response(command)
|
50
|
+
|
51
|
+
projects_response = ResponseForProjectsResponse.from_json!(response).to_dynamic
|
52
|
+
|
53
|
+
if projects_response.key?('success') && projects_response['success'] == true &&
|
54
|
+
projects_response.key?('data') && projects_response['data'].key?('data')
|
55
|
+
return projects_response['data']['data']
|
56
|
+
end
|
57
|
+
|
58
|
+
error_response(projects_response)
|
59
|
+
end
|
60
|
+
|
61
|
+
def update_project(id, project_put_request_name, organization_id)
|
62
|
+
project_put_request = ProjectPutRequest.new(
|
63
|
+
id: id,
|
64
|
+
project_put_request_name: project_put_request_name,
|
65
|
+
organization_id: organization_id
|
66
|
+
)
|
67
|
+
command = create_command(
|
68
|
+
update: project_put_request
|
69
|
+
)
|
70
|
+
response = parse_response(command)
|
71
|
+
|
72
|
+
projects_response = ResponseForProjectResponse.from_json!(response).to_dynamic
|
73
|
+
|
74
|
+
if projects_response.key?('success') && projects_response['success'] == true &&
|
75
|
+
projects_response.key?('data')
|
76
|
+
return projects_response['data']
|
77
|
+
end
|
78
|
+
|
79
|
+
error_response(projects_response)
|
80
|
+
end
|
81
|
+
|
82
|
+
def delete_projects(ids)
|
83
|
+
project_delete_request = ProjectsDeleteRequest.new(ids: ids)
|
84
|
+
command = create_command(delete: project_delete_request)
|
85
|
+
response = parse_response(command)
|
86
|
+
|
87
|
+
projects_response = ResponseForProjectsDeleteResponse.from_json!(response).to_dynamic
|
88
|
+
|
89
|
+
if projects_response.key?('success') && projects_response['success'] == true &&
|
90
|
+
projects_response.key?('data') && projects_response['data'].key?('data')
|
91
|
+
return projects_response['data']['data']
|
92
|
+
end
|
93
|
+
|
94
|
+
error_response(projects_response)
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def error_response(response)
|
100
|
+
raise BitwardenError, response['errorMessage'] if response.key?('errorMessage')
|
101
|
+
|
102
|
+
raise BitwardenError, 'Error while getting response'
|
103
|
+
end
|
104
|
+
|
105
|
+
def create_command(commands)
|
106
|
+
SelectiveCommand.new(projects: SelectiveProjectsCommand.new(commands))
|
107
|
+
end
|
108
|
+
|
109
|
+
def parse_response(command)
|
110
|
+
response = @command_runner.run(command)
|
111
|
+
raise BitwardenError, 'Error getting response' if response.nil?
|
112
|
+
|
113
|
+
response
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|