from contextlib import ExitStack, closing from pathlib import Path from tempfile import TemporaryDirectory from unittest.mock import patch import json import os import sqlite3 import subprocess import sys import unittest import zipfile import manage import server_config class ConfigurationTests(unittest.TestCase): def setUp(self): self.stack = ExitStack() self.directory = Path(self.stack.enter_context(TemporaryDirectory())) self.stack.enter_context(patch.dict(os.environ, {"REXIMEMO_CONFIG": str(self.directory / "settings.json")})) def tearDown(self): self.stack.close() def test_defaults_and_partial_save_preserve_unrelated_settings(self): self.assertEqual(server_config.load_config()["port"], 8080) saved = server_config.save_config({"site_name": "My Flipnotes", "port": 8088, "unknown_secret": "not saved"}) self.assertEqual(saved["site_name"], "My Flipnotes") self.assertNotIn("unknown_secret", saved) saved = server_config.save_config({"welcome_message": "Hello!", "guest_posting": "0"}) self.assertEqual(saved["site_name"], "My Flipnotes") self.assertEqual(saved["port"], 8088) self.assertFalse(saved["guest_posting"]) self.assertEqual(list(self.directory.glob("*.tmp")), []) def test_bad_settings_leave_existing_configuration_intact(self): original = server_config.save_config({"site_name": "Keep this"}) for field in ({"accent_colour": "red;background:url(evil)"}, {"port": 80}, {"host": "someone else's host"}, {"max_upload_bytes": 1}, {"logo_url": "https://other.example/picture.png"}, {"logo_url": "/static/../private.png"}, {"logo_url": "/static/%2e%2e/private.png"}): with self.subTest(field=field), self.assertRaises(ValueError): server_config.save_config(field) self.assertEqual(server_config.load_config(), original) self.assertEqual(server_config.save_config({"logo_url": "/branding/logo.png"})["logo_url"], "/branding/logo.png") def test_corrupt_settings_do_not_silently_reset_the_server(self): server_config.config_path().write_text("not json", encoding="utf-8") with self.assertRaisesRegex(ValueError, "valid JSON"): server_config.load_config() def test_backup_contains_snapshot_media_and_branding_without_logs(self): database_path = self.directory / "database" / "reximemo.sqlite3" database_path.parent.mkdir() with closing(sqlite3.connect(database_path)) as database: with database: database.execute("CREATE TABLE example(value TEXT)") database.execute("INSERT INTO example VALUES('preserved')") for name, data in (("database/Creators/SAMPLE/note.ppm", b"PARA"), ("database/Comments/note.ppm", b"mini"), ("web/static/logo.png", b"logo"), ("database/site-logo.png", b"custom logo"), ("logs/private.log", b"do not export")): path = self.directory / name path.parent.mkdir(parents=True, exist_ok=True) path.write_bytes(data) server_config.save_config({"site_name": "Backup server"}) destination = self.directory / "copy.zip" with patch.object(manage, "ROOT", self.directory), patch.object(manage, "database_path", return_value=database_path): self.assertEqual(manage.backup_server(destination), destination) with self.assertRaises(ValueError): manage.backup_server(destination) with zipfile.ZipFile(destination) as archive: self.assertEqual(archive.read("database/Creators/SAMPLE/note.ppm"), b"PARA") self.assertEqual(archive.read("database/Comments/note.ppm"), b"mini") self.assertEqual(archive.read("database/site-logo.png"), b"custom logo") self.assertEqual(json.loads(archive.read("server-settings.json"))["site_name"], "Backup server") self.assertFalse(any(name.startswith("logs/") for name in archive.namelist())) restored = self.directory / "restored.sqlite3" restored.write_bytes(archive.read("database/reximemo.sqlite3")) with closing(sqlite3.connect(restored)) as database: self.assertEqual(database.execute("SELECT value FROM example").fetchone()[0], "preserved") def test_setup_chooses_an_admin_and_disables_the_default_login(self): script = ''' import json import manage answers = iter(["A friendly server", "8099", "127.0.0.1", "friendlyadmin"]) manage.setup_server(input_fn=lambda prompt: next(answers), password_fn=lambda prompt: "a strong setup password") from database import Database assert Database.verify_account("friendlyadmin", "a strong setup password")["is_admin"] == 1 assert Database.verify_account("reximemo", "alpine") is None from server_config import load_config assert load_config()["setup_complete"] is True assert load_config()["port"] == 8099 Database.close() ''' environment = {**os.environ, "REXIMEMO_DB": str(self.directory / "setup.sqlite3")} result = subprocess.run([sys.executable, "-c", script], cwd=Path(manage.__file__).parent, env=environment, capture_output=True, text=True) self.assertEqual(result.returncode, 0, result.stderr) self.assertNotIn("a strong setup password", server_config.config_path().read_text()) if __name__ == "__main__": unittest.main()