Notificación de acceso por correo
This commit is contained in:
parent
f761ab7a5a
commit
95d3345418
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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])
|
||||
})
|
||||
|
|
|
@ -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)'}]},
|
||||
{},
|
||||
]
|
||||
|
||||
|
|
Loading…
Reference in New Issue