2121
2222__docformat__ = 'restructuredtext'
2323
24- import json
25- import urllib
24+ import requests
25+ from requests .packages .urllib3 .exceptions import InsecureRequestWarning
26+
2627from acsrf import acsrf
2728from ascan import ascan
2829from ajaxSpider import ajaxSpider
@@ -58,8 +59,7 @@ class ZAPv2(object):
5859 # base OTHER api url
5960 base_other = 'http://zap/OTHER/'
6061
61- def __init__ (self , proxies = {'http' : 'http://127.0.0.1:8080' ,
62- 'https' : 'http://127.0.0.1:8080' }):
62+ def __init__ (self , proxies = None , apikey = None ):
6363 """
6464 Creates an instance of the ZAP api client.
6565
@@ -69,7 +69,11 @@ def __init__(self, proxies={'http': 'http://127.0.0.1:8080',
6969 Note that all of the other classes in this directory are generated
7070 new ones will need to be manually added to this file
7171 """
72- self .__proxies = proxies
72+ self .__proxies = proxies or {
73+ 'http' : 'http://127.0.0.1:8080' ,
74+ 'https' : 'http://127.0.0.1:8080'
75+ }
76+ self .__apikey = apikey
7377
7478 self .acsrf = acsrf (self )
7579 self .ajaxSpider = ajaxSpider (self )
@@ -95,6 +99,15 @@ def __init__(self, proxies={'http': 'http://127.0.0.1:8080',
9599 self .stats = stats (self )
96100 self .users = users (self )
97101
102+ # not very nice, but prevents warnings when accessing the ZAP API via https
103+ requests .packages .urllib3 .disable_warnings (InsecureRequestWarning )
104+
105+ # Currently create a new session for each request to prevent request failing
106+ # e.g. when polling the spider status
107+ #self.session = requests.Session()
108+ #if apikey is not None:
109+ # self.session.headers['X-ZAP-API-Key'] = apikey
110+
98111 def urlopen (self , * args , ** kwargs ):
99112 """
100113 Opens a url forcing the proxies to be used.
@@ -103,25 +116,50 @@ def urlopen(self, *args, **kwargs):
103116 - `args`: all non-keyword arguments.
104117 - `kwargs`: all other keyword arguments.
105118 """
106- kwargs ['proxies' ] = self .__proxies
107- return urllib .urlopen (* args , ** kwargs ).read ()
119+ # Must never leak the API key via proxied requests
120+ return requests .get (* args , proxies = self .__proxies , verify = False , ** kwargs ).text
121+
122+ def _request_api (self , url , query = None ):
123+ """
124+ Shortcut for an API request. Will always add the apikey (if defined)
125+
126+ :Parameters:
127+ - `url`: the url to GET at.
128+ """
129+ if not url .startswith ('http://zap/' ):
130+ # Only allow requests to the API so that we never leak the apikey
131+ raise ValueError ('A non ZAP API url was specified ' + url )
132+ return ;
133+
134+ # In theory we should be able to reuse the session,
135+ # but there have been problems with that
136+ self .session = requests .Session ()
137+ if self .__apikey is not None :
138+ self .session .headers ['X-ZAP-API-Key' ] = self .__apikey
139+
140+ query = query or {}
141+ if self .__apikey is not None :
142+ # Add the apikey to get params for backwards compatibility
143+ if not query .get ('apikey' ):
144+ query ['apikey' ] = self .__apikey
145+ return self .session .get (url , params = query , proxies = self .__proxies , verify = False )
108146
109147 def _request (self , url , get = None ):
110148 """
111149 Shortcut for a GET request.
112150
113151 :Parameters:
114152 - `url`: the url to GET at.
115- - `get`: the disctionary to turn into GET variables.
153+ - `get`: the dictionary to turn into GET variables.
116154 """
117- return json . loads ( self .urlopen (url + '?' + urllib . urlencode ( get or {})) )
155+ return self ._request_api (url , get ). json ( )
118156
119- def _request_other (self , url , get = {} ):
157+ def _request_other (self , url , get = None ):
120158 """
121159 Shortcut for an API OTHER GET request.
122160
123161 :Parameters:
124162 - `url`: the url to GET at.
125- - `get`: the disctionary to turn into GET variables.
163+ - `get`: the dictionary to turn into GET variables.
126164 """
127- return self .urlopen (url + '?' + urllib . urlencode ( get or {}))
165+ return self ._request_api (url , get ). text
0 commit comments