Added libs

This commit is contained in:
Lucas
2026-01-25 13:55:46 +10:00
parent 575c682afc
commit f70af3c4ea
229 changed files with 26983 additions and 0 deletions

2
fspn/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
__pycache__
fspn.zip

1
fspn/.mtimes.json Normal file
View File

@@ -0,0 +1 @@
{".gitignore": 1741162475.4773676, "requirements.txt": 1740930861.0004706, "test.py": 1753436830.9918232, "protocol\\connection.py": 1757413256.9977374, "protocol\\security.py": 1757413451.9272285, "protocol\\server.py": 1757831912.1189482, "protocol\\__pycache__\\connection.cpython-311.pyc": 1753509446.7233407, "protocol\\__pycache__\\security.cpython-311.pyc": 1753436646.3835695, "protocol\\__pycache__\\server.cpython-311.pyc": 1739790368.10843, "utils\\aes_util.py": 1739790367.99551, "utils\\ecdh_util.py": 1739790367.9960146, "utils\\ecdsa_util.py": 1741151848.8236935, "utils\\observable.py": 1756021286.9012282, "utils\\sha256_util.py": 1752738996.6411796, "utils\\wrapper_util.py": 1739790368.001054, "utils\\__pycache__\\aes_util.cpython-311.pyc": 1739790368.1195576, "utils\\__pycache__\\aes_util.cpython-313.pyc": 1740069706.9769707, "utils\\__pycache__\\ecdh_util.cpython-311.pyc": 1739790368.1672213, "utils\\__pycache__\\ecdh_util.cpython-313.pyc": 1741381590.6166677, "utils\\__pycache__\\ecdsa_util.cpython-311.pyc": 1741380658.4493158, "utils\\__pycache__\\ecdsa_util.cpython-313.pyc": 1741381591.9633517, "utils\\__pycache__\\observable.cpython-311.pyc": 1753436646.3665586, "utils\\__pycache__\\sha256_util.cpython-311.pyc": 1752742523.9286432, "utils\\__pycache__\\sha256_util.cpython-313.pyc": 1744026927.3028462, "utils\\__pycache__\\wrappers.cpython-311.pyc": 1739790368.1048622, "utils\\__pycache__\\wrapper_util.cpython-311.pyc": 1740064619.98263, "utils\\__pycache__\\wrapper_util.cpython-313.pyc": 1741381591.983756}

5
fspn/info.json Normal file
View File

@@ -0,0 +1,5 @@
{
"id": "fspn",
"version": 0.007,
"modules": []
}

264
fspn/protocol/connection.py Normal file
View File

