class VChainClient::BlockstackClient

Constants

MASTER_ECC_PUBLIC_KEY

Public Class Methods

new(config) click to toggle source
# File lib/vchain_client/blockstack_client.rb, line 15
def initialize(config)
   @config = config

   @log = Log4r::Logger["vchain_client"]
end

Public Instance Methods

checkBlockstackRecord(blockstack_id, type) click to toggle source
# File lib/vchain_client/blockstack_client.rb, line 96
def checkBlockstackRecord(blockstack_id, type)

        if @log.debug?
                @log.debug("[Blockstack.checkBlockstackRecord] input:")
                @log.debug("-> blockstack_id: #{blockstack_id}")
                @log.debug("-> type: #{type}")
        end

        record = nil

        begin
                
                record = self.getBlockstackRecord(blockstack_id)

        rescue => e

               if @log.error?
                       @log.error("[Blockstack.checkBlockstackRecord] getBlockstackRecord raised exception:")
                       @log.error("#{e.class}, #{e.message}")
                       @log.error("-> blockstack_id: #{blockstack_id}")
                       @log.error("-> type: #{type}")
                       @log.error("--> blockstack_id: #{blockstack_id}")
               end

                raise e
        end

        if record == nil
                if @log.error?
                       @log.error("[Blockstack.checkBlockstackRecord] failed to retrieve record")
                       @log.error("-> blockstack_id: #{blockstack_id}")
                       @log.error("-> type: #{type}")
                       @log.error("--> blockstack_id: #{blockstack_id}")
                end

                return false
        end

        cryptoHelper = VChainClient::Crypto.new(@config)

        if @log.debug?
                @log.debug("[Blockstack.checkBlockstackRecord] Crypto initialized")
        end

        if record != nil

                if record.key?("ecc_pubkey")

                        if record.key?("vchain_role")
                                
                                if record["vchain_role"] != type
                                     if @log.error?
                                             @log.error("[Blockstack.checkBlockstackRecord] type mismatch")
                                            @log.error("-> blockstack_id: #{blockstack_id}")
                                            @log.error("-> type: #{type}")
                                            @log.error("--> '"+ record["vchain_role"] +"'")
                                     end     

                                        return false
                                end

                                if !record.key?("validator_blockstack_id")
                                     if @log.error?
                                             @log.error("[Blockstack.checkBlockstackRecord] record doesn't have 'validator_blockstack_id' field")
                                            @log.error("-> blockstack_id: #{blockstack_id}")
                                            @log.error("-> type: #{type}")
                                     end     

                                        return false
                                end

                                validator_blockstack_id = record["validator_blockstack_id"]

                             if @log.debug?
                                     @log.debug("[Blockstack.checkBlockstackRecord] record's vchain_role is '"+ record["vchain_role"] +"'")
                             end

                                 if record["vchain_role"] != 'validator'

                                    if @log.debug?
                                            @log.debug("[Blockstack.checkBlockstackRecord] going to check validator for #{blockstack_id}, validator_id: #{validator_blockstack_id}")
                                    end

                                    begin

                                                if !self.checkValidator(validator_blockstack_id)

                                                           if @log.error?
                                                                   @log.error("[Blockstack.checkBlockstackRecord] failed to check validator")
                                                                  @log.error("-> blockstack_id: #{blockstack_id}")
                                                                  @log.error("-> type: #{type}")
                                                                  @log.error("--> validator_blockstack_id: #{validator_blockstack_id}")
                                                           end  

                                                        return false
                                                end

                                         rescue => e
                                                   if @log.error?
                                                           @log.error("[Blockstack.checkBlockstackRecord] checkValidator raised exception:")
                                                           @log.error("#{e.class}, #{e.message}")
                                                           @log.error("-> blockstack_id: #{blockstack_id}")
                                                           @log.error("-> type: #{type}")
                                                           @log.error("--> validator_blockstack_id: #{validator_blockstack_id}")
                                                   end

                                                 raise e
                                         end

                                 end

                                 validator_ecc_pub_key = nil
                                 if record["vchain_role"] != 'validator'

                                         begin
                                                 
                                                 validator_ecc_pub_key = self.getPublicKeyECC(validator_blockstack_id)

                                         rescue => e
                                                   if @log.error?
                                                           @log.error("[Blockstack.checkBlockstackRecord] getPublicKeyECC raised exception:")
                                                           @log.error("#{e.class}, #{e.message}")
                                                           @log.error("-> blockstack_id: #{blockstack_id}")
                                                           @log.error("-> type: #{type}")
                                                           @log.error("--> validator_blockstack_id: #{validator_blockstack_id}")
                                                   end

                                                 raise e
                                         end

                                 else
                                         validator_ecc_pub_key = MASTER_ECC_PUBLIC_KEY;
                                 end

                                 if validator_ecc_pub_key == nil
                                         if @log.error?
                                            @log.error("[Blockstack.checkBlockstackRecord] failed to retrieve public key:")
                                            @log.error("-> blockstack_id: #{blockstack_id}")
                                            @log.error("-> type: #{type}")
                                            @log.error("--> validator_blockstack_id: #{validator_blockstack_id}")
                                         end

                                         return false
                                 end

                                 # check client's sig version 1
                                 client_sig = record["client_sig"]

                                 validator_sig = record["validator_sig"]

                                 client_sig_to_check = record["vchain_id"] + record["vchain_role"] + blockstack_id + record["ecc_pubkey"] + record["sig_version"];

                                 validator_sig_to_check = record["vchain_id"] + record["vchain_role"] + blockstack_id + record["ecc_pubkey"] + record["sig_version"] + record["validator_vchain_id"] + validator_blockstack_id

                                 # client's sig versions 2 && 3
                                 if record["sig_version"] == "2" || record["sig_version"] == "3"

                                         # need to retrieve RSA key
                                         if !record.key?("rsa_pubkey")
                                            if @log.error?
                                                    @log.error("[Blockstack.checkBlockstackRecord] record doesn't have 'rsa_pubkey' field")
                                                           @log.error("-> blockstack_id: #{blockstack_id}")
                                                           @log.error("-> type: #{type}")
                                            end

                                                 return false
                                         end

                                         if record["sig_version"] == "2"
                                                 # sig version 2

                                                 client_sig = record["client_sig_v2"]

                                                 validator_sig = record["validator_sig_v2"]

                                                 client_sig_to_check = record["vchain_id"] + record["vchain_role"] + blockstack_id + record["ecc_pubkey"] + record["rsa_pubkey"] + record["sig_version"];

                                                 validator_sig_to_check = record["vchain_id"] + record["vchain_role"] + blockstack_id + record["ecc_pubkey"].gsub(/\n/, "") + record["rsa_pubkey"].gsub(/\n/, "") + record["sig_version"] + record["validator_vchain_id"] + validator_blockstack_id

                                         elsif record["sig_version"] == "3"
                                                 # sig version 3

                                                 client_sig = record["client_sig_v3"]

                                                 validator_sig = record["validator_sig_v3"]

                                                 client_sig_to_check = record["vchain_id"] + record["vchain_role"] + blockstack_id + record["ecc_pubkey"].gsub(/\n/, "") + record["rsa_pubkey"].gsub(/\n/, "") + record["sig_version"];

                                                 validator_sig_to_check = record["vchain_id"] + record["vchain_role"] + blockstack_id + record["ecc_pubkey"].gsub(/\n/, "") + record["rsa_pubkey"].gsub(/\n/, "") + record["sig_version"] + record["validator_vchain_id"] + validator_blockstack_id
                                         end
                                 end

                                 begin

                                         if cryptoHelper.verifySignature(client_sig_to_check, client_sig, record["ecc_pubkey"])
                                                 
                                                 # check validator's sig
                                                 begin

                                                         if cryptoHelper.verifySignature(validator_sig_to_check, validator_sig, validator_ecc_pub_key)
                                                                 
                                                                 return true;

                                                         else
                                                                 if @log.error?
                                                                         @log.error("[Blockstack.checkBlockstackRecord] failed to verify validator_sig")
                                                                         @log.error("-> blockstack_id: #{blockstack_id}")
                                                                         @log.error("-> type: #{type}")
                                                                          @log.error("--> validator_sig_to_check: #{validator_sig_to_check}")
                                                                          @log.error("--> validator_sig: "+ Base64.encode64(record["validator_sig"]))
                                                                          @log.error("--> validator_ecc_pub_key: #{validator_ecc_pub_key}")
                                                                 end

                                                                 return false
                                                         end

                                                 rescue => e
                                                         if @log.error?
                                                                  @log.error("[Blockstack.checkBlockstackRecord] verifySignature for validator_sig raised exception:")
                                                                  @log.error("#{e.class}, #{e.message}")
                                                                  @log.error("-> blockstack_id: #{blockstack_id}")
                                                                  @log.error("-> type: #{type}")
                                                                  @log.error("--> validator_sig_to_check: #{validator_sig_to_check}")
                                                                  @log.error("--> validator_sig: "+ Base64.encode64(record["validator_sig"]))
                                                                  @log.error("--> validator_ecc_pub_key: #{validator_ecc_pub_key}")
                                                         end

                                                         raise e
                                                 end

                                         else
                                                 if @log.error?
                                                           @log.error("[Blockstack.checkBlockstackRecord] failed to verify client_sig")
                                                           @log.error("-> blockstack_id: #{blockstack_id}")
                                                           @log.error("-> type: #{type}")
                                                    @log.error("--> client_sig_to_check: #{client_sig_to_check}")
                                                    @log.error("--> client_sig: "+ Base64.encode64(record["client_sig"]))
                                                    @log.error("--> ecc_pubkey: "+ record["ecc_pubkey"])
                                                   end

                                                 return false
                                         end

                                 rescue => e
                                         if @log.error?
                                            @log.error("[Blockstack.checkBlockstackRecord] verifySignature for client_sig raised exception:")
                                            @log.error("#{e.class}, #{e.message}")
                                            @log.error("-> blockstack_id: #{blockstack_id}")
                                            @log.error("-> type: #{type}")
                                            @log.error("--> client_sig_to_check: #{client_sig_to_check}")
                                            @log.error("--> client_sig: "+ Base64.encode64(record["client_sig"]))
                                            @log.error("--> ecc_pubkey: "+ record["ecc_pubkey"])
                                         end

                                         raise e
                                 end

                        else 
                              if @log.error?
                                      @log.error("[Blockstack.checkBlockstackRecord] record doesn't have 'vchain_role' field")
                                     @log.error("-> blockstack_id: #{blockstack_id}")
                                     @log.error("-> type: #{type}")
                              end                                         
                        end

                else
                       if @log.error?
                               @log.error("[Blockstack.checkBlockstackRecord] record doesn't have 'ecc_pubkey' field")
                              @log.error("-> blockstack_id: #{blockstack_id}")
                              @log.error("-> type: #{type}")
                       end
                end

        else
                if @log.error?
                        @log.error("[Blockstack.checkBlockstackRecord] record is null")
                       @log.error("-> blockstack_id: #{blockstack_id}")
                       @log.error("-> type: #{type}")
                end
        end

        return false
