class GPGME::Ctx
Constants
- IMPORT_FLAGS
Public Class Methods
check_gpg_version()
click to toggle source
# File lib/schleuder/gpgme/ctx.rb, line 81 def self.check_gpg_version if ! sufficient_gpg_version?('2.2') $stderr.puts "Error: GnuPG version >= 2.2 required.\nPlease install it and/or provide the path to the binary via the environment-variable GPGBIN.\nExample: GPGBIN=/opt/gpg2/bin/gpg ..." exit 1 end end
gpg_engine()
click to toggle source
# File lib/schleuder/gpgme/ctx.rb, line 88 def self.gpg_engine GPGME::Engine.info.find {|e| e.protocol == GPGME::PROTOCOL_OpenPGP } end
gpgcli(args) { |stdin, stdout, stderr| ... }
click to toggle source
# File lib/schleuder/gpgme/ctx.rb, line 147 def self.gpgcli(args) exitcode = -1 errors = [] output = [] base_cmd = gpg_engine.file_name base_args = '--no-greeting --quiet --armor --trust-model always --no-tty --command-fd 0 --status-fd 1' cmd = [base_cmd, base_args, args].flatten.join(' ') Open3.popen3(cmd) do |stdin, stdout, stderr, thread| if block_given? output = yield(stdin, stdout, stderr) else output = stdout.readlines end stdin.close if ! stdin.closed? errors = stderr.readlines exitcode = thread.value.exitstatus end # Don't treat warnings as errors but log them. errors = errors.map do |line| if line.match?(/gpg: WARNING: (unsafe permissions on homedir|using insecure memory)/i) Schleuder.logger.warn(line) nil else line end end.compact [errors, output, exitcode] rescue Errno::ENOENT raise 'Need gpg in $PATH or in $GPGBIN' end
set_gpg_path_from_env()
click to toggle source
Tell gpgme to use the given binary.
# File lib/schleuder/gpgme/ctx.rb, line 65 def self.set_gpg_path_from_env path = ENV['GPGBIN'].to_s if ! path.empty? Schleuder.logger.debug "setting gpg to use #{path}" GPGME::Engine.set_info(GPGME::PROTOCOL_OpenPGP, path, ENV['GNUPGHOME']) if gpg_engine.version.nil? $stderr.puts "Error: The binary you specified doesn't provide a gpg-version." exit 1 end end end
sufficient_gpg_version?(required)
click to toggle source
# File lib/schleuder/gpgme/ctx.rb, line 77 def self.sufficient_gpg_version?(required) Gem::Version.new(required) <= Gem::Version.new(gpg_engine.version) end
Public Instance Methods
find_distinct_key(input=nil, secret_only=nil)
click to toggle source
# File lib/schleuder/gpgme/ctx.rb, line 42 def find_distinct_key(input=nil, secret_only=nil) keys = keys(normalize_key_identifier(input), secret_only) if keys.size == 1 keys.first else nil end end
find_keys(input=nil, secret_only=nil)
click to toggle source
# File lib/schleuder/gpgme/ctx.rb, line 38 def find_keys(input=nil, secret_only=nil) keys(normalize_key_identifier(input), secret_only) end
import_filter_arg()
click to toggle source
# File lib/schleuder/gpgme/ctx.rb, line 180 def import_filter_arg %{ --import-filter drop-sig='sig_created_d > 0000-00-00'} end
import_filtered(input, gpg_extra_arg='')
click to toggle source
# File lib/schleuder/gpgme/ctx.rb, line 92 def import_filtered(input, gpg_extra_arg='') # Import through gpgcli so we can use import-filter. GPGME still does # not provide that feature (as of summer 2023): <https://dev.gnupg.org/T4721> :( gpgerr, gpgout, exitcode = self.class.gpgcli("#{import_filter_arg} #{gpg_extra_arg} --import") do |stdin, stdout, stderr| # Wrap this into a block because gpg breaks the pipe if it encounters invalid data. begin stdin.print input rescue Errno::EPIPE end stdin.close stdout.readlines end if exitcode > 0 RuntimeError.new(gpgerr.join("\n")) else translate_import_data(gpgout) end end
interpret_import_result(import_result)
click to toggle source
TODO: find solution for I18n — could be a different language in API-clients than here!
# File lib/schleuder/gpgme/ctx.rb, line 21 def interpret_import_result(import_result) case import_result.imports.size when 1 import_status = import_result.imports.first if import_status.action == 'error' [nil, "Key #{import_status.fpr} could not be imported!"] else [import_status.fpr, nil] end when 0 [nil, 'The given key material did not contain any keys!'] else # TODO: report import-stati of the keys? [nil, 'The given key material contained more than one key, could not determine which fingerprint to use. Please set it manually!'] end end
keyimport(keydata)
click to toggle source
This differs from import_filtered
() in that it doesn’t filter the keys at all, and that it returns the import-results themselves, not strings based on those results.
# File lib/schleuder/gpgme/ctx.rb, line 13 def keyimport(keydata) self.import_keys(GPGME::Data.new(keydata)) result = self.import_result result.imports.map(&:set_action) result end
normalize_key_identifier(input)
click to toggle source
# File lib/schleuder/gpgme/ctx.rb, line 51 def normalize_key_identifier(input) case input when /.*?([^ <>]+@[^ <>]+).*?/ "<#{$1}>" when /^http/ input when Conf::FINGERPRINT_REGEXP "0x#{input.gsub(/^0x/, '')}" else input end end
refresh_key_filter_messages(strings)
click to toggle source
Unfortunately we can’t distinguish between a failure to connect the keyserver, and a failure to find the key on the server. So we try to filter misleading errors to check if there are any to be reported.
# File lib/schleuder/gpgme/ctx.rb, line 137 def refresh_key_filter_messages(strings) strings.reject do |line| line.chomp == 'gpg: keyserver refresh failed: No data' || line.match(/^gpgkeys: key .* not found on keyserver/) || line.match(/^gpg: refreshing /) || line.match(/^gpg: requesting key /) || line.match(/^gpg: no valid OpenPGP data found/) end end
translate_import_data(gpgoutput)
click to toggle source
# File lib/schleuder/gpgme/ctx.rb, line 111 def translate_import_data(gpgoutput) result = {} gpgoutput.grep(/IMPORT_OK/) do |import_ok| next if import_ok.blank? import_status, fingerprint = import_ok.split(/\s/).slice(2, 2) import_status = import_status.to_i states = [] if import_status == 0 states << I18n.t('import_states.unchanged') else IMPORT_FLAGS.each do |text, int| if (import_status & int) > 0 states << I18n.t("import_states.#{text}") end end end result[fingerprint] = states end result end