-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathvcarcher.py
160 lines (126 loc) · 5.54 KB
/
vcarcher.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import sys
import argparse
import logging
import json
import time
import datetime
from lxml import etree
from veracode_api_py import VeracodeAPI as vapi
def creds_expire_days_warning():
creds = vapi().get_creds()
exp = datetime.datetime.strptime(creds['expiration_ts'], "%Y-%m-%dT%H:%M:%S.%f%z")
delta = exp - datetime.datetime.now().astimezone() #we get a datetime with timezone...
if (delta.days < 7):
print('These API credentials expire ', creds['expiration_ts'])
def generate(period,from_date, to_date,scan_type):
params = {}
# parse args
if period == 'last-day':
period = 'yesterday'
elif period == 'last-week':
period = 'last_week'
elif period == 'last-month':
period = 'last_month'
elif period == 'all-time':
period = None
if period == 'range':
period = None
if not(from_date==None):
params['from_date'] = from_date
if not(to_date==None):
params['to_date'] = to_date
if not(period==None):
params['period'] = period
if not(scan_type==None):
params['scan_type'] = scan_type
if params=={}:
paramsobject = None
else:
paramsobject = params
# Initiate the Archer report generation job with provided parameters, returns a token
requestdata = vapi().generate_archer(payload=paramsobject)
return gettoken(requestdata)
def gettoken(requestdata):
# processes the response to generatearcherreport.do to identify the token to retrieve the archer job
archerroot = etree.fromstring(requestdata)
return archerroot.get('token')
def downloadreport(token):
# this will retry until the report is ready, with a 15 second wait between retries
response = vapi().download_archer(token)
# handle case where response is empty
if (reportlength(response) == 0):
return None
return response
def cleanup(report):
# selectively manually urldecode some stuff in the header; we don't want to urldecode the whole payload
report = report.replace("http://","http://")
report = report.replace("https://","https://")
report = report.replace("com/","com/")
report = report.replace("/2001/","/2001/")
report = report.replace("schema/2.0/","schema/2.0/")
report = report.replace("resource/2.0/","resource/2.0/")
report = report.replace("(","(")
report = report.replace(")",")")
# remove empty custom fields
report_root = etree.fromstring(report.encode())
apps = report_root.findall('{http://www.archer-tech.com/}Record')
for app in apps:
customfields = app.findall('{http://www.archer-tech.com/}customfield')
for customfield in reversed(customfields):
if customfield.get('value') == '':
app.remove(customfield)
return report_root
def reportlength(response):
numentries = len(response)
return numentries
def writereportfile(report):
report_tree = etree.ElementTree(report)
""" f = open("archerreport.xml","w")
f.write(report)
f.close() """
report_tree.write("archerreport.xml",method="xml")
print("Wrote report to archerreport.xml containing",reportlength(report),"entries")
def main():
parser = argparse.ArgumentParser(
description='This script adds the Security Labs User role for existing users. It can operate on one user '
'or all users in the account.')
parser.add_argument('-i', '--interval', required=False, help='Interval over which to import data. Options: last-day (default), last-week, last-month, all-time, range.',default='last-week')
parser.add_argument('-f', '--from_date', required=False, help='The date (mm-dd-yyyy) on which to begin the import range. Required if -i is "range."')
parser.add_argument('-t', '--to_date', required=False, help='The date (mm-dd-yyyy) on which to end the import range. Required if -i is "range."')
parser.add_argument('-s', '--scan_type', required=False, help='The scan type to import. Options: static, dynamic, manual.')
args = parser.parse_args()
period = args.interval
from_date = args.from_date
to_date = args.to_date
scan_type = args.scan_type
logging.basicConfig(filename='vcarcher.log',
format='%(asctime)s - %(levelname)s - %(funcName)s - %(message)s',
datefmt='%m/%d/%Y %I:%M:%S%p',
level=logging.INFO)
# CHECK FOR CREDENTIALS EXPIRATION
creds_expire_days_warning()
token=None
# cache token
print("Generating the Archer report")
token = generate(period, from_date, to_date, scan_type)
if token == 0:
logging.error("Error generating report. Got a 0 token\r\n{}\r\n{}\r\n{}\r\n\r\n{}\r\n"
.format(period,from_date,to_date,scan_type))
return
logging.debug("Got token:\r\n{}\r\n{}\r\n{}\r\n\r\n{}\r\n{}\r\n"
.format(token,period,from_date,to_date,scan_type))
# wait
time.sleep(5)
# call downloadarcherreport.do
print("Downloading the Archer report for token",token)
report = downloadreport(token)
if report == None:
logging.warning("No entries in Archer report for this time period:\r\n{}\r\n{}\r\n{}\r\n\r\n{}\r\n"
.format(period,from_date,to_date,scan_type))
else:
# clean up report - urldecode header
reportdecode = cleanup(report.decode('utf-8'))
# write to file
writereportfile(reportdecode)
if __name__ == '__main__':
main()