db.py 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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, user_id, email, group_id):
  53. cursor = yield self.execute('''
  54. SELECT 1 FROM user_groups WHERE user_id = %s AND group_id = %s;
  55. ''', user_id, group_id)
  56. if not cursor.fetchone():
  57. return
  58. cursor = yield self.execute('SELECT id FROM users WHERE email = %s;', email)
  59. user = cursor.fetchone()
  60. if not user:
  61. return
  62. user_id = cursor.fetchone()['id']
  63. yield self.execute('INSERT INTO user_groups (user_id, group_id) VALUES(%s, %s);', user_id, group_id)
  64. @tornado.gen.coroutine
  65. def get_groups(self, user_id):
  66. cursor = yield self.execute('''
  67. SELECT groups.id, groups.name, api_key FROM user_groups
  68. JOIN groups ON user_groups.group_id = groups.id
  69. WHERE user_id = %s;
  70. ''', user_id)
  71. return cursor.fetchall()
  72. @tornado.gen.coroutine
  73. def get_servers(self, user_id):
  74. cursor = yield self.execute('''
  75. SELECT servers.id, servers.group_id, servers.hostname FROM user_groups
  76. JOIN servers ON user_groups.group_id = servers.group_id
  77. WHERE user_id = %s;
  78. ''', user_id)
  79. servers = defaultdict(list)
  80. for row in cursor.fetchall():
  81. servers[row['group_id']].append(row)
  82. return servers
  83. @tornado.gen.coroutine
  84. def get_api_key(self, group_id):
  85. cursor = yield self.execute('SELECT api_key FROM groups WHERE id = %s', group_id)
  86. return cursor.fetchone()['api_key']