Skip to content

Commit

Permalink
release: v0.0.1a14.dev20240302 (#38)
Browse files Browse the repository at this point in the history
* Tests: Valida more views

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test: Validate more tests

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test: validate more views

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Update password hasher to argon2 (#37)

* feat: Replace bcryp with argon2 for password hash

References:
 - https://passlib.readthedocs.io/en/stable/narr/quickstart.html#recommended-hashes
 - https://pypi.org/project/argon2-cffi/
 - https://pypi.org/project/bcrypt/

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* docs: Update docs

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test: Update test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

---------

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Remove setup.py file

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* chore: Update copyrithg notice

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Remove black from test requeriments

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Update dev dependencies

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: cleanup

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: update requeriments

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Update build metadata

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* docs: update config

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: update docker base image

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Update coverga report

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* buil: clean

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: update atributes

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Update setup

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Test coverage update

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* test: More tests

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* release: v0.0.1a14.dev20240223

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Update config

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* feat: Configure mail backend with Flask-Mailman (#39)

* Update password hasher to argon2 (#37)

* feat: Replace bcryp with argon2 for password hash

References:
 - https://passlib.readthedocs.io/en/stable/narr/quickstart.html#recommended-hashes
 - https://pypi.org/project/argon2-cffi/
 - https://pypi.org/project/bcrypt/

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* docs: Update docs

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test: Update test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

---------

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* release: v0.0.1a14.dev20240223 (#35)

* Tests: Valida more views

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test: Validate more tests

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test: validate more views

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Update password hasher to argon2 (#37)

* feat: Replace bcryp with argon2 for password hash

References:
 - https://passlib.readthedocs.io/en/stable/narr/quickstart.html#recommended-hashes
 - https://pypi.org/project/argon2-cffi/
 - https://pypi.org/project/bcrypt/

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* docs: Update docs

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* Test: Update test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

---------

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Remove setup.py file

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* chore: Update copyrithg notice

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Remove black from test requeriments

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Update dev dependencies

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: cleanup

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: update requeriments

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Update build metadata

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* docs: update config

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: update docker base image

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Update coverga report

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* buil: clean

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: update atributes

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Update setup

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Test coverage update

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* test: More tests

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* release: v0.0.1a14.dev20240223

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

---------

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Use flask-mailman

Signed-off-by: William Moreno Reyes <williamjmorenor@fedoraproject.org>

* feat: Setup email backend with Flask-Mailman

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

---------

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>
Signed-off-by: William Moreno Reyes <williamjmorenor@fedoraproject.org>
Signed-off-by: William Moreno <williamjmorenor@gmail.com>

* build: Update config

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: update

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Update config

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Update entrypoint

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* test: Update test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Clean

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* build: Update test

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

* release: v0.0.1a14.dev20240302

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>

---------

Signed-off-by: William José Moreno Reyes <williamjmorenor@gmail.com>
Signed-off-by: William Moreno Reyes <williamjmorenor@fedoraproject.org>
Signed-off-by: William Moreno <williamjmorenor@gmail.com>
  • Loading branch information
williamjmorenor authored Mar 3, 2024
1 parent fdd8a04 commit e8c2ec1
Show file tree
Hide file tree
Showing 20 changed files with 437 additions and 298 deletions.
1 change: 0 additions & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ source = now_lms

[report]
exclude_lines =
pragma: no cover
def __repr__
if self.debug:
if settings.DEBUG
Expand Down
32 changes: 16 additions & 16 deletions .do/deploy.template.yaml
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
spec:
name: nowlearningmanagementsystem
services:
- name: web
build_command: python -m flask setup
run_command: python -m flask serve
git:
branch: main
repo_clone_url: https://github.com/bmosoluciones/now-lms.git
envs:
- key: LMS_KEY
value: "nsjksldknsdlkdsljdnsdjñasññqldñaas554dlkallas"
type: SECRET
- key: LMS_USER
value: "lms-admin"
- key: LMS_PSWD
value: "lms-admin"
type: SECRET
- name: web
build_command: python -m flask setup
run_command: python -m flask serve
git:
branch: main
repo_clone_url: https://github.com/bmosoluciones/now-lms.git
envs:
- key: LMS_KEY
value: "nsjksldknsdlkdsljdnsdjñasññqldñaas554dlkallaskkkkllk"
type: SECRET
- key: LMS_USER
value: "lms-admin"
- key: LMS_PSWD
value: "lms-admin"
type: SECRET
databases:
- name: example-db
- name: example-db
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,4 @@ passenger_wsgi.py
wsgi.py
test.txt
now_lms.egg-info

.ruff_cache
6 changes: 5 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ charset = utf-8
max_line_length = 127

[*.{yml,yaml,json,js,css,html}]
indent_size = 2
indent_size = 2

[{package.json,.travis.yml}]
indent_style = space
indent_size = 2
366 changes: 183 additions & 183 deletions LICENSE

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion Procfile
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
web: python -m now_lms
# Main proccess
web: python -m now_lms
3 changes: 0 additions & 3 deletions development.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
-r test.txt

flask-debugtoolbar
flask_profiler

# Servidor de desarrollo
hupper

Expand Down
2 changes: 1 addition & 1 deletion docker-entry-point.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/sh
set -e

/usr/bin/python3.9 -m flask db upgrade
# /usr/bin/python3.9 -m flask db upgrade
/usr/bin/python3.9 -m now_lms
3 changes: 2 additions & 1 deletion docs/setup-conf.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ Note that initial log messages will refer to the default options because you are

You can use the following options to configure NOW-LMS:

- **SECRET_KEY** (<span style="color:red">required</span>): A secure string used to secure the login proccess and form validation.
- **SECRET_KEY** (<span style="color:red">required</span>): A secure string used to secure the login proccess and form validation and to hash sensible data stored in the system database, if this parameter changes, hashed secrets will not be
decripted and you will need to save then againg.
- **SQLALCHEMY_DATABASE_URI** (<span style="color:red">required</span>): A valid SQLAlchemy conextion string, SQLite, MySQL version
8 and a resent version of PostgreSQL must work out of the box, MariaDB ans MS SQLServer should work but we not test the release versus this database engines. Checkout the
[SQLAlchemy docs](https://docs.sqlalchemy.org/en/20/core/engines.html) to valid examples to conections strings, the PyMSQL and PG800 database drivers are installed as normal dependencies, other database engines may requiere manual drivers setup.
Expand Down
62 changes: 20 additions & 42 deletions now_lms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
from flask.cli import FlaskGroup
from flask_alembic import Alembic
from flask_login import LoginManager, current_user
from flask_mail import Mail
from flask_mailman import Mail
from flask_mde import Mde
from flask_uploads import configure_uploads
from pg8000.dbapi import ProgrammingError as PGProgrammingError
Expand All @@ -58,6 +58,7 @@
# ---------------------------------------------------------------------------------------
# Recursos locales
# ---------------------------------------------------------------------------------------
from now_lms.auth import descifrar_secreto
from now_lms.cache import cache
from now_lms.config import (
CONFIGURACION,
Expand Down Expand Up @@ -136,6 +137,7 @@
alembic: Alembic = Alembic()
administrador_sesion: LoginManager = LoginManager()
mde: Mde = Mde()
mail: Mail = Mail()


# ---------------------------------------------------------------------------------------
Expand All @@ -151,36 +153,7 @@ def inicializa_extenciones_terceros(flask_app: Flask):
administrador_sesion.init_app(flask_app)
cache.init_app(flask_app)
mde.init_app(flask_app)
if environ.get("PROFILER"): # pragma: no cover
log.warning("Profiler activo, no se recomienda el uso de esta opción en entornos reales.")
try:
from flask_debugtoolbar import DebugToolbarExtension
from flask_profiler import Profiler

app.debug = True

app.config["flask_profiler"] = {
"enabled": app.config["DEBUG"],
"storage": {"engine": "sqlite"},
"basicAuth": {"enabled": True, "username": "admin", "password": "admin"},
"ignore": ["^/static/.*"],
}

app.config["DEBUG_TB_INTERCEPT_REDIRECTS"] = False
toolbar = DebugToolbarExtension(app)
profiler = Profiler(app)
log.debug("Profiler activo")
except ModuleNotFoundError: # pragma: no cover
toolbar = None
profiler = None
except ImportError: # pragma: no cover
toolbar = None
profiler = None

if toolbar:
log.info("Flask development toolbar enabled.")
if profiler:
log.info("Flask profiler enabled.")
mail.init_app(flask_app)
log.trace("Extensiones de terceros iniciadas correctamente.")


Expand Down Expand Up @@ -395,7 +368,7 @@ def initial_setup(with_examples=False, with_tests=False):
log.info("NOW - LMS iniciado correctamente.")


def init_app(with_examples=False): # pragma: no cover
def init_app(with_examples=False):
"""Funcion auxiliar para iniciar la aplicacion."""

with lms_app.app_context():
Expand Down Expand Up @@ -442,21 +415,26 @@ def init_app(with_examples=False): # pragma: no cover
log.trace("Acceso a base de datos verificado.")
config = Configuracion.query.first()

if config.email:
if (
config.email
and config.MAIL_HOST is not None
and config.MAIL_PORT is not None
and config.MAIL_USERNAME is not None
and config.MAIL_PASSWORD is not None
):
log.trace("Cargando configuración de correo electronico.")
lms_app.config.update(
{
"MAIL_SERVER": config.mail_server,
"MAIL_PORT": config.mail_port,
"MAIL_USERNAME": config.mail_username,
"MAIL_PASSWORD": config.mail_password,
"MAIL_USE_TLS": config.mail_use_tls,
"MAIL_USE_SSL": config.mail_use_ssl,
"MAIL_HOST": config.MAIL_HOST,
"MAIL_PORT": config.MAIL_PORT,
"MAIL_USERNAME": config.MAIL_USERNAME,
"MAIL_PASSWORD": descifrar_secreto(config.MAIL_PASSWORD),
"MAIL_USE_TLS": config.MAIL_USE_TLS,
"MAIL_USE_SSL": config.MAIL_USE_SSL,
}
)
if DESARROLLO:
lms_app.config.update({"MAIL_SUPPRESS_SEND": True})
e_mail = Mail()
e_mail.init_app(lms_app)
lms_app.config.update({"MAIL_BACKEND": "dummy"})


# ---------------------------------------------------------------------------------------
Expand Down
56 changes: 55 additions & 1 deletion now_lms/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
# ---------------------------------------------------------------------------------------
# Libreria estandar
# ---------------------------------------------------------------------------------------
import base64
from datetime import datetime
from functools import wraps

Expand All @@ -29,7 +30,10 @@
# ---------------------------------------------------------------------------------------
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError
from flask import abort, flash
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from flask import abort, flash, current_app
from flask_login import current_user

# ---------------------------------------------------------------------------------------
Expand Down Expand Up @@ -88,3 +92,53 @@ def wrapper(*args, **kwargs):
return wrapper

return decorator_verifica_acceso


def proteger_secreto(password):
"""
Devuelve el hash de una contraseña.
Se requiere que el parametro "SECRET_KEY" este establecido en la configuración de la aplicacion,
si cambia el valor de este parametro debera actualizar la configuración ya se utiliza el mismo
parametro para obtener la contraseña original.
"""

with current_app.app_context():
from now_lms.db import database, Configuracion

config = database.session.execute(database.select(Configuracion)).first()[0]

kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=config.r,
iterations=480000,
)
key = base64.urlsafe_b64encode(kdf.derive(current_app.config.get("SECRET_KEY").encode()))
f = Fernet(key)
return f.encrypt(password.encode())


def descifrar_secreto(hash):
"""
Devuelve el valor de una contraseña protegida.
Se utiliza el valor del parametro "SECRET_KEY" de la configuración de la aplicación para decodificar
la contraseña original, si el parametro "SECRET_KEY" cambia en la configuración no se posible desifrar
la contraseña original, debera generar una nueva.
"""

with current_app.app_context():
from now_lms.db import database, Configuracion

config = database.session.execute(database.select(Configuracion)).first()[0]

kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=config.r,
iterations=480000,
)
key = base64.urlsafe_b64encode(kdf.derive(current_app.config.get("SECRET_KEY").encode()))
f = Fernet(key)
return f.decrypt(hash)
21 changes: 15 additions & 6 deletions now_lms/db/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,12 +351,21 @@ class Configuracion(database.Model, BaseTabla):
custom_logo = database.Column(database.Boolean())
# Email settings
email = database.Column(database.Boolean())
mail_server = database.Column(database.String(50))
mail_port = database.Column(database.String(50))
mail_username = database.Column(database.String(50))
mail_password = database.Column(database.String(50))
mail_use_tls = database.Column(database.Boolean())
mail_use_ssl = database.Column(database.Boolean())
MAIL_HOST = database.Column(database.String(50))
MAIL_PORT = database.Column(database.String(50))
MAIL_USERNAME = database.Column(database.String(50))
MAIL_PASSWORD = database.Column(database.LargeBinary())
MAIL_USE_TLS = database.Column(database.Boolean())
MAIL_USE_SSL = database.Column(database.Boolean())
email_verificado = database.Column(database.Boolean())
# These are ramdon bytes to protect passwords like SMTP mail password or others
# than the users of the system will estore in the database as configuration parameters
# those password are not goint to be saved in plain text, we will save them in hashed version
# with your app SECRET_KEY
# So, if any one have access to your database it will access to the hashed
# version of the password and this 16 bytes, but will need your app SECRET_KEY
# in order to decode those passwords.
r = database.Column(database.LargeBinary())


class Categoria(database.Model, BaseTabla):
Expand Down
12 changes: 6 additions & 6 deletions now_lms/db/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,20 +85,20 @@ def verifica_estudiante_asignado_a_curso(id_curso: Union[None, str] = None):

def crear_configuracion_predeterminada():
"""Crea configuración predeterminada de la aplicación."""

from os import urandom

config = Configuracion(
titulo="NOW LMS",
descripcion="Sistema de aprendizaje en linea.",
modo="mooc",
style="dark",
custom_logo=False,
email=False,
mail_server=None,
mail_port=None,
mail_use_tls=False,
mail_use_ssl=False,
mail_username=None,
mail_password=None,
MAIL_USE_TLS=False,
MAIL_USE_SSL=False,
moneda="C$",
r=urandom(16),
)
database.session.add(config)
database.session.commit()
Expand Down
12 changes: 6 additions & 6 deletions now_lms/forms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,12 @@ class MailForm(FlaskForm):
"""Formulario de configuración de correo electronico."""

email = BooleanField(validators=[])
mail_server = StringField(validators=[DataRequired()])
mail_port = StringField(validators=[DataRequired()])
mail_use_tls = BooleanField(validators=[])
mail_use_ssl = BooleanField(validators=[])
mail_username = StringField(validators=[DataRequired()])
mail_password = StringField(validators=[DataRequired()])
MAIL_HOST = StringField(validators=[DataRequired()])
MAIL_PORT = StringField(validators=[DataRequired()])
MAIL_USERNAME = StringField(validators=[DataRequired()])
MAIL_PASSWORD = PasswordField()
MAIL_USE_TLS = BooleanField(validators=[])
MAIL_USE_SSL = BooleanField(validators=[])


class LogonForm(FlaskForm):
Expand Down
Loading

0 comments on commit e8c2ec1

Please sign in to comment.