ns2 0.2.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ns2/__init__.py +0 -0
- ns2/core.py +0 -0
- ns2/dbus/__init__.py +0 -0
- ns2/dbus/dbus.py +13 -0
- ns2/lib/__init__.py +0 -0
- ns2/lib/accounts.py +130 -0
- ns2/lib/commands.py +32 -0
- ns2/lib/firewalld.py +167 -0
- ns2/lib/introspection/org.fedoraproject.FirewallD1.config.xml +3 -0
- ns2/lib/introspection/org.fedoraproject.FirewallD1.xml +763 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.AccessPoint.xml +106 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.AgentManager.xml +43 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Checkpoint.xml +36 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Connection.Active.xml +185 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.DHCP4Config.xml +21 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.DHCP6Config.xml +20 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Adsl.xml +21 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Bluetooth.xml +36 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Bond.xml +40 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Bridge.xml +41 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Dummy.xml +20 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Generic.xml +27 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Hsr.xml +51 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.IPTunnel.xml +107 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Infiniband.xml +31 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Ipvlan.xml +38 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Loopback.xml +8 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Lowpan.xml +27 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Macsec.xml +109 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Macvlan.xml +39 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Modem.xml +62 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.xml +34 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.OvsBridge.xml +21 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.OvsInterface.xml +11 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.OvsPort.xml +21 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Ppp.xml +11 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Statistics.xml +35 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Team.xml +48 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Tun.xml +65 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Veth.xml +18 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Vlan.xml +45 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Vrf.xml +18 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Vxlan.xml +139 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.WiMax.xml +109 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.WifiP2P.xml +76 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.WireGuard.xml +38 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Wired.xml +53 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Wireless.xml +131 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Wpan.xml +20 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.xml +407 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.DnsManager.xml +40 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.IP4Config.xml +125 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.IP6Config.xml +95 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.PPP.xml +34 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.SecretAgent.xml +94 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Settings.Connection.xml +224 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Settings.xml +233 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.VPN.Connection.xml +42 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.VPN.Plugin.xml +204 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.WiMax.Nsp.xml +35 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.WifiP2PPeer.xml +91 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.xml +598 -0
- ns2/lib/lib.py +0 -0
- ns2/lib/network_delay.py +92 -0
- ns2/lib/networking.py +528 -0
- ns2/lib/ntl.py +188 -0
- ns2/lib/pam_client.py +37 -0
- ns2/lib/ping_data_collector.py +37 -0
- ns2/lib/snmp.py +511 -0
- ns2/lib/socket.py +132 -0
- ns2/lib/socket_client.py +62 -0
- ns2/lib/systemd.py +151 -0
- ns2/lib/test.py +374 -0
- ns2/lib/udp_client.py +227 -0
- ns2/lib/udp_server.py +167 -0
- ns2/snmp/__init__.py +0 -0
- ns2/snmp/ns_dbus_service.py +38 -0
- ns2/snmp/pam_interface.py +19 -0
- ns2/snmp/snmp_interface.py +66 -0
- ns2/ui/__init__.py +0 -0
- ns2/ui/assets/NOVUS_LOGO.svg +105 -0
- ns2/ui/assets/favicon.png +0 -0
- ns2/ui/firewalld_page.py +375 -0
- ns2/ui/fpga_page.py +24 -0
- ns2/ui/login.py +65 -0
- ns2/ui/main.py +200 -0
- ns2/ui/networking_page.py +406 -0
- ns2/ui/ntp.py +105 -0
- ns2/ui/root.py +31 -0
- ns2/ui/snmp_page.py +353 -0
- ns2/ui/terminal.py +65 -0
- ns2/ui/tests_page.py +116 -0
- ns2/ui/theme.py +25 -0
- ns2/utils.py +5 -0
- ns2-0.2.6.dist-info/METADATA +78 -0
- ns2-0.2.6.dist-info/RECORD +98 -0
- ns2-0.2.6.dist-info/WHEEL +4 -0
- ns2-0.2.6.dist-info/entry_points.txt +3 -0
ns2/ui/firewalld_page.py
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
from nicegui import ui, app, binding
|
|
2
|
+
from ns.lib.networking import *
|
|
3
|
+
from ns.lib.firewalld import *
|
|
4
|
+
from dbus_next.signature import Variant
|
|
5
|
+
from dbus_next.errors import DBusError
|
|
6
|
+
from dbus_next.aio.proxy_object import ProxyInterface
|
|
7
|
+
from ns.dbus import dbus
|
|
8
|
+
|
|
9
|
+
from ns.lib.systemd import *
|
|
10
|
+
|
|
11
|
+
async def interface_list(checks: dict):
|
|
12
|
+
for i in await GetInterfaces(dbus.AppBus):
|
|
13
|
+
checks[i] = False
|
|
14
|
+
ui.checkbox(i).props("flat color=accent align=left").bind_value(checks, i)
|
|
15
|
+
|
|
16
|
+
async def service_list(services: dict):
|
|
17
|
+
for s in await getServices(dbus.AppBus):
|
|
18
|
+
with ui.row():
|
|
19
|
+
ui.checkbox(s).props("flat color=accent align=left").bind_value(services, s)
|
|
20
|
+
|
|
21
|
+
with ui.column():
|
|
22
|
+
ui.label().bind_text_from(s, "UDP")
|
|
23
|
+
ui.label().bind_text_from(s, "TCP")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@ui.refreshable
|
|
27
|
+
async def firewall_status(on_network_page: bool):
|
|
28
|
+
|
|
29
|
+
firewall = Firewall()
|
|
30
|
+
firewall.Enable = await isActive(dbus.AppBus, 'firewalld.service')
|
|
31
|
+
firewall.Status = (await getServiceState(dbus.AppBus, "firewalld.service")).capitalize()
|
|
32
|
+
numActiveZones = 0
|
|
33
|
+
if firewall.Enable:
|
|
34
|
+
zone = await GetFirewalldZone(dbus.AppBus)
|
|
35
|
+
numActiveZones = len(await zone.call_get_active_zones())
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
with ui.column().classes("w-full"):
|
|
39
|
+
with ui.row().classes("w-full items-center justify-between"):
|
|
40
|
+
with ui.row().classes( "items-center"):
|
|
41
|
+
ui.label("Firewall").classes("text-h6")
|
|
42
|
+
if on_network_page:
|
|
43
|
+
ui.link(f'{numActiveZones} active zones', '/networking/firewall').classes('text-accent')
|
|
44
|
+
|
|
45
|
+
async def fire_switch_cb(e):
|
|
46
|
+
action = "enable" if e.sender.value else "disable"
|
|
47
|
+
with ui.dialog() as dialog, ui.card():
|
|
48
|
+
ui.label(f'Are you sure you want to {action} firewalld?')
|
|
49
|
+
with ui.row():
|
|
50
|
+
ui.button('Cancel', on_click=lambda: dialog.submit("Cancel")).props("flat color=accent align=left")
|
|
51
|
+
ui.button(f'{action}', on_click=lambda: dialog.submit(action)).props("flat color=accent align=left")
|
|
52
|
+
result = await dialog
|
|
53
|
+
active = await isActive(dbus.AppBus, "firewalld.service")
|
|
54
|
+
if result == "enable" and not active:
|
|
55
|
+
await systemd_start(dbus.AppBus, "firewalld.service")
|
|
56
|
+
if result == "disable" and active:
|
|
57
|
+
await systemd_stop(dbus.AppBus, "firewalld.service")
|
|
58
|
+
await firewall_status.refresh()
|
|
59
|
+
|
|
60
|
+
ui.switch(f"Status: {firewall.Status}").on('click', lambda e: fire_switch_cb(e)
|
|
61
|
+
).props("flat color=accent align=left dense").bind_value(firewall, "Enable").bind_text
|
|
62
|
+
|
|
63
|
+
if on_network_page:
|
|
64
|
+
ui.button("Edit rules and zones", on_click=lambda e: ui.navigate.to('/networking/firewall')).props("flat color=accent align=left dense")
|
|
65
|
+
|
|
66
|
+
else:
|
|
67
|
+
zoneDialog = await addZoneDialog()
|
|
68
|
+
ui.button("add new zone", on_click=zoneDialog.open).props("color=accent align=left")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def InterfaceText(zoneSettings :ZoneSetting):
|
|
77
|
+
interfaces = zoneSettings.Interfaces
|
|
78
|
+
if len(interfaces) == 1:
|
|
79
|
+
l1 = ui.label("Interface:").classes("font-bold")
|
|
80
|
+
else:
|
|
81
|
+
l1= ui.label("Interfaces:").classes("font-bold")
|
|
82
|
+
l2 = ui.label(formatListToString(interfaces))
|
|
83
|
+
return (l1, l2)
|
|
84
|
+
|
|
85
|
+
def AllowedAddressText(zoneSettings :ZoneSetting):
|
|
86
|
+
sources = zoneSettings.Sources
|
|
87
|
+
l1 = ui.label("Allowed Addresses:").classes("font-bold")
|
|
88
|
+
if len(sources) == 0:
|
|
89
|
+
l2 = ui.label("Entire subnet")
|
|
90
|
+
else:
|
|
91
|
+
l2 = ui.label(formatListToString(sources))
|
|
92
|
+
return (l1, l2)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
async def removeServiceFromZone(zoneName: str, serviceName:str):
|
|
98
|
+
|
|
99
|
+
print(f'remove {serviceName} from {zoneName}')
|
|
100
|
+
zone = await GetFirewalldZone(dbus.AppBus)
|
|
101
|
+
|
|
102
|
+
res = await zone.call_remove_service(zoneName, serviceName)
|
|
103
|
+
print("res1: ", res)
|
|
104
|
+
conf = await GetFirewalldConfig(dbus.AppBus)
|
|
105
|
+
|
|
106
|
+
p = await conf.call_get_zone_by_name(zoneName)
|
|
107
|
+
|
|
108
|
+
print(p)
|
|
109
|
+
|
|
110
|
+
configZone = await GetFirewalldConfigZone(dbus.AppBus, p)
|
|
111
|
+
res = await configZone.call_remove_service(serviceName)
|
|
112
|
+
print(res)
|
|
113
|
+
return
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
async def addZoneDialog():
|
|
118
|
+
with ui.dialog() as dialog:
|
|
119
|
+
with ui.card().props('flat'):
|
|
120
|
+
ui.label("Add zone").classes("text-h5")
|
|
121
|
+
ui.label("Interfaces").classes("text-h6")
|
|
122
|
+
|
|
123
|
+
with ui.row():
|
|
124
|
+
checks = {}
|
|
125
|
+
await interface_list(checks)
|
|
126
|
+
|
|
127
|
+
#selectedServices = ui.input_chips('Allowed services', new_value_mode='add-unique', clearable=True).props('disable-input')
|
|
128
|
+
with ui.scroll_area():
|
|
129
|
+
services = formatServicesInRows(await getServices(dbus.AppBus))
|
|
130
|
+
services_table = ui.table(
|
|
131
|
+
rows=services,
|
|
132
|
+
column_defaults={
|
|
133
|
+
"align": "left",
|
|
134
|
+
"headerClasses": "uppercase text-primary",
|
|
135
|
+
},
|
|
136
|
+
row_key='Service',
|
|
137
|
+
selection='multiple',
|
|
138
|
+
#on_select=lambda e: print(f'selected: {e.selection}'),
|
|
139
|
+
).props('dense')
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
services_table.props(f'visible-columns=["Service","UDP","TCP"]')
|
|
144
|
+
#
|
|
145
|
+
services_table.add_slot('header', r'''
|
|
146
|
+
<q-tr :props="props">
|
|
147
|
+
<q-th auto-width />
|
|
148
|
+
<q-th auto-width />
|
|
149
|
+
|
|
150
|
+
<q-th v-for="col in props.cols" :key="col.name" :props="props"> {{ col.label }} </q-th>
|
|
151
|
+
</q-tr>
|
|
152
|
+
''')
|
|
153
|
+
#
|
|
154
|
+
services_table.add_slot('body', r'''
|
|
155
|
+
<q-tr :props="props">
|
|
156
|
+
<!-- selection checkbox -->
|
|
157
|
+
<q-td auto-width>
|
|
158
|
+
<q-checkbox
|
|
159
|
+
:model-value="props.selected"
|
|
160
|
+
@update:model-value="props.selected = !props.selected"
|
|
161
|
+
color="accent"
|
|
162
|
+
dense
|
|
163
|
+
/>
|
|
164
|
+
</q-td>
|
|
165
|
+
|
|
166
|
+
<!-- expand button -->
|
|
167
|
+
<q-td auto-width @click.stop="">
|
|
168
|
+
<q-btn size="sm" color="accent" round dense
|
|
169
|
+
@click="props.expand = !props.expand"
|
|
170
|
+
:icon="props.expand ? 'remove' : 'add'" />
|
|
171
|
+
</q-td>
|
|
172
|
+
<!-- normal columns -->
|
|
173
|
+
<q-td v-for="col in props.cols" :key="col.name" :props="props"
|
|
174
|
+
style="white-space: normal; word-wrap: break-word; overflow-wrap: break-word; max-width: 200px;">
|
|
175
|
+
{{ col.value }}
|
|
176
|
+
</q-td>
|
|
177
|
+
</q-tr>
|
|
178
|
+
<!-- expanded description -->
|
|
179
|
+
<q-tr v-show="props.expand" :props="props">
|
|
180
|
+
<q-td colspan="100%" style="max-width: 0;">
|
|
181
|
+
<div class="text-left"
|
|
182
|
+
style="word-wrap: break-word; overflow-wrap: break-word; white-space: normal;">
|
|
183
|
+
{{ props.row.Description }}
|
|
184
|
+
</div>
|
|
185
|
+
</q-td>
|
|
186
|
+
</q-tr>
|
|
187
|
+
''')
|
|
188
|
+
#
|
|
189
|
+
serviceFilter = ui.input('Search for services').bind_value(services_table, "filter")
|
|
190
|
+
|
|
191
|
+
def on_save_cb():
|
|
192
|
+
for c,v in checks.items():
|
|
193
|
+
print(c, v)
|
|
194
|
+
|
|
195
|
+
# Get selected services when saving
|
|
196
|
+
selected = [row['Service'] for row in services if row.get('Select', False)]
|
|
197
|
+
print(f"Selected services: {selected}")
|
|
198
|
+
|
|
199
|
+
with ui.row():
|
|
200
|
+
ui.button('Add zone', on_click=on_save_cb).props("color=accent align=left")
|
|
201
|
+
ui.button('Cancel', on_click=dialog.close).props("flat color=accent align=left")
|
|
202
|
+
|
|
203
|
+
return dialog
|
|
204
|
+
|
|
205
|
+
async def addServiceDialog():
|
|
206
|
+
with ui.dialog() as dialog:
|
|
207
|
+
with ui.card():
|
|
208
|
+
ui.label("nothing")
|
|
209
|
+
ui.button('close', on_click=dialog.close)
|
|
210
|
+
|
|
211
|
+
return dialog
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
async def zone_list(firewall):
|
|
219
|
+
with ui.column():
|
|
220
|
+
for zoneName, zoneSetting in firewall.ZoneSettings.items():
|
|
221
|
+
with ui.card().classes("w-full").props('flat').classes("bg-secondary"):
|
|
222
|
+
with ui.column():
|
|
223
|
+
with ui.row().classes("w-full items-baseline justify-between"):
|
|
224
|
+
with ui.row().classes("items-baseline"):
|
|
225
|
+
ui.label(f'{zoneName.capitalize()} zone')
|
|
226
|
+
InterfaceText(zoneSetting)
|
|
227
|
+
|
|
228
|
+
with ui.row():
|
|
229
|
+
AllowedAddressText(zoneSetting)
|
|
230
|
+
|
|
231
|
+
with ui.row():
|
|
232
|
+
addDialog = await addServiceDialog()
|
|
233
|
+
ui.button("add services", on_click=addDialog.open).props("color=accent align=left")
|
|
234
|
+
ui.button(icon="more_vert").props("flat color=accent align=left")
|
|
235
|
+
|
|
236
|
+
services = formatServicesInRows(firewall.ZoneSettings[zoneName].ServiceSettings)
|
|
237
|
+
|
|
238
|
+
service_table = ui.table(
|
|
239
|
+
rows=services,
|
|
240
|
+
column_defaults={
|
|
241
|
+
"align": "left",
|
|
242
|
+
"headerClasses": "uppercase text-primary",
|
|
243
|
+
},
|
|
244
|
+
row_key='Service'
|
|
245
|
+
).props("flat")
|
|
246
|
+
service_table.props(f'visible-columns={"Service,UDP,TCP"}') # Only show these
|
|
247
|
+
|
|
248
|
+
service_table.add_slot('header', r'''
|
|
249
|
+
<q-tr :props="props">
|
|
250
|
+
<q-th auto-width />
|
|
251
|
+
<q-th v-for="col in props.cols" :key="col.name" :props="props"> {{ col.label }} </q-th>
|
|
252
|
+
<q-th auto-width />
|
|
253
|
+
</q-tr>
|
|
254
|
+
''')
|
|
255
|
+
|
|
256
|
+
async def handle_remove_service(e, zone=zoneName):
|
|
257
|
+
await removeServiceFromZone(zone, e.args)
|
|
258
|
+
|
|
259
|
+
service_table.on('remove-service', handle_remove_service)
|
|
260
|
+
|
|
261
|
+
service_table.add_slot('body', r'''
|
|
262
|
+
<q-tr :props="props">
|
|
263
|
+
<!-- expand button -->
|
|
264
|
+
<q-td auto-width>
|
|
265
|
+
<q-btn size="sm" color="accent" round dense @click="props.expand = !props.expand" :icon="props.expand ? 'remove' : 'add'" />
|
|
266
|
+
</q-td>
|
|
267
|
+
<!-- normal columns -->
|
|
268
|
+
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
|
269
|
+
{{ col.value }}
|
|
270
|
+
</q-td>
|
|
271
|
+
<!-- 3-dot menu -->
|
|
272
|
+
<q-td auto-width>
|
|
273
|
+
<q-btn flat round dense icon="more_vert" color="accent">
|
|
274
|
+
<q-menu auto-close>
|
|
275
|
+
<q-list style="min-width: 150px">
|
|
276
|
+
<q-item clickable
|
|
277
|
+
@click="$parent.$emit('remove-service', props.row.Service)">
|
|
278
|
+
<q-item-section class="text-negative">
|
|
279
|
+
Delete
|
|
280
|
+
</q-item-section>
|
|
281
|
+
</q-item>
|
|
282
|
+
</q-list>
|
|
283
|
+
</q-menu>
|
|
284
|
+
</q-btn>
|
|
285
|
+
</q-td>
|
|
286
|
+
</q-tr>
|
|
287
|
+
<!-- expanded description -->
|
|
288
|
+
<q-tr v-show="props.expand" :props="props">
|
|
289
|
+
<q-td colspan="100%" style="max-width: 0;">
|
|
290
|
+
<div class="text-left"
|
|
291
|
+
style="word-wrap: break-word; overflow-wrap: break-word; white-space: normal;">
|
|
292
|
+
{{ props.row.Description }}
|
|
293
|
+
</div>
|
|
294
|
+
</q-td>
|
|
295
|
+
</q-tr>
|
|
296
|
+
''')
|
|
297
|
+
|
|
298
|
+
pass # end of this...
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
@ui.refreshable
|
|
304
|
+
async def firewall_table():
|
|
305
|
+
|
|
306
|
+
firewall = Firewall()
|
|
307
|
+
#fire = await GetFirewall(dbus.AppBus)
|
|
308
|
+
firewall.Enable = await isActive(dbus.AppBus, "firewalld.service")
|
|
309
|
+
firewall.Status = (await getServiceState(dbus.AppBus, "firewalld.service")).capitalize()
|
|
310
|
+
|
|
311
|
+
if firewall.Enable:
|
|
312
|
+
fire = await GetFirewalld(dbus.AppBus)
|
|
313
|
+
zone = await GetFirewalldZone(dbus.AppBus)
|
|
314
|
+
firewall.ActiveZones = await zone.call_get_active_zones()
|
|
315
|
+
|
|
316
|
+
for az in firewall.ActiveZones:
|
|
317
|
+
|
|
318
|
+
zs = ZoneSetting()
|
|
319
|
+
|
|
320
|
+
zoneSettings = await zone.call_get_zone_settings2(az)
|
|
321
|
+
|
|
322
|
+
zs.Description = zoneSettings.get('description', Variant('s', 'description not available')).value
|
|
323
|
+
zs.Interfaces = zoneSettings.get('interfaces', Variant('as', [])).value
|
|
324
|
+
zs.Services = zoneSettings.get('services', Variant('as', [])).value
|
|
325
|
+
zs.Short = zoneSettings.get('short', Variant('s', 'short not available')).value
|
|
326
|
+
zs.Sources = zoneSettings.get('sources', Variant('as', [])).value
|
|
327
|
+
|
|
328
|
+
for s in zs.Services:
|
|
329
|
+
serSet = ServiceSetting()
|
|
330
|
+
serviceSettings = await fire.call_get_service_settings2(s)
|
|
331
|
+
|
|
332
|
+
includes = serviceSettings.get('includes', False)
|
|
333
|
+
if includes:
|
|
334
|
+
for i in includes.value:
|
|
335
|
+
ser_set = await fire.call_get_service_settings2(i)
|
|
336
|
+
serSet.Ports.extend(ser_set.get('ports', Variant('a(ss)', [['port not available', 'protocol not available']])).value)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
serSet.Name = serviceSettings.get('short', Variant('s', 'name not available')).value
|
|
340
|
+
serSet.Ports.extend(serviceSettings.get('ports', Variant('a(ss)', [['port not available', 'protocol not available']])).value)
|
|
341
|
+
serSet.Description = serviceSettings.get('description', Variant('s', 'Description not available')).value
|
|
342
|
+
zs.ServiceSettings[s] = serSet
|
|
343
|
+
#pprint(service_settings)
|
|
344
|
+
|
|
345
|
+
firewall.ZoneSettings[az] = zs
|
|
346
|
+
|
|
347
|
+
await zone_list(firewall)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
#def daemon_cb(mystr):
|
|
360
|
+
# print(mystr)
|
|
361
|
+
# firewall_table.refresh()
|
|
362
|
+
|
|
363
|
+
async def firewall_page():
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
#fire = await GetFirewall(dbus.AppBus)
|
|
367
|
+
#fire.on_daemon_changed(daemon_cb)
|
|
368
|
+
|
|
369
|
+
with ui.card():
|
|
370
|
+
with ui.row():
|
|
371
|
+
ui.link("Networking", "/networking").classes('text-accent')
|
|
372
|
+
ui.label(">")
|
|
373
|
+
ui.label('firewall')
|
|
374
|
+
await firewall_status(False)
|
|
375
|
+
await firewall_table()
|
ns2/ui/fpga_page.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from nicegui import ui, app, background_tasks, events
|
|
3
|
+
from ns.lib.commands import runAsyncCmd
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def fpga_page():
|
|
8
|
+
with ui.column() as pageContainer:
|
|
9
|
+
ui.label("FPGA Bitstream flasher").classes("text-h5")
|
|
10
|
+
with ui.row():
|
|
11
|
+
|
|
12
|
+
with ui.card():
|
|
13
|
+
async def handle_upload(e: events.UploadEventArguments):
|
|
14
|
+
ui.notify(f'Uploaded {e.file.name}', type='positive')
|
|
15
|
+
file_path = os.path.join("bitstreams", e.file.name)
|
|
16
|
+
await e.file.save(file_path)
|
|
17
|
+
|
|
18
|
+
res = await runAsyncCmd(["sudo", "xc3sprog", "-c", "ftdi", file_path])
|
|
19
|
+
ui.notify(f'Flashed {res}', type='positive')
|
|
20
|
+
|
|
21
|
+
ui.upload(label="FPGA Config Upload", on_upload=handle_upload).props("flat color=accent")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
ns2/ui/login.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
from nicegui import ui, app
|
|
3
|
+
|
|
4
|
+
from ns.ui.theme import init_colors
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
import pam
|
|
8
|
+
import os
|
|
9
|
+
from ns.utils import ASSETS_DIR
|
|
10
|
+
p = pam.pam()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
async def try_login(_username: str, _password: str) -> None:
|
|
15
|
+
|
|
16
|
+
if p.authenticate(_username, _password):
|
|
17
|
+
app.storage.user.update(
|
|
18
|
+
{
|
|
19
|
+
"username": _username,
|
|
20
|
+
"authenticated": True,
|
|
21
|
+
#"token": response["token"],
|
|
22
|
+
"login_time": time.time()
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
ui.notify(f"Welcome, {_username}!", color="positive")
|
|
26
|
+
ui.navigate.to("/root")
|
|
27
|
+
else:
|
|
28
|
+
ui.notify("Invalid username or password", color="negative")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@ui.page("/login")
|
|
32
|
+
def login_page():
|
|
33
|
+
init_colors()
|
|
34
|
+
|
|
35
|
+
with ui.dialog() as support_dialog, ui.card():
|
|
36
|
+
ui.label("Novus Power Products").classes("text-h5")
|
|
37
|
+
ui.label("novuspower.com")
|
|
38
|
+
ui.label("(816) 836-7446")
|
|
39
|
+
ui.label("support@novuspower.com")
|
|
40
|
+
ui.label(
|
|
41
|
+
"You can reset the administrator password using the maintenance port on the front of the unit: ns resetpw"
|
|
42
|
+
)
|
|
43
|
+
ui.button("Close", on_click=support_dialog.close).classes("bg-secondary")
|
|
44
|
+
|
|
45
|
+
with ui.column(align_items="center").classes("absolute-center gap-16"):
|
|
46
|
+
print(str(ASSETS_DIR / "NOVUS_LOGO.svg"))
|
|
47
|
+
ui.image(str(ASSETS_DIR / "NOVUS_LOGO.svg")).classes("w-128 max-w-128")
|
|
48
|
+
|
|
49
|
+
with ui.card():
|
|
50
|
+
username = ui.input("Username")
|
|
51
|
+
password = ui.input("Password", password=True, password_toggle_button=True)
|
|
52
|
+
|
|
53
|
+
async def on_login():
|
|
54
|
+
await try_login(username.value, password.value)
|
|
55
|
+
|
|
56
|
+
username.on("keydown.enter", on_login)
|
|
57
|
+
password.on("keydown.enter", on_login)
|
|
58
|
+
|
|
59
|
+
with ui.row():
|
|
60
|
+
ui.button("Log in", on_click=on_login).classes("bg-secondary")
|
|
61
|
+
|
|
62
|
+
ui.button(
|
|
63
|
+
"Support",
|
|
64
|
+
on_click=support_dialog.open,
|
|
65
|
+
).classes("bg-secondary")
|
ns2/ui/main.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
import sys
|
|
4
|
+
from nicegui import ui, app
|
|
5
|
+
from multiprocessing import freeze_support
|
|
6
|
+
|
|
7
|
+
from ns.lib.accounts import accounts_page, accounts_user_page
|
|
8
|
+
from ns.lib.socket import socket_stream
|
|
9
|
+
|
|
10
|
+
from ns.ui.networking_page import network_page, interface_page
|
|
11
|
+
from ns.ui.terminal import terminal_page
|
|
12
|
+
from ns.ui.theme import init_colors
|
|
13
|
+
from ns.ui.login import login_page
|
|
14
|
+
from ns.ui.root import root_page
|
|
15
|
+
from ns.ui.snmp_page import snmp_page, snmp_user_page
|
|
16
|
+
from ns.ui.ntp import ntp_page
|
|
17
|
+
from ns.ui.fpga_page import fpga_page
|
|
18
|
+
from ns.ui.tests_page import tests_page
|
|
19
|
+
from ns.dbus import dbus
|
|
20
|
+
from ns.ui.firewalld_page import firewall_page
|
|
21
|
+
from ns.utils import ASSETS_DIR
|
|
22
|
+
#
|
|
23
|
+
production = False
|
|
24
|
+
|
|
25
|
+
version = '0.0.1'
|
|
26
|
+
|
|
27
|
+
sock_task = None
|
|
28
|
+
|
|
29
|
+
def main():
|
|
30
|
+
freeze_support()
|
|
31
|
+
|
|
32
|
+
@ui.page('/networking')
|
|
33
|
+
@ui.page('/networking/firewall')
|
|
34
|
+
@ui.page('/networking/{interface_name}')
|
|
35
|
+
|
|
36
|
+
@ui.page('/snmp')
|
|
37
|
+
@ui.page('/snmp/{version}/{user}')
|
|
38
|
+
|
|
39
|
+
@ui.page('/terminal')
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
#@ui.page('/ntp')
|
|
43
|
+
@ui.page('/accounts')
|
|
44
|
+
@ui.page('/accounts/{user}')
|
|
45
|
+
#@ui.page('/fpga')
|
|
46
|
+
#@ui.page('/tests')
|
|
47
|
+
@ui.page('/')
|
|
48
|
+
|
|
49
|
+
@ui.page('/root')
|
|
50
|
+
async def root():
|
|
51
|
+
|
|
52
|
+
init_colors()
|
|
53
|
+
if not app.storage.user.get("authenticated", False):
|
|
54
|
+
ui.navigate.to("/login")
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
with ui.header().classes("items-center justify-between").classes("bg-dark"):
|
|
59
|
+
ui.button(on_click=lambda: left_drawer.toggle(), icon="menu").props(
|
|
60
|
+
"flat color=white"
|
|
61
|
+
)
|
|
62
|
+
ui.image(str(ASSETS_DIR / "NOVUS_LOGO.svg")).classes("w-48")
|
|
63
|
+
ui.label(f'Welcome {app.storage.user["username"]}!')
|
|
64
|
+
#ui.button("Request Admin").classes("bg-secondary").props("flat color=accent")
|
|
65
|
+
|
|
66
|
+
label = ui.label()
|
|
67
|
+
|
|
68
|
+
def update_date():
|
|
69
|
+
label.set_text(datetime.now().astimezone().strftime('%m-%d-%Y %H:%M:%SZ'))
|
|
70
|
+
|
|
71
|
+
ui.timer(1.0, update_date)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
async def nav(path :str):
|
|
75
|
+
ui.navigate.to(path)
|
|
76
|
+
width = await ui.run_javascript('window.innerWidth')
|
|
77
|
+
if width < 1024: # Adjust this breakpoint as needed
|
|
78
|
+
left_drawer.hide()
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
with ui.left_drawer(bordered=True).classes("bg-dark") as left_drawer:
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
ui.button(
|
|
85
|
+
"Networking",
|
|
86
|
+
on_click=lambda:nav('/networking'),
|
|
87
|
+
icon="settings_ethernet",
|
|
88
|
+
).props("flat color=white align=left").classes("full-width")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
#ui.button(
|
|
92
|
+
# "NTP",
|
|
93
|
+
# on_click=lambda: nav('/ntp'),
|
|
94
|
+
# icon="settings_ethernet",
|
|
95
|
+
#).props("flat color=white align=left").classes("full-width")
|
|
96
|
+
|
|
97
|
+
ui.button("Terminal",
|
|
98
|
+
on_click=lambda: nav('/terminal'),
|
|
99
|
+
icon="terminal"
|
|
100
|
+
).props("flat color=white align=left").classes("full-width")
|
|
101
|
+
|
|
102
|
+
#ui.button(
|
|
103
|
+
# "FPGA",
|
|
104
|
+
# on_click=lambda: nav('/fpga'),
|
|
105
|
+
# icon="settings_ethernet",
|
|
106
|
+
#).props("flat color=white align=left").classes("full-width")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
ui.button(
|
|
110
|
+
"SNMP",
|
|
111
|
+
on_click=lambda: nav('/snmp'),
|
|
112
|
+
icon="settings_applications",
|
|
113
|
+
).props("flat color=white align=left").classes("full-width")
|
|
114
|
+
|
|
115
|
+
ui.button(
|
|
116
|
+
"Accounts",
|
|
117
|
+
on_click=lambda: nav('/accounts'),
|
|
118
|
+
icon="group",
|
|
119
|
+
).props("flat color=white align=left").classes("full-width")
|
|
120
|
+
|
|
121
|
+
#ui.button(
|
|
122
|
+
# "Tests",
|
|
123
|
+
# on_click=lambda: nav('/tests'),
|
|
124
|
+
# icon="group",
|
|
125
|
+
#).props("flat color=white align=left").classes("full-width")
|
|
126
|
+
|
|
127
|
+
ui.separator()
|
|
128
|
+
|
|
129
|
+
ui.button(
|
|
130
|
+
"Logout",
|
|
131
|
+
on_click=lambda: (app.storage.user.clear(), nav("/login")),
|
|
132
|
+
icon="logout",
|
|
133
|
+
).props("flat color=negative align=left").classes("full-width")
|
|
134
|
+
|
|
135
|
+
# Footer
|
|
136
|
+
with ui.footer().classes("bg-dark"):
|
|
137
|
+
ui.label(version)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
ui.sub_pages({
|
|
141
|
+
'/': network_page,
|
|
142
|
+
'/networking': network_page,
|
|
143
|
+
'/networking/firewall': firewall_page,
|
|
144
|
+
'/networking/{interface_name}': interface_page,
|
|
145
|
+
'/ntp' : ntp_page,
|
|
146
|
+
'/snmp': snmp_page,
|
|
147
|
+
'/snmp/{version}/{user}': snmp_user_page,
|
|
148
|
+
'/accounts': accounts_page,
|
|
149
|
+
'/accounts/{user}': accounts_user_page,
|
|
150
|
+
'/terminal': terminal_page,
|
|
151
|
+
#'/fpga': fpga_page,
|
|
152
|
+
#'/tests': tests_page
|
|
153
|
+
}).classes("w-full")
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@app.on_startup
|
|
160
|
+
async def startup():
|
|
161
|
+
global sock_task
|
|
162
|
+
await dbus.setup()
|
|
163
|
+
sock_task = asyncio.create_task(socket_stream())
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@app.on_shutdown
|
|
167
|
+
async def shutdown():
|
|
168
|
+
global sock_task
|
|
169
|
+
await dbus.cleanup()
|
|
170
|
+
#await socket_cleanup()
|
|
171
|
+
sock_task.cancel()
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
if not sys.argv[1]:
|
|
175
|
+
sys.exit()
|
|
176
|
+
|
|
177
|
+
ui.run(
|
|
178
|
+
port=int(sys.argv[1]),
|
|
179
|
+
reload=False,
|
|
180
|
+
storage_secret="your-secret-key",
|
|
181
|
+
title="Novus Configuration Tool",
|
|
182
|
+
favicon=str(ASSETS_DIR / "favicon.png")
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
if __name__ in {"__main__", "__mp_main__"}:
|
|
189
|
+
main()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
#TODO Clean up and test ipv4 stuff, expand to dns and ipv6
|
|
194
|
+
#TODO Add firewalld to networking page
|
|
195
|
+
#TODO Move snmp to a separate service for permissions
|
|
196
|
+
#TODO Work on accounts and grouping users into accounts
|
|
197
|
+
#TODO Implement Policy kit one day
|
|
198
|
+
#TODO Move time server stuff to dbus service?
|
|
199
|
+
#TODO Move PAM / Auth to a different service
|
|
200
|
+
#TODO Fix terminal to be in the signed in user
|