Improve documentation

This commit is contained in:
Unrud 2020-01-12 23:32:28 +01:00
parent 6202257fc2
commit 88a0af8ba1
25 changed files with 207 additions and 76 deletions

View File

@ -18,9 +18,10 @@
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
""" """
Radicale WSGI application. Entry point for external WSGI servers (like uWSGI or Gunicorn).
Can be used with an external WSGI server or the built-in server. Configuration files can be specified in the environment variable
``RADICALE_CONFIG``.
""" """
@ -57,6 +58,7 @@ def _init_application(config_path, wsgi_errors):
def application(environ, start_response): def application(environ, start_response):
"""Entry point for external WSGI servers."""
config_path = environ.get("RADICALE_CONFIG", config_path = environ.get("RADICALE_CONFIG",
os.environ.get("RADICALE_CONFIG")) os.environ.get("RADICALE_CONFIG"))
if _application is None: if _application is None:

View File

@ -19,6 +19,7 @@
Radicale executable module. Radicale executable module.
This module can be executed from a command line with ``$python -m radicale``. This module can be executed from a command line with ``$python -m radicale``.
Uses the built-in WSGI server.
""" """

View File

@ -20,7 +20,8 @@
""" """
Radicale WSGI application. Radicale WSGI application.
Can be used with an external WSGI server or the built-in server. Can be used with an external WSGI server (see ``radicale.application()``) or
the built-in server (see ``radicale.server`` module).
""" """
@ -63,10 +64,14 @@ class Application(
ApplicationPropfindMixin, ApplicationProppatchMixin, ApplicationPropfindMixin, ApplicationProppatchMixin,
ApplicationPutMixin, ApplicationReportMixin): ApplicationPutMixin, ApplicationReportMixin):
"""WSGI application managing collections.""" """WSGI application."""
def __init__(self, configuration): def __init__(self, configuration):
"""Initialize application.""" """Initialize application.
``configuration`` see ``radicale.config`` module.
"""
super().__init__() super().__init__()
self.configuration = configuration self.configuration = configuration
self.auth = auth.load(configuration) self.auth = auth.load(configuration)

View File

@ -18,39 +18,13 @@
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
""" """
Authentication management. Authentication module.
Default is htpasswd authentication. Authentication is based on usernames and passwords. If something more
advanced is needed an external WSGI server or reverse proxy can be used
(see ``remote_user`` or ``http_x_remote_user`` backend).
Apache's htpasswd command (httpd.apache.org/docs/programs/htpasswd.html) Take a look at the class ``BaseAuth`` if you want to implement your own.
manages a file for storing user credentials. It can encrypt passwords using
different methods, e.g. BCRYPT, MD5-APR1 (a version of MD5 modified for
Apache), SHA1, or by using the system's CRYPT routine. The CRYPT and SHA1
encryption methods implemented by htpasswd are considered as insecure. MD5-APR1
provides medium security as of 2015. Only BCRYPT can be considered secure by
current standards.
MD5-APR1-encrypted credentials can be written by all versions of htpasswd (it
is the default, in fact), whereas BCRYPT requires htpasswd 2.4.x or newer.
The `is_authenticated(user, password)` function provided by this module
verifies the user-given credentials by parsing the htpasswd credential file
pointed to by the ``htpasswd_filename`` configuration value while assuming
the password encryption method specified via the ``htpasswd_encryption``
configuration value.
The following htpasswd password encrpytion methods are supported by Radicale
out-of-the-box:
- plain-text (created by htpasswd -p...) -- INSECURE
- CRYPT (created by htpasswd -d...) -- INSECURE
- SHA1 (created by htpasswd -s...) -- INSECURE
When passlib (https://pypi.python.org/pypi/passlib) is importable, the
following significantly more secure schemes are parsable by Radicale:
- MD5-APR1 (htpasswd -m...) -- htpasswd's default method
- BCRYPT (htpasswd -B...) -- Requires htpasswd 2.4.x
""" """

View File

@ -17,6 +17,41 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
Authentication backend that checks credentials with a htpasswd file.
Apache's htpasswd command (httpd.apache.org/docs/programs/htpasswd.html)
manages a file for storing user credentials. It can encrypt passwords using
different methods, e.g. BCRYPT, MD5-APR1 (a version of MD5 modified for
Apache), SHA1, or by using the system's CRYPT routine. The CRYPT and SHA1
encryption methods implemented by htpasswd are considered as insecure. MD5-APR1
provides medium security as of 2015. Only BCRYPT can be considered secure by
current standards.
MD5-APR1-encrypted credentials can be written by all versions of htpasswd (it
is the default, in fact), whereas BCRYPT requires htpasswd 2.4.x or newer.
The `is_authenticated(user, password)` function provided by this module
verifies the user-given credentials by parsing the htpasswd credential file
pointed to by the ``htpasswd_filename`` configuration value while assuming
the password encryption method specified via the ``htpasswd_encryption``
configuration value.
The following htpasswd password encrpytion methods are supported by Radicale
out-of-the-box:
- plain-text (created by htpasswd -p...) -- INSECURE
- CRYPT (created by htpasswd -d...) -- INSECURE
- SHA1 (created by htpasswd -s...) -- INSECURE
When passlib (https://pypi.python.org/pypi/passlib) is importable, the
following significantly more secure schemes are parsable by Radicale:
- MD5-APR1 (htpasswd -m...) -- htpasswd's default method
- BCRYPT (htpasswd -B...) -- Requires htpasswd 2.4.x
"""
import base64 import base64
import functools import functools
import hashlib import hashlib

View File

@ -17,6 +17,15 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
Authentication backend that takes the username from the
``HTTP_X_REMOTE_USER`` header.
It's intended for use with a reverse proxy. Be aware as this will be insecure
if the reverse proxy is not configured properly.
"""
import radicale.auth.none as none import radicale.auth.none as none

View File

@ -17,6 +17,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
A dummy backend that accepts any username and password.
"""
from radicale import auth from radicale import auth

View File

@ -17,6 +17,14 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
Authentication backend that takes the username from the ``REMOTE_USER``
WSGI environment variable.
It's intended for use with an external WSGI server.
"""
import radicale.auth.none as none import radicale.auth.none as none

View File

@ -18,9 +18,10 @@
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
""" """
Radicale configuration module. Configuration module
Give a configparser-like interface to read and write configuration. Use ``load()`` to obtain an instance of ``Configuration`` for use with
``radicale.app.Application``.
""" """
@ -254,9 +255,16 @@ def parse_compound_paths(*compound_paths):
def load(paths=()): def load(paths=()):
"""Load configuration from files. """
Create instance of ``Configuration`` for use with
``radicale.app.Application``.
``paths`` a list of the format ``[(PATH, IGNORE_IF_MISSING), ...]``. ``paths`` a list of configuration files with the format
``[(PATH, IGNORE_IF_MISSING), ...]``.
If a configuration file is missing and IGNORE_IF_MISSING is set, the
config is set to ``Configuration.SOURCE_MISSING``.
The configuration can later be changed with ``Configuration.update()``.
""" """
configuration = Configuration(DEFAULT_CONFIG_SCHEMA) configuration = Configuration(DEFAULT_CONFIG_SCHEMA)
@ -287,6 +295,9 @@ class Configuration:
``schema`` a dict that describes the configuration format. ``schema`` a dict that describes the configuration format.
See ``DEFAULT_CONFIG_SCHEMA``. See ``DEFAULT_CONFIG_SCHEMA``.
Use ``load()`` to create an instance for use with
``radicale.app.Application``.
""" """
self._schema = schema self._schema = schema
self._values = {} self._values = {}
@ -304,13 +315,12 @@ class Configuration:
"""Update the configuration. """Update the configuration.
``config`` a dict of the format {SECTION: {OPTION: VALUE, ...}, ...}. ``config`` a dict of the format {SECTION: {OPTION: VALUE, ...}, ...}.
Set to ``Configuration.SOURCE_MISSING`` to indicate a missing The configuration is checked for errors according to the config schema.
configuration source for inspection.
``source`` a description of the configuration source ``source`` a description of the configuration source (used in error
messages).
``internal`` allows updating "_internal" sections and skips the source ``internal`` allows updating "_internal" sections.
during inspection.
""" """
new_values = {} new_values = {}
@ -407,7 +417,14 @@ class Configuration:
return copy return copy
def log_config_sources(self): def log_config_sources(self):
"""Inspect all external config sources and write problems to logger.""" """
A helper function that writes a description of all config sources
to logger.
Configs set to ``Configuration.SOURCE_MISSING`` are described as
missing.
"""
for config, source, _ in self._configs: for config, source, _ in self._configs:
if config is self.SOURCE_MISSING: if config is self.SOURCE_MISSING:
logger.info("Skipped missing %s", source) logger.info("Skipped missing %s", source)

View File

@ -17,6 +17,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
Helper functions for HTTP.
"""
from http import client from http import client
NOT_ALLOWED = ( NOT_ALLOWED = (

View File

@ -18,6 +18,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
Module for address books and calendar entries (see ``Item``).
"""
import math import math
import sys import sys
from hashlib import md5 from hashlib import md5
@ -257,6 +262,8 @@ def find_tag_and_time_range(vobject_item):
class Item: class Item:
"""Class for address book and calendar entries."""
def __init__(self, collection_path=None, collection=None, def __init__(self, collection_path=None, collection=None,
vobject_item=None, href=None, last_modified=None, text=None, vobject_item=None, href=None, last_modified=None, text=None,
etag=None, uid=None, name=None, component_name=None, etag=None, uid=None, name=None, component_name=None,

View File

@ -16,10 +16,15 @@
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
""" """
Radicale logging module. Functions to set up Python's logging facility for Radicale's WSGI application.
Manage logging from a configuration file. For more information, see: Log messages are sent to the first available target of:
http://docs.python.org/library/logging.config.html
- Error stream specified by the WSGI server in wsgi.errors
- systemd-journald
- stderr
The logger is thread-safe and fork-safe.
""" """

View File

@ -16,6 +16,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
Helper functions for working with the file system.
"""
import contextlib import contextlib
import os import os
import posixpath import posixpath

View File

@ -16,25 +16,17 @@
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
""" """
Rights backends. The rights module used to determine if a user can read and/or write
collections and entries.
This module loads the rights backend, according to the rights Permissions:
configuration.
Default rights are based on a regex-based file whose name is specified in the - R: read a collection
config (section "right", key "file"). - r: read an address book or calendar entry
- W: write a collection
- w: read an address book or calendar entry
Authentication login is matched against the "user" key, and collection's path Take a look at the class ``BaseRights`` if you want to implement your own.
is matched against the "collection" key. You can use Python's ConfigParser
interpolation values %(login)s and %(path)s. You can also get groups from the
user regex in the collection with {0}, {1}, etc.
For example, for the "user" key, ".+" means "authenticated user" and ".*"
means "anybody" (including anonymous users).
Section names are only used for naming the rule.
Leading or ending slashes are trimmed from collection's path.
""" """

View File

@ -15,6 +15,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
Rights backend that allows authenticated users to read and write all
calendars and address books.
"""
from radicale import pathutils, rights from radicale import pathutils, rights

View File

@ -15,6 +15,24 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
Rights backend based on a regex-based file whose name is specified in the
config (section "right", key "file").
Authentication login is matched against the "user" key, and collection's path
is matched against the "collection" key. You can use Python's ConfigParser
interpolation values %(login)s and %(path)s. You can also get groups from the
user regex in the collection with {0}, {1}, etc.
For example, for the "user" key, ".+" means "authenticated user" and ".*"
means "anybody" (including anonymous users).
Section names are only used for naming the rule.
Leading or ending slashes are trimmed from collection's path.
"""
import configparser import configparser
import re import re

View File

@ -15,6 +15,12 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
Rights backend that allows authenticated users to read and write their own
calendars and address books.
"""
import radicale.rights.authenticated as authenticated import radicale.rights.authenticated as authenticated
from radicale import pathutils, rights from radicale import pathutils, rights

View File

@ -15,6 +15,12 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
Rights backend that allows authenticated users to read all calendars and
address books but only grants write access to their own.
"""
import radicale.rights.authenticated as authenticated import radicale.rights.authenticated as authenticated
from radicale import pathutils, rights from radicale import pathutils, rights

View File

@ -18,7 +18,9 @@
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
""" """
Radicale WSGI server. Built-in WSGI server.
Uses forking on POSIX to overcome Python's GIL.
""" """

View File

@ -17,12 +17,9 @@
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
""" """
Storage backends. The storage module that stores calendars and address books.
This module loads the storage backend, according to the storage configuration. Take a look at the class ``BaseCollection`` if you want to implement your own.
Default storage uses one folder per collection and one file per collection
entry.
""" """

View File

@ -16,6 +16,13 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
Storage backend that stores data in the file system.
Uses one folder per collection and one file per collection entry.
"""
import contextlib import contextlib
import os import os
import time import time

View File

@ -14,6 +14,13 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
The web module for the website at ``/.web``.
Take a look at the class ``BaseWeb`` if you want to implement your own.
"""
from importlib import import_module from importlib import import_module
from radicale.log import logger from radicale.log import logger

View File

@ -14,6 +14,18 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
The default web backend.
Features:
- Create and delete address books and calendars.
- Edit basic metadata of existing address books and calendars.
- Upload address books and calendars from files.
"""
import os import os
import posixpath import posixpath
import time import time

View File

@ -14,6 +14,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
A dummy web backend that shows a simple message.
"""
from http import client from http import client
from radicale import httputils, pathutils, web from radicale import httputils, pathutils, web

View File

@ -18,11 +18,7 @@
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
""" """
XML and iCal requests manager. Helper functions for XML.
Note that all these functions need to receive unicode objects for full
iCal requests (PUT) and string objects with charset correctly defined
in them for XML requests (all but PUT).
""" """