forked from elmau/empresa-libre
Notificación de acceso por correo
This commit is contained in:
parent
f761ab7a5a
commit
95d3345418
|
@ -47,6 +47,7 @@ class AppLogin(object):
|
||||||
session.invalidate()
|
session.invalidate()
|
||||||
values = req.params
|
values = req.params
|
||||||
values['rfc'] = values['rfc'].upper()
|
values['rfc'] = values['rfc'].upper()
|
||||||
|
values['ip'] = req.remote_addr
|
||||||
result, user = self._db.authenticate(values)
|
result, user = self._db.authenticate(values)
|
||||||
if result['login']:
|
if result['login']:
|
||||||
session.save()
|
session.save()
|
||||||
|
|
|
@ -18,12 +18,130 @@
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import math
|
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.fernet import Fernet
|
||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
from cryptography.hazmat.primitives import hashes
|
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):
|
def round_up(value):
|
||||||
return int(math.ceil(value))
|
return int(math.ceil(value))
|
||||||
|
|
||||||
|
@ -45,3 +163,10 @@ def decrypt(data, password):
|
||||||
return f.decrypt(data.encode()).decode()
|
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}
|
values = {r.clave: r.valor for r in data}
|
||||||
return values
|
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
|
@classmethod
|
||||||
def get_(cls, keys):
|
def get_(cls, keys):
|
||||||
if isinstance(keys, str):
|
if isinstance(keys, str):
|
||||||
|
@ -477,6 +488,7 @@ class Configuracion(BaseModel):
|
||||||
'complements',
|
'complements',
|
||||||
'folios',
|
'folios',
|
||||||
'correo',
|
'correo',
|
||||||
|
'admin_config_users',
|
||||||
)
|
)
|
||||||
opt = keys['fields']
|
opt = keys['fields']
|
||||||
if opt in options:
|
if opt in options:
|
||||||
|
@ -8570,6 +8582,50 @@ def _save_log(user, action, table):
|
||||||
return
|
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):
|
def authenticate(args):
|
||||||
respuesta = {'login': False, 'msg': 'No Autorizado', 'user': ''}
|
respuesta = {'login': False, 'msg': 'No Autorizado', 'user': ''}
|
||||||
values = util.get_con(args['rfc'])
|
values = util.get_con(args['rfc'])
|
||||||
|
@ -8594,7 +8650,11 @@ def authenticate(args):
|
||||||
respuesta['login'] = True
|
respuesta['login'] = True
|
||||||
respuesta['user'] = str(obj)
|
respuesta['user'] = str(obj)
|
||||||
respuesta['super'] = obj.es_superusuario
|
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
|
return respuesta, obj
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -59,11 +59,13 @@ var controllers = {
|
||||||
$$('grid_admin_unidades').attachEvent('onItemClick', grid_admin_unidades_click)
|
$$('grid_admin_unidades').attachEvent('onItemClick', grid_admin_unidades_click)
|
||||||
$$('grid_moneda_found').attachEvent('onValueSuggest', grid_moneda_found_click)
|
$$('grid_moneda_found').attachEvent('onValueSuggest', grid_moneda_found_click)
|
||||||
$$('cmd_agregar_impuesto').attachEvent('onItemClick', cmd_agregar_impuesto_click)
|
$$('cmd_agregar_impuesto').attachEvent('onItemClick', cmd_agregar_impuesto_click)
|
||||||
|
|
||||||
//~ Usuarios
|
//~ Usuarios
|
||||||
$$('cmd_usuario_agregar').attachEvent('onItemClick', cmd_usuario_agregar_click)
|
$$('cmd_usuario_agregar').attachEvent('onItemClick', cmd_usuario_agregar_click)
|
||||||
$$('grid_usuarios').attachEvent('onItemClick', grid_usuarios_click)
|
$$('grid_usuarios').attachEvent('onItemClick', grid_usuarios_click)
|
||||||
$$('grid_usuarios').attachEvent('onCheck', grid_usuarios_on_check)
|
$$('grid_usuarios').attachEvent('onCheck', grid_usuarios_on_check)
|
||||||
$$('grid_usuarios').attachEvent('onItemDblClick', grid_usuarios_double_click)
|
$$('grid_usuarios').attachEvent('onItemDblClick', grid_usuarios_double_click)
|
||||||
|
$$('chk_users_notify_access').attachEvent('onItemClick', chk_config_item_click)
|
||||||
admin_ui_windows.init()
|
admin_ui_windows.init()
|
||||||
|
|
||||||
//~ Opciones
|
//~ Opciones
|
||||||
|
@ -408,9 +410,22 @@ function get_admin_usos_cfdi(){
|
||||||
|
|
||||||
function get_admin_usuarios(){
|
function get_admin_usuarios(){
|
||||||
webix.ajax().sync().get('/values/allusuarios', function(text, data){
|
webix.ajax().sync().get('/values/allusuarios', function(text, data){
|
||||||
var values = data.json()
|
var rows = data.json()
|
||||||
$$('grid_usuarios').clearAll()
|
$$('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) {
|
success: function(text, data, xhr) {
|
||||||
var values = data.json()
|
var values = data.json()
|
||||||
//~ showvar(values)
|
|
||||||
Object.keys(values).forEach(function(key){
|
Object.keys(values).forEach(function(key){
|
||||||
$$(key).setValue(values[key])
|
$$(key).setValue(values[key])
|
||||||
})
|
})
|
||||||
|
|
|
@ -1219,6 +1219,10 @@ var usuarios_admin = [
|
||||||
{maxHeight: 20},
|
{maxHeight: 20},
|
||||||
{template: 'Usuarios Registrados', type: 'section'},
|
{template: 'Usuarios Registrados', type: 'section'},
|
||||||
{cols: [{maxWidth: 10}, grid_usuarios, {maxWidth: 10}]},
|
{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