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
api/.gitignore vendored Normal file
View File

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

1
api/.mtimes.json Normal file
View File

@@ -0,0 +1 @@
{".gitignore": 1741162450.0110252, "api.py": 1757749878.4958198, "apiBlueprint.py": 1757238077.9332085, "certs.py": 1757228708.4552765, "config.json": 1756001769.9660056, "eventsSocketio.py": 1757328543.5948038, "requirements.txt": 1766641471.4877045, "__pycache__\\api.cpython-311.pyc": 1739790368.2421517}

110
api/api.py Normal file
View File

@@ -0,0 +1,110 @@
import os
from pathlib import Path
from flask import Flask, Blueprint, request, send_from_directory, jsonify
from flask_cors import CORS, cross_origin
from flask_socketio import SocketIO, Namespace
from libs.app.common.logging import get_logger
from libs.app.common.paths import ROOT_DIR
from libs.fspn.utils.wrapper_util import threaded
from .apiBlueprint import ApiBlueprint
from .eventsSocketio import EventsSocketio
from libs.noSys.noSysModule import NoSysModule
from .certs import generate_ca_and_cert, add_ca_os
logger = get_logger()
class Api(NoSysModule):
def __init__(self, nosys_core):
super().__init__(nosys_core)
self.dist_dir = os.path.join(ROOT_DIR, "libs/vueNoSys/dist")
self.assets_dir = os.path.join(self.dist_dir, "assets")
self.app = Flask(__name__, static_folder=self.assets_dir, template_folder=self.dist_dir)
CORS(self.app, resources={r"/*": {"origins": "*"}}, supports_credentials=True)
self.socketio = SocketIO(self.app, cors_allowed_origins="*")
self.server = None
self.host = self.config["server"]["host"]
self.port = self.config["server"]["port"]
self.register_blueprint(BasicBlueprint(self).blueprint)
self.register_socketio(BasicEventSocketIo(self))
def setup(self):
self.nosys_core.modules.api = self
certs_path = os.path.join(ROOT_DIR, "libs", "api", "certs")
self.ca_path = os.path.join(certs_path , "ca.pem")
self.ca_key_path = os.path.join(certs_path, "ca_key.pem")
self.cert_path = os.path.join(certs_path, "cert.pem")
self.key_path = os.path.join(certs_path, "key.pem")
if not os.path.exists(self.cert_path) or not os.path.exists(self.key_path) or not os.path.exists(self.ca_path) or not os.path.exists(self.ca_key_path):
Path(certs_path).mkdir(parents=True, exist_ok=True)
logger.debug("Generating certs")
ca, cert, key = generate_ca_and_cert(self.ca_path, self.ca_key_path, self.cert_path, self.key_path)
logger.debug("Adding ca to operational system")
add_ca_os(self.ca_path)
logger.debug("Cert installed")
else:
logger.debug("Certs already exists")
def register_blueprint(self, blueprint:Blueprint):
try:
self.app.register_blueprint(blueprint)
logger.debug(f"Registered blueprint {blueprint.url_prefix}")
except Exception:
logger.exception(f"Failed registering blueprint {blueprint.url_prefix}")
def register_socketio(self, handler:EventsSocketio):
try:
handler.register_events(self.socketio)
logger.debug(f"Registered socketio {handler.namespace}")
except Exception:
logger.exception(f"Failed registering socketio {handler.namespace}")
def on_nosys_ready(self, event):
self.run()
@threaded
def run(self):
self.routes()
logger.debug(f'Running Flask API ({self.host}:{self.port}) with urls: {self.app.url_map}')
try:
self.socketio.run(app=self.app, host=self.host, port=self.port, allow_unsafe_werkzeug=True, ssl_context=(self.cert_path, self.key_path))
except Exception as e:
logger.error(e)
def routes(self):
@self.app.route("/", defaults={"path": ""})
@self.app.route("/<path:path>")
def index(path):
if path != "" and os.path.exists(os.path.join(self.dist_dir, path)):
return send_from_directory(self.dist_dir, path)
return send_from_directory(self.dist_dir, "index.html")
class BasicBlueprint(ApiBlueprint):
def routes(self):
self.api:Api = self.module
@self.blueprint.route('/')
def show():
return "API"
class BasicEventSocketIo(EventsSocketio):
def events(self):
@self.on("connect")
def on_connect(*args, **kwargs):
print('API connected',args, kwargs, request.sid)
self.emit("welcome", {"msg": f"Your id {request.sid}"})
@self.on("disconnect")
def on_disconnect(*args, **kwargs):
print('API disconnected',args, kwargs, request.sid)
@self.on("message")
def on_message(*args, **kwargs):
print('API Message',args, kwargs)
self.emit("message", f"Message received {args[0]}")

26
api/apiBlueprint.py Normal file
View File

@@ -0,0 +1,26 @@
from flask import Blueprint, jsonify
from libs.noSys.noSysModule import NoSysModule
from libs.noSys.events import Events
from flask_socketio import SocketIO
class ApiBlueprint():
def __init__(self, nosys_module:NoSysModule):
self.module = nosys_module
self.blueprint = Blueprint(self.module.name, __name__, url_prefix='/api/'+self.module.package_id)
self.default_routes()
self.routes()
def default_routes(self):
@self.blueprint.route('/health')
def health_check():
body = {"package":self.module.package_id, "moduleName":self.module.module_id}
return jsonify(body)
@self.blueprint.route('/config')
def config():
body = self.module.nosys_core.config.get(self.module.package_id)
return jsonify(body)
def routes(self):
pass

115
api/certs.py Normal file
View File

@@ -0,0 +1,115 @@
import os
import webview
import ssl
import ipaddress
import pathlib
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from datetime import datetime, timedelta
import os
import platform
import subprocess
def generate_ca_and_cert(ca_path="ca.pem", ca_key_path="ca_key.pem",
cert_path="cert.pem", key_path="key.pem"):
ca_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
ca_subject = x509.Name([
x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"NoSys-CA"),
x509.NameAttribute(NameOID.COMMON_NAME, u"NoSys Local CA"),
])
ca_cert = (
x509.CertificateBuilder()
.subject_name(ca_subject)
.issuer_name(ca_subject)
.public_key(ca_key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(datetime.utcnow())
.not_valid_after(datetime.utcnow() + timedelta(days=3650))
.add_extension(
x509.BasicConstraints(ca=True, path_length=None), critical=True,
)
.sign(ca_key, hashes.SHA256())
)
with open(ca_path, "wb") as f:
f.write(ca_cert.public_bytes(serialization.Encoding.PEM))
with open(ca_key_path, "wb") as f:
f.write(ca_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
))
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
subject = x509.Name([
x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"NoSys"),
x509.NameAttribute(NameOID.COMMON_NAME, u"localhost"),
])
cert = (
x509.CertificateBuilder()
.subject_name(subject)
.issuer_name(ca_subject)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(datetime.utcnow())
.not_valid_after(datetime.utcnow() + timedelta(days=3650))
.add_extension(
x509.SubjectAlternativeName([
x509.DNSName(u"localhost"),
x509.IPAddress(ipaddress.IPv4Address("127.0.0.1"))]),
critical=False,
)
.sign(ca_key, hashes.SHA256())
)
with open(cert_path, "wb") as f:
f.write(cert.public_bytes(serialization.Encoding.PEM))
with open(key_path, "wb") as f:
f.write(key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
))
return ca_path, cert_path, key_path
def add_ca_os(ca_path="ca.pem"):
system = platform.system()
if system == "Windows":
add_ca_windows(ca_path)
elif system == "Darwin":
add_ca_macos(ca_path)
elif system == "Linux":
add_ca_linux(ca_path)
else:
raise Exception("Operational system not supported")
def add_ca_windows(ca_path="ca.pem"):
subprocess.run([
"powershell",
"-Command",
f'Import-Certificate -FilePath "{os.path.abspath(ca_path)}" -CertStoreLocation Cert:\\CurrentUser\\Root'
], check=True)
def add_ca_macos(ca_path="ca.pem"):
subprocess.run([
"sudo",
"security",
"add-trusted-cert",
"-d",
"-r", "trustRoot",
"-k", "/Library/Keychains/System.keychain",
os.path.abspath(ca_path)
], check=True)
def add_ca_linux(ca_path="ca.pem"):
import shutil
dest = "/usr/local/share/ca-certificates/zecho-ca.crt"
shutil.copy(os.path.abspath(ca_path), dest)
subprocess.run(["sudo", "update-ca-certificates"], check=True)

6
api/config.json Normal file
View File

@@ -0,0 +1,6 @@
{
"server": {
"host": "127.0.0.1",
"port": "5050"
}
}

51
api/eventsSocketio.py Normal file
View File

@@ -0,0 +1,51 @@
from datetime import datetime
import time
from flask import Blueprint, make_response, request, jsonify, session, has_request_context
from flask_socketio import SocketIO, Namespace, emit, send, join_room, leave_room
from libs.noSys.noSysModule import NoSysModule
class EventsSocketio():
def __init__(self, module:NoSysModule):
self.module = module
self.namespace = f"/ws/{self.module.name}"
self.socketio:SocketIO = None
def register_events(self, socketio:SocketIO):
self.socketio = socketio
self.default_events()
self.events()
def default_events(self):
@self.socketio.on("health", namespace=self.namespace)
def on_health(*args, **kwargs):
self.emit("health", {"status": "ok"})
@self.socketio.on("ping", namespace=self.namespace)
def on_ping(data=None):
self.emit("pong", {"ts": time.time(), "echo": data})
def emit(self, event:str, data=None, room=None, **kwargs):
target = None
if room:
target = room
elif has_request_context():
target = request.sid
self.socketio.emit(event, data, to=target, namespace=self.namespace, **kwargs)
def on(self, event: str):
def decorator(handler):
@self.socketio.on(event, namespace=self.namespace)
def wrapper(*args, **kwargs):
try:
return handler(*args, **kwargs)
except Exception as e:
self.error(str(e))
return wrapper
return decorator
def events(self):
pass

10
api/info.json Normal file
View File

@@ -0,0 +1,10 @@
{
"id": "api",
"version": 0.042,
"modules": [
{
"id": "api",
"version": 0
}
]
}

4
api/requirements.txt Normal file
View File

@@ -0,0 +1,4 @@
flask
flask-socketio
python-socketio[client]
flask_cors