Class: Passwordstate::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/passwordstate/client.rb

Constant Summary collapse

USER_AGENT =
"RubyPasswordstate/#{Passwordstate::VERSION}"
DEFAULT_HEADERS =
{
  'accept' => 'application/json',
  'user-agent' => USER_AGENT
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(url, options = {}) ⇒ Client

Returns a new instance of Client.



17
18
19
20
21
22
23
24
# File 'lib/passwordstate/client.rb', line 17

def initialize(url, options = {})
  @server_url = URI(url)
  @validate_certificate = true
  @headers = DEFAULT_HEADERS
  @auth_data = options.select { |k, _v| %i[apikey username password].include? k }
  @api_type = options.fetch(:api_type) if options.key? :api_type
  @timeout = options.fetch(:timeout, 15)
end

Instance Attribute Details

#api_typeObject



30
31
32
# File 'lib/passwordstate/client.rb', line 30

def api_type
  @api_type || (auth_data.key?(:apikey) ? :api : :winapi)
end

#auth_dataObject

Returns the value of attribute auth_data.



13
14
15
# File 'lib/passwordstate/client.rb', line 13

def auth_data
  @auth_data
end

#headersObject

Returns the value of attribute headers.



13
14
15
# File 'lib/passwordstate/client.rb', line 13

def headers
  @headers
end

#server_urlObject

Returns the value of attribute server_url.



13
14
15
# File 'lib/passwordstate/client.rb', line 13

def server_url
  @server_url
end

#timeoutObject

Returns the value of attribute timeout.



14
15
16
# File 'lib/passwordstate/client.rb', line 14

def timeout
  @timeout
end

#validate_certificateObject

Returns the value of attribute validate_certificate.



13
14
15
# File 'lib/passwordstate/client.rb', line 13

def validate_certificate
  @validate_certificate
end

Instance Method Details

#address_bookObject



39
40
41
42
# File 'lib/passwordstate/client.rb', line 39

def address_book
  ResourceList.new Passwordstate::Resources::AddressBook,
                   client: self
end

#foldersObject



44
45
46
47
48
# File 'lib/passwordstate/client.rb', line 44

def folders
  ResourceList.new Passwordstate::Resources::Folder,
                   client: self,
                   only: %i[all search post]
end

#hostsObject



50
51
52
53
54
# File 'lib/passwordstate/client.rb', line 50

def hosts
  ResourceList.new Passwordstate::Resources::Host,
                   client: self,
                   except: %i[search put]
end

#loggerObject



26
27
28
# File 'lib/passwordstate/client.rb', line 26

def logger
  @logger ||= Logging.logger[self]
end

#password_listsObject



61
62
63
64
65
# File 'lib/passwordstate/client.rb', line 61

def password_lists
  ResourceList.new Passwordstate::Resources::PasswordList,
                   client: self,
                   except: %i[put delete]
end

#passwordsObject



56
57
58
59
# File 'lib/passwordstate/client.rb', line 56

def passwords
  ResourceList.new Passwordstate::Resources::Password,
                   client: self
end

#pretty_print(pp) ⇒ Object



144
145
146
147
148
# File 'lib/passwordstate/client.rb', line 144

def pretty_print(pp)
  return pp.pp self if respond_to? :mocha_inspect

  pp.pp_object self
end

#pretty_print_instance_variablesObject



140
141
142
# File 'lib/passwordstate/client.rb', line 140

def pretty_print_instance_variables
  instance_variables.reject { |k| %i[@auth_data @http @logger].include? k }.sort
end

#request(method, api_path, query: nil, reason: nil, **options) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/passwordstate/client.rb', line 101

def request(method, api_path, query: nil, reason: nil, **options)
  uri = URI(server_url + "/#{api_type}/" + api_path)
  uri.query = URI.encode_www_form(query) unless query.nil?
  uri.query = nil if uri.query.nil? || uri.query.empty?

  req_obj = Net::HTTP.const_get(method.to_s.capitalize.to_sym).new uri
  if options.key? :body
    req_obj.body = options.fetch(:body)
    req_obj.body = req_obj.body.to_json unless req_obj.body.is_a?(String)
    req_obj['content-type'] = 'application/json'
  end

  req_obj.ntlm_auth(auth_data[:username], auth_data[:password]) if api_type == :winapi
  headers.each { |h, v| req_obj[h] = v }
  req_obj['APIKey'] = auth_data[:apikey] if api_type == :api
  req_obj['Reason'] = reason if !reason.nil? && version?('>= 8.4.8449')

  print_http req_obj
  res_obj = http.request req_obj
  print_http res_obj

  return true if res_obj.is_a? Net::HTTPNoContent

  data = JSON.parse(res_obj.body) rescue nil
  if data
    return data if res_obj.is_a? Net::HTTPSuccess

    # data = data.first if data.is_a? Array
    # parsed = data.fetch('errors', []) if data.is_a?(Hash) && data.key?('errors')
    parsed = [data].flatten

    raise Passwordstate::HTTPError.new_by_code(res_obj.code, req_obj, res_obj, parsed || [])
  else
    return res_obj.body if res_obj.is_a?(Net::HTTPSuccess) && options.fetch(:allow_html, true)

    raise Passwordstate::HTTPError.new_by_code(res_obj.code, req_obj, res_obj, [{ 'message' => res_obj.body }])
  end
end

#require_version(compare) ⇒ Object



92
93
94
95
96
97
98
99
# File 'lib/passwordstate/client.rb', line 92

def require_version(compare)
  if version.nil?
    logger.debug 'Unable to detect Passwordstate version, assuming recent enough.'
    return true
  end

  raise "Your version of Passwordstate (#{version}) doesn't support the requested feature" unless version? compare
end

#valid?Boolean

Returns:

  • (Boolean)


67
68
69
70
71
72
# File 'lib/passwordstate/client.rb', line 67

def valid?
  version
  true
rescue StandardError
  false
end

#versionObject



74
75
76
77
78
79
80
81
# File 'lib/passwordstate/client.rb', line 74

def version
  @version ||= begin
    html = request(:get, '', allow_html: true)
    version = html.find_line { |line| line.include? '<span>V</span>' }
    version = />(\d\.\d) \(Build (.+)\)</.match(version)
    "#{version[1]}.#{version[2]}" if version
  end
end

#version?(compare) ⇒ Boolean

Returns:

  • (Boolean)


83
84
85
86
87
88
89
90
# File 'lib/passwordstate/client.rb', line 83

def version?(compare)
  if version.nil?
    logger.debug 'Unable to detect Passwordstate version, assuming recent enough.'
    return true
  end

  Gem::Dependency.new(to_s, compare).match?(to_s, version)
end