async def activate_page_autofill(_, lang, code): if lang == 'fr': register_template = env.get_template('activate/fr.html') page = register_template.render( VANILLA_PLAY_LINK=app.config.VANILLA_PLAY_LINK, site_key=app.config.GSITE_KEY, activation_key=code) return response.html(page) elif lang == 'es': register_template = env.get_template('activate/es.html') page = register_template.render( VANILLA_PLAY_LINK=app.config.VANILLA_PLAY_LINK, site_key=app.config.GSITE_KEY, activation_key=code) return response.html(page) elif lang == 'pt': register_template = env.get_template('activate/pt.html') page = register_template.render( VANILLA_PLAY_LINK=app.config.VANILLA_PLAY_LINK, site_key=app.config.GSITE_KEY, activation_key=code) return response.html(page) register_template = env.get_template('activate/en.html') page = register_template.render( VANILLA_PLAY_LINK=app.config.VANILLA_PLAY_LINK, site_key=app.config.GSITE_KEY, activation_key=code) return response.html(page)
async def activate_page(request, lang): if lang == 'fr': register_template = env.get_template('fr_vanilla_activation.html') page = register_template.render( play_subdomain=app.config.PLAY_SUBDOMAIN, site_key=app.config.GSITE_KEY) return response.html(page) elif lang == 'es': register_template = env.get_template('es_vanilla_activation.html') page = register_template.render( play_subdomain=app.config.PLAY_SUBDOMAIN, site_key=app.config.GSITE_KEY) return response.html(page) elif lang == 'pt': register_template = env.get_template('pt_vanilla_activation.html') page = register_template.render( play_subdomain=app.config.PLAY_SUBDOMAIN, site_key=app.config.GSITE_KEY) return response.html(page) else: register_template = env.get_template('en_vanilla_activation.html') page = register_template.render( play_subdomain=app.config.PLAY_SUBDOMAIN, site_key=app.config.GSITE_KEY) return response.html(page)
async def edit_player(request, penguin_id): data = await Penguin.query.where( func.lower(Penguin.username) == request.ctx.session.get('username') ).gino.first() player = await Penguin.query.where(Penguin.id == int(penguin_id) ).gino.first() if not player: template = env.get_template('manager/manage.html') penguins = await Penguin.query.order_by( Penguin.registration_date.desc()).gino.all() penguins = get_paginated_result(penguins) page = template.render( success_message=f'Could not find a player by the ID: {penguin_id}', error_message='', penguins=penguins, penguin=data) return response.html(page) latest_ban = await get_latest_ban(penguin_id) bans = await get_bans(penguin_id) login_history = await get_login_history(penguin_id) template = env.get_template('manager/edit-player.html') page = template.render(success_message='', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page)
async def password_reset_page(_, lang): template = env.get_template(f'password/request/{lang}.html') page = template.render( VANILLA_PLAY_LINK=app.config.VANILLA_PLAY_LINK, site_key=app.config.GSITE_KEY ) return response.html(page)
async def activate_page_autofill(_, lang, code): register_template = env.get_template(f'activate/{lang}.html') page = register_template.render( VANILLA_PLAY_LINK=app.config.VANILLA_PLAY_LINK, site_key=app.config.GSITE_KEY, activation_key=code) return response.html(page)
async def login_page(_): template = env.get_template('manager/login.html') page = template.render( success_message='', error_message='', site_key=app.config.GSITE_KEY ) return response.html(page)
def _edit_prompt(selector, message): prompt_template = env.get_template('html/prompt.html') return ({ 'command': 'insert', 'selector': selector, 'method': 'replaceWith', 'data': prompt_template.render(message=message) })
def _make_error_message(name, message): error_template = env.get_template('error.html') return ({ 'command': 'insert', 'selector': f'#{name}-error', 'method': 'html', 'data': error_template.render(message=message) })
async def choose_password_page(_, lang, reset_token): reset_key = await app.ctx.redis.get(f'{reset_token}.reset_key') if reset_key: template = env.get_template(f'password/choose/{lang}.html') page = template.render(VANILLA_PLAY_LINK=app.config.VANILLA_PLAY_LINK, token=reset_token, site_key=app.config.GSITE_KEY) return response.html(page) return response.json({'message': 'Reset key not found'}, status=404)
async def request_password_reset(request, lang): username = request.form.get('name', '').lower() email = request.form.get('email', '').lower() if app.config.GSECRET_KEY: gclient_response = request.form.get('recaptcha_response', '') async with aiohttp.ClientSession() as session: async with session.post(app.config.GCAPTCHA_URL, data=dict(secret=app.config.GSECRET_KEY, response=gclient_response, remoteip=request.ip)) as resp: gresult = await resp.json() if not gresult['success']: return response.text( 'Your captcha score was low, please try again.') if not username: return response.json([_add_class('name', 'error')], headers={'X-Drupal-Ajax-Token': 1}) elif not email or '@' not in email: return response.json([_add_class('email', 'error')], headers={'X-Drupal-Ajax-Token': 1}) data = await Penguin.query.where(Penguin.username == username).gino.first() if data and data.email == email: reset_key = secrets.token_urlsafe(45) mail_template = env.get_template(f'emails/password/{lang}.html') message = Mail( from_email=app.config.FROM_EMAIL, to_emails=email, subject=i18n.t('password.reset_password_subject', locale=lang), html_content=mail_template.render( username=username, site_name=app.config.SITE_NAME, reset_link= f'{app.config.VANILLA_PLAY_LINK}/{lang}/penguin/forgot-password/{reset_key}' )) sg = SendGridAPIClient(app.config.SENDGRID_API_KEY) sg.send(message) await app.ctx.redis.setex(f'{reset_key}.reset_key', app.config.AUTH_TTL, data.id) return response.json([ _remove_selector('#edit-name'), _remove_selector('#edit-email'), _remove_selector('#edit-submit'), _edit_title( '#forgotpassword h2', i18n.t('password.password_title', locale=lang), ), _edit_prompt( '#penguin-forgot-password-form span', i18n.t('password.password_prompt', locale=lang), ) ], headers={'X-Drupal-Ajax-Token': 1})
def _make_name_suggestion(names, message): name_suggestion_template = env.get_template('name_suggestion.html') return ({ 'command': 'insert', 'selector': '#name-error', 'method': 'html', 'data': name_suggestion_template.render(names=names, message=message) })
async def main_page(request): data = await Penguin.query.where(func.lower(Penguin.username) == request['session']['username']).gino.first() login_history = await Login.query.where(Login.penguin_id == data.id).order_by(Login.date.desc()).limit(5).gino.all() template = env.get_template('manager/panel.html') page = template.render( penguin=data, play_link=app.config.VANILLA_PLAY_LINK, login_history=login_history, success_message='', error_message='', site_key=app.config.GSITE_KEY ) return response.html(page)
async def manage_page(request): template = env.get_template('manager/manage.html') data = await Penguin.query.where( func.lower(Penguin.username) == request.ctx.session.get('username') ).gino.first() penguins = await Penguin.query.order_by(Penguin.registration_date.desc() ).gino.all() penguins = get_paginated_result(penguins) page = template.render(success_message='', error_message='', penguins=penguins, penguin=data) return response.html(page)
async def search_username(request): template = env.get_template('manager/verify.html') query_string = request.body.decode('UTF-8') post_data = parse_qs(query_string) username = post_data.get('username', [None])[0] language = post_data.get('language', [None])[0] data = await Penguin.query.where( func.lower(Penguin.username) == request['session']['username'] ).gino.first() if not language: return response.text('You must provide a valid language.') elif not username: return response.text('You must provide a valid username.') if language == 'en': unverified_penguins = await Penguin.query.where( (Penguin.approval_en == False) & (Penguin.rejection_en == False) & (Penguin.username.ilike(f"%{username}%"))).gino.all() elif language == 'de': unverified_penguins = await Penguin.query.where( (Penguin.approval_de == False) & (Penguin.rejection_de == False) & (Penguin.username.ilike(f"%{username}%"))).gino.all() elif language == 'es': unverified_penguins = await Penguin.query.where( (Penguin.approval_es == False) & (Penguin.rejection_es == False) & (Penguin.username.ilike(f"%{username}%"))).gino.all() elif language == 'fr': unverified_penguins = await Penguin.query.where( (Penguin.approval_fr == False) & (Penguin.rejection_fr == False) & (Penguin.username.ilike(f"%{username}%"))).gino.all() elif language == 'pt': unverified_penguins = await Penguin.query.where( (Penguin.approval_pt == False) & (Penguin.rejection_pt == False) & (Penguin.username.ilike(f"%{username}%"))).gino.all() elif language == 'ru': unverified_penguins = await Penguin.query.where( (Penguin.approval_ru == False) & (Penguin.rejection_ru == False) & (Penguin.username.ilike(f"%{username}%"))).gino.all() else: language = 'en' unverified_penguins = await Penguin.query.where( (Penguin.approval_en == False) & (Penguin.rejection_en == False) & (Penguin.username.ilike(f"%{username}%"))).gino.all() unverified_penguins = get_paginated_result(unverified_penguins) page = template.render( success_message=f"Searched usernames similar to {username}.", error_message='', unverified_penguins=unverified_penguins, penguin=data, language=language) return response.html(page)
async def ban_player(request): query_string = request.body.decode('UTF-8') post_data = parse_qs(query_string) player_id = post_data.get('player', [None])[0] hours = post_data.get('hours', [None])[0] comment = post_data.get('comment', [None])[0] player = await Penguin.query.where(Penguin.id == int(player_id) ).gino.first() moderator = await Penguin.query.where( func.lower(Penguin.username) == request['session']['username'] ).gino.first() if not player: return response.text('The player ID given does not exist.') number_bans = await db.select([db.func.count(Ban.penguin_id)] ).where(Ban.penguin_id == int(player.id) ).gino.scalar() date_issued = datetime.now() date_expires = date_issued + timedelta(hours=int(hours)) if number_bans >= 3: await Penguin.update.values(permaban=True ).where(Penguin.id == player.id ).gino.status() await Ban.create(penguin_id=player.id, issued=date_issued, expires=date_expires, moderator_id=moderator.id, reason=2, comment=comment, message='') data = await Penguin.query.where( func.lower(Penguin.username) == request['session']['username'] ).gino.first() latest_ban = await get_latest_ban(player_id) bans = await get_bans(player_id) login_history = await get_login_history(player_id) template = env.get_template('manager/edit-player.html') page = template.render(success_message='Sucessfully inserted ban entry.', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page)
async def create_page(request, lang): base64_captchas = [] captchas = random.sample(all_captchas, min(len(all_captchas), 3)) captcha_answer = random.choice(captchas)[0] captcha_object = [ captcha for captcha in captchas if captcha_answer in captcha ] if 'anon_token' not in request.ctx.session: anon_token = secrets.token_urlsafe(32) request.ctx.session['anon_token'] = anon_token request.ctx.session['captcha_answer'] = captchas.index(captcha_object[0]) request.ctx.session['captcha'] = {'passed': 0} request.ctx.session['errors'] = { 'name': True, 'pass': True, 'email': True, 'terms': True, 'captcha': True } request.ctx.session['captcha_answer'] = captchas.index(captcha_object[0]) for captcha_image in captchas: captcha_encoded = lsb.hide(captcha_image[1].copy(), request.ctx.session['anon_token']) buffered = BytesIO() captcha_encoded.save(buffered, format='PNG') captcha_base64 = base64.b64encode(buffered.getvalue()) base64_captchas.append(captcha_base64.decode('utf-8')) register_template = env.get_template(f'create/{lang}.html') page = register_template.render( VANILLA_PLAY_LINK=app.config.VANILLA_PLAY_LINK, anon_token=request.ctx.session['anon_token'], captcha_1=base64_captchas[0], captcha_2=base64_captchas[1], captcha_3=base64_captchas[2], captcha_answer=i18n.t(f'create.{captcha_answer}', locale=lang), site_key=app.config.GSITE_KEY) return response.html(page)
async def unban_player(request): query_string = request.body.decode('UTF-8') post_data = parse_qs(query_string) player_id = post_data.get('player', [None])[0] comment = post_data.get('comment', [None])[0] ban = await Ban.query.where((Ban.penguin_id == int(player_id)) & (Ban.comment == comment)).gino.first() data = await Penguin.query.where( func.lower(Penguin.username) == request['session']['username'] ).gino.first() player = await Penguin.query.where(Penguin.id == int(player_id) ).gino.first() latest_ban = await get_latest_ban(player_id) bans = await get_bans(player_id) login_history = await get_login_history(player_id) template = env.get_template('manager/edit-player.html') if not ban: page = template.render( success_message= 'This ban does not exist based on the comment chosen and penguin ID given.', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) else: await Ban.delete.where((Ban.penguin_id == int(player_id)) & (Ban.comment == comment)).gino.status() page = template.render(success_message='Successfully removed ban.', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page)
async def search_player(request): template = env.get_template('manager/manage.html') data = await Penguin.query.where( func.lower(Penguin.username) == request['session']['username'] ).gino.first() query_string = request.body.decode('UTF-8') post_data = parse_qs(query_string) search_query = post_data.get('search_query', [None])[0] search_type = post_data.get('search_type', [None])[0] if search_query is None: return response.text('You must provide a valid search query.') elif search_type is None: return response.text('You must provide a valid search type.') if search_type == 'id': if not search_query.isdigit(): return response.text('The ID given must be a number.') penguins = await Penguin.query.where( (Penguin.id == int(search_query)) ).order_by(Penguin.registration_date.desc()).gino.all() elif search_type == 'username': penguins = await Penguin.query.where( (Penguin.username.ilike(f"%{search_query}%")) ).order_by(Penguin.registration_date.desc()).gino.all() elif search_type == 'email': penguins = await Penguin.query.where( (Penguin.email.ilike(f"%{search_query}%")) ).order_by(Penguin.registration_date.desc()).gino.all() else: penguins = await Penguin.query.where( (Penguin.username.ilike(f"%{search_query}%")) ).order_by(Penguin.registration_date.desc()).gino.all() penguins = get_paginated_result(penguins) page = template.render( success_message= f'Searched players based on your search query: {search_query}.', error_message='', penguins=penguins, penguin=data) return response.html(page)
async def verify_page(request, lang): template = env.get_template('manager/verify.html') data = await Penguin.query.where( func.lower(Penguin.username) == request.ctx.session.get('username') ).gino.first() if lang == 'de': unverified_penguins = await Penguin.query.where( (Penguin.approval_de == False) & (Penguin.rejection_de == False)).gino.all() elif lang == 'es': unverified_penguins = await Penguin.query.where( (Penguin.approval_es == False) & (Penguin.rejection_es == False)).gino.all() elif lang == 'fr': unverified_penguins = await Penguin.query.where( (Penguin.approval_fr == False) & (Penguin.rejection_fr == False)).gino.all() elif lang == 'pt': unverified_penguins = await Penguin.query.where( (Penguin.approval_pt == False) & (Penguin.rejection_pt == False)).gino.all() elif lang == 'ru': unverified_penguins = await Penguin.query.where( (Penguin.approval_ru == False) & (Penguin.rejection_ru == False)).gino.all() else: lang = 'en' unverified_penguins = await Penguin.query.where( (Penguin.approval_en == False) & (Penguin.rejection_en == False)).gino.all() unverified_penguins = get_paginated_result(unverified_penguins) page = template.render(success_message='', error_message='', unverified_penguins=unverified_penguins, penguin=data, language=lang) return response.html(page)
async def _validate_registration(request, post_data, lang): username = post_data.get('name', [None])[0] password = post_data.get('pass', [None])[0] email = post_data.get('email', [None])[0] color = post_data.get('color', [None])[0] if 'username' not in request[ 'session'] or request['session']['username'] != username: return response.json({'message': '403 Forbidden'}, status=403) elif 'password' not in request[ 'session'] or request['session']['password'] != password: return response.json({'message': '403 Forbidden'}, status=403) elif 'email' not in request[ 'session'] or request['session']['email'] != email: return response.json({'message': '403 Forbidden'}, status=403) elif not color.isdigit() or int(color) not in range(1, 16): return response.json({'message': '403 Forbidden'}, status=403) if app.config.GSECRET_KEY: gclient_response = post_data.get('recaptcha_response', [None])[0] async with aiohttp.ClientSession() as session: async with session.post(app.config.GCAPTCHA_URL, data=dict(secret=app.config.GSECRET_KEY, response=gclient_response, remoteip=request.ip)) as resp: gresult = await resp.json() if not gresult['success']: return response.text(urlencode({'error': gresult})) password = Crypto.hash(password).upper() password = Crypto.get_login_hash(password, rndk=app.config.STATIC_KEY) password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(12)).decode('utf-8') if app.config.USERNAME_FORCE_CASE: username = username.title() penguin = await Penguin.create(username=username.lower(), nickname=username, password=password, email=email, color=int(color), approval_en=app.config.APPROVE_USERNAME, approval_pt=app.config.APPROVE_USERNAME, approval_fr=app.config.APPROVE_USERNAME, approval_es=app.config.APPROVE_USERNAME, approval_de=app.config.APPROVE_USERNAME, approval_ru=app.config.APPROVE_USERNAME, active=app.config.ACTIVATE_PLAYER) await PenguinItem.create(penguin_id=penguin.id, item_id=int(color)) await PenguinPostcard.create(penguin_id=penguin.id, sender_id=None, postcard_id=125) if not app.config.ACTIVATE_PLAYER: activation_key = secrets.token_urlsafe(45) if lang == 'es': mail_template = env.get_template('es_vanilla_email.html') elif lang == 'pt': mail_template = env.get_template('pt_vanilla_email.html') elif lang == 'fr': mail_template = env.get_template('fr_vanilla_email.html') else: mail_template = env.get_template('en_vanilla_email.html') message = Mail(from_email=app.config.FROM_EMAIL, to_emails=email, subject=i18n.t('create.activate_mail_subject'), html_content=mail_template.render( penguin=penguin, site_name=app.config.SITE_NAME, activation_code=activation_key, play_subdomain=app.config.PLAY_SUBDOMAIN, activate_link=app.config.ACTIVATE_LINK)) sg = SendGridAPIClient(app.config.SENDGRID_API_KEY) sg.send(message) await ActivationKey.create(penguin_id=penguin.id, activation_key=activation_key) return response.redirect(app.config.PLAY_SUBDOMAIN)
async def _validate_registration(request, lang): username = request.form.get('name', None) password = request.form.get('pass', None) email = request.form.get('email', None) color = request.form.get('color', None) if 'username' not in request.ctx.session or request.ctx.session[ 'username'] != username: return response.json({'message': '403 Forbidden'}, status=403) elif 'password' not in request.ctx.session or request.ctx.session[ 'password'] != password: return response.json({'message': '403 Forbidden'}, status=403) elif 'email' not in request.ctx.session or request.ctx.session[ 'email'] != email: return response.json({'message': '403 Forbidden'}, status=403) elif not color.isdigit() or int(color) not in range(1, 17): return response.json({'message': '403 Forbidden'}, status=403) elif app.config.GSECRET_KEY: gclient_response = request.form.get('recaptcha_response', None) async with aiohttp.ClientSession() as session: async with session.post(app.config.GCAPTCHA_URL, data=dict(secret=app.config.GSECRET_KEY, response=gclient_response, remoteip=request.ip)) as resp: gresult = await resp.json() if not gresult['success']: return response.text( 'Your captcha score was low, please try again.') password = Crypto.hash(password).upper() password = Crypto.get_login_hash(password, rndk=app.config.STATIC_KEY) password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(12)).decode('utf-8') username = username.strip() if app.config.USERNAME_FORCE_CASE: username = username.title() penguin = await Penguin.create(username=username.lower(), nickname=username, password=password, email=email, color=int(color), approval_en=app.config.APPROVE_USERNAME, approval_pt=app.config.APPROVE_USERNAME, approval_fr=app.config.APPROVE_USERNAME, approval_es=app.config.APPROVE_USERNAME, approval_de=app.config.APPROVE_USERNAME, approval_ru=app.config.APPROVE_USERNAME, active=app.config.ACTIVATE_PLAYER) await PenguinItem.create(penguin_id=penguin.id, item_id=int(color)) await PenguinPostcard.create(penguin_id=penguin.id, sender_id=None, postcard_id=125) if not app.config.ACTIVATE_PLAYER: activation_key = secrets.token_urlsafe(45) mail_template = env.get_template( f'emails/activation/vanilla/{lang}.html') message = Mail( from_email=app.config.FROM_EMAIL, to_emails=email, subject=i18n.t('activate.mail_subject', locale=lang), html_content=mail_template.render( penguin=penguin, site_name=app.config.SITE_NAME, activation_code=activation_key, VANILLA_PLAY_LINK=app.config.VANILLA_PLAY_LINK, activate_link= f'{app.config.VANILLA_PLAY_LINK}/{lang}/penguin/activate')) sg = SendGridAPIClient(app.config.SENDGRID_API_KEY) sg.send(message) await ActivationKey.create(penguin_id=penguin.id, activation_key=activation_key) return response.redirect(app.config.VANILLA_PLAY_LINK)
async def password_request(request): old_password = request.form.get('old_password', None) password = request.form.get('password', None) password_confirm = request.form.get('password_confirm', None) template = env.get_template('manager/password.html') if app.config.GSECRET_KEY: gclient_response = request.form.get('recaptcha_response', None) async with aiohttp.ClientSession() as session: async with session.post(app.config.GCAPTCHA_URL, data=dict(secret=app.config.GSECRET_KEY, response=gclient_response, remoteip=request.ip)) as resp: gresult = await resp.json() if not gresult['success']: page = template.render( success_message='', error_message= 'Your captcha score was low. Please try again.', site_key=app.config.GSITE_KEY) return response.html(page) if not old_password: page = template.render( success_message='', error_message='You must provide your old password.', site_key=app.config.GSITE_KEY) return response.html(page) elif not password or not password_confirm: page = template.render( success_message='', error_message='You must provide a new password.', site_key=app.config.GSITE_KEY) return response.html(page) elif len(password) < 5 or len(password) < 5: page = template.render( success_message='', error_message='Your new password must be more than 5 characters..', site_key=app.config.GSITE_KEY) return response.html(page) elif password != password_confirm: page = template.render(success_message='', error_message='Your new passwords must match.', site_key=app.config.GSITE_KEY) return response.html(page) data = await Penguin.query.where( func.lower(Penguin.username) == request.ctx.session.get('username') ).gino.first() loop = asyncio.get_event_loop() old_password = Crypto.hash(old_password).upper() old_password = Crypto.get_login_hash(old_password, rndk=app.config.STATIC_KEY) password_correct = await loop.run_in_executor( None, bcrypt.checkpw, old_password.encode('utf-8'), data.password.encode('utf-8')) if not password_correct: page = template.render(success_message='', error_message='Your old password is incorrect.', site_key=app.config.GSITE_KEY) return response.html(page) password = Crypto.hash(password).upper() password = Crypto.get_login_hash(password, rndk=app.config.STATIC_KEY) password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(12)).decode('utf-8') await Penguin.update.values(password=password).where(Penguin.id == data.id ).gino.status() data = await Penguin.query.where( func.lower(Penguin.username) == request.ctx.session.get('username') ).gino.first() login_history = await Login.query.where(Login.penguin_id == data.id ).order_by(Login.date.desc() ).limit(5).gino.all() template = env.get_template('manager/panel.html') page = template.render( penguin=data, play_link=app.config.VANILLA_PLAY_LINK, login_history=login_history, success_message='You have successfully updated your password.', error_message='', site_key=app.config.GSITE_KEY) return response.html(page)
async def update_player(request): player_id = request.form.get('player', None) type = request.form.get('type', None) template = env.get_template('manager/edit-player.html') data = await Penguin.query.where( func.lower(Penguin.username) == request.ctx.session.get('username') ).gino.first() player = await Penguin.query.where(Penguin.id == int(player_id) ).gino.first() if player is None: return response.redirect('/manager/manage') latest_ban = await get_latest_ban(player_id) bans = await get_bans(player_id) login_history = await get_login_history(player_id) if type is None: page = template.render( success_message='', error_message='You must provide a valid column to update.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) if type == 'id': id = request.form.get('id', None) if not id: page = template.render(success_message='', error_message='You must provide an ID.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) if not id.isdigit(): page = template.render(success_message='', error_message='Value must be an integer.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) id_exists = await Penguin.query.where(Penguin.id == int(id) ).gino.first() if id_exists: page = template.render( success_message='', error_message= 'This penguin ID is already taken, please try another one.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) await Penguin.update.values(id=int(id)).where(Penguin.id == player.id ).gino.status() player = await Penguin.query.where(Penguin.id == int(id)).gino.first() page = template.render(success_message='Successfully updated ID.', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) elif type == 'username': username = request.form.get('username', None) if not username: page = template.render( success_message='', error_message='You must provide a username.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) if len(username) < 4 or len(username) > 12: page = template.render( success_message='', error_message= 'The username length must be between 4-12 characters.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) username_exists = await Penguin.query.where( Penguin.username == username).gino.first() if username_exists: page = template.render( success_message='', error_message= 'This username is already taken, please try another one.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) await Penguin.update.values(username=username ).where(Penguin.id == player.id ).gino.status() player = await Penguin.query.where(Penguin.id == player.id ).gino.first() page = template.render( success_message='Successfully updated username.', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) elif type == 'nickname': nickname = request.form.get('nickname', None) if not nickname: page = template.render( success_message='', error_message='You must provide a nickname.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) if len(nickname) < 1 or len(nickname) > 30: page = template.render( success_message='', error_message= 'The nickname length must be at least 1 or more characters and below 30 characters.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) await Penguin.update.values(nickname=nickname ).where(Penguin.id == player.id ).gino.status() player = await Penguin.query.where(Penguin.id == player.id ).gino.first() page = template.render( success_message='Successfully updated nickname.', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) elif type == 'password': password = request.form.get('password', None) if not password: page = template.render( success_message='', error_message='You must provide a new password.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) password = Crypto.hash(password).upper() password = Crypto.get_login_hash(password, rndk=app.config.STATIC_KEY) password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(12)).decode('utf-8') await Penguin.update.values(password=password ).where(Penguin.id == player.id ).gino.status() page = template.render( success_message='Successfully updated password.', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) elif type == 'email': email = request.form.get('email', None) if not email: page = template.render(success_message='', error_message='You must provide an email.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) _, email = parseaddr(email) if not email or '@' not in email: page = template.render( success_message='', error_message='You must enter a valid email.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) email_count = await db.select([ db.func.count(Penguin.email) ]).where(db.func.lower(Penguin.email) == email.lower()).gino.scalar() if email_count >= app.config.MAX_ACCOUNT_EMAIL: page = template.render( success_message='', error_message= f'There are more than ${app.config.MAX_ACCOUNT_EMAIL} ' f'emails under this address. Please try another email address.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) await Penguin.update.values(email=email).where(Penguin.id == player.id ).gino.status() player = await Penguin.query.where(Penguin.id == player.id ).gino.first() page = template.render(success_message='Successfully updated email.', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) elif type == 'coins': coins = request.form.get('coins', None) if not coins: page = template.render( success_message='', error_message='You must provide an amount of coins.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) if not coins.isdigit(): page = template.render(success_message='', error_message='Value must be an integer.', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) await Penguin.update.values(coins=int(coins) ).where(Penguin.id == player.id ).gino.status() player = await Penguin.query.where(Penguin.id == player.id ).gino.first() page = template.render(success_message='Updated amount of coins.', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) elif type == 'moderator': if player.moderator: await Penguin.update.values(moderator=False ).where(Penguin.id == player.id ).gino.status() else: await Penguin.update.values(moderator=True ).where(Penguin.id == player.id ).gino.status() player = await Penguin.query.where(Penguin.id == player.id ).gino.first() page = template.render(success_message='Updated moderator status.', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) elif type == 'permaban': await Penguin.update.values(permaban=True ).where(Penguin.id == player.id ).gino.status() player = await Penguin.query.where(Penguin.id == player.id ).gino.first() page = template.render(success_message='Successfully banned user..', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) elif type == 'unban': await Penguin.update.values(permaban=False ).where(Penguin.id == player.id ).gino.status() player = await Penguin.query.where(Penguin.id == player.id ).gino.first() page = template.render(success_message='Successfully unbanned user.', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page) else: page = template.render( success_message='You must provide a valid column to update.', error_message='', play_link=app.config.VANILLA_PLAY_LINK, player=player, penguin=data, latest_ban=latest_ban, bans=bans, connection_history=login_history) return response.html(page)
async def email_request(request): email = request.form.get('email', None) email_confirm = request.form.get('email_confirm', None) template = env.get_template('manager/email.html') if app.config.GSECRET_KEY: gclient_response = request.form.get('recaptcha_response', None) async with aiohttp.ClientSession() as session: async with session.post(app.config.GCAPTCHA_URL, data=dict(secret=app.config.GSECRET_KEY, response=gclient_response, remoteip=request.ip)) as resp: gresult = await resp.json() if not gresult['success']: page = template.render( success_message='', error_message= 'Your captcha score was low. Please try again.', site_key=app.config.GSITE_KEY) return response.html(page) elif not email or not email_confirm: page = template.render(success_message='', error_message='You must provide your email.', site_key=app.config.GSITE_KEY) return response.html(page) _, email = parseaddr(email) domain = email.rsplit('@', 1)[-1] if not email or '@' not in email: page = template.render(success_message='', error_message='You must enter a valid email.', site_key=app.config.GSITE_KEY) return response.html(page) elif app.config.EMAIL_WHITELIST and domain not in app.config.EMAIL_WHITELIST: page = template.render( success_message='', error_message= 'You must enter an email provider that is whitelisted from out system.', site_key=app.config.GSITE_KEY) return response.html(page) email_count = await db.select([ db.func.count(Penguin.email) ]).where(db.func.lower(Penguin.email) == email.lower()).gino.scalar() if email_count >= app.config.MAX_ACCOUNT_EMAIL: page = template.render( success_message='', error_message=f'There are more than ${app.config.MAX_ACCOUNT_EMAIL} ' f'emails under this address. Please try another email address.', site_key=app.config.GSITE_KEY) return response.html(page) await Penguin.update.values(email=email).where( Penguin.username == request['session']['username']).gino.status() data = await Penguin.query.where( func.lower(Penguin.username) == request['session']['username'] ).gino.first() login_history = await Login.query.where(Login.penguin_id == data.id ).order_by(Login.date.desc() ).limit(5).gino.all() template = env.get_template('manager/panel.html') page = template.render( penguin=data, play_link=app.config.VANILLA_PLAY_LINK, login_history=login_history, success_message='You have successfully updated your email.', error_message='', site_key=app.config.GSITE_KEY) return response.html(page)
async def login_request(request): username = request.form.get('username', None) username = username.lower() password = request.form.get('password', None) loop = asyncio.get_event_loop() template = env.get_template('manager/login.html') if app.config.GSECRET_KEY: gclient_response = request.form.get('recaptcha_response', None) async with aiohttp.ClientSession() as session: async with session.post(app.config.GCAPTCHA_URL, data=dict( secret=app.config.GSECRET_KEY, response=gclient_response, remoteip=request.ip )) as resp: gresult = await resp.json() if not gresult['success']: page = template.render( success_message='', error_message='Your captcha score was low. Please try again.', site_key=app.config.GSITE_KEY ) return response.html(page) if not username: page = template.render( success_message='', error_message='You must provide a username.', site_key=app.config.GSITE_KEY ) return response.html(page) elif not password: page = template.render( success_message='', error_message='You must provide a password.', site_key=app.config.GSITE_KEY ) return response.html(page) data = await Penguin.query.where(func.lower(Penguin.username) == username).gino.first() if data is None: page = template.render( success_message='', error_message='Your penguin was not found.', site_key=app.config.GSITE_KEY ) return response.html(page) password = Crypto.hash(password).upper() password = Crypto.get_login_hash(password, rndk=app.config.STATIC_KEY) password_correct = await loop.run_in_executor(None, bcrypt.checkpw, password.encode('utf-8'), data.password.encode('utf-8')) flood_key = f'{request.ip}.flood' if not password_correct: if await app.ctx.redis.exists(flood_key): async with app.ctx.redis.pipeline(transaction=True) as tr: tr.incr(flood_key) tr.expire(flood_key, app.config.LOGIN_FAILURE_TIMER) failure_count, _ = await tr.execute() if failure_count >= app.config.LOGIN_FAILURE_LIMIT: page = template.render( success_message='', error_message='Maximum login attempts exceeded. Please try again in an hour.', site_key=app.config.GSITE_KEY ) return response.html(page) else: await app.ctx.redis.setex(flood_key, app.config.LOGIN_FAILURE_TIMER, 1) page = template.render( success_message='', error_message='You have entered an incorrect password.', site_key=app.config.GSITE_KEY ) return response.html(page) failure_count = await app.ctx.redis.get(flood_key) if failure_count: max_attempts_exceeded = int(failure_count) >= app.config.LOGIN_FAILURE_LIMIT if max_attempts_exceeded: page = template.render( success_message='', error_message='Maximum login attempts exceeded. Please try again in an hour.', site_key=app.config.GSITE_KEY ) return response.html(page) else: await app.ctx.redis.delete(flood_key) if not data.active: page = template.render( success_message='', error_message='Your account has not been activated.', site_key=app.config.GSITE_KEY ) return response.html(page) if data.permaban: page = template.render( success_message='', error_message='You are banned forever.', site_key=app.config.GSITE_KEY ) return response.html(page) if not data.moderator: page = template.render( success_message='', error_message='You do not have permission to access this panel.', site_key=app.config.GSITE_KEY ) return response.html(page) active_ban = await Ban.query.where((Ban.penguin_id == data.id) & (Ban.expires >= datetime.now())).gino.first() if active_ban is not None: hours_left = round((active_ban.expires - datetime.now()).total_seconds() / 60 / 60) page = template.render( success_message='', error_message=f'You are banned for the next {hours_left} hours.', site_key=app.config.GSITE_KEY ) return response.html(page) request.ctx.session['username'] = username request.ctx.session['logged_in'] = True return response.redirect('/manager')
async def reject_request(request, penguin_id): template = env.get_template('manager/verify.html') language = request.form.get('language', None) data = await Penguin.query.where( func.lower(Penguin.username) == request.ctx.session.get('username') ).gino.first() penguin = await Penguin.query.where(Penguin.id == int(penguin_id) ).gino.first() if not language: return response.text('You must provide a valid language.') if not penguin: return response.text('You must provide a valid penguin ID.') if language == 'en': await Penguin.update.values(rejection_en=True ).where(Penguin.id == penguin.id ).gino.status() unverified_penguins = await Penguin.query.where( (Penguin.approval_en == False) & (Penguin.rejection_en == False)).gino.all() elif language == 'de': await Penguin.update.values(rejection_de=True ).where(Penguin.id == penguin.id ).gino.status() unverified_penguins = await Penguin.query.where( (Penguin.approval_de == False) & (Penguin.rejection_de == False)).gino.all() elif language == 'es': await Penguin.update.values(rejection_es=True ).where(Penguin.id == penguin.id ).gino.status() unverified_penguins = await Penguin.query.where( (Penguin.approval_es == False) & (Penguin.rejection_es == False)).gino.all() elif language == 'fr': await Penguin.update.values(rejection_fr=True ).where(Penguin.id == penguin.id ).gino.status() unverified_penguins = await Penguin.query.where( (Penguin.approval_fr == False) & (Penguin.rejection_fr == False)).gino.all() elif language == 'pt': await Penguin.update.values(rejection_pt=True ).where(Penguin.id == penguin.id ).gino.status() unverified_penguins = await Penguin.query.where( (Penguin.approval_pt == False) & (Penguin.rejection_pt == False)).gino.all() elif language == 'ru': await Penguin.update.values(rejection_ru=True ).where(Penguin.id == penguin.id ).gino.status() unverified_penguins = await Penguin.query.where( (Penguin.approval_ru == False) & (Penguin.rejection_ru == False)).gino.all() else: language = 'en' unverified_penguins = await Penguin.query.where( (Penguin.approval_en == False) & (Penguin.rejection_en == False)).gino.all() unverified_penguins = get_paginated_result(unverified_penguins) page = template.render( success_message=f"Successfully rejected {penguin.username}'s username.", error_message='', unverified_penguins=unverified_penguins, penguin=data, language=language) return response.html(page)
async def validate_password_email(request): session_id = request.form.get('sid') username = request.ctx.session.get('username', None) color = request.ctx.session.get('color', '0') password = request.form.get('password', '') password_confirm = request.form.get('password_confirm', '') email = request.form.get('email', '') lang = request.form.get('lang', 'en') if session_id != request.ctx.session.get('sid'): return response.text( urlencode({'error': i18n.t('create.passwords_match', locale=lang)})) if app.config.GSECRET_KEY: gclient_response = request.form.get('gtoken', '') async with aiohttp.ClientSession() as session: async with session.post(app.config.GCAPTCHA_URL, data=dict(secret=app.config.GSECRET_KEY, response=gclient_response, remoteip=request.ip)) as resp: gresult = await resp.json() if not gresult['success']: return response.text(urlencode({'error': gresult})) if username is None or color is None: return response.text(urlencode({'error': ''})) elif str(password) != str(password_confirm): return response.text( urlencode({'error': i18n.t('create.passwords_match', locale=lang)})) elif len(password) < 4: return response.text( urlencode({'error': i18n.t('create.password_short', locale=lang)})) _, email = parseaddr(email) domain = email.rsplit('@', 1)[-1] if not email or '@' not in email: return response.text( urlencode({'error': i18n.t('create.email_invalid', locale=lang)})) elif app.config.EMAIL_WHITELIST and domain not in app.config.EMAIL_WHITELIST: return response.text( urlencode({'error': i18n.t('create.email_invalid', locale=lang)})) email_count = await db.select([ db.func.count(Penguin.email) ]).where(db.func.lower(Penguin.email) == email.lower()).gino.scalar() if email_count >= app.config.MAX_ACCOUNT_EMAIL: return response.text( urlencode({'error': i18n.t('create.email_invalid', locale=lang)})) password = Crypto.hash(password).upper() password = Crypto.get_login_hash(password, rndk=app.config.STATIC_KEY) password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(12)).decode('utf-8') username = username.strip() if app.config.USERNAME_FORCE_CASE: username = username.title() penguin = await Penguin.create(username=username.lower(), nickname=username, password=password, email=email, color=int(color), approval_en=app.config.APPROVE_USERNAME, approval_pt=app.config.APPROVE_USERNAME, approval_fr=app.config.APPROVE_USERNAME, approval_es=app.config.APPROVE_USERNAME, approval_de=app.config.APPROVE_USERNAME, approval_ru=app.config.APPROVE_USERNAME, active=app.config.ACTIVATE_PLAYER) await PenguinItem.create(penguin_id=penguin.id, item_id=int(color)) await PenguinPostcard.create(penguin_id=penguin.id, sender_id=None, postcard_id=125) if not app.config.ACTIVATE_PLAYER: activation_key = secrets.token_urlsafe(45) mail_template = env.get_template( f'emails/activation/legacy/{lang}.html') message = Mail( from_email=app.config.FROM_EMAIL, to_emails=email, subject=i18n.t('activate.mail_subject', locale=lang), html_content=mail_template.render( penguin=penguin, site_name=app.config.SITE_NAME, activate_link= f'{app.config.LEGACY_PLAY_LINK}/penguin/activate/{activation_key}' )) sg = SendGridAPIClient(app.config.SENDGRID_API_KEY) sg.send(message) await ActivationKey.create(penguin_id=penguin.id, activation_key=activation_key) return response.text(urlencode({'success': 1}))
async def approve_request(request, penguin_id): template = env.get_template('manager/verify.html') query_string = request.body.decode('UTF-8') post_data = parse_qs(query_string) language = post_data.get('language', [None])[0] data = await Penguin.query.where( func.lower(Penguin.username) == request['session']['username'] ).gino.first() penguin = await Penguin.query.where(Penguin.id == int(penguin_id) ).gino.first() if not language: return response.text('You must provide a valid language.') if not penguin: return response.text('You must provide a valid penguin ID.') if language == 'en': await Penguin.update.values(approval_en=True ).where(Penguin.id == penguin.id ).gino.status() unverified_penguins = await Penguin.query.where( (Penguin.approval_en == False) & (Penguin.rejection_en == False)).gino.all() elif language == 'de': await Penguin.update.values(approval_de=True ).where(Penguin.id == penguin.id ).gino.status() unverified_penguins = await Penguin.query.where( (Penguin.approval_de == False) & (Penguin.rejection_de == False)).gino.all() elif language == 'es': await Penguin.update.values(approval_es=True ).where(Penguin.id == penguin.id ).gino.status() unverified_penguins = await Penguin.query.where( (Penguin.approval_es == False) & (Penguin.rejection_es == False)).gino.all() elif language == 'fr': await Penguin.update.values(approval_fr=True ).where(Penguin.id == penguin.id ).gino.status() unverified_penguins = await Penguin.query.where( (Penguin.approval_fr == False) & (Penguin.rejection_fr == False)).gino.all() elif language == 'pt': await Penguin.update.values(approval_pt=True ).where(Penguin.id == penguin.id ).gino.status() unverified_penguins = await Penguin.query.where( (Penguin.approval_pt == False) & (Penguin.rejection_pt == False)).gino.all() elif language == 'ru': await Penguin.update.values(approval_ru=True ).where(Penguin.id == penguin.id ).gino.status() unverified_penguins = await Penguin.query.where( (Penguin.approval_ru == False) & (Penguin.rejection_ru == False)).gino.all() else: language = 'en' unverified_penguins = await Penguin.query.where( (Penguin.approval_en == False) & (Penguin.rejection_en == False)).gino.all() unverified_penguins = get_paginated_result(unverified_penguins) page = template.render( success_message=f"Successfully approved {penguin.username}'s username.", error_message='', unverified_penguins=unverified_penguins, penguin=data, language=language) return response.html(page)