# -*- coding: utf-8 -*-
# vim:fenc=utf-8

# This file is part of the  X2Go Project - https://www.x2go.org
# Copyright (C) 2012-2020 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
#
# X2Go Session Broker 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.
#
# X2Go Session Broker 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, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

# modules
import os

# Python X2Go Broker modules
import x2gobroker.defaults

from x2gobroker.loggers import logger_broker

def _override_do_authenticate(username='', password=''):
    return True

class X2GoBrokerClient(object):
    """\
    Implementation of a command line interface to X2Go Session Broker.
    This CLI can be evoked over an SSH connection. This provides the
    so-called SSH mode for X2Go Session Broker.

    """

    def get(self, args):
        """\

        Analogy to the http request get method of the HTTP X2Go Session
        Broker, this method expects a set of arguments (i.e., an instance
        of :class:``argparse.ArgumentParser``) and process the given
        arguments.

        Well-known arguments are:

          * ``args.user`` - broker user on whose behalf to operate
          * ``args.login`` - X2Go Server user for whom to perform the task
          * ``args.auth_cookie`` - authentication cookie
          * ``args.task`` - broker backend task to perform
          * ``args.profile_id`` - session profile ID

        :param args: an :class:``argparse.ArgumentParser`` object provide by the ``x2gobroker`` command line script
        :type args: ``obj``

        :returns: output as expected by the calling client side
        :rtype: ``str``

        """
        backend = args.backend

        if not backend:
            backend = x2gobroker.defaults.X2GOBROKER_DEFAULT_BACKEND

        # silence pyflakes...
        broker_backend = None
        try:
            # dynamically detect broker backend from given backend
            namespace = {}
            exec("import x2gobroker.brokers.{backend}_broker\nbroker_backend = x2gobroker.brokers.{backend}_broker.X2GoBroker()".format(backend=backend), namespace)
            broker_backend = namespace['broker_backend']
        except ImportError:
            logger_broker.error('unknown backend: {backend}'.format(backend=backend))

        if broker_backend.is_enabled():

            if 'SSH_CLIENT' in os.environ:
                ip = os.environ['SSH_CLIENT'].split()[0]
            else:
                ip = '127.0.0.1'

            if ip:
                logger_broker.info('client address is {address}'.format(address=ip))
                broker_backend.set_client_address(ip)

            broker_username = args.user
            server_username = args.login
            cookie = args.auth_cookie
            task = args.task
            profile_id = args.profile_id

            output = ''

            broker_backend._do_authenticate = _override_do_authenticate

            broker_username, password, task, profile_id, ip, cookie, authed, server = broker_backend.run_optional_script(script_type='pre_auth_scripts', username=broker_username, password="SSH", task=task, profile_id=profile_id, ip=ip, cookie=cookie)
            access, next_cookie = broker_backend.check_access(username=broker_username, ip=ip, cookie=cookie, override_password_auth=True)
            broker_username, password, task, profile_id, ip, cookie, authed, server = broker_backend.run_optional_script(script_type='post_auth_scripts', username=broker_username, password="SSH", task=task, profile_id=profile_id, ip=ip, cookie=cookie, authed=access)

            if access:

                logger_broker.debug ('broker_username: {broker_username}, server_username: {server_username}, task: {task}, profile_id: {profile_id}'.format(broker_username=broker_username, server_username=server_username, task=task, profile_id=profile_id))

                ###
                ### CONFIRM SUCCESSFUL AUTHENTICATION FIRST
                ###
                if next_cookie is not None:
                    output += "AUTHID:{authid}\n".format(authid=next_cookie)

                output += "Access granted\n"

                ###
                ### X2GO BROKER TASKS
                ###

                # FIXME: the ,,testcon'' task can be object to DoS attacks...
                if task == 'testcon':

                    ###
                    ### TEST THE CONNECTION
                    ###

                    return broker_backend.test_connection()

                if task == 'listsessions':

                    profiles = broker_backend.list_profiles(broker_username)
                    if profiles:
                        output += "START_USER_SESSIONS\n\n"
                        profile_ids = list(profiles.keys())
                        profile_ids.sort()
                        for profile_id in profile_ids:
                            output += "[{profile_id}]\n".format(profile_id=profile_id)
                            for key in list(profiles[profile_id].keys()):
                                if key == 'user' and not profiles[profile_id][key]:
                                    profiles[profile_id][key] = server_username
                                if type(profiles[profile_id][key]) == str:
                                    output += "{key}={value}".format(key=key, value=profiles[profile_id][key])
                                elif type(profiles[profile_id][key]) in (list, tuple):
                                    output += "{key}={value}".format(key=key, value=",".join(profiles[profile_id][key]))
                                else:
                                    output += "{key}={value}".format(key=key, value=int(profiles[profile_id][key]))

                                output += "\n"
                            output += "\n"

                        output += "END_USER_SESSIONS\n"

                elif task == 'selectsession':

                    if profile_id:

                        profile_info = broker_backend.select_session(profile_id=profile_id, username=server_username)

                        broker_username, password, task, profile_id, ip, cookie, authed, server = broker_backend.run_optional_script(script_type='select_session_scripts', username=broker_username, password="SSH", task=task, profile_id=profile_id, ip=ip, cookie=cookie, authed=access, server=profile_info['server'])

                        if 'server' in profile_info:
                            output += "SERVER:"
                            output += profile_info['server']
                            if 'port' in profile_info:
                                output += ":{port}".format(port=profile_info['port'])
                            output += "\n"
                            if 'authentication_privkey' in profile_info:
                                output += profile_info['authentication_privkey']
                            if 'session_info' in profile_info:
                                output += "SESSION_INFO:"
                                output += profile_info['session_info'] + "\n"

            else:
                logger_broker.error ('cookie authentication failed')

            return output

        logger_broker.error ('broker backend ,,{backend}\'\' is disabled on this system'.format(backend=backend))
