def api_security(producer, features, sectype): # Check through all nodes apis = db_connect.getQueryNodes(producer, features, 'all_apis') # If there is no API or Full node in DB return True, as no security to test if apis == None: return True, 'No APIs to test for', sectype else: if sectype == 'producer_api': info = str(eosio.Api_Calls('producer', 'paused')) elif sectype == 'net_api': info = str(eosio.Api_Calls('net', 'connections')) elif sectype == 'db_size_api': info = str(eosio.Api_Calls('db_size', 'get')) # Empty list for API results apilist = [] # Loop over APIs and check security for particular api for api in apis: try: headers = { 'Content-Type': 'application/json' } # only for curl request curlreq = core.curl_request(api + info, 'POST', headers, False) response = requests.get(api + info, timeout=defaulttimeout, verify=False, auth=auth_provider) # If the response was successful, no Exception will be raised response.raise_for_status() except HTTPError as http_err: #print(f'HTTP error occurred: {http_err}') message = True except Exception as err: #print(f'Other error occurred: {err}') message = True # If no error is returned and valid json is returned then API is running else: message = False # API results + api itself apiresult = api, message # Append API + result to apilist apilist.append(apiresult) for api in apilist: if api[1] != True: error = str(sectype) + " is enabled on " + api[ 0] + " this feature should be disabled: " + str(curlreq) return False, error else: True # Dont return here otherswise loop stops # If not False has been found return True return True, 'ok'
def check_api(producer, checktype): if checktype == "httpchk": api = db_connect.getQueryNodes(producer, 'chain-api', 'http') else: api = db_connect.getQueryNodes(producer, 'chain-api', 'api') # If there is no API or Full node in DB return False if api == None: error = "No API node found in JSON file" return False, error else: info = str(eosio.Api_Calls('v1', 'get_info')) try: headers = {'Content-Type': 'application/json'} # only for curl request curlreq = core.curl_request(api[0] + info, 'GET', headers, False) response = requests.get(api[0] + info, timeout=defaulttimeout, verify=False, auth=auth_provider) responsetimes = response.elapsed.total_seconds() * 1000 # If the response was successful, no Exception will be raised response.raise_for_status() except HTTPError as http_err: print(f'HTTP error occurred: {http_err}') error = curlreq + '\n' + str(http_err) return False, error except Exception as err: print(f'Other error occurred: {err}') error = curlreq + '\n' + str(err) return False, error else: # Check if API contains WAX chain ID - verifies its alive if checktype == "apichk" or checktype == 'httpchk': try: jsonres = response.json() except Exception as err: error = 'not providing JSON: ' + str(err) return False, error chainid = jsonres.get('chain_id') if chainid == chain_id: resptime = round(responsetimes, 2) print('Response time: ', resptime) return True, 'ok' else: error = curlreq + '\nError: has the wrong chain ID or HTTP is not working' return False, error # Checks for Access-Control-Allow-Origin = * elif checktype == "corschk": try: headers = response.headers['Access-Control-Allow-Origin'] if headers == "*": return True, 'ok' else: return False, str(headers) except Exception as err: print(f'Other error occurred: {err}') return False, str(err)
def check_https(producer, checktype): api = db_connect.getQueryNodes(producer, 'chain-api', 'https') # If there is no API or Full HTTPS node in DB return False if api == None: return False, 'No API node available in JSON' # If the URL contains Hyperion then change URL request string else: info = str(eosio.Api_Calls('v1', 'get_info')) try: curlreq = core.curl_request(api[0] + info, 'GET', headers, False) response = requests.get(api[0] + info, timeout=defaulttimeout, auth=auth_provider) # If the response was successful, no Exception will be raised response.raise_for_status() except HTTPError as http_err: print(f'HTTP error occurred: {http_err}') # Python 3.6 error = curlreq + '\n' + str(http_err) return False, error except Exception as err: print(f'Other error occurred: {err}') # Python 3.6 error = curlreq + '\n' + str(err) return False, error else: # Check if HTPS API contains WAX chain ID - verifies it's alive if checktype == "httpschk": jsonres = response.json() chainid = jsonres.get('chain_id') if chainid == chain_id: return True, 'ok' else: error = curlreq + '\nError:Wrong chain ID or HTTPS not working' return False, error elif checktype == "http2chk": httpsendpoint = api[0] # If the URL contains a port number, strip the port and assign to port if core.portRegex(httpsendpoint): portsplit = httpsendpoint.rsplit(':', 1) port = portsplit[1] # If no port number assigned presume port 443, as HTTP2 works with TLS else: port = "443" return core.check_http2(httpsendpoint, port, checktype) elif checktype == "tlschk": httpsendpoint = api[0] # If the URL contains a port number, strip the port and assign to port if core.portRegex(httpsendpoint): portsplit = httpsendpoint.rsplit(':', 1) port = portsplit[1] # If no port number assigned presume port 443, as HTTP2 works with TLS else: port = "443" return core.check_tls(httpsendpoint, port)
def check_hyperion(producer, feature): ### Check Hyperion exists in DB try: api = db_connect.getQueryNodes(producer, feature, 'api')[0] print('Hyperion node: ', api) # If there is no v1_history or hyperion node in DB return False except: return False, 'No ' + feature + ' in JSON' # Check Hyperion last indexed equals total indexed blocks - this also accounts for all other services being ok hyperionresult = eosio.hyperionindexedBlocks(api) if hyperionresult[0] == False: return False, hyperionresult[1] else: pass ### Check hyperion last indexed action history_url = str(eosio.Api_Calls( 'v2-history', 'get_actions?limit=1')) #'/v2/history/get_actions?limit=1' try: response = requests.get(api + history_url, timeout=defaulttimeout, auth=auth_provider) # If the response was successful, no Exception will be raised response.raise_for_status() # If returns codes are 500 OR 404 except HTTPError as http_err: if response.status_code == 500: error = "something else weird has happened" return False, error elif response.status_code == 404: error = 'Error: Not a full node' return False, error else: error = str(http_err) return False, error except Exception as err: print(f'Other error occurred: {err}') # Python 3.6 # also return err error = str(err) return False, error else: jsonres = response.json() last_action_date = dateutil.parser.parse( jsonres['actions'][0]['@timestamp']).replace(tzinfo=None) diff_secs = (datetime.utcnow() - last_action_date).total_seconds() if diff_secs > 600: msg = 'Hyperion Last action {} ago'.format( humanize.naturaldelta(diff_secs)) return False, msg else: return True, 'ok'
def check_history_v1(producer, feature): headers = {'Content-Type': 'application/json'} payload = {"account_name": "eosio", "pos": -1, "offset": -20} # Query nodes in DB and try and obtain API node try: api = db_connect.getQueryNodes(producer, feature, 'api')[0] print('Hyperion node: ', api) # If there is no v1_history or hyperion node in DB return False except: return False, 'No ' + feature + ' in JSON' info = str(eosio.Api_Calls('v1-history', 'get_actions')) curlreq = core.curl_request(api + info, 'POST', headers, payload) try: response = requests.post(api + info, headers=headers, json=payload, timeout=defaulttimeout, auth=auth_provider) response.raise_for_status() # If returns codes are 500 OR 404 except HTTPError as http_err: print(f'HTTP error occurred: {http_err}') # Python 3.6 # also return http_err if response.status_code == 500: jsonres = response.json() try: error = curlreq + '\nError: ' + str( jsonres.get('error').get('what')) except: error = "something else weird has happened" return False, error elif response.status_code == 404: error = curlreq + '\nError: Not a full node' return False, error else: error = curlreq + ' ' + str(http_err) return False, error except Exception as err: print(f'Other error occurred: {err}') # Python 3.6 # also return err error = curlreq + '\n' + str(err) return False, error jsonres = response.json() try: #Has trx been executed actions = jsonres['actions'] except Exception as err: return False, err if len(actions) == 0: return False, 'No actions returned' else: return True, 'ok'
def check_atomic_assets(producer, feature): info = str(eosio.Api_Calls('', 'health')) # Query nodes in DB and try and obtain API node try: api = db_connect.getQueryNodes(producer, feature, 'api')[0] api = format(api.rstrip('/')) # If there is no v1_history or hyperion node in DB return False except: return False, 'No ' + feature + ' in JSON' try: headers = {'Content-Type': 'application/json'} payloads = {} curlreq = core.curl_request(api + info, 'GET', headers, payloads) response = requests.get(api + info, headers=headers, timeout=defaulttimeout, auth=auth_provider) # If the response was successful, no Exception will be raised response.raise_for_status() except HTTPError as http_err: print(f'HTTP error occurred: {http_err}') # Python 3.6 # also return http_err if response.status_code == 500: try: jsonres = response.json() except Exception as err: error = 'not providing JSON: ' + str(err) return False, error try: error = curlreq + '\nError: ' + str( jsonres.get('error').get('what')) except: error = "something else weird has happened" return False, error elif response.status_code == 404: error = curlreq + '\nError: Server not a Atomic Assets Api ' return False, error else: error = curlreq + '\n' + str(http_err) return False, error except Exception as err: print(f'Other error occurred: {err}') # Python 3.6 # also return err error = curlreq + '\n' + str(err) return False, error else: jsonres = response.json() services = jsonres['data'] postgres = services['postgres']['status'] redis = services['redis']['status'] chain = services['chain']['status'] head_block = services['chain']['head_block'] reader = services['postgres']['readers'] last_indexed_block = reader[0]['block_num'] if abs(int(last_indexed_block) - int(head_block)) > 100: msg = 'Atomic API last_indexed_block is behind head_block' return (False, msg) else: pass services = dict(postgres=postgres, redis=redis, chain=chain) for k, v in services.items(): msg = 'Atomic service {} has status {}'.format(k, v) if v != 'OK': return False, msg else: return True, 'All Atomic services are working'