@@ -0,0 +1,264 @@
from ..utils.observable import Observable
from ..utils.wrapper_util import threaded
from .security import Security
from enum import Enum
import socket
import ipaddress
import struct
import time, datetime
import logging, traceback
import json
import uuid
# TODO Impossible: Hiding ip in a p2p connection hahahahahaha
HEADER_STRUCTURE = '!I?IIb' # size, encrypted, nonce_len, mac_len, is_binary
HEADER_SIZE = struct.calcsize(HEADER_STRUCTURE) # 14 bytes
MAX_CONNECTION_TRIES = 3
class EVENTS(Enum):
ON_CONNECTION = 0
ON_CONNECTION_ERROR = 1
ON_DISCONNECTION = 2
ON_MESSAGE = 3
events = [EVENTS.ON_CONNECTION, EVENTS.ON_CONNECTION_ERROR, EVENTS.ON_DISCONNECTION, EVENTS.ON_MESSAGE]
class STATUS(Enum):
DISCONNECTED = 0
CONNECTED = 1
CONNECTING = 2
HANDSHAKING = 3
ERROR = -1
class Connection(Observable):
def __init__(self, user, pmc, conn=None):
super().__init__(events)
self.security = Security(user, pmc)
self.status = STATUS.DISCONNECTED
self.address = None
self.hostname = None
self.bind_address = None
self.conn = conn
if conn:
self.set_addresses()
self.id = str(uuid.uuid4())
self.handshake_payload = None
def set_addresses(self, address=None):
if address:
self.address = address
host, port = address
try:
ipaddress.ip_address(host)
except ValueError:
self.hostname = host
else:
self.address = self.conn.getpeername()
self.bind_address = self.conn.getsockname()
@threaded
def connect(self, address, bind_address=('0.0.0.0', 0)):
self.set_addresses(address)
self.bind_address = bind_address
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s.bind(bind_address)
s.settimeout(10)
self.conn = s
except Exception:
self.status = STATUS.ERROR
self.fire_event(EVENTS.ON_CONNECTION_ERROR, error="Error to setup connection")
raise
self.status = STATUS.CONNECTING
logging.info(f'Socket trying to connect: {self.bind_address} -> {address}')
for i in range(MAX_CONNECTION_TRIES):
try:
s.settimeout(None)
self.conn = s
self.bind_address = s.getsockname()
s.connect(address)
self.address = s.getpeername()
break
except Exception as e:
logging.exception("ERROR")
if i < MAX_CONNECTION_TRIES - 1:
continue
else:
self.status = STATUS.ERROR
self.fire_event(EVENTS.ON_CONNECTION_ERROR, error=f"No connection could be made in {MAX_CONNECTION_TRIES} retries: {e}")
raise
self.new_connection()
def new_connection(self):
self.handshake_create_payload()
def handshake_create_payload(self):
self.status = STATUS.HANDSHAKING
logging.info(f'Socket handshaking: {self.bind_address} -> {self.address}')
my_ecdsa_str = self.security.user
my_proof_of_work = self.security.proof_of_work
my_ecdh_pk = self.security.ecdh.public_key_to_str()
date = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
self.handshake_payload = {'ecdsa':my_ecdsa_str, 'pof':my_proof_of_work, 'ecdh':my_ecdh_pk, 'date':date}
payload = {'ecdsa':my_ecdsa_str, 'pof':my_proof_of_work, 'ecdh':my_ecdh_pk, 'date':date}
request_id = self.security.sign_message_ecdsa(json.dumps(payload), self.payload_signature_callback, "Handshake Connection")
self.wait_signature()
@threaded
def wait_signature(self):
# TODO Config this time as security time validation
time.sleep(120)
if self.status == STATUS.HANDSHAKING:
logging.info(f"Closing connection, payload signature time exceded")
self.status = STATUS.DISCONNECTED
self.fire_event(EVENTS.ON_CONNECTION_ERROR, error="Payload signature time exceded")
self.close_connection()
def payload_signature_callback(self, request_id, signature):
if self.status != STATUS.HANDSHAKING:
logging.info(f"Not using signature, connection is closed")
return None
if signature:
self.handshake_payload['signature'] = signature
self.send_message(json.dumps(self.handshake_payload), False)
while self.status == STATUS.HANDSHAKING:
message = self.message_reader()["data"]
logging.error
if(message):
payload = json.loads(message)
payload_signed = payload.copy()
payload_signed.pop('signature')
self.security.handshake_validation(payload['ecdsa'], json.dumps(payload_signed), payload['signature'], payload['ecdh'], payload['pof'], payload['date'])
self.status = STATUS.CONNECTED
logging.info(f'Ready: {self.bind_address} -> {self.address}')
self.fire_event(EVENTS.ON_CONNECTION)
self.wait_message()
else:
self.status = STATUS.DISCONNECTED
self.fire_event(EVENTS.ON_CONNECTION_ERROR, error="Payload signature is None")
self.close_connection()
@threaded
def wait_message(self):
while self.status == STATUS.CONNECTED:
try:
message = self.message_reader()
except socket.timeout as to:
logging.exception("ERROR")
continue
except (ConnectionAbortedError, EOFError, ConnectionResetError, OSError):
# TODO Maybe try to reconnect
self.status = STATUS.DISCONNECTED
self.fire_event(EVENTS.ON_DISCONNECTION)
break
except Exception as e:
logging.exception("ERROR")
self.status = STATUS.DISCONNECTED
self.fire_event(EVENTS.ON_DISCONNECTION)
break
try:
if(message):
# logging.debug(message)
self.fire_event(EVENTS.ON_MESSAGE, message=message)
except Exception as e:
logging.error(traceback.format_exc())
def close_connection(self):
logging.info(f'Socket closed: {self.address}')
self.conn.close()
self.status = STATUS.DISCONNECTED
self.fire_event(EVENTS.ON_DISCONNECTION)
@threaded
def send_binary(self, data: bytes, meta: dict = None, encrypted=True):
meta_json = json.dumps(meta or {})
meta_encoded = meta_json.encode('utf-8')
meta_len_bytes = struct.pack('!I', len(meta_encoded))
full_payload = meta_len_bytes + meta_encoded + data
nonce = b''
mac = b''
if encrypted:
nonce, full_payload, mac = self.security.encrypt_message(full_payload)
message_header = struct.pack(
HEADER_STRUCTURE,
len(nonce) + len(mac) + len(full_payload),
encrypted,
len(nonce),
len(mac),
1 # is_binary = True
)
self.conn.sendall(message_header + nonce + mac + full_payload)
@threaded
def send_message(self, message: str, encrypted=True):
nonce = b''
mac = b''
meta = b''
encoded_msg = message.encode('utf-8')
if encrypted:
nonce, encoded_msg, mac = self.security.encrypt_message(encoded_msg)
message_header = struct.pack(
HEADER_STRUCTURE,
len(nonce) + len(mac) + len(meta) + len(encoded_msg),
encrypted,
len(nonce),
len(mac),
0 # is_binary = False
)
self.conn.sendall(message_header + nonce + mac + encoded_msg)
def message_reader(self):
message_header = self.recv_all(HEADER_SIZE)
if not message_header:
self.close_connection()
return None
total_len, encrypted, nonce_len, mac_len, is_binary = struct.unpack(HEADER_STRUCTURE, message_header)
data = self.recv_all(total_len)
if encrypted:
nonce = data[:nonce_len]
mac = data[nonce_len:nonce_len + mac_len]
payload = data[nonce_len + mac_len:]
decrypted = self.security.decrypt_message(nonce, payload, mac)
else:
decrypted = data
if is_binary:
meta_length = struct.unpack('!I', decrypted[:4])[0]
meta_raw = decrypted[4:4 + meta_length]
meta = json.loads(meta_raw)
file_data = decrypted[4 + meta_length:]
return {"meta": meta, "data": file_data}
else:
return {"data": decrypted.decode('utf-8')}
def recv_all(self, n: int) -> bytes:
buffer = b''
while len(buffer) < n:
chunk = self.conn.recv(n - len(buffer))
if not chunk:
raise ConnectionError("Connection closed before receive all bytes")
buffer += chunk
return buffer

