Notificación de acceso por correo

This commit is contained in:
Mauricio Baeza 2019-02-05 22:12:19 -06:00
parent f761ab7a5a
commit 95d3345418
5 changed files with 208 additions and 4 deletions

View File

@ -47,6 +47,7 @@ class AppLogin(object):
session.invalidate()
values = req.params
values['rfc'] = values['rfc'].upper()
values['ip'] = req.remote_addr
result, user = self._db.authenticate(values)
if result['login']:
session.save()

View File

@ -18,12 +18,130 @@
import base64
import math
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders
from email.utils import formatdate
import requests
from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
TIMEOUT = 10
class SendMail(object):
def __init__(self, config):
self._config = config
self._server = None
self._error = ''
self._is_connect = self._login()
@property
def is_connect(self):
return self._is_connect
@property
def error(self):
return self._error
def _login(self):
hosts = ('gmail' in self._config['server'] or
'outlook' in self._config['server'])
try:
if self._config['ssl'] and hosts:
self._server = smtplib.SMTP(
self._config['server'],
self._config['port'], timeout=TIMEOUT)
self._server.ehlo()
self._server.starttls()
self._server.ehlo()
elif self._config['ssl']:
self._server = smtplib.SMTP_SSL(
self._config['server'],
self._config['port'], timeout=TIMEOUT)
self._server.ehlo()
else:
self._server = smtplib.SMTP(
self._config['server'],
self._config['port'], timeout=TIMEOUT)
self._server.login(self._config['user'], self._config['pass'])
return True
except smtplib.SMTPAuthenticationError as e:
if '535' in str(e):
self._error = 'Nombre de usuario o contraseña inválidos'
return False
# ~ print (e)
if '534' in str(e) and 'gmail' in self._config['server']:
self._error = 'Necesitas activar el acceso a otras ' \
'aplicaciones en tu cuenta de GMail'
return False
except smtplib.SMTPException as e:
self._error = str(e)
return False
except Exception as e:
self._error = str(e)
return False
return
def send(self, options):
try:
message = MIMEMultipart()
message['From'] = self._config['user']
message['To'] = options['to']
message['CC'] = options.get('copy', '')
message['Subject'] = options['subject']
message['Date'] = formatdate(localtime=True)
if options.get('confirm', False):
message['Disposition-Notification-To'] = message['From']
message.attach(MIMEText(options['message'], 'html'))
for f in options.get('files', ()):
part = MIMEBase('application', 'octet-stream')
if isinstance(f[0], str):
part.set_payload(f[0].encode('utf-8'))
else:
part.set_payload(f[0])
encoders.encode_base64(part)
part.add_header(
'Content-Disposition',
"attachment; filename={}".format(f[1]))
message.attach(part)
receivers = options['to'].split(',') + message['CC'].split(',')
self._server.sendmail(
self._config['user'], receivers, message.as_string())
return ''
except Exception as e:
return str(e)
def close(self):
try:
self._server.quit()
except:
pass
return
def send_mail(data):
msg = ''
ok = True
server = SendMail(data['server'])
if server.is_connect:
msg = server.send(data['mail'])
else:
msg = server.error
ok = False
server.close()
return {'ok': ok, 'msg': msg}
def round_up(value):
return int(math.ceil(value))
@ -45,3 +163,10 @@ def decrypt(data, password):
return f.decrypt(data.encode()).decode()
def to_bool(value):
return bool(int(value))
def get_url(url):
r = requests.get(url).text
return r

View File

