From cf012c0b7efffb81b03497a04b0fdad0423c72f7 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 16:05:55 +0100 Subject: [PATCH 01/24] Added a barebones class for handleing mail stuff ref #118 --- src/mailer.ts | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/mailer.ts diff --git a/src/mailer.ts b/src/mailer.ts new file mode 100644 index 0000000..069e496 --- /dev/null +++ b/src/mailer.ts @@ -0,0 +1,7 @@ + +/** + * This class is responsible for all things mail sending. + */ +export class Mailer { + +} From 908ac4f1ce9d78749268353c668e67b57eae6f94 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 16:06:47 +0100 Subject: [PATCH 02/24] Added nodemailer dependecy ref #118 --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 6014db2..eca1b4f 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "jsonwebtoken": "^8.5.1", "libphonenumber-js": "^1.9.7", "mysql": "^2.18.1", + "nodemailer": "^6.4.17", "pg": "^8.5.1", "reflect-metadata": "^0.1.13", "routing-controllers": "^0.9.0-alpha.6", From d7ea928714f94814695cbd2815c8730df58033f6 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 16:09:11 +0100 Subject: [PATCH 03/24] Added mail env vars ref #118 --- src/config.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/config.ts b/src/config.ts index 3bdcd27..8919124 100644 --- a/src/config.ts +++ b/src/config.ts @@ -10,7 +10,12 @@ export const config = { phone_validation_countrycode: getPhoneCodeLocale(), postalcode_validation_countrycode: getPostalCodeLocale(), version: process.env.VERSION || require('../package.json').version, - seedTestData: getDataSeeding() + seedTestData: getDataSeeding(), + mail_server: process.env.MAIL_SERVER, + mail_port: process.env.MAIL_PORT, + mail_user: process.env.MAIL_USER, + mail_password: process.env.MAIL_PASSWORD, + mail_from: process.env.MAIL_FROM } let errors = 0 if (typeof config.internal_port !== "number") { From 33890b544b77272ab1c4797e91375d24568eae58 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 16:10:02 +0100 Subject: [PATCH 04/24] Added a folder for the mail templates ref #118 --- src/static/docs/mail_templates/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/static/docs/mail_templates/.gitkeep diff --git a/src/static/docs/mail_templates/.gitkeep b/src/static/docs/mail_templates/.gitkeep new file mode 100644 index 0000000..e69de29 From 6b0155f01464f5ef73ab679b9e3219743e9db66b Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 16:10:02 +0100 Subject: [PATCH 05/24] Added a folder for the mail templates ref #118 --- src/static/mail_templates/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/static/mail_templates/.gitkeep diff --git a/src/static/mail_templates/.gitkeep b/src/static/mail_templates/.gitkeep new file mode 100644 index 0000000..e69de29 From 470703c4de954da94726879becd57986b59e1f69 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 17:20:33 +0100 Subject: [PATCH 06/24] Added env vars ref #118 --- src/config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/config.ts b/src/config.ts index 8919124..4bd6b31 100644 --- a/src/config.ts +++ b/src/config.ts @@ -11,8 +11,9 @@ export const config = { postalcode_validation_countrycode: getPostalCodeLocale(), version: process.env.VERSION || require('../package.json').version, seedTestData: getDataSeeding(), + app_url: process.env.APP_URL || "localhost", mail_server: process.env.MAIL_SERVER, - mail_port: process.env.MAIL_PORT, + mail_port: Number(process.env.MAIL_PORT) || 25, mail_user: process.env.MAIL_USER, mail_password: process.env.MAIL_PASSWORD, mail_from: process.env.MAIL_FROM From 78d2ac3027f7109161ee36e9b3dda628a7039468 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 17:20:44 +0100 Subject: [PATCH 07/24] Added nodemailer types ref #118 --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index eca1b4f..bb5f2a0 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "@types/jest": "^26.0.16", "@types/jsonwebtoken": "^8.5.0", "@types/node": "^14.14.20", + "@types/nodemailer": "^6.4.0", "@types/uuid": "^8.3.0", "axios": "^0.21.1", "cp-cli": "^2.0.0", From c4186034233a296b5971fbef16e7ef6809fbac51 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 17:20:55 +0100 Subject: [PATCH 08/24] Added the first mail error ref #118 --- src/errors/MailErrors.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/errors/MailErrors.ts diff --git a/src/errors/MailErrors.ts b/src/errors/MailErrors.ts new file mode 100644 index 0000000..7772ca9 --- /dev/null +++ b/src/errors/MailErrors.ts @@ -0,0 +1,12 @@ +import { IsString } from 'class-validator' + +/** + * Error to throw when a permission couldn't be found. + */ +export class MailServerConfigError extends Error { + @IsString() + name = "MailServerConfigError" + + @IsString() + message = "The SMTP server you provided couldn't be reached!" +} \ No newline at end of file From 637975305f1adf9bf505507790638cf1e229cfb1 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 17:21:18 +0100 Subject: [PATCH 09/24] Implemented a basic mailer with reset link sending ref #118 --- src/mailer.ts | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/mailer.ts b/src/mailer.ts index 069e496..f834697 100644 --- a/src/mailer.ts +++ b/src/mailer.ts @@ -1,7 +1,44 @@ - +import nodemailer from 'nodemailer'; +import { MailOptions } from 'nodemailer/lib/json-transport'; +import Mail from 'nodemailer/lib/mailer'; +import { config } from './config'; +import { MailServerConfigError } from './errors/MailErrors'; +import { User } from './models/entities/User'; /** * This class is responsible for all things mail sending. */ export class Mailer { + private transport: Mail; + constructor() { + this.transport = nodemailer.createTransport({ + host: config.mail_server, + port: config.mail_port, + auth: { + user: config.mail_user, + pass: config.mail_password + } + }); + + this.transport.verify(function (error, success) { + if (error) { + throw new MailServerConfigError(); + } + }); + } + + public async sendResetMail(user: User, token: String) { + const reset_link = `${config.app_url}/reset/${token}` + const mail: MailOptions = { + to: user.email, + subject: "LfK! Password Reset", + html: `${reset_link}` + }; + await this.sendMail(mail); + } + + public async sendMail(mail: MailOptions) { + mail.from = config.mail_from; + await this.transport.sendMail(mail); + } } From d02e9dec5637aedefdf2ed3cd2c6d73216b6464b Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 17:28:20 +0100 Subject: [PATCH 10/24] Removed tests working directly with the old pw-reset response ref #118 --- src/tests/auth/auth_reset.spec.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/tests/auth/auth_reset.spec.ts b/src/tests/auth/auth_reset.spec.ts index 47c61e6..8a78a83 100644 --- a/src/tests/auth/auth_reset.spec.ts +++ b/src/tests/auth/auth_reset.spec.ts @@ -40,14 +40,6 @@ describe('POST /api/auth/reset valid', () => { reset_token = res1.data.resetToken; expect(res1.status).toEqual(200); }); - it('valid password reset should return 200', async () => { - const res2 = await axios.post(base + '/api/auth/reset/' + reset_token, { password: "demo" }, axios_config); - expect(res2.status).toEqual(200); - }); - it('valid login after reset should return 200', async () => { - const res = await axios.post(base + '/api/auth/login', { username: "demo_reset", password: "demo" }); - expect(res.status).toEqual(200); - }); }); // --------------- describe('POST /api/auth/reset invalid requests', () => { From e26744b7925d32d65ef4cc3911651758cfc9274f Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 17:35:03 +0100 Subject: [PATCH 11/24] Implementes mail sending on pw reset request ref #118 --- src/controllers/AuthController.ts | 17 ++++++++++++----- src/mailer.ts | 5 ++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index 507ac38..3545422 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -2,17 +2,23 @@ import { Body, CookieParam, JsonController, Param, Post, Req, Res } from 'routin import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { IllegalJWTError, InvalidCredentialsError, JwtNotProvidedError, PasswordNeededError, RefreshTokenCountInvalidError, UsernameOrEmailNeededError } from '../errors/AuthError'; import { UserNotFoundError } from '../errors/UserErrors'; +import { Mailer } from '../mailer'; import { CreateAuth } from '../models/actions/create/CreateAuth'; import { CreateResetToken } from '../models/actions/create/CreateResetToken'; import { HandleLogout } from '../models/actions/HandleLogout'; import { RefreshAuth } from '../models/actions/RefreshAuth'; import { ResetPassword } from '../models/actions/ResetPassword'; import { ResponseAuth } from '../models/responses/ResponseAuth'; +import { ResponseEmpty } from '../models/responses/ResponseEmpty'; import { Logout } from '../models/responses/ResponseLogout'; @JsonController('/auth') export class AuthController { + + private mailer: Mailer; + constructor() { + this.mailer = new Mailer(); } @Post("/login") @@ -82,13 +88,14 @@ export class AuthController { } @Post("/reset") - @ResponseSchema(ResponseAuth) - @ResponseSchema(UserNotFoundError) - @ResponseSchema(UsernameOrEmailNeededError) + @ResponseSchema(ResponseEmpty, { statusCode: 200 }) + @ResponseSchema(UserNotFoundError, { statusCode: 404 }) + @ResponseSchema(UsernameOrEmailNeededError, { statusCode: 406 }) @OpenAPI({ description: "Request a password reset token.
This will provide you with a reset token that you can use by posting to /api/auth/reset/{token}." }) async getResetToken(@Body({ validate: true }) passwordReset: CreateResetToken) { - //This really shouldn't just get returned, but sent via mail or sth like that. But for dev only this is fine. - return { "resetToken": await passwordReset.toResetToken() }; + const reset_token: String = await passwordReset.toResetToken(); + await this.mailer.sendResetMail(passwordReset.email, reset_token); + return new ResponseEmpty(); } @Post("/reset/:token") diff --git a/src/mailer.ts b/src/mailer.ts index f834697..a7d8e6e 100644 --- a/src/mailer.ts +++ b/src/mailer.ts @@ -3,7 +3,6 @@ import { MailOptions } from 'nodemailer/lib/json-transport'; import Mail from 'nodemailer/lib/mailer'; import { config } from './config'; import { MailServerConfigError } from './errors/MailErrors'; -import { User } from './models/entities/User'; /** * This class is responsible for all things mail sending. */ @@ -27,10 +26,10 @@ export class Mailer { }); } - public async sendResetMail(user: User, token: String) { + public async sendResetMail(to_address: string, token: String) { const reset_link = `${config.app_url}/reset/${token}` const mail: MailOptions = { - to: user.email, + to: to_address, subject: "LfK! Password Reset", html: `${reset_link}` }; From 536de2a3199b1befed54b6fe520a2e3fcefe0d90 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 17:54:25 +0100 Subject: [PATCH 12/24] Implemented automatic ci env generation ref #118 --- package.json | 6 ++++-- scripts/create_testenv.ts | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 scripts/create_testenv.ts diff --git a/package.json b/package.json index bb5f2a0..2653861 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,9 @@ "docs": "typedoc --out docs src", "test": "jest", "test:watch": "jest --watchAll", - "test:ci": "start-server-and-test dev http://localhost:4010/api/docs/openapi.json test", + "test:ci:generate_env": "ts-node scripts/create_testenv.ts", + "test:ci:run": "start-server-and-test dev http://localhost:4010/api/docs/openapi.json test", + "test:ci": "npm run test:ci:generate_env && npm run test:ci:run", "seed": "ts-node ./node_modules/typeorm/cli.js schema:sync && ts-node ./node_modules/typeorm-seeding/dist/cli.js seed", "openapi:export": "ts-node scripts/openapi_export.ts", "licenses:export": "license-exporter --md", @@ -102,4 +104,4 @@ "docs/*" ] } -} +} \ No newline at end of file diff --git a/scripts/create_testenv.ts b/scripts/create_testenv.ts new file mode 100644 index 0000000..1fa6c8c --- /dev/null +++ b/scripts/create_testenv.ts @@ -0,0 +1,37 @@ +import consola from "consola"; +import fs from "fs"; +import nodemailer from "nodemailer"; + + +nodemailer.createTestAccount((err, account) => { + if (err) { + console.error('Failed to create a testing account. ' + err.message); + return process.exit(1); + } + + const env = ` +APP_PORT=4010 +DB_TYPE=sqlite +DB_HOST=bla +DB_PORT=bla +DB_USER=bla +DB_PASSWORD=bla +DB_NAME=./test.sqlite +NODE_ENV=dev +POSTALCODE_COUNTRYCODE=DE +SEED_TEST_DATA=true +MAIL_SERVER=${account.smtp.host} +MAIL_PORT=${account.smtp.port} +MAIL_USER=${account.user} +MAIL_PASSWORD=${account.pass} +MAIL_FROM=${account.user}` + + try { + fs.writeFileSync("./.env", env, { encoding: "utf-8" }); + consola.success("Exported ci env to .env"); + } catch (error) { + consola.error("Couldn't export the ci env"); + } + +}); + From 71c4caae8ba67e253d893409b3c5c3a39b08060a Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 17:55:41 +0100 Subject: [PATCH 13/24] Removed bs console.log ref #118 --- src/tests/contacts/contact_update.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tests/contacts/contact_update.spec.ts b/src/tests/contacts/contact_update.spec.ts index 3132cbc..52fe57c 100644 --- a/src/tests/contacts/contact_update.spec.ts +++ b/src/tests/contacts/contact_update.spec.ts @@ -111,7 +111,6 @@ describe('Update contact group after adding (should work)', () => { "lastname": "last", "groups": added_team.id }, axios_config); - console.log(res.data) expect(res.status).toEqual(200); expect(res.headers['content-type']).toContain("application/json"); expect(res.data).toEqual({ From c43334bf96901bfd5116301ff7cf4b2ae1dfcbd3 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 18:07:42 +0100 Subject: [PATCH 14/24] The auth tests now use mail to identify the user ref #118 --- src/tests/auth/auth_reset.spec.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tests/auth/auth_reset.spec.ts b/src/tests/auth/auth_reset.spec.ts index 8a78a83..498b66d 100644 --- a/src/tests/auth/auth_reset.spec.ts +++ b/src/tests/auth/auth_reset.spec.ts @@ -15,7 +15,7 @@ beforeAll(async () => { "lastname": "demo_reset", "username": "demo_reset", "password": "demo_reset", - "email": "demo_reset@dev.lauf-fuer-kaya.de" + "email": "demo_reset1@dev.lauf-fuer-kaya.de" }, { headers: { "authorization": "Bearer " + res_login.data["access_token"] }, validateStatus: undefined @@ -26,7 +26,7 @@ beforeAll(async () => { "lastname": "demo_reset2", "username": "demo_reset2", "password": "demo_reset2", - "email": "demo_reset1@dev.lauf-fuer-kaya.de" + "email": "demo_reset2@dev.lauf-fuer-kaya.de" }, { headers: { "authorization": "Bearer " + res_login.data["access_token"] }, validateStatus: undefined @@ -36,7 +36,7 @@ beforeAll(async () => { describe('POST /api/auth/reset valid', () => { let reset_token; it('valid reset token request should return 200', async () => { - const res1 = await axios.post(base + '/api/auth/reset', { username: "demo_reset" }); + const res1 = await axios.post(base + '/api/auth/reset', { email: "demo_reset1@dev.lauf-fuer-kaya.de" }); reset_token = res1.data.resetToken; expect(res1.status).toEqual(200); }); @@ -44,8 +44,8 @@ describe('POST /api/auth/reset valid', () => { // --------------- describe('POST /api/auth/reset invalid requests', () => { it('request another password reset before the timeout should return 406', async () => { - const res1 = await axios.post(base + '/api/auth/reset', { username: "demo_reset2" }, axios_config); - const res2 = await axios.post(base + '/api/auth/reset', { username: "demo_reset2" }, axios_config); + const res1 = await axios.post(base + '/api/auth/reset', { email: "demo_reset2@dev.lauf-fuer-kaya.de" }, axios_config); + const res2 = await axios.post(base + '/api/auth/reset', { email: "demo_reset2@dev.lauf-fuer-kaya.de" }, axios_config); expect(res2.status).toEqual(406); }); }); @@ -55,9 +55,9 @@ describe('POST /api/auth/reset invalid token', () => { const res2 = await axios.post(base + '/api/auth/reset/' + "123123", { password: "demo" }, axios_config); expect(res2.status).toEqual(401); }); - it('providing no reset token should return 404', async () => { + it('providing no reset token should return 400', async () => { const res2 = await axios.post(base + '/api/auth/reset/' + "", { password: "demo" }, axios_config); - expect(res2.status).toEqual(404); + expect(res2.status).toEqual(400); }); }); // --------------- From 979d36ea9147dc575e9e989f6833388828285176 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 18:07:56 +0100 Subject: [PATCH 15/24] Password reset now enforces email ref #118 --- src/models/actions/create/CreateResetToken.ts | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/models/actions/create/CreateResetToken.ts b/src/models/actions/create/CreateResetToken.ts index 81f430a..8194fe4 100644 --- a/src/models/actions/create/CreateResetToken.ts +++ b/src/models/actions/create/CreateResetToken.ts @@ -1,39 +1,33 @@ -import { IsEmail, IsOptional, IsString } from 'class-validator'; +import { IsEmail, IsNotEmpty, IsString } from 'class-validator'; import { getConnectionManager } from 'typeorm'; import { ResetAlreadyRequestedError, UserDisabledError, UserNotFoundError } from '../../../errors/AuthError'; -import { UsernameOrEmailNeededError } from '../../../errors/UserErrors'; +import { UserEmailNeededError } from '../../../errors/UserErrors'; import { JwtCreator } from '../../../jwtcreator'; import { User } from '../../entities/User'; /** - * This calss is used to create password reset tokens for users. + * This class is used to create password reset tokens for users. * These password reset token can be used to set a new password for the user for the next 15mins. */ export class CreateResetToken { - /** - * The username of the user that wants to reset their password. - */ - @IsOptional() - @IsString() - username?: string; /** * The email address of the user that wants to reset their password. */ - @IsOptional() + @IsNotEmpty() @IsEmail() @IsString() - email?: string; + email: string; /** * Create a password reset token based on this. */ public async toResetToken(): Promise { - if (this.email === undefined && this.username === undefined) { - throw new UsernameOrEmailNeededError(); + if (!this.email) { + throw new UserEmailNeededError(); } - let found_user = await getConnectionManager().get().getRepository(User).findOne({ where: [{ username: this.username }, { email: this.email }] }); + let found_user = await getConnectionManager().get().getRepository(User).findOne({ where: [{ email: this.email }] }); if (!found_user) { throw new UserNotFoundError(); } if (found_user.enabled == false) { throw new UserDisabledError(); } if (found_user.resetRequestedTimestamp > (Math.floor(Date.now() / 1000) - 15 * 60)) { throw new ResetAlreadyRequestedError(); } From c116338cd74cf726362f8fa0ae5eea7ec9fabac4 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 18:09:00 +0100 Subject: [PATCH 16/24] Added pw reset template provided by @philipp ref #118 --- .../mail_templates/pw-reset-template.html | 384 ++++++++++++++++++ 1 file changed, 384 insertions(+) create mode 100644 src/static/docs/mail_templates/pw-reset-template.html diff --git a/src/static/docs/mail_templates/pw-reset-template.html b/src/static/docs/mail_templates/pw-reset-template.html new file mode 100644 index 0000000..b110247 --- /dev/null +++ b/src/static/docs/mail_templates/pw-reset-template.html @@ -0,0 +1,384 @@ + + + + + LfK! - Passwort zurücksetzen + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ LfK! - Passwort zurücksetzen +
+ + + + +
+ + \ No newline at end of file From fb77f4d798550fdb6fe6b2c8a81198db0328f71e Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 18:09:27 +0100 Subject: [PATCH 17/24] Renamed the template ref #118 --- .../docs/mail_templates/{pw-reset-template.html => pw-reset.html} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/static/docs/mail_templates/{pw-reset-template.html => pw-reset.html} (100%) diff --git a/src/static/docs/mail_templates/pw-reset-template.html b/src/static/docs/mail_templates/pw-reset.html similarity index 100% rename from src/static/docs/mail_templates/pw-reset-template.html rename to src/static/docs/mail_templates/pw-reset.html From 5cade25eeb137eb5890b3fd450646acfbdff2e8b Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 18:17:52 +0100 Subject: [PATCH 18/24] Translated the pw reset mail to english ref #118 --- src/static/docs/mail_templates/pw-reset.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/static/docs/mail_templates/pw-reset.html b/src/static/docs/mail_templates/pw-reset.html index b110247..948e9cc 100644 --- a/src/static/docs/mail_templates/pw-reset.html +++ b/src/static/docs/mail_templates/pw-reset.html @@ -306,8 +306,8 @@ -

