GNServer 0.0.0.0.59__py3-none-any.whl → 0.0.0.0.61__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.
- GNServer/_app.py +38 -28
- GNServer/_client.py +2 -10
- GNServer/models.py +40 -30
- {gnserver-0.0.0.0.59.dist-info → gnserver-0.0.0.0.61.dist-info}/METADATA +1 -1
- {gnserver-0.0.0.0.59.dist-info → gnserver-0.0.0.0.61.dist-info}/RECORD +8 -8
- {gnserver-0.0.0.0.59.dist-info → gnserver-0.0.0.0.61.dist-info}/WHEEL +0 -0
- {gnserver-0.0.0.0.59.dist-info → gnserver-0.0.0.0.61.dist-info}/licenses/LICENSE +0 -0
- {gnserver-0.0.0.0.59.dist-info → gnserver-0.0.0.0.61.dist-info}/top_level.txt +0 -0
GNServer/_app.py
CHANGED
@@ -249,6 +249,8 @@ class App:
|
|
249
249
|
return r.handler(**kw)
|
250
250
|
|
251
251
|
result = await r.handler(**kw)
|
252
|
+
if result is None:
|
253
|
+
result = AllGNFastCommands.ok()
|
252
254
|
if isinstance(result, GNResponse):
|
253
255
|
if r.cors is None:
|
254
256
|
if result._cors is None:
|
@@ -339,30 +341,7 @@ class App:
|
|
339
341
|
|
340
342
|
if not stream: # если не стрим, то ждем конец quic стрима и запускаем обработку ответа
|
341
343
|
if event.end_stream:
|
342
|
-
|
343
|
-
if self._api._kdc is not None:
|
344
|
-
buf, domain = self._api._kdc.decode(bytes(buf))
|
345
|
-
else:
|
346
|
-
domain = None
|
347
|
-
|
348
|
-
if buf is not None:
|
349
|
-
try:
|
350
|
-
request = GNRequest.deserialize(buf, mode)
|
351
|
-
if domain is not None:
|
352
|
-
request.client._data['domain'] = domain
|
353
|
-
except:
|
354
|
-
asyncio.create_task(self.sendRawResponse(stream_id, AllGNFastCommands.KDCDecryptRequestFailed().serialize(mode=mode)))
|
355
|
-
self._buffer.pop(event.stream_id, None)
|
356
|
-
return
|
357
|
-
|
358
|
-
else:
|
359
|
-
raise Exception('Не удалось расшифровать от KDC')
|
360
|
-
|
361
|
-
request.stream_id = stream_id # type: ignore
|
362
|
-
logger.debug(f'Request: {request.method} {request.url}')
|
363
|
-
asyncio.create_task(self._handle_request(request, mode))
|
364
|
-
|
365
|
-
self._buffer.pop(event.stream_id, None)
|
344
|
+
asyncio.create_task(self._resolve_raw_request(stream_id, buf, mode))
|
366
345
|
return
|
367
346
|
|
368
347
|
# если стрим, то смотрим сколько пришло данных
|
@@ -378,6 +357,9 @@ class App:
|
|
378
357
|
del buf[:lenght]
|
379
358
|
|
380
359
|
# формируем запрос
|
360
|
+
|
361
|
+
asyncio.create_task(self.sendRawResponse(stream_id, AllGNFastCommands.NotImplemented().serialize(mode=mode)))
|
362
|
+
return
|
381
363
|
|
382
364
|
if self._api._kdc is not None:
|
383
365
|
data, domain = self._api._kdc.decode(data)
|
@@ -420,9 +402,37 @@ class App:
|
|
420
402
|
request._stream = w # type: ignore
|
421
403
|
asyncio.create_task(self._handle_request(request, mode))
|
422
404
|
|
423
|
-
async def
|
405
|
+
async def _resolve_raw_request(self, stream_id: int, data: bytes, mode: int):
|
424
406
|
|
407
|
+
if self._api._kdc is not None:
|
408
|
+
data, domain = await self._api._kdc.decode(bytes(data))
|
409
|
+
else:
|
410
|
+
domain = None
|
411
|
+
|
412
|
+
if data is None:
|
413
|
+
self._buffer.pop(stream_id, None)
|
414
|
+
raise Exception('Не удалось расшифровать от KDC')
|
415
|
+
|
416
|
+
try:
|
417
|
+
request = GNRequest.deserialize(data, mode)
|
418
|
+
if domain is not None:
|
419
|
+
request.client._data['domain'] = domain
|
420
|
+
except:
|
421
|
+
self._buffer.pop(stream_id, None)
|
422
|
+
await self.sendRawResponse(stream_id, AllGNFastCommands.KDCDecryptRequestFailed().serialize(mode=mode))
|
423
|
+
return
|
424
|
+
|
425
|
+
logger.debug(f'[<] Request: {request.method} {request.url}')
|
426
|
+
|
425
427
|
request.client._data['remote_addr'] = self._quic._network_paths[0].addr
|
428
|
+
request.stream_id = stream_id # type: ignore
|
429
|
+
|
430
|
+
self._buffer.pop(stream_id, None)
|
431
|
+
await self._handle_request(request, mode)
|
432
|
+
|
433
|
+
|
434
|
+
async def _handle_request(self, request: GNRequest, mode: int):
|
435
|
+
|
426
436
|
|
427
437
|
try:
|
428
438
|
response = await self._api.dispatchRequest(request)
|
@@ -457,13 +467,13 @@ class App:
|
|
457
467
|
await response.assembly()
|
458
468
|
|
459
469
|
|
460
|
-
logger.debug(f'Response: {request.method} {request.url} -> {response.command} {response.payload if len(str(response.payload)) < 256 else ''}')
|
470
|
+
logger.debug(f'[>] Response: {request.method} {request.url} -> {response.command} {response.payload if len(str(response.payload)) < 256 else ''}')
|
461
471
|
|
462
472
|
blob = response.serialize(mode)
|
463
473
|
|
464
474
|
|
465
475
|
if self._api._kdc is not None:
|
466
|
-
blob = self._api._kdc.encode(request.client.domain, blob)
|
476
|
+
blob = await self._api._kdc.encode(request.client.domain, blob)
|
467
477
|
|
468
478
|
await self.sendRawResponse(request.stream_id, blob=blob, end_stream=end_stream)
|
469
479
|
|
@@ -542,4 +552,4 @@ class App:
|
|
542
552
|
cert_path=cert_path,
|
543
553
|
key_path=key_path,
|
544
554
|
host=host
|
545
|
-
)
|
555
|
+
)
|
GNServer/_client.py
CHANGED
@@ -189,15 +189,11 @@ class AsyncClient:
|
|
189
189
|
|
190
190
|
async def connect(self, request: GNRequest, restart_connection: bool = False, reconnect_wait: float = 10, keep_alive: bool = True) -> 'QuicClient':
|
191
191
|
domain = request.url.hostname
|
192
|
-
devLog(request, '1.2.1', 10, f'Connect to {domain}: restart_connection={restart_connection}, reconnect_wait={reconnect_wait}, keep_alive={keep_alive}')
|
193
192
|
if not restart_connection and domain in self._active_connections:
|
194
193
|
c = self._active_connections[domain]
|
195
|
-
devLog(request, '1.2.2', 10, f'Connection to {domain} found: status={c.status}')
|
196
194
|
if c.status == 'connecting':
|
197
|
-
devLog(request, '1.2.3', 10, f'Waiting for connection to {domain}...')
|
198
195
|
try:
|
199
196
|
await asyncio.wait_for(c.connect_future, reconnect_wait)
|
200
|
-
devLog(request, '1.2.4', 10, f'Connected to {domain}: status={c.status}')
|
201
197
|
if c.status == 'active':
|
202
198
|
return c
|
203
199
|
elif c.status == 'connecting': # если очень долго подключаемся, то кидаем ошибку
|
@@ -206,7 +202,6 @@ class AsyncClient:
|
|
206
202
|
elif c.status == 'disconnect':
|
207
203
|
raise GNExceptions.ConnectionError.client.connection
|
208
204
|
except:
|
209
|
-
devLog(request, '1.2.5', 10, f'Connection to {domain} failed or timed out.')
|
210
205
|
await self.disconnect(domain)
|
211
206
|
|
212
207
|
else:
|
@@ -216,9 +211,7 @@ class AsyncClient:
|
|
216
211
|
c.status = 'connecting'
|
217
212
|
self._active_connections[domain] = c
|
218
213
|
|
219
|
-
devLog(request, '1.2.6', 10, f'Connecting to {domain}...')
|
220
214
|
data = await self.getDNS(domain, raise_errors=True)
|
221
|
-
devLog(request, '1.2.7', 10, f'Got DNS for {domain}: {data}')
|
222
215
|
|
223
216
|
data = data.split(':')
|
224
217
|
|
@@ -229,7 +222,6 @@ class AsyncClient:
|
|
229
222
|
|
230
223
|
c._disconnect_signal = f # type: ignore
|
231
224
|
c._domain = domain # type: ignore
|
232
|
-
devLog(request, '1.2.8', 10, f'Creating QuicClient for {domain}...')
|
233
225
|
await c.connect(data[0], int(data[1]), keep_alive=keep_alive)
|
234
226
|
await c.connect_future
|
235
227
|
|
@@ -625,7 +617,7 @@ class RawQuicClient(QuicConnectionProtocol):
|
|
625
617
|
blob = request.serialize(_sys_s_mode)
|
626
618
|
|
627
619
|
if self.quicClient._client._kdc is not None:
|
628
|
-
blob = self.quicClient._client._kdc.encode(request.url.hostname, blob)
|
620
|
+
blob = await self.quicClient._client._kdc.encode(request.url.hostname, blob)
|
629
621
|
|
630
622
|
sid = self._quic.get_next_available_stream_id()
|
631
623
|
self._enqueue(sid, blob, True, False)
|
@@ -637,7 +629,7 @@ class RawQuicClient(QuicConnectionProtocol):
|
|
637
629
|
data = await fut
|
638
630
|
|
639
631
|
if self.quicClient._client._kdc is not None:
|
640
|
-
data, domain = self.quicClient._client._kdc.decode(data)
|
632
|
+
data, domain = await self.quicClient._client._kdc.decode(data)
|
641
633
|
|
642
634
|
if data is not None:
|
643
635
|
r = GNResponse.deserialize(data, _sys_s_mode)
|
GNServer/models.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
from typing import List, Optional, Dict
|
2
|
+
from typing import List, Optional, Dict, Union
|
3
3
|
from KeyisBTools.cryptography.sign import s2
|
4
4
|
from KeyisBTools.cryptography import m1
|
5
5
|
|
@@ -9,12 +9,13 @@ from gnobjects.net.objects import Url
|
|
9
9
|
from KeyisBTools.cryptography.bytes import hash3
|
10
10
|
|
11
11
|
class KDCObject:
|
12
|
-
def __init__(self, domain: str, kdc_domain: str, kdc_key: bytes, requested_domains: List[str]):
|
12
|
+
def __init__(self, domain: str, kdc_domain: str, kdc_key: bytes, requested_domains: List[str], active_key_synchronization: bool = True):
|
13
13
|
self._domain = domain
|
14
14
|
self._domain_hash = hash3(domain.encode())
|
15
15
|
self._kdc_domain = kdc_domain
|
16
16
|
self._kdc_key = kdc_key
|
17
17
|
self._requested_domains = requested_domains
|
18
|
+
self._active_key_synchronization = active_key_synchronization
|
18
19
|
|
19
20
|
from ._client import AsyncClient
|
20
21
|
self._client = AsyncClient(domain)
|
@@ -28,13 +29,6 @@ class KDCObject:
|
|
28
29
|
|
29
30
|
async def init(self, servers_keys: Optional[Dict[str, bytes]] = None): # type: ignore
|
30
31
|
|
31
|
-
|
32
|
-
self._servers_keys[self._kdc_domain] = self._kdc_key
|
33
|
-
h = hash3(self._kdc_domain.encode())
|
34
|
-
self._servers_keys_hash_domain[h] = self._kdc_domain
|
35
|
-
self._servers_keys_domain_hash[self._kdc_domain] = h
|
36
|
-
|
37
|
-
|
38
32
|
if servers_keys is not None:
|
39
33
|
for i in self._requested_domains:
|
40
34
|
if i in servers_keys:
|
@@ -43,47 +37,63 @@ class KDCObject:
|
|
43
37
|
servers_keys = {}
|
44
38
|
|
45
39
|
if len(self._requested_domains) > 0:
|
46
|
-
|
47
|
-
r = await self._client.request(GNRequest('GET', Url(f'gn://{self._kdc_domain}/api/sys/server/keys'), payload=payload))
|
48
|
-
|
49
|
-
if not r.command.ok:
|
50
|
-
print(f'ERROR: {r.command} {r.payload}')
|
51
|
-
raise r
|
52
|
-
|
53
|
-
if servers_keys is None:
|
54
|
-
print(f'ERROR: {r.command} {r.payload}')
|
55
|
-
raise r
|
56
|
-
|
57
|
-
servers_keys.update(r.payload)
|
58
|
-
|
59
|
-
|
60
|
-
self._servers_keys.update(servers_keys)
|
40
|
+
await self.requestKDC(self._requested_domains) # type: ignore
|
61
41
|
|
42
|
+
|
43
|
+
def _update(self):
|
62
44
|
for domain in self._servers_keys.keys():
|
63
45
|
h = hash3(domain.encode())
|
64
46
|
self._servers_keys_hash_domain[h] = domain
|
65
47
|
self._servers_keys_domain_hash[domain] = h
|
66
48
|
|
49
|
+
async def requestKDC(self, domain_or_hash: Union[str, bytes, List[Union[str, bytes]]]):
|
50
|
+
if self._kdc_domain not in self._servers_keys:
|
51
|
+
self._servers_keys[self._kdc_domain] = self._kdc_key
|
52
|
+
h = hash3(self._kdc_domain.encode())
|
53
|
+
self._servers_keys_hash_domain[h] = self._kdc_domain
|
54
|
+
self._servers_keys_domain_hash[self._kdc_domain] = h
|
55
|
+
|
67
56
|
|
57
|
+
if not isinstance(domain_or_hash, list):
|
58
|
+
domain_or_hash = [domain_or_hash]
|
59
|
+
|
60
|
+
r = await self._client.request(GNRequest('GET', Url(f'gn://{self._kdc_domain}/api/sys/server/keys'), payload=domain_or_hash))
|
68
61
|
|
62
|
+
|
63
|
+
if not r.command.ok:
|
64
|
+
print(f'ERROR: {r.command} {r.payload}')
|
65
|
+
raise r
|
66
|
+
|
67
|
+
self._servers_keys.update(r.payload)
|
68
|
+
self._update()
|
69
69
|
|
70
|
-
|
70
|
+
|
71
|
+
async def encode(self, domain: str, request: bytes):
|
71
72
|
if domain not in self._servers_keys:
|
72
|
-
|
73
|
+
if not self._active_key_synchronization:
|
74
|
+
return request
|
75
|
+
else:
|
76
|
+
await self.requestKDC(domain)
|
77
|
+
|
73
78
|
key = self._servers_keys[domain]
|
74
79
|
sig = s2.sign(key)
|
75
80
|
data = m1.encrypt(domain.encode(), sig, request[8:], key)
|
76
81
|
return request[:8] + sig + self._domain_hash + data
|
77
82
|
|
78
|
-
def decode(self, response: bytes):
|
83
|
+
async def decode(self, response: bytes):
|
84
|
+
r = response
|
79
85
|
if len(response) < 8+164+64:
|
80
|
-
return
|
86
|
+
return r, None
|
81
87
|
h = response[:8]
|
82
88
|
response = response[8:]
|
83
89
|
sig, domain_h, data = response[:164], response[164:164+64], response[164+64:]
|
84
90
|
if domain_h not in self._servers_keys_hash_domain:
|
85
|
-
|
86
|
-
|
91
|
+
if not self._active_key_synchronization:
|
92
|
+
print(domain_h, 'not in', self._servers_keys_hash_domain)
|
93
|
+
return r, None
|
94
|
+
else:
|
95
|
+
await self.requestKDC(domain_h)
|
96
|
+
|
87
97
|
d = self._servers_keys_hash_domain[domain_h]
|
88
98
|
key = self._servers_keys[d]
|
89
99
|
if not s2.verify(key, sig):
|
@@ -1,14 +1,14 @@
|
|
1
1
|
GNServer/__init__.py,sha256=QmvIIE5RWIv040_l216aWtYuiIPtLasdsFbH0Fya2SI,1793
|
2
|
-
GNServer/_app.py,sha256=
|
3
|
-
GNServer/_client.py,sha256=
|
2
|
+
GNServer/_app.py,sha256=VaQFxnIOC7xXnsbNP6UeknsJMLRAcqaNjrB1z7S8Oqg,19468
|
3
|
+
GNServer/_client.py,sha256=J8dkXBlehb23FVM9dq6OX5xUxpAGX_DWX5abD0SfFe0,32422
|
4
4
|
GNServer/_cors_resolver.py,sha256=aDxk4ItaEK-6vlDbkno8FJZEjczGEe8vkOui6_kz5-Y,5950
|
5
5
|
GNServer/_crt.py,sha256=SOmyX7zBiCY9EhVSekksQtBHgTIZVvdqNZ8Ni-E5Zow,1390
|
6
6
|
GNServer/_func_params_validation.py,sha256=pDXRzPVTdPnDHFMMmKd014SConBjFOuaLeJTY0vldlM,11412
|
7
7
|
GNServer/_routes.py,sha256=bJnmQ8uEhPVQgy2tTqE5TEIM8aFXV-lVI7c2nG0rQwk,3384
|
8
8
|
GNServer/_template_resolver.py,sha256=vdJYb_7PjIeTWq-Clr7jyj7QIvPBxplU7EqeOuMJ64c,1409
|
9
|
-
GNServer/models.py,sha256=
|
10
|
-
gnserver-0.0.0.0.
|
11
|
-
gnserver-0.0.0.0.
|
12
|
-
gnserver-0.0.0.0.
|
13
|
-
gnserver-0.0.0.0.
|
14
|
-
gnserver-0.0.0.0.
|
9
|
+
GNServer/models.py,sha256=OlXrV823qaeL2oClodC_AC2r5S9CCZeCN_t8-sMgs2Y,3781
|
10
|
+
gnserver-0.0.0.0.61.dist-info/licenses/LICENSE,sha256=_rN-sb3LemR3cKsEqjJRdXkdt7mME1mkW1BwWEn-zAw,1309
|
11
|
+
gnserver-0.0.0.0.61.dist-info/METADATA,sha256=gUzbJhdOIambAewKEY17QWX1pcMqdogsk2faorIQRmU,830
|
12
|
+
gnserver-0.0.0.0.61.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
13
|
+
gnserver-0.0.0.0.61.dist-info/top_level.txt,sha256=-UOUBuD4u7Qkb1o5PdcwyA3kx8xCH2lwy0tJHi26Wb4,9
|
14
|
+
gnserver-0.0.0.0.61.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|