import sys
import os
import psycopg2
-import ConfigParser
+import ConfigParser
+import requests
+import base64
+import json
+import time
+import datetime
+from Crypto.Cipher import AES
class KeySynchronizer(object):
def __init__(self, db):
def sync(self):
"""
- Perform the synchronization. This is going to be rather inefficient - we just
- load up the complete list of users in memory, and then write it to a local table.
-
- There's not likely (TM) to ever be a lot of data...
+ Perform the synchronization.
"""
- masterpg = psycopg2.connect(c.get('database','masterdb'))
curs = self.db.cursor()
- mcurs = masterpg.cursor()
+
+ # Record synctime at *start* of sync, in case it takes some time
+ synctime = datetime.datetime.now()
# Fetch last sync date, and see if anything has changed since
- curs.execute("SELECT lastsync FROM key_last_sync LIMIT 1")
+ curs.execute("SELECT lastsync-'5 minutes'::interval FROM key_last_sync LIMIT 1")
lastsync = curs.fetchone()[0]
- mcurs.execute("SELECT CURRENT_TIMESTAMP, CASE WHEN EXISTS (SELECT * FROM users_keys WHERE sshkey_last_update >= %s) THEN 1 ELSE 0 END", [lastsync])
- synctime, hasupd = mcurs.fetchone()
- if hasupd == 0:
- return # Nothing changed, just get out
-
- # Fetch a list of all keys on the master server
- mcurs.execute("SELECT userid, sshkey FROM users_keys")
- allkeys = mcurs.fetchall()
- mcurs.close()
- masterpg.close()
-
- # Load them into the local table
- curs.execute("TRUNCATE TABLE git_users")
- for row in allkeys:
- curs.execute("INSERT INTO git_users (userid, sshkey) VALUES (%s,%s)", row)
-
- # If there ever turns out to be a bunch, better analyze
- curs.execute("ANALYZE git_users")
-
- # Note the fact that we have synced (note that we use the timestamp value from the master,
- # in case there is clock skew)
+ r = requests.get("{0}/account/auth/{1}/getkeys/{2}/".format(
+ c.get('upstream', 'root'),
+ c.get('upstream', 'siteid'),
+ int(time.mktime(lastsync.timetuple())),
+ ))
+ if r.status_code != 200:
+ print("API call failed: %s" % r.status_code)
+ return
+
+ (ivs, datas) = str(r.text).split('&')
+ decryptor = AES.new(base64.b64decode(c.get('upstream', 'key')),
+ AES.MODE_CBC,
+ base64.b64decode(ivs, "-_"))
+ s = decryptor.decrypt(base64.b64decode(datas, "-_")).rstrip(' ')
+ j = json.loads(s)
+ for u in j:
+ curs.execute("INSERT INTO git_users (userid, sshkey) VALUES (%(userid)s, %(key)s) ON CONFLICT (userid) DO UPDATE SET sshkey=excluded.sshkey", {
+ 'userid': u['u'],
+ 'key': u['s'],
+ })
+
+ # Flag our last sync time
curs.execute("UPDATE key_last_sync SET lastsync=%s", [synctime])
self.db.commit()