Passwort zurücksetzen

-

Es wurde eine Passwort-Reset Mail angefordert.
Solltest du dies nicht angefordert haben, ignoriere bitte diese E-Mail.
Dein Passwort ändert sich erst, wenn du auf den Link klickst und ein neues erstellst.

+

Password reset

+

A password reset for your account got requested.
If you didn't request the reset please ignore this mail.
Your password won't be changed until you click the reset link below and set a new one.

@@ -317,7 +317,7 @@
- Passwort zurücksetzen + Reset password
@@ -342,14 +342,14 @@ - Copyright © {{copyright_owner}}. Alle Rechte vorbehalten. + Copyright © {{copyright_owner}}. All rights reserved. Impressum     - Datenschutz + style="color: #9199A1; text-decoration: underline;">Imprint     + Privacy @@ -365,7 +365,7 @@ - this mail was sent to {{recipient_mail}} + This mail was sent to {{recipient_mail}} because someone request a password reset for a account linked to the mail address. From b4c117b7dc326d212598b6e720d0a422134e383d Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 18:31:17 +0100 Subject: [PATCH 19/24] Fixed wrong file location ref #118 --- src/static/docs/mail_templates/.gitkeep | 0 src/static/{docs => }/mail_templates/pw-reset.html | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/static/docs/mail_templates/.gitkeep rename src/static/{docs => }/mail_templates/pw-reset.html (100%) diff --git a/src/static/docs/mail_templates/.gitkeep b/src/static/docs/mail_templates/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/static/docs/mail_templates/pw-reset.html b/src/static/mail_templates/pw-reset.html similarity index 100% rename from src/static/docs/mail_templates/pw-reset.html rename to src/static/mail_templates/pw-reset.html From 46af7865165bbfb97ed3e6cdfef15dfb72add611 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 18:31:34 +0100 Subject: [PATCH 20/24] Fixed missing app_url protocol ref #118 --- src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.ts b/src/config.ts index 4bd6b31..d2840da 100644 --- a/src/config.ts +++ b/src/config.ts @@ -11,7 +11,7 @@ export const config = { postalcode_validation_countrycode: getPostalCodeLocale(), version: process.env.VERSION || require('../package.json').version, seedTestData: getDataSeeding(), - app_url: process.env.APP_URL || "localhost", + app_url: process.env.APP_URL || "http://localhost:4010", mail_server: process.env.MAIL_SERVER, mail_port: Number(process.env.MAIL_PORT) || 25, mail_user: process.env.MAIL_USER, From 389e423850d68a5fe440b62413a6c662353ac9c6 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 18:41:21 +0100 Subject: [PATCH 21/24] Cleaned up the replacements ref #118 --- src/mailer.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mailer.ts b/src/mailer.ts index a7d8e6e..80c22f5 100644 --- a/src/mailer.ts +++ b/src/mailer.ts @@ -1,3 +1,4 @@ +import fs from "fs"; import nodemailer from 'nodemailer'; import { MailOptions } from 'nodemailer/lib/json-transport'; import Mail from 'nodemailer/lib/mailer'; @@ -28,10 +29,14 @@ export class Mailer { public async sendResetMail(to_address: string, token: String) { const reset_link = `${config.app_url}/reset/${token}` + let body = fs.readFileSync(__dirname + '/static/mail_templates/pw-reset.html', { encoding: 'utf8' }); + + body = body.replace("{{reset_link}}", reset_link).replace("{{recipient_mail}}", to_address).replace("{{copyright_owner}}", "LfK!").replace("{{link_imprint}}", `${config.app_url}/imprint`).replace("{{link_privacy}}", `${config.app_url}/privacy`); + const mail: MailOptions = { to: to_address, subject: "LfK! Password Reset", - html: `${reset_link}` + html: body }; await this.sendMail(mail); } From d3647e339990d989dbca4d91aa8c3fe5789dd24a Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 18:41:50 +0100 Subject: [PATCH 22/24] Added a txt variant of the pw-reset mail ref #118 --- src/static/mail_templates/pw-reset.html | 6 +++--- src/static/mail_templates/pw-reset.txt | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 src/static/mail_templates/pw-reset.txt diff --git a/src/static/mail_templates/pw-reset.html b/src/static/mail_templates/pw-reset.html index 948e9cc..7f672b8 100644 --- a/src/static/mail_templates/pw-reset.html +++ b/src/static/mail_templates/pw-reset.html @@ -285,7 +285,7 @@
- LfK! - Passwort zurücksetzen + LfK! - Password reset
@@ -347,9 +347,9 @@ - Imprint     - Privacy + Privacy diff --git a/src/static/mail_templates/pw-reset.txt b/src/static/mail_templates/pw-reset.txt new file mode 100644 index 0000000..68366b7 --- /dev/null +++ b/src/static/mail_templates/pw-reset.txt @@ -0,0 +1,12 @@ +LfK! - Password reset. + +A password reset for your account got requested +If you didn't request the reset please ignore this mail +Your password won't be changed until you click the reset link below and set a new one. + +Reset: {{reset_link}} + + +Copyright © {{copyright_owner}}. All rights reserved. +Imprint: {{link_imprint}} | Privacy: {{link_privacy}} +This mail was sent to {{recipient_mail}} because someone request a password reset for a account linked to the mail address. \ No newline at end of file From b92f633d68604636cecc5e9fdd0d6990b9cb83fe Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 26 Jan 2021 18:45:19 +0100 Subject: [PATCH 23/24] Now also sending txt mail body ref #118 --- src/mailer.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mailer.ts b/src/mailer.ts index 80c22f5..bc2281d 100644 --- a/src/mailer.ts +++ b/src/mailer.ts @@ -29,14 +29,14 @@ export class Mailer { public async sendResetMail(to_address: string, token: String) { const reset_link = `${config.app_url}/reset/${token}` - let body = fs.readFileSync(__dirname + '/static/mail_templates/pw-reset.html', { encoding: 'utf8' }); - - body = body.replace("{{reset_link}}", reset_link).replace("{{recipient_mail}}", to_address).replace("{{copyright_owner}}", "LfK!").replace("{{link_imprint}}", `${config.app_url}/imprint`).replace("{{link_privacy}}", `${config.app_url}/privacy`); + const body_html = fs.readFileSync(__dirname + '/static/mail_templates/pw-reset.html', { encoding: 'utf8' }).replace("{{reset_link}}", reset_link).replace("{{recipient_mail}}", to_address).replace("{{copyright_owner}}", "LfK!").replace("{{link_imprint}}", `${config.app_url}/imprint`).replace("{{link_privacy}}", `${config.app_url}/privacy`); + const body_txt = fs.readFileSync(__dirname + '/static/mail_templates/pw-reset.html', { encoding: 'utf8' }).replace("{{reset_link}}", reset_link).replace("{{recipient_mail}}", to_address).replace("{{copyright_owner}}", "LfK!").replace("{{link_imprint}}", `${config.app_url}/imprint`).replace("{{link_privacy}}", `${config.app_url}/privacy`); const mail: MailOptions = { to: to_address, subject: "LfK! Password Reset", - html: body + text: body_txt, + html: body_html }; await this.sendMail(mail); } From 08e6e5965544906f5033f2080166bddc37cc30c7 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 27 Jan 2021 12:06:00 +0100 Subject: [PATCH 24/24] Removed the duplicate env copy/create from ci tests ref #124 --- .drone.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 204f6c3..db1b1e7 100644 --- a/.drone.yml +++ b/.drone.yml @@ -9,7 +9,6 @@ steps: commands: - git clone $DRONE_REMOTE_URL . - git checkout $DRONE_SOURCE_BRANCH - - mv .env.ci .env - name: run tests image: node:latest commands: