db.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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 = hashlib.pbkdf2_hmac('sha512', password.encode('utf-8'), salt, 100000)
  16. hashed_hex = binascii.hexlify(hashed).decode()
  17. salt_hex = binascii.hexlify(salt).decode()
  18. return hashed_hex, salt_hex
  19. class MomokoDB:
  20. db = momoko.Pool(dsn='dbname=%s user=%s' % (config.database, config.db_user), size=2)
  21. @tornado.gen.coroutine
  22. def execute(self, query, *args):
  23. result = yield momoko.Op(self.db.execute, query, args, cursor_factory=psycopg2.extras.DictCursor)
  24. return result
  25. @tornado.gen.coroutine
  26. def create_user(self, email, password):
  27. hashed, salt = hash_pw(password)
  28. sql = 'INSERT INTO users (email, password, salt) VALUES (%s, %s, %s) RETURNING id;'
  29. cursor = yield self.execute(sql, email, hashed, salt)
  30. return cursor.fetchone()['id']
  31. @tornado.gen.coroutine
  32. def check_user(self, email, password):
  33. sql = 'SELECT id, email, password, salt FROM users WHERE email=%s;'
  34. cursor = yield self.execute(sql, email)
  35. user = cursor.fetchone()
  36. if not user:
  37. return
  38. salt = binascii.unhexlify(user['salt'].encode())
  39. hashed, _ = hash_pw(password, salt)
  40. if hashed == user['password']:
  41. return user
  42. @tornado.gen.coroutine
  43. def create_group(self, user_id, group_name):
  44. hmac_msg = ('%d%s%d' % (user_id, group_name, time.time())).encode('utf-8')
  45. h = hmac.new(config.cookie_secret.encode('utf-8'), hmac_msg, hashlib.sha1)
  46. sql = 'INSERT INTO groups (name, api_key) VALUES(%s, %s) RETURNING id;'
  47. cursor = yield self.execute(sql, group_name, h.hexdigest())
  48. group_id = cursor.fetchone()['id']
  49. yield self.execute('INSERT INTO user_groups (user_id, group_id) VALUES(%s, %s);', user_id, group_id)
  50. return group_id
  51. @tornado.gen.coroutine
  52. def invite_user_group(self, email, group_id):
  53. cursor = yield self.execute('SELECT id FROM users WHERE email = %s;', email)
  54. user_id = cursor.fetchone()['id']
  55. yield self.execute('INSERT INTO user_groups (user_id, group_id) VALUES(%s, %s);', user_id, group_id)
  56. @tornado.gen.coroutine
  57. def get_groups(self, user_id):
  58. cursor = yield self.execute('''
  59. SELECT groups.id, groups.name, api_key FROM user_groups
  60. JOIN groups ON user_groups.group_id = groups.id
  61. WHERE user_id = %s;
  62. ''', user_id)
  63. return cursor.fetchall()
  64. @tornado.gen.coroutine
  65. def get_servers(self, user_id):
  66. cursor = yield self.execute('''
  67. SELECT servers.id, servers.group_id, servers.hostname FROM user_groups
  68. JOIN servers ON user_groups.group_id = servers.group_id
  69. WHERE user_id = %s;
  70. ''', user_id)
  71. servers = defaultdict(list)
  72. for row in cursor.fetchall():
  73. servers[row['group_id']].append(row)
  74. return servers
  75. @tornado.gen.coroutine
  76. def get_api_key(self, group_id):
  77. cursor = yield self.execute('SELECT api_key FROM groups WHERE id = %s', group_id)
  78. return cursor.fetchone()['api_key']