GNServer 0.0.0.0.47__py3-none-any.whl → 0.0.0.0.48__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
@@ -7,7 +7,7 @@ import asyncio
7
7
  import inspect
8
8
  import traceback
9
9
  import datetime
10
- from typing import Any, Callable, Dict, List, Optional, Tuple, Union, AsyncGenerator
10
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Union, AsyncGenerator, Awaitable
11
11
  from aioquic.asyncio.server import serve
12
12
  from aioquic.asyncio.protocol import QuicConnectionProtocol
13
13
  from aioquic.quic.configuration import QuicConfiguration
@@ -24,6 +24,7 @@ from ._cors_resolver import resolve_cors
24
24
 
25
25
  from ._routes import Route, _compile_path, _ensure_async, _convert_value
26
26
 
27
+ from .models import KDCObject
27
28
 
28
29
 
29
30
  try:
@@ -120,6 +121,13 @@ class App:
120
121
 
121
122
  self.domain: str = None # type: ignore
122
123
 
124
+ self.__allowed_modes = (1, 2, 4)
125
+
126
+ self._kdc: Optional[KDCObject] = None
127
+
128
+ def setKDC(self, kdc: KDCObject):
129
+ self._kdc = kdc
130
+
123
131
  def route(self, method: str, path: str, cors: Optional[CORSObject] = None):
124
132
  if path == '/':
125
133
  path = ''
@@ -158,7 +166,7 @@ class App:
158
166
 
159
167
 
160
168
  def addEventListener(self, name: str):
161
- def decorator(fn: Callable[[Optional[dict]], Any]):
169
+ def decorator(fn: Callable[[Callable[[dict | None], Awaitable[Any]]], None]):
162
170
  events = self._events.get(name, [])
