require 'net/http'
require 'json'
require 'base64'
require 'openssl'

class Registry
   def getKeyValues (root)
        uri = URI.parse(ENV["CONSUL_URL"] + "/v1/kv/#{root}?recurse=true")
        http = prepareHttp(uri)

        request = Net::HTTP::Get.new(uri.request_uri)
        resp = http.request(request)

        if ( Integer(resp.code) != 200 )
            puts "-- KEY VALUE NOT FOUND! " + root
            abort("Problem reading registry, response code #{resp.code}")
        else
            response = []
            result = JSON.parse(resp.body)
            result.each() do |item|
              response.push({item["Key"] => Base64.decode64(item["Value"])})
            end
            return JSON.generate(response)
        end
   end

   def getKeyValue (key)

        uri = URI.parse(ENV["CONSUL_URL"] + "/v1/kv/#{key}")
        http = prepareHttp(uri)

        request = Net::HTTP::Get.new(uri.request_uri)
        resp = http.request(request)

        if Integer(resp.code) != 200
            puts "-- KEY VALUE NOT FOUND! " + key
            abort("Problem reading registry, response code #{resp.code}")
        end

        result = JSON.parse(resp.body)
        return Base64.decode64(result[0]["Value"])
   end

   def setKeyValue (root, key, value)

        uri = URI.parse(ENV["CONSUL_URL"] + "/v1/kv/#{root}/#{key}")
        http = prepareHttp(uri)

        request = Net::HTTP::Put.new(uri.request_uri)
        request.body = "#{value}";
        resp = http.request(request)

        if Integer(resp.code) != 200
            puts "-- KEY VALUE NOT SAVED! #{root} #{key}"
            abort("Problem adding to registry, response code #{resp.code}")
        end
   end

   def exists (key)
        uri = URI.parse(ENV["CONSUL_URL"] + "/v1/kv/#{key}")
        http = prepareHttp(uri)

        request = Net::HTTP::Get.new(uri.request_uri)
        resp = http.request(request)

        if Integer(resp.code) == 200
            return true
        else
            return false
        end
   end

   def deleteDirectory (root)
        uri = URI.parse(ENV["CONSUL_URL"] + "/v1/kv/#{root}?recurse=true")
        http = prepareHttp(uri)

        request = Net::HTTP::Delete.new(uri.request_uri)
        resp = http.request(request)

        if Integer(resp.code) != 200
            puts "-- KEY NOT DELETED! " + root
            abort("Response code #{resp.code}")
        end
   end

   def registerDirectory (root)
        uri = URI.parse(ENV["CONSUL_URL"] + "/v1/kv/#{root}?dir=true")
        http = prepareHttp(uri)

        request = Net::HTTP::Put.new(uri.request_uri)
        resp = http.request(request)

        if Integer(resp.code) > 202
            puts "-- KEY DIRECTORY NOT SAVED! #{root}"
            abort("Problem adding to registry, response code #{resp.code}")
        end
   end

   def register (root, key, value)
        setKeyValue root, key, value
   end

   def getSecret (key)

        uri = URI.parse(ENV["VAULT_URL"] + "/v1/secret/#{key}")
        http = prepareHttpForVault(uri)

        request = Net::HTTP::Get.new(uri.request_uri)
        request['X-Vault-Token'] = ENV["VAULT_TOKEN"]
        resp = http.request(request)

        if Integer(resp.code) != 200
            puts "-- UNABLE TO GET SECRET! #{key}"
            abort("Problem getting secret from vault, response code #{resp.code}")
        end
        return JSON.parse(resp.body)['data']
   end

   def setVaultRecord (key, value)

        uri = URI.parse(ENV["VAULT_URL"] + "/v1/#{key}")
        http = prepareHttpForVault(uri)

        request = Net::HTTP::Put.new(uri.request_uri)
        request['Content-Type'] = 'application/json'
        request['X-Vault-Token'] = ENV["VAULT_TOKEN"]
        request.body = "#{value}";
        resp = http.request(request)

        if Integer(resp.code) != 204
            puts "-- VAULT RECORD NOT SAVED! #{key}"
            abort("Problem adding to vault, response code #{resp.code}")
        end
   end

   def setSecret (key, value)

        uri = URI.parse(ENV["VAULT_URL"] + "/v1/secret/#{key}")
        http = prepareHttpForVault(uri)

        request = Net::HTTP::Put.new(uri.request_uri)
        request['Content-Type'] = 'application/json'
        request['X-Vault-Token'] = ENV["VAULT_TOKEN"]
        request.body = "#{value}";
        resp = http.request(request)

        if Integer(resp.code) != 204
            puts "-- SECRET NOT SAVED! #{key}"
            abort("Problem adding to vault, response code #{resp.code}")
        end
   end

    def prepareHttp (uri)
        http = Net::HTTP.new(uri.host, uri.port)

        if (Canzea::config[:consul_tls])
            pemCert = File.read(Canzea::config[:consul_tls_cert_file])
            pemKey = File.read(Canzea::config[:consul_tls_key_file])

            http.use_ssl = true
            http.ca_file = Canzea::config[:consul_tls_ca_file]
            http.cert = OpenSSL::X509::Certificate.new(pemCert)
            http.key = OpenSSL::PKey::RSA.new(pemKey)
            http.verify_mode = OpenSSL::SSL::VERIFY_PEER
            # http.set_debug_output($stdout)
            http.ssl_version = :SSLv23
        end

        return http
    end

    def prepareHttpForVault (uri)
        http = Net::HTTP.new(uri.host, uri.port)

        if (Canzea::config[:consul_tls])
            pemCert = File.read(Canzea::config[:vault_tls_cert_file])
            pemKey = File.read(Canzea::config[:vault_tls_key_file])

            http.use_ssl = true
            http.ca_file = Canzea::config[:consul_tls_ca_file]
            http.cert = OpenSSL::X509::Certificate.new(pemCert)
            http.key = OpenSSL::PKey::RSA.new(pemKey)
            http.verify_mode = OpenSSL::SSL::VERIFY_PEER
            # http.set_debug_output($stdout)
            http.ssl_version = :SSLv23
        end

        return http
    end

end