Skip to content

Commit

Permalink
Merge pull request #99 from GitAlexxx/master
Browse files Browse the repository at this point in the history
Error handling and functionality enhancement
  • Loading branch information
paragbaxi authored Oct 24, 2021
2 parents 3fb5eee + af51472 commit c56047d
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 15 deletions.
52 changes: 42 additions & 10 deletions qualysapi/api_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,16 @@ def listReports(self, id=0):
self.request(call, parameters).encode("utf-8")
).RESPONSE
reportsArray = []
while repData.find("REPORT_LIST") is None and max_retries > 0:
max_retries = max_retries - 1
time.sleep(30)
qualys_resp = self.request(call, parameters).encode("utf-8")
logging.info("QUALYS_REPONSE " + str(qualys_resp))
repData = objectify.fromstring(qualys_resp).RESPONSE
if repData.find("REPORT_LIST"):
while repData.find("REPORT_LIST") is None and max_retries > 0:
max_retries = max_retries - 1
time.sleep(30)
qualys_resp = self.request(call, parameters).encode("utf-8")
logging.info("QUALYS_REPONSE " + str(qualys_resp))
repData = objectify.fromstring(qualys_resp).RESPONSE
else:
logging.info("There are no reports")
return []

if max_retries <= 0:
logging.info("Report Listing not successful")
Expand Down Expand Up @@ -269,6 +273,7 @@ def launchReport(
tag_set_include=None,
tag_set_by=None,
tag_set_exclude=None,
tag_include_selector=None,
max_retries=3,
):
call = "/api/2.0/fo/report"
Expand Down Expand Up @@ -297,6 +302,11 @@ def launchReport(
parameters["tag_set_by"] = tag_set_by
else:
raise ValueError("tag_set_by must be id or name")
if tag_include_selector:
if tag_include_selector in ('any', 'all'):
parameters["tag_include_selector"] = tag_include_selector
else:
raise ValueError("use_tags must be 'any' or 'all'")

repData = objectify.fromstring(self.request(call, parameters).encode("utf-8")).RESPONSE
while (
Expand All @@ -315,10 +325,10 @@ def launchReport(

if repData.find("TEXT") == "New report launched":
report_id = repData.find("ITEM_LIST").find("ITEM").find("VALUE")
return report_id.pyval

logging.warn("Report ID is empty.")
return None
return report_id.pyval, repData.find("TEXT")
else:
logging.warning(repData.find("TEXT"))
return -1, repData.find("TEXT")

def downloadReport(self, report_id, echo_request=0):
call = "/api/2.0/fo/report"
Expand Down Expand Up @@ -528,3 +538,25 @@ def launchScan(self, title, option_title, iscanner_name, asset_groups="", ip="")
scan.find("TYPE"),
scan.find("USER_LOGIN"),
)


def deleteReport(self, id):
call = "/api/2.0/fo/report/"
parameters = {"action": "delete", "id": id}
res = objectify.fromstring(self.request(call, parameters).encode("utf-8")).RESPONSE
code = getattr(res, "CODE", "")

max_retries = 7
while res.TEXT != 'Report deleted' and max_retries > 0:
max_retries = max_retries - 1
time.sleep(40)
res = objectify.fromstring(self.request(call, parameters).encode("utf-8")).RESPONSE
code = getattr(res, "CODE", "")
logging.info("QUALYS_REPONSE " + str(res.TEXT))

if max_retries <= 0:
logging.info("%s %s", code, res.TEXT)
return None

logging.debug("%s %s %s", res.DATETIME, code, res.TEXT)
return code, res
20 changes: 16 additions & 4 deletions qualysapi/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class QGConnector(api_actions.QGActions):
"""

def __init__(self, auth, server="qualysapi.qualys.com", proxies=None, max_retries=3):
def __init__(self, auth, server="qualysapi.qualys.com", proxies=None, data_exchange_format=None, max_retries=3):
# Read username & password from file, if possible.
self.auth = auth
# Remember QualysGuard API server.
Expand All @@ -55,6 +55,7 @@ def __init__(self, auth, server="qualysapi.qualys.com", proxies=None, max_retrie
qualysapi.api_methods.api_methods_with_trailing_slash
)
self.proxies = proxies
self.data_exchange_format = data_exchange_format
logger.debug("proxies = \n%s", proxies)
# Set up requests max_retries.
logger.debug("max_retries = \n%s", max_retries)
Expand Down Expand Up @@ -255,9 +256,15 @@ def build_request(self, api_call, data=None, api_version=None, http_method=None)
"X-Requested-With": f"Parag Baxi QualysAPI (python) v{qualysapi.version.__version__}"
}
logger.debug("headers =\n%s", str(headers))
# Portal API takes in XML text, requiring custom header.
# Portal API support XML/JSON exchange format (JSON for assets tagging and management).
# The data exchange format must be specified in the headers.
if api_version in ("am", "was", "am2"):
headers["Content-type"] = "text/xml"
if self.data_exchange_format == 'xml':
headers["Content-type"] = "text/xml"
headers["Accept"] = "text/xml"
if self.data_exchange_format == 'json':
headers["Content-type"] = "application/json"
headers["Accept"] = "application/json"
#
# Set up http request method, if not specified.
if not http_method:
Expand Down Expand Up @@ -396,7 +403,7 @@ def request(
# And sometimes with MemoryError
if request.encoding is None:
request.encoding = "utf-8"
#

# Remember how many times left user can make against api_call.
try:
self.rate_limit_remaining[api_call] = int(
Expand Down Expand Up @@ -568,4 +575,9 @@ def request(
logger.error("Content = \n%s", response)
logger.error("Headers = \n%s", str(request.headers))
return False

# return bytes if pdf
if 'application/pdf' in request.headers['content-type']:
return request.content

return response
4 changes: 3 additions & 1 deletion qualysapi/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ def connect(
hostname="qualysapi.qualys.com",
max_retries="3",
proxies=None,
data_exchange_format='xml'
):
""" Return a QGAPIConnect object for v1 API pulling settings from config
file.
"""
# Use function parameter login credentials.
if username and password:
connect = qcconn.QGConnector(
auth=(username, quote_plus(password)), server=hostname, max_retries=max_retries, proxies=proxies
auth=(username, quote_plus(password)), server=hostname, max_retries=max_retries,
proxies=proxies, data_exchange_format=data_exchange_format
)

# Retrieve login credentials from config file.
Expand Down

0 comments on commit c56047d

Please sign in to comment.