From 082ce35dda3ece598e215723435ef2a46ef573b7 Mon Sep 17 00:00:00 2001 From: Eliot Berriot <contact@eliotberriot.com> Date: Mon, 4 Mar 2019 17:29:20 +0100 Subject: [PATCH] More flexible config --- funkwhale_cli/api.py | 12 ++++++++ funkwhale_cli/cli.py | 56 ++++++++++++++++++++++++++++++++----- funkwhale_cli/config.py | 10 +++++++ funkwhale_cli/exceptions.py | 4 +++ setup.cfg | 3 ++ tests/test_config.py | 10 +++++++ 6 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 funkwhale_cli/config.py create mode 100644 tests/test_config.py diff --git a/funkwhale_cli/api.py b/funkwhale_cli/api.py index 3d9e92d..1227802 100644 --- a/funkwhale_cli/api.py +++ b/funkwhale_cli/api.py @@ -43,3 +43,15 @@ def clean_nodeinfo(data): schema = schemas.NodeInfo2Schema() result = schema.load(data) return result.data + + +async def get_jwt_token(session, url, username, password): + url = f"{url}/api/v1/token/" + response = await session.post( + url, data={"username": username, "password": password} + ) + if response.status == 400: + raise exceptions.AuthenticationError( + "Unable to log in with provided credentials" + ) + return (await response.json())["token"] diff --git a/funkwhale_cli/cli.py b/funkwhale_cli/cli.py index a5eb15c..0026ca1 100644 --- a/funkwhale_cli/cli.py +++ b/funkwhale_cli/cli.py @@ -3,6 +3,7 @@ import aiohttp import click import click_log import functools +import keyring import logging import urllib.parse import json @@ -36,11 +37,10 @@ def async_command(f): return functools.update_wrapper(wrapper, f) -@click.group() -@click.option("-H", "--url", envvar="FUNKWHALE_SERVER_URL", type=URL) -@click_log.simple_verbosity_option(logs.logger, expose_value=True) -@click.pass_context -def cli(ctx, url, verbosity): +SERVER_DECORATOR = click.option("-H", "--url", envvar="FUNKWHALE_SERVER_URL", type=URL) + + +def set_server(ctx, url): ctx.ensure_object(dict) ctx.obj["SERVER_URL"] = url parsed = urllib.parse.urlparse(url) @@ -48,17 +48,59 @@ def cli(ctx, url, verbosity): ctx.obj["SERVER_PROTOCOL"] = parsed.scheme +@click.group() +@SERVER_DECORATOR +@click_log.simple_verbosity_option(logs.logger, expose_value=True) +@click.pass_context +def cli(ctx, url, verbosity): + set_server(ctx, url) + + +@cli.command() +@SERVER_DECORATOR +@click.option("-u", "--username", envvar="FUNKWHALE_USERNAME", prompt=True) +@click.option( + "-p", "--password", envvar="FUNKWHALE_PASSWORD", prompt=True, hide_input=True +) +@click.pass_context +@async_command +async def login(ctx, url, username, password): + set_server(ctx, url) + async with api.get_session() as session: + token = await api.get_jwt_token( + session, ctx.obj["SERVER_URL"], username=username, password=password + ) + + keyring.set_password(ctx.obj["SERVER_URL"], username, token) + click.echo("Login successfull!") + + +@cli.command() +@SERVER_DECORATOR +@click.option("-u", "--username", envvar="FUNKWHALE_USERNAME", prompt=True) +@click.pass_context +@async_command +async def logout(ctx, url, username): + set_server(ctx, url) + keyring.delete_password(ctx.obj["SERVER_URL"], username) + click.echo("Logout successfull!") + + @cli.group() +@SERVER_DECORATOR @click.pass_context -def server(ctx): +def server(ctx, url): + set_server(ctx, url) ctx.ensure_object(dict) @server.command() +@SERVER_DECORATOR @click.option("--raw", is_flag=True) @click.pass_context @async_command -async def info(ctx, raw): +async def info(ctx, url, raw): + set_server(ctx, url) async with api.get_session() as session: nodeinfo = await api.fetch_nodeinfo( session, diff --git a/funkwhale_cli/config.py b/funkwhale_cli/config.py new file mode 100644 index 0000000..1107491 --- /dev/null +++ b/funkwhale_cli/config.py @@ -0,0 +1,10 @@ +import appdirs +import keyring + + +def get_app_dirs(): + return appdirs.AppDirs("funkwhale", "funkwhale") + + +def set_password(key, user, password): + keyring.set_password(key, user, password) diff --git a/funkwhale_cli/exceptions.py b/funkwhale_cli/exceptions.py index 4a4096f..6a775f6 100644 --- a/funkwhale_cli/exceptions.py +++ b/funkwhale_cli/exceptions.py @@ -4,3 +4,7 @@ class FunkwhaleError(Exception): class NoNodeInfo(FunkwhaleError): pass + + +class AuthenticationError(FunkwhaleError): + pass diff --git a/setup.cfg b/setup.cfg index 96330ec..16402bc 100644 --- a/setup.cfg +++ b/setup.cfg @@ -21,9 +21,12 @@ packages = find: install_requires = aiofiles aiohttp + appdirs click click-log + keyring marshmallow + python-dotenv semver [options.entry_points] diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000..d54cf7d --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,10 @@ +import appdirs + +from funkwhale_cli import config + + +def test_get_app_dir(): + assert ( + config.get_app_dirs().user_config_dir + == appdirs.AppDirs("funkwhale", "funkwhale").user_config_dir + ) -- GitLab