Skip to content

Commit

Permalink
Documentation cleanups
Browse files Browse the repository at this point in the history
  • Loading branch information
fluffy-critter committed Jul 22, 2020
1 parent 25983d7 commit 9ec20c1
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 74 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
all: setup version format mypy cov pylint flake8 doc requirements.txt
all: setup version format mypy cov pylint flake8 doc

.PHONY: setup
setup:
Expand Down
17 changes: 10 additions & 7 deletions authl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def get_handler_for_url(self, url: str) -> typing.Tuple[typing.Optional[handlers
:param str url: The identity address; typically a URL but can also be a
WebFinger or email address.
Returns a tuple of ``(handler, hander_id, profile_url)``.
:returns: a tuple of ``(handler, hander_id, profile_url)``.
"""

Expand Down Expand Up @@ -106,28 +106,31 @@ def from_config(config: typing.Dict[str, typing.Any],
:param dict config: a configuration dictionary. See the individual handlers'
from_config functions to see possible configuration values.
:param dict state_storage: a dict-like object that will store session
state for methods that need it. Defaults to an instance-local
ExpiringDict; this will not work well in load-balanced scenarios. This
can be safely stored in a user session, if available.
:param tokens.TokenStore token_storage: a TokenStore for storing session
state for methods that need it. Defaults to an instance-local DictStore
backed by an ExpiringDict; this will not work well in load-balanced
scenarios.
Handlers will be enabled based on truthy values of the following keys:
``EMAIL_FROM`` / ``EMAIL_SENDMAIL`` -- enable :py:mod:`handlers.email_addr`
* ``EMAIL_FROM`` / ``EMAIL_SENDMAIL``: enable :py:mod:`handlers.email_addr`
``FEDIVERSE_NAME`` -- enable :py:mod:`handlers.fediverse`
* ``FEDIVERSE_NAME``: enable :py:mod:`handlers.fediverse`
``INDIEAUTH_CLIENT_ID`` -- enable :py:mod:`handlers.indieauth`
* ``INDIEAUTH_CLIENT_ID``: enable :py:mod:`handlers.indieauth`
``TWITTER_CLIENT_KEY`` -- enable :py:mod:`handlers.twitter`
* ``TWITTER_CLIENT_KEY``: enable :py:mod:`handlers.twitter`
``TEST_ENABLED`` -- enable :py:mod:`handlers.test_handler`
* ``TEST_ENABLED``: enable :py:mod:`handlers.test_handler`
For additional configuration settings, see each handler's respective ``from_config()``.
For additional configuration settings, see each handler's respective
``from_config()``.
"""

Expand Down
14 changes: 8 additions & 6 deletions authl/flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,15 @@ def setup(app: flask.Flask, config: typing.Dict[str, typing.Any], **kwargs) -> A
""" Simple setup function.
:param flask.flask app: The Flask app to configure with Authl.
:param dict config: Configuration values for the Authl instance; see
:py:func:`authl.from_config`
:param kwargs: Additional arguments to pass along to the
:py:class:`AuthlFlask` constructor
Returns the configured :py:class:`authl.Authl` instance. Note that if you
want the :py:class:`AuthlFlask` instance you should instantiate that directly.
:returns: The configured :py:class:`authl.Authl` instance. Note that if you
want the :py:class:`AuthlFlask` instance you should instantiate that directly.
"""
return AuthlFlask(app, config, **kwargs).authl
Expand All @@ -91,7 +93,7 @@ def load_template(filename: str) -> str:
Raises `FileNotFoundError` on no such template
Returns the contents of the template.
:returns: the contents of the template.
"""
return utils.read_file(os.path.join(os.path.dirname(__file__), 'flask_templates', filename))

Expand All @@ -106,7 +108,6 @@ def wrapped_func(*args, **kwargs):
return wrapped_func
return decorator


def _redir_dest_to_path(destination: str):
""" Convert a redirection destination to a path fragment """
assert destination.startswith('/'), "Redirection destinations must begin with '/'"
Expand All @@ -118,7 +119,6 @@ def _redir_path_to_dest(path: str):
assert not path.startswith('/'), "Path fragments cannot start with '/'"
return '/' + path


class AuthlFlask:
""" Easy Authl wrapper for use with a Flask application.
Expand Down Expand Up @@ -244,7 +244,7 @@ def __init__(self,
notify_render_func: typing.Callable = None,
session_auth_name: str = 'me',
force_https: bool = False,
stylesheet: typing.Union[str, typing.Callable] = None,
stylesheet: typing.Union[str,typing.Callable] = None,
on_verified: typing.Callable = None,
make_permanent: bool = True,
state_storage: dict = None,
Expand Down Expand Up @@ -444,3 +444,5 @@ def client_id():
baseurl = f'{parsed.scheme}://{parsed.hostname}'
LOGGER.debug("using client_id %s", baseurl)
return baseurl


31 changes: 18 additions & 13 deletions authl/handlers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@

"""
Base handler class
==================
The :py:class:`Handler` class defines the abstract interface for an
authentication handler. Handlers are registered to an :py:class:`authl.Authl`
instance which then selects the handler based on the provided identity.
The basic flow for how a handler is selected is:
1. The :py:class:`authl.Authl` instance checks to see if any handler knows how to
handle the identity URL directly
2. The instance retrieves the URL, and hands the parse tree and response
headers off to each handler to see if it's able to handle the URL based
on that
#. The :py:class:`authl.Authl` instance checks to see if any handler knows how
to handle the identity URL directly; if so, it returns the first match.
#. The instance retrieves the URL, and hands the parse tree and response headers
off to each handler to see if it's able to handle the URL based on that; if
so, it returns the first match.
In the case of a Webfinger address (e.g. ``@user@example.com``) it repeats this
process for every profile URL provided by the Webfinger response.
process for every profile URL provided by the Webfinger response until it finds
a match.
"""
"""

import typing
from abc import ABC, abstractmethod
Expand All @@ -34,8 +39,8 @@ def handles_url(self, url: str) -> typing.Optional[str]:
It is okay to check for an API endpoint (relative to the URL) in
implementing this. However, if the content kept at the URL itself needs
to be parsed to make the determination, implement that in handles_page
instead.
to be parsed to make the determination, implement that in
:py:func:`handles_page` instead.
Whatever value this returns will be passed back in to initiate_auth, so
if that value matters, return a reasonable URL.
Expand All @@ -50,9 +55,9 @@ def handles_page(self, url: str, headers, content, links) -> bool:
:param str url: the canonicized identity URL
:param dict headers: the raw headers from the page request, as a
MultiDict (as provided by the `Requests`_ library)
:param bs4.BeautifulSoup content: -- the page content, as a
:param bs4.BeautifulSoup content: the page content, as a
`BeautifulSoup4`_ parse tree
:param dict links: -- the results of parsing the Link: headers, as a
:param dict links: the results of parsing the Link: headers, as a
dict of rel -> dict of 'url' and 'rel', as provided by the
`Requests`_ library
Expand All @@ -77,7 +82,7 @@ def initiate_auth(self, id_url: str, callback_uri: str, redir: str) -> dispositi
:param str callback_uri: Callback URL for verification
:param str redir: Where to redirect the user to after verification
Returns the :py:mod:`authl.disposition` to be handled by the frontend.
:returns: the :py:mod:`authl.disposition` to be handled by the frontend.
"""

Expand All @@ -89,7 +94,7 @@ def check_callback(self, url: str, get: dict, data: dict) -> disposition.Disposi
:param dict get: the GET parameters for the verification
:param dict data: the POST parameters for the verification
Returns a :py:mod:`authl.disposition` object to be handled by the
:returns: a :py:mod:`authl.disposition` object to be handled by the
frontend. Any errors which get raised internally should be caught and
returned as an appropriate :py:class:`authl.disposition.Error`.
Expand Down
38 changes: 19 additions & 19 deletions authl/handlers/email_addr.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def simple_sendmail(connector, sender_address, subject):
:param str sender_address: The email address to use for the sender
:param str subject: the subject line to attach to the message
Returns a function that, when called with an
:returns" a function that, when called with an
:py:class:`email.message.EmailMessage`, sets the `From` and `Subject` lines
and sends the message via the provided connector.
Expand All @@ -221,34 +221,34 @@ def from_config(config, token_store: tokens.TokenStore):
:param dict config: The configuration settings for the handler. Relevant
keys:
* ``EMAIL_SENDMAIL``: a function to call to send the email (defaults to
using :py:func:`simple_sendmail`)
* ``EMAIL_SENDMAIL``: a function to call to send the email; if omitted,
generates one using :py:func:`simple_sendmail` configured with:
* ``EMAIL_FROM``: the ``From:`` address to use when sending an email
* ``EMAIL_FROM``: the ``From:`` address to use when sending an email
* ``EMAIL_SUBJECT``: the ``Subject:`` to use for a login email
* ``EMAIL_SUBJECT``: the ``Subject:`` to use for a login email
* ``EMAIL_CHECK_MESSAGE``: The :py:class:`authl.disposition.Notify` client
data. Defaults to a simple string-based message.
* ``SMTP_HOST``: the outgoing SMTP host
* ``EMAIL_TEMPLATE_FILE``: A path to a text file for the email message; if
not specified a default template will be used.
* ``SMTP_PORT``: the outgoing SMTP port
* ``EMAIL_EXPIRE_TIME``: How long a login email is valid for, in seconds
(defaults to the :py:class:`EmailAddress` default value)
* ``SMTP_USE_SSL``: whether to use SSL for the SMTP connection (defaults
to ``False``). It is *highly recommended* to set this to `True` if
your ``SMTP_HOST`` is anything other than ``localhost``.
* ``SMTP_HOST``: the outgoing SMTP host (required if no
``EMAIL_SENDMAIL``)
* ``SMTP_USERNAME``: the username to use with the SMTP server
* ``SMTP_PORT``: the outgoing SMTP port (required if no ``EMAIL_SENDMAIL``)
* ``SMTP_PASSWORD``: the password to use with the SMTP server
* ``SMTP_USE_SSL``: whether to use SSL for the SMTP connection (defaults
to ``False``). It is *highly recommended* to set this to `True` if
your ``SMTP_HOST`` is anything other than `localhost`.
* ``EMAIL_CHECK_MESSAGE``: The :py:class:`authl.disposition.Notify` client
data. Defaults to a simple string-based message.
* ``SMTP_USERNAME``: the username to use with the SMTP server
* ``EMAIL_TEMPLATE_FILE``: A path to a text file for the email message; if
not specified a default template will be used.
* ``EMAIL_EXPIRE_TIME``: How long a login email is valid for, in seconds
(defaults to the :py:class:`EmailAddress` default value)
* ``SMTP_PASSWORD``: the password to use with the SMTP server
:param tokens.TokenStore token_store: the authentication token storage
mechanism; see :py:mod:`authl.tokens` for more information.
Expand Down
17 changes: 12 additions & 5 deletions authl/handlers/fediverse.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
=================
This handler allows login via Fediverse instances; currently `Mastodon
<https://joinmastodon.org>` and `Pleroma <https://pleroma.social>` are
<https://joinmastodon.org>`_ and `Pleroma <https://pleroma.social>`_ are
supported, as is anything else with basic support for the Mastodon client API.
See :py:func:`from_config` for the simplest configuration mechanism.
Expand All @@ -28,7 +28,7 @@
class Fediverse(Handler):
""" Handler for Fediverse services (Mastodon, Pleroma) """

class Client:
class _Client:
""" Fediverse OAuth client info """
# pylint:disable=too-few-public-methods

Expand Down Expand Up @@ -115,6 +115,10 @@ def _get_instance(url) -> typing.Optional[str]:
return None

def handles_url(self, url):
"""
Checks for an ``/api/v1/instance`` endpoint to determine if this
is a Mastodon-compatible instance
"""
LOGGER.info("Checking URL %s", url)

instance = self._get_instance(url)
Expand All @@ -132,7 +136,7 @@ def handles_url(self, url):
return instance

@functools.lru_cache(128)
def _get_client(self, id_url: str, callback_uri: str) -> typing.Optional['Fediverse.Client']:
def _get_client(self, id_url: str, callback_uri: str) -> typing.Optional['Fediverse._Client']:
""" Get the client data """
instance = self._get_instance(id_url)
if not instance:
Expand All @@ -151,7 +155,7 @@ def _get_client(self, id_url: str, callback_uri: str) -> typing.Optional['Fedive
if info['redirect_uri'] != callback_uri:
raise ValueError("Got incorrect redirect_uri")

return Fediverse.Client(instance, {
return Fediverse._Client(instance, {
'client_id': info['client_id'],
'redirect_uri': info['redirect_uri'],
'scope': 'read:accounts'
Expand Down Expand Up @@ -213,7 +217,7 @@ def check_callback(self, url, get, data):
if time.time() > when + self._timeout:
return disposition.Error("Transaction timed out", redir)

client = Fediverse.Client(*client_tuple)
client = Fediverse._Client(*client_tuple)

if 'error' in get:
return disposition.Error("Error signing into Fediverse", redir)
Expand Down Expand Up @@ -258,8 +262,11 @@ def from_config(config, token_store: tokens.TokenStore):
""" Generate a Fediverse handler from the given config dictionary.
:param dict config: Configuration values; relevant keys:
* ``FEDIVERSE_NAME``: the name of your website (required)
* ``FEDIVERSE_HOMEPAGE``: your website's homepage (recommended)
* ``FEDIVERSE_TIMEOUT``: the maximum time to wait for login to complete
:param tokens.TokenStore token_store: The authentication token storage
Expand Down

0 comments on commit 9ec20c1

Please sign in to comment.