Class: Passwordstate::Client

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

Constant Summary collapse

USER_AGENT =
"RubyPasswordstate/#{Passwordstate::VERSION}".freeze
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.



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

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



28
29
30
# File 'lib/passwordstate/client.rb', line 28

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

#auth_dataObject

Returns the value of attribute auth_data.



11
12
13
# File 'lib/passwordstate/client.rb', line 11

def auth_data
  @auth_data
end

#headersObject

Returns the value of attribute headers.



11
12
13
# File 'lib/passwordstate/client.rb', line 11

def headers
  @headers
end

#server_urlObject

Returns the value of attribute server_url.



11
12
13
# File 'lib/passwordstate/client.rb', line 11

def server_url
  @server_url
end

#timeoutObject

Returns the value of attribute timeout.



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

def timeout
  @timeout
end

#validate_certificateObject

Returns the value of attribute validate_certificate.



11
12
13
# File 'lib/passwordstate/client.rb', line 11

def validate_certificate
  @validate_certificate
end

Instance Method Details

#foldersObject



37
38
39
40
# File 'lib/passwordstate/client.rb', line 37

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

#hostsObject



42
43
44
45
# File 'lib/passwordstate/client.rb', line 42

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

#inspectObject



117
118
119
# File 'lib/passwordstate/client.rb', line 117

def inspect
  "#{to_s[0..-2]} #{instance_variables.reject { |k| %i[@auth_data @http @logger].include? k }.map { |k| "#{k}=#{instance_variable_get(k).inspect}" }.join ', '}>"
end

#loggerObject



24
25
26
# File 'lib/passwordstate/client.rb', line 24

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

#password_listsObject



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

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

#passwordsObject



47
48
49
# File 'lib/passwordstate/client.rb', line 47

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

#request(method, api_path, options = {}) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/passwordstate/client.rb', line 80

def request(method, api_path, options = {})
  uri = URI(server_url + "/#{api_type}/" + api_path)
  uri.query = URI.encode_www_form(options.fetch(:query)) if options.key? :query
  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'] = options.fetch(:reason) if options.key?(:reason) && 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

    raise Passwordstate::HTTPError.new_by_code(res_obj.code, req_obj, res_obj, data&.fetch('errors', []) || [])
  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



76
77
78
# File 'lib/passwordstate/client.rb', line 76

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

#valid?Boolean

Returns:

  • (Boolean)


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

def valid?
  version
  true
rescue StandardError
  false
end

#versionObject



63
64
65
66
67
68
69
70
# File 'lib/passwordstate/client.rb', line 63

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]}"
  end
end

#version?(compare) ⇒ Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/passwordstate/client.rb', line 72

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