diff --git a/.gitignore b/.gitignore index a5179e3..cbc0f6d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ __pycache__/ *.iml -.idea/ \ No newline at end of file +.idea/ +.venv/ +.vscode/ +debug.log \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..501d18b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "MeterFeeder"] + path = MeterFeeder + url = git@github.com:TheRandonauts/MeterFeeder.git + shallow = true diff --git a/LICENSE b/LICENSE index 2105aad..23eab68 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,8 @@ MIT License Copyright (c) 2020 Andika Wasisto +Modified by randogoth / Randonauts Co. +Modified by soliax / fp2.dev Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MeterFeeder b/MeterFeeder new file mode 160000 index 0000000..6b8de4b --- /dev/null +++ b/MeterFeeder @@ -0,0 +1 @@ +Subproject commit 6b8de4bd2c8fc0c483c1988b1d99694d8ad31d8d diff --git a/README.md b/README.md index de56092..dad2bdc 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -Pod Entropy Server -================== +Quanttp 2 Entropy Server +======================== _based on [quanttp](https://github.com/awasisto/quanttp) by [Andika Wasisto](https://www.wasisto.com/)_ -An HTTP API that wraps [ComScire quantum random number generator API](https://comscire.com/downloads/qwqngdoc/). +An HTTP API that wraps [MeterFeeder](https://github.com/TheRandonauts/MeterFeeder) instead of the [ComScire quantum random number generator API](https://comscire.com/downloads/qwqngdoc/) to support serving entropy from multiple devices. It also adds JSON endpoints. Running ------- @@ -37,9 +37,6 @@ Usage Example ### REST JSON API - http://localhost:/api/json/randint32?length=3&deviceId=QWR4E001 - < {"devices":['QWR4E002|MED100KX8 100 kHz', 'QWR4E001|MED100KX8 100 kHz']} - http://localhost:/api/json/randint32?length=3&deviceId=QWR4E001 < {"server": "", "type": "string", "format": "int32", "length": 3, "data": [1524492492, -1194151004, 1365408501], "success": "true"} @@ -103,7 +100,7 @@ License ------- Copyright (c) 2020 Andika Wasisto - Modified by Tobias Raayoni Last / Randonauts Co. + Modified by randogoth / Randonauts Co. Modified by soliax / fp2.dev Permission is hereby granted, free of charge, to any person obtaining a copy @@ -122,4 +119,4 @@ License AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. \ No newline at end of file + SOFTWARE. diff --git a/debug.log b/debug.log deleted file mode 100644 index 2398904..0000000 --- a/debug.log +++ /dev/null @@ -1 +0,0 @@ -[0917/192900.742:ERROR:registration_protocol_win.cc(103)] CreateFile: The system cannot find the file specified. (0x2) diff --git a/libmeterfeeder.dylib b/libmeterfeeder.dylib deleted file mode 100755 index 7968ec6..0000000 Binary files a/libmeterfeeder.dylib and /dev/null differ diff --git a/libmeterfeeder.so b/libmeterfeeder.so deleted file mode 100644 index 7b1073e..0000000 Binary files a/libmeterfeeder.so and /dev/null differ diff --git a/meterfeeder.dll b/meterfeeder.dll deleted file mode 100644 index 3bdb168..0000000 Binary files a/meterfeeder.dll and /dev/null differ diff --git a/quanttp/__main__.py b/quanttp/__main__.py index 961171b..f7a61bc 100644 --- a/quanttp/__main__.py +++ b/quanttp/__main__.py @@ -1,5 +1,5 @@ # Copyright (c) 2020 Andika Wasisto -# Modified by Tobias Raayoni Last +# Modified by randogoth # Modified by soliax # # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -159,95 +159,95 @@ def serve(servername, port, id): try: deviceId = request.args.get('deviceId') if len(deviceId) != 8: - return Response(json.dumps({"error": 'deviceId must be a valid 8 character serial number', "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": 'deviceId must be a valid 8 character serial number', "success":False}), status=400, content_type='application/json') status = str(mf_wrapper.status()) length = int(request.args.get('length')) if length < 1: - return Response(json.dumps({"error": 'length must be greater than 0', "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": 'length must be greater than 0', "success":False}), status=400, content_type='application/json') int32array = [] for x in range(0, length): int32array.append(mf_wrapper.randint32(deviceId)) - return Response(json.dumps({"server" : servername, "device": id, "status": status, "type": "string", "format": "int32", "length":length, "data": int32array, "success": "true"}), content_type='application/json') + return Response(json.dumps({"server" : servername, "device": id, "status": status, "type": "string", "format": "int32", "length":length, "data": int32array, "success":True}), content_type='application/json') except (TypeError, ValueError) as e: - return Response(json.dumps({"error": str(e), "status": status, "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": str(e), "status": status, "success":False}), status=400, content_type='application/json') @app.route('/api/json/randuniform') def randjsonuniform(): try: deviceId = request.args.get('deviceId') if len(deviceId) != 8: - return Response(json.dumps({"error": 'deviceId must be a valid 8 character serial number', "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": 'deviceId must be a valid 8 character serial number', "success":False}), status=400, content_type='application/json') status = str(mf_wrapper.status()) length = int(request.args.get('length')) if length < 1: - return Response(json.dumps({"error": 'length must be greater than 0', "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": 'length must be greater than 0', "success":False}), status=400, content_type='application/json') uniformarray = [] for x in range(0, length): uniformarray.append(mf_wrapper.randuniform(deviceId)) - return Response(json.dumps({"server" : servername, "device": id, "status": status, "type": "string", "format": "uniform", "length":length, "data": uniformarray, "success": "true"}), content_type='application/json') + return Response(json.dumps({"server" : servername, "device": id, "status": status, "type": "string", "format": "uniform", "length":length, "data": uniformarray, "success":True}), content_type='application/json') except (TypeError, ValueError) as e: - return Response(json.dumps({"error": str(e), "device": id, "status": status, "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": str(e), "device": id, "status": status, "success":False}), status=400, content_type='application/json') @app.route('/api/json/randnormal') def randjsonnormal(): try: deviceId = request.args.get('deviceId') if len(deviceId) != 8: - return Response(json.dumps({"error": 'deviceId must be a valid 8 character serial number', "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": 'deviceId must be a valid 8 character serial number', "success":False}), status=400, content_type='application/json') status = str(mf_wrapper.status()) length = int(request.args.get('length')) if length < 1: - return Response(json.dumps({"error": 'length must be greater than 0', "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": 'length must be greater than 0', "success":False}), status=400, content_type='application/json') normarray = [] for x in range(0, length): normarray.append(mf_wrapper.randnormal(deviceId)) - return Response(json.dumps({"server" : servername, "device": id, "status": status, "type": "string", "format": "normal", "length":length, "data": normarray, "success": "true"}), content_type='application/json') + return Response(json.dumps({"server" : servername, "device": id, "status": status, "type": "string", "format": "normal", "length":length, "data": normarray, "success":True}), content_type='application/json') except (TypeError, ValueError) as e: - return Response(json.dumps({"error": str(e), "device": id, "status": status, "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": str(e), "device": id, "status": status, "success":False}), status=400, content_type='application/json') @app.route('/api/json/randhex') def randjsonhex(): try: deviceId = request.args.get('deviceId') if len(deviceId) != 8: - return Response(json.dumps({"error": 'deviceId must be a valid 8 character serial number', "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": 'deviceId must be a valid 8 character serial number', "success":False}), status=400, content_type='application/json') status = str(mf_wrapper.status()) length = int(request.args.get('length')) size = int(request.args.get('size')) if length < 1: - return Response(json.dumps({"error": 'length must be greater than 0', "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": 'length must be greater than 0', "success":False}), status=400, content_type='application/json') if size < 1: - return Response(json.dumps({"error": 'size must be greater than 0', "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": 'size must be greater than 0', "success":False}), status=400, content_type='application/json') # entropy = mf_wrapper.randbytes(size*length) hexarray = [] for x in range(0, length): hexarray.append(mf_wrapper.randbytes(deviceId, size).hex()) # hexarray.append(entropy[x*size:(x+1)*size].hex()) - return Response(json.dumps({"server" : servername, "device": id, "status": status, "type": "string", "format": "hex", "length":length, "size": size, "data": hexarray, "success": "true"}), content_type='application/json') + return Response(json.dumps({"server" : servername, "device": id, "status": status, "type": "string", "format": "hex", "length":length, "size": size, "data": hexarray, "success":True}), content_type='application/json') except (TypeError, ValueError) as e: - return Response(json.dumps({"error": str(e), "device": id, "status": status, "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": str(e), "device": id, "status": status, "success":False}), status=400, content_type='application/json') @app.route('/api/json/randbase64') def randjsonbase64(): try: deviceId = request.args.get('deviceId') if len(deviceId) != 8: - return Response(json.dumps({"error": 'deviceId must be a valid 8 character serial number', "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": 'deviceId must be a valid 8 character serial number', "success":False}), status=400, content_type='application/json') status = str(mf_wrapper.status()) length = int(request.args.get('length')) size = int(request.args.get('size')) if length < 1: - return Response(json.dumps({"error": 'length must be greater than 0', "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": 'length must be greater than 0', "success":False}), status=400, content_type='application/json') if size < 1: - return Response(json.dumps({"error": 'size must be greater than 0', "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": 'size must be greater than 0', "success":False}), status=400, content_type='application/json') # entropy = mf_wrapper.randbytes(size*length) basearray = [] for x in range(0, length): basearray.append(base64.b64encode(mf_wrapper.randbytes(deviceId, size)).decode('utf-8')) # basearray.append(base64.b64encode(entropy[x*size:(x+1)*size]).decode('utf-8')) - return Response(json.dumps({"server" : servername, "device": id, "status": status, "type": "string", "format": "base64", "length":length, "size": size, "data": basearray, "success": "true"}), content_type='application/json') + return Response(json.dumps({"server" : servername, "device": id, "status": status, "type": "string", "format": "base64", "length":length, "size": size, "data": basearray, "success":True}), content_type='application/json') except (TypeError, ValueError) as e: - return Response(json.dumps({"error": str(e), "device": id, "status": status, "success":"false"}), status=400, content_type='application/json') + return Response(json.dumps({"error": str(e), "device": id, "status": status, "success":False}), status=400, content_type='application/json') # Websockets ---------------------------------------------- @@ -261,53 +261,85 @@ def serve(servername, port, id): def handle_ws_message(message, websocket, subscribed): try: split_message = message.strip().upper().split() - if split_message[0] == 'RANDINT32': - websocket.send(str(mf_wrapper.randint32())) + if split_message[0] == 'DEVICES': + websocket.send(str(mf_wrapper.deviceIds(False))) + elif split_message[0] == 'RANDINT32': + deviceId = split_message[1] + if len(deviceId) != 8: + raise ValueError() + websocket.send(str(mf_wrapper.randint32(deviceId))) elif split_message[0] == 'RANDUNIFORM': - websocket.send(str(mf_wrapper.randuniform())) + deviceId = split_message[1] + if len(deviceId) != 8: + raise ValueError() + websocket.send(str(mf_wrapper.randuniform(deviceId))) elif split_message[0] == 'RANDNORMAL': - websocket.send(str(mf_wrapper.randnormal())) + deviceId = split_message[1] + if len(deviceId) != 8: + raise ValueError() + websocket.send(str(mf_wrapper.randnormal(deviceId))) elif split_message[0] == 'RANDBYTES': - length = int(split_message[1]) + deviceId = split_message[1] + if len(deviceId) != 8: + raise ValueError() + length = int(split_message[2]) if length < 1: raise ValueError() - websocket.send(mf_wrapper.randbytes(length)) + websocket.send(mf_wrapper.randbytes(deviceId, length)) elif split_message[0] == 'SUBSCRIBEINT32': + deviceId = split_message[1] + if len(deviceId) != 8: + raise ValueError() if not subscribed[0]: subscribed[0] = True while subscribed[0] and not websocket.closed: - websocket.send(str(mf_wrapper.randint32())) + websocket.send(str(mf_wrapper.randint32(deviceId))) elif split_message[0] == 'SUBSCRIBEUNIFORM': + deviceId = split_message[1] + if len(deviceId) != 8: + raise ValueError() if not subscribed[0]: subscribed[0] = True while subscribed[0] and not websocket.closed: - websocket.send(str(mf_wrapper.randuniform())) + websocket.send(str(mf_wrapper.randuniform(deviceId))) elif split_message[0] == 'SUBSCRIBENORMAL': + deviceId = split_message[1] + if len(deviceId) != 8: + raise ValueError() if not subscribed[0]: subscribed[0] = True while subscribed[0] and not websocket.closed: - websocket.send(str(mf_wrapper.randnormal())) + websocket.send(str(mf_wrapper.randnormal(deviceId))) elif split_message[0] == 'SUBSCRIBEBYTES': - chunk = int(split_message[1]) + deviceId = split_message[1] + if len(deviceId) != 8: + raise ValueError() + chunk = int(split_message[2]) if chunk < 1: raise ValueError() if not subscribed[0]: subscribed[0] = True while subscribed[0] and not websocket.closed: - websocket.send(mf_wrapper.randbytes(chunk)) + websocket.send(mf_wrapper.randbytes(deviceId, chunk)) elif split_message[0] == 'SUBSCRIBEHEX': - chunk = int(split_message[1]) + deviceId = split_message[1] + if len(deviceId) != 8: + raise ValueError() + chunk = int(split_message[2]) if chunk < 1: raise ValueError() if not subscribed[0]: subscribed[0] = True while subscribed[0] and not websocket.closed: - websocket.send(mf_wrapper.randbytes(chunk).hex()) + websocket.send(mf_wrapper.randbytes(deviceId, chunk).hex()) elif split_message[0] == 'UNSUBSCRIBE': subscribed[0] = False websocket.send('UNSUBSCRIBED') elif split_message[0] == 'CLEAR': - mf_wrapper.clear() + deviceId = split_message[1] + if len(deviceId) != 8: + raise ValueError() + mf_wrapper.clear(deviceId) except (IndexError, ValueError, BlockingIOError): pass except Exception as e: diff --git a/quanttp/data/meterfeeder_wrapper.py b/quanttp/data/meterfeeder_wrapper.py index 86aa006..f8cb3cb 100644 --- a/quanttp/data/meterfeeder_wrapper.py +++ b/quanttp/data/meterfeeder_wrapper.py @@ -1,7 +1,7 @@ ## # MeterFeeder Library Wrapper # - # by soliax + # by soliax, randogoth ## from platform import os @@ -15,13 +15,13 @@ class MeterFeederWrapper: def __init__(self): if platform == "linux" or platform == "linux2": # Linux - self._meterfeeder = cdll.LoadLibrary(os.getcwd() + '/libmeterfeeder.so') + self._meterfeeder = cdll.LoadLibrary(os.getcwd() + '/MeterFeeder/builds/linux/libmeterfeeder.so') elif platform == "darwin": # OS X - self._meterfeeder = cdll.LoadLibrary(os.getcwd() + '/libmeterfeeder.dylib') + self._meterfeeder = cdll.LoadLibrary(os.getcwd() + '/MeterFeeder/builds/mac/libmeterfeeder.dylib') elif platform == "win32": # Windows - self._meterfeeder = cdll.LoadLibrary(os.getcwd() + '/meterfeeder.dll') + self._meterfeeder = cdll.LoadLibrary(os.getcwd() + '/MeterFeeder/builds/windows/meterfeeder.dll') # Declare function bridging self._meterfeeder.MF_Initialize.argtypes = c_char_p,