blob: 9e37004d56d5bb1276ec9aa16fe4cad91dd6982f [file] [log] [blame]
#!/usr/bin/python
"""
Background daemon to refresh OAuth access tokens.
Tokens are written to ~/.git-credential-cache/cookie
Git config variable http.cookiefile is updated.
Runs only on Google Compute Engine.
"""
import atexit
import contextlib
import cookielib
import json
import os
import subprocess
import sys
import time
import urllib2
REFRESH = 25 # seconds remaining when starting refresh
RETRY_INTERVAL = 5 # seconds between retrying a failed refresh
A = 'http://metadata/0.1/meta-data/service-accounts/default/acquire'
S = 'https://www.googleapis.com/auth/gerritcodereview'
COOKIE_JAR = None
def configure_git():
global COOKIE_JAR
dir = os.path.join(os.environ['HOME'], '.git-credential-cache')
COOKIE_JAR = os.path.join(dir, 'cookie')
if os.path.exists(dir):
os.chmod(dir, 0700)
else:
os.mkdir(dir, 0700)
subprocess.call([
'git', 'config', '--global',
'http.cookiefile', COOKIE_JAR
])
def acquire_token(retry):
while True:
try:
with contextlib.closing(urllib2.urlopen(A + '?scopes=' + S)) as token:
return json.load(token)
except urllib2.URLError:
if not retry:
raise
time.sleep(RETRY_INTERVAL)
def update_cookie(retry):
token = acquire_token(retry)
expires = token['expiresAt']
access_token = token['accessToken']
tmp_jar = COOKIE_JAR + '.lock'
cj = cookielib.MozillaCookieJar(tmp_jar)
cj.set_cookie(cookielib.Cookie(
version = 0,
name = 'o',
value = access_token,
port = None,
port_specified = False,
domain = 'source.developers.google.com',
domain_specified = True,
domain_initial_dot = False,
path = '/',
path_specified = True,
secure = True,
expires = expires,
discard = False,
comment = None,
comment_url = None,
rest = None))
cj.set_cookie(cookielib.Cookie(
version = 0,
name = 'o',
value = access_token,
port = None,
port_specified = False,
domain = '.googlesource.com',
domain_specified = True,
domain_initial_dot = True,
path = '/',
path_specified = True,
secure = True,
expires = expires,
discard = False,
comment = None,
comment_url = None,
rest = None))
cj.save()
os.rename(tmp_jar, COOKIE_JAR)
return expires
def cleanup():
if COOKIE_JAR:
for p in [COOKIE_JAR, COOKIE_JAR + '.lock']:
if os.path.exists(p):
os.remove(p)
def refresh_loop(expires):
atexit.register(cleanup)
expires = expires - REFRESH
while True:
now = time.time()
expires = max(expires, now + RETRY_INTERVAL)
while now < expires:
time.sleep(expires - now)
now = time.time()
expires = update_cookie(retry=True) - REFRESH
def main():
configure_git()
expires = update_cookie(retry=False)
if '--nofork' not in sys.argv:
if os.fork() > 0:
sys.exit(0)
os.chdir('/')
os.setsid()
os.umask(0)
pid = os.fork()
if pid > 0:
print '%s PID %d' % (sys.argv[0], pid)
sys.exit(0)
refresh_loop(expires)
if __name__ == '__main__':
main()