Skip to content

Commit

Permalink
implement #17; various cleanups in rhsecapi.main()
Browse files Browse the repository at this point in the history
  • Loading branch information
ryran committed Nov 29, 2016
1 parent 40b37cc commit 768ec65
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 111 deletions.
113 changes: 46 additions & 67 deletions rhsda.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ def _parse_cve_to_plaintext(self, cve):
out.append(" ACKNOWLEDGEMENT : {0}".format(self.__stripjoin(J['acknowledgement'])))
# DETAILS
if self.__check_field('details', J):
out.append(" DETAILS : {0}".format(self.__stripjoin(J['details'])))
out.append(" DETAILS : {0}".format(self.__stripjoin(J['details'])))
# STATEMENT
if self.__check_field('statement', J):
out.append(" STATEMENT : {0}".format(self.__stripjoin(J['statement'])))
Expand Down Expand Up @@ -880,7 +880,7 @@ def mget_iavas(self, iavas, numThreads=0, onlyCount=False, outFormat='plaintext'
elif outFormat == 'jsonpretty':
return jprint(iavaOutput)

def cve_search_query(self, params, outFormat='list'):
def cve_search_query(self, params, outFormat='list', urls=False):
"""Perform a CVE search query.
ON *OUTFORMAT*:
Expand All @@ -897,13 +897,53 @@ def cve_search_query(self, params, outFormat='list'):
return result
if outFormat == 'jsonpretty':
return jprint(result)
cves = []
for i in result:
cves.append(i['CVE'])
if outFormat == 'list':
cves = []
for i in result:
cves.append(i['CVE'])
return cves
if outFormat == 'plaintext':
return "\n".join(cves)
rows = []
rows.append(["CVE ID", "PUB DATE", "BUGZILLA", "SEVERITY", "CVSS2", "CVSS3", "RHSAS", "PKGS"])
for i in result:
date = ""
if i.has_key('public_date'):
date = i['public_date'].split("T")[0]
bz = ""
if urls:
cve = "https://access.redhat.com/security/cve/{0}".format(i['CVE'])
if i.has_key('bugzilla'):
bz = "https://bugzilla.redhat.com/show_bug.cgi?id={0}".format(i['bugzilla'])
else:
cve = i['CVE']
if i.has_key('bugzilla'):
bz = i['bugzilla']
severity = i['severity']
rhsas = ""
if i.has_key('advisories'):
rhsas = "{0: >2}".format(len(i['advisories']))
pkgs = ""
if i.has_key('affected_packages'):
pkgs = "{0: >2}".format(len(i['affected_packages']))
cvss2 = ""
if i.has_key('cvss_score'):
cvss2 = str(i['cvss_score'])
cvss3 = ""
if i.has_key('cvss3_score'):
cvss3 = str(i['cvss3_score'])
line = [cve, date, bz, severity, cvss2, cvss3, rhsas, pkgs]
rows.append(line)
return self._columnize(rows, sep=" ")

def _columnize(self, rows, sep=" "):
"""Columnize (a la column -t) input list of lists, returning string.
Credit: http://stackoverflow.com/a/12065663
"""
widths = [ max(map(len, col)) for col in zip(*rows) ]
output = []
for row in rows:
output.append(sep.join((val.ljust(width) for val,width in zip(row, widths))))
return "\n".join(output)

def _err_print_support_urls(self, msg=None):
"""Print error + support urls."""
Expand All @@ -912,67 +952,6 @@ def _err_print_support_urls(self, msg=None):
print("\nFor help, open an issue at http://github.com/ryran/rhsecapi\n"
"Or post a comment at https://access.redhat.com/discussions/2713931", file=sys.stderr)

# def _iavm_query(self, url):
# """Get IAVA json from IAVM Mapper App."""
# logger.info("Getting {0}".format(url))
# try:
# r = requests.get(url, auth=())
# except requests.exceptions.ConnectionError as e:
# self._err_print_support_urls(e)
# raise
# except requests.exceptions.RequestException as e:
# self._err_print_support_urls(e)
# raise
# except requests.exceptions.HTTPError as e:
# self._err_print_support_urls(e)
# raise
# r.raise_for_status()
# baseurl = r.url.split("/")[-1]
# if not baseurl:
# baseurl = r.url.split("/")[-2]
# logger.debug("Return '.../{0}': Status {1}, Content-Type {2}".format(baseurl, r.status_code, r.headers['Content-Type'].split(";")[0]))
# if 'application/json' in r.headers['Content-Type']:
# result = r.json()
# elif '<title>Login - Red Hat Customer Portal</title>' in r.content:
# logger.error("Login error")
# print("\nIAVA→CVE mapping data is not provided by the public RH Security Data API.\n"
# "Instead, this uses the IAVM Mapper App (access.redhat.com/labs/iavmmapper).\n\n"
# "Access to this data requires RH Customer Portal credentials be provided.\n"
# "Create a ~/.netrc with the following contents:\n\n"
# "machine access.redhat.com\n"
# " login YOUR-CUSTOMER-PORTAL-LOGIN\n"
# " password YOUR_PASSWORD_HERE",
# file=sys.stderr)
# self._err_print_support_urls()
# return []
# return result

# def get_iava(self, iavaId):
# """Validate IAVA number and return json."""
# # Get main IAVA master index
# url = 'https://access.redhat.com/labs/iavmmapper/api/iava/'
# result = self._iavm_query(url)
# if not result:
# # If no result, we're not logged in & error has already been logged
# return []
# if iavaId in result:
# logger.debug("IAVM Mapper app main index contains '{0}'".format(iavaId))
# else:
# logger.error("IAVM Mapper app main index doesn't contain '{0}'".format(iavaId))
# self._err_print_support_urls()
# return []
# # Get specific IAVA now
# url += '{0}'.format(iavaId)
# try:
# result = self._iavm_query(url)
# except requests.exceptions.HTTPError as e:
# logger.info(e)
# logger.error("IAVM Mapper app doesn't have entry for '{0}'".format(iavaId))
# self._err_print_support_urls()
# return []
# logger.log(25, "{0} CVEs found with search".format(len(result['IAVM']['CVEs']['CVENumber'])))
# return result


if __name__ == "__main__":
a = ApiClient('info')
Expand Down
69 changes: 25 additions & 44 deletions rhsecapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
prog = 'rhsecapi'
vers = {}
vers['version'] = '1.0.0_rc8'
vers['date'] = '2016/11/27'
vers['date'] = '2016/11/29'


# Logging
Expand Down Expand Up @@ -199,7 +199,7 @@ def parse_args():
help="Select what page number to return (default: 1); only relevant when there are more than PAGESZ results")
g_listByAttr.add_argument(
'--q-raw', metavar="RAWQUERY", action='append',
help="Narrow down results by RAWQUERY (e.g.: '--q-raw a=x --q-raw b=y'); this allows passing arbitrary params (e.g. something new that is unsupported by {0})".format(prog))
help="Narrow down results by RAWQUERY (e.g.: '--q-raw a=x --q-raw b=y'); this allows passing arbitrary params (e.g. something new that is unknown to {0})".format(prog))
# New group
g_listByIava = p.add_argument_group(
'RETRIEVE SPECIFIC IAVAS')
Expand Down Expand Up @@ -338,69 +338,50 @@ def parse_args():

def main(opts):
apiclient = rhsda.ApiClient(opts.loglevel)
apiclient.cfg.apiUrl = 'https://accessci.usersys.redhat.com/labs/securitydataapi'
searchOutput = []
iavaOutput = []
# apiclient.cfg.apiUrl = 'https://accessci.usersys.redhat.com/labs/securitydataapi'
searchOutput = ""
iavaOutput = ""
cveOutput = ""
if opts.doSearch:
result = apiclient.cve_search_query(opts.searchParams, 'json')
if opts.extract_search:
result = apiclient.cve_search_query(params=opts.searchParams, outFormat='list')
for cve in result:
opts.cves.append(cve['CVE'])
elif not opts.count:
if opts.json:
searchOutput.append(rhsda.jprint(result))
else:
for cve in result:
searchOutput.append(cve['CVE'] + "\n")
opts.cves.append(cve)
elif opts.count:
result = apiclient.cve_search_query(params=opts.searchParams)
else:
searchOutput = apiclient.cve_search_query(params=opts.searchParams, outFormat=opts.outFormat, urls=opts.printUrls)
if not opts.json:
searchOutput += "\n"
if not opts.pastebin:
print(file=sys.stderr)
print("".join(searchOutput), end="")
print(searchOutput, end="")
elif opts.iavas:
logger.debug("IAVAs: {0}".format(opts.iavas))
if opts.extract_search:
oF = 'list'
result = apiclient.mget_iavas(iavas=opts.iavas, numThreads=opts.threads, onlyCount=opts.count, outFormat='list')
opts.cves.extend(result)
elif opts.count:
result = apiclient.mget_iavas(iavas=opts.iavas, numThreads=opts.threads, onlyCount=opts.count)
else:
oF = opts.outFormat
iavaOutput = apiclient.mget_iavas(iavas=opts.iavas,
numThreads=opts.threads,
onlyCount=opts.count,
outFormat=oF,
urls=opts.printUrls)
if iavaOutput:
if opts.extract_search:
opts.cves.extend(iavaOutput)
elif not opts.count:
if opts.json:
iavaOutput.append(rhsda.jprint(result))
# else:
# for iava in result:
# for cve in iava['cvelist']:
# iavaOutput.append(cve + "\n")
if not opts.pastebin:
print(file=sys.stderr)
print(iavaOutput, end="")
iavaOutput = apiclient.mget_iavas(iavas=opts.iavas, numThreads=opts.threads, outFormat=opts.outFormat, urls=opts.printUrls)
if not opts.pastebin:
print(file=sys.stderr)
print(iavaOutput, end="")
if opts.dryrun and opts.cves:
logger.log(25, "Skipping CVE retrieval due to --dryrun; would have retrieved: {0}".format(len(opts.cves)))
cveOutput = " ".join(opts.cves) + "\n"
elif opts.cves:
if searchOutput or iavaOutput:
print(file=sys.stderr)
cveOutput = apiclient.mget_cves(cves=opts.cves,
numThreads=opts.threads,
onlyCount=opts.count,
outFormat=opts.outFormat,
urls=opts.printUrls,
fields=opts.fields,
wrapWidth=opts.wrapWidth,
product=opts.product)
cveOutput = apiclient.mget_cves(cves=opts.cves, numThreads=opts.threads, onlyCount=opts.count, outFormat=opts.outFormat, urls=opts.printUrls, fields=opts.fields, wrapWidth=opts.wrapWidth, product=opts.product)
if opts.count:
return
if opts.pastebin:
opts.p_lang = 'text'
if opts.json or not opts.cves:
if opts.json:
opts.p_lang = 'Python'
data = "".join(searchOutput) + "".join(iavaOutput) + cveOutput
data = searchOutput + iavaOutput + cveOutput
try:
response = fpaste_it(inputdata=data, author=prog, lang=opts.p_lang, expire=opts.pexpire)
except ValueError as e:
Expand Down

0 comments on commit 768ec65

Please sign in to comment.