112
fspn/protocol/security.py Normal file
View File

@@ -0,0 +1,112 @@
from ..utils.observable import Observable
from ..utils.wrapper_util import singleton
from ..utils import sha256_util, aes_util, ecdh_util, ecdsa_util
import base64
import logging
import importlib
# class EcdsaKey:
# def __init__(self) -> None:
# self.verifying:ecdsa_util.VerifyingKey = None
# self.signing:ecdsa_util.SigningKey = None
# def create_key_from_string(self, password:str):
# self.verifying, self.signing = ecdsa_util.create_keys(password.encode())
# def create_key_from_bytes(self, password:bytes):
# self.verifying, self.signing = ecdsa_util.create_keys(password)
# def load_verifying(self, key:str):
# self.verifying = ecdsa_util.load_verifying_key(base64.b64decode(key.encode()))
# def verifying_key_to_str(self):
# return base64.b64encode(self.verifying.to_string('compressed')).decode()
class UserData:
def __init__(self):
self.proof_of_work = None
# Password Manager Client
class Pmc:
def raiseException(self):
raise Exception("Missing Password Manager Client")
def get(self, user) -> UserData:
self.raiseException()
# Returns a request_id. Callback receives str:request_id str:signature
def sign(self, data, user, callback, info=None) -> str:
self.raiseException()
class EcdhKey:
def __init__(self):
self.public, self.private = ecdh_util.generate_keys()
self.derived_key = None
def generate_derived_key(self, peer_key:str):
ecdh_pk = ecdh_util.load_public_key_str(peer_key, True)
shared_key = ecdh_util.generate_shared_key(self.private, ecdh_pk)
self.derived_key = ecdh_util.generate_derived_key(shared_key)
def update_derived_key(self):
self.derived_key = ecdh_util.generate_derived_key(self.derived_key)
def public_key_to_str(self):
return ecdh_util.public_key_to_str(self.public, True)
class Security():
def __init__(self, user, pmc:Pmc):
self.pmc = pmc
self.user = user
self.proof_of_work = self.pmc.get(user).proof_of_work
self.peer_user = None
self.peer_ecdsa = None
self.ecdh = EcdhKey()
self.peer_pof_level = None
self.min_proof_of_work_level = 4
def encrypt_message(self, message:bytes):
return aes_util.encrypt(message, self.ecdh.derived_key)
def decrypt_message(self, nonce:bytes, message:bytes, mac:bytes):
return aes_util.decrypt_and_verify(nonce, message, mac, self.ecdh.derived_key)
def sign_message_ecdsa(self, message:str, callback, info=None):
hash_message = sha256_util.hash_string(message)
return self.pmc.sign(hash_message, self.user, callback, info)
# return base64.b64encode(ecdsa_util.sign_message(message, self.my_ecdsa.signing)).decode()
def check_signature_ecdsa(self, message:str, signature:str):
hash_message = sha256_util.hash_string(message)
return ecdsa_util.verify_message(hash_message.encode(), base64.b64decode(signature.encode()), self.peer_ecdsa)
def check_signature_ecdsa_vk(self, verifying_key:str, message:str, signature:str):
hash_message = sha256_util.hash_string(message)
return ecdsa_util.verify_message(hash_message.encode(), base64.b64decode(signature.encode()), ecdsa_util.load_verifying_key(base64.b64decode(verifying_key.encode())))
# def encrypt_message_ecdsa(self, message:str):
# encrypted = ecdsa_util.encrypt_message(base64.b64decode(self.peer_ecdsa.verifying_key_to_str().encode()), message.encode())
# return base64.b64encode(encrypted).decode()
# def decrypt_message_ecdsa(self, message:str):
# return ecdsa_util.decrypt_message(self.my_ecdsa.signing.to_string(), base64.b64decode(message.encode()))
def verify_proof_of_work(self, ecdsa:str, proof_of_work:str):
hash = sha256_util.hash_string(f'{ecdsa}{proof_of_work}')
logging.debug(f'ECDSA {ecdsa}, POF {proof_of_work}, HASH {hash}')
if hash[0:self.min_proof_of_work_level] != "0"*self.min_proof_of_work_level:
raise Exception(f'Proof of work below minimum level {self.min_proof_of_work_level}')
# TODO validate date/time
def handshake_validation(self, peer_ecdsa, payload, payload_signature, ecdh, proof_of_work, date):
self.peer_user = peer_ecdsa
self.peer_ecdsa = ecdsa_util.load_verifying_key(base64.b64decode(peer_ecdsa.encode()))
self.check_signature_ecdsa(payload, payload_signature)
self.verify_proof_of_work(peer_ecdsa, proof_of_work)
self.ecdh.generate_derived_key(ecdh)

