class Keepasshttp

At the moment everything is in this one class as the “logic” is manageable

Constants

VERSION

Attributes

id[R]
port[RW]
session[R]

Public Class Methods

connect(**params) click to toggle source
# File lib/keepasshttp.rb, line 22
def self.connect(**params)
  kee = new(**params)
  kee.login
  kee
end
new(port: 19_455, key_store: false) click to toggle source
# File lib/keepasshttp.rb, line 33
def initialize(port: 19_455, key_store: false)
  @port = port
  @session = false
  init_keystore(key_store) if key_store
end

Public Instance Methods

cached_login() click to toggle source
# File lib/keepasshttp.rb, line 79
def cached_login
  cache = @key_store.load
  @key = cache[:key]
  @id = cache[:id]
  new_iv
  ping
end
credentials_for(url) click to toggle source
# File lib/keepasshttp.rb, line 47
def credentials_for(url)
  ping

  enc_url = encrypt(url, iv: new_iv)
  json = http('get-logins', Url: enc_url)
  iv = json['Nonce']
  json['Entries'].map do |dataset|
    dataset.map do |key, val|
      [key, decrypt(val, iv: iv)]
    end.to_h
  end
end
init_keystore(key_store) click to toggle source
# File lib/keepasshttp.rb, line 39
def init_keystore(key_store)
  @key_store = if key_store.is_a?(Hash)
                 KeyStore::External.new(key_store)
               else
                 KeyStore.const_get(key_store)
               end
end
login() click to toggle source
# File lib/keepasshttp.rb, line 60
def login
  return true if @session

  @session = OpenSSL::Cipher.new('AES-256-CBC')
  session.encrypt

  return cached_login if @key_store&.available?

  @key = session.random_key
  new_iv

  json = http(:associate, Key: @key.to_base64)
  return false unless json

  @id = json['Id']

  @key_store&.save(id: @id, key: @key)
end
ping() click to toggle source
# File lib/keepasshttp.rb, line 87
def ping
  http 'test-associate'
end

Private Instance Methods

decrypt(string, iv:) click to toggle source
# File lib/keepasshttp.rb, line 127
def decrypt(string, iv:)
  session.decrypt
  session.key = @key
  session.iv = iv.unpack1('m*')

  session.update(string.unpack1('m*')) + session.final
end
encrypt(val, iv:) click to toggle source
# File lib/keepasshttp.rb, line 119
def encrypt(val, iv:)
  session.encrypt
  session.key = @key
  session.iv = iv

  (session.update(val) + session.final).to_base64
end
http(request_type, params = {}) click to toggle source
# File lib/keepasshttp.rb, line 93
def http(request_type, params = {})
  params = { RequestType: request_type, TriggerUnlock: false }.merge(params)
  params[:Id] ||= @id if @id
  params[:Verifier] ||= @verifier if @verifier
  params[:Nonce] ||= @nonce if @nonce

  success?(
    Net::HTTP.post(URI("http://localhost:#{port}/"), params.to_json,
                   'Content-Type' => 'application/json')
  )
end
new_iv() click to toggle source
# File lib/keepasshttp.rb, line 112
def new_iv
  iv = session.random_iv
  @nonce = iv.to_base64
  @verifier = encrypt(iv.to_base64, iv: iv)
  iv
end
success?(resp) click to toggle source
# File lib/keepasshttp.rb, line 105
def success?(resp)
  json = JSON.parse(resp.body)
  return json if resp.code =~ /^2..$/ && json['Success']

  raise(json['Error'] || resp.body)
end