diff --git a/bin/yunohost-api b/bin/yunohost-api index fe6b00282b..8d6d9128d7 100755 --- a/bin/yunohost-api +++ b/bin/yunohost-api @@ -49,6 +49,14 @@ def _parse_api_args() -> argparse.Namespace: type=int, help="Port to listen on (default: %d)" % DEFAULT_PORT, ) + srv_group.add_argument( + "-s", + "--socket", + action="store", + default=None, + type=str, + help="Socket path to listen on (default is none) without authentication" + ) glob_group = parser.add_argument_group("global arguments") glob_group.add_argument( "--debug", @@ -68,4 +76,4 @@ def _parse_api_args() -> argparse.Namespace: if __name__ == "__main__": opts = _parse_api_args() # Run the server - yunohost.api(debug=opts.debug, host=opts.host, port=opts.port) + yunohost.api(debug=opts.debug, host=opts.host, port=opts.port, socket=opts.socket) diff --git a/share/actionsmap.yml b/share/actionsmap.yml index 73528e4e6b..863ca23be4 100755 --- a/share/actionsmap.yml +++ b/share/actionsmap.yml @@ -37,6 +37,7 @@ _global: authentication: api: ldap_admin cli: null + sockapi: sockapi ############################# # User # diff --git a/src/__init__.py b/src/__init__.py index fa1976724f..565a7b9ae9 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -20,18 +20,20 @@ import os import sys +import argparse import moulinette from moulinette import m18n from moulinette.interfaces.cli import colorize, get_locale from moulinette.utils.log import configure_logging +from moulinette.core import MoulinetteLock -def is_installed(): +def is_installed() -> bool: return os.path.isfile("/etc/yunohost/installed") -def cli(debug, quiet, output_as, timeout, args, parser): +def cli(debug: bool, quiet: bool, output_as: str, timeout: int, args: list[str], parser: argparse.ArgumentParser) -> None: init_logging(interface="cli", debug=debug, quiet=quiet) # Check that YunoHost is installed @@ -49,7 +51,7 @@ def cli(debug, quiet, output_as, timeout, args, parser): sys.exit(ret) -def api(debug, host, port): +def api(debug: bool, host: str, port: int, socket: str | None) -> None: allowed_cors_origins = [] allowed_cors_origins_file = "/etc/yunohost/.admin-api-allowed-cors-origins" @@ -73,10 +75,22 @@ def is_installed_api(): routes={("GET", "/installed"): is_installed_api}, allowed_cors_origins=allowed_cors_origins, ) + if ret: + sys.exit(ret) + + if socket: + ret = moulinette.socket_api( + socket_path=socket, + actionsmap="/usr/share/yunohost/actionsmap.yml", + locales_dir="/usr/share/yunohost/locales/", + routes={("GET", "/installed"): is_installed_api}, + allowed_cors_origins=allowed_cors_origins, + ) + sys.exit(ret) -def portalapi(debug, host, port): +def portalapi(debug: bool, host: str, port: int) -> None: allowed_cors_origins = [] allowed_cors_origins_file = "/etc/yunohost/.portal-api-allowed-cors-origins" @@ -97,7 +111,7 @@ def portalapi(debug, host, port): sys.exit(ret) -def check_command_is_valid_before_postinstall(args): +def check_command_is_valid_before_postinstall(args: list[str]) -> None: allowed_if_not_postinstalled = [ "tools postinstall", "tools versions", @@ -113,28 +127,26 @@ def check_command_is_valid_before_postinstall(args): sys.exit(1) -def init(interface="cli", debug=False, quiet=False, logdir="/var/log/yunohost"): +def init(interface: str = "cli", debug: bool = False, quiet: bool = False, logdir: str = "/var/log/yunohost") -> MoulinetteLock: """ This is a small util function ONLY meant to be used to initialize a Yunohost context when ran from tests or from scripts. """ init_logging(interface=interface, debug=debug, quiet=quiet, logdir=logdir) init_i18n() - from moulinette.core import MoulinetteLock - lock = MoulinetteLock("yunohost", timeout=30) lock.acquire() return lock -def init_i18n(): +def init_i18n() -> None: # This should only be called when not willing to go through moulinette.cli # or moulinette.api but still willing to call m18n.n/g... m18n.set_locales_dir("/usr/share/yunohost/locales/") m18n.set_locale(get_locale()) -def init_logging(interface="cli", debug=False, quiet=False, logdir="/var/log/yunohost"): +def init_logging(interface: str = "cli", debug: bool = False, quiet: bool = False, logdir: str = "/var/log/yunohost") -> None: logfile = os.path.join(logdir, "yunohost-%s.log" % interface) if not os.path.isdir(logdir): diff --git a/src/authenticators/sockapi.py b/src/authenticators/sockapi.py new file mode 100644 index 0000000000..cb830f2c4f --- /dev/null +++ b/src/authenticators/sockapi.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2024 YunoHost Contributors +# +# This file is part of YunoHost (see https://yunohost.org) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +from moulinette.authentication import BaseAuthenticator + + +class Authenticator(BaseAuthenticator): + name = "sockapi" + + def __init__(self, *args, **kwargs): + pass + + def _authenticate_credentials(self, credentials=None): + return {"user": 0} + + def set_session_cookie(self, infos): + pass + + def get_session_cookie(self, raise_if_no_session_exists=True): + return {"id": "pouetpouet"} + + def delete_session_cookie(self): + pass + + @staticmethod + def invalidate_all_sessions_for_user(user): + pass