| import hashlib, hmac, base64 |
| from datetime import datetime, tzinfo, timedelta |
| import requests |
| import urllib |
| import json |
|
|
| class PandaRequest(object): |
| def __init__(self, verb, path, cred, data={}, timestamp=None): |
| self.verb = verb.upper() |
| self.path = self.canonical_path(path) |
| self.cred = cred |
| self.data = data |
| self.timestamp = timestamp |
|
|
| for name, val in self.data.iteritems(): |
| if isinstance(val, dict): |
| self.data[name] = json.dumps(val) |
|
|
| signed_params = self.signed_params() |
|
|
| self.files = None |
| if self.verb == 'POST' and ('file' in data): |
| self.files = {'file': open(data['file'], 'rb')} |
|
|
| self.requests_url = '%s%s' % (self.api_url(), path + "?" + self.canonical_querystring(signed_params)) |
|
|
| def send(self): |
| req = getattr(requests, self.verb.lower())(self.requests_url, files=self.files) |
| return req.text |
|
|
| def signed_params(self): |
| auth_params = self.data.copy() |
| auth_params['cloud_id'] = self.cred["cloud_id"] |
| auth_params['access_key'] = self.cred["access_key"] |
| auth_params['timestamp'] = self.timestamp or self.generate_timestamp() |
| additional_args = auth_params.copy() |
| additional_args.update(auth_params) |
|
|
| |
| if 'file' in additional_args: |
| del(additional_args['file']) |
|
|
| auth_params['signature'] = self.generate_signature(self.verb, self.path, self.cred["api_host"], self.cred["secret_key"], additional_args) |
| return auth_params |
|
|
| def api_protocol(self): |
| if str(self.cred["api_port"]) == '443': |
| return 'https' |
| else: |
| return 'http' |
|
|
| def api_url(self): |
| return self.api_protocol() + '://' + self.api_host_and_port() + self.api_path() |
|
|
| def api_host_and_port(self): |
| ret = self.cred["api_host"] |
| if str(self.cred["api_port"]) != '80': |
| ret += ':' + str(self.cred["api_port"]) |
| return ret |
|
|
| def api_path(self): |
| return '/v' + str(self.cred["api_version"]) |
|
|
| def generate_signature(self, verb, request_uri, host, secret_key, params={}): |
| query_string = self.canonical_querystring(params) |
| |
| string_to_sign = ( |
| verb.upper() + "\n" + |
| host.lower() + "\n" + |
| request_uri + "\n" + |
| query_string |
| ) |
| signature = hmac.new(secret_key, string_to_sign, hashlib.sha256).digest() |
| return base64.b64encode(signature).strip() |
| |
| def urlescape(self, s): |
| s = unicode(s).encode('utf-8') |
| return urllib.quote(s).replace("%7E", "~").replace(' ', '%20').replace('/', '%2F') |
| |
| def canonical_path(self, path): |
| return '/' + path.strip(' \t\n\r\0\x0B/') |
| |
| def canonical_querystring(self, d): |
| def recursion(d, base=None): |
| pairs = [] |
| |
| ordered_params = sorted([(k, v) for k, v in d.iteritems()]) |
| for key, value in ordered_params: |
| if key == 'file': |
| continue |
| if hasattr(value, 'values'): |
| pairs += recursion(value, key) |
| else: |
| new_pair = None |
| if base: |
| new_pair = "%s[%s]=%s" % (base, self.urlescape(key), self.urlescape(value)) |
| else: |
| new_pair = "%s=%s" % (self.urlescape(key), self.urlescape(value)) |
| pairs.append(new_pair) |
| return pairs |
| return '&'.join(recursion(d)) |
| |
| def generate_timestamp(self): |
| return datetime.now(UTC()).isoformat() |
|
|
| class UTC(tzinfo): |
| """UTC""" |
|
|
| def utcoffset(self, dt): |
| return timedelta(0) |
|
|
| def tzname(self, dt): |
| return "UTC" |
|
|
| def dst(self, dt): |
| return timedelta(0) |
|
|