diff --git a/dev/releases/3.2.yml b/dev/releases/3.2.yml index fa78d45..6a154f9 100644 --- a/dev/releases/3.2.yml +++ b/dev/releases/3.2.yml @@ -40,6 +40,7 @@ minor_release_name: "Nicole" - "[Bugfix] Fixed Last.fm authentication" 3.2.3: notes: + - "[Architecture] Upgraded doreah, significant rework of authentication" - "[Bugfix] Fixed initial permission check" - "[Bugfix] Fixed and updated various texts" - - "[Bugfix] Fixed moving tracks to different album" \ No newline at end of file + - "[Bugfix] Fixed moving tracks to different album" diff --git a/maloja/apis/native_v1.py b/maloja/apis/native_v1.py index 042687f..4ea98ad 100644 --- a/maloja/apis/native_v1.py +++ b/maloja/apis/native_v1.py @@ -7,7 +7,6 @@ from bottle import response, static_file, FormsDict from inspect import signature from doreah.logging import log -from doreah.auth import authenticated_function # nimrodel API from nimrodel import EAPI as API @@ -15,7 +14,7 @@ from nimrodel import Multi from .. import database -from ..pkg_global.conf import malojaconfig, data_dir +from ..pkg_global.conf import malojaconfig, data_dir, auth @@ -575,7 +574,7 @@ def album_info_external(k_filter, k_limit, k_delimit, k_amount): @api.post("newscrobble") -@authenticated_function(alternate=api_key_correct,api=True,pass_auth_result_as='auth_result') +@auth.authenticated_function(alternate=api_key_correct,api=True,pass_auth_result_as='auth_result') @catch_exceptions def post_scrobble( artist:Multi=None, @@ -655,7 +654,7 @@ def post_scrobble( @api.post("addpicture") -@authenticated_function(alternate=api_key_correct,api=True) +@auth.authenticated_function(alternate=api_key_correct,api=True) @catch_exceptions @convert_kwargs def add_picture(k_filter, k_limit, k_delimit, k_amount, k_special): @@ -678,7 +677,7 @@ def add_picture(k_filter, k_limit, k_delimit, k_amount, k_special): @api.post("importrules") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def import_rulemodule(**keys): """Internal Use Only""" @@ -697,7 +696,7 @@ def import_rulemodule(**keys): @api.post("rebuild") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def rebuild(**keys): """Internal Use Only""" @@ -773,7 +772,7 @@ def search(**keys): @api.post("newrule") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def newrule(**keys): """Internal Use Only""" @@ -784,21 +783,21 @@ def newrule(**keys): @api.post("settings") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def set_settings(**keys): """Internal Use Only""" malojaconfig.update(keys) @api.post("apikeys") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def set_apikeys(**keys): """Internal Use Only""" apikeystore.update(keys) @api.post("import") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def import_scrobbles(identifier): """Internal Use Only""" @@ -806,7 +805,7 @@ def import_scrobbles(identifier): import_scrobbles(identifier) @api.get("backup") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def get_backup(**keys): """Internal Use Only""" @@ -819,7 +818,7 @@ def get_backup(**keys): return static_file(os.path.basename(archivefile),root=tmpfolder) @api.get("export") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def get_export(**keys): """Internal Use Only""" @@ -833,7 +832,7 @@ def get_export(**keys): @api.post("delete_scrobble") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def delete_scrobble(timestamp): """Internal Use Only""" @@ -845,7 +844,7 @@ def delete_scrobble(timestamp): @api.post("edit_artist") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def edit_artist(id,name): """Internal Use Only""" @@ -855,7 +854,7 @@ def edit_artist(id,name): } @api.post("edit_track") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def edit_track(id,title): """Internal Use Only""" @@ -865,7 +864,7 @@ def edit_track(id,title): } @api.post("edit_album") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def edit_album(id,albumtitle): """Internal Use Only""" @@ -876,7 +875,7 @@ def edit_album(id,albumtitle): @api.post("merge_tracks") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def merge_tracks(target_id,source_ids): """Internal Use Only""" @@ -887,7 +886,7 @@ def merge_tracks(target_id,source_ids): } @api.post("merge_artists") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def merge_artists(target_id,source_ids): """Internal Use Only""" @@ -898,7 +897,7 @@ def merge_artists(target_id,source_ids): } @api.post("merge_albums") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def merge_artists(target_id,source_ids): """Internal Use Only""" @@ -909,7 +908,7 @@ def merge_artists(target_id,source_ids): } @api.post("associate_albums_to_artist") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def associate_albums_to_artist(target_id,source_ids,remove=False): result = database.associate_albums_to_artist(target_id,source_ids,remove=remove) @@ -921,7 +920,7 @@ def associate_albums_to_artist(target_id,source_ids,remove=False): } @api.post("associate_tracks_to_artist") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def associate_tracks_to_artist(target_id,source_ids,remove=False): result = database.associate_tracks_to_artist(target_id,source_ids,remove=remove) @@ -933,7 +932,7 @@ def associate_tracks_to_artist(target_id,source_ids,remove=False): } @api.post("associate_tracks_to_album") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def associate_tracks_to_album(target_id,source_ids): result = database.associate_tracks_to_album(target_id,source_ids) @@ -945,7 +944,7 @@ def associate_tracks_to_album(target_id,source_ids): @api.post("reparse_scrobble") -@authenticated_function(api=True) +@auth.authenticated_function(api=True) @catch_exceptions def reparse_scrobble(timestamp): """Internal Use Only""" diff --git a/maloja/database/__init__.py b/maloja/database/__init__.py index c8cc75d..59a3ed8 100644 --- a/maloja/database/__init__.py +++ b/maloja/database/__init__.py @@ -27,7 +27,6 @@ from . import exceptions # doreah toolkit from doreah.logging import log -from doreah.auth import authenticated_api, authenticated_api_with_alternate import doreah diff --git a/maloja/dev/profiler.py b/maloja/dev/profiler.py index c20db90..49563a4 100644 --- a/maloja/dev/profiler.py +++ b/maloja/dev/profiler.py @@ -1,9 +1,9 @@ import os import cProfile, pstats +import time from doreah.logging import log -from doreah.timing import Clock from ..pkg_global.conf import data_dir @@ -27,8 +27,7 @@ def profile(func): def newfunc(*args,**kwargs): - clock = Clock() - clock.start() + starttime = time.time() if FULL_PROFILE: benchmarkfolder = data_dir['logs']("benchmarks") @@ -44,7 +43,7 @@ def profile(func): if FULL_PROFILE: localprofiler.disable() - seconds = clock.stop() + seconds = time.time() - starttime if not SINGLE_CALLS: times.setdefault(realfunc,[]).append(seconds) diff --git a/maloja/pkg_global/conf.py b/maloja/pkg_global/conf.py index 16b132c..bd152d3 100644 --- a/maloja/pkg_global/conf.py +++ b/maloja/pkg_global/conf.py @@ -1,4 +1,7 @@ import os + +import doreah.auth +import doreah.logging from doreah.configuration import Configuration from doreah.configuration import types as tp @@ -330,26 +333,15 @@ data_dir = { -### DOREAH CONFIGURATION +### DOREAH OBJECTS -from doreah import config - -config( - auth={ - "multiuser":False, - "cookieprefix":"maloja", - "stylesheets":["/maloja.css"], - "dbfile":data_dir['auth']("auth.ddb") - }, - logging={ - "logfolder": data_dir['logs']() if malojaconfig["LOGGING"] else None - }, - regular={ - "offset": malojaconfig["TIMEZONE"] - } -) +auth = doreah.auth.AuthManager(singleuser=True,cookieprefix='maloja',stylesheets=("/maloja.css",),dbfile=data_dir['auth']("auth.sqlite")) +#logger = doreah.logging.Logger(logfolder=data_dir['logs']() if malojaconfig["LOGGING"] else None) +#log = logger.log +# this is not how its supposed to be done, but lets ease the transition +doreah.logging.defaultlogger.logfolder = data_dir['logs']() if malojaconfig["LOGGING"] else None diff --git a/maloja/server.py b/maloja/server.py index a2ff5bc..9090630 100644 --- a/maloja/server.py +++ b/maloja/server.py @@ -12,14 +12,13 @@ from jinja2.exceptions import TemplateNotFound # doreah toolkit from doreah.logging import log -from doreah import auth # rest of the project from . import database from .database.jinjaview import JinjaDBConnection from .images import image_request from .malojauri import uri_to_internal, remove_identical -from .pkg_global.conf import malojaconfig, data_dir +from .pkg_global.conf import malojaconfig, data_dir, auth from .pkg_global import conf from .jinjaenv.context import jinja_environment from .apis import init_apis, apikeystore @@ -97,7 +96,7 @@ aliases = { ### API -auth.authapi.mount(server=webserver) +conf.auth.authapi.mount(server=webserver) init_apis(webserver) # redirects for backwards compatibility @@ -197,7 +196,7 @@ def jinja_page(name): if name in aliases: redirect(aliases[name]) keys = remove_identical(FormsDict.decode(request.query)) - adminmode = request.cookies.get("adminmode") == "true" and auth.check(request) + adminmode = request.cookies.get("adminmode") == "true" and auth.check_request(request) with JinjaDBConnection() as conn: @@ -222,7 +221,7 @@ def jinja_page(name): return res @webserver.route("/") -@auth.authenticated +@auth.authenticated_function() def jinja_page_private(name): return jinja_page(name) diff --git a/maloja/setup.py b/maloja/setup.py index 4aa75dd..a8652f1 100644 --- a/maloja/setup.py +++ b/maloja/setup.py @@ -6,9 +6,8 @@ try: except ImportError: import distutils from doreah.io import col, ask, prompt -from doreah import auth -from .pkg_global.conf import data_dir, dir_settings, malojaconfig +from .pkg_global.conf import data_dir, dir_settings, malojaconfig, auth @@ -67,10 +66,10 @@ def setup(): if forcepassword is not None: # user has specified to force the pw, nothing else matters - auth.defaultuser.setpw(forcepassword) + auth.change_pw(password=forcepassword) print("Password has been set.") - elif auth.defaultuser.checkpw("admin"): - # if the actual pw is admin, it means we've never set this up properly (eg first start after update) + elif auth.still_has_factory_default_user(): + # this means we've never set this up properly (eg first start after update) while True: newpw = prompt("Please set a password for web backend access. Leave this empty to generate a random password.",skip=SKIP,secret=True) if newpw is None: @@ -81,7 +80,7 @@ def setup(): newpw_repeat = prompt("Please type again to confirm.",skip=SKIP,secret=True) if newpw != newpw_repeat: print("Passwords do not match!") else: break - auth.defaultuser.setpw(newpw) + auth.change_pw(password=newpw) except EOFError: print("No user input possible. If you are running inside a container, set the environment variable",col['yellow']("MALOJA_SKIP_SETUP=yes")) diff --git a/pyproject.toml b/pyproject.toml index 3a56757..774afdb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "malojaserver" version = "3.2.2" description = "Self-hosted music scrobble database" readme = "./README.md" -requires-python = ">=3.10" +requires-python = ">=3.11" license = { file="./LICENSE" } authors = [ { name="Johannes Krattenmacher", email="maloja@dev.krateng.ch" } ] @@ -21,7 +21,7 @@ classifiers = [ dependencies = [ "bottle>=0.12.16", "waitress>=2.1.0", - "doreah>=1.9.4, <2", + "doreah>=2.0.0, <3", "nimrodel>=0.8.0", "setproctitle>=1.1.10", #"pyvips>=2.1.16", @@ -31,7 +31,9 @@ dependencies = [ "sqlalchemy>=2.0", "python-datauri>=1.1.0", "requests>=2.27.1", - "setuptools>68.0.0" + "setuptools>68.0.0", + "toml>=0.10.2", + "PyYAML>=6.0.1" ] [project.optional-dependencies] diff --git a/requirements.txt b/requirements.txt index 940b543..c24f84b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ bottle>=0.12.16 waitress>=2.1.0 -doreah>=1.9.4, <2 +doreah>=2.0.0, <3 nimrodel>=0.8.0 setproctitle>=1.1.10 jinja2>=3.0.0 @@ -10,3 +10,5 @@ sqlalchemy>=2.0 python-datauri>=1.1.0 requests>=2.27.1 setuptools>68.0.0 +toml>=0.10.2 +PyYAML>=6.0.1 \ No newline at end of file