74
fspn/protocol/server.py Normal file
View File

@@ -0,0 +1,74 @@
from ..utils.observable import Observable, Event as ObservableEvent
from ..utils.wrapper_util import threaded
from .connection import Connection, EVENTS as CONNECTION_EVENTS
from enum import Enum
import logging, traceback
import socket
import random
class EVENTS(Enum):
ON_START = 0
ON_START_ERROR = 1
ON_CONNECTION = 2
ON_CONNECTION_ERROR = 3
ON_DISCONNECTION = 4
ON_MESSAGE = 5
class Server(Observable):
def __init__(self):
super().__init__()
self.connections:dict[tuple[str,int],Connection] = {}
self.bind_address = None
self.running = False
self.user = None
@threaded
def run(self, user, pmc, bind_address = ('127.0.0.1', random.randint(5000, 5999))):
try:
self.user = user
if not bind_address:
self.bind_address = ('127.0.0.1', random.randint(5000, 5999))
else:
self.bind_address = bind_address
logging.info(f"Starting server on address {self.bind_address}")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(self.bind_address)
s.settimeout(10)
s.listen(5)
self.running = True
self.fire_event(EVENTS.ON_START)
logging.info(f"Listening on {self.bind_address}")
while True:
try:
conn, addr = s.accept()
logging.info(f"Incoming connection: {addr}")
connection = Connection(user, pmc, conn)
connection.subscribe_event(CONNECTION_EVENTS.ON_CONNECTION, self.on_server_connection)
connection.subscribe_event(CONNECTION_EVENTS.ON_MESSAGE, self.on_server_message)
connection.subscribe_event(CONNECTION_EVENTS.ON_DISCONNECTION, self.on_server_disconnection)
self.connections[addr] = connection
self.connections[addr].new_connection()
except socket.timeout:
continue
except Exception:
logging.error("ERROR")
conn.close()
except Exception as e:
logging.error("ERROR")
self.fire_event(EVENTS.ON_START_ERROR, error=e)
def on_server_connection(self, event:ObservableEvent):
pass
def on_server_message(self, event):
pass
def on_server_disconnection(self, event):
pass

