From 98e9820161c95124619774472f7fdd8a466c88d5 Mon Sep 17 00:00:00 2001 From: Antonio de la Rosa Date: Tue, 21 Jun 2016 04:59:30 +0200 Subject: [PATCH] Added support for protect and recovery accounts --- paramecio/citoplasma/sendmail.py | 8 +- paramecio/cromosoma/extrafields/langfield.py | 3 +- paramecio/cromosoma/formsutils.py | 4 +- paramecio/cromosoma/usermodel.py | 1 + paramecio/cromosoma/webmodel.py | 8 +- paramecio/modules/admin/index.py | 226 ++++++++++++++---- paramecio/modules/admin/models/admin.py | 4 + .../admin/templates/admin/check_token.phtml | 75 ++++++ .../modules/admin/templates/admin/login.phtml | 8 +- .../admin/templates/admin/recovery.phtml | 66 +++++ .../admin/templates/admin/recovery_mail.phtml | 10 + .../templates/admin/recovery_password.phtml | 10 + 12 files changed, 366 insertions(+), 57 deletions(-) create mode 100644 paramecio/modules/admin/templates/admin/check_token.phtml create mode 100644 paramecio/modules/admin/templates/admin/recovery.phtml create mode 100644 paramecio/modules/admin/templates/admin/recovery_mail.phtml create mode 100644 paramecio/modules/admin/templates/admin/recovery_password.phtml diff --git a/paramecio/citoplasma/sendmail.py b/paramecio/citoplasma/sendmail.py index 8207f79..4df7150 100644 --- a/paramecio/citoplasma/sendmail.py +++ b/paramecio/citoplasma/sendmail.py @@ -21,12 +21,11 @@ class SendMail: password='' ssl=True - - txt_error='' def __init__(self): self.smtp=smtplib.SMTP(host=self.host, port=self.port) + self.txt_error='' def send(self, from_address, to_address, subject, message, content_type='plain', attachments=[]): @@ -167,4 +166,7 @@ class SendMail: def quit(self): self.smtp.quit() - \ No newline at end of file + + def __del__(self): + + self.quit() diff --git a/paramecio/cromosoma/extrafields/langfield.py b/paramecio/cromosoma/extrafields/langfield.py index f79c484..c67469c 100644 --- a/paramecio/cromosoma/extrafields/langfield.py +++ b/paramecio/cromosoma/extrafields/langfield.py @@ -15,7 +15,8 @@ class LangField(CharField): for lang in I18n.dict_i18n: select_lang[lang]=lang - self.change_form(coreforms.SelectForm, [select_lang, I18n.default_lang]) + self.change_form(coreforms.SelectForm, [select_lang]) + self.default_value=I18n.default_lang def check(self, value): diff --git a/paramecio/cromosoma/formsutils.py b/paramecio/cromosoma/formsutils.py index e3e07f1..71683d9 100644 --- a/paramecio/cromosoma/formsutils.py +++ b/paramecio/cromosoma/formsutils.py @@ -59,7 +59,7 @@ class CheckForm(): return post, arr_form -def show_form(post, arr_form, t, yes_error=True, modelform_tpl='forms/modelform.phtml'): +def show_form(post, arr_form, t, yes_error=True, pass_values=True, modelform_tpl='forms/modelform.phtml'): # Create csrf_token in session @@ -67,7 +67,7 @@ def show_form(post, arr_form, t, yes_error=True, modelform_tpl='forms/modelform. s['csrf_token']=create_key_encrypt() - if yes_error==True: + if pass_values==True: pass_values_to_form(post, arr_form, yes_error) return t.load_template(modelform_tpl, forms=arr_form) diff --git a/paramecio/cromosoma/usermodel.py b/paramecio/cromosoma/usermodel.py index e8de9b4..550b638 100644 --- a/paramecio/cromosoma/usermodel.py +++ b/paramecio/cromosoma/usermodel.py @@ -144,6 +144,7 @@ class UserModel(WebModel): self.conditions=original_conditions if error>0: + self.sql_error+='Error:if is not expected, please, check that you disabled the special checkings of this model' return False return fields, values, update_values diff --git a/paramecio/cromosoma/webmodel.py b/paramecio/cromosoma/webmodel.py index 1fe50ad..22bade3 100644 --- a/paramecio/cromosoma/webmodel.py +++ b/paramecio/cromosoma/webmodel.py @@ -7,6 +7,7 @@ from importlib import import_module, reload from collections import OrderedDict from paramecio.cromosoma.databases.mysqldb import SqlClass from paramecio.cromosoma.coreforms import BaseForm, HiddenForm +import traceback # The most important class for the framework # @@ -249,6 +250,9 @@ class WebModel: fields, values, update_values=self.check_all_fields(dict_values, external_agent, True, 'update') except: + + #self.query_error+="\n"+traceback.format_exc() + return False sql="update `"+self.name+"` SET "+", ".join(update_values)+" "+self.conditions[0] @@ -732,7 +736,7 @@ class WebModel: value=dict_values[k] - # Need rewrite the error because shitty python don't clean nothing + # Cleaning the error self.fields[k].error=False @@ -769,7 +773,7 @@ class WebModel: update_values.append(f_update(k, value)) else: self.num_errors+=1 - + self.fields_errors[k].append("Error: "+self.fields[k].label+" is not in valid fields") self.fields[k].error=True self.fields[k].txt_error="Error: "+self.fields[k].label+" is not in valid fields" diff --git a/paramecio/modules/admin/index.py b/paramecio/modules/admin/index.py index 0957ac7..1c9d9dc 100644 --- a/paramecio/modules/admin/index.py +++ b/paramecio/modules/admin/index.py @@ -20,13 +20,23 @@ from importlib import import_module, reload from bottle import redirect from collections import OrderedDict from time import time -from paramecio.citoplasma.keyutils import create_key_encrypt +from paramecio.citoplasma.keyutils import create_key_encrypt, create_key_encrypt_256, create_key +from paramecio.citoplasma.sendmail import SendMail from os import path import copy #from citoplasma.login import LoginClass # Check login +yes_recovery_login=False +email_address='localhost' + +if hasattr(config, 'yes_recovery_login'): + yes_recovery_login=config.yes_recovery_login + +if hasattr(config, 'email_address'): + email_address=config.email_address + load_lang(['paramecio', 'admin'], ['paramecio', 'common']) key_encrypt=config.key_encrypt #create_key_encrypt() @@ -175,7 +185,7 @@ def home(module='', submodule=''): #connection.close() - return t.load_template('admin/login.phtml', forms=forms) + return t.load_template('admin/login.phtml', forms=forms, yes_recovery_login=yes_recovery_login) else: @@ -207,53 +217,70 @@ def login(): user_admin.conditions=['WHERE username=%s', [username]] - arr_user=user_admin.select_a_row_where(['id', 'password', 'privileges', 'lang']) + arr_user=user_admin.select_a_row_where(['id', 'password', 'privileges', 'lang', 'num_tries']) if arr_user==False: return {'error': 1} else: - if user_admin.fields['password'].verify(password, arr_user['password']): - - generate_session() - - s=get_session() - - s['id']=arr_user['id'] - s['login']=1 - s['privileges']=arr_user['privileges'] - s['lang']=arr_user['lang'] - - if s['lang']=='': - s['lang']=I18n.default_lang - - remember_login=getpostfiles.post.get('remember_login', '0') - - if remember_login=='1': + num_tries=int(arr_user['num_tries']) + + if arr_user['num_tries']<3: + + if user_admin.fields['password'].verify(password, arr_user['password']): - timestamp=time()+315360000 + generate_session() - random_text=create_key_encrypt() + s=get_session() - #Update user with autologin token + s['id']=arr_user['id'] + s['login']=1 + s['privileges']=arr_user['privileges'] + s['lang']=arr_user['lang'] + + if s['lang']=='': + s['lang']=I18n.default_lang + + remember_login=getpostfiles.post.get('remember_login', '0') + + if remember_login=='1': + + timestamp=time()+315360000 + + random_text=create_key_encrypt() + + #Update user with autologin token + + user_admin.check_user=False + + user_admin.conditions=['WHERE username=%s', [username]] + + user_admin.valid_fields=['token_login'] + + user_admin.reset_require() + + if user_admin.update({'token_login': random_text}): + + response.set_cookie('remember_login', random_text, path="/", expires=timestamp, secret=key_encrypt) + #else: + #print(user_admin.query_error) + #s.save() + + return {'error': 0} + else: user_admin.check_user=False - + user_admin.conditions=['WHERE username=%s', [username]] - user_admin.valid_fields=['token_login'] + user_admin.valid_fields=['num_tries'] user_admin.reset_require() - if user_admin.update({'token_login': random_text}): - - response.set_cookie('remember_login', random_text, path="/", expires=timestamp, secret=key_encrypt) - #else: - #print(user_admin.query_error) - #s.save() - - return {'error': 0} + user_admin.update({'num_tries': arr_user['num_tries']+1}) + + return {'error': 1} else: return {'error': 1} @@ -330,24 +357,127 @@ def logout(): redirect('/'+config.admin_folder) -""" -def set_extra_forms_user(user_admin): +@get('/'+config.admin_folder+'/recovery_password') +def recovery_password(): - user_admin.fields['password'].required=True - user_admin.fields['email'].required=True + t=PTemplate(env) + + connection=WebModel.connection() + + user_admin=UserAdmin(connection) + + post={} + + user_admin.create_forms(['email']) + + forms=show_form(post, user_admin.forms, t, yes_error=False) + + #connection.close() + + return t.load_template('admin/recovery.phtml', forms=forms) - user_admin.create_forms(['username', 'email', 'password']) +@post('/'+config.admin_folder+'/recovery_password') +def send_password(): - user_admin.forms['repeat_password']=PasswordForm('repeat_password', '') + connection=WebModel.connection() - user_admin.forms['repeat_password'].required=1 + user_admin=UserAdmin(connection) - user_admin.forms['repeat_password'].label=I18n.lang('common', 'repeat_password', 'Repeat Password') -""" + t=PTemplate(env) + + getpost=GetPostFiles() + + getpost.obtain_post() + + email=getpost.post.get('email', '') + + email=user_admin.fields['email'].check(email) + + if user_admin.fields['email'].error: + + return {'email': user_admin.fields['email'].txt_error, 'error': 1} + + else: + + user_admin.set_conditions('WHERE email=%s', [email]) + + user_admin.yes_reset_conditions=False + + if user_admin.select_count()==1: + + user_admin.reset_require() + + user_admin.valid_fields=['token_recovery'] + + user_admin.check_user=False + + token=create_key_encrypt_256() + + if user_admin.update({'token_recovery': token}): + + send_mail=SendMail() + + content_mail=t.load_template('admin/recovery_mail.phtml', token=token) + + if not send_mail.send(email_address, [email], I18n.lang('admin', 'send_email', 'Email for recovery your password'), content_mail): + return {'email': 'Error: i cannot send mail', 'error': 1} + + + return {'email': '', 'error': 0} + + +@get('/'+config.admin_folder+'/check_token') +def check_token(): + t=PTemplate(env) + + return t.load_template('admin/check_token.phtml') + +@post('/'+config.admin_folder+'/check_token') +def check_code_token(): + + t=PTemplate(env) + + if yes_recovery_login==True: + + getpost=GetPostFiles() + + getpost.obtain_post() + + connection=WebModel.connection() + + user_admin=UserAdmin(connection) + + token=getpost.post.get('token', '') + + token=user_admin.fields['token_recovery'].check(token) + + if token.strip()!='': + + user_admin.set_conditions('WHERE token_recovery=%s', [token]) + + user_admin.yes_reset_conditions=False + + arr_user=user_admin.select_a_row_where(['id', 'email']) + + if arr_user: + + new_password=create_key() + + user_admin.valid_fields=['password', 'token_recovery', 'num_tries'] - -"""user_admin.create_forms() - - users=user_admin.select()""" - -#By default id is not showed + user_admin.reset_require() + + user_admin.check_user=False + + if user_admin.update({'password': new_password, 'token_recovery': "", 'num_tries': 0}, False): + + send_mail=SendMail() + + content_mail=t.load_template('admin/recovery_password.phtml', password=new_password) + + if not send_mail.send(email_address, [arr_user['email']], I18n.lang('admin', 'send_password_email', 'Your new password'), content_mail): + return {'token': 'Error: i cannot send mail', 'error': 1} + + return {'token': 'Error: cannot send the maild with the new password', 'error': 0} + + return {'token': 'Error: token is not valid', 'error': 1} diff --git a/paramecio/modules/admin/models/admin.py b/paramecio/modules/admin/models/admin.py index 9ce70bb..a1c799d 100644 --- a/paramecio/modules/admin/models/admin.py +++ b/paramecio/modules/admin/models/admin.py @@ -49,6 +49,10 @@ class UserAdmin(UserModel): self.register(PrivilegesField('privileges')) self.register(LangField('lang', 20)) + + self.register(corefields.BooleanField('disabled')) + + self.register(corefields.IntegerField('num_tries', 1)) """ diff --git a/paramecio/modules/admin/templates/admin/check_token.phtml b/paramecio/modules/admin/templates/admin/check_token.phtml new file mode 100644 index 0000000..6d20f01 --- /dev/null +++ b/paramecio/modules/admin/templates/admin/check_token.phtml @@ -0,0 +1,75 @@ +<%inherit file="login.phtml"/> +<%block name="ajax"> + + +<%block name="title">${lang('common', 'recovery_password', 'Recovery password')} +<%block name="content"> +
+
+ ${lang('common', 'recovery_password', 'Recovery password')} +
+
+ + + +
+
+
+ +   +
+
+ diff --git a/paramecio/modules/admin/templates/admin/login.phtml b/paramecio/modules/admin/templates/admin/login.phtml index a20de4b..1ef57e9 100644 --- a/paramecio/modules/admin/templates/admin/login.phtml +++ b/paramecio/modules/admin/templates/admin/login.phtml @@ -64,11 +64,17 @@ ${lang('admin', 'login', 'Paramecio Login')} ${forms|n} -
${lang('admin', 'remember_login', 'Remember login?')}
+
+ ${lang('admin', 'remember_login', 'Remember login?')} +
 