end
checkFederativeServer(federative_server_id) click to toggle source
# File lib/vchain_client/blockstack_client.rb, line 21
def checkFederativeServer(federative_server_id)

        if @log.debug?
                @log.debug("[Blockstack.checkFederativeServer] input:")
                @log.debug("-> federative_server_id: #{federative_server_id}")
        end

        begin
                
                return self.checkBlockstackRecord(federative_server_id, 'federative_server')

        rescue => e

               if @log.error?
                       @log.error("[Blockstack.checkFederativeServer] checkBlockstackRecord raised exception:")
                       @log.error("#{e.class}, #{e.message}")
                       @log.error("-> federative_server_id: #{federative_server_id}")
                       @log.error("--> federative_server_id: #{federative_server_id}")
                       @log.error("--> type: federative_server")
               end

                raise e
        end
end
checkValidator(validator_id) click to toggle source
# File lib/vchain_client/blockstack_client.rb, line 71
def checkValidator(validator_id)

        if @log.debug?
                @log.debug("[Blockstack.checkValidator] input:")
                @log.debug("-> validator_id: #{validator_id}")
        end

        begin
                
                return self.checkBlockstackRecord(validator_id, 'validator')

        rescue => e

               if @log.error?
                       @log.error("[Blockstack.checkValidator] checkBlockstackRecord raised exception:")
                       @log.error("#{e.class}, #{e.message}")
                       @log.error("-> validator_id: #{validator_id}")
                       @log.error("--> validator_id: #{validator_id}")
                       @log.error("--> type: validator")
               end

                raise e
        end
end
checkVerificator(verificator_id) click to toggle source
# File lib/vchain_client/blockstack_client.rb, line 46
def checkVerificator(verificator_id)

        if @log.debug?
                @log.debug("[Blockstack.checkVerificator] input:")
                @log.debug("-> verificator_id: #{verificator_id}")
        end

        begin
                
                return self.checkBlockstackRecord(verificator_id, 'verificator')

        rescue => e

               if @log.error?
                       @log.error("[Blockstack.checkVerificator] checkBlockstackRecord raised exception:")
                       @log.error("#{e.class}, #{e.message}")
                       @log.error("-> verificator_id: #{verificator_id}")
                       @log.error("--> verificator_id: #{verificator_id}")
                       @log.error("--> type: verificator")
               end

                raise e
        end
end
getBlockstackRecord(blockstack_id, force_refresh=false) click to toggle source
# File lib/vchain_client/blockstack_client.rb, line 508
def getBlockstackRecord(blockstack_id, force_refresh=false)

        if @log.debug?
                @log.debug("[Blockstack.getBlockstackRecord] input:")
                @log.debug("-> blockstack_id: #{blockstack_id}")
        end

        if !force_refresh
               if @@recs_cache.key?(blockstack_id)
                      if @log.debug?
                              @log.debug("[Blockstack.getBlockstackRecord] '#{blockstack_id}' is in a cache")
                      end

                       return @@recs_cache[blockstack_id]
               end
        end

        blockstack_path = @config["blockstack"]["path"]

        cmd_init = blockstack_path +" set_advanced_mode on"

        cmd = blockstack_path +" get_name_zonefile "+ blockstack_id

        if @log.debug?
                @log.debug("[Blockstack.getBlockstackRecord] using '#{blockstack_path}' as a Blockstack path")
                @log.debug("[Blockstack.getBlockstackRecord] running '#{cmd}'")
        end

        ret = nil

        begin 

                `#{cmd_init}`

                ret = `#{cmd}`

        rescue => e
                if @log.error?
                        @log.error("[Blockstack.getBlockstackRecord] cmd call '#{cmd}' raised exception:")
                        @log.error("#{e.class}, #{e.message}")
                        @log.error("-> blockstack_id: #{blockstack_id}")
                        @log.error("--> '#{cmd}'")
                end

                raise e
        end

        if ret == nil
                if @log.error?
                        @log.error("[Blockstack.getBlockstackRecord] failed to retrieve record from cmd call")
                        @log.error("-> blockstack_id: #{blockstack_id}")
                        @log.error("--> '#{cmd}'")
                end

                return nil
        end

        if @log.debug?
                @log.debug("[Blockstack.getBlockstackRecord] cmd call return:")
                @log.debug(ret)
        end

        ret = JSON.parse ret

        @log.debug(ret)

        lines = ret["zonefile"].split("\n")

        fz = {}

         lines.each { |line|

                 recs = line.split(" ")

                 if recs.size == 3
                         if recs[0] == "A1" || recs[0] == "A2" || recs[0] == "A3" || recs[0] == "A4" || recs[0] == "A5" || recs[0] == "A6" || recs[0] == "A7" || recs[0] == "A8" || recs[0] == "A9" || recs[0] == "A10" || recs[0] == "A11"
                                 fz[recs[0]] = recs[2][1..-2]
                         end
                 end
         }

        if @log.debug?
                @log.debug("[Blockstack.getBlockstackRecord] fz:")
                @log.debug(fz)
        end

        if fz.key?("A1") &&  fz.key?("A2") &&  fz.key?("A3") &&  fz.key?("A4") && fz.key?("A5") &&  fz.key?("A6") &&  fz.key?("A7") && fz.key?("A8")

                ecc_pubkey_aligned = fz["A1"]
                ecc_pubkey = ecc_pubkey_aligned[0..63] +"\n"+ ecc_pubkey_aligned[64..ecc_pubkey_aligned.length]

                rsa_pubkey = nil
                if fz["A7"] == "2" || fz["A7"] == "3"
                        # sig versions 2 && 3

                        if !fz.key?("A9")
                              if @log.error?
                                       @log.error("[Blockstack.getBlockstackRecord] no 'A9' field, sig ver is >1")
                                       @log.error("-> blockstack_id: #{blockstack_id}")
                               end

                               return nil
                        end

                       rsa_pubkey_aligned = fz["A9"]
                       rsa_pubkey = rsa_pubkey_aligned[0..63] +"\n"+ rsa_pubkey_aligned[64..127] +"\n"+ rsa_pubkey_aligned[128..191] +"\n"+ rsa_pubkey_aligned[192..255] +"\n"+ rsa_pubkey_aligned[256..319] +"\n"+ rsa_pubkey_aligned[320..383] +"\n"+ rsa_pubkey_aligned[384..rsa_pubkey_aligned.length]
                end

                output = {
                         "ecc_pubkey"              => ecc_pubkey,
                         "rsa_pubkey"              => rsa_pubkey,
                         "vchain_id"               => fz["A2"],
                         "validator_sig"           => Base64.decode64(fz["A3"]),
                         "validator_vchain_id"     => fz["A4"],
                         "validator_blockstack_id" => fz["A5"],
                         "vchain_role"             => fz["A6"],
                         "sig_version"             => fz["A7"],
                         "client_sig"              => Base64.decode64(fz["A8"])
                }

                if fz["A7"] == "2" || fz["A7"] == "3"
                        # sig versions 2 && 3

                        output["client_sig_v2"]    = Base64.decode64(fz["A8"])
                        output["validator_sig_v2"] = Base64.decode64(fz["A3"])

                        if fz["A7"] == "3"
                                # sig version 3

                               if !fz.key?("A10") || !fz.key?("A11")
                                     if @log.error?
                                              @log.error("[Blockstack.getBlockstackRecord] no 'A10' or 'A11' fields, sig ver = 3")
                                              @log.error("-> blockstack_id: #{blockstack_id}")
                                      end

                                      return nil
                               end

                               output["client_sig_v3"]    = Base64.decode64(fz["A10"])
                               output["validator_sig_v3"] = Base64.decode64(fz["A11"])

                        end

                end

               if @log.debug?
                       @log.debug("[Blockstack.getBlockstackRecord] output:")
                       @log.debug(output)
               end

                @@recs_cache[blockstack_id] = output
                @@ecc_keys_cache[blockstack_id] = ecc_pubkey
                @@rsa_keys_cache[blockstack_id] = rsa_pubkey

                return output

        else
                if @log.error?
                         @log.error("[Blockstack.getBlockstackRecord] no 'A*' field")
                         @log.error("-> blockstack_id: #{blockstack_id}")
                         @log.error("--> blockstack_id: #{blockstack_id}")
                 end
        end

        return nil
