← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~lgp171188/launchpad:allow-ssh-keys-without-comment into launchpad:master

 

Guruprasad has proposed merging ~lgp171188/launchpad:allow-ssh-keys-without-comment into launchpad:master.

Commit message:
Allow SSH keys without a comment to be uploaded

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~lgp171188/launchpad/+git/launchpad/+merge/423518
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~lgp171188/launchpad:allow-ssh-keys-without-comment into launchpad:master.
diff --git a/lib/lp/registry/model/person.py b/lib/lp/registry/model/person.py
index 6a9eea7..5f061aa 100644
--- a/lib/lp/registry/model/person.py
+++ b/lib/lp/registry/model/person.py
@@ -4374,9 +4374,18 @@ class SSHKey(SQLBase):
         if send_notification:
             # For security reasons we want to notify the preferred email
             # address that this sshkey has been removed.
+            if self.comment:
+                change_description = (
+                    "The SSH key %s was removed from your account."
+                ) % (self.comment)
+            else:
+                change_description = (
+                    "An SSH key of type '%s' was removed from your "
+                    "account." % self.getFullKeyText().split(" ", 2)[0]
+                )
             self.person.security_field_changed(
-                "SSH Key removed from your Launchpad account.",
-                "The SSH Key %s was removed from your account." % self.comment)
+                "SSH key removed from your Launchpad account.",
+                change_description)
         super().destroySelf()
 
     def getFullKeyText(self):
@@ -4397,7 +4406,10 @@ class SSHKey(SQLBase):
                 raise ValueError(
                     "SSH key of type %s has invalid data '%s'" %
                     (self.keytype, self.keytext))
-        return "%s %s %s" % (ssh_keytype, self.keytext, self.comment)
+        key_text = "%s %s" % (ssh_keytype, self.keytext)
+        if self.comment:
+            key_text = "%s %s" % (key_text, self.comment)
+        return key_text
 
 
 @implementer(ISSHKeySet)
@@ -4418,9 +4430,18 @@ class SSHKeySet:
                 raise SSHKeyAdditionError(type_mismatch=(kind, keydatatype))
 
         if send_notification:
+            if comment:
+                change_description = (
+                    "The SSH key '%s' has been added to your account."
+                ) % comment
+            else:
+                change_description = (
+                    "An SSH key of type '%s' has been added "
+                    "to your account." % keydatatype
+                )
             person.security_field_changed(
                 "New SSH key added to your account.",
-                "The SSH key '%s' has been added to your account." % comment)
+                change_description)
 
         if not dry_run:
             return SSHKey(person=person, keytype=keytype, keytext=keytext,
@@ -4446,12 +4467,17 @@ class SSHKeySet:
 
     def _extract_ssh_key_components(self, sshkey):
         try:
-            kind, keytext, comment = sshkey.split(' ', 2)
-        except (ValueError, AttributeError):
+            ssh_key_components = sshkey.split(' ', 2)
+        except AttributeError:
             raise SSHKeyAdditionError(key=sshkey)
 
-        if not (kind and keytext and comment):
+        if len(ssh_key_components) < 2:
             raise SSHKeyAdditionError(key=sshkey)
+        elif len(ssh_key_components) == 2:
+            kind, keytext = ssh_key_components
+            comment = ''
+        else:
+            kind, keytext, comment = ssh_key_components
 
         keytype = SSH_TEXT_TO_KEY_TYPE.get(kind)
         if keytype is None:
diff --git a/lib/lp/registry/stories/person/xx-add-sshkey.txt b/lib/lp/registry/stories/person/xx-add-sshkey.txt
index a9ab70c..dde5b7f 100644
--- a/lib/lp/registry/stories/person/xx-add-sshkey.txt
+++ b/lib/lp/registry/stories/person/xx-add-sshkey.txt
@@ -173,6 +173,16 @@ format.
     ...     print(tag.decode_contents())
     SSH public key added.
 
+    >>> sshkey_without_comment = (
+    ...     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGoDIdJaOkdr0wn0egyWEOtGxhe"
+    ...     "3x0Iz9um6CEOFaqIw")
+    >>> browser.getControl(name='sshkey').value = sshkey_without_comment
+    >>> browser.getControl('Import Public Key').click()
+    >>> soup = find_main_content(browser.contents)
+    >>> for tag in soup('p', 'informational message'):
+    ...     print(tag.decode_contents())
+    SSH public key added.
+
 Launchpad administrators are not allowed to poke at other user's ssh keys.
 
     >>> login(ANONYMOUS)
@@ -198,6 +208,7 @@ to edit his keys is on the page.
     salgado@canario
     salgado@canario
     salgado@canario
+    ED25519 key
     >>> browser.getLink('Update SSH keys').click()
     >>> print(browser.title)
     Change your SSH keys...
@@ -245,7 +256,7 @@ that the key has been removed.
     >>> to_addr
     ['guilherme.salgado@xxxxxxxxxxxxx']
     >>> payload = email.message_from_bytes(msg).get_payload()
-    >>> assert payload.startswith('The SSH Key')
+    >>> assert payload.startswith('The SSH key')
 
 
 Keys containing non-ASCII comments
diff --git a/lib/lp/registry/templates/person-portlet-contact-details.pt b/lib/lp/registry/templates/person-portlet-contact-details.pt
index a1e4de6..8650e7b 100644
--- a/lib/lp/registry/templates/person-portlet-contact-details.pt
+++ b/lib/lp/registry/templates/person-portlet-contact-details.pt
@@ -157,7 +157,10 @@
       </dt>
       <dd tal:define="sshkeys context/sshkeys">
         <tal:keys repeat="sshkey sshkeys">
-          <a href="+sshkeys" tal:content="sshkey/comment">foo@bar</a>
+          <a href="+sshkeys" tal:content="sshkey/comment" tal:condition="sshkey/comment">foo@bar</a>
+          <a href="+sshkeys" tal:condition="not: sshkey/comment">
+            <span tal:condition="not: sshkey/comment" tal:content="sshkey/keytype/title">RSA</span> key
+          </a>
           <br />
         </tal:keys>
         <div tal:condition="not: context/sshkeys">
diff --git a/lib/lp/registry/tests/test_ssh.py b/lib/lp/registry/tests/test_ssh.py
index c85baad..07a4e30 100644
--- a/lib/lp/registry/tests/test_ssh.py
+++ b/lib/lp/registry/tests/test_ssh.py
@@ -68,6 +68,13 @@ class TestSSHKey(TestCaseWithFactory):
         expected = "ssh-ed25519 %s %s" % (key.keytext, key.comment)
         self.assertEqual(expected, key.getFullKeyText())
 
+    def test_getFullKeyText_for_key_without_comment(self):
+        person = self.factory.makePerson()
+        with person_logged_in(person):
+            key = self.factory.makeSSHKey(person, "ssh-rsa", comment="")
+        expected = "ssh-rsa %s" % (key.keytext)
+        self.assertEqual(expected, key.getFullKeyText())
+
     def test_getFullKeyText_for_corrupt_key(self):
         # If the key text is corrupt, the type from the database is used
         # instead of the one decoded from the text.
@@ -88,7 +95,7 @@ class TestSSHKey(TestCaseWithFactory):
             [email] = pop_notifications()
             self.assertEqual(
                 email['Subject'],
-                "SSH Key removed from your Launchpad account.")
+                "SSH key removed from your Launchpad account.")
             self.assertThat(
                 email.get_payload(),
                 StartsWith(
@@ -96,6 +103,27 @@ class TestSSHKey(TestCaseWithFactory):
                     % key.comment)
             )
 
+    def test_destroySelf_notification_empty_comment(self):
+        person = self.factory.makePerson()
+        with person_logged_in(person):
+            key = self.factory.makeSSHKey(
+                person, send_notification=False, comment=""
+            )
+            key.destroySelf()
+            [email] = pop_notifications()
+            self.assertEqual(
+                "SSH key removed from your Launchpad account.",
+                email['Subject']
+            )
+            keytype = key.getFullKeyText().split(" ", 1)[0]
+            self.assertThat(
+                email.get_payload(),
+                StartsWith(
+                    "An SSH key of type '%s' was removed "
+                    "from your account." % keytype
+                )
+            )
+
     def test_destroySelf_notifications_can_be_suppressed(self):
         person = self.factory.makePerson()
         with person_logged_in(person):
@@ -124,6 +152,25 @@ class TestSSHKeySet(TestCaseWithFactory):
             StartsWith("The SSH key 'comment' has been added to your account.")
         )
 
+    def test_notification_add_ssh_key_comment_empty(self):
+        person = self.factory.makePerson()
+        with person_logged_in(person):
+            key = getUtility(ISSHKeySet).new(
+                person,
+                self.factory.makeSSHKeyText(comment="")
+            )
+            [email] = pop_notifications()
+        self.assertEqual(
+            "New SSH key added to your account.", email['Subject']
+        )
+        keytype = key.getFullKeyText().split(" ", 1)[0]
+        self.assertThat(
+            email.get_payload(),
+            StartsWith(
+                "An SSH key of type '%s' has been added "
+                "to your account." % keytype)
+        )
+
     def test_does_not_send_notifications(self):
         person = self.factory.makePerson()
         with person_logged_in(person):
diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py
index 29c6059..6a5e459 100644
--- a/lib/lp/testing/factory.py
+++ b/lib/lp/testing/factory.py
@@ -4548,7 +4548,7 @@ class BareLaunchpadObjectFactory(ObjectFactory):
         return "%s %s %s" % (key_type, key_text, comment)
 
     def makeSSHKey(self, person=None, key_type="ssh-rsa",
-                   send_notification=True):
+                   send_notification=True, comment=None):
         """Create a new SSHKey.
 
         :param person: If specified, the person to attach the key to. If
@@ -4561,7 +4561,7 @@ class BareLaunchpadObjectFactory(ObjectFactory):
         """
         if person is None:
             person = self.makePerson()
-        public_key = self.makeSSHKeyText(key_type=key_type)
+        public_key = self.makeSSHKeyText(key_type=key_type, comment=comment)
         return getUtility(ISSHKeySet).new(
             person, public_key, send_notification=send_notification)
 

Follow ups