Repository: freedomofpress/securedrop

Issue:
[0.7.0] Enable ssh over tor config is automatically populated with invalid response
# Bug

## Description
'LAN' setting is not persisted to `site-specific` and must be re-entered at every `./securedrop-admin sdconfig` run
## Steps to Reproduce

* run `./securedrop-admin sdconfig`
* when prompted for `Enable SSH over Tor (recommended) or LAN`, set `LAN`
* inspect `install_files/ansible-base/group_vars/all/site-specific` and observe `enable_ssh_over_tor: false`
* run `./securedrop-admin sdconfig` and observe that the default response for the `Enable SSH over Tor (recommended) or LAN` is no, and requires user input to change back to `LAN`

## Expected Behavior
`./securedrop-admin sdconfig` should populate default responses based on current SecureDrop instance configuration.

## Actual Behavior
The `Enable SSH over Tor (recommended) or LAN` field is automatically populated with an invalid response.



Discussion:
Suggestion for a minimal/quick fix given the time constraints for 0.7.0 release:
* Revert the changes introduced in https://github.com/freedomofpress/securedrop/issues/3324
* Replace the prompt with clearer language such as: "Would you like to enable SSH over local network? This will disable SSH over Tor (If not, SSH will be only available over Tor)"
I think that's a great idea @emkll. That a minimal solution that will be clear for admins. Note that we'll need to update the pre-release announcement.
What is the expected effort on the less minimal solution of persisting the current config if no user input is provided?
It would unfortunately involve either a hack or broader code changes that we should probably avoid so close to release unless necessary
Thanks for the clarification. I agree the bug is severe enough to justify the revert/language change. Will update release announcement once that's merged.

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,13 +71,6 @@ 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}$',
@@ -347,9 +340,10 @@ def __init__(self, args):
              SiteConfig.ValidateOSSECPassword(),
              None],
             ['enable_ssh_over_tor', True, bool,
-             u'Enable SSH over Tor (recommended) or LAN',
-             SiteConfig.ValidateSSH(),
-             self.sanitize_ssh_over_tor_or_lan],
+             u'Enable SSH over Tor (recommended, disables SSH over LAN). '
+             u'If you respond no, SSH will be available over LAN only',
+             SiteConfig.ValidateYesNo(),
+             lambda x: x.lower() == 'yes'],
             ['securedrop_supported_locales', [], types.ListType,
              u'Space separated list of additional locales to support '
              '(' + translations + ')',
@@ -418,12 +412,6 @@ 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,17 +363,6 @@ 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(
@@ -613,6 +602,7 @@ 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
 
@@ -649,7 +639,6 @@ 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