Merge lp:~smoser/software-properties/trunk.lp1667725-https-signing-key into lp:software-properties

Proposed by Scott Moser
Status: Merged
Merged at revision: 1050
Proposed branch: lp:~smoser/software-properties/trunk.lp1667725-https-signing-key
Merge into: lp:software-properties
Diff against target: 138 lines (+41/-8)
3 files modified
debian/changelog (+7/-0)
softwareproperties/ppa.py (+29/-8)
tests/test_lp.py (+5/-0)
To merge this branch: bzr merge lp:~smoser/software-properties/trunk.lp1667725-https-signing-key
Reviewer Review Type Date Requested Status
Colin Watson Approve
Review via email: mp+351824@code.launchpad.net

Commit message

Get PPA key signing data from launchpad https rather than keyserver.

Previously adding of a PPA would read the signing key fingerprint from
launchpad and then read the signing key data from keyserver.ubuntu.com
over https.

This changes that to use the newly added getSigningKeyData operation
from launchpad. And uses the launchpad 'devel' api version.
The primary benefit of this is a reduction in the number
of external services that 'add-apt-repository' relies upon.
That means less external services that may be down, and also less
holes poked in egress networking to allow add-apt-repository to work.

There are also 3 other changes/improvements that we found along the way:
 a.) make python2 (pycurl) path follow http redirects.
 b.) use 'mangle_ppa_shortcut' in other paths.
 c.) mangle_ppa_shortcut can now support input with or without 'ppa:' as
     a prefix.

To post a comment you must log in.
1051. By Scott Moser

remove staging, launchpad marked released.

1052. By Scott Moser

Get PPA key signing data from launchpad https rather than keyserver.
(LP: #1667725)

Revision history for this message
Colin Watson (cjwatson) :
review: Approve
Revision history for this message
Scott Moser (smoser) wrote :

Addressed your other comments.

Thank you.

1053. By Scott Moser

debian/changelog: fix version

1054. By Scott Moser

address cjwatson's other comments.

1055. By Scott Moser

improve docstring, fix a bug in use of 'path', treat response as json.

cjwatson pointed out the response is json so we have to treat it as such.
just use the 'accept_json' and we're good.

1056. By Scott Moser

fix bug in calling of _recv_key (thanks cjwatson)

1057. By Scott Moser

use mangle_ppa_shortcut consistently.

this fixes a bug/issue in the python2 path with
  python -m softwareproperties.ppa ppa:~smoser/ppa

The issue was that launchpad would return a 301 and pycurl would
not follow the redirect.
  https://launchpad.net/api/devel/~smoser/+archive/ppa
would get a 301 to
  https://launchpad.net/api/devel/~smoser/+archive/ubuntu/ppa

1058. By Scott Moser

In python2 (pycurl) path follow redirects.

the pycurl path was not following redirects which made it inconsistent
behavior with python3 path. now they both act the same in this regard.

1059. By Scott Moser

Fix tests, support mangle_ppa_shortcut without a leading 'ppa:'

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/changelog'
--- debian/changelog 2018-07-26 08:56:14 +0000
+++ debian/changelog 2018-08-03 14:40:33 +0000
@@ -1,3 +1,10 @@
1software-properties (0.96.26) UNRELEASED; urgency=medium
2
3 * Get PPA key signing data from launchpad https rather than keyserver.
4 (LP: #1667725)
5
6 -- Scott Moser <smoser@ubuntu.com> Mon, 30 Jul 2018 21:44:24 -0400
7
1software-properties (0.96.25) cosmic; urgency=medium8software-properties (0.96.25) cosmic; urgency=medium
29
3 * Port the KDE frontend to a pure Qt frontend that Lubuntu can use as well.10 * Port the KDE frontend to a pure Qt frontend that Lubuntu can use as well.
411
=== modified file 'softwareproperties/ppa.py'
--- softwareproperties/ppa.py 2018-07-16 17:34:17 +0000
+++ softwareproperties/ppa.py 2018-08-03 14:40:33 +0000
@@ -49,7 +49,7 @@
4949
50SKS_KEYSERVER = 'https://keyserver.ubuntu.com/pks/lookup?op=get&options=mr&exact=on&search=0x%s'50SKS_KEYSERVER = 'https://keyserver.ubuntu.com/pks/lookup?op=get&options=mr&exact=on&search=0x%s'
51# maintained until 201551# maintained until 2015
52LAUNCHPAD_PPA_API = 'https://launchpad.net/api/1.0/%s/+archive/%s'52LAUNCHPAD_PPA_API = 'https://launchpad.net/api/devel/%s/+archive/%s'
53LAUNCHPAD_USER_API = 'https://launchpad.net/api/1.0/%s'53LAUNCHPAD_USER_API = 'https://launchpad.net/api/1.0/%s'
54LAUNCHPAD_USER_PPAS_API = 'https://launchpad.net/api/1.0/%s/ppas'54LAUNCHPAD_USER_PPAS_API = 'https://launchpad.net/api/1.0/%s/ppas'
55LAUNCHPAD_DISTRIBUTION_API = 'https://launchpad.net/api/1.0/%s'55LAUNCHPAD_DISTRIBUTION_API = 'https://launchpad.net/api/1.0/%s'
@@ -170,6 +170,7 @@
170 curl = pycurl.Curl()170 curl = pycurl.Curl()
171 curl.setopt(pycurl.SSL_VERIFYPEER, 1)171 curl.setopt(pycurl.SSL_VERIFYPEER, 1)
172 curl.setopt(pycurl.SSL_VERIFYHOST, 2)172 curl.setopt(pycurl.SSL_VERIFYHOST, 2)
173 curl.setopt(pycurl.FOLLOWLOCATION, 1)
173 curl.setopt(pycurl.WRITEFUNCTION, callback.body_callback)174 curl.setopt(pycurl.WRITEFUNCTION, callback.body_callback)
174 if LAUNCHPAD_PPA_CERT:175 if LAUNCHPAD_PPA_CERT:
175 curl.setopt(pycurl.CAINFO, LAUNCHPAD_PPA_CERT)176 curl.setopt(pycurl.CAINFO, LAUNCHPAD_PPA_CERT)
@@ -200,7 +201,10 @@
200201
201202
202def mangle_ppa_shortcut(shortcut):203def mangle_ppa_shortcut(shortcut):
203 ppa_shortcut = shortcut.split(":")[1]204 if ":" in shortcut:
205 ppa_shortcut = shortcut.split(":")[1]
206 else:
207 ppa_shortcut = shortcut
204 if ppa_shortcut.startswith("/"):208 if ppa_shortcut.startswith("/"):
205 ppa_shortcut = ppa_shortcut.lstrip("/")209 ppa_shortcut = ppa_shortcut.lstrip("/")
206 user = ppa_shortcut.split("/")[0]210 user = ppa_shortcut.split("/")[0]
@@ -237,7 +241,8 @@
237 cmd = "gpg -q --homedir %s --no-default-keyring --no-options --import --import-options %s" % (self._homedir, args)241 cmd = "gpg -q --homedir %s --no-default-keyring --no-options --import --import-options %s" % (self._homedir, args)
238 return subprocess.Popen(cmd.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE)242 return subprocess.Popen(cmd.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE)
239 243
240 def _recv_key(self, signing_key_fingerprint):244 def _recv_key(self, ppa_info):
245 signing_key_fingerprint = ppa_info["signing_key_fingerprint"]
241 try:246 try:
242 # double check that the signing key is a v4 fingerprint (160bit)247 # double check that the signing key is a v4 fingerprint (160bit)
243 if not verify_keyid_is_v4(signing_key_fingerprint):248 if not verify_keyid_is_v4(signing_key_fingerprint):
@@ -248,8 +253,7 @@
248 print("Error: signing key fingerprint does not exist")253 print("Error: signing key fingerprint does not exist")
249 return False254 return False
250255
251 return get_info_from_https(SKS_KEYSERVER % signing_key_fingerprint,256 return get_ppa_signing_key_data(ppa_info)
252 accept_json=False, retry_delays=(1, 2))
253257
254 def _minimize_key(self, key):258 def _minimize_key(self, key):
255 p = self.gpg_cmd("import-minimal,import-export")259 p = self.gpg_cmd("import-minimal,import-export")
@@ -292,7 +296,7 @@
292 ppa_path = self.ppa_path296 ppa_path = self.ppa_path
293297
294 try:298 try:
295 ppa_info = get_ppa_info(ppa_path)299 ppa_info = get_ppa_info(mangle_ppa_shortcut(ppa_path))
296 except PPAException as e:300 except PPAException as e:
297 print(e.value)301 print(e.value)
298 return False302 return False
@@ -303,7 +307,7 @@
303 return False307 return False
304 308
305 # download the armored_key309 # download the armored_key
306 armored_key = self._recv_key(signing_key_fingerprint)310 armored_key = self._recv_key(ppa_info)
307 if not armored_key:311 if not armored_key:
308 return False312 return False
309313
@@ -394,6 +398,23 @@
394 (LAUNCHPAD_PPA_API % (user, ppa)))398 (LAUNCHPAD_PPA_API % (user, ppa)))
395399
396400
401def get_ppa_signing_key_data(info=None):
402 """Return signing key data in armored ascii format for the provided ppa.
403
404 If 'info' is a dictionary, it is assumed to be the result
405 of 'get_ppa_info(ppa)'. If it is a string, it is assumed to
406 be a ppa_path.
407
408 Return value is a text string."""
409 if isinstance(info, dict):
410 link = info["self_link"]
411 else:
412 link = get_ppa_info(mangle_ppa_shortcut(info))["self_link"]
413
414 return get_info_from_https(link + "?ws.op=getSigningKeyData",
415 accept_json=True, retry_delays=(1, 2, 3))
416
417
397class PPAShortcutHandler(object):418class PPAShortcutHandler(object):
398 def __init__(self, shortcut):419 def __init__(self, shortcut):
399 super(PPAShortcutHandler, self).__init__()420 super(PPAShortcutHandler, self).__init__()
@@ -450,5 +471,5 @@
450471
451if __name__ == "__main__":472if __name__ == "__main__":
452 import sys473 import sys
453 ppa = sys.argv[1].split(":")[1]474 ppa = mangle_ppa_shortcut(sys.argv[1])
454 print(get_ppa_info(ppa))475 print(get_ppa_info(ppa))
455476
=== modified file 'tests/test_lp.py'
--- tests/test_lp.py 2018-03-30 14:14:39 +0000
+++ tests/test_lp.py 2018-08-03 14:40:33 +0000
@@ -25,6 +25,7 @@
25 'distribution_link': 'https://launchpad.net/api/1.0/ubuntu',25 'distribution_link': 'https://launchpad.net/api/1.0/ubuntu',
26 'owner_link': 'https://launchpad.net/api/1.0/~mvo',26 'owner_link': 'https://launchpad.net/api/1.0/~mvo',
27 'reference': '~mvo/ubuntu/ppa',27 'reference': '~mvo/ubuntu/ppa',
28 'self_link': 'https://launchpad.net/api/devel/~mvo/+archive/ubuntu/ppa',
28 }29 }
2930
30MOCK_KEY="""31MOCK_KEY="""
@@ -96,6 +97,10 @@
96 self.assertEqual("~gottcode/ubuntu/gcppa",97 self.assertEqual("~gottcode/ubuntu/gcppa",
97 mangle_ppa_shortcut("ppa:/gottcode/gcppa"))98 mangle_ppa_shortcut("ppa:/gottcode/gcppa"))
9899
100 def test_mangle_ppa_supports_no_ppa_colon_prefix(self):
101 """mangle_ppa should also support input without 'ppa:'."""
102 self.assertEqual("~mvo/ubuntu/ppa", mangle_ppa_shortcut("~mvo/ppa"))
103
99104
100class AddPPASigningKeyTestCase(unittest.TestCase):105class AddPPASigningKeyTestCase(unittest.TestCase):
101106

Subscribers

People subscribed via source and target branches

to status/vote changes: