~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/archiveuploader/dscfile.py

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-05-24 00:34:34 UTC
  • mfrom: (13101.1.5 90628-spec-sub)
  • Revision ID: launchpad@pqm.canonical.com-20110524003434-n05kxyulvedoksmx
[r=sinzui][bug=90628] 'Sort blueprints subscribers list by display
        name.

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
    UploadWarning,
43
43
    )
44
44
from lp.archiveuploader.tagfiles import (
45
 
    parse_tagfile_content,
 
45
    parse_tagfile,
46
46
    TagFileParseError,
47
47
    )
48
48
from lp.archiveuploader.utils import (
111
111
class SignableTagFile:
112
112
    """Base class for signed file verification."""
113
113
 
 
114
    fingerprint = None
114
115
    signingkey = None
115
 
    parsed_content = None
116
 
 
117
 
    @property
118
 
    def signer(self):
119
 
        if self.signingkey is not None:
120
 
            return self.signingkey.owner
121
 
 
122
 
    def parse(self, verify_signature=True):
123
 
        """Parse the tag file, optionally verifying the signature.
124
 
 
125
 
        If verify_signature is True, signingkey will be set to the signing
126
 
        `IGPGKey`, and only the verified content will be parsed. Otherwise,
127
 
        any signature will be stripped and the contained content parsed.
128
 
 
129
 
        Will raise an `UploadError` if the tag file was unparsable,
130
 
        or if signature verification was requested but failed.
131
 
        """
132
 
        try:
133
 
            with open(self.filepath, 'rb') as f:
134
 
                self.raw_content = f.read()
135
 
        except IOError, error:
136
 
            raise UploadError(
137
 
                "Unable to read %s: %s" % (self.filename, error))
138
 
 
139
 
        if verify_signature:
140
 
            self.signingkey, self.parsed_content = self.verifySignature(
141
 
                self.raw_content, self.filepath)
142
 
        else:
143
 
            self.logger.debug("%s can be unsigned." % self.filename)
144
 
            self.parsed_content = self.raw_content
145
 
        try:
146
 
            self._dict = parse_tagfile_content(
147
 
                self.parsed_content, filename=self.filepath)
148
 
        except TagFileParseError, error:
149
 
            raise UploadError(
150
 
                "Unable to parse %s: %s" % (self.filename, error))
151
 
 
152
 
    def verifySignature(self, content, filename):
153
 
        """Verify the signature on the file content.
 
116
    signer = None
 
117
 
 
118
    def processSignature(self):
 
119
        """Verify the signature on the filename.
 
120
 
 
121
        Stores the fingerprint, the IGPGKey used to sign, the owner of
 
122
        the key and a dictionary containing
154
123
 
155
124
        Raise UploadError if the signing key cannot be found in launchpad
156
125
        or if the GPG verification failed for any other reason.
157
126
 
158
 
        Returns a tuple of the key (`IGPGKey` object) and the verified
159
 
        cleartext data.
 
127
        Returns the key owner (person object), the key (gpgkey object) and
 
128
        the pyme signature as a three-tuple
160
129
        """
161
 
        self.logger.debug(
162
 
            "Verifying signature on %s" % os.path.basename(filename))
 
130
        self.logger.debug("Verifying signature on %s" % self.filename)
 
131
        assert os.path.exists(self.filepath), (
 
132
            "File not found: %s" % self.filepath)
163
133
 
164
134
        try:
165
135
            sig = getUtility(IGPGHandler).getVerifiedSignatureResilient(
166
 
                content)
 
136
                file(self.filepath, "rb").read())
167
137
        except GPGVerificationError, error:
168
138
            raise UploadError(
169
139
                "GPG verification of %s failed: %s" % (
170
 
                filename, str(error)))
 
140
                self.filename, str(error)))
171
141
 
172
142
        key = getUtility(IGPGKeySet).getByFingerprint(sig.fingerprint)
173
143
        if key is None:
176
146
 
177
147
        if key.active == False:
178
148
            raise UploadError("File %s is signed with a deactivated key %s"
179
 
                              % (filename, key.keyid))
 
149
                              % (self.filename, key.keyid))
180
150
 
181
 
        return (key, sig.plain_data)
 
151
        self.fingerprint = sig.fingerprint
 
152
        self.signingkey = key
 
153
        self.signer = key.owner
 
154
        self.signer_address = self.parseAddress("%s <%s>" % (
 
155
            self.signer.displayname, self.signer.preferredemail.email))
182
156
 
183
157
    def parseAddress(self, addr, fieldname="Maintainer"):
184
158
        """Parse an address, using the policy to decide if we should add a
243
217
        "Build-Conflicts-Indep",
244
218
        "Format",
245
219
        "Standards-Version",
 
220
        "filecontents",
246
221
        "homepage",
247
222
        ]))
248
223
 
267
242
        SourceUploadFile.__init__(
268
243
            self, filepath, digest, size, component_and_section, priority,
269
244
            package, version, changes, policy, logger)
270
 
        self.parse(verify_signature=not policy.unsigned_dsc_ok)
 
245
        try:
 
246
            self._dict = parse_tagfile(
 
247
                self.filepath, dsc_whitespace_rules=1,
 
248
                allow_unsigned=self.policy.unsigned_dsc_ok)
 
249
        except (IOError, TagFileParseError), error:
 
250
            raise UploadError(
 
251
                "Unable to parse the dsc %s: %s" % (self.filename, error))
271
252
 
272
253
        self.logger.debug("Performing DSC verification.")
273
254
        for mandatory_field in self.mandatory_fields:
288
269
            raise EarlyReturnUploadError(
289
270
                "Unsupported source format: %s" % self._dict['Format'])
290
271
 
 
272
        if self.policy.unsigned_dsc_ok:
 
273
            self.logger.debug("DSC file can be unsigned.")
 
274
        else:
 
275
            self.processSignature()
291
276
 
292
277
    #
293
278
    # Useful properties.
321
306
        """Return the DSC claimed binary line."""
322
307
        return self._dict['Binary']
323
308
 
 
309
 
324
310
    #
325
311
    # DSC file checks.
326
312
    #
629
615
 
630
616
        # We have no way of knowing what encoding the original copyright
631
617
        # file is in, unfortunately, and there is no standard, so guess.
632
 
        encoded_raw_content = guess_encoding(self.raw_content)
633
618
        encoded = Deb822Dict()
634
619
        for key, value in pending.items():
635
620
            if value is not None:
667
652
            creator=self.changes.changed_by['person'],
668
653
            urgency=self.changes.converted_urgency,
669
654
            homepage=encoded.get('homepage'),
670
 
            dsc=encoded_raw_content,
 
655
            dsc=encoded['filecontents'],
671
656
            dscsigningkey=self.signingkey,
672
657
            dsc_maintainer_rfc822=encoded['Maintainer'],
673
658
            dsc_format=encoded['Format'],