class Passwordstate::Client
Constants
- DEFAULT_HEADERS
- USER_AGENT
Attributes
api_type[W]
auth_data[RW]
headers[RW]
server_url[RW]
timeout[R]
validate_certificate[RW]
Public Class Methods
new(url, options = {})
click to toggle source
# 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
Public Instance Methods
api_type()
click to toggle source
# File lib/passwordstate/client.rb, line 28 def api_type @api_type || (auth_data.key?(:apikey) ? :api : :winapi) end
folders()
click to toggle source
# File lib/passwordstate/client.rb, line 37 def folders ResourceList.new self, Passwordstate::Resources::Folder, only: %i[all search post] end
hosts()
click to toggle source
# File lib/passwordstate/client.rb, line 42 def hosts ResourceList.new self, Passwordstate::Resources::Host, except: %i[search put] end
inspect()
click to toggle source
# 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
logger()
click to toggle source
# File lib/passwordstate/client.rb, line 24 def logger @logger ||= Logging.logger[self] end
password_lists()
click to toggle source
# File lib/passwordstate/client.rb, line 51 def password_lists ResourceList.new self, Passwordstate::Resources::PasswordList, except: %i[put delete] end
passwords()
click to toggle source
# File lib/passwordstate/client.rb, line 47 def passwords ResourceList.new self, Passwordstate::Resources::Password end
request(method, api_path, options = {})
click to toggle source
# 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)
click to toggle source
# 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
timeout=(sec)
click to toggle source
# File lib/passwordstate/client.rb, line 32 def timeout=(sec) @timeout = sec @http.read_timeout = sec if @http end
valid?()
click to toggle source
# File lib/passwordstate/client.rb, line 56 def valid? version true rescue StandardError false end
version()
click to toggle source
# 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)
click to toggle source
# File lib/passwordstate/client.rb, line 72 def version?(compare) Gem::Dependency.new(to_s, compare).match?(to_s, version) end
Private Instance Methods
http()
click to toggle source
# File lib/passwordstate/client.rb, line 123 def http @http ||= Net::HTTP.new server_url.host, server_url.port return @http if @http.active? @http.read_timeout = @timeout if @timeout @http.use_ssl = server_url.scheme == 'https' @http.verify_mode = validate_certificate ? ::OpenSSL::SSL::VERIFY_NONE : nil @http.start end
print_http(http, truncate = true)
click to toggle source
# File lib/passwordstate/client.rb, line 133 def print_http(http, truncate = true) return unless logger.debug? if http.is_a? Net::HTTPRequest dir = '>' logger.debug "#{dir} Sending a #{http.method} request to `#{http.path}`:" else dir = '<' logger.debug "#{dir} Received a #{http.code} #{http.message} response:" end http.to_hash.map { |k, v| "#{k}: #{%w[authorization apikey].include?(k.downcase) ? '[redacted]' : v.join(', ')}" }.each do |h| logger.debug "#{dir} #{h}" end logger.debug dir return if http.body.nil? clean_body = JSON.parse(http.body) rescue nil if clean_body clean_body = clean_body.each { |k, v| v.replace('[ REDACTED ]') if k.is_a?(String) && %w[password apikey].include?(k.downcase) }.to_json if http.body else clean_body = http.body end clean_body = clean_body.slice(0..2000) + "... [truncated, #{clean_body.length} Bytes total]" if truncate && clean_body.length > 2000 logger.debug "#{dir} #{clean_body}" if clean_body end