From 2575ee029ca41f4bc9777b40dade3da9962b22ae Mon Sep 17 00:00:00 2001 From: neodarz Date: Sun, 31 Jan 2021 19:23:00 +0100 Subject: Add plain HTTP authentification --- README.md | 88 +++++++++++++++++++++++++++++++++++++----------- pyfunkwhale/client.py | 76 ++++++++++++++++++++++++----------------- pyfunkwhale/funkwhale.py | 9 ++--- 3 files changed, 116 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 41fe849..a798c1e 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,47 @@ pip install -r requirements.txt # Use -This client library use th OAuth2 Authorization Code flow and ask to the user -to authorize this app. I'm not ok with how I do this for the moment. If you -have suggestion about how to do this, I will gladly accept to discuse it. -And you can also send me suggestions for other parts of this module ;) +First you to select an authentification method, two are actually available +Plain HTTP and OAuth2. -Example usage: +## Plain HTTP authentification + +``` +#!/usr/bin/env python +# -*- condig: utf-8 -*- + +from pyfunkwhale.funkwhale import Funkwhale +from pyfunkwhale.client import InvalidTokenError + +client_name = "pyfunkwhale" + +redirect_uri = "urn:ietf:wg:oauth:2.0:oob" + +# This is your instance and login information +username = "demo" +password = "demo" +domain = "https://demo.funkwhale.audio" + +authorization_endpoint = domain + "/authorize" +login_endpoint = domain + "/api/v1/oauth/token/" + +login_endpoint = domain + "/api/v1/token/" + +funkwhale = Funkwhale( + client_name, + redirect_uri, + username, + password, + domain, + login_endpoint, +) + +artists = funkwhale.albums() + +print(artists) +``` + +## OAuth2 Authorization Code flow ``` #!/usr/bin/env python @@ -48,9 +83,8 @@ domain = "https://demo.funkwhale.audio" scopes = "read" -authorization_endpoint = "https://demo.funkwhale.audio/authorize" -token_endpoint = "https://demo.funkwhale.audio/api/v1/oauth/token/" - +authorization_endpoint = domain + "/authorize" +login_endpoint = domain + "/api/v1/oauth/token/" # Save the OAuth2 infos in file, this is ugly yup token_filename = 'oauth_token.data' @@ -61,9 +95,19 @@ def _ask_new_auth(funkwhale, message): authorization_code = input("Enter response code: ") funkwhale.client._set_token(authorization_code) -funkwhale = Funkwhale(client_name, redirect_uri, client_id, client_secret, - scopes, username, password, domain, authorization_endpoint, - token_endpoint, token_filename) +funkwhale = Funkwhale( + client_name, + redirect_uri, + username, + password, + domain, + login_endpoint, + client_secret, + scopes, + client_id, + authorization_endpoint, + token_filename, +) try: artists = funkwhale.artists() @@ -72,13 +116,14 @@ except InvalidTokenError as e: artists = funkwhale.artists() print(artists) +``` -# In case you ask, their is an example for downloading a song -try: - r = funkwhale.listen("f9d02c64-bafa-43cb-8e1e-fa612e7c5dab") -except InvalidTokenError as e: - _ask_new_auth(funkwhale, e.message) - r = funkwhale.rate_limit() +## Examples + +In case you ask, their is an example for downloading a song + +``` +r = funkwhale.listen("f9d02c64-bafa-43cb-8e1e-fa612e7c5dab") with open('/tmp/test.mp3', 'wb') as f: for chunk in r.iter_content(chunk_size=8192): @@ -91,9 +136,12 @@ with open('/tmp/test.mp3', 'wb') as f: List of features implemented or planned: - [/] Auth - - [x] Login with OAuth2 Authorization Code flow - - [x] Register an OAuth2 application - - [x] Get an JWT token + - [x] OAuth2 Authorization Code flow + - [x] Login + - [x] Register an application + - [x] Get an JWT token + - [x] Simple Authentication + - [x] Login - [ ] Create an account - [ ] Request a password request - [x] Retrieve user information diff --git a/pyfunkwhale/client.py b/pyfunkwhale/client.py index a2f5b57..9e0b72c 100644 --- a/pyfunkwhale/client.py +++ b/pyfunkwhale/client.py @@ -4,6 +4,7 @@ import json import re from time import time +import requests from requests_oauthlib import OAuth2Session from oauthlib.oauth2.rfc6749.errors import InvalidScopeError from requests.models import Response @@ -21,31 +22,39 @@ class InvalidTokenError(Exception): class Client(object): - def __init__(self, client_name, redirect_uri, client_id, - client_secret, scopes, username, password, domain, - authorization_endpoint, token_endpoint, - token_filename): + def __init__(self, client_name, redirect_uri, username, password, domain, + login_endpoint, client_secret = None, scopes = None, + client_id = None, authorization_endpoint = None, + token_filename = None): + self.client_name = client_name self.redirect_uri = redirect_uri - self.client_id = client_id - self.client_secret = client_secret - self.scopes = scopes self.token = None self.username = username self.password = password self.domain = domain - self.authorization_endpoint = authorization_endpoint - self.token_endpoint = token_endpoint - self.token_filename = token_filename - self.oauth_client = OAuth2Session( - self.client_id, - redirect_uri=self.redirect_uri, - scope=self.scopes) - self.authorization_url, self.state = self.oauth_client. \ - authorization_url( - self.authorization_endpoint) + self.login_endpoint = login_endpoint + + if 'oauth' not in self.login_endpoint: + self.session = requests.Session() + self.session.auth = (username, password) + + self.session.get(self.domain + '/api/v1/token/') + else: + self.client_secret = client_secret + self.scopes = scopes + self.client_id = client_id + self.authorization_endpoint = authorization_endpoint + self.token_filename = token_filename + self.oauth_client = OAuth2Session( + self.client_id, + redirect_uri=self.redirect_uri, + scope=self.scopes) + self.authorization_url, self.state = self.oauth_client. \ + authorization_url( + self.authorization_endpoint) def _connect(self): """ @@ -64,7 +73,7 @@ class Client(object): self.authorization_code = authorization_code self.token = self.oauth_client.fetch_token( - self.token_endpoint, + self.login_endpoint, code=self.authorization_code, client_secret=self.client_secret) write_file(self.token_filename, self.token) @@ -77,7 +86,7 @@ class Client(object): if time() - 60 > self.token["expires_at"]: try: self.token = self.oauth_client.refresh_token( - self.token_endpoint, + self.login_endpoint, refresh_token=self.token["refresh_token"], client_id=self.client_id, client_secret=self.client_secret) @@ -122,21 +131,28 @@ class Client(object): pyfunkwhale.client.InvalidTokenError If current token is invalid """ - self._refresh_token() - if headers is None: - headers = {'Authorization': self.token['token_type'] + ' ' + - self.token['access_token']} + if getattr(self, 'oauth_client', False): + self._refresh_token() + if headers is None: + headers = {'Authorization': self.token['token_type'] + ' ' + + self.token['access_token']} - _call = getattr(self.oauth_client, method) + _call = getattr(self.oauth_client, method) - endpoint = re.sub(r'^\/', '', endpoint) + endpoint = re.sub(r'^\/', '', endpoint) - r = _call(self.domain + '/api/v1/' + endpoint, headers=headers, - params=params, data=data) + r = _call(self.domain + '/api/v1/' + endpoint, headers=headers, + params=params, data=data) - if r.status_code == 401: - raise InvalidTokenError(self) + if r.status_code == 401: + raise InvalidTokenError(self) + + r.raise_for_status() + else: + _call = getattr(self.session, method) + r = _call(self.domain + '/api/v1/' + endpoint, headers=headers, + params=params, data=data) - r.raise_for_status() + r.raise_for_status() return r diff --git a/pyfunkwhale/funkwhale.py b/pyfunkwhale/funkwhale.py index 1faf788..47e6b84 100644 --- a/pyfunkwhale/funkwhale.py +++ b/pyfunkwhale/funkwhale.py @@ -7,13 +7,8 @@ from pyfunkwhale.client import Client class Funkwhale(object): - def __init__(self, client_name, redirect_uri, client_id, - client_secret, scopes, username, password, domain, - authorization_endpoint, token_endpoint, token_filename): - self.client = Client( - client_name, redirect_uri, client_id, client_secret, - scopes, username, password, domain, authorization_endpoint, - token_endpoint, token_filename) + def __init__(self, *args, **kwargs): + self.client = Client(*args, **kwargs) def _build_params(self, arguments: dict) -> dict: """ -- cgit v1.2.1