3
fspn/requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
pycryptodome
cryptography
ecdsa

78
fspn/test.py Normal file
View File

@@ -0,0 +1,78 @@
import os, sys
root_dir = os.path.normpath(__file__.split("libs")[0])
sys.path.append(root_dir)
from libs.fspn.protocol.connection import Connection, EVENTS
from libs.fspn.utils import sha256_util, aes_util, ecdh_util, ecdsa_util
from libs.fspn.utils.wrapper_util import singleton, threaded
import base64, time
class UserData:
def __init__(self):
self.proof_of_work = None
class Pmc:
def __init__(self):
self.verifying_key, self.signing_key = ecdsa_util.create_keys(base64.b64decode("I0x1Y2FzR2FicmllbFZhekRvc1NhbnRvc0luYWNpbyE="))
def get(self, user) -> UserData:
user_data = UserData()
user_data.proof_of_work = "eYnU*@"
return user_data
# Returns a request_id. Callback receives str:request_id str:signature
def sign(self, data, user, callback) -> str:
self.send_callback("test", callback, data)
return "test"
def send_callback(self, request_id, callback, data):
signature = ecdsa_util.sign_message(data, self.signing_key)
signature = base64.b64encode(signature).decode()
callback(request_id, signature)
class Test:
def __init__(self):
pass
def test(self):
pmc = Pmc()
c1 = Connection("A4DZSk+TlR+4w39MbiIAQbti+N0H1QlJEhRH2DI6Iubj", pmc)
c2 = Connection("A4DZSk+TlR+4w39MbiIAQbti+N0H1QlJEhRH2DI6Iubj", pmc)
p1= 5676
p2 = 5686
c1.connect(("127.0.0.1", p1), ("127.0.0.1", p2))
c2.connect(("127.0.0.1", p2), ("127.0.0.1", p1))
c1.subscribe_event(EVENTS.ON_MESSAGE, self.on_message_1)
c2.subscribe_event(EVENTS.ON_MESSAGE, self.on_message_2)
time.sleep(2)
c1.send_message("Testing", True)
c1.send_binary(data=b"Test", meta={"test":"test"}, encrypted=True)
time.sleep(2)
c1.close_connection()
c2.close_connection()
def on_message_1(self, event):
print("C1 got message: ",event.__dict__)
def on_message_2(self, event):
print("C2 got message: ",event.__dict__)
import logging
import sys
logging.basicConfig(
level=logging.DEBUG,
format='[%(levelname)s] %(asctime)s - %(message)s',
stream=sys.stdout
)
t = Test()
t.test()

17
fspn/utils/aes_util.py Normal file
View File

