Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removes v2 service configuration and setup support #5915

Merged
merged 3 commits into from Apr 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
79 changes: 2 additions & 77 deletions admin/securedrop_admin/__init__.py
Expand Up @@ -64,7 +64,7 @@
sdlog = logging.getLogger(__name__)
RELEASE_KEY = '22245C81E3BAEB4138B36061310F561200F4AD77'
DEFAULT_KEYSERVER = 'hkps://keys.openpgp.org'
SUPPORT_ONION_URL = 'http://support6kv2242qx.onion'
SUPPORT_ONION_URL = 'http://sup6h5iyiyenvjkfxbgrjynm5wsgijjoatvnvdgyyi7je3xqm4kh6uqd.onion'
SUPPORT_URL = 'https://support.freedom.press'
EXIT_SUCCESS = 0
EXIT_SUBPROCESS_ERROR = 1
Expand Down Expand Up @@ -193,23 +193,6 @@ def validate(self, document: Document) -> bool:
return True
raise ValidationError(message="Must be either yes or no")

class ValidateYesNoForV3(Validator):

def __init__(self, *args: Any, **kwargs: Any) -> None:
Validator.__init__(*args, **kwargs)
self.caller = args[0]

def validate(self, document: Document) -> bool:
text = document.text.lower()
# Raise error if admin tries to disable v3 when v2
# is already disabled.
if text == 'no' and \
not self.caller._config_in_progress.get("v2_onion_services"): # noqa: E501
raise ValidationError(message="Since you disabled v2 onion services, you must enable v3 onion services.") # noqa: E501
if text == 'yes' or text == 'no':
return True
raise ValidationError(message="Must be either yes or no")

class ValidateFingerprint(Validator):
def validate(self, document: Document) -> bool:
text = document.text.replace(' ', '')
Expand Down Expand Up @@ -457,17 +440,6 @@ def __init__(self, args: argparse.Namespace) -> None:
SiteConfig.ValidateLocales(self.args.app_path),
str.split,
lambda config: True),
('v2_onion_services', self.check_for_v2_onion(), bool,
'WARNING: v2 onion services cannot be installed on servers ' +
'running Ubuntu 20.04. Do you want to enable v2 onion services?',
SiteConfig.ValidateYesNo(),
lambda x: x.lower() == 'yes',
lambda config: True),
('v3_onion_services', self.check_for_v3_onion, bool,
'Do you want to enable v3 onion services (recommended)?',
SiteConfig.ValidateYesNoForV3(self),
lambda x: x.lower() == 'yes',
lambda config: True),
] # type: List[_DescEntryType]

def load_and_update_config(self, validate: bool = True, prompt: bool = True) -> bool:
Expand All @@ -485,52 +457,8 @@ def update_config(self, prompt: bool = True) -> bool:
self.save()
self.validate_gpg_keys()
self.validate_journalist_alert_email()
self.validate_https_and_v3()
return True

def validate_https_and_v3(self) -> bool:
"""
Checks if https is enabled with v3 onion service.

:returns: False if both v3 and https enabled, True otherwise.
"""
warning_msg = ("You have configured HTTPS on your source interface "
"and v3 onion services. "
"IMPORTANT: Ensure that you update your certificate "
"to include your v3 source URL before advertising "
"it to sources! ")

if self.config.get("v3_onion_services", False) and \
self.config.get("securedrop_app_https_certificate_cert_src"):
print(warning_msg)
return False
return True

def check_for_v2_onion(self) -> bool:
"""
Check if v2 onion services are already enabled or not.
"""
source_ths = os.path.join(self.args.ansible_path, "app-source-ths")
if os.path.exists(source_ths): # Means old installation
data = ""
with open(source_ths) as fobj:
data = fobj.read()

data = data.strip()
if len(data) < 56: # Old v2 onion address
return True
return False

def check_for_v3_onion(self) -> bool:
"""
Check if v3 onion services should be enabled by default or not.
"""
v2_value = self._config_in_progress.get("v2_onion_services", False)
# We need to see the value in the configuration file
# for v3_onion_services
v3_value = self.config.get("v3_onion_services", True)
return v3_value or not v2_value

def user_prompt_config(self) -> Dict[str, Any]:
self._config_in_progress = {}
for desc in self.desc:
Expand All @@ -547,10 +475,7 @@ def user_prompt_config_one(
self, desc: _DescEntryType, from_config: Optional[Any]
) -> Any:
(var, default, type, prompt, validator, transform, condition) = desc
if from_config is not None and var != "v3_onion_services":
# v3_onion_services must be true if v2 is disabled by the admin
# otherwise, we may end up in a situation where both v2 and v3
# are disabled by the admin (by mistake).
if from_config is not None:
default = from_config
prompt += ': '

Expand Down
227 changes: 0 additions & 227 deletions admin/tests/test_integration.py
Expand Up @@ -47,76 +47,6 @@
smtp_relay: smtp.gmail.com
smtp_relay_port: 587
ssh_users: sd
v2_onion_services: false
v3_onion_services: true
'''

WHEN_BOTH_TRUE = '''app_hostname: app
app_ip: 10.20.2.2
daily_reboot_time: 5
dns_server:
- 8.8.8.8
- 8.8.4.4
enable_ssh_over_tor: true
journalist_alert_email: ''
journalist_alert_gpg_public_key: ''
journalist_gpg_fpr: ''
monitor_hostname: mon
monitor_ip: 10.20.3.2
ossec_alert_email: test@gmail.com
ossec_alert_gpg_public_key: sd_admin_test.pub
ossec_gpg_fpr: 1F544B31C845D698EB31F2FF364F1162D32E7E58
sasl_domain: gmail.com
sasl_password: testpassword
sasl_username: testuser
securedrop_app_gpg_fingerprint: 1F544B31C845D698EB31F2FF364F1162D32E7E58
securedrop_app_gpg_public_key: sd_admin_test.pub
securedrop_app_https_certificate_cert_src: ''
securedrop_app_https_certificate_chain_src: ''
securedrop_app_https_certificate_key_src: ''
securedrop_app_https_on_source_interface: false
securedrop_supported_locales:
- de_DE
- es_ES
smtp_relay: smtp.gmail.com
smtp_relay_port: 587
ssh_users: sd
v2_onion_services: true
v3_onion_services: true
'''

WHEN_ONLY_V2 = '''app_hostname: app
app_ip: 10.20.2.2
daily_reboot_time: 5
dns_server:
- 8.8.8.8
- 8.8.4.4
enable_ssh_over_tor: true
journalist_alert_email: ''
journalist_alert_gpg_public_key: ''
journalist_gpg_fpr: ''
monitor_hostname: mon
monitor_ip: 10.20.3.2
ossec_alert_email: test@gmail.com
ossec_alert_gpg_public_key: sd_admin_test.pub
ossec_gpg_fpr: 1F544B31C845D698EB31F2FF364F1162D32E7E58
sasl_domain: gmail.com
sasl_password: testpassword
sasl_username: testuser
securedrop_app_gpg_fingerprint: 1F544B31C845D698EB31F2FF364F1162D32E7E58
securedrop_app_gpg_public_key: sd_admin_test.pub
securedrop_app_https_certificate_cert_src: ''
securedrop_app_https_certificate_chain_src: ''
securedrop_app_https_certificate_key_src: ''
securedrop_app_https_on_source_interface: false
securedrop_supported_locales:
- de_DE
- es_ES
smtp_relay: smtp.gmail.com
smtp_relay_port: 587
ssh_users: sd
v2_onion_services: true
v3_onion_services: false
'''

JOURNALIST_ALERT_OUTPUT = '''app_hostname: app
Expand Down Expand Up @@ -149,8 +79,6 @@
smtp_relay: smtp.gmail.com
smtp_relay_port: 587
ssh_users: sd
v2_onion_services: false
v3_onion_services: true
'''

HTTPS_OUTPUT = '''app_hostname: app
Expand Down Expand Up @@ -183,8 +111,6 @@
smtp_relay: smtp.gmail.com
smtp_relay_port: 587
ssh_users: sd
v2_onion_services: false
v3_onion_services: true
'''


Expand Down Expand Up @@ -339,21 +265,6 @@ def verify_locales_prompt(child):
child.expect(rb'Space separated list of additional locales to support') # noqa: E501


def verify_v2_onion_for_first_time(child):
child.expect(rb'Do you want to enable v2 onion services\?\:', timeout=2) # noqa: E501
assert ANSI_ESCAPE.sub('', child.buffer.decode("utf-8")).strip() == 'no' # noqa: E501


def verify_v3_onion_for_first_time(child):
child.expect(rb'Do you want to enable v3 onion services \(recommended\)\?\:', timeout=2) # noqa: E501
assert ANSI_ESCAPE.sub('', child.buffer.decode("utf-8")).strip() == 'yes' # noqa: E501


def verify_v3_onion_when_v2_is_enabled(child):
child.expect(rb'Do you want to enable v3 onion services \(recommended\)\?\:', timeout=2) # noqa: E501
assert ANSI_ESCAPE.sub('', child.buffer.decode("utf-8")).strip() == 'yes' # noqa: E501


def verify_install_has_valid_config():
"""
Checks that securedrop-admin install validates the configuration.
Expand Down Expand Up @@ -424,9 +335,7 @@ def test_sdconfig_on_first_run():
child.sendline('')
verify_locales_prompt(child)
child.sendline('de_DE es_ES')
verify_v2_onion_for_first_time(child)
child.sendline('\b' * 3 + 'no')
verify_v3_onion_for_first_time(child)
child.sendline('\b' * 4 + 'yes')

child.expect(pexpect.EOF, timeout=10) # Wait for validation to occur
Expand All @@ -441,134 +350,6 @@ def test_sdconfig_on_first_run():
verify_install_has_valid_config()


def test_sdconfig_both_v2_v3_true():
cmd = os.path.join(os.path.dirname(CURRENT_DIR),
'securedrop_admin/__init__.py')
child = pexpect.spawn('python {0} --force --root {1} sdconfig'.format(cmd, SD_DIR))
verify_username_prompt(child)
child.sendline('')
verify_reboot_prompt(child)
child.sendline('\b5') # backspace and put 5
verify_ipv4_appserver_prompt(child)
child.sendline('')
verify_ipv4_monserver_prompt(child)
child.sendline('')
verify_hostname_app_prompt(child)
child.sendline('')
verify_hostname_mon_prompt(child)
child.sendline('')
verify_dns_prompt(child)
child.sendline('')
verify_app_gpg_key_prompt(child)
child.sendline('\b' * 14 + 'sd_admin_test.pub')
verify_https_prompt(child)
# Default answer is no
child.sendline('')
verify_app_gpg_fingerprint_prompt(child)
child.sendline('1F544B31C845D698EB31F2FF364F1162D32E7E58')
verify_ossec_gpg_key_prompt(child)
child.sendline('\b' * 9 + 'sd_admin_test.pub')
verify_ossec_gpg_fingerprint_prompt(child)
child.sendline('1F544B31C845D698EB31F2FF364F1162D32E7E58')
verify_admin_email_prompt(child)
child.sendline('test@gmail.com')
verify_journalist_gpg_key_prompt(child)
child.sendline('')
verify_smtp_relay_prompt(child)
child.sendline('')
verify_smtp_port_prompt(child)
child.sendline('')
verify_sasl_domain_prompt(child)
child.sendline('')
verify_sasl_username_prompt(child)
child.sendline('testuser')
verify_sasl_password_prompt(child)
child.sendline('testpassword')
verify_ssh_over_lan_prompt(child)
child.sendline('')
verify_locales_prompt(child)
child.sendline('de_DE es_ES')
verify_v2_onion_for_first_time(child)
child.sendline('\b' * 3 + 'yes')
verify_v3_onion_when_v2_is_enabled(child)
child.sendline('\b' * 3 + 'yes')

child.expect(pexpect.EOF, timeout=10) # Wait for validation to occur
child.close()
assert child.exitstatus == 0
assert child.signalstatus is None

with open(os.path.join(SD_DIR, 'install_files/ansible-base/group_vars/all/site-specific')) as fobj: # noqa: E501
data = fobj.read()
assert data == WHEN_BOTH_TRUE

verify_install_has_valid_config()


def test_sdconfig_only_v2_true():
cmd = os.path.join(os.path.dirname(CURRENT_DIR),
'securedrop_admin/__init__.py')
child = pexpect.spawn('python {0} --force --root {1} sdconfig'.format(cmd, SD_DIR))
verify_username_prompt(child)
child.sendline('')
verify_reboot_prompt(child)
child.sendline('\b5') # backspace and put 5
verify_ipv4_appserver_prompt(child)
child.sendline('')
verify_ipv4_monserver_prompt(child)
child.sendline('')
verify_hostname_app_prompt(child)
child.sendline('')
verify_hostname_mon_prompt(child)
child.sendline('')
verify_dns_prompt(child)
child.sendline('')
verify_app_gpg_key_prompt(child)
child.sendline('\b' * 14 + 'sd_admin_test.pub')
verify_https_prompt(child)
# Default answer is no
child.sendline('')
verify_app_gpg_fingerprint_prompt(child)
child.sendline('1F544B31C845D698EB31F2FF364F1162D32E7E58')
verify_ossec_gpg_key_prompt(child)
child.sendline('\b' * 9 + 'sd_admin_test.pub')
verify_ossec_gpg_fingerprint_prompt(child)
child.sendline('1F544B31C845D698EB31F2FF364F1162D32E7E58')
verify_admin_email_prompt(child)
child.sendline('test@gmail.com')
verify_journalist_gpg_key_prompt(child)
child.sendline('')
verify_smtp_relay_prompt(child)
child.sendline('')
verify_smtp_port_prompt(child)
child.sendline('')
verify_sasl_domain_prompt(child)
child.sendline('')
verify_sasl_username_prompt(child)
child.sendline('testuser')
verify_sasl_password_prompt(child)
child.sendline('testpassword')
verify_ssh_over_lan_prompt(child)
child.sendline('')
verify_locales_prompt(child)
child.sendline('de_DE es_ES')
verify_v2_onion_for_first_time(child)
child.sendline('\b' * 3 + 'yes')
verify_v3_onion_when_v2_is_enabled(child)
child.sendline('\b' * 3 + 'no')

child.expect(pexpect.EOF, timeout=10) # Wait for validation to occur
child.close()
assert child.exitstatus == 0
assert child.signalstatus is None

with open(os.path.join(SD_DIR, 'install_files/ansible-base/group_vars/all/site-specific')) as fobj: # noqa: E501
data = fobj.read()
assert data == WHEN_ONLY_V2

verify_install_has_valid_config()


def test_sdconfig_enable_journalist_alerts():
cmd = os.path.join(os.path.dirname(CURRENT_DIR),
'securedrop_admin/__init__.py')
Expand Down Expand Up @@ -621,10 +402,6 @@ def test_sdconfig_enable_journalist_alerts():
child.sendline('')
verify_locales_prompt(child)
child.sendline('de_DE es_ES')
verify_v2_onion_for_first_time(child)
child.sendline('\b' * 3 + 'no')
verify_v3_onion_for_first_time(child)
child.sendline('\b' * 4 + 'yes')

child.expect(pexpect.EOF, timeout=10) # Wait for validation to occur
child.close()
Expand Down Expand Up @@ -697,10 +474,6 @@ def test_sdconfig_enable_https_on_source_interface():
child.sendline('')
verify_locales_prompt(child)
child.sendline('de_DE es_ES')
verify_v2_onion_for_first_time(child)
child.sendline('\b' * 3 + 'no')
verify_v3_onion_for_first_time(child)
child.sendline('\b' * 4 + 'yes')

child.expect(pexpect.EOF, timeout=10) # Wait for validation to occur
child.close()
Expand Down