mirror of
https://github.com/SantaSpeen/winConnect.git
synced 2026-10-27 14:40:24 +00:00
Merge pull request #1 from SantaSpeen/dev
Update 0.9.2; New protocol version: 2
This commit is contained in:
15 files changed
+284
-40
No files matched your search
@@ -1,15 +1,15 @@
|
|||||||
# winConnect (Windows Only)
|
# winConnect
|
||||||
Communicate Client-Server via Windows NamedPipe
|
Communicate Client-Server via Windows NamedPipe
|
||||||
|
|
||||||
## ToDo:
|
## ToDo:
|
||||||
|
|
||||||
- [x] Add support for sending and receiving data
|
- [x] Add support for sending and receiving data (0.1.0)
|
||||||
- [x] Add support for other header settings
|
- [x] Add support for safe closing (0.9.0)
|
||||||
- [x] Add support for safe closing
|
- [x] Add support for other header settings (0.9.0)
|
||||||
- [x] Add logging
|
- [x] Add logging (0.9.1)
|
||||||
- [ ] Send data in chunks (if data is too large)
|
- [ ] Send data in chunks (if data is too large) (0.9.3)
|
||||||
- [ ] Add support for encryption
|
- [x] Add support for encryption (0.9.2)
|
||||||
- [ ] simple (via char shift; and auto-pairing)
|
- [x] simple (via char xor'ing; auto-pairing)
|
||||||
- [ ] password (via AES and PBKDF2)
|
- [ ] password (via AES and PBKDF2)
|
||||||
- [ ] certificate (via RSA)
|
- [ ] certificate (via RSA)
|
||||||
- [ ] Add support for multiple clients
|
- [ ] Add support for multiple clients
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ from winConnect import WinConnectDaemon
|
|||||||
connector = WinConnectDaemon('test')
|
connector = WinConnectDaemon('test')
|
||||||
# Set header settings
|
# Set header settings
|
||||||
# see: https://docs.python.org/3.13/library/struct.html#format-characters
|
# see: https://docs.python.org/3.13/library/struct.html#format-characters
|
||||||
# Default: ">L"
|
# Default: ">H" - Big-endian unsigned short integer (header_size: 2 bytes, max_size: 65535)
|
||||||
# >L - Big-endian long integer (header_size: 4 bytes, max_size: 4294967295)
|
connector.set_header_settings(">H")
|
||||||
connector.set_header_settings(">L")
|
|
||||||
|
|
||||||
for data in connector.listen():
|
for data in connector.listen():
|
||||||
print(f"({type(data)}) {data=}")
|
print(f"({type(data)}) {data=}")
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
from winConnect import WinConnectClient, crypto
|
||||||
|
|
||||||
|
logger.remove()
|
||||||
|
logger.add(sys.stdout, level="DEBUG")
|
||||||
|
|
||||||
|
crypt_mode = crypto.WinConnectCryptoSimple()
|
||||||
|
|
||||||
|
connector = WinConnectClient('test')
|
||||||
|
connector.set_logger(logger)
|
||||||
|
connector.set_crypto(crypt_mode)
|
||||||
|
|
||||||
|
def console():
|
||||||
|
with connector as conn:
|
||||||
|
while True:
|
||||||
|
i = input(":> ")
|
||||||
|
if i == "exit":
|
||||||
|
break
|
||||||
|
conn.send_data(i)
|
||||||
|
data = conn.read_pipe()
|
||||||
|
print(f"({type(data)}) {data=}")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
console()
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
from winConnect import WinConnectDaemon
|
||||||
|
from winConnect import crypto
|
||||||
|
|
||||||
|
logger.remove()
|
||||||
|
logger.add(sys.stdout, level="DEBUG")
|
||||||
|
|
||||||
|
crypt_mode = crypto.WinConnectCryptoSimple()
|
||||||
|
|
||||||
|
connector = WinConnectDaemon('test')
|
||||||
|
connector.set_logger(logger)
|
||||||
|
connector.set_crypto(crypt_mode)
|
||||||
|
|
||||||
|
for data in connector.listen():
|
||||||
|
print(f"({type(data)}) {data=}")
|
||||||
|
if data is None and connector.closed:
|
||||||
|
break
|
||||||
|
connector.send_data(data)
|
||||||
@@ -9,9 +9,11 @@ import ormsgpack
|
|||||||
import pywintypes
|
import pywintypes
|
||||||
import win32file
|
import win32file
|
||||||
|
|
||||||
from winConnect.errors import WinConnectErrors, WinConnectClientError
|
from .crypto.WinConnectCrypto import WinConnectCrypto
|
||||||
from winConnect import exceptions
|
from .crypto.crypto_classes import WinConnectCryptoNone
|
||||||
from winConnect.utils import SimpleConvertor
|
from .errors import WinConnectErrors, WinConnectError
|
||||||
|
from . import exceptions
|
||||||
|
from .utils import SimpleConvertor
|
||||||
|
|
||||||
# header: len(data) in struct.pack via header_format
|
# header: len(data) in struct.pack via header_format
|
||||||
# data: action:data
|
# data: action:data
|
||||||
@@ -19,17 +21,20 @@ from winConnect.utils import SimpleConvertor
|
|||||||
|
|
||||||
class WinConnectBase:
|
class WinConnectBase:
|
||||||
init_encoding = 'utf-8'
|
init_encoding = 'utf-8'
|
||||||
init_header_format = ">L" # Format for reading header (big-endian, unsigned long; 4 bytes)
|
init_header_format = ">H" # Format for reading header (big-endian, unsigned long; 4 bytes)
|
||||||
|
|
||||||
default_encoding = 'utf-8'
|
default_encoding = 'utf-8'
|
||||||
|
|
||||||
read_max_buffer = SimpleConvertor.to_gb(4) # Max size of buffer for message
|
read_max_buffer = SimpleConvertor.to_gb(3)-1 # Max size via chunked messages
|
||||||
|
|
||||||
ormsgpack_options = ormsgpack.OPT_NON_STR_KEYS | ormsgpack.OPT_NAIVE_UTC | ormsgpack.OPT_PASSTHROUGH_TUPLE # ormsgpack options
|
ormsgpack_options = ormsgpack.OPT_NON_STR_KEYS | ormsgpack.OPT_NAIVE_UTC | ormsgpack.OPT_PASSTHROUGH_TUPLE # ormsgpack options
|
||||||
|
|
||||||
def __init__(self, pipe_name: str):
|
def __init__(self, pipe_name: str):
|
||||||
self._log = logging.getLogger(f"WinConnect:{pipe_name}")
|
self._log = logging.getLogger(f"WinConnect:{pipe_name}")
|
||||||
self._version = 1
|
# _version:
|
||||||
|
# 1 - 0.9.1
|
||||||
|
# 2 - 0.9.2+ (with crypto)
|
||||||
|
self._version = 2
|
||||||
self._pipe_name = r'\\.\pipe\{}'.format(pipe_name)
|
self._pipe_name = r'\\.\pipe\{}'.format(pipe_name)
|
||||||
self._pipe = None
|
self._pipe = None
|
||||||
self._opened = False
|
self._opened = False
|
||||||
@@ -42,12 +47,24 @@ class WinConnectBase:
|
|||||||
self._inited = False
|
self._inited = False
|
||||||
self._session_encoding = self.init_encoding
|
self._session_encoding = self.init_encoding
|
||||||
|
|
||||||
self._parts_buffer = None # Buffer for parts of message (If message is too big)
|
self.__crypto = WinConnectCrypto()
|
||||||
|
self.__crypto.set_crypto_class(WinConnectCryptoNone())
|
||||||
|
|
||||||
|
# self._chunks = []
|
||||||
|
|
||||||
self._lock = threading.Lock()
|
self._lock = threading.Lock()
|
||||||
|
|
||||||
|
def set_crypto(self, crypto):
|
||||||
|
if self._connected:
|
||||||
|
raise exceptions.WinConnectConnectionAlreadyOpenException("Can't change crypto while session is active")
|
||||||
|
self.__crypto.set_crypto_class(crypto)
|
||||||
|
if not self.__crypto.test_and_load():
|
||||||
|
raise exceptions.WinConnectCryptoException("Crypto failed test")
|
||||||
|
|
||||||
def set_logger(self, logger):
|
def set_logger(self, logger):
|
||||||
|
logger.debug(f"[{self._pipe_name}] Update logger")
|
||||||
self._log = logger
|
self._log = logger
|
||||||
|
self.__crypto.set_logger(logger)
|
||||||
|
|
||||||
def _calc_body_max_size(self):
|
def _calc_body_max_size(self):
|
||||||
# Max size of body: 2 ** (8 * header_size) - 1 - header_size - 1
|
# Max size of body: 2 ** (8 * header_size) - 1 - header_size - 1
|
||||||
@@ -129,8 +146,10 @@ class WinConnectBase:
|
|||||||
if not self._connected:
|
if not self._connected:
|
||||||
return None, None
|
return None, None
|
||||||
_, data = win32file.ReadFile(self._pipe, message_size)
|
_, data = win32file.ReadFile(self._pipe, message_size)
|
||||||
|
if self._inited:
|
||||||
|
data = self.__crypto.decrypt(data)
|
||||||
action, data = self.__unpack_data(data)
|
action, data = self.__unpack_data(data)
|
||||||
# self._log.debug(f"[{self._pipe_name}] Received message: {action=} {data=}")
|
self._log.debug(f"[{self._pipe_name}] Received message: {action=} {data=}")
|
||||||
return action, data
|
return action, data
|
||||||
|
|
||||||
def _send_message(self, action: str, data: Any):
|
def _send_message(self, action: str, data: Any):
|
||||||
@@ -139,6 +158,8 @@ class WinConnectBase:
|
|||||||
if self.closed:
|
if self.closed:
|
||||||
raise exceptions.WinConnectSessionClosedException("Session is closed")
|
raise exceptions.WinConnectSessionClosedException("Session is closed")
|
||||||
packed_data = self.__pack_data(action, data)
|
packed_data = self.__pack_data(action, data)
|
||||||
|
if self._inited:
|
||||||
|
packed_data = self.__crypto.encrypt(packed_data)
|
||||||
message_size = len(packed_data)
|
message_size = len(packed_data)
|
||||||
if message_size > self._body_max_size:
|
if message_size > self._body_max_size:
|
||||||
raise ValueError('Message is too big')
|
raise ValueError('Message is too big')
|
||||||
@@ -147,9 +168,9 @@ class WinConnectBase:
|
|||||||
raise ValueError('Message is too big')
|
raise ValueError('Message is too big')
|
||||||
_hfmt, _ = self.__header_settings
|
_hfmt, _ = self.__header_settings
|
||||||
header = struct.pack(_hfmt, message_size)
|
header = struct.pack(_hfmt, message_size)
|
||||||
# self._log.debug(f"[{self._pipe_name}] Sending message: {action=} {data=}")
|
packet = header + packed_data
|
||||||
win32file.WriteFile(self._pipe, header)
|
self._log.debug(f"[{self._pipe_name}] Sending message: {action=} {data=}; {packet=}")
|
||||||
win32file.WriteFile(self._pipe, packed_data)
|
win32file.WriteFile(self._pipe, packet)
|
||||||
|
|
||||||
def _send_error(self, error: WinConnectErrors, error_message: str = None):
|
def _send_error(self, error: WinConnectErrors, error_message: str = None):
|
||||||
e = {"error": True, "code": error.value, "message": error.name, "description": error_message}
|
e = {"error": True, "code": error.value, "message": error.name, "description": error_message}
|
||||||
@@ -165,7 +186,7 @@ class WinConnectBase:
|
|||||||
case b"data":
|
case b"data":
|
||||||
return False, data
|
return False, data
|
||||||
case b"error":
|
case b"error":
|
||||||
return False, WinConnectClientError(data['code'], data['message'])
|
return False, WinConnectError(data['code'], data['message'])
|
||||||
case _:
|
case _:
|
||||||
return self._send_error(WinConnectErrors.UNKNOWN_ACTION, f"Unknown action '{action}'")
|
return self._send_error(WinConnectErrors.UNKNOWN_ACTION, f"Unknown action '{action}'")
|
||||||
|
|
||||||
@@ -179,7 +200,8 @@ class WinConnectBase:
|
|||||||
'encoding': self.default_encoding,
|
'encoding': self.default_encoding,
|
||||||
'header_size': self._header_size,
|
'header_size': self._header_size,
|
||||||
'header_format': self._header_format,
|
'header_format': self._header_format,
|
||||||
'max_buffer': self.read_max_buffer
|
'max_buffer': self.read_max_buffer,
|
||||||
|
"crypto": self.__crypto.get_info()
|
||||||
}
|
}
|
||||||
session_settings = f"set_session_settings:{json.dumps(settings)}".encode(self.init_encoding)
|
session_settings = f"set_session_settings:{json.dumps(settings)}".encode(self.init_encoding)
|
||||||
self._send_message("command", session_settings)
|
self._send_message("command", session_settings)
|
||||||
@@ -191,15 +213,20 @@ class WinConnectBase:
|
|||||||
self._send_error(WinConnectErrors.BAD_DATA, f"JSONDecodeError: {e}")
|
self._send_error(WinConnectErrors.BAD_DATA, f"JSONDecodeError: {e}")
|
||||||
return self.close()
|
return self.close()
|
||||||
if settings.get('version') != self._version:
|
if settings.get('version') != self._version:
|
||||||
|
self._log.error(f"{WinConnectErrors.BAD_VERSION}")
|
||||||
self._send_error(WinConnectErrors.BAD_VERSION, f"Version mismatch")
|
self._send_error(WinConnectErrors.BAD_VERSION, f"Version mismatch")
|
||||||
return self.close()
|
return self.close()
|
||||||
|
if settings.get('crypto') != self.__crypto.get_info():
|
||||||
|
self._log.error(f"{WinConnectErrors.BAD_CRYPTO}")
|
||||||
|
self._send_error(WinConnectErrors.BAD_CRYPTO, f"Crypto mismatch")
|
||||||
|
return self.close()
|
||||||
self._session_encoding = settings.get('encoding', self.default_encoding)
|
self._session_encoding = settings.get('encoding', self.default_encoding)
|
||||||
self._header_size = settings.get('header_size', self._header_size)
|
self._header_size = settings.get('header_size', self._header_size)
|
||||||
self._header_format = settings.get('header_format', self._header_format)
|
self._header_format = settings.get('header_format', self._header_format)
|
||||||
self.read_max_buffer = settings.get('max_buffer', self.read_max_buffer)
|
self.read_max_buffer = settings.get('max_buffer', self.read_max_buffer)
|
||||||
self._send_message("command", b"ready:")
|
|
||||||
return True
|
return True
|
||||||
case b"ready":
|
case b"session_ready":
|
||||||
|
self._inited = True
|
||||||
return True
|
return True
|
||||||
case b"close":
|
case b"close":
|
||||||
self.close()
|
self.close()
|
||||||
@@ -215,7 +242,8 @@ class WinConnectBase:
|
|||||||
return self._send_error(WinConnectErrors.BAD_DATA, "Unknown data type")
|
return self._send_error(WinConnectErrors.BAD_DATA, "Unknown data type")
|
||||||
if not self._parse_command(data):
|
if not self._parse_command(data):
|
||||||
return self._send_error(WinConnectErrors.INIT_FIRST, "Server need to init session first")
|
return self._send_error(WinConnectErrors.INIT_FIRST, "Server need to init session first")
|
||||||
self._inited = True
|
self._send_message("command", b"session_ready:")
|
||||||
|
self._parse_action(*self._read_message())
|
||||||
|
|
||||||
def send_data(self, data):
|
def send_data(self, data):
|
||||||
self._send_message("data", data)
|
self._send_message("data", data)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import pywintypes
|
import pywintypes
|
||||||
import win32file
|
import win32file
|
||||||
|
|
||||||
from winConnect.WinConnectBase import WinConnectBase
|
from .WinConnectBase import WinConnectBase
|
||||||
from winConnect.exceptions import WinConnectConnectionNoPipeException
|
from .exceptions import WinConnectConnectionNoPipeException
|
||||||
|
|
||||||
|
|
||||||
class WinConnectClient(WinConnectBase):
|
class WinConnectClient(WinConnectBase):
|
||||||
@@ -30,7 +30,7 @@ class WinConnectClient(WinConnectBase):
|
|||||||
)
|
)
|
||||||
self._opened = True
|
self._opened = True
|
||||||
self._connected = True
|
self._connected = True
|
||||||
self._log.debug(f"Pipe '{self._pipe_name}' opened")
|
self._log.debug(f"[{self._pipe_name}] Pipe opened")
|
||||||
except pywintypes.error as e:
|
except pywintypes.error as e:
|
||||||
if e.winerror == 2:
|
if e.winerror == 2:
|
||||||
exc = WinConnectConnectionNoPipeException(f"Error while opening pipe: Pipe not found")
|
exc = WinConnectConnectionNoPipeException(f"Error while opening pipe: Pipe not found")
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import win32pipe
|
import win32pipe
|
||||||
|
|
||||||
from winConnect.WinConnectBase import WinConnectBase
|
from .WinConnectBase import WinConnectBase
|
||||||
from winConnect.utils import SimpleConvertor
|
from .crypto import WinConnectCrypto
|
||||||
|
|
||||||
|
|
||||||
class WinConnectDaemon(WinConnectBase):
|
class WinConnectDaemon(WinConnectBase):
|
||||||
# see: https://mhammond.github.io/pywin32/win32pipe__CreateNamedPipe_meth.html
|
# see: https://mhammond.github.io/pywin32/win32pipe__CreateNamedPipe_meth.html
|
||||||
pipe_openMode = win32pipe.PIPE_ACCESS_DUPLEX # Open mode (read/write)
|
pipe_openMode = win32pipe.PIPE_ACCESS_DUPLEX # Open mode (read/write)
|
||||||
pipe_pipeMode = win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT # Pipe mode (message type, message read mode, blocking mode)
|
pipe_pipeMode = win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT # Pipe mode (message type, message read mode, blocking mode)
|
||||||
pipe_nMaxInstances = 2 # Max number of instances
|
pipe_nMaxInstances = 1 # Max number of instances
|
||||||
pipe_nOutBufferSize = SimpleConvertor.to_kb(64) # Max size of output buffer
|
|
||||||
pipe_nInBufferSize = SimpleConvertor.to_kb(64) # Max size of input buffer
|
|
||||||
pipe_nDefaultTimeOut = 0 # ~ ms
|
pipe_nDefaultTimeOut = 0 # ~ ms
|
||||||
pipe_sa = None # Security attributes
|
pipe_sa = None # Security attributes
|
||||||
|
|
||||||
@@ -19,13 +17,17 @@ class WinConnectDaemon(WinConnectBase):
|
|||||||
self.run = True
|
self.run = True
|
||||||
|
|
||||||
def _open_pipe(self):
|
def _open_pipe(self):
|
||||||
|
pipe_nOutBufferSize, pipe_nInBufferSize = self._body_max_size+20, self._body_max_size+20
|
||||||
|
self._log.debug(f"[{self._pipe_name}] Creating pipe. "
|
||||||
|
f"Settings: {self.pipe_openMode=}, {self.pipe_pipeMode=}, {self.pipe_nMaxInstances=}, "
|
||||||
|
f"{pipe_nOutBufferSize=}, {pipe_nInBufferSize=}, {self.pipe_nDefaultTimeOut=}, {self.pipe_sa=}")
|
||||||
self._pipe = win32pipe.CreateNamedPipe(
|
self._pipe = win32pipe.CreateNamedPipe(
|
||||||
self._pipe_name,
|
self._pipe_name,
|
||||||
self.pipe_openMode,
|
self.pipe_openMode,
|
||||||
self.pipe_pipeMode,
|
self.pipe_pipeMode,
|
||||||
self.pipe_nMaxInstances,
|
self.pipe_nMaxInstances,
|
||||||
self.pipe_nOutBufferSize,
|
pipe_nOutBufferSize,
|
||||||
self.pipe_nInBufferSize,
|
pipe_nInBufferSize,
|
||||||
self.pipe_nDefaultTimeOut,
|
self.pipe_nDefaultTimeOut,
|
||||||
self.pipe_sa
|
self.pipe_sa
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
from .WinConnectDaemon import WinConnectDaemon
|
from .WinConnectDaemon import WinConnectDaemon
|
||||||
from .WinConnectClient import WinConnectClient
|
from .WinConnectClient import WinConnectClient
|
||||||
|
|
||||||
|
from . import crypto
|
||||||
|
|
||||||
from .__meta__ import *
|
from .__meta__ import *
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
__title__ = 'winConnect'
|
__title__ = 'winConnect'
|
||||||
__description__ = 'Communicate Client-Server via Windows NamedPipe.'
|
__description__ = 'Communicate Client-Server via Windows NamedPipe.'
|
||||||
__url__ = 'https://github.com/SantaSpeen/winConnect'
|
__url__ = 'https://github.com/SantaSpeen/winConnect'
|
||||||
__version__ = '0.9.1'
|
__version__ = '0.9.2'
|
||||||
__build__ = 16
|
__build__ = 39
|
||||||
__author__ = 'SantaSpeen'
|
__author__ = 'SantaSpeen'
|
||||||
__author_email__ = 'admin@anidev.ru'
|
__author_email__ = 'admin@anidev.ru'
|
||||||
__license__ = "MIT"
|
__license__ = "MIT"
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from .crypto_class_base import WinConnectCryptoBase
|
||||||
|
from winConnect.exceptions import (
|
||||||
|
WinConnectCryptoBadModeException,
|
||||||
|
WinConnectCryptoException,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_crypto_class(crypto_class: "WinConnectCryptoBase"):
|
||||||
|
if not isinstance(crypto_class, WinConnectCryptoBase):
|
||||||
|
raise WinConnectCryptoBadModeException("crypto_class must be a subclass of WinConnectCryptoBase")
|
||||||
|
if not crypto_class.test():
|
||||||
|
raise WinConnectCryptoException("crypto_class failed test (test_bytes != decrypt_bytes)")
|
||||||
|
|
||||||
|
class WinConnectCrypto:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.__crypto_class = None
|
||||||
|
self.__log_prefix = None
|
||||||
|
self._log = logging.getLogger("WinConnectCrypto")
|
||||||
|
|
||||||
|
def set_crypto_class(self, crypto_class: "WinConnectCryptoBase"):
|
||||||
|
self._log.debug(f"{self.__log_prefix}Updating crypto class. {self.get_info()} -> {crypto_class.__class__.__name__}")
|
||||||
|
test_crypto_class(crypto_class)
|
||||||
|
self.__crypto_class = crypto_class
|
||||||
|
self.__log_prefix = f"[{self.get_info()}] "
|
||||||
|
self._log.debug(f"{self.__log_prefix}Crypto class updated.")
|
||||||
|
|
||||||
|
def set_logger(self, logger):
|
||||||
|
logger.debug(f"{self.__log_prefix}Setting logger")
|
||||||
|
self._log = logger
|
||||||
|
|
||||||
|
def test_and_load(self) -> bool:
|
||||||
|
self._log.debug(f"{self.__log_prefix}Testing and loading crypto class")
|
||||||
|
if not self.__crypto_class.test():
|
||||||
|
return False
|
||||||
|
self.__crypto_class.load()
|
||||||
|
self._log.debug(f"{self.__log_prefix}Crypto class loaded")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_info(self):
|
||||||
|
return self.__crypto_class.__class__.__name__
|
||||||
|
|
||||||
|
def encrypt(self, data: bytes) -> bytes:
|
||||||
|
return self.__crypto_class.encrypt(data)
|
||||||
|
|
||||||
|
def decrypt(self, data: bytes) -> bytes:
|
||||||
|
return self.__crypto_class.decrypt(data)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
from .WinConnectCrypto import WinConnectCrypto
|
||||||
|
from .crypto_classes import (
|
||||||
|
WinConnectCryptoBase,
|
||||||
|
WinConnectCryptoNone,
|
||||||
|
WinConnectCryptoSimple,
|
||||||
|
# WinConnectCryptoPassword,
|
||||||
|
# WinConnectCryptoCert
|
||||||
|
)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
class WinConnectCryptoBase:
|
||||||
|
|
||||||
|
def encrypt(self, data: bytes) -> bytes: ...
|
||||||
|
def decrypt(self, data: bytes) -> bytes: ...
|
||||||
|
|
||||||
|
def test(self, test_bytes: bytes = b"test_string") -> bool:
|
||||||
|
encrypted = self.encrypt(test_bytes)
|
||||||
|
decrypted = self.decrypt(encrypted)
|
||||||
|
if decrypted != test_bytes:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def load(self) -> None: ...
|
||||||
|
def unload(self) -> None: ...
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import random
|
||||||
|
|
||||||
|
from .crypto_class_base import WinConnectCryptoBase
|
||||||
|
from winConnect.exceptions import WinConnectCryptoSimpleBadHeaderException
|
||||||
|
|
||||||
|
|
||||||
|
class WinConnectCryptoNone(WinConnectCryptoBase):
|
||||||
|
def __init__(self): ...
|
||||||
|
def encrypt(self, data: bytes) -> bytes:
|
||||||
|
return data
|
||||||
|
def decrypt(self, data: bytes) -> bytes:
|
||||||
|
return data
|
||||||
|
|
||||||
|
class WinConnectCryptoSimple(WinConnectCryptoBase):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def encrypt(self, data: bytes) -> bytes:
|
||||||
|
shift_key = random.randint(100, 749)
|
||||||
|
key = random.randint(5, 250)
|
||||||
|
encrypted_text = bytearray()
|
||||||
|
header = f"wccs{shift_key}{key+shift_key}:"
|
||||||
|
for char in header:
|
||||||
|
encrypted_text.append(ord(char))
|
||||||
|
for char in data:
|
||||||
|
encrypted_text.append(char ^ key)
|
||||||
|
return bytes(encrypted_text)
|
||||||
|
|
||||||
|
def decrypt(self, data: bytes) -> bytes:
|
||||||
|
try:
|
||||||
|
header, content = data.split(b":", 1)
|
||||||
|
if header[:4] != b"wccs":
|
||||||
|
raise WinConnectCryptoSimpleBadHeaderException("Bad header in message.")
|
||||||
|
except ValueError:
|
||||||
|
raise WinConnectCryptoSimpleBadHeaderException("No header in message.")
|
||||||
|
shift_key = int(header[4:7])
|
||||||
|
key = int(header[7:]) - shift_key
|
||||||
|
decrypted_text = bytearray()
|
||||||
|
for char in content:
|
||||||
|
decrypted_text.append(char ^ key)
|
||||||
|
return bytes(decrypted_text)
|
||||||
|
|
||||||
|
|
||||||
|
class WinConnectCryptoPassword(WinConnectCryptoBase):
|
||||||
|
|
||||||
|
def __init__(self, password: str):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def encrypt(self, data: bytes) -> bytes:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def decrypt(self, data: bytes) -> bytes:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class WinConnectCryptoCert(WinConnectCryptoBase):
|
||||||
|
def __init__(self, cert_file: str):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _open_cert(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def load(self) -> None:
|
||||||
|
self._open_cert()
|
||||||
|
|
||||||
|
def encrypt(self, data: bytes) -> bytes:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def decrypt(self, data: bytes) -> bytes:
|
||||||
|
pass
|
||||||
|
|
||||||
@@ -14,11 +14,13 @@ class WinConnectErrors(Enum):
|
|||||||
BAD_DATA = 50
|
BAD_DATA = 50
|
||||||
BAD_VERSION = 51
|
BAD_VERSION = 51
|
||||||
BAD_HEADER = 52
|
BAD_HEADER = 52
|
||||||
|
BAD_BODY = 53
|
||||||
|
BAD_CRYPTO = 54
|
||||||
|
|
||||||
BODY_TOO_BIG = 60
|
BODY_TOO_BIG = 60
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class WinConnectClientError:
|
class WinConnectError:
|
||||||
code: WinConnectErrors
|
code: WinConnectErrors
|
||||||
message: str
|
message: str
|
||||||
@@ -31,3 +31,26 @@ class WinConnectSessionAlreadyActiveException(WinConnectBaseException): ...
|
|||||||
|
|
||||||
class WinConnectSessionClosedException(WinConnectBaseException): ...
|
class WinConnectSessionClosedException(WinConnectBaseException): ...
|
||||||
|
|
||||||
|
# Crypto
|
||||||
|
|
||||||
|
class WinConnectCryptoException(WinConnectBaseException): ...
|
||||||
|
|
||||||
|
class WinConnectCryptoBadModeException(WinConnectCryptoException): ...
|
||||||
|
|
||||||
|
## Simple
|
||||||
|
|
||||||
|
class WinConnectCryptoSimpleBadHeaderException(WinConnectCryptoException): ...
|
||||||
|
|
||||||
|
## key
|
||||||
|
class WinConnectCryptoKeyRequiredException(WinConnectCryptoException): ...
|
||||||
|
|
||||||
|
class WinConnectCryptoKeyInvalidException(WinConnectCryptoException): ...
|
||||||
|
|
||||||
|
## cert
|
||||||
|
class WinConnectCryptoCertificationRequiredException(WinConnectCryptoException): ...
|
||||||
|
|
||||||
|
class WinConnectCryptoCertificationNotFoundException(WinConnectCryptoException): ...
|
||||||
|
|
||||||
|
class WinConnectCryptoCertificationInvalidException(WinConnectCryptoException): ...
|
||||||
|
|
||||||
|
|
||||||
Reference in new issue
Block a user