@@ -0,0 +1,17 @@
from Crypto.Cipher import AES
def encrypt(data:bytes, key:bytes):
cipher = AES.new(key, AES.MODE_EAX)
nonce = cipher.nonce
ciphertext, mac = cipher.encrypt_and_digest(data)
return nonce, ciphertext, mac
def decrypt_and_verify(nonce:bytes, data:bytes, mac:bytes, key:bytes):
cipher = AES.new(key, AES.MODE_EAX, nonce=nonce)
plaintext = cipher.decrypt(data)
try:
cipher.verify(mac)
except ValueError:
return None
return plaintext

36
fspn/utils/ecdh_util.py Normal file
View File

@@ -0,0 +1,36 @@
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives.serialization import PublicFormat, Encoding, load_pem_public_key
def generate_keys():
private_key = ec.generate_private_key(
ec.SECP384R1()
)
public_key = private_key.public_key()
return public_key, private_key
def generate_shared_key(private_key:ec.EllipticCurvePrivateKey, public_key:ec.EllipticCurvePublicKey):
shared_key = private_key.exchange(ec.ECDH(), public_key)
return shared_key
def generate_derived_key(shared_key:bytes):
derived_key = HKDF(
algorithm=hashes.SHA256(),
length=32,
salt=None,
info=None,
).derive(shared_key)
return derived_key
def public_key_to_str(public_key:ec.EllipticCurvePublicKey, remove_header_and_footer=False):
public_key_str = public_key.public_bytes(Encoding.PEM, PublicFormat.SubjectPublicKeyInfo).decode()
if(remove_header_and_footer):
public_key_str = public_key_str.replace('-----BEGIN PUBLIC KEY-----\n','')
public_key_str = public_key_str.replace('\n-----END PUBLIC KEY-----\n','')
return public_key_str
def load_public_key_str(public_key_str:str, removed_header_and_footer=False):
if(removed_header_and_footer):
public_key_str = f'-----BEGIN PUBLIC KEY-----\n{public_key_str}\n-----END PUBLIC KEY-----\n'
return load_pem_public_key(public_key_str.encode())

62
fspn/utils/ecdsa_util.py Normal file
View File

@@ -0,0 +1,62 @@
from ecdsa import SigningKey, VerifyingKey, SECP256k1, keys
from hashlib import sha256
# from ecies import encrypt, decrypt
def create_keys(password:bytes) -> tuple[VerifyingKey, SigningKey]: # type: ignore
privateKey = SigningKey.from_string(password, curve=SECP256k1)
publicKey:VerifyingKey = privateKey.get_verifying_key()
return (publicKey, privateKey)
def create_pem(fullpath, privateKey:SigningKey, publicKey:VerifyingKey):
with open(fullpath+"privateKey.pem", "wb") as f:
f.write(privateKey.to_pem(format="pkcs8"))
with open(fullpath+"publicKey.pem", "wb") as f:
f.write(publicKey.to_pem())
def read_pem(fullpath):
with open(fullpath+"privateKey.pem") as f:
privateKey = SigningKey.from_pem(f.read())
with open(fullpath+"publicKey.pem") as f:
publicKey = VerifyingKey.from_pem(f.read())
return (privateKey, publicKey)
def sign_message(message:str, privateKey:SigningKey) -> bytes:
return privateKey.sign(message.encode('utf-8'), hashfunc=sha256)
def load_signing_key(signing_key:bytes) -> SigningKey:
return SigningKey.from_string(signing_key, curve=SECP256k1, hashfunc=sha256)
def get_verifying_key(signing_key:SigningKey) -> VerifyingKey:
return signing_key.get_verifying_key()
def load_verifying_key(verifying_key:bytes) -> VerifyingKey:
return VerifyingKey.from_string(verifying_key, curve=SECP256k1, hashfunc=sha256)
def verify_message(message:bytes, signature:bytes, publicKey:VerifyingKey) -> bool:
try:
return publicKey.verify(signature, message, hashfunc=sha256)
except keys.BadSignatureError:
return False
# ecdsa_vk.to_string('compressed') or vk_bytes
# def encrypt_message(verifying_key:bytes, message:bytes):
# return encrypt(verifying_key, message)
# ecdsa_sk.to_string() or sk_bytes
# def decrypt_message(signing_key:bytes, message:bytes):
# return decrypt(signing_key, message)
# password = b'#LucasGabrielVazDosSantosInacio!'
# vk,sk = create_keys(password)
# import base64
# print(base64.b64encode(vk.to_string('compressed')).decode())
# pk ='AuWgGLOi4VUxYQnZzcXqtzl1nA4H4MAL+fzLgjf+TX8C'
# message= '{"text":"Hello","public_key":"AuWgGLOi4VUxYQnZzcXqtzl1nA4H4MAL+fzLgjf+TX8C","pof":"69201","signature":null,"files":[],"networks":["000"],"datetime":"2024-10-06T07:08:30.419000Z","parents":[]}'
# sig = 'dRAyr67oZXblKEqS9EpghhS7mbl1DOoqCF8n8krQ2KsTcV9VRK6Hc4O2A27WkdjW2ZEaalp2PbPd1ZamAMJJ/A=='
# pk = load_verifying_key(base64.b64decode(pk))
# sig = base64.b64decode(sig)
# print(verify_message(message.encode(), sig, pk))

