More fixes for modernize codebase
This commit is contained in:
parent
e93adee075
commit
aa1ad66525
4 changed files with 109 additions and 127 deletions
|
|
@ -1,4 +1,23 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Parameciofm is a series of wrappers for bottle.py, mako and others and construct a simple headless cms.
|
||||
|
||||
Copyright (C) 2024 Antonio de la Rosa Caballero
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
import os
|
||||
import smtplib
|
||||
import mimetypes
|
||||
|
|
@ -13,6 +32,8 @@ import ssl as ssl_module
|
|||
import sys
|
||||
|
||||
class SendMail:
|
||||
"""Class for send email
|
||||
"""
|
||||
|
||||
port=587
|
||||
|
||||
|
|
@ -25,6 +46,20 @@ class SendMail:
|
|||
#ssl=True
|
||||
|
||||
def __init__(self, ssl=True):
|
||||
"""Class for send email
|
||||
|
||||
Class for send email using standard python library
|
||||
|
||||
Attributes:
|
||||
port (int): The port used for send email, by default 587
|
||||
host (str): The hostname of mail server used for send the email
|
||||
username (str): The username for login in mail server
|
||||
password (str): The password for login in mail server
|
||||
smtp (smtplib.SMTP): The python SMTP object used for send emails
|
||||
txt_error: (str): If error, is saved in this attribute
|
||||
|
||||
"""
|
||||
|
||||
|
||||
self.smtp=None #smtplib.SMTP(host=self.host, port=self.port)
|
||||
self.txt_error=''
|
||||
|
|
@ -79,9 +114,9 @@ class SendMail:
|
|||
|
||||
return False
|
||||
|
||||
except smtplib.SMTPAuthenticationError:
|
||||
except smtplib.SMTPAuthenticationError as eauth:
|
||||
|
||||
self.txt_error='Error: cannot login. Wrong username or password'
|
||||
self.txt_error='Error: cannot login. Wrong username or password '+eauth.__str__()
|
||||
|
||||
return False
|
||||
|
||||
|
|
@ -94,6 +129,18 @@ class SendMail:
|
|||
return True
|
||||
|
||||
def send(self, from_address, to_address: list, subject, message, content_type='plain', attachments=[]):
|
||||
""" Method that send email
|
||||
|
||||
With this method you can send email to multiple address, html, and add attachments to email
|
||||
|
||||
Args:
|
||||
from_address (str): The adress used for send the email
|
||||
to_address (list): A list of emails where the email will be sended.
|
||||
subject (str): The subject of the email
|
||||
message (str): The content of the message
|
||||
content_type (str): The type of mail content, can be plain or html.
|
||||
attachments (list): A list with a serie of file paths for attach to the email.
|
||||
"""
|
||||
|
||||
if self.smtp==None:
|
||||
if not self.connect():
|
||||
|
|
@ -174,12 +221,14 @@ class SendMail:
|
|||
return True
|
||||
|
||||
def quit(self):
|
||||
"""Function used when you need quit connection for any reason"""
|
||||
|
||||
if self.smtp!=None:
|
||||
self.smtp.quit()
|
||||
self.smtp=None
|
||||
|
||||
def __del__(self):
|
||||
"""Method for clean the connection when the object is closed"""
|
||||
|
||||
if self.smtp!=None:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,38 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
"""
|
||||
Parameciofm is a series of wrappers for bottle.py, mako and others and construct a simple headless cms.
|
||||
|
||||
Copyright (C) 2024 Antonio de la Rosa Caballero
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from paramecio.cromosoma.corefields import PhangoField
|
||||
from paramecio.cromosoma.coreforms import PasswordForm
|
||||
from hmac import compare_digest as compare_hash
|
||||
import crypt
|
||||
from hmac import compare_digest as compare_hash
|
||||
#try:
|
||||
# import crypt
|
||||
#except:
|
||||
# pass
|
||||
|
||||
#import bcrypt
|
||||
from argon2 import PasswordHasher
|
||||
|
||||
class PasswordField(PhangoField):
|
||||
"""Field for check and save passwords"""
|
||||
|
||||
def __init__(self, name, size=1024, required=False):
|
||||
|
||||
|
|
@ -43,7 +72,10 @@ class PasswordField(PhangoField):
|
|||
|
||||
#salt=crypt.mksalt(crypt.METHOD_SHA512)
|
||||
if self.encrypt_password:
|
||||
value=crypt.crypt(value)
|
||||
#value=crypt.crypt(value)
|
||||
ph=PasswordHasher()
|
||||
final_value=ph.hash(value)
|
||||
return final_value
|
||||
|
||||
"""
|
||||
else:
|
||||
|
|
@ -57,8 +89,14 @@ class PasswordField(PhangoField):
|
|||
|
||||
@staticmethod
|
||||
def verify( password, h):
|
||||
"""Static method used for verify a password save using PasswordField"""
|
||||
#return bcrypt_sha256.verify(password, h)
|
||||
return compare_hash(h, crypt.crypt(password, h))
|
||||
#return compare_hash(h, crypt.crypt(password, h))
|
||||
ph=PasswordHasher()
|
||||
try:
|
||||
return ph.verify(h, password)
|
||||
except:
|
||||
return False
|
||||
|
||||
# Old function bcrypt
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ from paramecio.wsgiapp import app
|
|||
import copy
|
||||
from paramecio.i18n import admin
|
||||
|
||||
admin_app=Bottle()
|
||||
|
||||
#from citoplasma.login import LoginClass
|
||||
# Check login
|
||||
|
||||
|
|
@ -70,11 +72,11 @@ if hasattr(config, 'admin_templates_index'):
|
|||
num_template+=1
|
||||
|
||||
|
||||
@app.get('/'+config.admin_folder)
|
||||
@app.get('/'+config.admin_folder+'/<module>')
|
||||
@app.post('/'+config.admin_folder+'/<module>')
|
||||
@app.get('/'+config.admin_folder+'/<module>/<submodule>')
|
||||
@app.post('/'+config.admin_folder+'/<module>/<submodule>')
|
||||
@app.get('/admin')
|
||||
@admin_app.get('/<module>')
|
||||
@admin_app.post('/<module>')
|
||||
@admin_app.get('/<module>/<submodule>')
|
||||
@admin_app.post('/<module>/<submodule>')
|
||||
def home(module='', submodule='', t=t):
|
||||
|
||||
# A simple boolean used for show or not the code of admin module in standard template
|
||||
|
|
@ -248,121 +250,12 @@ def home(module='', submodule='', t=t):
|
|||
|
||||
return ""
|
||||
|
||||
@app.post('/'+config.admin_folder+'/login')
|
||||
@admin_app.post('/login')
|
||||
def login():
|
||||
|
||||
return login_model(UserAdmin)
|
||||
|
||||
"""
|
||||
connection=WebModel.connection()
|
||||
|
||||
user_admin=UserAdmin(connection)
|
||||
|
||||
getpostfiles=GetPostFiles()
|
||||
|
||||
getpostfiles.obtain_post()
|
||||
|
||||
getpostfiles.post['username']=getpostfiles.post.get('username', '')
|
||||
getpostfiles.post['password']=getpostfiles.post.get('password', '')
|
||||
|
||||
username=user_admin.fields['username'].check(getpostfiles.post['username'])
|
||||
|
||||
password=getpostfiles.post['password'].strip()
|
||||
|
||||
user_admin.conditions=['WHERE username=%s', [username]]
|
||||
|
||||
arr_user=user_admin.select_a_row_where(['id', 'password', 'privileges', 'lang', 'num_tries', 'email'])
|
||||
|
||||
if arr_user==False:
|
||||
|
||||
s=get_session()
|
||||
|
||||
s['csrf_token']=create_key_encrypt()
|
||||
|
||||
s.save()
|
||||
connection.close()
|
||||
return {'error': 1, 'csrf_token': s['csrf_token']}
|
||||
else:
|
||||
|
||||
num_tries=int(arr_user['num_tries'])
|
||||
|
||||
if arr_user['num_tries']<3:
|
||||
|
||||
if user_admin.fields['password'].verify(password, arr_user['password']):
|
||||
|
||||
s=get_session()
|
||||
|
||||
s['id']=arr_user['id']
|
||||
s['login']=1
|
||||
s['privileges']=arr_user['privileges']
|
||||
s['lang']=arr_user['lang']
|
||||
s['email']=arr_user['email']
|
||||
|
||||
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=config.session_opts['session.path'], expires=timestamp, secret=key_encrypt)
|
||||
#else:
|
||||
#print(user_admin.query_error)
|
||||
s.save()
|
||||
|
||||
connection.close()
|
||||
|
||||
return {'error': 0}
|
||||
else:
|
||||
|
||||
user_admin.check_user=False
|
||||
|
||||
user_admin.conditions=['WHERE username=%s', [username]]
|
||||
|
||||
user_admin.valid_fields=['num_tries']
|
||||
|
||||
user_admin.reset_require()
|
||||
|
||||
user_admin.update({'num_tries': arr_user['num_tries']+1})
|
||||
|
||||
s=get_session()
|
||||
|
||||
s['csrf_token']=create_key_encrypt()
|
||||
|
||||
s.save()
|
||||
|
||||
connection.close()
|
||||
|
||||
return {'error': 1, 'csrf_token': s['csrf_token']}
|
||||
else:
|
||||
s=get_session()
|
||||
|
||||
s['csrf_token']=create_key_encrypt()
|
||||
|
||||
s.save()
|
||||
|
||||
connection.close()
|
||||
|
||||
return {'error': 1, 'csrf_token': s['csrf_token']}
|
||||
"""
|
||||
|
||||
@app.post('/'+config.admin_folder+'/register')
|
||||
@admin_app.post('/register')
|
||||
def register():
|
||||
|
||||
getpostfiles=GetPostFiles()
|
||||
|
|
@ -423,7 +316,7 @@ def register():
|
|||
|
||||
return {'error': 1}
|
||||
|
||||
@app.get('/'+config.admin_folder+'/logout')
|
||||
@admin_app.get('/logout')
|
||||
def logout():
|
||||
|
||||
s=get_session()
|
||||
|
|
@ -446,7 +339,7 @@ def logout():
|
|||
|
||||
redirect(make_url(config.admin_folder))
|
||||
|
||||
@app.get('/'+config.admin_folder+'/recovery_password')
|
||||
@admin_app.get('/recovery_password')
|
||||
def recovery_password():
|
||||
|
||||
t=PTemplate(env)
|
||||
|
|
@ -465,7 +358,7 @@ def recovery_password():
|
|||
connection.close()
|
||||
return t.load_template('admin/recovery.phtml', forms=forms)
|
||||
|
||||
@app.post('/'+config.admin_folder+'/recovery_password')
|
||||
@admin_app.post('/recovery_password')
|
||||
def send_password():
|
||||
|
||||
connection=WebModel.connection()
|
||||
|
|
@ -522,13 +415,13 @@ def send_password():
|
|||
return {'email': '', 'error': 0}
|
||||
|
||||
|
||||
@app.get('/'+config.admin_folder+'/check_token')
|
||||
@admin_app.get('/check_token')
|
||||
def check_token():
|
||||
t=PTemplate(env)
|
||||
|
||||
return t.load_template('admin/check_token.phtml')
|
||||
|
||||
@app.post('/'+config.admin_folder+'/check_token')
|
||||
@admin_app.post('/check_token')
|
||||
def check_code_token():
|
||||
|
||||
t=PTemplate(env)
|
||||
|
|
@ -583,3 +476,5 @@ def check_code_token():
|
|||
s.save()
|
||||
|
||||
return {'token': 'Error: token is not valid', 'error': 1, 'csrf_token': s['csrf_token']}
|
||||
|
||||
app.mount('/'+config.admin_folder+'/', admin_app)
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -21,7 +21,7 @@ setup(name='paramecio',
|
|||
url='https://git.cuchulu.com/paramecio/parameciofm/',
|
||||
packages=['paramecio', 'paramecio.i18n', 'paramecio.settings'],
|
||||
include_package_data=True,
|
||||
install_requires=['bottle', 'mako', 'pymysql', 'sqlalchemy', 'oslo.concurrency', 'itsdangerous', 'colorama','cherrypy', 'arrow'],
|
||||
install_requires=['bottle', 'mako', 'pymysql', 'sqlalchemy', 'oslo.concurrency', 'itsdangerous', 'colorama','cherrypy', 'arrow', 'argon2-cffi', 'pillow'],
|
||||
entry_points={'console_scripts': [
|
||||
'paramecio = paramecio.console:start',
|
||||
'parameciodb = paramecio.cromosoma.dbamin.start'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue