From 275885cb4187d7df5b72182f9fba091cdd21e3b5 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 11 Jan 2014 00:03:09 +0000 Subject: [PATCH] improve keyring analyzer - define separate gnupg homedir as gnupghome - update file comments in ddportfolioservice/model/ddportfolio.ini and ddportfolioservice/model/keyringanalyzer.py to reflect current copyright years and project name - keyringanalyzer.py: - refactor to reduce function complexity - fix PEP8 violations - use gnupghome setting - switch to SafeConfigParser --- ddportfolioservice/model/ddportfolio.ini | 23 ++-- ddportfolioservice/model/keyringanalyzer.py | 117 ++++++++++++-------- 2 files changed, 81 insertions(+), 59 deletions(-) diff --git a/ddportfolioservice/model/ddportfolio.ini b/ddportfolioservice/model/ddportfolio.ini index 7dd4073..3545b44 100644 --- a/ddportfolioservice/model/ddportfolio.ini +++ b/ddportfolioservice/model/ddportfolio.ini @@ -1,24 +1,25 @@ # -# Configuration for DDPortfolio service -# Copyright © 2009, 2010, 2011, 2012, 2013 Jan Dittberner +# Configuration for Debian Member Portfolio service # -# This file is part of DDPortfolio service. +# Copyright © 2009-2014 Jan Dittberner # -# DDPortfolio service is free software: you can redistribute it and/or -# modify it under the terms of the GNU Affero General Public License -# as published by the Free Software Foundation, either version 3 of -# the License, or (at your option) any later version. +# This file is part of the Debian Member Portfolio service. # -# DDPortfolio service 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 -# Affero General Public License for more details. +# Debian Member Portfolio service is free software: you can redistribute it +# and/or modify it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the License, +# or (at your option) any later version. +# +# Debian Member Portfolio service 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 Affero +# General Public License for more details. # # You should have received a copy of the GNU Affero General Public # License along with this program. If not, see # . # [DEFAULT] +gnupghome=~/debian/gnupghome keyring.dir=~/debian/keyring.debian.org/keyrings urlbuilder.sections=overview,bugs,build,qa,lists,files,membership, miscellaneous,ssh,ubuntu diff --git a/ddportfolioservice/model/keyringanalyzer.py b/ddportfolioservice/model/keyringanalyzer.py index c82772e..4f134a4 100644 --- a/ddportfolioservice/model/keyringanalyzer.py +++ b/ddportfolioservice/model/keyringanalyzer.py @@ -1,20 +1,21 @@ # -*- python -*- # -*- coding: utf-8 -*- # -# DDPortfolio service application key ring analyzer tool -# Copyright © 2009, 2010, 2011, 2012 Jan Dittberner +# Debian Member Portfolio service application key ring analyzer tool # -# This file is part of DDPortfolio service. +# Copyright © 2009-2014 Jan Dittberner # -# DDPortfolio service is free software: you can redistribute it and/or -# modify it under the terms of the GNU Affero General Public License -# as published by the Free Software Foundation, either version 3 of +# This file is part of the Debian Member Portfolio service. +# +# Debian Member Portfolio service is free software: you can redistribute it +# and/or modify it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of # the License, or (at your option) any later version. # -# DDPortfolio service 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 -# Affero General Public License for more details. +# Debian Member Portfolio service 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 Affero +# General Public License for more details. # # You should have received a copy of the GNU Affero General Public # License along with this program. If not, see @@ -38,27 +39,28 @@ import sys import email.utils +CONFIG = ConfigParser.SafeConfigParser() + + def _get_keyrings(): """ Gets the available keyring files from the keyring directory configured in ddportfolio.ini. """ - my_config = ConfigParser.ConfigParser() - my_config.readfp(pkg_resources.resource_stream( - __name__, 'ddportfolio.ini')) - keyringdir = os.path.expanduser(my_config.get('DEFAULT', 'keyring.dir')) + keyringdir = os.path.expanduser(CONFIG.get('DEFAULT', 'keyring.dir')) logging.debug("keyring dir is %s", keyringdir) keyrings = glob.glob(os.path.join(keyringdir, '*.gpg')) keyrings.extend(glob.glob(os.path.join(keyringdir, '*.pgp'))) keyrings.sort() return keyrings + def _parse_uid(uid): """ Parse a uid of the form 'Real Name ' into email and realname parts. """ - + # First try with the Python library, but it doesn't always catch everything (name, mail) = email.utils.parseaddr(uid) if (not name) and (not mail): @@ -103,49 +105,63 @@ def _add_to_result(key, newvalue): resultdict[thekey].append(newvalue) +def _handle_mail(mail, fpr): + if mail.endswith('@debian.org'): + login = mail[0:-len('@debian.org')] + _add_to_result('login:email:%s' % mail, login) + _add_to_result('login:fpr:%s' % fpr, login) + _add_to_result('fpr:login:%s' % login, fpr) + _add_to_result('fpr:email:%s' % mail, fpr) + _add_to_result('email:fpr:%s' % fpr, mail) + + +def _handle_uid(uid, fpr): + # Do stuff with 'uid' + if uid: + (uid, mail) = _parse_uid(uid) + if mail: + _handle_mail(mail, fpr) + if uid: + _add_to_result('name:fpr:%s' % fpr, uid) + if mail: + _add_to_result('name:email:%s' % mail, uid) + return fpr + + +def process_gpg_list_keys_line(line, fpr): + """ + Process a line of gpg --list-keys --with-colon output. + """ + items = line.split(':') + if items[0] == 'pub': + return None + if items[0] == 'fpr': + return items[9].strip() + if items[0] == 'uid': + if items[1] == 'r': + return fpr + return _handle_uid(items[9].strip(), fpr) + else: + return fpr + + def process_keyrings(): """Process the keyrings and store the extracted data in an anydbm file.""" for keyring in _get_keyrings(): logging.debug("get data from %s", keyring) - proc = subprocess.Popen(["gpg", "--no-options", "--no-default-keyring", + proc = subprocess.Popen([ + "gpg", "--no-options", "--no-default-keyring", + "--homedir", os.path.expanduser( + CONFIG.get('DEFAULT', 'gnupghome')), "--no-expensive-trust-checks", "--keyring", keyring, "--list-keys", - "--with-colons", "--fixed-list-mode", "--with-fingerprint", "--with-fingerprint"], + "--with-colons", "--fixed-list-mode", "--with-fingerprint", + "--with-fingerprint"], stdout=subprocess.PIPE) fpr = None - entry = None - lastpub = None for line in proc.stdout.readlines(): - items = line.split(':') - uid = None - if items[0] == 'pub': - fpr = entry = None - lastpub = items[4].strip() - continue - elif items[0] == 'fpr': - fpr = items[9].strip() - elif items[0] == 'uid': - if items[1] == 'r': - continue - uid = items[9].strip() - else: - continue - # Do stuff with 'uid' - if uid: - (uid, mail) = _parse_uid(uid) - if mail: - if mail.endswith('@debian.org'): - login = mail[0:-len('@debian.org')] - _add_to_result('login:email:%s' % mail, login) - _add_to_result('login:fpr:%s' % fpr, login) - _add_to_result('fpr:login:%s' % login, fpr) - _add_to_result('fpr:email:%s' % mail, fpr) - _add_to_result('email:fpr:%s' % fpr, mail) - if uid: - _add_to_result('name:fpr:%s' % fpr, uid) - if mail: - _add_to_result('name:email:%s' % mail, uid) + fpr = process_gpg_list_keys_line(line, fpr) retcode = proc.wait() if retcode != 0: logging.error("subprocess ended with return code %d", retcode) @@ -158,4 +174,9 @@ def process_keyrings(): if __name__ == '__main__': logging.basicConfig(stream=sys.stderr, level=logging.WARNING) + CONFIG.readfp(pkg_resources.resource_stream( + __name__, 'ddportfolio.ini')) + gpghome = os.path.expanduser(CONFIG.get('DEFAULT', 'gnupghome')) + if not os.path.isdir(gpghome): + os.makedirs(gpghome, 0700) process_keyrings()