HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //opt/moodle-mlbackend-python/moodlemlbackend/webapp/access.py
import os
import re
import hashlib

from functools import wraps

from flask import request


class MoodleMLError(Exception):
    pass


STASH_DIR = os.environ.get('MOODLE_ML_STASH_DIR')

USER_ENV = "MOODLE_MLBACKEND_PYTHON_USERS"
USERS = {}

def _init_users():
    users = os.environ.get(USER_ENV)
    if users is None:
        raise MoodleMLError(f"""

The value of {USER_ENV} environment should be a comma separated list
of colon separated user/password values. Passwords can optionally be
encrypted using the ./gen-passwd tool.

Usernames may not contain ',', ':', or a line break. Encrypted
passwords can contain any character. unencrypted psswords follow the
same rule as usernames.

For example, with {USER_ENV} set to the following value, 'user_1' has
the password 'pa$$word', while user_2 has an encrypted password that
we cannot see:

user_1:pa$$word,user_2:sha256:da243a51bce11bf9083d78da99a2544b:c33487b5ff686cc9e3d088303c08376aa9811a289bad296b11cfb1811b159cfb
""".strip())

    for userpass in users.split(','):
        user, password = userpass.split(':', 1)

        if ':' in password:
            hash_name, salt, password = password.split(':', 2)
            salt = salt.encode('utf8')
            if hash_name not in hashlib.algorithms_available:
                raise MoodleMLError(f"'{hash_name} is not a supported hash")
        else:
            hash_name, salt = None, None

        USERS[user] = (password, hash_name, salt)


_init_users()


def stash_data(*args, **kwargs):
    import pickle, time
    reqdir = os.path.join(STASH_DIR, 'requests')
    os.makedirs(reqdir, exist_ok=True)
    t = time.strftime('%Y-%m-%d-%H-%M-%S-')
    s = os.path.join(reqdir, t + re.sub(r'\W', '_', request.path))
    try:
        f = open(s, 'xb')
    except FileExistsError:
        for i in range(1, 10):
            s2 = f'{s}.{i}'
            try:
                f = open(s2, 'xb')
                break
            except FileExistsError:
                continue

    # filter out sensitive/useless headers
    headers = []
    for h in request.headers.to_wsgi_list():
        if h[0].lower() in {'content-type',
                            'content-length'}:
            headers.append(h)

    r = {
        'url':   request.url,
        'data':  request.get_data(),
        'headers': headers
    }
    pickle.dump(r, f)
    f.close()


def check_access(f):
    '''Checks the access to the route.'''

    @wraps(f)
    def access_wrapper(*args, **kwargs):
        if STASH_DIR is not None:
            stash_data(*args, **kwargs)

        if (request.authorization is None or
            request.authorization.username is None or
            request.authorization.password is None):
            # Response for the client.
            return 'No user and/or password included in the request.', 401

        if request.authorization.username in USERS:
            passwd, hash_fn, salt = USERS[request.authorization.username]

            if hash_fn is None:
                # The old plaintext format
                p = request.authorization.password
            else:
                h = hashlib.new(hash_fn)
                h.update(salt)
                h.update(request.authorization.password.encode('utf-8'))
                p = h.hexdigest()

            if passwd == p:
                # If all good we return the return from 'f' passing the
                # original list of params to it.
                return f(*args, **kwargs)

        # Response for the client.
        return 'Incorrect user and/or password provided by Moodle.', 401

    return access_wrapper