368
374
time.sleep(sleep_time)
379
class OauthUrlHelper(object):
380
def __init__(self, consumer_key=None, token_key=None,
381
token_secret=None, consumer_secret=None,
382
skew_data_file="/run/oauth_skew.json"):
383
self.consumer_key = consumer_key
384
self.consumer_secret = consumer_secret or ""
385
self.token_key = token_key
386
self.token_secret = token_secret
387
self.skew_data_file = skew_data_file
388
self._do_oauth = True
389
self.skew_change_limit = 5
390
required = (self.token_key, self.token_secret, self.consumer_key)
391
if not any(required):
392
self._do_oauth = False
393
elif not all(required):
394
raise ValueError("all or none of token_key, token_secret, or "
395
"consumer_key can be set")
397
old = self.read_skew_file()
398
self.skew_data = old or {}
400
def read_skew_file(self):
401
if self.skew_data_file and os.path.isfile(self.skew_data_file):
402
with open(self.skew_data_file, mode="r") as fp:
403
return json.load(fp.read())
406
def update_skew_file(self, host, value):
408
if not self.skew_data_file:
410
cur = self.read_skew_file()
412
with open(self.skew_data_file, mode="w") as fp:
413
fp.write(json.dumps(cur))
415
def exception_cb(self, msg, exception):
416
if not (isinstance(exception, UrlError) and
417
(exception.code == 403 or exception.code == 401)):
420
if 'date' not in exception.headers:
421
LOG.warn("Missing header 'date' in %s response", exception.code)
424
date = exception.headers['date']
426
remote_time = time.mktime(parsedate(date))
427
except Exception as e:
428
LOG.warn("Failed to convert datetime '%s': %s", date, e)
431
skew = int(remote_time - time.time())
432
host = urlparse(exception.url).netloc
433
old_skew = self.skew_data.get(host, 0)
434
if abs(old_skew - skew) > self.skew_change_limit:
435
self.update_skew_file(host, skew)
436
LOG.warn("Setting oauth clockskew for %s to %d", host, skew)
437
skew_data[host] = skew
441
def headers_cb(self, url):
442
if not self._do_oauth:
446
host = urlparse(url).netloc
447
if self.skew_data and host in self.skew_data:
448
timestamp = int(time.time()) + self.skew_data[host]
450
return oauth_headers(
451
url=url, consumer_key=self.consumer_key,
452
token_key=self.token_key, token_secret=self.token_secret,
453
consumer_secret=self.consumer_secret, timestamp=timestamp)
455
def _wrapped(self, wrapped_func, args, kwargs):
456
kwargs['headers_cb'] = partial(
457
self._headers_cb, kwargs.get('headers_cb'))
458
kwargs['exception_cb'] = partial(
459
self._exception_cb, kwargs.get('exception_cb'))
460
return wrapped_func(*args, **kwargs)
462
def wait_for_url(self, *args, **kwargs):
463
return self._wrapped(wait_for_url, args, kwargs)
465
def readurl(self, *args, **kwargs):
466
return self._wrapped(readurl, args, kwargs)
468
def _exception_cb(self, extra_exception_cb, msg, exception):
471
if extra_exception_cb:
472
ret = extra_exception_cb(msg, exception)
474
self.exception_cb(msg, exception)
477
def _headers_cb(self, extra_headers_cb, url):
480
headers = extra_headers_cb(url)
481
headers.update(self.headers_cb(url))
485
def oauth_headers(url, consumer_key, token_key, token_secret, consumer_secret,
488
timestamp = str(timestamp)
492
client = oauth1.Client(
494
client_secret=consumer_secret,
495
resource_owner_key=token_key,
496
resource_owner_secret=token_secret,
497
signature_method=oauth1.SIGNATURE_PLAINTEXT,
499
uri, signed_headers, body = client.sign(url)
500
return signed_headers