44
fspn/utils/observable.py Normal file
View File

@@ -0,0 +1,44 @@
from .wrapper_util import threaded
import logging, traceback
class Event(object):
def __init__(self):
self.source = self
class Observable(object):
"""
A simple publish-subscribe system.
"""
def __init__(self, events = []):
self.events: dict[str, list] = {}
for event in events:
self.register_event(event)
def register_event(self, event):
if(event not in self.events):
self.events[event] = []
def subscribe_event(self, event, callback):
if(event not in self.events):
self.register_event(event)
self.events[event].append(callback)
@threaded
def fire_event(self, event, **kwargs):
e = Event()
e.source = self
for k, v in kwargs.items():
setattr(e, k, v)
if(event in self.events):
for fn in self.events[event]:
self.call_observer(fn, e)
else:
logging.warning(f"Event {event} without callback")
@threaded
def call_observer(self, function, event):
try:
function(event)
except Exception as ex:
logging.exception(f'Error in event {event} to function {function.__name__}')

67
fspn/utils/sha256_util.py Normal file
View File

@@ -0,0 +1,67 @@
import hashlib
def hash_file(filepath):
BUF_SIZE = 65 * 1024
sha = hashlib.sha256()
with open(filepath, 'rb') as f:
while True:
data = f.read(BUF_SIZE)
if not data:
break
sha.update(data)
return sha.hexdigest()
def hash_bytes(data):
sha = hashlib.sha256()
sha.update(data)
return sha.hexdigest()
def hash_string(data:str):
sha = hashlib.sha256()
sha.update(str(data).encode('utf-8'))
return sha.hexdigest()
# ---------------
import datetime
import string
import itertools
import random
def get_nonce(characters, lenght):
yield from itertools.product(*([characters] * lenght))
def count_leading_zeros(text):
n = 0
for i in range(len(text)):
if text[:i] == "0" * i:
n = i
else:
break
return n
def mine_user(data, force=4, nonce_lenght=4):
characters = '[@_!#$%^&*()<>?/\|}{~:]'+string.ascii_letters+string.digits
while True:
for x in get_nonce(characters, nonce_lenght):
nonce = ''.join(x)+random.choice(characters)
hash = hash_string(data+ nonce)
leading_zeros = count_leading_zeros(hash)
if leading_zeros >= force:
return nonce
def test():
print(datetime.datetime.now(), "EXECUTING HASH TEST - MINE USER")
public_key_str = "A4DZSk+TlR+4w39MbiIAQbti+N0H1QlJEhRH2DI6Iubj"
nonce, hash = mine_user(public_key_str)
print(nonce, hash)
# test()
# A4DZSk+TlR+4w39MbiIAQbti+N0H1QlJEhRH2DI6Iubj
# 8
# eYnU*@
# [/Q#7r

View File

@@ -0,0 +1,19 @@
import functools
from threading import Thread
def threaded(fn):
"""Decorator to automatically launch a function in a thread"""
@functools.wraps(fn)
def wrapper(*args, **kwargs):
thread = Thread(target=fn, args=args, kwargs=kwargs)
thread.start()
return thread
return wrapper
def singleton(cls):
instances = {}
def getinstance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return getinstance