passwordstate 0.0.3 → 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 +4 -4
- data/.github/workflows/ruby.yml +33 -0
- data/.gitignore +2 -1
- data/.gitlab-ci.yml +10 -7
- data/.rubocop.yml +6 -9
- data/CHANGELOG.md +11 -0
- data/README.md +64 -16
- data/Rakefile +2 -2
- data/lib/passwordstate/client.rb +55 -16
- data/lib/passwordstate/errors.rb +6 -1
- data/lib/passwordstate/resource.rb +131 -49
- data/lib/passwordstate/resource_list.rb +56 -42
- data/lib/passwordstate/resources/active_directory.rb +23 -0
- data/lib/passwordstate/resources/address_book.rb +28 -0
- data/lib/passwordstate/resources/document.rb +32 -3
- data/lib/passwordstate/resources/folder.rb +6 -3
- data/lib/passwordstate/resources/host.rb +2 -0
- data/lib/passwordstate/resources/password.rb +50 -15
- data/lib/passwordstate/resources/password_list.rb +41 -8
- data/lib/passwordstate/resources/permission.rb +2 -0
- data/lib/passwordstate/resources/privileged_account.rb +32 -0
- data/lib/passwordstate/resources/remote_site.rb +26 -0
- data/lib/passwordstate/resources/report.rb +2 -0
- data/lib/passwordstate/util.rb +22 -2
- data/lib/passwordstate/version.rb +3 -1
- data/lib/passwordstate.rb +4 -1
- data/passwordstate.gemspec +9 -3
- data/test/client_test.rb +39 -0
- data/test/fixtures/get_password.json +31 -0
- data/test/fixtures/get_password_list.json +42 -0
- data/test/fixtures/get_password_otp.json +5 -0
- data/test/fixtures/password_list_search_passwords.json +60 -0
- data/test/fixtures/update_password.json +31 -0
- data/test/fixtures/update_password_managed.json +8 -0
- data/test/passwordstate_test.rb +10 -2
- data/test/resources/password_list_test.rb +81 -0
- data/test/resources/password_test.rb +105 -0
- data/test/test_helper.rb +8 -0
- metadata +56 -15
@@ -1,57 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Passwordstate
|
2
|
-
# A simple resource DSL
|
4
|
+
# A simple resource DSL helper
|
5
|
+
#
|
6
|
+
# rubocop:disable Metrics/ClassLength This DSL class will be large
|
3
7
|
class Resource
|
4
8
|
attr_reader :client
|
5
9
|
|
6
|
-
|
7
|
-
|
10
|
+
# Update the object based off of up-to-date upstream data
|
11
|
+
# @return [Resource] self
|
12
|
+
def get(**query)
|
13
|
+
set! self.class.get(client, send(self.class.index_field), **query)
|
8
14
|
end
|
9
15
|
|
10
|
-
|
16
|
+
# Push any unapplied changes to the object
|
17
|
+
# @return [Resource] self
|
18
|
+
def put(body = {}, **query)
|
11
19
|
to_send = modified.merge(self.class.index_field => send(self.class.index_field))
|
12
|
-
set! self.class.put(client, to_send.merge(body), query).first
|
20
|
+
set! self.class.put(client, to_send.merge(body), **query).first
|
13
21
|
end
|
14
22
|
|
15
|
-
|
16
|
-
|
23
|
+
# Create the object based off of provided information
|
24
|
+
# @return [Resource] self
|
25
|
+
def post(body = {}, **query)
|
26
|
+
set! self.class.post(client, attributes.merge(body), **query)
|
17
27
|
end
|
18
28
|
|
19
|
-
|
20
|
-
|
29
|
+
# Delete the object
|
30
|
+
# @return [Resource] self
|
31
|
+
def delete(**query)
|
32
|
+
self.class.delete(client, send(self.class.index_field), **query)
|
21
33
|
end
|
22
34
|
|
23
35
|
def initialize(data)
|
24
36
|
@client = data.delete :_client
|
25
|
-
set! data, false
|
37
|
+
set! data, store_old: false
|
26
38
|
old
|
27
39
|
end
|
28
40
|
|
41
|
+
# Is the object stored on the Passwordstate server
|
29
42
|
def stored?
|
30
43
|
!send(self.class.index_field).nil?
|
31
44
|
end
|
32
45
|
|
46
|
+
# Check if the resource type is available on the connected Passwordstate server
|
33
47
|
def self.available?(_client)
|
34
48
|
true
|
35
49
|
end
|
36
50
|
|
37
|
-
|
51
|
+
# Retrieve all accessible instances of the resource type, requires the method :get
|
52
|
+
def self.all(client, **query)
|
53
|
+
raise NotAcceptableError, "Read is not implemented for #{self}" unless acceptable_methods.include? :get
|
54
|
+
|
38
55
|
path = query.fetch(:_api_path, api_path)
|
56
|
+
reason = query.delete(:_reason)
|
39
57
|
query = passwordstateify_hash query.reject { |k| k.to_s.start_with? '_' }
|
40
58
|
|
41
|
-
[client.request(:get, path, query: query)].flatten.map do |object|
|
59
|
+
[client.request(:get, path, query: query, reason: reason)].flatten.map do |object|
|
42
60
|
new object.merge(_client: client)
|
43
61
|
end
|
44
62
|
end
|
45
63
|
|
46
|
-
|
64
|
+
# Retrieve a specific instance of the resource type, requires the method :get
|
65
|
+
def self.get(client, object, **query)
|
66
|
+
raise NotAcceptableError, "Read is not implemented for #{self}" unless acceptable_methods.include? :get
|
67
|
+
|
47
68
|
object = object.send(object.class.send(index_field)) if object.is_a? Resource
|
48
69
|
|
49
70
|
return new _client: client, index_field => object if query[:_bare]
|
50
71
|
|
51
72
|
path = query.fetch(:_api_path, api_path)
|
73
|
+
reason = query.delete(:_reason)
|
52
74
|
query = passwordstateify_hash query.reject { |k| k.to_s.start_with? '_' }
|
53
75
|
|
54
|
-
resp = client.request(:get, "#{path}/#{object}", query: query).map do |data|
|
76
|
+
resp = client.request(:get, "#{path}/#{object}", query: query, reason: reason).map do |data|
|
55
77
|
new data.merge(_client: client)
|
56
78
|
end
|
57
79
|
return resp.first if resp.one? || resp.empty?
|
@@ -59,56 +81,82 @@ module Passwordstate
|
|
59
81
|
resp
|
60
82
|
end
|
61
83
|
|
62
|
-
|
84
|
+
# Create a new instance of the resource type, requires the method :post
|
85
|
+
def self.post(client, data, **query)
|
86
|
+
raise NotAcceptableError, "Create is not implemented for #{self}" unless acceptable_methods.include? :post
|
87
|
+
|
63
88
|
path = query.fetch(:_api_path, api_path)
|
89
|
+
reason = query.delete(:_reason)
|
64
90
|
data = passwordstateify_hash data
|
65
91
|
query = passwordstateify_hash query.reject { |k| k.to_s.start_with? '_' }
|
66
92
|
|
67
|
-
new [client.request(:post, path, body: data, query: query)].flatten.first.merge(_client: client)
|
93
|
+
new [client.request(:post, path, body: data, query: query, reason: reason)].flatten.first.merge(_client: client)
|
68
94
|
end
|
69
95
|
|
70
|
-
|
96
|
+
# Push new data to an instance of the resource type, requires the method :put
|
97
|
+
def self.put(client, data, **query)
|
98
|
+
raise NotAcceptableError, "Update is not implemented for #{self}" unless acceptable_methods.include? :put
|
99
|
+
|
71
100
|
path = query.fetch(:_api_path, api_path)
|
101
|
+
reason = query.delete(:_reason)
|
72
102
|
data = passwordstateify_hash data
|
73
103
|
query = passwordstateify_hash query.reject { |k| k.to_s.start_with? '_' }
|
74
104
|
|
75
|
-
client.request :put, path, body: data, query: query
|
105
|
+
client.request :put, path, body: data, query: query, reason: reason
|
76
106
|
end
|
77
107
|
|
78
|
-
|
108
|
+
# Delete an instance of the resource type, requires the method :delete
|
109
|
+
def self.delete(client, object, **query)
|
110
|
+
raise NotAcceptableError, "Delete is not implemented for #{self}" unless acceptable_methods.include? :delete
|
111
|
+
|
79
112
|
path = query.fetch(:_api_path, api_path)
|
113
|
+
reason = query.delete(:_reason)
|
80
114
|
query = passwordstateify_hash query.reject { |k| k.to_s.start_with? '_' }
|
81
115
|
|
82
116
|
object = object.send(object.class.send(index_field)) if object.is_a? Resource
|
83
|
-
client.request :delete, "#{path}/#{object}", query: query
|
84
|
-
end
|
85
|
-
|
86
|
-
def self.passwordstateify_hash(hash)
|
87
|
-
Hash[hash.map { |k, v| [ruby_to_passwordstate_field(k), v] }]
|
88
|
-
end
|
89
|
-
|
90
|
-
def api_path
|
91
|
-
self.class.instance_variable_get :@api_path
|
117
|
+
client.request :delete, "#{path}/#{object}", query: query, reason: reason
|
92
118
|
end
|
93
119
|
|
94
|
-
|
95
|
-
|
120
|
+
# Get a hash of all active attributes on the resource instance
|
121
|
+
#
|
122
|
+
# @param ignore_redact [Boolean] Should any normally redacted fields be displayed in clear-text
|
123
|
+
# @param atify [Boolean] Should the resulting hash be returned with instance variable names ('@'-prefixed)
|
124
|
+
# @option opts nil_as_string [Boolean] (resource dependent) Should nil values be treated as the empty string
|
125
|
+
def attributes(ignore_redact: true, atify: false, **opts)
|
96
126
|
nil_as_string = opts.fetch(:nil_as_string, self.class.nil_as_string)
|
97
|
-
|
127
|
+
(self.class.send(:accessor_field_names) + self.class.send(:read_field_names) + self.class.send(:write_field_names)).to_h do |field|
|
98
128
|
redact = self.class.send(:field_options)[field]&.fetch(:redact, false) && !ignore_redact
|
99
|
-
|
129
|
+
at_field = "@#{field}".to_sym
|
130
|
+
field = at_field if atify
|
131
|
+
value = instance_variable_get(at_field) unless redact
|
100
132
|
value = '[ REDACTED ]' if redact
|
101
133
|
value = '' if value.nil? && nil_as_string
|
102
134
|
[field, value]
|
103
|
-
end
|
135
|
+
end.compact
|
104
136
|
end
|
105
137
|
|
106
|
-
def
|
107
|
-
|
138
|
+
def pretty_print(pp)
|
139
|
+
pp.object_address_group(self) do
|
140
|
+
attrs = attributes(atify: true, nil_as_string: false, ignore_redact: false).compact
|
141
|
+
pp.seplist(attrs.keys.sort, -> { pp.text ',' }) do |v|
|
142
|
+
pp.breakable
|
143
|
+
v = v.to_s if v.is_a? Symbol
|
144
|
+
pp.text v
|
145
|
+
pp.text '='
|
146
|
+
pp.group(1) do
|
147
|
+
pp.breakable ''
|
148
|
+
pp.pp(attrs[v.to_sym])
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
108
152
|
end
|
109
153
|
|
110
154
|
protected
|
111
155
|
|
156
|
+
def api_path
|
157
|
+
self.class.instance_variable_get :@api_path
|
158
|
+
end
|
159
|
+
|
112
160
|
def modified
|
113
161
|
attribs = attributes
|
114
162
|
attribs.reject { |field| old[field] == attribs[field] }
|
@@ -122,7 +170,7 @@ module Passwordstate
|
|
122
170
|
@old ||= attributes.dup
|
123
171
|
end
|
124
172
|
|
125
|
-
def set!(data, store_old
|
173
|
+
def set!(data, store_old: true)
|
126
174
|
@old = attributes.dup if store_old
|
127
175
|
data = data.attributes if data.is_a? Passwordstate::Resource
|
128
176
|
data.each do |key, value|
|
@@ -133,8 +181,11 @@ module Passwordstate
|
|
133
181
|
|
134
182
|
if !value.nil? && opts&.key?(:is)
|
135
183
|
klass = opts.fetch(:is)
|
136
|
-
parsed_value = klass.send :parse, value rescue nil if klass.respond_to?
|
137
|
-
parsed_value ||= klass.send :new, value rescue nil if klass.respond_to? :
|
184
|
+
parsed_value = klass.send :parse, value rescue nil if klass.respond_to?(:parse)
|
185
|
+
parsed_value ||= klass.send :new, value rescue nil if klass.respond_to?(:new) && !klass.respond_to?(:parse)
|
186
|
+
elsif !value.nil? && opts&.key?(:convert)
|
187
|
+
convert = opts.fetch(:convert)
|
188
|
+
parsed_value = convert.call(value, direction: :from)
|
138
189
|
end
|
139
190
|
|
140
191
|
instance_variable_set "@#{field}".to_sym, parsed_value || value
|
@@ -145,26 +196,52 @@ module Passwordstate
|
|
145
196
|
class << self
|
146
197
|
alias search all
|
147
198
|
|
199
|
+
# Get/Set the API path for the resource type
|
148
200
|
def api_path(path = nil)
|
149
201
|
@api_path = path unless path.nil?
|
150
202
|
@api_path
|
151
203
|
end
|
152
204
|
|
205
|
+
# Get/Set the index field for the resource type
|
153
206
|
def index_field(field = nil)
|
154
207
|
@index_field = field unless field.nil?
|
155
208
|
@index_field
|
156
209
|
end
|
157
210
|
|
211
|
+
# Get/Set whether the resource type requires nil values to be handled as the empty string
|
158
212
|
def nil_as_string(opt = nil)
|
159
213
|
@nil_as_string = opt unless opt.nil?
|
160
214
|
@nil_as_string
|
161
215
|
end
|
162
216
|
|
217
|
+
# Get/Set acceptable CRUD methods for the resource type
|
218
|
+
def acceptable_methods(*meths)
|
219
|
+
if meths.empty?
|
220
|
+
@acceptable_methods || %i[post get put delete]
|
221
|
+
elsif meths.count == 1 && meths.to_s.upcase == meths.to_s
|
222
|
+
@acceptable_methods = []
|
223
|
+
meths = meths.first.to_s
|
224
|
+
@acceptable_methods << :post if meths.include? 'C'
|
225
|
+
@acceptable_methods << :get if meths.include? 'R'
|
226
|
+
@acceptable_methods << :put if meths.include? 'U'
|
227
|
+
@acceptable_methods << :delete if meths.include? 'D'
|
228
|
+
else
|
229
|
+
@acceptable_methods = meths
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Convert a hash from Ruby syntax to Passwordstate syntax
|
234
|
+
def passwordstateify_hash(hash)
|
235
|
+
hash.transform_keys { |k| ruby_to_passwordstate_field(k) }
|
236
|
+
end
|
237
|
+
|
238
|
+
# Convert a Passwordstate field name into Ruby syntax
|
163
239
|
def passwordstate_to_ruby_field(field)
|
164
240
|
opts = send(:field_options).find { |(_k, v)| v[:name] == field }
|
165
241
|
opts&.first || field.to_s.snake_case.to_sym
|
166
242
|
end
|
167
243
|
|
244
|
+
# Convert a Ruby field name into Passwordstate syntax
|
168
245
|
def ruby_to_passwordstate_field(field)
|
169
246
|
send(:field_options)[field]&.[](:name) || field.to_s.camel_case
|
170
247
|
end
|
@@ -225,18 +302,23 @@ module Passwordstate
|
|
225
302
|
end
|
226
303
|
end
|
227
304
|
end
|
305
|
+
# rubocop:enable Metrics/ClassLength
|
228
306
|
|
229
307
|
module Resources
|
230
|
-
autoload :
|
231
|
-
autoload :
|
232
|
-
autoload :
|
233
|
-
autoload :
|
234
|
-
autoload :
|
235
|
-
autoload :
|
236
|
-
autoload :Password,
|
237
|
-
autoload :
|
238
|
-
autoload :
|
239
|
-
autoload :
|
240
|
-
autoload :
|
308
|
+
autoload :ActiveDirectory, 'passwordstate/resources/active_directory'
|
309
|
+
autoload :AddressBook, 'passwordstate/resources/address_book'
|
310
|
+
autoload :Document, 'passwordstate/resources/document'
|
311
|
+
autoload :Folder, 'passwordstate/resources/folder'
|
312
|
+
autoload :FolderPermission, 'passwordstate/resources/folder'
|
313
|
+
autoload :Host, 'passwordstate/resources/host'
|
314
|
+
autoload :Password, 'passwordstate/resources/password'
|
315
|
+
autoload :PasswordList, 'passwordstate/resources/password_list'
|
316
|
+
autoload :PasswordListPermission, 'passwordstate/resources/password_list'
|
317
|
+
autoload :PasswordHistory, 'passwordstate/resources/password'
|
318
|
+
autoload :PasswordPermission, 'passwordstate/resources/password_list'
|
319
|
+
autoload :PrivilegedAccount, 'passwordstate/resources/privileged_account'
|
320
|
+
autoload :PrivilegedAccountPermission, 'passwordstate/resources/privileged_account'
|
321
|
+
autoload :Permission, 'passwordstate/resources/permission'
|
322
|
+
autoload :Report, 'passwordstate/resources/report'
|
241
323
|
end
|
242
324
|
end
|
@@ -1,45 +1,49 @@
|
|
1
|
-
|
2
|
-
class ResourceList < Array
|
3
|
-
Array.public_instance_methods(false).each do |method|
|
4
|
-
next if %i[reject select slice clear inspect].include?(method.to_sym)
|
5
|
-
|
6
|
-
class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
7
|
-
def #{method}(*args)
|
8
|
-
lazy_load unless @loaded
|
9
|
-
super
|
10
|
-
end
|
11
|
-
EVAL
|
12
|
-
end
|
1
|
+
# frozen_string_literal: true
|
13
2
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
lazy_load unless @loaded
|
18
|
-
data = super
|
19
|
-
self.clone.clear.concat(data)
|
20
|
-
end
|
21
|
-
EVAL
|
22
|
-
end
|
23
|
-
|
24
|
-
def inspect
|
25
|
-
lazy_load unless @loaded
|
26
|
-
super
|
27
|
-
end
|
3
|
+
module Passwordstate
|
4
|
+
class ResourceList
|
5
|
+
include Enumerable
|
28
6
|
|
29
7
|
attr_reader :client, :resource, :options
|
30
8
|
|
31
|
-
def initialize(
|
9
|
+
def initialize(resource, client:, **options)
|
32
10
|
@client = client
|
33
11
|
@resource = resource
|
34
12
|
@loaded = false
|
35
13
|
@options = options
|
14
|
+
@data = []
|
36
15
|
|
37
16
|
options[:only] = [options[:only]].flatten if options.key? :only
|
38
17
|
options[:except] = [options[:except]].flatten if options.key? :except
|
39
18
|
end
|
40
19
|
|
20
|
+
def pretty_print_instance_variables
|
21
|
+
instance_variables.reject { |k| %i[@client @data].include? k }.sort
|
22
|
+
end
|
23
|
+
|
24
|
+
def pretty_print(pp)
|
25
|
+
return pp.pp self if respond_to? :mocha_inspect
|
26
|
+
|
27
|
+
pp.pp_object(self)
|
28
|
+
end
|
29
|
+
|
30
|
+
alias inspect pretty_print_inspect
|
31
|
+
|
32
|
+
def each(&block)
|
33
|
+
lazy_load unless @loaded
|
34
|
+
|
35
|
+
return to_enum(__method__) { @data.size } unless block_given?
|
36
|
+
|
37
|
+
@data.each(&block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def [](index)
|
41
|
+
@data[index]
|
42
|
+
end
|
43
|
+
|
41
44
|
def clear
|
42
|
-
@
|
45
|
+
@data = []
|
46
|
+
@loaded = false
|
43
47
|
end
|
44
48
|
|
45
49
|
def reload
|
@@ -48,9 +52,12 @@ module Passwordstate
|
|
48
52
|
end
|
49
53
|
|
50
54
|
def load(entries)
|
51
|
-
clear
|
55
|
+
clear
|
56
|
+
entries.tap do |loaded|
|
52
57
|
loaded.sort! { |a, b| a.send(a.class.index_field) <=> b.send(b.class.index_field) } if options.fetch(:sort, true)
|
53
|
-
end
|
58
|
+
end
|
59
|
+
entries.each { |obj| @data << obj }
|
60
|
+
@loaded = true
|
54
61
|
self
|
55
62
|
end
|
56
63
|
|
@@ -74,58 +81,65 @@ module Passwordstate
|
|
74
81
|
obj
|
75
82
|
end
|
76
83
|
|
77
|
-
def search(query
|
84
|
+
def search(**query)
|
78
85
|
raise 'Operation not supported' unless operation_supported?(:search)
|
79
86
|
|
80
87
|
api_path = options.fetch(:search_path, resource.api_path)
|
81
88
|
query = options.fetch(:search_query, {}).merge(query)
|
82
89
|
|
83
|
-
resource.search(client, query.merge(_api_path: api_path))
|
90
|
+
resource.search(client, **query.merge(_api_path: api_path))
|
84
91
|
end
|
85
92
|
|
86
|
-
def all(query
|
93
|
+
def all(**query)
|
87
94
|
raise 'Operation not supported' unless operation_supported?(:all)
|
88
95
|
|
89
96
|
api_path = options.fetch(:all_path, resource.api_path)
|
90
97
|
query = options.fetch(:all_query, {}).merge(query)
|
91
98
|
|
92
|
-
load resource.all(client, query.merge(_api_path: api_path))
|
99
|
+
load resource.all(client, **query.merge(_api_path: api_path))
|
93
100
|
end
|
94
101
|
|
95
|
-
def get(id, query
|
102
|
+
def get(id, **query)
|
96
103
|
raise 'Operation not supported' unless operation_supported?(:get)
|
97
104
|
|
105
|
+
if query.empty? && !@data.empty?
|
106
|
+
existing = @data.find do |entry|
|
107
|
+
entry.send(entry.class.index_field) == id
|
108
|
+
end
|
109
|
+
return existing if existing
|
110
|
+
end
|
111
|
+
|
98
112
|
api_path = options.fetch(:get_path, resource.api_path)
|
99
113
|
query = options.fetch(:get_query, {}).merge(query)
|
100
114
|
|
101
|
-
resource.get(client, id, query.merge(_api_path: api_path))
|
115
|
+
resource.get(client, id, **query.merge(_api_path: api_path))
|
102
116
|
end
|
103
117
|
|
104
|
-
def post(data, query
|
118
|
+
def post(data, **query)
|
105
119
|
raise 'Operation not supported' unless operation_supported?(:post)
|
106
120
|
|
107
121
|
api_path = options.fetch(:post_path, resource.api_path)
|
108
122
|
query = options.fetch(:post_query, {}).merge(query)
|
109
123
|
|
110
|
-
resource.post(client, data, query.merge(_api_path: api_path))
|
124
|
+
resource.post(client, data, **query.merge(_api_path: api_path))
|
111
125
|
end
|
112
126
|
|
113
|
-
def put(data, query
|
127
|
+
def put(data, **query)
|
114
128
|
raise 'Operation not supported' unless operation_supported?(:put)
|
115
129
|
|
116
130
|
api_path = options.fetch(:put_path, resource.api_path)
|
117
131
|
query = options.fetch(:put_query, {}).merge(query)
|
118
132
|
|
119
|
-
resource.put(client, data, query.merge(_api_path: api_path))
|
133
|
+
resource.put(client, data, **query.merge(_api_path: api_path))
|
120
134
|
end
|
121
135
|
|
122
|
-
def delete(id, query
|
136
|
+
def delete(id, **query)
|
123
137
|
raise 'Operation not supported' unless operation_supported?(:delete)
|
124
138
|
|
125
139
|
api_path = options.fetch(:delete_path, resource.api_path)
|
126
140
|
query = options.fetch(:delete_query, {}).merge(query)
|
127
141
|
|
128
|
-
resource.delete(client, id, query.merge(_api_path: api_path))
|
142
|
+
resource.delete(client, id, **query.merge(_api_path: api_path))
|
129
143
|
end
|
130
144
|
|
131
145
|
private
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Passwordstate
|
4
|
+
module Resources
|
5
|
+
class ActiveDirectory < Passwordstate::Resource
|
6
|
+
api_path 'activedirectory'
|
7
|
+
|
8
|
+
index_field :ad_domain_id
|
9
|
+
|
10
|
+
accessor_fields :ad_domain_netbios, { name: 'ADDomainNetBIOS' },
|
11
|
+
:ad_domain_ldap, { name: 'ADDomainLDAP' },
|
12
|
+
:fqdn, { name: 'FQDN' },
|
13
|
+
:default_domain,
|
14
|
+
:pa_read_id, { name: 'PAReadID' },
|
15
|
+
:site_id, { name: 'SiteID' },
|
16
|
+
:used_for_authentication,
|
17
|
+
:protocol,
|
18
|
+
:domain_controller_fqdn, { name: 'DomainControllerFQDN' }
|
19
|
+
|
20
|
+
read_fields :ad_domain_id, { name: 'ADDomainID' }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Passwordstate
|
4
|
+
module Resources
|
5
|
+
class AddressBook < Passwordstate::Resource
|
6
|
+
api_path 'addressbook'
|
7
|
+
|
8
|
+
index_field :address_book_id
|
9
|
+
|
10
|
+
accessor_fields :first_name,
|
11
|
+
:surname,
|
12
|
+
:email_adress,
|
13
|
+
:company,
|
14
|
+
:business_phone,
|
15
|
+
:personal_phone,
|
16
|
+
:street,
|
17
|
+
:city,
|
18
|
+
:state,
|
19
|
+
:zipcode,
|
20
|
+
:country,
|
21
|
+
:notes,
|
22
|
+
:pass_phrase,
|
23
|
+
:global_contact
|
24
|
+
|
25
|
+
read_fields :address_book_id, { name: 'AddressBookID' }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Passwordstate
|
2
4
|
module Resources
|
3
5
|
class Document < Passwordstate::Resource
|
@@ -10,12 +12,39 @@ module Passwordstate
|
|
10
12
|
|
11
13
|
alias title document_name
|
12
14
|
|
13
|
-
def self.
|
14
|
-
client.
|
15
|
+
def self.all(client, store, **query)
|
16
|
+
super client, query.merge(_api_path: "#{api_path}/#{validate_store! store}")
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.search(client, store, **options)
|
20
|
+
all client, store, **options
|
15
21
|
end
|
16
22
|
|
17
23
|
def self.get(client, store, object)
|
18
|
-
client
|
24
|
+
super client, object, _api_path: "#{api_path}/#{validate_store! store}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.post(client, store, data, **query)
|
28
|
+
super client, data, query.merge(_api_path: "#{api_path}/#{validate_store! store}")
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.put(client, store, data, **query)
|
32
|
+
super client, data, query.merge(_api_path: "#{api_path}/#{validate_store! store}")
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.delete(client, store, object, **query)
|
36
|
+
super client, object, query.merge(_api_path: "#{api_path}/#{validate_store! store}")
|
37
|
+
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
private
|
41
|
+
|
42
|
+
def validate_store!(store)
|
43
|
+
raise ArgumentError, 'Store must be one of password, passwordlist, folder' \
|
44
|
+
unless %i[password passwordlist folder].include?(store.to_s.downcase.to_sym)
|
45
|
+
|
46
|
+
store.to_s.downcase.to_sym
|
47
|
+
end
|
19
48
|
end
|
20
49
|
end
|
21
50
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Passwordstate
|
2
4
|
module Resources
|
3
5
|
class Folder < Passwordstate::Resource
|
@@ -16,7 +18,8 @@ module Passwordstate
|
|
16
18
|
alias title folder_name
|
17
19
|
|
18
20
|
def password_lists
|
19
|
-
Passwordstate::ResourceList.new
|
21
|
+
Passwordstate::ResourceList.new Passwordstate::Resources::PasswordList,
|
22
|
+
client: client,
|
20
23
|
search_query: { tree_path: tree_path },
|
21
24
|
all_path: 'searchpasswordlists',
|
22
25
|
all_query: { tree_path: tree_path },
|
@@ -28,7 +31,7 @@ module Passwordstate
|
|
28
31
|
FolderPermission.new(_client: client, folder_id: folder_id)
|
29
32
|
end
|
30
33
|
|
31
|
-
def full_path(unix
|
34
|
+
def full_path(unix: false)
|
32
35
|
return tree_path.tr('\\', '/') if unix
|
33
36
|
|
34
37
|
tree_path
|
@@ -40,7 +43,7 @@ module Passwordstate
|
|
40
43
|
|
41
44
|
index_field :folder_id
|
42
45
|
|
43
|
-
read_fields :folder_id, { name: 'FolderID' }
|
46
|
+
read_fields :folder_id, { name: 'FolderID' }
|
44
47
|
end
|
45
48
|
end
|
46
49
|
end
|