Skip to content

Commit

Permalink
download and confirm add-on licenses from the registration server
Browse files Browse the repository at this point in the history
  • Loading branch information
lslezak committed May 15, 2014
1 parent a16f3c4 commit fa5e2f0
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 13 deletions.
8 changes: 4 additions & 4 deletions package/yast2-registration.spec
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ Requires: yast2 >= 3.1.26
Requires: yast2-pkg-bindings >= 2.17.20
# N_() method
Requires: yast2-ruby-bindings >= 3.1.12
Requires: rubygem-suse-connect
Requires: rubygem-suse-connect >= 0.0.16
Requires: yast2-slp >= 3.1.2
Requires: yast2-add-on >= 3.1.3
Requires: yast2-packager >= 3.1.14
Requires: yast2-packager >= 3.1.16

BuildRequires: yast2 >= 3.1.26
BuildRequires: update-desktop-files
BuildRequires: yast2-devtools >= 3.1.6
BuildRequires: rubygem-rspec
BuildRequires: rubygem-suse-connect
BuildRequires: rubygem-suse-connect >= 0.0.16
BuildRequires: yast2-slp >= 3.1.2
BuildRequires: yast2-packager >= 3.1.14
BuildRequires: yast2-packager >= 3.1.16

BuildArch: noarch

Expand Down
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ylibdir = @ylibdir@/registration
ylib_DATA = \
lib/registration/addon.rb \
lib/registration/exceptions.rb \
lib/registration/eula_downloader.rb \
lib/registration/sw_mgmt.rb \
lib/registration/storage.rb \
lib/registration/registration.rb \
Expand All @@ -21,6 +22,7 @@ ylib_DATA = \

ylibuidir = @ylibdir@/registration/ui
ylibui_DATA = \
lib/registration/ui/addon_eula_dialog.rb \
lib/registration/ui/import_certificate_dialog.rb

ylibyastdir = @ylibdir@/yast
Expand Down
27 changes: 18 additions & 9 deletions src/clients/inst_scc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
require "registration/sw_mgmt"
require "registration/storage"
require "registration/registration"
require "registration/ui/addon_eula_dialog"

module Yast
class InstSccClient < Client
Expand Down Expand Up @@ -678,16 +679,21 @@ def registration_check
return :register
end
end

def addon_eula
::Registration::UI::AddonEulaDialog.run(@selected_addons)
end

# UI workflow definition
def start_workflow
aliases = {
# skip this when going back
"check" => [ lambda { registration_check() }, true ],
"register" => lambda { register_base_system() },
"select_addons" => lambda { select_addons() },
"register_addons" => lambda { register_addons() },
"media_addons" => lambda { media_addons() },
# skip this when going back
"check" => [ lambda { registration_check() }, true ]
"addon_eula" => lambda { addon_eula() },
"register_addons" => lambda { register_addons() }
}

sequence = {
Expand All @@ -709,16 +715,19 @@ def start_workflow
"select_addons" => {
:abort => :abort,
:skip => "media_addons",
:next => "register_addons"
},
"register_addons" => {
:abort => :abort,
:next => "media_addons"
},
"media_addons" => {
:abort => :abort,
:next => :next,
:auto => :auto
:next => "addon_eula",
},
"addon_eula" => {
:abort => :abort,
:next => "register_addons"
},
"register_addons" => {
:abort => :abort,
:next => :next
}
}

Expand Down
115 changes: 115 additions & 0 deletions src/lib/registration/eula_downloader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# encoding: utf-8

# ------------------------------------------------------------------------------
# Copyright (c) 2014 Novell, Inc. All Rights Reserved.
#
#
# 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.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, contact Novell, Inc.
#
# To contact Novell about this file by physical or electronic mail, you may find
# current contact information at www.novell.com.
# ------------------------------------------------------------------------------
#
#

require "yast"

require "net/http"
require "uri"

module Registration

# class for downloading addon EULAs from the registration server
class EulaDownloader
attr_accessor :base_url, :target_dir, :insecure

include Yast::Logger

# name of the directory index file with list of available files
INDEX_FILE = "directory.yast"

def initialize(base_url, target_dir, insecure: false)
@base_url = base_url
@target_dir = target_dir
@insecure = insecure
end

# start the download
def download
licenses = download_license_index

# download the files listed in the index
licenses.each do |license|
license_file_url = URI(base_url)
license_file_url.path = File.join(license_file_url.path, license)

log.info "Downloading license from #{license_file_url}..."
license_text = download_file(license_file_url)
log.info "Downloaded license size: #{license_text.size}"

license_file_name = File.join(target_dir, license)

log.info "Saving the license to file: #{license_file_name}"
File.write(license_file_name, license_text)
end
end

private

def download_file(file_url)
url = file_url.is_a?(URI) ? file_url : URI(file_url)
http = Net::HTTP.new(url.host, url.port)

# switch to HTTPS connection if needed
if url.is_a? URI::HTTPS
http.use_ssl = true
http.verify_mode = insecure ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
log.warn("Warning: SSL certificate verification disabled") if insecure
else
log.warn("Warning: Using insecure \"#{url.scheme}\" transfer protocol")
end

# TODO: handle redirection?
request = Net::HTTP::Get.new(url.request_uri)
response = http.request(request)

if response.is_a?(Net::HTTPSuccess)
return response.body
else
log.error "HTTP request failed: Error #{response.code}:#{response.message}: #{response.body}"
raise "Download failed"
end
end

# returns list of available files in a remote location
def download_license_index
# download the index file (directory.yast)
index_url = URI(base_url)

# add the index file to the URL path
index_url.path = File.join(index_url.path, INDEX_FILE)

# download the index
log.info "Downloading license index from #{index_url}..."
licenses = download_file(index_url).split

# the index file itself might be also present in the list, just remove it
licenses.reject!{|license| license == INDEX_FILE}
log.info "Downloaded license index: #{licenses}"

licenses
end

end


end
1 change: 1 addition & 0 deletions src/lib/registration/registration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def connect_params(params)
:language => ::Registration::Helpers.language,
:debug => ENV["SCCDEBUG"],
:verbose => ENV["Y2DEBUG"] == "1",
:product => {}, #SwMgmt.base_product_to_register,
# pass a verify_callback to get details about failed SSL verification
:verify_callback => lambda do |verify_ok, context|
# we cannot raise an exception with details here (all exceptions in
Expand Down
103 changes: 103 additions & 0 deletions src/lib/registration/ui/addon_eula_dialog.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@

require "yast"
require "registration/eula_downloader"

module Registration
module UI

class AddonEulaDialog
include Yast::Logger
include Yast::I18n
include Yast::UIShortcuts

attr_accessor :addons

Yast.import "Popup"
Yast.import "ProductLicense"
Yast.import "Report"
Yast.import "Wizard"

# create a new dialog for accepting importing a SSL certificate and run it
def self.run(selected_addons)
dialog = AddonEulaDialog.new(selected_addons)
dialog.run
end

# @param selected_addons
def initialize(selected_addons)
textdomain "registration"
@addons = selected_addons
end

# display the EULA for each dialog and wait for a button click
# @return [Symbol] user input (:import, :cancel)
def run
Yast::Wizard.SetContents(
# dialog title
_("License Agreement"),
Label(_("Downloading Licenses...")),
"",
false,
false
)

all_accepted = addons.all? do |addon|
if addon.eula_url
log.info "Addon '#{addon.short_name}' has an EULA at #{addon.eula_url}"
accept_eula(addon)
else
# no EULA specified => accepted
true
end
end

# go back if any EULA has not been accepted, let the user deselect the
# not accepted extension
all_accepted ? :next : :back
end

private

def accept_eula(addon)
Dir.mktmpdir("extension-eula-") do |tmpdir|
begin
Yast::Popup.Feedback(
_("Downloading License Agreement..."),
addon.short_name
) do
# download the license (with translations)
loader = EulaDownloader.new(addon.eula_url, tmpdir,
insecure: Helpers.insecure_registration)

loader.download
end
rescue Exception => e
log.error "Download failed: #{e.message}: #{e.backtrace}"
# %s is an extension name, e.g. "SUSE Linux Enterprise Software Development Kit"
Yast::Report.Error(_("Downloading the license for\n%s\nfailed.") % addon.short_name)
return false
end

Yast::ProductLicense.AskLicensesAgreementWithHeading(
[tmpdir],
Yast::ProductLicense.license_patterns,
# do not continue if not accepted
"abort",
# enable [Back]
true,
# base product
false,
# require agreement
true,
# dialog title
_("Extension and Module License Agreement"),
# %s is an extension name, e.g. "SUSE Linux Enterprise Software Development Kit"
_("%s License Agreement") % addon.short_name
) == :accepted
end
end

end
end
end

71 changes: 71 additions & 0 deletions test/eula_downloader_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#! /usr/bin/env rspec

require_relative "spec_helper"
require_relative "yast_stubs"
require 'tmpdir'

describe "Registration::EulaDownloader" do

before do
stub_yast_require
require "registration/eula_downloader"
end

describe ".download" do
it "downloads the license with translations" do
en_eula = "English EULA"
de_eula = "Deutsch EULA"

index = Net::HTTPSuccess.new("1.1", 200, "OK")
index.should_receive(:body).and_return("directory.yast\nlicense.txt\nlicense.de.txt")

license = Net::HTTPSuccess.new("1.1", 200, "OK")
license.should_receive(:body).and_return(en_eula)

license_de = Net::HTTPSuccess.new("1.1", 200, "OK")
license_de.should_receive(:body).and_return(de_eula)

# mock the responses for respective URL paths
Net::HTTP.any_instance.stub(:request) do |request|
case request.path
when "/eula/directory.yast"
index
when "/eula/license.txt"
license
when "/eula/license.de.txt"
license_de
end
end

Dir.mktmpdir do |tmpdir|
loader = Registration::EulaDownloader.new("https://example.com/eula", tmpdir)

expect{loader.download}.not_to raise_error

# the index file is not saved
expect(Dir.entries(tmpdir)).to match_array([".", "..", "license.txt", "license.de.txt"])
# check the license content
expect(File.read(File.join(tmpdir, "license.de.txt"))).to eq(de_eula)
expect(File.read(File.join(tmpdir, "license.de.txt"))).to eq(de_eula)
end
end

it "it raises an exception when download fails" do
index = Net::HTTPNotFound.new("1.1", 404, "Not Found")
index.should_receive(:body).and_return("")

Net::HTTP.any_instance.should_receive(:request).
with(an_instance_of(Net::HTTP::Get)).and_return(index)

Dir.mktmpdir do |tmpdir|
loader = Registration::EulaDownloader.new("https://example.com/eula", tmpdir)

expect{loader.download}.to raise_error RuntimeError, "Download failed"

# nothing saved
expect(Dir.entries(tmpdir)).to match_array([".", ".."])
end
end
end

end

0 comments on commit fa5e2f0

Please sign in to comment.