summaryrefslogtreecommitdiff
path: root/server/web.py
blob: 2cc4c3bc643dcbe1cc51e2e958f8c9424b098673 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
'''
    Handles everything related to the GUI,
    exposing the necessary functionality.
    Taking care of logging & middleware.

    Verified: 2021 February 8
    * Follows PEP8
    * Tested Platforms
        * Windows 10
    * Third Party Modules
        * eel
'''

from server.state import ServerStatic, Dynamic
from server.helper import ServerHelper
from server.settings import Settings
from server.error import ServerError
from server.console import Console
from shared.helper import Helper
from shared.state import Static

import traceback
import bottle
import eel


class Web:

    @staticmethod
    @eel.expose
    def clients_eel():
        return [[key, value.data] for key, value
                in Dynamic.CLIENTS.items()]

    @staticmethod
    @eel.expose
    def session_eel():
        return list(Dynamic.SESSION)

    @staticmethod
    @eel.expose
    def help_eel():
        return ServerStatic.GUI_HELP

    @staticmethod
    @eel.expose
    def host_eel():
        return ServerStatic.HOST


class Gui:

    @staticmethod
    @ServerError.thread
    def start():
        eel.init(ServerStatic.GUI_DIR)

        if ServerStatic.WEB_GUI:
            Gui.__execute_start(False)
        else:
            try:
                Gui.__execute_start('chrome')
            except EnvironmentError:
                Console.log(traceback.format_exc(),
                            log_type=ServerStatic.TRACEBACK)

                Console.printf(Helper.join(
                    'Chrome browser is not installed',
                    'Converting to web GUI instance'
                ), Static.INFO, newline=True)

                ServerStatic.WEB_GUI = True
                Gui.__execute_start(False)

    @staticmethod
    def __execute_start(mode):
        eel.start(ServerStatic.GUI_PAGE,
                  mode=mode,
                  host=Static.IP,
                  port=ServerStatic.GUI_PORT,
                  app=Gui.__load_middleware(),
                  size=ServerStatic.WINDOW_SIZE,
                  close_callback=lambda *_: None)

    @staticmethod
    def __load_middleware():
        bottle_instance = bottle.default_app()
        bottle_instance.install(Middleware.verify)
        bottle_instance.install(bottle.auth_basic(Middleware.login))

        # CONSTANT : logout path is GUI dependant
        @bottle_instance.route('/logout')
        def _(): bottle.abort(401, 'Access denied')

        return bottle_instance


class Middleware:

    __IP_PROXY = ('REMOTE_ADDR',
                  'HTTP_X_FORWARDED_FOR')

    @staticmethod
    def verify(callback):
        def wrapper(*args, **kwargs):
            if Settings.GUI_WHITELIST:
                normal, proxy = ServerHelper.keys(bottle.request.environ,
                                                  Middleware.__IP_PROXY)
                gui_whitelist = Settings.GUI_WHITELIST.split(',')

                if normal in gui_whitelist or proxy in gui_whitelist:
                    return callback(*args, **kwargs)
                else:
                    Console.log('Blocked: {} [{}/{}]\n'.format(
                        bottle.request.url, normal, proxy
                    ), Static.DANGER, ServerStatic.HTTP)

                    bottle.abort(401, 'Access denied')
            else:
                return callback(*args, **kwargs)

        return wrapper

    @staticmethod
    def login(username, password):
        if (username == Settings.GUI_USERNAME and
                password == Settings.GUI_PASSWORD):
            Middleware.__resource(True)
            return True
        else:
            Middleware.__resource(False)
            return False

    @staticmethod
    def __resource(success):
        Console.log('Resource Request: {} [{}/{}]\n'.format(
            bottle.request.url, *ServerHelper.keys(bottle.request.environ,
                                                   Middleware.__IP_PROXY)
        ), Static.SUCCESS if success else Static.DANGER, ServerStatic.HTTP)