FreedomBox/plinth/modules/kiwix/privileged.py
Sunil Mohan Adapa cfdf92cf0d
kiwix: Fix various issues after review
- Fix icon paths in copyright file.

- Minor refactoring.

- Add Kiwix library link to app page as well as users may want to see the
  content available before installing the app.

- Consolidate terminology to 'content package' for UI and just 'package'
internally.

- Drop unused SYSTEM_USER constant.

- Simplify the ExecStart= in systemd service file.

- Fix incorrect i18n caused by non-lazy formatting of strings.

- Confirm that xml parsing is not vulnerable as expat library of required
version is used in Debian bookworm.

- Don't start the kiwix daemon when managing library if app is disabled.

- Ignore errors when removing files during uninstallation.

- Handle failures more gracefully when library XML file does not have required
attributes.

- Update SVG/PNG icons to adhere to FreedomBox guidelines.

- Trim block translations in templates.

- Drop comments/deadcode inside translation strings.

- Drop a comment inside add content page that only makes sense with multiple
methods for adding content.

- tests: Don't use pkg_resources library as it is deprecated. We can use
importlib.resources library in future if we run tests on zip installations.

- Fix potential security issues while writing file to tmp directory.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
2023-10-17 13:40:31 -07:00

102 lines
3.0 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Privileged actions for Kiwix content server.
"""
import os
import pathlib
import shutil
import subprocess
from xml.etree import ElementTree
from plinth import action_utils
from plinth.actions import privileged
from plinth.modules import kiwix
# Only one central library is supported.
KIWIX_HOME = pathlib.Path('/var/lib/kiwix-server-freedombox')
LIBRARY_FILE = KIWIX_HOME / 'library_zim.xml'
CONTENT_DIR = KIWIX_HOME / 'content'
@privileged
def add_package(file_name: str):
"""Adds a content package to Kiwix.
Adding packages is idempotent.
Users can add content to Kiwix in multiple ways:
- Upload a ZIM file
- Provide a link to the ZIM file
- Provide a magnet link to the ZIM file
The commandline download manager aria2c is a dependency of kiwix-tools.
aria2c is used for both HTTP and Magnet downloads.
"""
kiwix.validate_file_name(file_name)
# Moving files to the Kiwix library path ensures that
# they can't be removed by other apps or users.
zim_file_name = pathlib.Path(file_name).name
CONTENT_DIR.mkdir(exist_ok=True)
zim_file_dest = str(CONTENT_DIR / zim_file_name)
shutil.chown(file_name, 'root', 'root')
os.chmod(file_name, 0o644)
shutil.move(file_name, zim_file_dest)
_kiwix_manage_add(zim_file_dest)
def _kiwix_manage_add(zim_file: str):
subprocess.check_call(['kiwix-manage', LIBRARY_FILE, 'add', zim_file])
# kiwix-serve doesn't read the library file unless it is restarted.
action_utils.service_try_restart('kiwix-server-freedombox')
@privileged
def uninstall() -> None:
"""Remove all content during uninstall."""
shutil.rmtree(str(CONTENT_DIR), ignore_errors=True)
LIBRARY_FILE.unlink(missing_ok=True)
@privileged
def list_packages() -> dict[str, dict[str, str]]:
"""Return the list of content packages configured in library file."""
library = ElementTree.parse(LIBRARY_FILE).getroot()
books = {}
for book in library:
path = book.attrib['path'].split('/')[-1]
path = path.removesuffix('.zim').lower() # Strip '.zim' from the path
try:
books[book.attrib['id']] = {
'title': book.attrib['title'],
'description': book.attrib['description'],
'path': path
}
except KeyError:
pass # Ignore entries that don't have expected properties
return books
@privileged
def delete_package(zim_id: str):
"""Remove a content package from the library file."""
library = ElementTree.parse(LIBRARY_FILE).getroot()
for book in library:
try:
if book.attrib['id'] != zim_id:
continue
subprocess.check_call(
['kiwix-manage', LIBRARY_FILE, 'remove', zim_id])
(KIWIX_HOME / book.attrib['path']).unlink()
action_utils.service_try_restart('kiwix-server-freedombox')
return
except KeyError: # Expected properties not found on elements
pass