2020-05-21 21:05:12 +07:00
# Copyright (c) 2020 Andika Wasisto
2020-09-17 20:23:59 +02:00
# Modified by Tobias Raayoni Last
2021-06-04 00:28:38 +08:00
# Modified by soliax
2020-05-21 21:05:12 +07:00
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 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.
2020-09-07 20:45:21 +07:00
2020-08-17 05:03:36 +07:00
import os
2020-09-18 15:22:26 +02:00
import sys
2020-05-25 12:35:08 +07:00
import threading
2020-09-17 20:23:59 +02:00
import json
2020-09-18 16:04:35 +02:00
import socket
import requests
2020-12-26 03:54:01 +03:00
import base64
2020-05-25 12:35:08 +07:00
2020-05-21 21:05:12 +07:00
from flask import Flask , request , Response
from flask_sockets import Sockets
from gevent import pywsgi
from geventwebsocket . handler import WebSocketHandler
2021-06-04 00:28:38 +08:00
from quanttp . data . meterfeeder_wrapper import MeterFeederWrapper
2020-05-25 12:56:13 +07:00
2020-05-21 21:05:12 +07:00
app = Flask ( __name__ )
sockets = Sockets ( app )
2021-06-04 00:28:38 +08:00
mf_wrapper = MeterFeederWrapper ( )
2020-05-21 21:05:12 +07:00
2020-09-18 15:22:26 +02:00
def main ( ) :
# Commandline Arguments (servername, port)
argNo = len ( sys . argv ) - 1
if argNo < 2 :
print ( " -------------------------------------------- " )
print ( " Please provide arguments: <servername> <port> " )
print ( " -------------------------------------------- " )
else :
servername = sys . argv [ 1 ]
port = int ( sys . argv [ 2 ] )
2020-09-18 16:04:35 +02:00
ip = requests . get ( ' https://api.ipify.org ' ) . text
2021-06-04 00:28:38 +08:00
id = str ( mf_wrapper . deviceIds ( False ) )
2020-09-18 15:22:26 +02:00
print ( " ---------------------------------------------------------------------------------------- " )
2020-09-18 16:04:35 +02:00
print ( " Serving Entropy from TRNG " , id , " as pod \" " , servername , " \" on http:// " , ip , " : " , port , " /api/... " , sep = ' ' )
2020-09-18 15:22:26 +02:00
print ( " ---------------------------------------------------------------------------------------- " )
2020-09-18 16:18:53 +02:00
serve ( servername , port , id )
2020-09-18 15:22:26 +02:00
2020-09-18 16:18:53 +02:00
def serve ( servername , port , id ) :
2020-09-18 15:22:26 +02:00
# Original API ----------------------------------------------
2021-06-04 00:28:38 +08:00
@app.route ( ' /api/devices ' )
def devices ( ) :
devices = str ( mf_wrapper . deviceIds ( False ) )
return Response ( devices , content_type = ' text/plain ' )
2020-09-18 15:22:26 +02:00
@app.route ( ' /api/randint32 ' )
def randint32 ( ) :
2021-06-04 00:28:38 +08:00
deviceId = request . args . get ( ' deviceId ' )
if len ( deviceId ) != 8 :
return Response ( ' deviceId must be a valid 8 character serial number ' , status = 400 , content_type = ' text/plain ' )
return Response ( str ( mf_wrapper . randint32 ( deviceId ) ) , content_type = ' text/plain ' )
2020-09-18 15:22:26 +02:00
@app.route ( ' /api/randuniform ' )
def randuniform ( ) :
2021-06-04 00:28:38 +08:00
deviceId = request . args . get ( ' deviceId ' )
if len ( deviceId ) != 8 :
return Response ( ' deviceId must be a valid 8 character serial number ' , status = 400 , content_type = ' text/plain ' )
return Response ( str ( mf_wrapper . randuniform ( deviceId ) ) , content_type = ' text/plain ' )
2020-09-18 15:22:26 +02:00
@app.route ( ' /api/randnormal ' )
def randnormal ( ) :
2021-06-04 00:28:38 +08:00
deviceId = request . args . get ( ' deviceId ' )
if len ( deviceId ) != 8 :
return Response ( ' deviceId must be a valid 8 character serial number ' , status = 400 , content_type = ' text/plain ' )
return Response ( str ( mf_wrapper . randnormal ( deviceId ) ) , content_type = ' text/plain ' )
2020-09-18 15:22:26 +02:00
@app.route ( ' /api/randhex ' )
def randhex ( ) :
try :
2021-06-04 00:28:38 +08:00
deviceId = request . args . get ( ' deviceId ' )
if len ( deviceId ) != 8 :
return Response ( ' deviceId must be a valid 8 character serial number ' , status = 400 , content_type = ' text/plain ' )
2020-09-18 15:22:26 +02:00
length = int ( request . args . get ( ' length ' ) )
if length < 1 :
return Response ( ' length must be greater than 0 ' , status = 400 , content_type = ' text/plain ' )
2021-06-04 00:28:38 +08:00
return Response ( mf_wrapper . randbytes ( deviceId , length ) . hex ( ) , content_type = ' text/plain ' )
2020-09-18 15:22:26 +02:00
except ( TypeError , ValueError ) as e :
return Response ( str ( e ) , status = 400 , content_type = ' text/plain ' )
2020-12-26 03:54:01 +03:00
@app.route ( ' /api/randbase64 ' )
def randbase64 ( ) :
try :
2021-06-04 00:28:38 +08:00
deviceId = request . args . get ( ' deviceId ' )
if len ( deviceId ) != 8 :
return Response ( ' deviceId must be a valid 8 character serial number ' , status = 400 , content_type = ' text/plain ' )
2020-12-26 03:54:01 +03:00
length = int ( request . args . get ( ' length ' ) )
if length < 1 :
return Response ( ' length must be greater than 0 ' , status = 400 , content_type = ' text/plain ' )
2021-06-04 00:28:38 +08:00
return Response ( base64 . b64encode ( mf_wrapper . randbytes ( deviceId , length ) ) . decode ( ' utf-8 ' ) , content_type = ' text/plain ' )
2020-12-26 03:54:01 +03:00
except ( TypeError , ValueError ) as e :
return Response ( str ( e ) , status = 400 , content_type = ' text/plain ' )
2020-09-18 15:22:26 +02:00
@app.route ( ' /api/randbytes ' )
def randbytes ( ) :
try :
2021-06-04 00:28:38 +08:00
deviceId = request . args . get ( ' deviceId ' )
if len ( deviceId ) != 8 :
return Response ( ' deviceId must be a valid 8 character serial number ' , status = 400 , content_type = ' text/plain ' )
2020-09-18 15:22:26 +02:00
length = int ( request . args . get ( ' length ' ) )
if length < 1 :
return Response ( ' length must be greater than 0 ' , status = 400 , content_type = ' text/plain ' )
2021-06-04 00:28:38 +08:00
return Response ( mf_wrapper . randbytes ( deviceId , length ) , content_type = ' application/octet-stream ' )
2020-09-18 15:22:26 +02:00
except ( TypeError , ValueError ) as e :
return Response ( str ( e ) , status = 400 , content_type = ' text/plain ' )
2020-12-26 03:54:01 +03:00
@app.route ( ' /api/clear ' )
def clear ( ) :
2021-06-04 00:28:38 +08:00
deviceId = request . args . get ( ' deviceId ' )
if len ( deviceId ) != 8 :
return Response ( ' deviceId must be a valid 8 character serial number ' , status = 400 , content_type = ' text/plain ' )
mf_wrapper . clear ( deviceId )
2020-12-26 03:54:01 +03:00
return Response ( status = 204 )
@app.route ( ' /api/reset ' )
def reset ( ) :
2021-06-04 00:28:38 +08:00
mf_wrapper . reset ( )
2020-12-26 03:54:01 +03:00
return Response ( status = 204 )
@app.route ( ' /api/status ' )
2021-06-04 00:28:38 +08:00
def status ( ) :
2021-06-04 00:41:48 +08:00
status = " ONLINE " # TODO implement me
2021-06-04 00:28:38 +08:00
return Response ( json . dumps ( { " server " : servername , " devices " : id , " status " : status } ) , status = 400 , content_type = ' text/plain ' )
2020-12-26 03:54:01 +03:00
2020-09-18 15:22:26 +02:00
# JSON API ----------------------------------------------
2021-06-04 00:28:38 +08:00
@app.route ( ' /api/json/devices ' )
def devicesjson ( ) :
devices = str ( mf_wrapper . deviceIds ( True ) )
return Response ( json . dumps ( devices ) , content_type = ' application/json ' )
2020-09-18 15:22:26 +02:00
@app.route ( ' /api/json/randint32 ' )
def randjsonint32 ( ) :
try :
2021-06-04 00:28:38 +08:00
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 ' )
status = str ( mf_wrapper . status ( ) )
2020-09-18 15:22:26 +02:00
length = int ( request . args . get ( ' length ' ) )
if length < 1 :
2021-06-04 00:28:38 +08:00
return Response ( json . dumps ( { " error " : ' length must be greater than 0 ' , " success " : " false " } ) , status = 400 , content_type = ' application/json ' )
2020-09-18 15:22:26 +02:00
int32array = [ ]
for x in range ( 0 , length ) :
2021-06-04 00:28:38 +08:00
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 ' )
2020-09-18 15:22:26 +02:00
except ( TypeError , ValueError ) as e :
2021-06-04 00:28:38 +08:00
return Response ( json . dumps ( { " error " : str ( e ) , " status " : status , " success " : " false " } ) , status = 400 , content_type = ' application/json ' )
2020-09-18 15:22:26 +02:00
@app.route ( ' /api/json/randuniform ' )
def randjsonuniform ( ) :
try :
2021-06-04 00:28:38 +08:00
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 ' )
status = str ( mf_wrapper . status ( ) )
2020-09-18 15:22:26 +02:00
length = int ( request . args . get ( ' length ' ) )
if length < 1 :
2021-06-04 00:28:38 +08:00
return Response ( json . dumps ( { " error " : ' length must be greater than 0 ' , " success " : " false " } ) , status = 400 , content_type = ' application/json ' )
2020-09-18 15:22:26 +02:00
uniformarray = [ ]
for x in range ( 0 , length ) :
2021-06-04 00:28:38 +08:00
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 ' )
2020-09-18 15:22:26 +02:00
except ( TypeError , ValueError ) as e :
2021-06-04 00:28:38 +08:00
return Response ( json . dumps ( { " error " : str ( e ) , " device " : id , " status " : status , " success " : " false " } ) , status = 400 , content_type = ' application/json ' )
2020-09-18 15:22:26 +02:00
@app.route ( ' /api/json/randnormal ' )
def randjsonnormal ( ) :
try :
2021-06-04 00:28:38 +08:00
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 ' )
status = str ( mf_wrapper . status ( ) )
2020-09-18 15:22:26 +02:00
length = int ( request . args . get ( ' length ' ) )
if length < 1 :
2021-06-04 00:28:38 +08:00
return Response ( json . dumps ( { " error " : ' length must be greater than 0 ' , " success " : " false " } ) , status = 400 , content_type = ' application/json ' )
2020-09-18 15:22:26 +02:00
normarray = [ ]
for x in range ( 0 , length ) :
2021-06-04 00:28:38 +08:00
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 ' )
2020-09-18 15:22:26 +02:00
except ( TypeError , ValueError ) as e :
2021-06-04 00:28:38 +08:00
return Response ( json . dumps ( { " error " : str ( e ) , " device " : id , " status " : status , " success " : " false " } ) , status = 400 , content_type = ' application/json ' )
2020-09-18 15:22:26 +02:00
@app.route ( ' /api/json/randhex ' )
def randjsonhex ( ) :
try :
2021-06-04 00:28:38 +08:00
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 ' )
status = str ( mf_wrapper . status ( ) )
2020-09-18 15:22:26 +02:00
length = int ( request . args . get ( ' length ' ) )
size = int ( request . args . get ( ' size ' ) )
2020-09-18 11:15:23 +02:00
if length < 1 :
2021-06-04 00:28:38 +08:00
return Response ( json . dumps ( { " error " : ' length must be greater than 0 ' , " success " : " false " } ) , status = 400 , content_type = ' application/json ' )
2020-09-18 15:22:26 +02:00
if size < 1 :
2021-06-04 00:28:38 +08:00
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)
2020-09-18 15:22:26 +02:00
hexarray = [ ]
for x in range ( 0 , length ) :
2021-06-04 00:28:38 +08:00
hexarray . append ( mf_wrapper . randbytes ( deviceId , size ) . hex ( ) )
2020-12-26 03:54:01 +03:00
# hexarray.append(entropy[x*size:(x+1)*size].hex())
2021-06-04 00:28:38 +08:00
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 ' )
2020-09-18 15:22:26 +02:00
except ( TypeError , ValueError ) as e :
2021-06-04 00:28:38 +08:00
return Response ( json . dumps ( { " error " : str ( e ) , " device " : id , " status " : status , " success " : " false " } ) , status = 400 , content_type = ' application/json ' )
2020-12-26 03:54:01 +03:00
@app.route ( ' /api/json/randbase64 ' )
def randjsonbase64 ( ) :
try :
2021-06-04 00:28:38 +08:00
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 ' )
status = str ( mf_wrapper . status ( ) )
2020-12-26 03:54:01 +03:00
length = int ( request . args . get ( ' length ' ) )
size = int ( request . args . get ( ' size ' ) )
if length < 1 :
2021-06-04 00:28:38 +08:00
return Response ( json . dumps ( { " error " : ' length must be greater than 0 ' , " success " : " false " } ) , status = 400 , content_type = ' application/json ' )
2020-12-26 03:54:01 +03:00
if size < 1 :
2021-06-04 00:28:38 +08:00
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)
2020-12-26 03:54:01 +03:00
basearray = [ ]
for x in range ( 0 , length ) :
2021-06-04 00:28:38 +08:00
basearray . append ( base64 . b64encode ( mf_wrapper . randbytes ( deviceId , size ) ) . decode ( ' utf-8 ' ) )
2020-12-26 03:54:01 +03:00
# basearray.append(base64.b64encode(entropy[x*size:(x+1)*size]).decode('utf-8'))
2021-06-04 00:28:38 +08:00
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 ' )
2020-12-26 03:54:01 +03:00
except ( TypeError , ValueError ) as e :
2021-06-04 00:28:38 +08:00
return Response ( json . dumps ( { " error " : str ( e ) , " device " : id , " status " : status , " success " : " false " } ) , status = 400 , content_type = ' application/json ' )
2020-12-26 03:54:01 +03:00
2020-09-18 15:22:26 +02:00
# Websockets ----------------------------------------------
@sockets.route ( ' /ws ' )
def ws ( websocket ) :
subscribed = [ False ]
while not websocket . closed :
threading . Thread ( target = handle_ws_message , args = ( websocket . receive ( ) , websocket , subscribed ) ) . start ( )
def handle_ws_message ( message , websocket , subscribed ) :
try :
split_message = message . strip ( ) . upper ( ) . split ( )
if split_message [ 0 ] == ' RANDINT32 ' :
2021-06-04 00:28:38 +08:00
websocket . send ( str ( mf_wrapper . randint32 ( ) ) )
2020-09-18 15:22:26 +02:00
elif split_message [ 0 ] == ' RANDUNIFORM ' :
2021-06-04 00:28:38 +08:00
websocket . send ( str ( mf_wrapper . randuniform ( ) ) )
2020-09-18 15:22:26 +02:00
elif split_message [ 0 ] == ' RANDNORMAL ' :
2021-06-04 00:28:38 +08:00
websocket . send ( str ( mf_wrapper . randnormal ( ) ) )
2020-09-18 15:22:26 +02:00
elif split_message [ 0 ] == ' RANDBYTES ' :
length = int ( split_message [ 1 ] )
if length < 1 :
raise ValueError ( )
2021-06-04 00:28:38 +08:00
websocket . send ( mf_wrapper . randbytes ( length ) )
2020-09-18 15:22:26 +02:00
elif split_message [ 0 ] == ' SUBSCRIBEINT32 ' :
if not subscribed [ 0 ] :
subscribed [ 0 ] = True
while subscribed [ 0 ] and not websocket . closed :
2021-06-04 00:28:38 +08:00
websocket . send ( str ( mf_wrapper . randint32 ( ) ) )
2020-09-18 15:22:26 +02:00
elif split_message [ 0 ] == ' SUBSCRIBEUNIFORM ' :
if not subscribed [ 0 ] :
subscribed [ 0 ] = True
while subscribed [ 0 ] and not websocket . closed :
2021-06-04 00:28:38 +08:00
websocket . send ( str ( mf_wrapper . randuniform ( ) ) )
2020-09-18 15:22:26 +02:00
elif split_message [ 0 ] == ' SUBSCRIBENORMAL ' :
if not subscribed [ 0 ] :
subscribed [ 0 ] = True
while subscribed [ 0 ] and not websocket . closed :
2021-06-04 00:28:38 +08:00
websocket . send ( str ( mf_wrapper . randnormal ( ) ) )
2020-09-18 15:22:26 +02:00
elif split_message [ 0 ] == ' SUBSCRIBEBYTES ' :
chunk = int ( split_message [ 1 ] )
if chunk < 1 :
raise ValueError ( )
if not subscribed [ 0 ] :
subscribed [ 0 ] = True
while subscribed [ 0 ] and not websocket . closed :
2021-06-04 00:28:38 +08:00
websocket . send ( mf_wrapper . randbytes ( chunk ) )
2020-09-18 15:22:26 +02:00
elif split_message [ 0 ] == ' SUBSCRIBEHEX ' :
chunk = int ( split_message [ 1 ] )
if chunk < 1 :
raise ValueError ( )
if not subscribed [ 0 ] :
subscribed [ 0 ] = True
while subscribed [ 0 ] and not websocket . closed :
2021-06-04 00:28:38 +08:00
websocket . send ( mf_wrapper . randbytes ( chunk ) . hex ( ) )
2020-09-18 15:22:26 +02:00
elif split_message [ 0 ] == ' UNSUBSCRIBE ' :
subscribed [ 0 ] = False
websocket . send ( ' UNSUBSCRIBED ' )
elif split_message [ 0 ] == ' CLEAR ' :
2021-06-04 00:28:38 +08:00
mf_wrapper . clear ( )
2020-09-18 15:22:26 +02:00
except ( IndexError , ValueError , BlockingIOError ) :
pass
except Exception as e :
websocket . close ( code = 1011 , message = str ( e ) )
@app.errorhandler ( Exception )
def handle_exception ( e ) :
return Response ( e . description , status = e . code , content_type = ' text/plain ' )
server = pywsgi . WSGIServer ( ( ' 0.0.0.0 ' , port ) , application = app , handler_class = WebSocketHandler )
server . serve_forever ( )
if __name__ == " __main__ " :
main ( )