You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 lines
8.7 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. import ldap as l
  2. from ldap3 import Server, Connection, ALL, MODIFY_REPLACE
  3. from ldap3.core.exceptions import LDAPBindError
  4. from flask import Flask, g, request, session, redirect, url_for, render_template, flash
  5. from flask_bs4 import Bootstrap
  6. from flask_sqlalchemy import SQLAlchemy
  7. from flask_login import LoginManager, login_manager, current_user, login_user, \
  8. logout_user, login_required
  9. from flask_wtf import FlaskForm
  10. from wtforms import StringField, PasswordField, BooleanField, SubmitField
  11. from wtforms.validators import DataRequired
  12. import yaml
  13. import datetime as dt
  14. import pytz
  15. import os
  16. import sqlite3
  17. app = Flask(__name__)
  18. Bootstrap(app)
  19. app.secret_key = 'asdf'
  20. app.debug = True
  21. app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
  22. app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
  23. app.config['WTF_CSRF_SECRET_KEY'] = 'asdf'
  24. # Base
  25. app.config['LDAP_REALM_NAME'] = 'OpenLDAP Authentication'
  26. app.config['LDAP_HOST'] = os.environ.get('LDAP_HOST')
  27. app.config['LDAP_BASE_DN'] = os.environ.get('LDAP_BASE_DN')
  28. app.config['LDAP_USERNAME'] = os.environ.get('LDAP_USERNAME')
  29. app.config['LDAP_PASSWORD'] = os.environ.get('LDAP_PASSWORD')
  30. # OpenLDAP
  31. app.config['LDAP_OBJECTS_DN'] = 'dn'
  32. app.config['LDAP_OPENLDAP'] = True
  33. app.config['LDAP_USER_OBJECT_FILTER'] = '(&(objectclass=posixAccount)(uid=%s))'
  34. # Login cookies
  35. app.config['REMEMBER_COOKIE_DOMAIN'] = os.environ.get('COOKIE_DOMAIN')
  36. db = SQLAlchemy(app)
  37. login_manager = LoginManager(app)
  38. login_manager.init_app(app)
  39. login_manager.login_view = 'login'
  40. db.create_all()
  41. eastern = pytz.timezone('US/Eastern')
  42. with open('config/config.yaml') as f:
  43. yaml_data = yaml.load(f, Loader=yaml.SafeLoader)
  44. search = yaml_data['search']
  45. account_url = yaml_data['accounts']['account_url']
  46. description = yaml_data['description']
  47. game_description = yaml_data['game_description']
  48. countdown_data = None
  49. if yaml_data['countdown']['active'] == True:
  50. countdown_data = yaml_data['countdown']
  51. final_countdown_data = None
  52. final_time = None
  53. if yaml_data['final_countdown']['active'] == True:
  54. final_countdown_data = yaml_data['final_countdown']
  55. final_time = eastern.localize(dt.datetime.strptime(final_countdown_data['timestamp'], '%B %d %Y %H:%M:%S%z').replace(tzinfo=None))
  56. apps = []
  57. for itm in yaml_data['apps'].items():
  58. apps.append(itm[1])
  59. games = []
  60. for itm in yaml_data['games'].items():
  61. games.append(itm[1])
  62. server = Server(app.config['LDAP_HOST'])
  63. conn = Connection(server, app.config['LDAP_USERNAME'], app.config['LDAP_PASSWORD'], auto_bind=True)
  64. class User(db.Model):
  65. __tablename__ = 'user'
  66. id = db.Column(db.Integer, primary_key=True)
  67. username = db.Column(db.String(100))
  68. password = db.Column(db.String(128))
  69. authenticated = db.Column(db.Boolean, default=False)
  70. def __init__(self, username, password):
  71. self.username = username
  72. self.password = password
  73. @staticmethod
  74. def try_login(username, password):
  75. conn.search(app.config['LDAP_BASE_DN'], app.config['LDAP_USER_OBJECT_FILTER'] % username, attributes=['*'])
  76. if len(conn.entries) > 0:
  77. Connection(app.config['LDAP_HOST'], conn.entries[0].entry_dn, password, auto_bind=True)
  78. return
  79. raise LDAPBindError
  80. def is_authenticated(self):
  81. return self.authenticated
  82. def is_active(self):
  83. return True
  84. def is_anonymous(self):
  85. return False
  86. def get_id(self):
  87. return self.id
  88. def get_user_dict(self):
  89. user = {'dn': '',
  90. 'firstName': '',
  91. 'lastName': '',
  92. 'email': '',
  93. 'userName': self.username,
  94. }
  95. conn.search(app.config['LDAP_BASE_DN'], app.config['LDAP_USER_OBJECT_FILTER'] % self.username, attributes=['*'])
  96. user['dn'] = conn.entries[0].entry_dn
  97. user['firstName'] = conn.entries[0].givenName.value
  98. user['lastName'] = conn.entries[0].sn.value
  99. user['email'] = conn.entries[0].mail.value
  100. return user
  101. class LoginForm(FlaskForm):
  102. username = StringField('Username', validators=[DataRequired()])
  103. password = PasswordField('Password', validators=[DataRequired()])
  104. remember_me = BooleanField('Remember Me')
  105. submit = SubmitField('Sign In')
  106. @login_manager.user_loader
  107. def load_user(id):
  108. return User.query.get(int(id))
  109. @app.before_request
  110. def get_current_user():
  111. g.user = current_user
  112. @app.route('/')
  113. def index():
  114. current_time = eastern.localize(dt.datetime.now())
  115. if final_countdown_data != None:
  116. if (final_time - current_time).days > -1:
  117. return render_template('final_countdown.j2', final_countdown = final_countdown_data)
  118. if countdown_data != None:
  119. return render_template('index.j2', apps = apps, search = search, account_url = account_url, description = description, countdown = countdown_data)
  120. return render_template('index.j2', apps = apps, search = search, account_url = account_url, description = description)
  121. @app.route('/games')
  122. def game():
  123. current_time = eastern.localize(dt.datetime.now())
  124. if final_countdown_data != None:
  125. if (final_time - current_time).days > -1:
  126. return render_template('final_countdown.j2', final_countdown = final_countdown_data)
  127. if countdown_data != None:
  128. return render_template('games.j2', apps = games, search = search, account_url = account_url, description = game_description, countdown = countdown_data)
  129. if current_user.is_authenticated:
  130. return render_template('games.j2', apps = games, search = search, account_url = account_url, description = game_description, user = current_user.get_user_dict(), game_list = generate_game_list())
  131. return render_template('games.j2', apps = games, search = search, account_url = account_url, description = game_description)
  132. @app.route('/login', methods=['GET', 'POST'])
  133. def login():
  134. if current_user.is_authenticated:
  135. flash('You are already logged in.')
  136. return redirect(url_for('auth.home'))
  137. form = LoginForm(request.form)
  138. print(form)
  139. print(request.method)
  140. if request.method == 'POST' and form.validate():
  141. username = request.form.get('username')
  142. password = request.form.get('password')
  143. print(username)
  144. print(password)
  145. try:
  146. User.try_login(username, password)
  147. except LDAPBindError:
  148. flash(
  149. 'Invalid username or password. Please try again.',
  150. 'danger')
  151. return render_template('login.j2', form=form)
  152. user = User.query.filter(User.username == username).first()
  153. print(user)
  154. if user is None:
  155. user = User(username, password)
  156. db.session.add(user)
  157. user.authenticated = True
  158. db.session.commit()
  159. login_user(user, remember=form.remember_me.data)
  160. print('You have successfully logged in.')
  161. return redirect('/games')
  162. if form.errors:
  163. flash(form.errors, 'danger')
  164. return render_template('login.j2', form=form)
  165. @app.route('/add', methods=['POST'])
  166. @login_required
  167. def add_game():
  168. if request.method == 'POST':
  169. game_title = request.form['game_title']
  170. game_link = request.form['game_link']
  171. conn = sqlite3.connect('config/games_in_progress.db')
  172. c = conn.cursor()
  173. if game_title is not None and len(game_title) > 0 and game_link is not None and len(game_link) > 0:
  174. c.execute("INSERT INTO games (user_id, game_title, game_link) VALUES (?, ?, ?)", (session['user_id'], game_title, game_link,))
  175. conn.commit()
  176. conn.close()
  177. return 'Success'
  178. conn.commit()
  179. conn.close()
  180. return 'Error'
  181. @app.route('/delete', methods=['POST'])
  182. @login_required
  183. def delete_game():
  184. if request.method == 'POST':
  185. game_id = request.form['game_id']
  186. conn = sqlite3.connect('config/games_in_progress.db')
  187. c = conn.cursor()
  188. if game_id is not None and len(game_id) > 0:
  189. c.execute("DELETE FROM games WHERE id=? AND user_id=?", (game_id, session['user_id'],))
  190. conn.commit()
  191. conn.close()
  192. return 'Success'
  193. conn.commit()
  194. conn.close()
  195. return 'Error'
  196. def generate_game_list():
  197. conn = sqlite3.connect('config/games_in_progress.db')
  198. c = conn.cursor()
  199. if 'user_id' in session:
  200. c.execute('SELECT * FROM games WHERE user_id=?', (session['user_id'], ))
  201. rows = c.fetchall()
  202. conn.close()
  203. return rows
  204. conn.close()
  205. return []
  206. @app.route('/logout')
  207. @login_required
  208. def logout():
  209. user = current_user
  210. user.authenticated = False
  211. db.session.add(user)
  212. db.session.commit()
  213. logout_user()
  214. return redirect(url_for('game'))
  215. if __name__ == '__main__':
  216. app.run(extra_files="config/config.yaml")