end
getPublicKeyECC(blockstack_id, force_refresh=false) click to toggle source
# File lib/vchain_client/blockstack_client.rb, line 380
def getPublicKeyECC(blockstack_id, force_refresh=false)

        if @log.debug?
                @log.debug("[Blockstack.getPublicKeyECC] input:")
                @log.debug("-> blockstack_id: #{blockstack_id}")
        end

        if !force_refresh
               if @@ecc_keys_cache.key?(blockstack_id)

                      if @log.debug?
                              @log.debug("[Blockstack.getPublicKeyECC] '#{blockstack_id}' is in a cache")
                      end

                       return @@ecc_keys_cache[blockstack_id]
               end
        end

        if @log.debug?
                @log.debug("[Blockstack.getPublicKeyECC] '#{blockstack_id}' is not in a cache yet")
        end

        begin

               record = self.getBlockstackRecord(blockstack_id, force_refresh);

               if record != nil
                       
                       if record.key?("ecc_pubkey")

                               @@ecc_keys_cache[blockstack_id] = record["ecc_pubkey"]

                               return record["ecc_pubkey"]

                       else 
                             if @log.error?
                                     @log.error("[Blockstack.getPublicKeyECC] record '#{blockstack_id}' doesn't have 'ecc_pubkey' field")
                                     @log.error("-> blockstack_id: #{blockstack_id}")
                                     @log.error("--> blockstack_id: #{blockstack_id}")
                             end
                       end

               else
                      if @log.error?
                              @log.error("[Blockstack.getPublicKeyECC] failed to retrieve '#{blockstack_id}' record")
                              @log.error("-> blockstack_id: #{blockstack_id}")
                              @log.error("--> blockstack_id: #{blockstack_id}")
                      end
               end

       rescue => e
               if @log.error?
                       @log.error("[Blockstack.getPublicKeyECC] getBlockstackRecord raised exception:")
                       @log.error("#{e.class}, #{e.message}")
                       @log.error("-> blockstack_id: #{blockstack_id}")
                       @log.error("--> blockstack_id: #{blockstack_id}")
               end

               raise e
       end

        return nil
