diff --git a/.gitmodules b/.gitmodules index cbed4d8..1f804fd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "pycapnp"] - path = pycapnp - url = https://github.com/capnproto/pycapnp.git [submodule "schema"] path = schema url = https://gitlab.com/fabinfra/fabaccess/fabaccess-api diff --git a/fabapi/__init__.py b/fabapi/__init__.py index fa939b8..aceaf47 100644 --- a/fabapi/__init__.py +++ b/fabapi/__init__.py @@ -1 +1 @@ -from .connect import connect +from .connect import connect, connect_with_fabfire_initial, connect_with_fabfire_step \ No newline at end of file diff --git a/fabapi/connect.py b/fabapi/connect.py index 079df6c..81b8ff1 100644 --- a/fabapi/connect.py +++ b/fabapi/connect.py @@ -1,11 +1,12 @@ import asyncio import socket import ssl - import capnp + connection_capnp = capnp.load('schema/connection.capnp') authenticationsystem_capnp = capnp.load('schema/authenticationsystem.capnp') + async def myreader(client, reader): while True: data = await reader.read(4096) @@ -18,6 +19,7 @@ async def mywriter(client, writer): writer.write(data.tobytes()) await writer.drain() + async def connect(host, port, user, pw): # Setup SSL context ctx = ssl.create_default_context( @@ -55,3 +57,60 @@ async def connect(host, port, user, pw): else: print("Auth failed") return None + + +async def connect_with_fabfire_initial(host, port, uid): + # Setup SSL context + ctx = ssl.create_default_context( + ssl.Purpose.SERVER_AUTH + ) + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + + # Handle both IPv4 and IPv6 cases + try: + reader, writer = await asyncio.open_connection( + host, port, ssl=ctx, family=socket.AF_INET6 + ) + except Exception: + reader, writer = await asyncio.open_connection( + host, port, ssl=ctx, family=socket.AF_INET + ) + + # Start TwoPartyClient using TwoWayPipe (takes no arguments in this mode) + client = capnp.TwoPartyClient() + cap = client.bootstrap().cast_as(connection_capnp.Bootstrap) + + # Assemble reader and writer tasks, run in the background + coroutines = [myreader(client, reader), mywriter(client, writer)] + asyncio.gather(*coroutines, return_exceptions=True) + + auth = cap.authenticationSystem().authenticationSystem + req = auth.start_request() + req.request.mechanism = "X-FABFIRE" + req.request.initialResponse.initial = uid + rep_prom = req.send() + response = await rep_prom.a_wait() + print(response.response.which()) + if response.response.which() == "challence": + print(f"challenge: {response.response.challence}") + return auth, response.response.challence, cap + else: + print(f"Auth failed: {response.response.outcome.result}, additional info: {response.response.outcome.helpText}") + return None + + +async def connect_with_fabfire_step(auth, msg): + req = auth.step_request() + req.response = msg + rep_prom = req.send() + response = await rep_prom.a_wait() + if response.response.which() == "challence": + print(f"challenge: {response.response.challence}") + return response.response.challence, False # auth cap, challenge, not done + elif response.response.outcome.result == "successful": + print(f"Auth completed successfully! Got additional Data: {response.response.outcome.additionalData.additional}") + return response.response.outcome.additionalData.additional, True # dont care, message, we are done + else: + print(f"Auth failed: {response.response.outcome.result}, additional info: {response.response.outcome.helpText}") + return None diff --git a/pycapnp b/pycapnp deleted file mode 160000 index 5dade41..0000000 --- a/pycapnp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5dade41aebcee627ef65e4f3471d7568dcd7a5e2 diff --git a/schema b/schema index c855646..18ed9c2 160000 --- a/schema +++ b/schema @@ -1 +1 @@ -Subproject commit c855646a90958ae575d58be074d187acb9f8f4fa +Subproject commit 18ed9c2ae6a221f57d19e255165c7ebc4508e9af diff --git a/single.py b/single.py new file mode 100644 index 0000000..6d62675 --- /dev/null +++ b/single.py @@ -0,0 +1,44 @@ +import asyncio + +from asyncio_mqtt import Client +import json +import fabapi + + + +async def main(): + done = False + cap = None + auth = None + msg = None + + async with Client("192.168.178.31") as client: + await client.publish("/cmnd/reader", payload='{"Cmd":"haltPICC"}', qos=2, retain=False) + await client.publish("/cmnd/reader", payload='{"Cmd": "message", "MssgID": 0, "AddnTxt":" Karte auflegen"}', qos=2, retain=False) + async with client.filtered_messages("/rfid_reader/111") as messages: + await client.subscribe("/rfid_reader/#") + async for message in messages: + if not auth: + auth, msg, cap = await fabapi.connect_with_fabfire_initial("192.168.178.31", 59661, message.payload) + elif not done: + msg, done = await fabapi.connect_with_fabfire_step(auth, message.payload) + if done: + await client.publish("/cmnd/reader", payload='{"Cmd":"haltPICC"}', qos=2, retain=False) + ms = await cap.machineSystem().a_wait() + info = await ms.machineSystem.info().a_wait() + ma = await info.info.getMachineURN("urn:fabaccess:resource:Testmachine").a_wait() + if ma.machine.state == "inUse": + await ma.machine.inuse.giveBack().a_wait() + else: + await ma.machine.use.use().a_wait() + done = False + cap = None + auth = None + msg = None + + await client.publish("/cmnd/reader", payload=msg, qos=2, retain=False) + + +if __name__ == "__main__": + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) diff --git a/test.py b/test.py deleted file mode 100644 index ac27c8d..0000000 --- a/test.py +++ /dev/null @@ -1,15 +0,0 @@ -import asyncio -import fabapi - - -async def main(): - boot = await fabapi.connect("localhost", 59661, "Testuser", "secret") - if boot: - ms = await boot.machineSystem().a_wait() - info = await ms.machineSystem.info().a_wait() - ma = await info.info.getMachineURN("urn:fabaccess:resource:Another").a_wait() - print(ma.machine) - -if __name__ == "__main__": - loop = asyncio.get_event_loop() - loop.run_until_complete(main())