163
171
  events.append({
164
172
  'func': fn,
@@ -323,13 +331,21 @@ class App:
323
331
  # получаем длинну пакета
324
332
  mode, stream, lenght = GNRequest.type(buf)
325
333
 
326
- if mode not in (1, 2, 4): # не наш пакет
327
- logger.debug(f'Пакет отклонен: mode пакета {mode}. Разрешен 1, 2, 3')
334
+ if mode not in self._api._App__allowed_modes: # не наш пакет # type: ignore
335
+ logger.debug(f'Пакет отклонен: mode пакета {mode}. Разрешен 1, 2, 4')
328
336
  return
329
337
 
330
338
  if not stream: # если не стрим, то ждем конец quic стрима и запускаем обработку ответа
331
339
  if event.end_stream:
332
- request = GNRequest.deserialize(buf, mode)
340
+
341
+ if self._api._kdc is not None:
342
+ buf = self._api._kdc.decode(buf)
343
+
344
+ if buf is not None:
345
+ request = GNRequest.deserialize(buf, mode)
346
+ else:
347
+ raise Exception('Не удалось расшифровать от KDC')
348
+
333
349
  request.stream_id = event.stream_id # type: ignore
334
350
  asyncio.create_task(self._handle_request(request, mode))
335
351
  logger.debug(f'Отправлена задача разрешения пакета {request} route -> {request.route}')
@@ -350,6 +366,9 @@ class App:
350
366
  del buf[:lenght]
351
367
 
352
368
  # формируем запрос
369
+
370
+ if self._api._kdc is not None:
371
+ data = self._api._kdc.decode(data)
353
372
  request = GNRequest.deserialize(data, mode)
354
373
 
355
374
  logger.debug(request, f'event.stream_id -> {event.stream_id}')
@@ -411,7 +430,7 @@ class App:
411
430
  await self.sendResponse(request, response, mode)
412
431
  logger.debug(f'Отправлен на сервер ответ -> {response.command} {response.payload if response.payload and len(str(response.payload)) < 200 else ''}')
413
432
  except Exception as e:
414
- if isinstance(e, GNFastCommand):
433
+ if isinstance(e, GNRequest):
415
434
  await self.sendResponse(request, e, mode)
416
435
  else:
417
436
  logger.error('GNServer: error\n' + traceback.format_exc())
@@ -422,9 +441,14 @@ class App:
422
441
 
423
442
  async def sendResponse(self, request: GNRequest, response: GNResponse, mode: int, end_stream: bool = True):
424
443
  await response.assembly()
444
+
445
+ blob = response.serialize(mode)
446
+
425
447
 
448
+ if self._api._kdc is not None:
449
+ blob = self._api._kdc.encode(blob)
426
450
 
427
- self._quic.send_stream_data(request.stream_id, response.serialize(mode), end_stream=end_stream) # type: ignore
451
+ self._quic.send_stream_data(request.stream_id, blob, end_stream=end_stream) # type: ignore
428
452
  self.transmit()
429
453
 
430
454
  def run(
GNServer/_client.py CHANGED
@@ -84,7 +84,7 @@ from KeyisBTools.ranges.positionRange import in_range
84
84
  from gnobjects.net.objects import GNRequest, GNResponse, Url
85
85
 
86
86
  from ._crt import crt_client
87
-
87
+ from .models import KDCObject
88
88
 
89
89
 
90
90
  _log_levels: dict[str, int] = {
@@ -124,10 +124,6 @@ def devLog(request: GNRequest, point: str, level: int, log: str):
124
124
 
125
125
 
126
126
 
127
-
128
-
129
-
130
-
131
127
  async def chain_async(first_item, rest: AsyncIterable) -> AsyncGenerator:
132
128
  yield first_item
133
129
  async for x in rest:
@@ -151,6 +147,8 @@ class AsyncClient:
151
147
 
152
148
  self.__domain = domain
153
149
 
150
+ self._kdc: Optional[KDCObject] = None
151
+
154
152
  if server_key:
155
153
  if isinstance(server_key, bytes):
156
154
  self.__server_key = server_key
@@ -162,6 +160,8 @@ class AsyncClient:
162
160
  else:
163
161
  self.__server_key = None
164
162
 
163
+ def setKDC(self, kdc: KDCObject):
164
+ self._kdc = kdc
165
165
 
166
166
  def addRequestCallback(self, callback: Callable, name: str):
167
167
  self.__request_callbacks[name] = callback
@@ -195,7 +195,7 @@ class AsyncClient:
195
195
  else:
196
196
  return c
197
197
 
198
- c = QuicClient()
198
+ c = QuicClient(self)
199
199
  c.status = 'connecting'
200
200
  self._active_connections[domain] = c
201
201
 
@@ -252,7 +252,7 @@ class AsyncClient:
252
252
  request = await self._resolve_requests_transport(request)
253
253
  try:
254
254
  c = await self.connect(request, restart_connection, reconnect_wait, keep_alive=keep_alive)
255
- except Exception as e:
255
+ except BaseException as e:
256
256
  if isinstance(e, GNResponse):
257
257
  return e
258
258
  else:
@@ -606,15 +606,26 @@ class RawQuicClient(QuicConnectionProtocol):
606
606
  async def request(self, request: Union[GNRequest, AsyncGenerator[GNRequest, Any]]):
607
607
  if isinstance(request, GNRequest):
608
608
  blob = request.serialize(2)
609
+
610
+ if self.quicClient._client._kdc is not None:
611
+ blob = self.quicClient._client._kdc.encode(request.url.hostname, blob)
612
+
609
613
  sid = self._quic.get_next_available_stream_id()
610
- devLog(request, '1.3.1', 10, f'Sending request on stream {sid}')
611
614
  self._enqueue(sid, blob, True, False)
612
615
  self._schedule_flush()
613
616
 
614
617
 
615
618
  fut = asyncio.get_running_loop().create_future()
616
619
  self._inflight[sid] = fut
617
- return await fut
620
+ data = await fut
621
+
622
+ if self.quicClient._client._kdc is not None:
623
+ data = self.quicClient._client._kdc.decode(request.url.hostname, data)
624
+
625
+ if data is not None:
626
+ return GNResponse.deserialize(data, 2)
627
+ else:
628
+ return GNResponse('gn:client:0')
618
629
 
619
630
  else:
620
631
  sid = self._quic.get_next_available_stream_id()
@@ -692,7 +703,8 @@ class RawQuicClient(QuicConnectionProtocol):
692
703
  class QuicClient:
693
704
  """Обёртка‑фасад над RawQuicClient."""
694
705
 
695
- def __init__(self):
706
+ def __init__(self, Client: AsyncClient):
707
+ self._client = Client
696
708
  self._quik_core: Optional[RawQuicClient] = None
697
709
  self._client_cm = None
698
710
  self._disconnect_signal = None
@@ -768,9 +780,7 @@ class QuicClient:
768
780
  raise RuntimeError("Not connected")
769
781
 
770
782
  resp = await self._quik_core.request(request)
771
- r = GNResponse.deserialize(resp, 2)
772
- devLog(request, '1.4.1', 10, f'Response received: {r}')
773
- return r
783
+ return resp
774
784
 
775
785
  async def asyncRequestStream(self, request: Union[GNRequest, AsyncGenerator[GNRequest, Any]]) -> AsyncGenerator[GNResponse, None]:
776
786
 
GNServer/models.py ADDED
@@ -0,0 +1,60 @@
1
+
2
+ from typing import List, Optional, Dict
3
+ from KeyisBTools.cryptography.sign import s2
4
+ from KeyisBTools.cryptography import m1
5
+
6
+ from ._client import AsyncClient
7
+ from ._app import GNRequest, GNResponse
8
+ from gnobjects.net.objects import Url
9
+
10
+ from KeyisBTools.cryptography.bytes import hash3
11
+
12
+ class KDCObject:
13
+ def __init__(self, domain: str, kdc_domain: str, kdc_key: bytes, requested_domains: List[str]):
14
+ self._domain = domain
15
+ self._kdc_domain = kdc_domain
16
+ self._kdc_key = kdc_key
17
+ self._requested_domains = requested_domains
18
+
19
+ self._client = AsyncClient(domain)
20
+
21
+ self._servers_keys: Optional[Dict[str, bytes]] = None
22
+ self._servers_keys_hash_domain: Dict[bytes, str] = {}
23
+ self._servers_keys_domain_hash: Dict[str, bytes] = {}
24
+
25
+
26
+
27
+
28
+ async def init(self):
29
+ payload = self._requested_domains
30
+ r = await self._client.request(GNRequest('GET', Url(f'gn://{self._kdc_domain}/api/sys/server/keys'), payload=payload))
31
+
32
+ if not r.command.ok:
33
+ raise r
34
+
35
+ self._servers_keys: Dict[str, bytes] = r.payload
36
+
37
+ for domain in self._servers_keys.keys():
38
+ h = hash3(domain.encode())
39
+ self._servers_keys_hash_domain[h] = domain
40
+ self._servers_keys_domain_hash[domain] = h
41
+
42
+
43
+ self._servers_keys[self._kdc_domain] = self._kdc_key
44
+ h = hash3(self._kdc_domain.encode())
45
+ self._servers_keys_hash_domain[h] = self._kdc_domain
46
+ self._servers_keys_domain_hash[self._kdc_domain] = h
47
+
48
+
49
+ def encode(self, domain: str, request: bytes):
50
+ sig = s2.sign(self._kdc_key)
51
+ data = m1.encrypt(self._domain.encode(), sig, request, self._kdc_key)
52
+ return sig + self._servers_keys_domain_hash[domain] + data
53
+
54
+ def decode(self, response: bytes):
55
+ sig, domain_h, data = response[:164], response[164:164+64], response[164+64:]
56
+
57
+ key = self._servers_keys[self._servers_keys_hash_domain[domain_h]]
58
+ if not s2.verify(key, sig):
59
+ return None
60
+ return m1.decrypt(self._domain.encode(), sig, data, key)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GNServer
3
- Version: 0.0.0.0.47
3
+ Version: 0.0.0.0.48
4
4
  Summary: GNServer
5
5
  Home-page: https://github.com/KeyisB/libs/tree/main/GNServer
6
6
  Author: KeyisB
@@ -1,13 +1,14 @@
1
1
  GNServer/__init__.py,sha256=6CMCZlkBO74PW8i8DAri5xz2fYM9EyPH8vdsLYBMmOo,1560
2
- GNServer/_app.py,sha256=p9TNz6m3eNiRw4g66iilZydqad73e9FcmtLusTP3nJU,17518
3
- GNServer/_client.py,sha256=MNNnBl1u9OAafIzDnOz3aYgcJUg8QizEV8QDFdGy8LQ,32071
2
+ GNServer/_app.py,sha256=tXaeAZPfibuNSNCgebJnA9MGlk4nYTkPWcdxMcuXrlI,18369
3
+ GNServer/_client.py,sha256=UISxnk6lhU90knh0okWA7aAlvTNiEvxZf7D472Y7eEM,32567
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-0.0.0.0.47.dist-info/licenses/LICENSE,sha256=_rN-sb3LemR3cKsEqjJRdXkdt7mME1mkW1BwWEn-zAw,1309
10
- gnserver-0.0.0.0.47.dist-info/METADATA,sha256=r9-LTxLBcALai6o3aSp1bCvajalgSAr4uHkt2s_bvmI,830
11
- gnserver-0.0.0.0.47.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
- gnserver-0.0.0.0.47.dist-info/top_level.txt,sha256=-UOUBuD4u7Qkb1o5PdcwyA3kx8xCH2lwy0tJHi26Wb4,9
13
- gnserver-0.0.0.0.47.dist-info/RECORD,,
9
+ GNServer/models.py,sha256=uqewqQX958PNsi4UzK0I71gwSiZHx0xEihkZxGCKK8E,2160
10
+ gnserver-0.0.0.0.48.dist-info/licenses/LICENSE,sha256=_rN-sb3LemR3cKsEqjJRdXkdt7mME1mkW1BwWEn-zAw,1309
11
+ gnserver-0.0.0.0.48.dist-info/METADATA,sha256=q9APw9klgeRtaR1vHExywbnV9KOFvgB_WIQBlT4lIwQ,830
12
+ gnserver-0.0.0.0.48.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
13
+ gnserver-0.0.0.0.48.dist-info/top_level.txt,sha256=-UOUBuD4u7Qkb1o5PdcwyA3kx8xCH2lwy0tJHi26Wb4,9
14
+ gnserver-0.0.0.0.48.dist-info/RECORD,,