Skip to content

Commit 9a07da9

Browse files
author
Casey Boettcher
committed
Adding in unit tests before moving further with web UI
1 parent 861efdb commit 9a07da9

File tree

6 files changed

+68
-35
lines changed

6 files changed

+68
-35
lines changed

test/test_xfipchk.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import unittest
2+
import xfipchk
3+
4+
5+
class TestXfipchk(unittest.TestCase):
6+
API_CREDS = './xforce.cfg'
7+
8+
def test_validate_ip(self):
9+
ADDRESS_FILE = './ips.txt'
10+
BAD_IPS = 4
11+
GOOD_IPS = 16
12+
13+
good, bad = 0
14+
with open(ADDRESS_FILE, 'r') as ipfile:
15+
for ip in ipfile:
16+
if xfipchk(ip):
17+
good += 1
18+
else:
19+
bad += 1
20+
21+
assert (good == GOOD_IPS and bad == BAD_IPS)
22+
23+
24+
if __name__ == '__main__':
25+
unittest.main()

test/web/__init__.py

Whitespace-only changes.

test/web/test_webui.py

Whitespace-only changes.

web/webui.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
#!/usr/bin/env python
22

33
import cherrypy
4-
import os
5-
import io
6-
4+
import xfipchk
75

86
class XforceForm(object):
97
def __init__(self, address='127.0.0.1', port=8000):
@@ -13,13 +11,17 @@ def __init__(self, address='127.0.0.1', port=8000):
1311
cherrypy.config.update({'server.socket_port': port,
1412
'server.socket_host': address})
1513

16-
# def start_server(self):
17-
# cherrypy.quickstart(XforceForm(), '/', './web/server.cfg')
1814

1915
@cherrypy.expose
2016
def index(self):
2117
return "/"
2218

19+
@cherrypy.expose()
20+
def process_form(self, api_key, api_password, ip_addresses):
21+
if isinstance(ip_addresses, list):
22+
xfipchk.r
23+
xfipchk.call_xforce_api(ip_addresses, api_key, api_password)
24+
2325

2426
if __name__ == '__main__':
2527
cherrypy.quickstart(XforceForm())

web/xfipchk.html

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</head>
1111
<body>
1212
<div id="column">
13-
<form id="the-form">
13+
<form id="the-form" action="process_form">
1414
<div>
1515
<p><span>Instructions:</span>
1616
<ol>
@@ -20,15 +20,15 @@
2020
</ol>
2121
</p>
2222
<label for="api-key">X-Force API Key</label>
23-
<input type="text" autofocus required class="api-cred" name="api-key" id="api-key" title="api-key"
23+
<input type="text" autofocus required class="api-cred" name="api_key" id="api-key" title="api-key"
2424
placeholder="01234567-9abc-def0-1234-56789abcdef0"/>
2525
<label for="api-password">X-Force API Password</label>
26-
<input type="text" class="api-cred" required name="api-password" id="api-password" title="api-password"
26+
<input type="text" class="api-cred" required name="api_password" id="api-password" title="api-password"
2727
placeholder="01234567-9abc-def0-1234-56789abcdef0"/>
2828
</div>
2929
<div>
3030
<label for="ip-addresses">IP Addresses</label>
31-
<input type="textarea" class="ip-addresses" id="ip-addresses"/>
31+
<input type="textarea" class="ip-addresses" name="ip_addresses" id="ip-addresses"/>
3232
</div>
3333
<script>
3434
$("the-form").validate();

xfipchk.py

+32-26
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
method of IBM's X-Force API to retrieve data describing the address's reputation.
99
1010
"""
11-
11+
import tempfile
1212
import os
1313
import sys
1414
import re
@@ -19,7 +19,6 @@
1919
import web.webui
2020
import cherrypy
2121

22-
2322
XFORCE_API_BASE = 'https://api.xforce.ibmcloud.com'
2423
XFORCE_API_IP_REP = 'ipr'
2524
XFORCE_CRED_PATTERN = '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
@@ -35,11 +34,13 @@ def parse_args():
3534
subparsers = parser.add_subparsers(help="Mutually exclusive sub-commands")
3635

3736
cli_parser = subparsers.add_parser('cli', help="Command-line Interface; run 'xfipchk cli -h' to see options")
38-
cli_parser.add_argument('-o', '--out', metavar='output_file',
39-
type=argparse.FileType('w'), help="Write result of X-Force call to file.")
37+
cli_parser.add_argument('-o', '--out', metavar='output_file', nargs='?',
38+
const=tempfile.NamedTemporaryFile(delete=False), type=argparse.FileType('w'),
39+
help="Write result of X-Force call to file; if this option is elected but no filename is "
40+
"provided, a file will be created for the user.")
4041
cli_parser.add_argument('authN', type=argparse.FileType('r'),
41-
help='Path to a file containing your X-Force credentials, key and password on first and second '
42-
'lines, respectively.')
42+
help='Path to a file containing your X-Force credentials, key and password on first and '
43+
'second lines, respectively.')
4344

4445
# user should not be able to specify both IP on cmdline and in a file
4546
ip_group = cli_parser.add_mutually_exclusive_group()
@@ -115,6 +116,17 @@ def read_in_address_file(file):
115116
return address_list
116117

117118

119+
def validate_api_creds(xforce_api_token):
120+
"""
121+
Validates the general form of a user submitted X-Force API key or password
122+
123+
:param xforce_api_token: an X-Force key or password, as generated by the X-Force API
124+
:return: True or False, as regards the validity of the token passed in
125+
"""
126+
matcher = re.compile(XFORCE_CRED_PATTERN)
127+
return matcher.match(xforce_api_token)
128+
129+
118130
def read_in_xforce_keys(file):
119131
"""
120132
Read a plaintext file of two lines and return X-Force credentials in the form of a tuple, validating general form
@@ -123,19 +135,13 @@ def read_in_xforce_keys(file):
123135
:param file: a two-line plaintext files; the first line contains the X-Force API key and the second the password
124136
:return: a tuple of (key, password)
125137
"""
126-
matcher = re.compile(XFORCE_CRED_PATTERN)
127-
for x in range(0, 2):
128-
if x == 0:
129-
key = file.readline().strip()
130-
if not matcher.match(key):
131-
print("API key invalid. Exiting...")
132-
sys.exit(1)
133-
if x == 1:
134-
password = file.readline().strip()
135-
if not matcher.match(password):
136-
print("API password invalid. Exiting...")
137-
sys.exit(1)
138-
return key, password
138+
key = file.readline().strip()
139+
password = file.readline().strip()
140+
if validate_api_creds(key) and validate_api_creds(password):
141+
return key, password
142+
else:
143+
print("API credentials invalid. Please check your key and password. Exiting...")
144+
sys.exit(1)
139145

140146

141147
def call_xforce_api(address_list, key, password):
@@ -148,7 +154,7 @@ def call_xforce_api(address_list, key, password):
148154
"""
149155
results = []
150156
for a in address_list:
151-
url = "{}/{}/{}".foGrmat(XFORCE_API_BASE, XFORCE_API_IP_REP, a)
157+
url = "{}/{}/{}".format(XFORCE_API_BASE, XFORCE_API_IP_REP, a)
152158
results.append(requests.get(url, auth=(key, password)).json())
153159
return results
154160

@@ -173,7 +179,7 @@ def print_json_file(results, file):
173179
:param results: a list of json objects
174180
:param file: the destination file for the printed list of json objects passed in
175181
"""
176-
print("Writing results to file...")
182+
print("Writing results to {}...".format(file.name))
177183
for json in results:
178184
file.write("\n########## Result for IP {} ##########\n".format(json['ip']))
179185
pprint.pprint(json, stream=file)
@@ -188,7 +194,7 @@ def start_server(address='127.0.0.1', port=8000):
188194
def main():
189195
args = parse_args()
190196
# if port is in Namespace object, assume web interface
191-
if args.port:
197+
if hasattr(args, 'port'):
192198
# TODO: should use a context manager here
193199
current = os.curdir
194200
try:
@@ -198,15 +204,15 @@ def main():
198204
print(ose.strerror)
199205
finally:
200206
os.chdir(current)
201-
202-
elif args.cli:
207+
# assume cli if user passed in api key file
208+
elif hasattr(args, 'authN'):
203209
ip = None
204210
addresses = list()
205-
if args.Ips:
211+
if getattr(args, 'Ips', False):
206212
addresses = read_in_address_file(args.Ips)
207213
else:
208214
# get user-supplied IP address from the cmd line
209-
if args.ip:
215+
if getattr(args, 'ip', False):
210216
ip = validate_ip(args.ip)
211217
# prompt user for valid IP in case of typo on cmdline
212218
while not ip:

0 commit comments

Comments
 (0)