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 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 _handle_request(self, request: GNRequest, mode: int):
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
- payload = self._requested_domains
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
- def encode(self, domain: str, request: bytes):
70
+
71
+ async def encode(self, domain: str, request: bytes):
71
72
  if domain not in self._servers_keys:
72
- return request
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 response, None
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
- print(domain_h, 'not in', self._servers_keys_hash_domain)
86
- return response, None
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GNServer
3
- Version: 0.0.0.0.59
3
+ Version: 0.0.0.0.61
4
4
  Summary: GNServer
5
5
  Home-page: https://github.com/KeyisB/libs/tree/main/GNServer
6
6
  Author: KeyisB
@@ -1,14 +1,14 @@
1
1
  GNServer/__init__.py,sha256=QmvIIE5RWIv040_l216aWtYuiIPtLasdsFbH0Fya2SI,1793
2
- GNServer/_app.py,sha256=bf5sXwimwgsSq51bK3YVq0e46p-0Hr9NY5wME2Okh54,19328
3
- GNServer/_client.py,sha256=MDAVnMGc5QNweOt8Tbas7OF9d_0Z3upxtrA7PmIttVs,33163
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=CXBJR_g3clIKKaMJ_zsUFLEG0EBa3g_Ik10te7whd30,3211
10
- gnserver-0.0.0.0.59.dist-info/licenses/LICENSE,sha256=_rN-sb3LemR3cKsEqjJRdXkdt7mME1mkW1BwWEn-zAw,1309
11
- gnserver-0.0.0.0.59.dist-info/METADATA,sha256=8x6eFAgjqAlpnOR29WUGyFwtj78jLfU0UARWXZMqTwM,830
12
- gnserver-0.0.0.0.59.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
13
- gnserver-0.0.0.0.59.dist-info/top_level.txt,sha256=-UOUBuD4u7Qkb1o5PdcwyA3kx8xCH2lwy0tJHi26Wb4,9
14
- gnserver-0.0.0.0.59.dist-info/RECORD,,
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,,