Added keyutils and fixes in autologin
This commit is contained in:
parent
cd0fdacbb7
commit
192e8b4b0b
4 changed files with 155 additions and 10 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
# A more simple set for make queries
|
# A more simple set for make queries
|
||||||
|
|
||||||
def insert(model, dict_values, db):
|
def insert(model, db, dict_values):
|
||||||
|
|
||||||
final_values={}
|
final_values={}
|
||||||
|
|
||||||
|
|
@ -25,3 +25,20 @@ def insert(model, dict_values, db):
|
||||||
|
|
||||||
return success
|
return success
|
||||||
|
|
||||||
|
|
||||||
|
def select(model, db, dict_fields=[], where_sql='', limit='', dict_values=[]):
|
||||||
|
|
||||||
|
if len(dict_fields)==0:
|
||||||
|
dict_fields=['`'+field+'`' for field in model.fields.keys()]
|
||||||
|
|
||||||
|
str_fields=", ".join(dict_fields)
|
||||||
|
|
||||||
|
str_query='select {} from {} {} limit 1'.format(str_fields, model.name, where_sql)
|
||||||
|
|
||||||
|
arr_result=[]
|
||||||
|
|
||||||
|
with db.query(str_query, dict_values) as cursor:
|
||||||
|
|
||||||
|
arr_result=cursor.fetchall()
|
||||||
|
|
||||||
|
return arr_result
|
||||||
|
|
|
||||||
86
parameciofast/libraries/keyutils.py
Normal file
86
parameciofast/libraries/keyutils.py
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
"""
|
||||||
|
Paramecio2fm is a series of wrappers for Flask, mako and others and construct a simple headless cms.
|
||||||
|
|
||||||
|
Copyright (C) 2023 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 hashlib import sha512, sha256
|
||||||
|
from base64 import b64encode
|
||||||
|
from os import urandom
|
||||||
|
import string
|
||||||
|
import secrets
|
||||||
|
|
||||||
|
# Functions for create random strings usando urandom
|
||||||
|
|
||||||
|
def create_key_encrypt(n=10):
|
||||||
|
""" Simple function for create a random string
|
||||||
|
|
||||||
|
Simple function for create a random string based in sha512
|
||||||
|
|
||||||
|
Args:
|
||||||
|
n (int): size of string random bytes (view urandom function in Python3 Help)
|
||||||
|
"""
|
||||||
|
|
||||||
|
return sha512(urandom(n)).hexdigest()
|
||||||
|
|
||||||
|
def create_key_encrypt_256(n=10):
|
||||||
|
|
||||||
|
""" Simple function for create a random string
|
||||||
|
|
||||||
|
Simple function for create a random string based in sha256
|
||||||
|
|
||||||
|
Args:
|
||||||
|
n (int): size of string random bytes (view urandom function in Python3 Help)
|
||||||
|
"""
|
||||||
|
|
||||||
|
return sha256(urandom(n)).hexdigest()
|
||||||
|
|
||||||
|
def create_key(n=10):
|
||||||
|
|
||||||
|
""" Simple function for create a random string
|
||||||
|
|
||||||
|
Simple function for create a random string based in urandom function and base64 encoding
|
||||||
|
|
||||||
|
Args:
|
||||||
|
n (int): size of string random bytes (view urandom function in Python3 Help)
|
||||||
|
"""
|
||||||
|
|
||||||
|
rand_bytes=urandom(n)
|
||||||
|
|
||||||
|
return b64encode(rand_bytes).decode('utf-8')[0:-2]
|
||||||
|
|
||||||
|
def create_simple_password(n=14):
|
||||||
|
|
||||||
|
""" Based in python3 documentation for create passwords using secrets module
|
||||||
|
|
||||||
|
https://docs.python.org/3/library/secrets.html
|
||||||
|
|
||||||
|
Args:
|
||||||
|
n (int): Number of random elements of the password
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
password=''
|
||||||
|
|
||||||
|
alphabet=string.ascii_letters+string.digits+string.punctuation
|
||||||
|
|
||||||
|
while True:
|
||||||
|
password=''.join(secrets.choice(alphabet) for i in range(n))
|
||||||
|
if (any(c.islower() for c in password) and any(c.isupper() for c in password) and sum(c.isdigit() for c in password) >= 3):
|
||||||
|
break
|
||||||
|
|
||||||
|
return password
|
||||||
|
|
||||||
|
|
@ -12,6 +12,8 @@ from parameciofast.libraries.fastutils import ResponseData
|
||||||
from parameciofast.libraries.db import simplequery
|
from parameciofast.libraries.db import simplequery
|
||||||
from settings import config
|
from settings import config
|
||||||
from parameciofast.libraries.datetime import now, format_local_strtime, timestamp_to_datetime, obtain_timestamp
|
from parameciofast.libraries.datetime import now, format_local_strtime, timestamp_to_datetime, obtain_timestamp
|
||||||
|
from parameciofast.libraries.keyutils import create_key_encrypt, create_key
|
||||||
|
from time import time
|
||||||
|
|
||||||
env=env_theme(__file__)
|
env=env_theme(__file__)
|
||||||
t=PTemplate(env, app.url_path_for)
|
t=PTemplate(env, app.url_path_for)
|
||||||
|
|
@ -28,15 +30,16 @@ seconds_login=300
|
||||||
if hasattr(config, 'seconds_login'):
|
if hasattr(config, 'seconds_login'):
|
||||||
seconds_login=config.seconds_login
|
seconds_login=config.seconds_login
|
||||||
|
|
||||||
|
cookie_name='paramecio_session'
|
||||||
|
|
||||||
#useradmin.create_forms()
|
if hasattr(config, 'cookie_name'):
|
||||||
|
cookie_name=config.cookie_name
|
||||||
#useradmin.safe_query=True
|
|
||||||
|
|
||||||
@admin_app.get('/', response_class=HTMLResponse)
|
@admin_app.get('/', response_class=HTMLResponse)
|
||||||
def home_admin(request: Request, paramecio_session: Annotated[str | None, Cookie(description='Cookie for validate into the admin site. The cookie name can change in you settings/config.py')] = None, remote_address: Annotated[str | None, Header()] = None):
|
def home_admin(request: Request, paramecio_session: Annotated[str | None, Cookie(description='Cookie for validate into the admin site. The cookie name can change in you settings/config.py')] = None, remote_address: Annotated[str | None, Header()] = None):
|
||||||
|
|
||||||
if not request.session.get('login_admin', None):
|
if not request.session.get('login_admin', None):
|
||||||
|
|
||||||
return RedirectResponse(app.url_path_for('login_admin'))
|
return RedirectResponse(app.url_path_for('login_admin'))
|
||||||
|
|
||||||
return "Hello world!"
|
return "Hello world!"
|
||||||
|
|
@ -47,6 +50,22 @@ def login_admin(request: Request):
|
||||||
|
|
||||||
db=WebModel.connection()
|
db=WebModel.connection()
|
||||||
|
|
||||||
|
if cookie_name+'_remember' in request.cookies:
|
||||||
|
|
||||||
|
arr_user=simplequery.select(usermodel, db, dict_fields=['id', 'username'], where_sql='WHERE token_login=%s', dict_values=[request.cookies[cookie_name+'_remember']])
|
||||||
|
|
||||||
|
if len(arr_user)>0:
|
||||||
|
now_str=now()
|
||||||
|
date_now=format_local_strtime('YYYY-MM-DD HH:mm:ss', now_str)
|
||||||
|
|
||||||
|
db.query('update useradmin set last_login=%s WHERE id=%s', [date_now, arr_user[0]['id']])
|
||||||
|
|
||||||
|
request.session['login_admin']=True
|
||||||
|
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
return RedirectResponse(app.url_path_for('home_admin'))
|
||||||
|
|
||||||
with db.query('select count(id) as num_users from useradmin', []) as cursor:
|
with db.query('select count(id) as num_users from useradmin', []) as cursor:
|
||||||
num_users=cursor.fetchone()['num_users']
|
num_users=cursor.fetchone()['num_users']
|
||||||
|
|
||||||
|
|
@ -85,7 +104,7 @@ class ResponseDataLogin(ResponseData):
|
||||||
no_login: bool
|
no_login: bool
|
||||||
|
|
||||||
@admin_app.post('/login')
|
@admin_app.post('/login')
|
||||||
def check_login_admin(user: UserAdmin, request: Request) -> ResponseDataLogin:
|
def check_login_admin(user: UserAdmin, request: Request, response: Response) -> ResponseDataLogin:
|
||||||
|
|
||||||
db=WebModel.connection()
|
db=WebModel.connection()
|
||||||
|
|
||||||
|
|
@ -106,6 +125,22 @@ def check_login_admin(user: UserAdmin, request: Request) -> ResponseDataLogin:
|
||||||
|
|
||||||
if usermodel.fields['password'].verify(user.password, result['password']):
|
if usermodel.fields['password'].verify(user.password, result['password']):
|
||||||
|
|
||||||
|
remember_key=''
|
||||||
|
|
||||||
|
if user.remember_login==True:
|
||||||
|
# Send cookies
|
||||||
|
|
||||||
|
remember_key=create_key_encrypt()
|
||||||
|
|
||||||
|
timestamp=int(time())+315360000
|
||||||
|
|
||||||
|
response.set_cookie(key=cookie_name+'_remember', value=remember_key, expires=timestamp, max_age=315360000, httponly=True, path=config.application_root)
|
||||||
|
|
||||||
|
now_str=now()
|
||||||
|
date_now=format_local_strtime('YYYY-MM-DD HH:mm:ss', now_str)
|
||||||
|
|
||||||
|
db.query('update useradmin set token_login=%s, last_login=%s WHERE id=%s', [remember_key, date_now, result['id']])
|
||||||
|
|
||||||
request.session['login_admin']=True
|
request.session['login_admin']=True
|
||||||
error=0
|
error=0
|
||||||
message=''
|
message=''
|
||||||
|
|
@ -156,7 +191,7 @@ def signup_insert_admin(user: UserSignup, request: Request) -> ResponseData:
|
||||||
|
|
||||||
if not error:
|
if not error:
|
||||||
|
|
||||||
if simplequery.insert(usermodel, dict(user), db):
|
if simplequery.insert(usermodel, db, dict(user)):
|
||||||
error=0
|
error=0
|
||||||
message="User added!"
|
message="User added!"
|
||||||
|
|
||||||
|
|
@ -168,10 +203,15 @@ def signup_insert_admin(user: UserSignup, request: Request) -> ResponseData:
|
||||||
@admin_app.get('/logout')
|
@admin_app.get('/logout')
|
||||||
def logout_admin(request: Request) -> RedirectResponse:
|
def logout_admin(request: Request) -> RedirectResponse:
|
||||||
|
|
||||||
|
response=RedirectResponse(app.url_path_for('login_admin'))
|
||||||
|
|
||||||
if 'login_admin' in request.session:
|
if 'login_admin' in request.session:
|
||||||
del request.session['login_admin']
|
del request.session['login_admin']
|
||||||
|
|
||||||
return RedirectResponse(app.url_path_for('login_admin'))
|
if cookie_name+'_remember' in request.cookies:
|
||||||
|
response.delete_cookie(cookie_name+'_remember', path=config.application_root)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
def check_login_tries(request, db):
|
def check_login_tries(request, db):
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3 form-check">
|
<div class="mb-3 form-check">
|
||||||
<input type="checkbox" class="form-check-input" id="autologin" name="autologin">
|
<input type="checkbox" class="form-check-input" id="remember_login_form" name="remember_login" value="1">
|
||||||
<label class="form-check-label" for="autologin">${tlang('Autologin')}</label>
|
<label class="form-check-label" for="autologin">${tlang('Remember login')}</label>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" id="login_submit" class="btn btn-primary">Submit</button>
|
<button type="submit" id="login_submit" class="btn btn-primary">Submit</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
@ -100,7 +100,9 @@
|
||||||
|
|
||||||
$('#login_submit').prop('disabled', true);
|
$('#login_submit').prop('disabled', true);
|
||||||
|
|
||||||
data_form={'username': $('#username_form').val(), 'password': $('#password_form').val(), 'csrf_token': $("#csrf_token").val(), 'remember_login': 0};
|
const is_checked=document.getElementById('remember_login_form').checked;
|
||||||
|
|
||||||
|
data_form={'username': $('#username_form').val(), 'password': $('#password_form').val(), 'csrf_token': $("#csrf_token").val(), 'remember_login': is_checked};
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "${url_for('check_login_admin')}",
|
url: "${url_for('check_login_admin')}",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue