Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
*This repo has had small changes to now work with python3.*

# rhsecapi

`rhsecapi` makes it easy to interface with the [Red Hat Security Data API](https://access.redhat.com/documentation/en/red-hat-security-data-api/) -- even from [behind a proxy](https://github.com/ryran/rhsecapi/issues/29). From the rpm description:
Expand Down
31 changes: 17 additions & 14 deletions rhsda.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/python2
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Copyright 2016, 2017
Expand All @@ -16,18 +16,20 @@
#-------------------------------------------------------------------------------

# Modules from standard library
from __future__ import print_function
# from __future__ import print_function
import requests
import logging
import sys
import re
import textwrap, fcntl, termios, struct
import json
import signal
import copy_reg
import copyreg
import types
import multiprocessing as mp
import multiprocessing.dummy as multiprocessing
from argparse import Namespace
from io import TextIOWrapper


# Logging
Expand Down Expand Up @@ -101,7 +103,6 @@
# A list of all fields + all aliases
cveFields.all_plus_aliases = list(cveFields.all)
cveFields.all_plus_aliases.extend([k for k in cveFields.aliases])
del(k)


# Regex to match a CVE id string
Expand All @@ -118,14 +119,14 @@ def _reduce_method(m):
else:
return getattr, (m.__self__, m.__func__.__name__)

copy_reg.pickle(types.MethodType, _reduce_method)
copyreg.pickle(types.MethodType, _reduce_method)


# Set default number of worker threads
if multiprocessing.cpu_count() <= 2:
if mp.cpu_count() <= 2:
numThreadsDefault = 4
else:
numThreadsDefault = multiprocessing.cpu_count() * 2
numThreadsDefault = mp.cpu_count() * 2


def jprint(jsoninput):
Expand Down Expand Up @@ -175,7 +176,7 @@ class ApiClient:

def __init__(self, logLevel='notice'):
self.cfg = Namespace()
self.cfg.apiUrl = 'https://access.redhat.com/labs/securitydataapi'
self.cfg.apiUrl = 'https://access.redhat.com/hydra/rest/securitydata'
logger.setLevel(logLevel.upper())

def _get_terminal_width(self):
Expand All @@ -192,7 +193,9 @@ def __validate_out_format(self, oF):
if oF not in outFormats:
raise ValueError("Invalid outFormat type ('{0}') requested; should be one of: {1}".format(oF, ", ".join(outFormats)))

def __get(self, url, params={}):
def __get(self, url, params=None):
if params is None:
params = {}
url = self.cfg.apiUrl + url
u = ""
if params:
Expand All @@ -217,7 +220,7 @@ def __get(self, url, params={}):
if 'application/json' in r.headers['Content-Type']:
return r.json()
else:
return r.content
return r.text

def _find(self, dataType, params, outFormat):
self.__validate_data_type(dataType)
Expand Down Expand Up @@ -368,11 +371,11 @@ def __stripjoin(self, input, oneLineEach=False):
text = ""
if isinstance(input, list):
if oneLineEach:
text = "\n".join(input).encode('utf-8').strip()
text = "\n".join(input).strip()
else:
text = " ".join(input).encode('utf-8').strip()
text = " ".join(input).strip()
else:
text = input.encode('utf-8').strip()
text = input.strip()
if oneLineEach:
text = "\n" + text
text = re.sub(r"\n[\n\s]*", "\n ", text)
Expand Down Expand Up @@ -728,7 +731,7 @@ def mget_cves(self, cves, numThreads=0, onlyCount=False, outFormat='plaintext',
"""
if outFormat not in ['plaintext', 'json', 'jsonpretty']:
raise ValueError("Invalid outFormat ('{0}') requested; should be one of: 'plaintext', 'json', 'jsonpretty'".format(outFormat))
if isinstance(cves, str) or isinstance(cves, file):
if isinstance(cves, str) or isinstance(cves, TextIOWrapper):
cves = extract_cves_from_input(cves)
elif not isinstance(cves, list):
raise ValueError("Invalid 'cves=' argument input; must be list, string, or file obj")
Expand Down
17 changes: 9 additions & 8 deletions rhsecapi.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/python2
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# PYTHON_ARGCOMPLETE_OK
#-------------------------------------------------------------------------------
Expand Down Expand Up @@ -83,7 +83,7 @@ def fpaste_it(inputdata, lang='text', author=None, password=None, private='no',
params['paste_user'] = author
# Check size of what we're about to post and raise exception if too big
# FIXME: Figure out how to do this in requests without wasteful call to urllib.urlencode()
from urllib import urlencode
from urllib.parse import urlencode
p = urlencode(params)
pasteSizeKiB = len(p)/1024.0
if pasteSizeKiB >= 512:
Expand All @@ -98,11 +98,11 @@ def fpaste_it(inputdata, lang='text', author=None, password=None, private='no',
# If no json returned, we've hit some weird error
from tempfile import NamedTemporaryFile
tmp = NamedTemporaryFile(delete=False)
print(r.content, file=tmp)
tmp.write(r.content)
tmp.flush()
raise ValueError("Fedora Pastebin client ERROR: Didn't receive expected JSON response (saved to '{0}' for debugging)".format(tmp.name))
# Error keys adapted from Jason Farrell's fpaste
if j.has_key('error'):
if 'error' in j:
err = j['error']
if err == 'err_spamguard_php':
raise ValueError("Fedora Pastebin server ERROR: Poster's IP rejected as malicious")
Expand All @@ -118,7 +118,7 @@ def fpaste_it(inputdata, lang='text', author=None, password=None, private='no',
raise ValueError("Fedora Pastebin server ERROR: '{0}'".format(err))
# Put together URL with optional hash if requested
pasteUrl = '{0}/{1}'.format(url, j['result']['id'])
if 'yes' in private and j['result'].has_key('hash'):
if 'yes' in private and 'hash' in j['result']:
pasteUrl += '/{0}'.format(j['result']['hash'])
return pasteUrl

Expand Down Expand Up @@ -283,7 +283,8 @@ def parse_args():
if o.showHelp:
from tempfile import NamedTemporaryFile
from subprocess import call
tmp = NamedTemporaryFile(prefix='{0}-help-'.format(prog), suffix='.txt')
#tmp = NamedTemporaryFile(prefix='{0}-help-'.format(prog), suffix='.txt')
tmp = NamedTemporaryFile(mode='w+', prefix='{0}-help-'.format(prog), suffix='.txt')
p.print_help(file=tmp)
tmp.flush()
call(['less', tmp.name])
Expand Down Expand Up @@ -347,7 +348,7 @@ def parse_args():
def main(opts):
apiclient = rhsda.ApiClient(opts.loglevel)
from os import environ
if environ.has_key('RHSDA_URL') and environ['RHSDA_URL'].startswith('http'):
if 'RHSDA_URL' in environ and environ['RHSDA_URL'].startswith('http'):
apiclient.cfg.apiUrl = environ['RHSDA_URL']
searchOutput = ""
iavaOutput = ""
Expand Down Expand Up @@ -404,7 +405,7 @@ def main(opts):
except ValueError as e:
print(e, file=sys.stderr)
logger.error("Submitting to pastebin failed; print results to stdout instead? [y]")
answer = raw_input("> ")
answer = input("> ")
if "y" in answer or len(answer) == 0:
print(data, end="")
else:
Expand Down