Implementando envió de correo electrónico por SMTP o app-notificaiones y correcciones

parent 41c8c1a5
......@@ -2,6 +2,14 @@
# Puerto que usará la aplicación
PORT=3000
# IOP Activa el uso del módulo app-iop para la interoperabilidad
# - No funcionará la contrastación con el SEGIP
# - No funcionará el inicio de sesión con el SIN
IOP=true
# Validar con SEGIP en la creación de usuarios mediante el módulo app-iop si IOP=true
SEGIP=true
# DATABASE
DB_NAME=postgres
DB_USER=postgres
......@@ -11,18 +19,6 @@ DB_HOST=localhost
DB_DIALECT=postgres
DB_TIMEZONE=America/La_Paz
# MAIL SMTP (Opcional)
MAIL_SENDER=info@midominio.gob.bo
MAIL_HOST=smtp.midominio.gob.bo
MAIL_PORT=587
MAIL_SECURE=false
MAIL_IGNORE_TLS=false
MAIL_TLS_REJECT_UNAUTHORIZED=false
# Solo si el servidor SMTP lo requiere
MAIL_AUTH_USER=unusuario@midominio.gob.bo 
MAIL_AUTH_PASS=password 
# LOGS
# ¿Dónde guardar los logs?
# - database: Guardar en la base de datos (se usa db.js para acceder)
......@@ -42,3 +38,18 @@ LOG_FORMAT=combined
# nivel de verbosidad, posibles: error, info, warning, debug
LOG_LEVEL=info
# MAIL SMTP (Opcional)
# - MAIL_SMTP=true activa el envió de correos mediante SMTP
# - MAIL_SMTP=false usa el módulo app-notificaciones para el envío de correos
MAIL_SMTP=false
MAIL_SENDER=info@midominio.gob.bo
MAIL_HOST=smtp.midominio.gob.bo
MAIL_PORT=587
MAIL_SECURE=false
MAIL_IGNORE_TLS=false
MAIL_TLS_REJECT_UNAUTHORIZED=false
# Solo si el servidor SMTP lo requiere
MAIL_AUTH_USER=unusuario@midominio.gob.bo 
MAIL_AUTH_PASS=password
......@@ -32,7 +32,7 @@ Creamos una llave ssh para poder conectarnos directamente con el servidor de pro
``` bash
# Generamos la llave ssh dentro la carpeta deploy/ssh con el nombre deploy
ssh-keygen -t rsa -C "ogutierrez@agetic.gob.bo - deploy"
ssh-keygen -t rsa -C "ogutierrez@email.gob.bo - deploy"
```
## 5. Configurando servidor
......@@ -95,7 +95,7 @@ ansible-playbook -i inventory.ini backend.yml --private-key ssh/deploy
``` bash
# Probando conexión a la bd en el servidor de producción
psql -U agetic apostilla
psql -U usuario base-de-datos
# Comprobamos el estado del servicio backend-admin
systemctl status backend-admin
......@@ -110,7 +110,7 @@ systemctl status backend-proxy
Si se desea probar el deploy de manera local seguir los siguientes pasos:
1. Requisitos.-
1. Requisitos.-
- Instalar Virtualbox https://www.virtualbox.org/wiki/Downloads
- Instalar Vagrant https://www.vagrantup.com/downloads.html
......
postgresql_databases:
- name: database
owner: agetic
owner: usuario
hstore: yes
postgresql_users:
- name: agetic
pass: agetic
- name: usuario
pass: usuario
encrypted: no
postgresql_user_privileges:
- name: agetic
- name: usuario
db: database
priv: "ALL"
......@@ -40,7 +40,7 @@
"amqplib": "^0.5.5",
"apollo-server-express": "^2.9.12",
"app-iop": "git+https://gitlab.softwarelibre.gob.bo/agetic/app-iop.git",
"app-logs": "git+ssh://git@github.com/strymsg/app-logs.git",
"app-logs": "^2.0.0",
"app-notificaciones": "git+https://gitlab.softwarelibre.gob.bo/agetic/app-notificaciones.git",
"app-params": "^0.2.5",
"asyncawait": "^3.0.0",
......
......@@ -35,14 +35,22 @@ module.exports = function setupUsuarioController (services) {
};
persona = { persona };
} else {
if (tipoDoc === 'CI') {
persona = await Iop.segip.buscarPersona(ci, fechaNacimiento, complemento);
if (process.env.SEGIP === 'true') {
if (tipoDoc === 'CI') {
persona = await Iop.segip.buscarPersona(ci, fechaNacimiento, complemento);
} else {
return res.send({ observacion: 'La persona no está registrada en el sistema, complete los datos para registrarla.' });
}
} else {
return res.send({ observacion: 'La persona no está registrada en el sistema, complete los datos para registrarla.' });
}
}
} else {
persona = await Iop.segip.buscarPersona(ci, fechaNacimiento, complemento);
if (process.env.SEGIP === 'true') {
persona = await Iop.segip.buscarPersona(ci, fechaNacimiento, complemento);
} else {
return res.send({ warning: 'La validación con el SEGIP está deshabilitada.' });
}
}
} catch (e) {
return next(e);
......
......@@ -3,14 +3,12 @@
const domain = require('../domain');
const Params = require('app-params');
const Logs = require('app-logs');
const { config } = require('../common');
const { config, mail } = require('../common');
const Graphql = require('./graphql');
const { mergeGraphql } = require('./lib/util');
module.exports = async function setupModule (settings = { iop: true }) {
try {
global.IOP = !!settings.iop;
// Cargando Capa del dominio
let services = await domain(settings);
......@@ -33,7 +31,7 @@ module.exports = async function setupModule (settings = { iop: true }) {
// Uniendo Graphql de usuarios con Graphql de Logs
mergeGraphql(graphql, services.Log.graphql, ['DateL']);
if (global.IOP) {
if (process.env.IOP === 'true') {
// Agregando Iop a los servicios
const Iop = require('app-iop');
services.Iop = await Iop(config.db);
......@@ -42,6 +40,9 @@ module.exports = async function setupModule (settings = { iop: true }) {
mergeGraphql(graphql, services.Iop.graphql, ['DateI']);
}
// Configurando el envio de email
mail.init(services);
return {
services,
graphql,
......
......@@ -6,14 +6,14 @@ const correoConfig = {
origen: process.env.MAIL_SENDER,
host: process.env.MAIL_HOST,
port: process.env.MAIL_PORT,
secure: process.env.MAIL_SECURE,
ignoreTLS: process.env.MAIL_IGNORE_TLS,
secure: process.env.MAIL_SECURE === 'true',
ignoreTLS: process.env.MAIL_IGNORE_TLS === 'true',
auth: {
user: process.env.MAIL_AUTH_USER,
pass: process.env.MAIL_AUTH_PASS
},
tls: {
rejectUnauthorized: process.env.MAIL_TLS_REJECT_UNAUTHORIZED
rejectUnauthorized: process.env.MAIL_TLS_REJECT_UNAUTHORIZED === 'true'
},
logging: s => debug(s)
};
......
'use strict';
function enviar (data) {
const nodemailer = require('nodemailer');
const smtpTransport = require('nodemailer-smtp-transport');
const { mail } = require('../config');
const transporter = nodemailer.createTransport(smtpTransport(mail));
const settings = {
from: mail.origen,
to: data.para,
subject: data.titulo,
text: data.mensaje,
html: data.html,
attachments: data.attachments
};
return new Promise((resolve, reject) => {
transporter.sendMail(settings, (error, info) => {
if (error === null) {
resolve(info);
const mime = require('mime');
const { mail } = require('../config');
const text = require('./text');
let Iop = null;
let Parametro = null;
let Mail = null;
async function init (services) {
if (process.env.MAIL_SMTP === 'true') {
Parametro = services.Parametro;
const nodemailer = require('nodemailer');
const smtpTransport = require('nodemailer-smtp-transport');
Mail = nodemailer.createTransport(smtpTransport(mail));
} else {
Iop = services.Iop;
Mail = require('app-notificaciones');
}
}
async function enviar (data, template = 'TEMPLATE_CORREO_BASE') {
return new Promise(async (resolve, reject) => {
if (process.env.MAIL_SMTP === 'true') {
let tmpl = await Parametro.getParam(template);
let contenido = text.nano(tmpl.valor, { mensaje: data.contenido, year: new Date().getFullYear() });
const settings = {
from: mail.origen,
to: data.para,
subject: data.asunto,
// text: data.mensaje,
html: contenido
};
if (data.adjuntoBase64) {
let mimeType = data.adjuntoBase64.split(';')[0];
mimeType = mimeType.split(':')[1];
settings.attachments = [{
filename: `archivo_adjunto.${mime.getExtension(mimeType)}`,
path: data.adjuntoBase64
}];
} else {
if (error.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {
resolve(error);
} else {
reject(error);
settings.attachments = [{ path: data.adjunto }];
}
Mail.sendMail(settings, (error, info) => {
console.log('✅📧 Respuesta envio correo SMPT', error, info);
if (error) {
if (error.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {
return resolve(error);
} else {
return reject(error);
}
}
return resolve({ message: 'Correo enviado correctamente' });
});
} else {
let pne = await Iop.findByCode('PNE-01');
let cli = new Mail(pne.token, pne.url);
const settings = {
para: Array.isArray(data.para) ? data.para : [data.para],
asunto: data.asunto,
contenido: data.contenido,
adjuntoBase64: data.adjuntoBase64,
adjunto: data.adjunto
};
let correo = await cli.correo(settings);
console.log('✅📧 Respuesta envio correo APP-NOTIFICACIONES', correo);
if (correo && !correo.finalizado) {
return reject(new Error(`No se pudo enviar el correo: ${correo.mensaje}`));
}
});
return resolve({ message: 'Correo enviado correctamente' });
}
});
}
module.exports = {
init,
enviar
};
......@@ -8,15 +8,14 @@ const path = require('path');
const Logs = require('app-logs');
const Params = require('app-params');
module.exports = async function initDomain (settings = { iop: true }) {
global.IOP = !!settings.iop;
module.exports = async function initDomain () {
// Obteniendo repositorios de la capa de infrastructura
let repositories = await db(config.db).catch(errors.handleFatalError);
// Cargando Parámetros
repositories.Parametro = await Params(config.db);
if (global.IOP) {
if (process.env.IOP === 'true') {
const Iop = require('app-iop');
// Agregando servicio Iop a los repositorios
repositories.Iop = await Iop(config.db);
......
'use strict';
const debug = require('debug')('app:service:token');
const ClienteNotificaciones = require('app-notificaciones');
const { mail } = require('../../../common');
const Service = require('../Service');
module.exports = function tokenService (repositories, valueObjects, res) {
const { TokenRepository, UsuarioRepository, EntidadRepository, Iop } = repositories;
const { TokenRepository, UsuarioRepository, EntidadRepository } = repositories;
const {
TokenToken,
TokenTipo,
......@@ -52,21 +52,12 @@ module.exports = function tokenService (repositories, valueObjects, res) {
result = await TokenRepository.createOrUpdate(data);
if (result && datos.email) {
let pne = await Iop.findByCode('PNE-01');
let cli = new ClienteNotificaciones(pne.token, pne.url);
const parametros = {
await mail.enviar({
para: [datos.email],
asunto: 'Token de acceso - APP',
contenido: `<br> Token de acceso tipo ${data.tipo}:<br><br><small>Revise el archivo adjunto.</small>`,
adjuntoBase64: `data:text/plain;base64,${Buffer.from(data.token).toString('base64')}`
};
let correo = await cli.correo(parametros);
debug('Respuesta envio correo', correo);
if (correo && !correo.finalizado) {
return res.warning(new Error('No se pudo enviar el correo'));
}
});
}
} catch (e) {
return res.error(e);
......
......@@ -3,9 +3,8 @@
const debug = require('debug')('app:service:usuario');
const moment = require('moment');
const crypto = require('crypto');
const { text } = require('../../../common');
const { text, mail } = require('../../../common');
const { generateToken } = require('../../../application/lib/auth');
const ClienteNotificaciones = require('app-notificaciones');
const Service = require('../Service');
module.exports = function userService (repositories, valueObjects, res) {
......@@ -350,18 +349,11 @@ module.exports = function userService (repositories, valueObjects, res) {
};
await UsuarioRepository.createOrUpdate(data);
let pne = await Iop.findByCode('PNE-01');
let cli = new ClienteNotificaciones(pne.token, pne.url);
const email = {
let correo = await mail.enviar({
para: [datos.email],
asunto: 'Nueva contraseña - APP',
contenido: `<br> Nueva contraseña: <strong>${contrasena}</strong>`
};
let correo = await cli.correo(email);
debug('Respuesta envio correo', correo);
if (correo && !correo.finalizado) {
return res.error(new Error('No se pudo enviar el correo'));
}
asunto: '<br> Nueva contraseña - APP',
contenido: `Nueva contraseña: <strong>${contrasena}</strong>`
});
return res.success(correo);
} catch (e) {
return res.error(e);
......
......@@ -40,7 +40,7 @@ test.serial('EntidadService#createOrUpdate - new', async t => {
email: 'yoyo@gmail.com',
telefonos: '4535345',
direccion: 'Av x. Nro1234',
web: 'http://agetic.gob.bo',
web: 'http://dominio.gob.bo',
estado: 'ACTIVO',
_user_created: 1,
_created_at: new Date()
......
......@@ -15,9 +15,9 @@ class UsuarioContrasena extends ValueObject {
tooLong: '^La contraseña necesita tener a lo mucho %{count} caracteres'
},
format: {
pattern: /^(?=.*[\d])(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*])[\w!@#$%^&*]{8,}$/,
pattern: /^(?=.*[\d])(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*-_])[\w!@#$%^&*-_]{8,}$/,
flags: 'g',
message: '^La contraseña debe tener al menos un dígito, una letra minúscula, una letra mayúscula y los siguientes caracteres: ! @ # $ % ^ & *'
message: '^La contraseña debe tener al menos un dígito, una letra minúscula, una letra mayúscula y los siguientes caracteres: ! @ # $ % ^ & * - _'
}
};
super.validate();
......
......@@ -10,7 +10,7 @@ let items = [
{
usuario: 'admin',
contrasena,
email: 'admin@agetic.gob.bo',
email: 'admin@email.gob.bo',
estado: 'ACTIVO',
cargo: 'Profesional',
id_persona: 1,
......
......@@ -60,7 +60,11 @@ items = setTimestampsSeeder(items);
module.exports = {
up (queryInterface, Sequelize) {
return queryInterface.bulkInsert('servicios_iop', items, {});
if (process.env.IOP === 'true') {
return queryInterface.bulkInsert('servicios_iop', items, {});
} else {
return Promise.resolve(true);
}
},
down (queryInterface, Sequelize) { }
......
......@@ -2,7 +2,6 @@
const Sequelize = require('sequelize');
const Params = require('app-params');
const Iop = require('app-iop');
const minimist = require('minimist');
const inquirer = require('inquirer');
const { errors, config } = require('../common');
......@@ -36,7 +35,10 @@ async function setup () {
await Params(configDB);
// Cargando Servicios Iop
await Iop(configDB);
if (process.env.IOP === 'true') {
const Iop = require('app-iop');
await Iop(configDB);
}
let sequelize = new Sequelize(configDB);
// Verificando conexión con la BD
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment