tags 700515 + patch thanks Hi,
motivated by Paus Wise, I scratched my own itch: here's a patch that makes PTS parse GPG signatures - therefore being able to display a package's sponsor. Please review. A few notes and remarks: I'm using GPGME, or rather its python binding, so python-gpgme becomes a dependency. Currently, if there's anything wrong with the signature or the public key missing, there's no warning or anything. It will simply fall back to display the sender of the email, as before. Not sure if that's much of an issue. A public key may have multiple uids and the signature is only specific to the key, not any specific uid. But I only want to display a single uid. The way I implemented this now is: we take the first uid. Only if a later uid has an email ending in "@debian.org", we prefer that one. That's certainly not ideal. We could possibly do an LDAP lookup via the key's fingerprint on db.debian.org instead... In the news.xml file, I replaced the "from" attribute of the news item with more fine grained "from_address" and "from_realname". However, I think existing entries will be kept, so the XSL-templates need to be able to parse both. At least that's how I've implemented it. If a complete rewrite of all news.xml files is feasible, the XSLTs could be simplified quite a bit. I also added links to http://qa.debian.org/developer.php?login=$EMAIL for both, the sender and signer of the mail in the HTML display of the NEWS. Not in RSS. Comments? Regards Markus Wanner
Index: www/xsl/news2rss.xsl =================================================================== --- www/xsl/news2rss.xsl (revision 2950) +++ www/xsl/news2rss.xsl (working copy) @@ -60,9 +60,32 @@ <item> <title> <xsl:value-of select="." /> - <xsl:text> (</xsl:text> - <xsl:value-of select="@from" /> - <xsl:text>)</xsl:text> + + <xsl:if test="@from or @from_address"> + <xsl:text> (</xsl:text> + <xsl:choose> + <!-- old style --> + <xsl:when test="@from"><xsl:value-of select="@from"/></xsl:when> + <!-- newer variants --> + <xsl:when test="@from_address and @sign_address and @from_address != @sign_address"> + <xsl:choose> + <xsl:when test="@from_realname"><xsl:value-of select="@from_realname"/> + <xsl:otherwise><xsl:value-of select="@from_address"/> + <xsl:choose> + <xsl:text> - </xsl:text> + <xsl:choose> + <xsl:when test="@sign_realname"><xsl:value-of select="@sign_realname"/> + <xsl:otherwise><xsl:value-of select="@sign_address"/> + </xsl:choose> + </xsl:when> + <xsl:when test="@from_realname"><xsl:value-of select="@from_realname"/></xsl:when> + <xsl:otherwise><xsl:value-of select="@from_address"/></xsl:otherwise> + </xsl:choose> + <xsl:text>)</xsl:text> + </xsl:if> + + + <xsl:value-of select="@from_realname" /> </title> <xsl:variable name="id"> <xsl:value-of select="$ptsurl" /> @@ -81,9 +104,30 @@ <xsl:value-of select="@date" /> <xsl:text>] </xsl:text> <xsl:value-of select="." /> - <xsl:text> (</xsl:text> - <xsl:value-of select="@from" /> - <xsl:text>)</a></xsl:text> + + <xsl:if test="@from or @from_address"> + <xsl:text> (</xsl:text> + <xsl:choose> + <!-- old style --> + <xsl:when test="@from"><xsl:value-of select="@from"/></xsl:when> + <!-- newer variants --> + <xsl:when test="@from_address and @sign_address and @from_address != @sign_address"> + <xsl:choose> + <xsl:when test="@from_realname"><xsl:value-of select="@from_realname"/> + <xsl:otherwise><xsl:value-of select="@from_address"/> + <xsl:choose> + <xsl:text> - </xsl:text> + <xsl:choose> + <xsl:when test="@sign_realname"><xsl:value-of select="@sign_realname"/> + <xsl:otherwise><xsl:value-of select="@sign_address"/> + </xsl:choose> + </xsl:when> + <xsl:when test="@from_realname"><xsl:value-of select="@from_realname"/></xsl:when> + <xsl:otherwise><xsl:value-of select="@from_address"/></xsl:otherwise> + </xsl:choose> + <xsl:text>)</xsl:text> + </xsl:if> + <xsl:text></a></xsl:text> </description> </item> </xsl:template> Index: www/xsl/pts.xsl =================================================================== --- www/xsl/pts.xsl (revision 2950) +++ www/xsl/pts.xsl (working copy) @@ -75,6 +75,30 @@ <xsl:variable name="security-mirror">http://security.debian.org/</xsl:variable> <xsl:variable name="backports-mirror">http://http.debian.net/debian-backports</xsl:variable> +<xsl:template name="name_email_link"> + <xsl:param name="realname"/> + <xsl:param name="address"/> + <xsl:param name="title"/> + + <xsl:element name="a"> + <xsl:attribute name="href"> + <xsl:text>http://qa.debian.org/developer.php?login=</xsl:text> + <xsl:call-template name="escape-name"> + <xsl:with-param name="text"><xsl:value-of select="$address"/></xsl:with-param> + </xsl:call-template> + </xsl:attribute> + <span class="name"> + <xsl:if test="string-length($title) > 0"> + <xsl:attribute name="title"><xsl:value-of select="$title"/></xsl:attribute> + </xsl:if> + <xsl:choose> + <xsl:when test="string-length($realname) > 0"><xsl:value-of select="$realname"/></xsl:when> + <xsl:otherwise><xsl:value-of select="$address"/></xsl:otherwise> + </xsl:choose> + </span> + </xsl:element> +</xsl:template> + <xsl:template name="outputitem"> <xsl:choose> <xsl:when test="@url"> @@ -83,10 +107,40 @@ <xsl:value-of select="@date"/> <xsl:text>] </xsl:text> </xsl:if><a href="{@url}"> - <xsl:value-of select="text()"/></a><xsl:if test="@from"> + <xsl:value-of select="text()"/></a> + + <xsl:if test="@from or @from_address"> <xsl:text> (</xsl:text> - <xsl:value-of select="@from"/> - <xsl:text>)</xsl:text></xsl:if></li> + + <xsl:choose> + <!-- old style news entry, no link or signature info --> + <xsl:when test="@from"><xsl:value-of select="@from"/></xsl:when> + + <xsl:when test="@from_address and @sign_address and @from_address != @sign_address"> + <xsl:text></xsl:text><xsl:call-template name="name_email_link"> + <xsl:with-param name="title">email sender</xsl:with-param> + <xsl:with-param name="realname"><xsl:value-of select="@from_realname"/></xsl:with-param> + <xsl:with-param name="address"><xsl:value-of select="@from_address"/></xsl:with-param> + </xsl:call-template> + <xsl:text> - </xsl:text> + <xsl:text>signed by: </xsl:text><xsl:call-template name="name_email_link"> + <xsl:with-param name="title">signer</xsl:with-param> + <xsl:with-param name="realname"><xsl:value-of select="@sign_realname"/></xsl:with-param> + <xsl:with-param name="address"><xsl:value-of select="@sign_address"/></xsl:with-param> + </xsl:call-template> + </xsl:when> + + <xsl:otherwise> + <xsl:call-template name="name_email_link"> + <xsl:with-param name="realname"><xsl:value-of select="@from_realname"/></xsl:with-param> + <xsl:with-param name="address"><xsl:value-of select="@from_address"/></xsl:with-param> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + + <xsl:text>)</xsl:text> + </xsl:if> + </li> </xsl:when> <xsl:when test="@type='raw'"> <li> @@ -208,13 +262,6 @@ </xsl:if> </xsl:template> -<xsl:template name="maintainer-email"> - <xsl:param name="email" /> - <a class="email" href="mailto:{$email}"> - <img alt="[email]" src="../common/email.png" title="email" /> - </a> -</xsl:template> - <xsl:template name="general-information"> <div class="block info"> <a name="general" /> @@ -245,17 +292,11 @@ <dt title="Maintainer and Uploaders">maint</dt> <dd class="maintainer"> - <xsl:element name="a"> - <xsl:attribute name="href"> - <xsl:text>http://qa.debian.org/developer.php?login=</xsl:text> - <xsl:call-template name="escape-name"> - <xsl:with-param name="text"><xsl:value-of select="maintainer/email"/></xsl:with-param> - </xsl:call-template> - </xsl:attribute> - <span class="name" title="maintainer"> - <xsl:value-of select="maintainer/name"/> - </span> - </xsl:element> + <xsl:call-template name="name_email_link"> + <xsl:with-param name="title">maintainer</xsl:with-param> + <xsl:with-param name="realname"><xsl:value-of select="maintainer/name"/></xsl:with-param> + <xsl:with-param name="address"><xsl:value-of select="maintainer/email"/></xsl:with-param> + </xsl:call-template> <xsl:if test="$hasother and $other/dms/item/@email=maintainer/email"> (<small>dm</small>) </xsl:if> @@ -264,19 +305,11 @@ <xsl:text>, </xsl:text> <span class="uploader"> <small> - <xsl:element name="a"> - <xsl:attribute name="href"> - <xsl:text>http://qa.debian.org/developer.php?login=</xsl:text> - <xsl:call-template name="escape-name"> - <xsl:with-param name="text"> - <xsl:value-of select="email"/> - </xsl:with-param> - </xsl:call-template> - </xsl:attribute> - <span class="name" title="uploader"> - <xsl:value-of select="name"/> - </span> - </xsl:element> + <xsl:call-template name="name_email_link"> + <xsl:with-param name="title">uploader</xsl:with-param> + <xsl:with-param name="realname"><xsl:value-of select="name"/></xsl:with-param> + <xsl:with-param name="address"><xsl:value-of select="email"/></xsl:with-param> + </xsl:call-template> <xsl:text> (u</xsl:text> <xsl:if test="$hasother and $other/dms/item/@email=email"> <xsl:text>, dm</xsl:text> Index: www/bin/update_news.py =================================================================== --- www/bin/update_news.py (revision 2950) +++ www/bin/update_news.py (working copy) @@ -79,8 +79,11 @@ sub_elt.setAttribute("date", info["date"]) sub_elt.setAttribute("rfc822date", timestamp_to_rfc822date(info["timestamp"])) - if info.has_key("from_name"): - sub_elt.setAttribute("from", info["from_name"]) + # Copy these attributes as-is + for attname in ("from_realname", "from_address", + "sign_realname", "sign_address"): + if info.has_key(attname): + sub_elt.setAttribute(attname, info[attname]) elt.appendChild(sub_elt) Index: www/bin/common.py =================================================================== --- www/bin/common.py (revision 2950) +++ www/bin/common.py (working copy) @@ -7,8 +7,12 @@ # This file is distributed under the terms of the General Public License # version 2 or (at your option) any later version. -import hashlib, os, os.path, re, rfc822, time, email, sys +import hashlib, os, os.path, re, rfc822, time, email, sys, gpgme from email import Utils, Header +try: + from io import BytesIO +except ImportError: + from StringIO import StringIO as BytesIO from config import root @@ -93,12 +97,48 @@ frm = msg.get("From") if msg.has_key("X-PTS-From"): frm = msg.get("X-PTS-From") (realname, address) = rfc822.parseaddr(frm) + if realname: - frm = realname - else: - frm = address - frm = decode_header(frm) - info["from_name"] = frm + info["from_realname"] = decode_header(realname) + info["from_address"] = decode_header(address) + + # Check if the mail containes signed data. If so, parse the signature + # invoking gnupg. + isSigned = False + for i in range(3): + if lines[i].startswith("-----BEGIN PGP"): + isSigned = True + break + + if isSigned: + ctx = gpgme.Context() + plain = BytesIO() + result = ctx.verify(BytesIO(body), None, plain) + for sig in result: + if sig.status == gpgme.ERR_NO_ERROR and sig.summary & gpgme.SIGSUM_GOOD: + # Some signature, for PTS, we don't care if it's good or + # not, just *who* claims to have signed. + key = ctx.get_key(sig.fpr) + + best = None + for uid in key.uids: + print "signature uid: %s <%s>" % (uid.name, uid.email) + if not best: + best = (uid.name, uid.email) + # We continue the loop, because we prefer a + # @debian.org address. + + if uid.email.endswith("@debian.org"): + best = (uid.name, uid.email) + break + + if best: + info['sign_realname'] = best[0] + info['sign_address'] = best[1] + + # Simply use the first valid signature found + break + return info def hash_name(pkg):
signature.asc
Description: OpenPGP digital signature