end
getPublicKeyRSA(blockstack_id, force_refresh=false) click to toggle source
# File lib/vchain_client/blockstack_client.rb, line 444
def getPublicKeyRSA(blockstack_id, force_refresh=false)

        if @log.debug?
                @log.debug("[Blockstack.getPublicKeyRSA] input:")
                @log.debug("-> blockstack_id: #{blockstack_id}")
        end

        if !force_refresh
               if @@rsa_keys_cache.key?(blockstack_id)

                      if @log.debug?
                              @log.debug("[Blockstack.getPublicKeyRSA] '#{blockstack_id}' is in a cache")
                      end

                       return @@rsa_keys_cache[blockstack_id]
               end
        end

        if @log.debug?
                @log.debug("[Blockstack.getPublicKeyRSA] '#{blockstack_id}' is not in a cache yet")
        end

        begin

               record = self.getBlockstackRecord(blockstack_id, force_refresh);

               if record != nil
                       
                       if record.key?("rsa_pubkey")

                               @@rsa_keys_cache[blockstack_id] = record["rsa_pubkey"]

                               return record["rsa_pubkey"]

                       else 
                             if @log.error?
                                     @log.error("[Blockstack.getPublicKeyRSA] record '#{blockstack_id}' doesn't have 'rsa_pubkey' field")
                                     @log.error("-> blockstack_id: #{blockstack_id}")
                                     @log.error("--> blockstack_id: #{blockstack_id}")
                             end
                       end

               else
                      if @log.error?
                              @log.error("[Blockstack.getPublicKeyRSA] failed to retrieve '#{blockstack_id}' record")
                              @log.error("-> blockstack_id: #{blockstack_id}")
                              @log.error("--> blockstack_id: #{blockstack_id}")
                      end
               end

       rescue => e
               if @log.error?
                       @log.error("[Blockstack.getPublicKeyRSA] getBlockstackRecord raised exception:")
                       @log.error("#{e.class}, #{e.message}")
                       @log.error("-> blockstack_id: #{blockstack_id}")
                       @log.error("--> blockstack_id: #{blockstack_id}")
               end

               raise e
       end

        return nil
end