Skip to content

Commit

Permalink
Small refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
lslezak committed Feb 22, 2019
1 parent 14a7c8f commit ca20e5e
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 59 deletions.
65 changes: 7 additions & 58 deletions src/lib/registration/connect_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
require "registration/ssl_error_codes"
require "registration/storage"
require "registration/ui/import_certificate_dialog"
require "registration/ui/failed_certificate_popup"
require "registration/url_helpers"

module Registration
Expand Down Expand Up @@ -203,25 +204,18 @@ def self.handle_ssl_error(error, certificate_imported)
return true
end

report_ssl_error(error.message, cert)
report_ssl_error(error.message, cert, error_code)
else
# error message
Yast::Report.Error(_("Received SSL Certificate does not match " \
"the expected certificate."))
end
else
report_ssl_error(error.message, cert)
report_ssl_error(error.message, cert, error_code)
end
false
end

def self.ssl_error_details(cert, _code)
return "" if cert.nil?

details = SslCertificateDetails.new(cert)
details.richtext_summary
end

def self.ask_import_ssl_certificate(cert)
# run the import dialog, check the user selection
if UI::ImportCertificateDialog.run(cert) != :import
Expand Down Expand Up @@ -266,53 +260,8 @@ def self.import_ssl_certificate(cert)
result
end

def self.report_ssl_error(message, cert)
# try to use a translatable message first, if not found then use
# the original error message from openSSL
error_code = Storage::SSLErrors.instance.ssl_error_code
msg = UI::ImportCertificateDialog::OPENSSL_ERROR_MESSAGES[error_code]
msg = msg ? _(msg) : Storage::SSLErrors.instance.ssl_error_msg
msg = message if msg.nil? || msg.empty?

url = UrlHelpers.registration_url || SUSE::Connect::YaST::DEFAULT_URL
msg = "<p>" + (_("Secure connection error: %s") % "#{url}: #{msg}") + "</p>\n"

if error_code == SslErrorCodes::NO_LOCAL_ISSUER_CERTIFICATE
msg << import_hint
end

msg << "<hr><h3>" << _("Failed Certificate Details") << "</h3>" <<
ssl_error_details(cert, error_code)

# this uses a RichText message format
Yast::Report.LongError(msg)
end

def self.import_hint
"<p>" + _("The issuer certificate cannot be found, " \
"it needs to be installed manually.") + "</p>\n<p><ul>\n" +
# TRANSLATORS: %{dir} is replaced by the certificate directory
_("<li>Copy the certificate in PEM format to <tt>%{dir}</tt> directory</li>") %
{ dir: "/etc/pki/trust/anchors" } + "\n" +
import_commands +
"<li>" + _("Run registration again") + "</li>" \
"\n</ul></p>"
end

def self.import_commands
# in the inst-sys we need to import the certificate manually,
# the update-ca-certificates script is missing
commands = if Yast::Stage.initial
["trust extract --format=openssl-directory --filter=ca-anchors " \
"--overwrite #{SslCertificate::TMP_CA_CERTS_DIR}",
"cp #{SslCertificate::TMP_CA_CERTS_DIR}/* #{SslCertificate::CA_CERTS_DIR}/openssl"]
else
["update-ca-certificates"]
end

commands.map do |c|
"<li>" + (_("Run command: %s") % "<tt>#{c}</tt>") + "</li>\n"
end.join
def self.report_ssl_error(message, cert, error_code)
UI::FailedCertificatePopup.show(message, cert, error_code)
end

# Check whether the registration server provides the old NCC API,
Expand Down Expand Up @@ -388,7 +337,7 @@ def self.add_update_hint(error_msg)
error_msg << msg
end

private_class_method :report_error, :error_with_details, :ssl_error_details,
:import_ssl_certificate, :report_ssl_error, :check_smt_api, :handle_network_error
private_class_method :report_error, :error_with_details, :import_ssl_certificate,
:report_ssl_error, :check_smt_api, :handle_network_error
end
end
38 changes: 37 additions & 1 deletion src/lib/registration/ssl_error_codes.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
# ------------------------------------------------------------------------------
# Copyright (c) 2019 SUSE LLC
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of version 2 of the GNU General Public License as published by the
# Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# ------------------------------------------------------------------------------
#

require "yast"

module Registration
class SslErrorCodes
# see https://github.com/openssl/openssl/blob/2c75f03b39de2fa7d006bc0f0d7c58235a54d9bb/include/openssl/x509_vfy.h#L99-L189
extend Yast::I18n

textdomain "registration"

# see https://github.com/openssl/openssl/blob/2c75f03b39de2fa7d006bc0f0d7c58235a54d9bb/include/openssl/x509_vfy.h#L99-L189
# "certificate has expired"
EXPIRED = 10
# "self signed certificate"
Expand All @@ -18,5 +37,22 @@ class SslErrorCodes
SELF_SIGNED_CERT,
SELF_SIGNED_CERT_IN_CHAIN
].freeze

# error code => translatable error message
# @see https://www.openssl.org/docs/apps/verify.html
# @see https://github.com/openssl/openssl/blob/2c75f03b39de2fa7d006bc0f0d7c58235a54d9bb/include/openssl/x509_vfy.h#L99-L189
# @note the text messages need to be translated at runtime via _() call
OPENSSL_ERROR_MESSAGES = {
# TRANSLATORS: SSL error message
EXPIRED => N_("Certificate has expired"),
# TRANSLATORS: SSL error message
SELF_SIGNED_CERT => N_("Self signed certificate"),
# TRANSLATORS: SSL error message
SELF_SIGNED_CERT_IN_CHAIN => N_(
"Self signed certificate in certificate chain"
),
# TRANSLATORS: SSL error message
NO_LOCAL_ISSUER_CERTIFICATE => N_("Unable to get local issuer certificate")
}.freeze
end
end
111 changes: 111 additions & 0 deletions src/lib/registration/ui/failed_certificate_popup.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# ------------------------------------------------------------------------------
# Copyright (c) 2019 SUSE LLC
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of version 2 of the GNU General Public License as published by the
# Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# ------------------------------------------------------------------------------
#

require "yast"

require "registration/ssl_certificate_details"
require "registration/ssl_error_codes"
require "registration/url_helpers"


module Registration
module UI
# this class displays and runs the dialog for importing a SSL certificate
class FailedCertificatePopup
include Yast::Logger
include Yast::I18n

attr_accessor :certificate, :error_code, :message

Yast.import "Report"
Yast.import "Stage"

# create a new dialog for importing a SSL certificate and run it
# @param cert [Registration::SslCertitificate] certificate to display
# @return [Symbol] user input (:import, :cancel)
def self.show(msg, cert, error_code)
popup = FailedCertificatePopup.new(msg, cert, error_code)
popup.show
end

# the constructor
# @param cert [Registration::SslCertitificate] certificate to display
def initialize(msg, cert, error_code)
textdomain "registration"

@certificate = cert
@message = msg
@error_code = error_code
end

# display the dialog and wait for a button click
# @return [Symbol] user input (:import, :cancel)
def show
# this uses a RichText message format
Yast::Report.LongError(ssl_error_message)
end

private

def ssl_error_message
# try to use a translatable message first, if not found then use
# the original error message from openSSL
msg = _(SslErrorCodes::OPENSSL_ERROR_MESSAGES[error_code]) || message
url = UrlHelpers.registration_url || SUSE::Connect::YaST::DEFAULT_URL

msg = "<p>" + (_("Secure connection error: %s") % "#{url}: #{msg}") + "</p>\n"

if error_code == SslErrorCodes::NO_LOCAL_ISSUER_CERTIFICATE
msg << import_hint
end

msg << "<hr><h3>" << _("Failed Certificate Details") << "</h3>" <<
ssl_certificate_details
end

# render Richtext description with the certificate details
def ssl_certificate_details(richtext: true)
details = SslCertificateDetails.new(certificate)
richtext ? details.richtext_summary : details.summary
end

def import_hint
"<p>" + _("The issuer certificate cannot be found, " \
"it needs to be installed manually.") + "</p>\n<p><ul>\n" +
# TRANSLATORS: %{dir} is replaced by the certificate directory
_("<li>Copy the certificate in PEM format to <tt>%{dir}</tt> directory</li>") %
{ dir: "/etc/pki/trust/anchors" } + "\n" +
import_commands +
"<li>" + _("Run registration again") + "</li>" \
"\n</ul></p>"
end

def import_commands
# in the inst-sys we need to import the certificate manually,
# the update-ca-certificates script is missing
commands = if Yast::Stage.initial
["trust extract --format=openssl-directory --filter=ca-anchors " \
"--overwrite #{SslCertificate::TMP_CA_CERTS_DIR}",
"cp #{SslCertificate::TMP_CA_CERTS_DIR}/* #{SslCertificate::CA_CERTS_DIR}/openssl"]
else
["update-ca-certificates"]
end

commands.map do |c|
"<li>" + (_("Run command: %s") % "<tt>#{c}</tt>") + "</li>\n"
end.join
end
end
end
end

0 comments on commit ca20e5e

Please sign in to comment.