Repository: freedomofpress/securedrop

Issue:
SSH over LAN sdconfig prompt could be clearer
## Description

This isn't a bug, but I think there's an opportunity for a slight improvement to Admin UX in this prompt.

The current prompt for SSH over LAN in `securedrop-admin sdconfig`:

```
Enable SSH over Tor: yes
```

A suggestion for improved prompt for SSH over LAN in `securedrop-admin sdconfig`:

```
Enable SSH over Tor or LAN [Tor (Recommended) or LAN]: Tor
```

where Tor is the default

## User Research Evidence

Two people QAing the release asked Mike or asked Gitter about what they should set in the prompt to set LAN only ;)


Discussion:

Resolving patch:
diff --git a/admin/securedrop_admin/__init__.py b/admin/securedrop_admin/__init__.py
--- a/admin/securedrop_admin/__init__.py
+++ b/admin/securedrop_admin/__init__.py
@@ -71,6 +71,13 @@ def validate(self, document):
             raise ValidationError(
                 message="Must not be root, amnesia or an empty string")
 
+    class ValidateSSH(Validator):
+        def validate(self, document):
+            text = document.text
+            if text.lower() == 'tor' or text.lower() == 'lan':
+                return True
+            raise ValidationError(message="Must be Tor (recommended) or LAN")
+
     class ValidateIP(Validator):
         def validate(self, document):
             if re.match('((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}$',
@@ -339,9 +346,9 @@ def __init__(self, args):
              SiteConfig.ValidateOSSECPassword(),
              None],
             ['enable_ssh_over_tor', True, bool,
-             u'Enable SSH over Tor',
-             SiteConfig.ValidateYesNo(),
-             lambda x: x.lower() == 'yes'],
+             u'Enable SSH over Tor (recommended) or LAN',
+             SiteConfig.ValidateSSH(),
+             self.sanitize_ssh_over_tor_or_lan],
             ['securedrop_supported_locales', [], types.ListType,
              u'Space separated list of additional locales to support '
              '(' + translations + ')',
@@ -401,6 +408,12 @@ def validated_input(self, prompt, default, validator, transform):
     def sanitize_fingerprint(self, value):
         return value.upper().replace(' ', '')
 
+    def sanitize_ssh_over_tor_or_lan(self, value):
+        if value.lower() == 'tor':
+            return True
+        elif value.lower() == 'lan':
+            return False
+
     def validate_gpg_keys(self):
         keys = (('securedrop_app_gpg_public_key',
                  'securedrop_app_gpg_fingerprint'),


Test patch:
diff --git a/admin/tests/test_securedrop-admin.py b/admin/tests/test_securedrop-admin.py
--- a/admin/tests/test_securedrop-admin.py
+++ b/admin/tests/test_securedrop-admin.py
@@ -363,6 +363,17 @@ def test_validate_yes_no(self):
         assert validator.validate(Document("no"))
         assert validator.validate(Document("NO"))
 
+    def test_validate_ssh_tor_or_lan(self):
+        validator = securedrop_admin.SiteConfig.ValidateSSH()
+        with pytest.raises(ValidationError):
+            validator.validate(Document("not Tor or LAN"))
+        with pytest.raises(ValidationError):
+            validator.validate(Document("yes"))
+        with pytest.raises(ValidationError):
+            validator.validate(Document("no"))
+        assert validator.validate(Document("Tor"))
+        assert validator.validate(Document("LAN"))
+
     def test_validate_fingerprint(self):
         validator = securedrop_admin.SiteConfig.ValidateFingerprint()
         assert validator.validate(Document(
@@ -602,7 +613,6 @@ def verify_prompt_boolean(
 
     verify_prompt_securedrop_app_https_on_source_interface = \
         verify_prompt_boolean
-    verify_prompt_enable_ssh_over_tor = verify_prompt_boolean
 
     verify_prompt_securedrop_app_gpg_public_key = verify_desc_consistency
 
@@ -639,6 +649,7 @@ def verify_prompt_fingerprint(self, site_config, desc):
     verify_prompt_sasl_domain = verify_desc_consistency_allow_empty
     verify_prompt_sasl_username = verify_prompt_not_empty
     verify_prompt_sasl_password = verify_prompt_not_empty
+    verify_prompt_enable_ssh_over_tor = verify_prompt_not_empty
 
     def verify_prompt_securedrop_supported_locales(self, site_config, desc):
         (var, default, etype, prompt, validator, transform) = desc