db.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import binascii
  2. from collections import defaultdict
  3. import hashlib
  4. import hmac
  5. import os
  6. import time
  7. import tornado.gen
  8. import psycopg2
  9. import momoko
  10. import config
  11. def hash_pw(password, salt=None):
  12. if salt is None:
  13. salt = os.urandom(16)
  14. h = hmac.new(salt, password.encode('utf-8'), hashlib.sha256)
  15. hashed = h.hexdigest()
  16. salt_hex = binascii.hexlify(salt).decode()
  17. return hashed, salt_hex
  18. class MomokoDB:
  19. db = momoko.Pool(dsn='dbname=%s user=%s' % (config.database, config.db_user), size=2)
  20. @tornado.gen.coroutine
  21. def execute(self, query, *args):
  22. result = yield momoko.Op(self.db.execute, query, args, cursor_factory=psycopg2.extras.DictCursor)
  23. return result
  24. @tornado.gen.coroutine
  25. def create_user(self, username, password):
  26. hashed_password, salt = hash_pw(password)
  27. sql = 'INSERT INTO users (username, password, salt) VALUES (%s, %s, %s) RETURNING id;'
  28. cursor = yield self.execute(sql, username, hashed_password, salt)
  29. return cursor.fetchone()['id']
  30. @tornado.gen.coroutine
  31. def check_user(self, username, password):
  32. sql = 'SELECT id, username, password, salt FROM users WHERE username=%s;'
  33. cursor = yield self.execute(sql, username)
  34. user = cursor.fetchone()
  35. if not user:
  36. return
  37. salt = binascii.unhexlify(bytes(user['salt'], 'ascii'))
  38. hashed, _ = hash_pw(password, salt)
  39. if hashed == user['password']:
  40. return user
  41. @tornado.gen.coroutine
  42. def create_group(self, user_id, group_name):
  43. hmac_msg = ('%d%s%d' % (user_id, group_name, time.time())).encode('utf-8')
  44. h = hmac.new(config.cookie_secret.encode('utf-8'), hmac_msg, hashlib.sha1)
  45. sql = 'INSERT INTO groups (name, api_key) VALUES(%s, %s) RETURNING id;'
  46. cursor = yield self.execute(sql, group_name, h.hexdigest())
  47. group_id = cursor.fetchone()['id']
  48. yield self.execute('INSERT INTO user_groups (user_id, group_id) VALUES(%s, %s);', user_id, group_id)
  49. return group_id
  50. @tornado.gen.coroutine
  51. def get_groups(self, user_id):
  52. cursor = yield self.execute('''
  53. SELECT groups.id, groups.name, api_key FROM user_groups
  54. JOIN groups ON user_groups.group_id = groups.id
  55. WHERE user_id = %s;
  56. ''', user_id)
  57. return cursor.fetchall()
  58. @tornado.gen.coroutine
  59. def get_servers(self, user_id):
  60. cursor = yield self.execute('''
  61. SELECT servers.id, servers.group_id, servers.hostname FROM user_groups
  62. JOIN servers ON user_groups.group_id = servers.group_id
  63. WHERE user_id = %s;
  64. ''', user_id)
  65. servers = defaultdict(list)
  66. for row in cursor.fetchall():
  67. servers[row['group_id']].append(row)
  68. return servers
  69. @tornado.gen.coroutine
  70. def get_api_key(self, group_id):
  71. cursor = yield self.execute('SELECT api_key FROM groups WHERE id = %s', group_id)
  72. return cursor.fetchone()['api_key']