db.py 2.9 KB

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