diff --git a/backend/package.json b/backend/package.json index c8537ae0b..45f47db44 100644 --- a/backend/package.json +++ b/backend/package.json @@ -72,6 +72,7 @@ "neo4j-driver": "~1.7.4", "neo4j-graphql-js": "git+https://github.com/Human-Connection/neo4j-graphql-js.git#temporary_fixes", "node-fetch": "~2.6.0", + "nodemailer": "^6.2.1", "npm-run-all": "~4.1.5", "request": "~2.88.0", "sanitize-html": "~1.20.1", diff --git a/backend/src/config/index.js b/backend/src/config/index.js index aed6f7c1c..6931126e2 100644 --- a/backend/src/config/index.js +++ b/backend/src/config/index.js @@ -8,6 +8,13 @@ export const requiredConfigs = { PRIVATE_KEY_PASSPHRASE: process.env.PRIVATE_KEY_PASSPHRASE, } +export const smtpConfigs = { + SMTP_HOST: process.env.SMTP_HOST || 'localhost', + SMTP_PORT: process.env.SMTP_PORT || 1025, + SMTP_USERNAME: process.env.SMTP_USERNAME, + SMTP_PASSWORD: process.env.SMTP_PASSWORD, +} + export const neo4jConfigs = { NEO4J_URI: process.env.NEO4J_URI || 'bolt://localhost:7687', NEO4J_USERNAME: process.env.NEO4J_USERNAME || 'neo4j', @@ -29,6 +36,7 @@ export const developmentConfigs = { export default { ...requiredConfigs, + ...smtpConfigs, ...neo4jConfigs, ...serverConfigs, ...developmentConfigs, diff --git a/backend/src/schema/resolvers/passwordReset.js b/backend/src/schema/resolvers/passwordReset.js index e2fb1a80f..fe37187b5 100644 --- a/backend/src/schema/resolvers/passwordReset.js +++ b/backend/src/schema/resolvers/passwordReset.js @@ -1,5 +1,21 @@ import uuid from 'uuid/v4' import bcrypt from 'bcryptjs' +import CONFIG from '../../config' +import nodemailer from 'nodemailer' + +const transporter = () => { + const { SMTP_HOST: host, SMTP_PORT: port, SMTP_USERNAME: user, SMTP_PASSWORD: pass } = CONFIG + const configs = { + host, + port, + ignoreTLS: true, + secure: false, // true for 465, false for other ports + } + if (user && pass) { + configs.auth = { user, pass } + } + return nodemailer.createTransport(configs) +} export async function createPasswordReset(options) { const { driver, code, email, issuedAt = new Date() } = options @@ -10,7 +26,11 @@ export async function createPasswordReset(options) { MERGE (u)-[:REQUESTED]->(pr) RETURN pr ` - const transactionRes = await session.run(cypher, { issuedAt: issuedAt.toISOString(), code, email }) + const transactionRes = await session.run(cypher, { + issuedAt: issuedAt.toISOString(), + code, + email, + }) const resets = transactionRes.records.map(record => record.get('pr')) session.close() return resets @@ -19,8 +39,16 @@ export async function createPasswordReset(options) { export default { Mutation: { requestPasswordReset: async (_, { email }, { driver }) => { - const code = uuid().substring(0,6) + const code = uuid().substring(0, 6) await createPasswordReset({ driver, code, email }) + await transporter().sendMail({ + from: '"Human Connection" ', // sender address + to: email, // list of receivers + subject: 'Password Reset', // Subject line + text: `Code is ${code}`, // plain text body + html: `Code is ${code}`, // plain text body + }) + return true }, resetPassword: async (_, { email, code, newPassword }, { driver }) => { diff --git a/backend/src/schema/resolvers/passwordReset.spec.js b/backend/src/schema/resolvers/passwordReset.spec.js index 6d0347703..545945f51 100644 --- a/backend/src/schema/resolvers/passwordReset.spec.js +++ b/backend/src/schema/resolvers/passwordReset.spec.js @@ -76,11 +76,7 @@ describe('passwordReset', () => { describe('resetPassword', () => { const setup = async (options = {}) => { - const { - email = 'user@example.org', - issuedAt = new Date(), - code = 'abcdef', - } = options + const { email = 'user@example.org', issuedAt = new Date(), code = 'abcdef' } = options const session = driver.session() await createPasswordReset({ driver, email, issuedAt, code }) diff --git a/backend/yarn.lock b/backend/yarn.lock index d2c5da176..eaee0a3f3 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -5693,6 +5693,11 @@ node-releases@^1.1.19: dependencies: semver "^5.3.0" +nodemailer@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.2.1.tgz#20d773925eb8f7a06166a0b62c751dc8290429f3" + integrity sha512-TagB7iuIi9uyNgHExo8lUDq3VK5/B0BpbkcjIgNvxbtVrjNqq0DwAOTuzALPVkK76kMhTSzIgHqg8X1uklVs6g== + nodemon@~1.19.1: version "1.19.1" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.19.1.tgz#576f0aad0f863aabf8c48517f6192ff987cd5071"