diff --git a/plinth/modules/backups/tests/test_ssh_remotes.py b/plinth/modules/backups/tests/test_ssh_remotes.py new file mode 100644 index 000000000..1ab962877 --- /dev/null +++ b/plinth/modules/backups/tests/test_ssh_remotes.py @@ -0,0 +1,106 @@ +# +# This file is part of FreedomBox. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +""" +Tests for SSH remotes for backups. +""" + +import datetime +import os +import pwd +import shutil +import subprocess +import tempfile + +import pytest + +from plinth.utils import generate_password, random_string + +from .. import forms + +pytestmark = pytest.mark.usefixtures('needs_root', 'needs_sudo') + + +@pytest.fixture(name='temp_home', scope='module', autouse=True) +def fixture_temp_home_directory(): + """Create a new temporary directory to act as a home directory. + """ + # TODO Try to get this working with tempfile.TemporaryDirectory() + tempfile.TemporaryDirectory() + dir_name = f'/tmp/{random_string()}' + os.mkdir(dir_name) + yield dir_name + subprocess.check_call(['sudo', 'rm', '-rf', dir_name]) + + +@pytest.fixture(name='password', scope='module', autouse=True) +def fixture_password(): + return generate_password() + + +@pytest.fixture(name='temp_user', scope='module', autouse=True) +def fixture_create_temp_user(temp_home, password): + """Create a temporary user. + """ + username = random_string() + # User account expires tomorrow + tomorrow = datetime.date.today() + datetime.timedelta(days=1) + subprocess.check_call([ + 'sudo', 'useradd', '-d', temp_home, '-m', '-p', password, username, + '-e', + tomorrow.strftime('%Y-%m-%d') + ]) + subprocess.check_call(['sudo', 'chown', username, temp_home]) + yield username + subprocess.check_call(['sudo', 'userdel', username]) + + +@pytest.fixture(name='has_ssh_key', scope='module', autouse=True) +def fixture_ssh_key(temp_home, temp_user, password): + subprocess.check_call([ + 'sudo', '-u', temp_user, 'ssh-keygen', '-t', 'rsa', '-b', '1024', '-N', + '', '-f', f'{temp_home}/.ssh/id_rsa', '-q' + ]) + + +@pytest.mark.usefixtures('has_ssh_key') +def test_user_setup(temp_home, temp_user): + assert os.path.isdir(temp_home) + assert pwd.getpwnam(temp_user) + + +# Tests +# forms.AddRepositoryForm +# * Create empty directory if not exists +# * Check if the directory is empty +# - if not empty, check if it's an existing backup repository +# - else throw an error + + +@pytest.mark.django_db +@pytest.mark.usefixtures('has_ssh_key') +def test_add_repository_when_directory_is_missing(temp_home, temp_user, + password): + repo_path = os.path.join(temp_home, 'backups') + data = { + 'repository': f'{temp_user}@localhost:{repo_path}', + 'ssh_password': password, + 'encryption': 'none' + } + form = forms.AddRepositoryForm(data=data) + form.is_valid() + form.clean() + assert os.path.isdir(repo_path) diff --git a/plinth/utils.py b/plinth/utils.py index 5c5562500..78fbb9ca3 100644 --- a/plinth/utils.py +++ b/plinth/utils.py @@ -120,6 +120,13 @@ class YAMLFile(object): return os.stat(self.yaml_file).st_size == 0 +def random_string(size=8): + """Generate a random alphanumeric string.""" + chars = (random.SystemRandom().choice(string.ascii_letters) + for _ in range(size)) + return ''.join(chars) + + def generate_password(size=32): """Generate a random password using ascii alphabet and digits.""" chars = (random.SystemRandom().choice(string.ascii_letters + string.digits)