Class: FrontEndBuilds::Pubkey

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/front_end_builds/pubkey.rb

Instance Method Summary collapse

Instance Method Details

#fingerprintObject



17
18
19
20
21
22
23
24
25
26
27
# File 'app/models/front_end_builds/pubkey.rb', line 17

def fingerprint
  content = pubkey.split(/\s/)[1]

  if content
    Digest::MD5.hexdigest(Base64.decode64(content))
      .scan(/.{1,2}/)
      .join(":")
  else
    'Unknown'
  end
end

#last_buildObject



83
84
85
86
87
88
# File 'app/models/front_end_builds/pubkey.rb', line 83

def last_build
  builds
    .order('created_at desc')
    .limit(1)
    .first
end

#serializeObject



90
91
92
93
94
95
96
97
# File 'app/models/front_end_builds/pubkey.rb', line 90

def serialize
  {
    id: id,
    name: name,
    fingerprint: fingerprint,
    lastUsedAt: last_build.try(:created_at)
  }
end

#ssh_pubkey?Boolean

Returns:

  • (Boolean)


29
30
31
32
# File 'app/models/front_end_builds/pubkey.rb', line 29

def ssh_pubkey?
  (type, b64, _) = pubkey.split(/\s/)
  %w{ssh-rsa ssh-dss}.include?(type) && b64.present?
end

#to_rsa_pkeyObject

Public: In order to verify a signature we need the key to be an OpenSSL RSA PKey and not a string that you would find in an ssh pubkey key. Most people are going to be adding ssh public keys to their build system, this method will covert them to OpenSSL RSA if needed.



38
39
40
41
# File 'app/models/front_end_builds/pubkey.rb', line 38

def to_rsa_pkey
  FrontEndBuilds::Utils::SSHPubKeyConvert
    .convert(pubkey)
end

#verify(build) ⇒ Object

Public: Will verify that the sigurate has access to deploy the build object. The signature includes the endpoint and app name.

Returns boolean



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'app/models/front_end_builds/pubkey.rb', line 47

def verify(build)
  # TODO might as well cache this and store in the db so we dont have to
  # convert every time
  pkey = to_rsa_pkey
  signature = Base64.decode64(build.signature)
  digest = OpenSSL::Digest::SHA256.new

  # If the user submits html were going to expect the
  # signature to match the html they are submitting.
  # However, if the user gives a url where we can download
  # the html, we're going to expect the signature to match
  # the app name and the url.
  if build.endpoint.present?
    expected = "#{build.app.name}-#{build.endpoint}"
  else
    expected = build.html
  end

  match = expected &&
    signature &&
    pkey.verify(digest, signature, expected)
  # Bug in ruby's OpenSSL implementation.
  # SSL connection with PostgreSQL can fail, after a call to
  # OpenSSL::X509::Certificate#verify with result 'false'. Root cause is
  # the thread local error queue of OpenSSL, that is used to transmit
  # textual error messages to the application after a failed crypto
  # operation. A failure in Certificate#verify leaves some messages on the
  # error queue, which can lead to errors in a SSL communication of other
  # parts of the application. The only solution at the moment is running:
  # OpenSSL.errors.clear after certificate verifying. This clears OpenSSL
  # errors array and keeps database connection alive.
  # From https://bugs.ruby-lang.org/issues/7215
  OpenSSL.errors.clear
  match # return true/false
end