@ -460,6 +460,17 @@ class Configuracion(BaseModel):
values = {r.clave: r.valor for r in data}
return values
def _get_admin_config_users(self):
fields = (
'chk_users_notify_access',
)
data = (Configuracion
.select()
.where(Configuracion.clave.in_(fields))
)
values = {r.clave: util.get_bool(r.valor) for r in data}
return values
@classmethod
def get_(cls, keys):
if isinstance(keys, str):
@ -477,6 +488,7 @@ class Configuracion(BaseModel):
'complements',
'folios',
'correo',
'admin_config_users',
)
opt = keys['fields']
if opt in options:
@ -8570,6 +8582,50 @@ def _save_log(user, action, table):
return
@util.run_in_thread
def _send_notify_access(args):
admins = (Usuarios
.select(Usuarios.correo)
.where(Usuarios.es_admin==True)
.scalar(as_tuple=True))
if not admins:
return
config = Configuracion.get_({'fields': 'correo'})
contra = Configuracion.get_('correo_contra')
if not config:
return
user = args['usuario']
rfc = args['rfc']
ip = args['ip']
url = f"http://ip-api.com/line/{ip}?fields=city"
city = utils.get_url(url)
message = f"Desde la IP: {ip} en: {city}"
server = {
'server': config['correo_servidor'],
'port': config['correo_puerto'],
'ssl': utils.to_bool(config['correo_ssl']),
'user': config['correo_usuario'],
'pass': utils.decrypt(contra, rfc),
}
mail = {
'to': ','.join(admins),
'subject': f"Usuario {user} identificado",
'message': message,
}
data= {
'server': server,
'mail': mail,
}
result = utils.send_mail(data)
return
def authenticate(args):
respuesta = {'login': False, 'msg': 'No Autorizado', 'user': ''}
values = util.get_con(args['rfc'])
@ -8594,7 +8650,11 @@ def authenticate(args):
respuesta['login'] = True
respuesta['user'] = str(obj)
respuesta['super'] = obj.es_superusuario
#~ respuesta['admin'] = obj.es_superusuario or obj.es_admin
notify_access = Configuracion.get_bool('chk_users_notify_access')
if notify_access:
_send_notify_access(args)
return respuesta, obj

View File

@ -59,11 +59,13 @@ var controllers = {
$$('grid_admin_unidades').attachEvent('onItemClick', grid_admin_unidades_click)
$$('grid_moneda_found').attachEvent('onValueSuggest', grid_moneda_found_click)
$$('cmd_agregar_impuesto').attachEvent('onItemClick', cmd_agregar_impuesto_click)
//~ Usuarios
$$('cmd_usuario_agregar').attachEvent('onItemClick', cmd_usuario_agregar_click)
$$('grid_usuarios').attachEvent('onItemClick', grid_usuarios_click)
$$('grid_usuarios').attachEvent('onCheck', grid_usuarios_on_check)
$$('grid_usuarios').attachEvent('onItemDblClick', grid_usuarios_double_click)
$$('chk_users_notify_access').attachEvent('onItemClick', chk_config_item_click)
admin_ui_windows.init()
//~ Opciones
@ -408,9 +410,22 @@ function get_admin_usos_cfdi(){
function get_admin_usuarios(){
webix.ajax().sync().get('/values/allusuarios', function(text, data){
var values = data.json()
var rows = data.json()
$$('grid_usuarios').clearAll()
$$('grid_usuarios').parse(values, 'json')
$$('grid_usuarios').parse(rows)
})
webix.ajax().get('/config', {'fields': 'admin_config_users'}, {
error: function(text, data, xhr) {
msg = 'Error al consultar'
msg_error(msg)
},
success: function(text, data, xhr) {
var values = data.json()
Object.keys(values).forEach(function(key){
$$(key).setValue(values[key])
})
}
})
}
@ -447,7 +462,6 @@ function get_config_values(opt){
},
success: function(text, data, xhr) {
var values = data.json()
//~ showvar(values)
Object.keys(values).forEach(function(key){
$$(key).setValue(values[key])
})

View File

@ -1219,6 +1219,10 @@ var usuarios_admin = [
{maxHeight: 20},
{template: 'Usuarios Registrados', type: 'section'},
{cols: [{maxWidth: 10}, grid_usuarios, {maxWidth: 10}]},
{maxHeight: 20},
{template: 'Opciones', type: 'section'},
{cols: [{view: 'checkbox', id: 'chk_users_notify_access', labelWidth: 15,
labelRight: 'Notificar accesos al sistema (solo a administradores)'}]},
{},
]