library/packages/src/modules/SignatureCheckDialogs.rb
# ***************************************************************************
#
# Copyright (c) 2002 - 2012 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
#
# ***************************************************************************
# Module: SignatureCheckDialogs.ycp
# Authors: Lukas Ocilka <locilka@suse.cz>
#
# Dialogs handling for RPM/Repository GPM signatures.
#
# $Id: SignatureCheckDialogs.ycp 28363 2006-02-24 12:27:15Z locilka $
require "yast"
module Yast
class SignatureCheckDialogsClass < Module
def main
Yast.import "Pkg"
Yast.import "UI"
textdomain "base"
Yast.import "Label"
Yast.import "Popup"
Yast.import "Message"
Yast.import "DontShowAgain"
Yast.import "Stage"
Yast.import "Linuxrc"
# --------------------------- Don't show this dialog again Magic ---------------------------
# /etc/sysconfig/security:CHECK_SIGNATURES
@check_signatures = nil # lazy
# Standard text strings
# GnuPG fingerprint used as "Fingerprint: AAA BBB CCC"
@s_fingerprint = _("Fingerprint")
# GnuPG key ID used as "Key ID: 1144AAAA444"
@s_keyid = _("Key ID")
# UI can show images
@has_local_image_support = nil
# List of trusted keys
#
# @see bugzilla #282254
@list_of_trusted_keys = []
end
# --------------------------- Don't show this dialog again Magic ---------------------------
# Functions sets whether user want's to show the dialog again
#
# @param [String] popup_type dialog type
# @param [true, false] show_it show again
# @param [String] popup_url
def SetShowThisPopup(popup_type, show_it, popup_url)
if popup_type.nil? || show_it.nil?
Builtins.y2error(
"Neither popup_type %1 nor show_it %2 can be nil!",
popup_type,
show_it
)
return
end
# it's the default
if show_it
Builtins.y2debug(
"User decision to show dialog '%1' again is '%2'",
popup_type,
show_it
)
# store only "don't show"
else
Builtins.y2milestone(
"User decision to show dialog '%1' for '%2' again is '%3'",
popup_type,
popup_url,
show_it
)
# Show again -> false, so, store it
DontShowAgain.SetShowQuestionAgain(
{
"q_type" => "inst-source",
"q_ident" => popup_type,
"q_url" => popup_url
},
show_it
)
end
nil
end
# Function returns whether user want's to show the dialog (again).
# true is the default if nothing is set.
#
# @param [String] popup_type dialog type
# @param [String] popup_url if any
# @return [Boolean] show the dialog
def GetShowThisPopup(popup_type, popup_url)
if popup_type.nil?
Builtins.y2error("popup_type %1 mustn't be nil!", popup_type)
return true
end
# Read the current configuration from system configuration
stored = DontShowAgain.GetShowQuestionAgain(
"q_type" => "inst-source",
"q_ident" => popup_type,
"q_url" => popup_url
)
# Stored in the configuration?
stored.nil? ? true : stored
end
# Function sets the default dialog return value
# for case when user selected "don't show again"
#
# @param [String] popup_type dialog type
# @param [Boolean] default_return
def SetDefaultDialogReturn(popup_type, default_return, popup_url)
if popup_type.nil? || default_return.nil?
Builtins.y2error(
"Neither popup_type %1 nor default_return %2 can be nil!",
popup_type,
default_return
)
return
end
Builtins.y2milestone(
"User decision in default return for '%1' for '%2' is '%3'",
popup_type,
popup_url,
default_return
)
DontShowAgain.SetDefaultReturn(
{
"q_type" => "inst-source",
"q_ident" => popup_type,
"q_url" => popup_url
},
default_return
)
nil
end
# Function returns the default popup return value
# for case when user selected "don't show again"
#
# @param [String] popup_type dialog type
# @param [String] popup_url dialog type
# @return [true, false] default dialog return
def GetDefaultDialogReturn(popup_type, popup_url)
if popup_type.nil?
Builtins.y2error("popup_type %1 mustn't be nil!", popup_type)
return false
end
stored_return = Convert.to_boolean(
DontShowAgain.GetDefaultReturn(
"q_type" => "inst-source",
"q_ident" => popup_type,
"q_url" => popup_url
)
)
Builtins.y2milestone(
"User decided not to show popup for '%1' again, returning user-decision '%2'",
popup_type,
stored_return
)
stored_return
end
# A semi-public helper. Convert the kernel parameter
# to the sysconfig string
# @return sysconfig value: yes, yast, no
def CheckSignatures
cmdline = Linuxrc.InstallInf("Cmdline")
Builtins.y2milestone("Cmdline: %1", cmdline)
val = Builtins.regexpsub(
cmdline,
"CHECK_SIGNATURES=([[:alpha:]]+)",
"\\1"
)
if val.nil?
val = Builtins.regexpsub(cmdline, "no_sig_check=([^[:digit:]]+)", "\\1")
if !val.nil?
trans = { "0" => "yes", "1" => "yast", "2" => "no" }
val = Ops.get(trans, val)
end
end
val = "yes" if val.nil?
val
end
# Should signatures be checked at all? Check a sysconfig variable
# (or a kernel parameter for the 1st installation stage).
# @return do checking?
def CheckSignaturesInYaST
if @check_signatures.nil?
chs = if Stage.initial
CheckSignatures()
else
# default is "yes"
Convert.to_string(
SCR.Read(path(".sysconfig.security.CHECK_SIGNATURES"))
)
end
Builtins.y2milestone("CHECK_SIGNATURES: %1", chs)
@check_signatures = chs != "no"
end
@check_signatures
end
# Used for unsiged file or package. Opens dialog asking whether user wants
# to use this unsigned item.
#
# @param [Symbol] item_type `file or `package
# @param [String] item_name file name or package name
# @param [String] dont_show_dialog_ident for the identification in magic "don't show" functions
# @return [Boolean] use or don't use ('true' if 'yes')
def UseUnsignedItem(item_type, item_name, dont_show_dialog_ident, repository)
Builtins.y2milestone(
"UseUnsignedItem: type: %1, name: %2, dontshowid: %3, repo: %4",
item_type,
item_name,
dont_show_dialog_ident,
repository
)
repo = Pkg.SourceGeneralData(repository)
description_text = Builtins.sformat(
if item_type == :package
# popup question, %1 stands for the package name
# %2 is a repository name
# %3 is URL of the repository
_(
"The package %1 from repository %2\n" \
"%3\n" \
"is not digitally signed. This means that the origin\n" \
"and integrity of the package cannot be verified. Installing the package\n" \
"may put the integrity of your system at risk.\n" \
"\n" \
"Install it anyway?"
)
else
item_name = strip_download_prefix(item_name)
# popup question, %1 stands for the filename
# %2 is a repository name
# %3 is URL of the repository
_(
"The file %1 from repository %2\n" \
"%3\n" \
"is not digitally signed. The origin and integrity of the file\n" \
"cannot be verified. Using the file anyway puts the integrity of your \n" \
"system at risk.\n" \
"\n" \
"Use it anyway?\n"
)
end,
item_name,
Ops.get_locale(repo, "name", _("Unknown")),
Ops.get_locale(repo, "url", _("Unknown"))
)
UI.OpenDialog(
Opt(:decorated),
VBox(
Heading(
if item_type == :package
_("Unsigned Package")
else
_("Unsigned File")
end
),
MarginBox(0.5, 0.5, Label(description_text)),
Left(
MarginBox(
0,
1.2,
CheckBox(
Id(:dont_show_again),
Message.DoNotShowMessageAgain,
GetShowThisPopup(dont_show_dialog_ident, item_name) ? false : true
)
)
),
YesNoButtons(:no)
)
)
ret = WaitForYesNoCancelUserInput()
# default value
ret = false if ret.nil?
# Store the don't show value, store the default return value
HandleDoNotShowDialogAgain(
ret,
dont_show_dialog_ident,
:dont_show_again,
item_name
)
UI.CloseDialog
ret
end
# Used for file or package on signed repository but without any checksum.
# Opens dialog asking whether user wants to use this item.
#
# @param [Symbol] item_type `file or `package
# @param [String] item_name file name or package name
# @param [String] dont_show_dialog_ident for the identification in magic "don't show" functions
# @return [Boolean] use or don't use ('true' if 'yes')
def UseItemWithNoChecksum(item_type, item_name, dont_show_dialog_ident)
description_text = Builtins.sformat(
if item_type == :package
# popup question, %1 stands for the package name
_(
"No checksum for package %1 was found in the repository.\n" \
"While the package is part of the signed repository, it is not contained \n" \
"in the list of checksums in this repository. Installing the package puts \n" \
"the integrity of your system at risk.\n" \
"\n" \
"Install it anyway?\n"
)
else
item_name = strip_download_prefix(item_name)
# popup question, %1 stands for the filename
_(
"No checksum for file %1 was found in the repository.\n" \
"This means that the file is part of the signed repository,\n" \
"but the list of checksums in this repository does not mention this file. Using the file\n" \
"may put the integrity of your system at risk.\n" \
"\n" \
"Use it anyway?"
)
end,
item_name
)
UI.OpenDialog(
Opt(:decorated),
VBox(
# popup heading
Heading(_("No Checksum Found")),
MarginBox(0.5, 0.5, Label(description_text)),
Left(
MarginBox(
0,
1.2,
CheckBox(
Id(:dont_show_again),
Message.DoNotShowMessageAgain,
GetShowThisPopup(dont_show_dialog_ident, item_name) ? false : true
)
)
),
YesNoButtons(:no)
)
)
ret = WaitForYesNoCancelUserInput()
# default value
ret = false if ret.nil?
# Store the don't show value, store the default return value
HandleDoNotShowDialogAgain(
ret,
dont_show_dialog_ident,
:dont_show_again,
item_name
)
UI.CloseDialog
ret
end
# Used for corrupted file or package. Opens dialog asking whether user wants
# to use this corrupted item.
#
# @param [Symbol] item_type `file or `package
# @param [String] item_name file name or package name
# @param [Hash{String => Object}] key Used key
# @return [Boolean] use or don't use ('true' if 'yes')
def UseCorruptedItem(item_type, item_name, key, repository)
key = deep_copy(key)
repo = Pkg.SourceGeneralData(repository)
description_text = Builtins.sformat(
if item_type == :package
# popup question, %1 stands for the package name, %2 for the complete description of the GnuPG key (multiline)
_(
"Package %1 from repository %2\n" \
"%3\n" \
"is signed with the following GnuPG key, but the integrity check failed: %4\n" \
"\n" \
"The package has been changed, either by accident or by an attacker,\n" \
"since the repository creator signed it. Installing it is a big risk\n" \
"for the integrity and security of your system.\n" \
"\n" \
"Install it anyway?\n"
)
else
item_name = strip_download_prefix(item_name)
# popup question, %1 stands for the filename, %2 for the complete description of the GnuPG key (multiline)
_(
"File %1 from repository %2\n" \
"%3\n" \
"is signed with the following GnuPG key, but the integrity check failed: %4\n" \
"\n" \
"The file has been changed, either by accident or by an attacker,\n" \
"since the repository creator signed it. Using it is a big risk\n" \
"for the integrity and security of your system.\n" \
"\n" \
"Use it anyway?\n"
)
end,
item_name,
Ops.get_locale(repo, "name", _("Unknown")),
Ops.get_locale(repo, "url", _("Unknown")),
Ops.add("\n\n", GPGKeyAsString(key))
)
UI.OpenDialog(
Opt(:decorated),
VBox(
# popup heading
Heading(_("Validation Check Failed")),
MarginBox(0.5, 0.5, Label(description_text)),
YesNoButtons(:no)
)
)
ret = WaitForYesNoCancelUserInput()
# default value
ret = false if ret.nil?
UI.CloseDialog
ret
end
# Used for file or package signed by unknown key.
#
# @param [Symbol] item_type `file or `package
# @param [String] item_name file name or package name
# @param [String] key_id
# @param [String] dont_show_dialog_ident for the identification in magic "don't show" functions
# @param [Fixnum] repoid Id of the repository from the item was downloaded
# @return [Boolean] true if 'yes, use file'
def ItemSignedWithUnknownSignature(item_type, item_name, key_id, dont_show_dialog_ident, repoid)
repo_url = Ops.get_string(Pkg.SourceGeneralData(repoid), "url", "")
description_text = Builtins.sformat(
if item_type == :package
# popup question, %1 stands for the package name, %2 for the complex multiline description of the GnuPG key
_(
"The package %1 is digitally signed\n" \
"with the following unknown GnuPG key: %2.\n" \
"\n" \
"This means that a trust relationship to the creator of the package\n" \
"cannot be established. Installing the package may put the integrity\n" \
"of your system at risk.\n" \
"\n" \
"Install it anyway?"
)
else
item_name = strip_download_prefix(item_name)
# popup question, %1 stands for the filename, %2 for the complex multiline description of the GnuPG key
_(
"The file %1\n" \
"is digitally signed with the following unknown GnuPG key: %2.\n" \
"\n" \
"This means that a trust relationship to the creator of the file\n" \
"cannot be established. Using the file may put the integrity\n" \
"of your system at risk.\n" \
"\n" \
"Use it anyway?"
)
end,
# TODO: use something like "%1 from %2" and make it translatable
if repo_url == ""
item_name
else
Builtins.sformat("%1 (%2)", item_name, repo_url)
end,
Ops.add(
"\n",
# Part of the GnuPG key description in popup, %1 is a GnuPG key ID
Builtins.sformat(_("ID: %1"), key_id)
)
)
UI.OpenDialog(
Opt(:decorated),
VBox(
# popup heading
Heading(_("Unknown GnuPG Key")),
MarginBox(0.5, 0.5, Label(description_text)),
Left(
MarginBox(
0,
1.2,
CheckBox(
Id(:dont_show_again),
Message.DoNotShowMessageAgain,
GetShowThisPopup(dont_show_dialog_ident, item_name) ? false : true
)
)
),
YesNoButtons(:no)
)
)
# This will optionally offer to retrieve the key from gpg keyservers
# That's why it will return 'symbol' instead of 'boolean'
# But by now it only handles yes/no/cancel
ret = WaitForYesNoCancelUserInput()
# default value
ret = false if ret.nil?
# Store the don't show value, store the default return value
HandleDoNotShowDialogAgain(
ret,
dont_show_dialog_ident,
:dont_show_again,
item_name
)
UI.CloseDialog
ret
end
# Used for file or package signed by a public key. This key is still
# not listed in trusted keys.
#
# @param item_type [Symbol] `:file` or `:package`
# @param item_name [String] file name or package name
# @param key [Hash<String, Object>]
# @return [Symbol] `:key_import`, `:install`, `:skip`
def ItemSignedWithPublicSignature(item_type, item_name, key)
key = deep_copy(key)
description_text = Builtins.sformat(
if item_type == :package
# popup question, %1 stands for the package name, %2 for the key ID, %3 for the key name
_(
"The package %1 is digitally signed\n" \
"with key '%2 (%3)'.\n" \
"\n" \
"There is no trust relationship with the owner of the key.\n" \
"If you trust the owner, mark the key as trusted.\n" \
"\n" \
"Installing a package from an unknown repository puts\n" \
"the integrity of your system at risk. It is safest\n" \
"to skip the package.\n"
)
else
item_name = strip_download_prefix(item_name)
# popup question, %1 stands for the filename, %2 for the key ID, %3 for the key name
_(
"The file %1 is digitally signed\n" \
"with key '%2 (%3)'.\n" \
"\n" \
"There is no trust relationship with the owner of the key.\n" \
"If you trust the owner, mark the key as trusted.\n" \
"\n" \
"Installing a file from an unknown repository puts\n" \
"the integrity of your system at risk. It is safest\n" \
"to skip it.\n"
)
end,
item_name,
Ops.get_string(key, "id", ""),
Ops.get_string(key, "name", "")
)
UI.OpenDialog(
Opt(:decorated),
VBox(
# popup heading
Heading(_("Signed with Untrusted Public Key")),
MarginBox(0.5, 0.5, Label(description_text)),
ButtonBox(
# push button
PushButton(
Id(:trust),
Opt(:okButton, :key_F10),
_("&Trust and Import the Key")
),
PushButton(Id(:skip), Opt(:cancelButton, :key_F9), Label.SkipButton)
)
)
)
UI.SetFocus(:skip)
# wait for one of listed ID's, return the default value in case of `cancel
ret = WaitForSymbolUserInput([:trust, :skip], :skip)
if ret == :trust
# later, if asking whether to import the key, the key is trusted
# so it will be also imported
# bugzilla #282254
@list_of_trusted_keys = Builtins.add(
@list_of_trusted_keys,
Ops.get_string(key, "id", "")
)
end
UI.CloseDialog
ret
end
# ImportUntrustedGPGKeyIntoTrustedDialog
#
# @param key [Hash<String, Object>]
# @param repository [Integer]
# @return [Boolean] whether zypp should import the key into the keyring of trusted keys
def ImportGPGKeyIntoTrustedDialog(key, repository)
key = deep_copy(key)
# additional Richtext (HTML) warning text (kind of help), 1/2
warning_text = _(
"<p>The owner of the key may distribute updates,\n" \
"packages, and package repositories that your system will trust and offer\n" \
"for installation and update without any further warning. In this way,\n" \
"importing the key into your keyring of trusted keys allows the key owner\n" \
"to have a certain amount of control over the software on your system.</p>"
) +
# additional Richtext (HTML) warning text (kind of help), 2/2
_(
"<p>A warning dialog opens for every package that\n" \
"is not signed by a trusted (imported) key. If you do not trust the key,\n" \
"the packages or repositories created by the owner of the key will not be used.</p>"
)
repo = Pkg.SourceGeneralData(repository)
# popup message - label, part 1, %1 stands for repository name, %2 for its URL
dialog_text = Builtins.sformat(
_(
"The following GnuPG key has been found in repository\n" \
"%1\n" \
"(%2):"
),
Ops.get_locale(repo, "name", _("Unknown")),
(repo && repo["url"]) ? repo["url"].scan(/.{1,59}/).join("\n") : _("Unknown")
)
# popup message - label, part 2
dialog_text2 = _(
"You can choose to import it into your keyring of trusted\n" \
"public keys, meaning that you trust the owner of the key.\n" \
"You should be sure that you can trust the owner and that\n" \
"the key really belongs to that owner before importing it."
)
expires = Ops.get_integer(key, "expires_raw", 0)
if Ops.greater_than(expires, 0) &&
Ops.greater_than(Builtins.time, expires)
# warning label - the key to import is expired
dialog_text2 = Ops.add(
Ops.add(Builtins.sformat(_("WARNING: The key has expired!")), "\n\n"),
dialog_text2
)
end
displayinfo = UI.GetDisplayInfo
# hide additional help text in not enough wide terminals so
# the important GPG key properties are completely displayed
hide_help = Ops.get_boolean(displayinfo, "TextMode", false) &&
Ops.less_than(Ops.get_integer(displayinfo, "Width", 80), 105)
UI.OpenDialog(
Opt(:decorated),
HBox(
# left-side help
if hide_help
Empty()
else
HWeight(3, VBox(RichText(warning_text)))
end,
HSpacing(1.5),
# dialog
HWeight(
5,
VBox(
# popup heading
Heading(_("Import Untrusted GnuPG Key")),
# dialog message
MarginBox(
0.4,
0.4,
VBox(
Left(Label(dialog_text)),
GPGKeyAsTerm(key),
Left(Label(dialog_text2))
)
),
# dialog buttons
ButtonBox(
# push button
PushButton(Id(:trust), Opt(:key_F10, :okButton), _("&Trust")),
PushButton(
Id(:cancel),
Opt(:key_F9, :cancelButton),
Label.CancelButton
)
)
)
)
)
)
UI.SetFocus(:cancel)
ret = Convert.to_symbol(UI.UserInput)
UI.CloseDialog
ret == :trust
end
# Ask user to accept wrong digest
# @param [String] filename Name of the file
# @param [String] requested_digest Expected checksum
# @param [String] found_digest Current checksum
# @param [String] dont_show_dialog_ident Uniq ID for "don't show again"
# @return [Boolean] true when user accepts the file
def UseFileWithWrongDigest(filename, requested_digest, found_digest, dont_show_dialog_ident)
filename = strip_download_prefix(filename)
description_text =
# popup question, %1 stands for the filename, %2 is expected checksum
# %3 is the current checksum (e.g. "803a8ff00d00c9075a1bd223a480bcf92d2481c1")
Builtins.sformat(
_(
"The expected checksum of file %1\n" \
"is %2,\n" \
"but the current checksum is %3.\n" \
"\n" \
"The file has been changed by accident or by an attacker\n" \
"since the repository creator signed it. Using it is a big risk\n" \
"for the integrity and security of your system.\n" \
"\n" \
"Use it anyway?\n"
),
filename,
requested_digest,
found_digest
)
# dialog heading - displayed in a big bold font
heading = _("Wrong Digest")
RunSimpleErrorPopup(
heading,
description_text,
dont_show_dialog_ident,
filename
)
end
# Ask user to accept a file with unknown checksum
# @param [String] filename Name of the file
# @param [String] digest Current checksum
# @param [String] dont_show_dialog_ident Uniq ID for "don't show again"
# @return [Boolean] true when user accepts the file
def UseFileWithUnknownDigest(filename, digest, dont_show_dialog_ident)
filename = strip_download_prefix(filename)
description_text =
# popup question, %1 stands for the filename, %2 is expected digest, %3 is the current digest
Builtins.sformat(
_(
"The checksum of file %1\n" \
"is %2,\n" \
"but the expected checksum is not known.\n" \
"\n" \
"This means that the origin and integrity of the file\n" \
"cannot be verified. Using the file puts the integrity of your system at risk.\n" \
"\n" \
"Use it anyway?\n"
),
filename,
digest
)
# dialog heading - displayed in a big bold font
heading = _("Unknown Digest")
RunSimpleErrorPopup(
heading,
description_text,
dont_show_dialog_ident,
filename
)
end
publish function: :SetShowThisPopup, type: "void (string, boolean, string)"
publish function: :GetShowThisPopup, type: "boolean (string, string)"
publish function: :SetDefaultDialogReturn, type: "void (string, boolean, string)"
publish function: :GetDefaultDialogReturn, type: "boolean (string, string)"
publish function: :CheckSignatures, type: "string ()"
publish function: :CheckSignaturesInYaST, type: "boolean ()"
publish function: :UseUnsignedItem, type: "boolean (symbol, string, string, integer)"
publish function: :UseItemWithNoChecksum, type: "boolean (symbol, string, string)"
publish function: :UseCorruptedItem, type: "boolean (symbol, string, map <string, any>, integer)"
publish function: :ItemSignedWithUnknownSignature, type: "boolean (symbol, string, string, string, integer)"
publish function: :ItemSignedWithPublicSignature, type: "symbol (symbol, string, map <string, any>)"
publish function: :ImportGPGKeyIntoTrustedDialog, type: "boolean (map <string, any>, integer)"
publish function: :UseFileWithWrongDigest, type: "boolean (string, string, string, string)"
publish function: :UseFileWithUnknownDigest, type: "boolean (string, string, string)"
private
# helper to strip download path. It uses internal knowledge that download
# prefix ends in TmpDir.* zypp location
def strip_download_prefix(path)
path.sub(/\A\/.*\/TmpDir\.[^\/]+\//, "")
end
def HandleDoNotShowDialogAgain(default_return, dont_show_dialog_ident, dont_show_dialog_checkboxid, dont_show_url)
dont_show_status = Convert.to_boolean(
UI.QueryWidget(Id(dont_show_dialog_checkboxid), :Value)
)
# Widget doesn't exist
if dont_show_status.nil?
Builtins.y2warning(
"No such UI widget with ID: %1",
dont_show_dialog_checkboxid
)
# Checkbox selected -> Don't show again
elsif dont_show_status == true
Builtins.y2debug(
"User decision -- don't show the dialog %1 again, setting default return %2",
dont_show_dialog_ident,
default_return
)
SetShowThisPopup(dont_show_dialog_ident, false, dont_show_url)
SetDefaultDialogReturn(
dont_show_dialog_ident,
default_return,
dont_show_url
)
# Checkbox not selected -> Show again
else
SetShowThisPopup(dont_show_dialog_ident, true, dont_show_url)
end
nil
end
# Function adds delimiter between after_chars characters in the string
#
# @param whattosplit [String] text to be splitted
# @param delimiter [String] to place
# @param after_chars [Integer] after characters
# @return [String] after_chars with delimiters
def StringSplitter(whattosplit, delimiter, after_chars)
splittedstring = ""
after_chars_counter = 0
max_size = Builtins.size(whattosplit)
loop do
if Ops.greater_or_equal(
Ops.add(after_chars_counter, after_chars),
max_size
)
splittedstring = Ops.add(
Ops.add(splittedstring, (splittedstring == "") ? "" : delimiter),
Builtins.substring(whattosplit, after_chars_counter)
)
break
else
splittedstring = Ops.add(
Ops.add(splittedstring, (splittedstring == "") ? "" : delimiter),
Builtins.substring(whattosplit, after_chars_counter, after_chars)
)
after_chars_counter = Ops.add(after_chars_counter, after_chars)
end
end
splittedstring
end
# Returns term of yes/no buttons
#
# @param default_button [Symbol] `:yes` or `:no`. If another value is passed, `:no` is used.
# @return [Yast::Term] with buttons
def YesNoButtons(default_button)
yes_button = PushButton(
Id(:yes),
Opt(:okButton, :key_F10),
Label.YesButton
)
no_button = PushButton(
Id(:no),
Opt(:cancelButton, :key_F9),
Label.NoButton
)
if default_button == :yes
yes_button = PushButton(
Id(:yes),
Opt(:default, :okButton, :key_F10),
Label.YesButton
)
else
no_button = PushButton(
Id(:no),
Opt(:default, :cancelButton, :key_F9),
Label.NoButton
)
end
ButtonBox(yes_button, no_button)
end
# Returns 'true' (yes), 'false' (no) or 'nil' (cancel)
#
# @return [Boolean] user input yes==true
def WaitForYesNoCancelUserInput
user_input = nil
ret = nil
loop do
user_input = UI.UserInput
# yes button
case user_input
when :yes
ret = true
break
# no button
when :no
ret = false
break
# closing window uisng [x]
when :cancel
ret = nil
break
else
Builtins.y2error("Unknown user input: '%1'", user_input)
next
end
end
ret
end
# Waits for user input and checks it agains accepted symbols.
# Returns the default symbol in case of `cancel (user closes the dialog).
#
# @param list_of_accepted [Array<Symbol>] of accepted symbol by UserInput
# @param default_symb [Symbol] default return for case of `cancel
def WaitForSymbolUserInput(list_of_accepted, default_symb)
list_of_accepted = deep_copy(list_of_accepted)
user_input = nil
ret = nil
loop do
user_input = Convert.to_symbol(UI.UserInput)
if Builtins.contains(list_of_accepted, user_input)
ret = user_input
break
elsif user_input == :cancel
ret = default_symb
break
else
Builtins.y2error("Unknown user input: '%1'", user_input)
next
end
end
ret
end
# FIXME: add GPG class that have method to_string and to_term
def GPGKeyAsString(key)
key = deep_copy(key)
# Part of the GnuPG key description in popup, %1 is a GnuPG key ID
Ops.add(
Ops.add(
Ops.add(
Ops.add(
Ops.add(
Builtins.sformat(_("ID: %1"), Ops.get_string(key, "id", "")),
"\n"
),
if Ops.get_string(key, "fingerprint", "").nil? ||
Ops.get_string(key, "fingerprint", "") == ""
# Part of the GnuPG key description in popup, %1 is a GnuPG key fingerprint
""
else
Builtins.sformat(
_("Fingerprint: %1") + "\n",
StringSplitter(Ops.get_string(key, "fingerprint", ""), " ", 4)
)
end
),
# Part of the GnuPG key description in popup, %1 is a GnuPG key name
Builtins.sformat(_("Name: %1"), Ops.get_string(key, "name", ""))
),
if Ops.get_string(key, "created", "") == ""
""
else
Ops.add(
"\n",
Builtins.sformat(
_("Created: %1"),
Ops.get_string(key, "created", "")
)
)
end
),
if Ops.get_string(key, "expires", "") == ""
""
else
Ops.add(
"\n",
Builtins.sformat(
_("Expires: %1"),
Ops.get_string(key, "expires", "")
)
)
end
)
end
# FIXME: add GPG class that have method to_string and to_term
def GPGKeyAsTerm(key)
key = deep_copy(key)
rt = Ops.add(
# GPG key property
Builtins.sformat(
"<b>%1</b>%2",
_("ID: "),
Ops.get_string(key, "id", "")
),
# GPG key property
Builtins.sformat(
"<br><b>%1</b>%2",
_("Name: "),
Ops.get_string(key, "name", "")
)
)
if Ops.greater_than(
Builtins.size(Ops.get_string(key, "fingerprint", "")),
0
)
# GPG key property
rt = Ops.add(
rt,
Builtins.sformat(
"<br><b>%1</b>%2",
_("Fingerprint: "),
StringSplitter(Ops.get_string(key, "fingerprint", ""), " ", 4)
)
)
end
if Ops.greater_than(Builtins.size(Ops.get_string(key, "created", "")), 0)
# GPG key property
rt = Ops.add(
rt,
Builtins.sformat(
"<br><b>%1</b>%2",
_("Created: "),
Ops.get_string(key, "created", "")
)
)
end
if Ops.greater_than(Builtins.size(Ops.get_string(key, "expires", "")), 0)
# GPG key property
rt = Ops.add(
rt,
Builtins.sformat(
"<br><b>%1</b>%2",
_("Expires: "),
Ops.get_string(key, "expires", "")
)
)
end
RichText(rt)
end
def RunSimpleErrorPopup(heading, description_text, dont_show_dialog_ident, dont_show_dialog_param)
UI.OpenDialog(
Opt(:decorated),
VBox(
# dialog heading - displayed in a big bold font
Heading(heading),
MarginBox(0.5, 0.5, Label(description_text)),
Left(
MarginBox(
0,
1.2,
CheckBox(
Id(:dont_show_again),
Message.DoNotShowMessageAgain,
GetShowThisPopup(dont_show_dialog_ident, dont_show_dialog_param) ? false : true
)
)
),
YesNoButtons(:no)
)
)
ret = WaitForYesNoCancelUserInput()
# default value
ret = false if ret.nil?
# Store the don't show value, store the default return value
HandleDoNotShowDialogAgain(
ret,
dont_show_dialog_ident,
:dont_show_again,
dont_show_dialog_param
)
UI.CloseDialog
ret
end
end
SignatureCheckDialogs = SignatureCheckDialogsClass.new
SignatureCheckDialogs.main
end