class OrangeData::Credentials

wrapper for keys/certs used for connection auth

Constants

DEFAULT_KEY_LENGTH

Attributes

certificate[RW]
certificate_key[RW]
signature_key[RW]
signature_key_name[RW]
title[RW]

Public Class Methods

default_test() click to toggle source

ключи для тествого окружения

# File lib/orange_data/credentials.rb, line 288
def self.default_test
  from_hash(YAML.load_file(File.expand_path('credentials_test.yml', __dir__)))
end
from_hash(creds, key_pass:nil) click to toggle source
# File lib/orange_data/credentials.rb, line 145
def self.from_hash(creds, key_pass:nil)
  key_pass ||= '' # to prevent password prompt, works in fresh openssl gem/ruby
  new(
    title: creds[:title],
    signature_key_name: creds[:signature_key_name],
    signature_key: OpenSSL::PKey::RSA.load_from(creds[:signature_key], creds[:signature_key_pass] || key_pass),
    certificate: creds[:certificate] && OpenSSL::X509::Certificate.new(creds[:certificate]),
    certificate_key: OpenSSL::PKey::RSA.load_from(creds[:certificate_key], creds[:certificate_key_pass] || key_pass)
  )
end
from_json(json) click to toggle source
# File lib/orange_data/credentials.rb, line 181
def self.from_json(json)
  require 'json'
  from_hash(JSON.parse(json, symbolize_names: true))
end
generate_signature_key(key_length=DEFAULT_KEY_LENGTH) click to toggle source
# File lib/orange_data/credentials.rb, line 220
def self.generate_signature_key(key_length=DEFAULT_KEY_LENGTH)
  raise ArgumentError, "key length should be >= 489, recomended #{DEFAULT_KEY_LENGTH}" unless key_length >= 489

  OpenSSL::PKey::RSA.new(key_length)
end
new(signature_key_name:nil, signature_key:nil, certificate:nil, certificate_key:nil, title:nil) click to toggle source
# File lib/orange_data/credentials.rb, line 115
def initialize(signature_key_name:nil, signature_key:nil, certificate:nil, certificate_key:nil, title:nil)
  raise ArgumentError, "Signature key should be a private key" if signature_key && !signature_key.private?
  raise ArgumentError, "Certificate key should be a private key" if certificate_key && !certificate_key.private?

  @signature_key_name = signature_key_name
  @signature_key = signature_key
  @certificate = certificate
  @certificate_key = certificate_key
  @title = title
end
read_certs_from_pack(path, signature_key_name:nil, cert_key_pass:nil, title:nil, signature_key:nil) click to toggle source
# File lib/orange_data/credentials.rb, line 226
def self.read_certs_from_pack(path, signature_key_name:nil, cert_key_pass:nil, title:nil, signature_key:nil)
  path = File.expand_path(path)
  client_cert = Dir.glob(path + '/*.{crt}').select{|f| File.file?(f.sub(/.crt\z/, '.key')) }
  raise 'Expect to find exactly one <num>.crt with corresponding <num>.key file' unless client_cert.size == 1

  client_cert = client_cert.first

  unless signature_key
    # private_key_test.xml || rsa_\d+_private_key.xml
    xmls = Dir.glob(path + '/*.{xml}').select{|f| f =~ /private/ }
    signature_key = if xmls.size == 1
      File.read(xmls.first)
    else
      generate_signature_key(DEFAULT_KEY_LENGTH)
      # .tap{|k| logger.info("Generated public signature key: #{k.public_key.to_xml}") }
    end
  end

  from_hash(
    title: title || "Generated from #{File.basename(path)}",
    signature_key_name: signature_key_name || File.basename(client_cert).gsub(/\..*/, ''),
    certificate: File.read(client_cert),
    certificate_key: File.read(client_cert.sub(/.crt\z/, '.key')),
    certificate_key_pass: cert_key_pass,
    signature_key: signature_key
  )
end
read_certs_from_zip_pack(rubyzip_object, signature_key_name:nil, cert_key_pass:nil, title:nil, signature_key:nil) click to toggle source
# File lib/orange_data/credentials.rb, line 254
def self.read_certs_from_zip_pack(rubyzip_object, signature_key_name:nil, cert_key_pass:nil, title:nil, signature_key:nil)
  client_cert = rubyzip_object.glob("*.crt").select{|f| rubyzip_object.glob(f.name.sub(/.crt\z/, '.key')).any? }
  raise 'Expect to find exactly one <num>.crt with corresponding <num>.key file' unless client_cert.size == 1

  client_cert = client_cert.first
  client_key = rubyzip_object.glob(client_cert.name.sub(/.crt\z/, '.key')).first

  unless signature_key
    # private_key_test.xml || rsa_\d+_private_key.xml
    xmls = rubyzip_object.glob('/*.{xml}').select{|f| f =~ /private/ }
    signature_key = if xmls.size == 1
      xmls.first.get_input_stream.read
    else
      generate_signature_key(DEFAULT_KEY_LENGTH)
      # .tap{|k| logger.info("Generated public signature key: #{k.public_key.to_xml}") }
    end
  end

  from_hash(
    title: title || "Generated from zip",
    signature_key_name: signature_key_name || File.basename(client_cert.name).gsub(/\..*/, ''),
    certificate: client_cert.get_input_stream.read,
    certificate_key: client_key.get_input_stream.read,
    certificate_key_pass: cert_key_pass,
    signature_key: signature_key
  )
end

Public Instance Methods

==(other) click to toggle source
# File lib/orange_data/credentials.rb, line 134
def ==(other)
  return false unless %i[signature_key_name title].all?{|m| send(m) == other.send(m) }

  # certificates/keys cannot be compared directly, so dump
  %i[signature_key certificate certificate_key].all?{|m|
    c1 = send(m)
    c2 = other.send(m)
    c1 == c2 || (c1 && c2 && c1.to_der == c2.to_der)
  }
end
certificate_subject() click to toggle source
# File lib/orange_data/credentials.rb, line 207
def certificate_subject
  if subj = certificate.subject.to_a.select{|ent| ent.first == 'O' }.first
    subj[1].force_encoding('UTF-8')
  end
end
generate_signature_key!(key_length=DEFAULT_KEY_LENGTH) click to toggle source

deprecated

# File lib/orange_data/credentials.rb, line 216
def generate_signature_key!(key_length=DEFAULT_KEY_LENGTH)
  self.signature_key = self.class.generate_signature_key(key_length)
end
inspect() click to toggle source
# File lib/orange_data/credentials.rb, line 194
def inspect
  info_fields = {
    title: (title || 'untitled').inspect,
    key_name: signature_key_name.inspect,
  }

  if certificate && (subject_name = certificate_subject)
    info_fields[:certificate] = %("#{(subject_name || 'unknown').gsub('"', '\"')}")
  end

  "#<#{self.class.name}:#{object_id} #{info_fields.map{|(k, v)| "#{k}=#{v}" }.join(' ')}>"
end
signature_public_xml() click to toggle source

публичная часть ключа подписи в формате пригодном для отдачи в ЛК

# File lib/orange_data/credentials.rb, line 283
def signature_public_xml
  signature_key.public_key.to_xml
end
to_hash(key_pass:nil, save_pass:false) click to toggle source
# File lib/orange_data/credentials.rb, line 156
def to_hash(key_pass:nil, save_pass:false)
  if key_pass.nil?
    key_pass = SecureRandom.hex
    save_pass = true
  elsif key_pass == false
    key_pass = nil
  end

  {
    title: title,
    signature_key_name: signature_key_name,
    signature_key: signature_key &&
      signature_key.to_pem(key_pass && OpenSSL::Cipher.new("aes-128-cbc"), key_pass),
    certificate: certificate && certificate.to_pem,
    certificate_key: certificate_key &&
      certificate_key.to_pem(key_pass && OpenSSL::Cipher.new("aes-128-cbc"), key_pass),
  }.tap do |h|
    h.delete(:title) if !title || title == ''
    if save_pass
      h[:certificate_key_pass] = key_pass if certificate && key_pass
      h[:signature_key_pass] = key_pass if signature_key && key_pass
    end
  end
end
to_json(key_pass:nil, save_pass:false) click to toggle source
# File lib/orange_data/credentials.rb, line 186
def to_json(key_pass:nil, save_pass:false)
  to_hash(key_pass:key_pass, save_pass:save_pass).to_json
end
to_yaml(key_pass:nil, save_pass:false) click to toggle source
# File lib/orange_data/credentials.rb, line 190
def to_yaml(key_pass:nil, save_pass:false)
  to_hash(key_pass:key_pass, save_pass:save_pass).to_yaml
end
valid?() click to toggle source
# File lib/orange_data/credentials.rb, line 126
def valid?
  signature_key_name &&
    signature_key && signature_key.private? &&
    (signature_key.n.num_bits >= 489) && # minimum working key length for sha256 signature
    certificate && certificate_key &&
    certificate_key.private? && certificate.check_private_key(certificate_key)
end