db.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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. hashed = hashlib.pbkdf2_hmac('sha512', password.encode('utf-8'), salt, 100000)
  15. hashed_hex = binascii.hexlify(hashed).decode()
  16. salt_hex = binascii.hexlify(salt).decode()
  17. return hashed_hex, 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, email, password):
  26. hashed, salt = hash_pw(password)
  27. sql = 'INSERT INTO users (email, password, salt) VALUES (%s, %s, %s) RETURNING id;'
  28. cursor = yield self.execute(sql, email, hashed, salt)
  29. return cursor.fetchone()['id']
  30. @tornado.gen.coroutine
  31. def check_user(self, email, password):
  32. sql = 'SELECT id, email, password, salt FROM users WHERE email=%s;'
  33. cursor = yield self.execute(sql, email)
  34. user = cursor.fetchone()
  35. if not user:
  36. return
  37. salt = binascii.unhexlify(user['salt'].encode())
  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 invite_user_group(self, user_id, email, group_id):
  52. cursor = yield self.execute('''
  53. SELECT 1 FROM user_groups WHERE user_id = %s AND group_id = %s;
  54. ''', user_id, group_id)
  55. if not cursor.fetchone():
  56. return
  57. cursor = yield self.execute('SELECT id FROM users WHERE email = %s;', email)
  58. user = cursor.fetchone()
  59. if not user:
  60. return
  61. user_id = user['id']
  62. yield self.execute('INSERT INTO user_groups (user_id, group_id) VALUES(%s, %s);', user_id, group_id)
  63. @tornado.gen.coroutine
  64. def get_groups(self, user_id):
  65. cursor = yield self.execute('''
  66. SELECT groups.id, groups.name, api_key FROM user_groups
  67. JOIN groups ON user_groups.group_id = groups.id
  68. WHERE user_id = %s;
  69. ''', user_id)
  70. return cursor.fetchall()
  71. @tornado.gen.coroutine
  72. def get_servers(self, user_id):
  73. cursor = yield self.execute('''
  74. SELECT servers.id, servers.group_id, servers.hostname FROM user_groups
  75. JOIN servers ON user_groups.group_id = servers.group_id
  76. WHERE user_id = %s;
  77. ''', user_id)
  78. servers = defaultdict(list)
  79. for row in cursor.fetchall():
  80. servers[row['group_id']].append(row)
  81. return servers
  82. @tornado.gen.coroutine
  83. def get_api_key(self, group_id):
  84. cursor = yield self.execute('SELECT api_key FROM groups WHERE id = %s', group_id)
  85. return cursor.fetchone()['api_key']