+ % if yes_recovery_login: +
${lang('admin', 'recovery_password', 'Recovery password?')}
+ % endif +
${lang('admin', 'remember_tries', 'Remember that only have 3 attempts')}
diff --git a/paramecio/modules/admin/templates/admin/recovery.phtml b/paramecio/modules/admin/templates/admin/recovery.phtml new file mode 100644 index 0000000..1d6027d --- /dev/null +++ b/paramecio/modules/admin/templates/admin/recovery.phtml @@ -0,0 +1,66 @@ +<%inherit file="login.phtml"/> +<%block name="ajax"> + + +<%block name="title">${lang('common', 'recovery_password', 'Recovery password')} +<%block name="content"> +
+
+ ${lang('common', 'recovery_password', 'Recovery password')} +
+ ${forms|n} +
+
+ +   +
+
+ diff --git a/paramecio/modules/admin/templates/admin/recovery_mail.phtml b/paramecio/modules/admin/templates/admin/recovery_mail.phtml new file mode 100644 index 0000000..f9ef896 --- /dev/null +++ b/paramecio/modules/admin/templates/admin/recovery_mail.phtml @@ -0,0 +1,10 @@ +Hi User + +You send a request for get a new password + +Please, copy and paste the next code in your browser for complete the request: + +${token} + +If you don't send any request for get a new password, ignore this mail. + diff --git a/paramecio/modules/admin/templates/admin/recovery_password.phtml b/paramecio/modules/admin/templates/admin/recovery_password.phtml new file mode 100644 index 0000000..7f99f10 --- /dev/null +++ b/paramecio/modules/admin/templates/admin/recovery_password.phtml @@ -0,0 +1,10 @@ +Hi User + +You send a request for get a new password + +Your new password is ${password} + +Thanks!!! + + +