From a18d4d3cee58f8eb9dc428b051a2394bd3ece5c2 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 2 Feb 2021 15:02:34 +0000 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=A7=BENew=20changelog=20file=20versio?= =?UTF-8?q?n=20[CI=20SKIP]=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cddaeb..62b0323 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,12 @@ All notable changes to this project will be documented in this file. Dates are d #### [v0.4.2](https://git.odit.services/lfk/backend/compare/v0.4.1...v0.4.2) -- 📖New license file version [CI SKIP] [skip ci] [`74791df`](https://git.odit.services/lfk/backend/commit/74791df68b40355e1d1a1f7f5ae4f64422571dc9) +- Merge pull request 'Alpha Release 0.4.2' (#137) from dev into main [`390b36d`](https://git.odit.services/lfk/backend/commit/390b36dfd46cf8829126581bd62dd3d4ce8558fa) +- 🧾New changelog file version [CI SKIP] [skip ci] [`3b718f3`](https://git.odit.services/lfk/backend/commit/3b718f3ce58f12007b6068e5db00a00dbe1c5398) - 🧾New changelog file version [CI SKIP] [skip ci] [`f7a0ec7`](https://git.odit.services/lfk/backend/commit/f7a0ec7174521b1863a4bc58c7ff2b86cafdee66) - 🚀Bumped version to v0.4.2 [`321b20b`](https://git.odit.services/lfk/backend/commit/321b20b073b6debd605a92544779d0dfc0449f10) - Merge pull request 'Imprint&Privacy Links feature/135-imprint_and_privacy' (#136) from feature/135-imprint_and_privacy into dev [`110a847`](https://git.odit.services/lfk/backend/commit/110a84783e023407cbcf81506deb7cc204db9659) +- 📖New license file version [CI SKIP] [skip ci] [`74791df`](https://git.odit.services/lfk/backend/commit/74791df68b40355e1d1a1f7f5ae4f64422571dc9) - 🧾New changelog file version [CI SKIP] [skip ci] [`8425043`](https://git.odit.services/lfk/backend/commit/84250430996920ada15af23b68756daba8f99257) - Added new url env vars to config [`bcad691`](https://git.odit.services/lfk/backend/commit/bcad691045d00c9630bedb0936c123610b655946) - fixed license-exporter call [`74b982a`](https://git.odit.services/lfk/backend/commit/74b982afba3ec82a038c4748420920732fe32a51) From 8f0a396dd07937fb7ccfb345d1acbac86eb5d9bb Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 7 Feb 2021 13:37:01 +0100 Subject: [PATCH 2/5] Bugfix for @lfk/frontend/#43 --- src/config.ts | 2 +- src/controllers/AuthController.ts | 3 ++- src/mailer.ts | 4 ++-- src/models/actions/create/CreateResetToken.ts | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/config.ts b/src/config.ts index 2e52f56..8dbffca 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 || "http://localhost:4010", + app_url: process.env.APP_URL || "http://localhost:8080", mail_server: process.env.MAIL_SERVER, mail_port: Number(process.env.MAIL_PORT) || 25, mail_user: process.env.MAIL_USER, diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index 3545422..29511a3 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -31,6 +31,7 @@ export class AuthController { @OpenAPI({ description: 'Login with your username/email and password.
You will receive: \n * access token (use it as a bearer token) \n * refresh token (will also be sent as a cookie)' }) async login(@Body({ validate: true }) createAuth: CreateAuth, @Res() response: any) { let auth; + console.log(createAuth) try { auth = await createAuth.toAuth(); response.cookie('lfk_backend__refresh_token', auth.refresh_token, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); @@ -93,7 +94,7 @@ export class AuthController { @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) { - const reset_token: String = await passwordReset.toResetToken(); + const reset_token: string = await passwordReset.toResetToken(); await this.mailer.sendResetMail(passwordReset.email, reset_token); return new ResponseEmpty(); } diff --git a/src/mailer.ts b/src/mailer.ts index d52e540..d1f31c2 100644 --- a/src/mailer.ts +++ b/src/mailer.ts @@ -38,8 +38,8 @@ export class Mailer { * @param to_address The address the mail will be sent to. Should always get pulled from a user object. * @param token The requested password reset token - will be combined with the app_url to generate a password reset link. */ - public async sendResetMail(to_address: string, token: String) { - const reset_link = `${config.app_url}/reset/${token}` + public async sendResetMail(to_address: string, token: string) { + const reset_link = `${config.app_url}/reset/${(Buffer.from(token)).toString("base64")}` 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`); diff --git a/src/models/actions/create/CreateResetToken.ts b/src/models/actions/create/CreateResetToken.ts index 8194fe4..35f71ef 100644 --- a/src/models/actions/create/CreateResetToken.ts +++ b/src/models/actions/create/CreateResetToken.ts @@ -23,7 +23,7 @@ export class CreateResetToken { /** * Create a password reset token based on this. */ - public async toResetToken(): Promise { + public async toResetToken(): Promise { if (!this.email) { throw new UserEmailNeededError(); } @@ -37,7 +37,7 @@ export class CreateResetToken { await getConnectionManager().get().getRepository(User).save(found_user); //Create the reset token - let reset_token = JwtCreator.createReset(found_user); + let reset_token: string = JwtCreator.createReset(found_user); return reset_token; } From f3f5cb462e4ecf932ad55eb519815222b4e5dd17 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sun, 7 Feb 2021 12:38:54 +0000 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=A7=BENew=20changelog=20file=20versio?= =?UTF-8?q?n=20[CI=20SKIP]=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62b0323..768b495 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,16 @@ All notable changes to this project will be documented in this file. Dates are displayed in UTC. +#### [v0.4.2](https://git.odit.services/lfk/backend/compare/v0.4.2...v0.4.2) + +- Merge pull request 'Bugfix for @lfk/frontend/#43' (#138) from bugfix/118-encode_jwt_in_mail into dev [`9959172`](https://git.odit.services/lfk/backend/commit/9959172f2ae11cbb7a2b8e97bad432956fc70a80) +- Bugfix for @lfk/frontend/#43 [`8f0a396`](https://git.odit.services/lfk/backend/commit/8f0a396dd07937fb7ccfb345d1acbac86eb5d9bb) +- 🧾New changelog file version [CI SKIP] [skip ci] [`a18d4d3`](https://git.odit.services/lfk/backend/commit/a18d4d3cee58f8eb9dc428b051a2394bd3ece5c2) + #### [v0.4.2](https://git.odit.services/lfk/backend/compare/v0.4.1...v0.4.2) +> 2 February 2021 + - Merge pull request 'Alpha Release 0.4.2' (#137) from dev into main [`390b36d`](https://git.odit.services/lfk/backend/commit/390b36dfd46cf8829126581bd62dd3d4ce8558fa) - 🧾New changelog file version [CI SKIP] [skip ci] [`3b718f3`](https://git.odit.services/lfk/backend/commit/3b718f3ce58f12007b6068e5db00a00dbe1c5398) - 🧾New changelog file version [CI SKIP] [skip ci] [`f7a0ec7`](https://git.odit.services/lfk/backend/commit/f7a0ec7174521b1863a4bc58c7ff2b86cafdee66) From 656d564baa8c8bf1f63523b0301ad9ff23e08aa4 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 7 Feb 2021 13:40:32 +0100 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=9A=80Bumped=20version=20to=20v0.4.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/controllers/AuthController.ts | 221 +++++++++++++++--------------- 2 files changed, 111 insertions(+), 112 deletions(-) diff --git a/package.json b/package.json index aeb4303..e658fde 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@odit/lfk-backend", - "version": "0.4.2", + "version": "0.4.3", "main": "src/app.ts", "repository": "https://git.odit.services/lfk/backend", "author": { diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index 29511a3..de5ed39 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -1,111 +1,110 @@ -import { Body, CookieParam, JsonController, Param, Post, Req, Res } from 'routing-controllers'; -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") - @ResponseSchema(ResponseAuth) - @ResponseSchema(InvalidCredentialsError) - @ResponseSchema(UserNotFoundError) - @ResponseSchema(UsernameOrEmailNeededError) - @ResponseSchema(PasswordNeededError) - @ResponseSchema(InvalidCredentialsError) - @OpenAPI({ description: 'Login with your username/email and password.
You will receive: \n * access token (use it as a bearer token) \n * refresh token (will also be sent as a cookie)' }) - async login(@Body({ validate: true }) createAuth: CreateAuth, @Res() response: any) { - let auth; - console.log(createAuth) - try { - auth = await createAuth.toAuth(); - response.cookie('lfk_backend__refresh_token', auth.refresh_token, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); - response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); - return response.send(auth) - } catch (error) { - throw error; - } - } - - @Post("/logout") - @ResponseSchema(Logout) - @ResponseSchema(InvalidCredentialsError) - @ResponseSchema(UserNotFoundError) - @ResponseSchema(UsernameOrEmailNeededError) - @ResponseSchema(PasswordNeededError) - @ResponseSchema(InvalidCredentialsError) - @OpenAPI({ description: 'Logout using your refresh token.
This instantly invalidates all your access and refresh tokens.', security: [{ "RefreshTokenCookie": [] }] }) - async logout(@Body({ validate: true }) handleLogout: HandleLogout, @CookieParam("lfk_backend__refresh_token") refresh_token: string, @Res() response: any) { - if (refresh_token && refresh_token.length != 0 && handleLogout.token == undefined) { - handleLogout.token = refresh_token; - } - - let logout; - try { - logout = await handleLogout.logout() - await response.cookie('lfk_backend__refresh_token', "expired", { expires: new Date(Date.now()), httpOnly: true }); - response.cookie('lfk_backend__refresh_token_expires_at', "expired", { expires: new Date(Date.now()), httpOnly: true }); - } catch (error) { - throw error; - } - return response.send(logout) - } - - @Post("/refresh") - @ResponseSchema(ResponseAuth) - @ResponseSchema(JwtNotProvidedError) - @ResponseSchema(IllegalJWTError) - @ResponseSchema(UserNotFoundError) - @ResponseSchema(RefreshTokenCountInvalidError) - @OpenAPI({ description: 'Refresh your access and refresh tokens using a valid refresh token.
You will receive: \n * access token (use it as a bearer token) \n * refresh token (will also be sent as a cookie)', security: [{ "RefreshTokenCookie": [] }] }) - async refresh(@Body({ validate: true }) refreshAuth: RefreshAuth, @CookieParam("lfk_backend__refresh_token") refresh_token: string, @Res() response: any, @Req() req: any) { - if (refresh_token && refresh_token.length != 0 && refreshAuth.token == undefined) { - refreshAuth.token = refresh_token; - } - let auth; - try { - auth = await refreshAuth.toAuth(); - response.cookie('lfk_backend__refresh_token', auth.refresh_token, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); - response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); - } catch (error) { - throw error; - } - return response.send(auth) - } - - @Post("/reset") - @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) { - const reset_token: string = await passwordReset.toResetToken(); - await this.mailer.sendResetMail(passwordReset.email, reset_token); - return new ResponseEmpty(); - } - - @Post("/reset/:token") - @ResponseSchema(ResponseAuth) - @ResponseSchema(UserNotFoundError) - @ResponseSchema(UsernameOrEmailNeededError) - @OpenAPI({ description: "Reset a user's utilising a valid password reset token.
This will set the user's password to the one you provided in the body.
To get a reset token post to /api/auth/reset with your username." }) - async resetPassword(@Param("token") token: string, @Body({ validate: true }) passwordReset: ResetPassword) { - passwordReset.resetToken = token; - return await passwordReset.resetPassword(); - } -} +import { Body, CookieParam, JsonController, Param, Post, Req, Res } from 'routing-controllers'; +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") + @ResponseSchema(ResponseAuth) + @ResponseSchema(InvalidCredentialsError) + @ResponseSchema(UserNotFoundError) + @ResponseSchema(UsernameOrEmailNeededError) + @ResponseSchema(PasswordNeededError) + @ResponseSchema(InvalidCredentialsError) + @OpenAPI({ description: 'Login with your username/email and password.
You will receive: \n * access token (use it as a bearer token) \n * refresh token (will also be sent as a cookie)' }) + async login(@Body({ validate: true }) createAuth: CreateAuth, @Res() response: any) { + let auth; + try { + auth = await createAuth.toAuth(); + response.cookie('lfk_backend__refresh_token', auth.refresh_token, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); + response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); + return response.send(auth) + } catch (error) { + throw error; + } + } + + @Post("/logout") + @ResponseSchema(Logout) + @ResponseSchema(InvalidCredentialsError) + @ResponseSchema(UserNotFoundError) + @ResponseSchema(UsernameOrEmailNeededError) + @ResponseSchema(PasswordNeededError) + @ResponseSchema(InvalidCredentialsError) + @OpenAPI({ description: 'Logout using your refresh token.
This instantly invalidates all your access and refresh tokens.', security: [{ "RefreshTokenCookie": [] }] }) + async logout(@Body({ validate: true }) handleLogout: HandleLogout, @CookieParam("lfk_backend__refresh_token") refresh_token: string, @Res() response: any) { + if (refresh_token && refresh_token.length != 0 && handleLogout.token == undefined) { + handleLogout.token = refresh_token; + } + + let logout; + try { + logout = await handleLogout.logout() + await response.cookie('lfk_backend__refresh_token', "expired", { expires: new Date(Date.now()), httpOnly: true }); + response.cookie('lfk_backend__refresh_token_expires_at', "expired", { expires: new Date(Date.now()), httpOnly: true }); + } catch (error) { + throw error; + } + return response.send(logout) + } + + @Post("/refresh") + @ResponseSchema(ResponseAuth) + @ResponseSchema(JwtNotProvidedError) + @ResponseSchema(IllegalJWTError) + @ResponseSchema(UserNotFoundError) + @ResponseSchema(RefreshTokenCountInvalidError) + @OpenAPI({ description: 'Refresh your access and refresh tokens using a valid refresh token.
You will receive: \n * access token (use it as a bearer token) \n * refresh token (will also be sent as a cookie)', security: [{ "RefreshTokenCookie": [] }] }) + async refresh(@Body({ validate: true }) refreshAuth: RefreshAuth, @CookieParam("lfk_backend__refresh_token") refresh_token: string, @Res() response: any, @Req() req: any) { + if (refresh_token && refresh_token.length != 0 && refreshAuth.token == undefined) { + refreshAuth.token = refresh_token; + } + let auth; + try { + auth = await refreshAuth.toAuth(); + response.cookie('lfk_backend__refresh_token', auth.refresh_token, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); + response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); + } catch (error) { + throw error; + } + return response.send(auth) + } + + @Post("/reset") + @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) { + const reset_token: string = await passwordReset.toResetToken(); + await this.mailer.sendResetMail(passwordReset.email, reset_token); + return new ResponseEmpty(); + } + + @Post("/reset/:token") + @ResponseSchema(ResponseAuth) + @ResponseSchema(UserNotFoundError) + @ResponseSchema(UsernameOrEmailNeededError) + @OpenAPI({ description: "Reset a user's utilising a valid password reset token.
This will set the user's password to the one you provided in the body.
To get a reset token post to /api/auth/reset with your username." }) + async resetPassword(@Param("token") token: string, @Body({ validate: true }) passwordReset: ResetPassword) { + passwordReset.resetToken = token; + return await passwordReset.resetPassword(); + } +} From 23c732b6905cc9f6479a53a7744b72d01e345ecb Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 7 Feb 2021 12:40:54 +0000 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=A7=BENew=20changelog=20file=20versio?= =?UTF-8?q?n=20[CI=20SKIP]=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 768b495..a287c4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,10 @@ All notable changes to this project will be documented in this file. Dates are displayed in UTC. -#### [v0.4.2](https://git.odit.services/lfk/backend/compare/v0.4.2...v0.4.2) +#### [v0.4.3](https://git.odit.services/lfk/backend/compare/v0.4.2...v0.4.3) +- 🚀Bumped version to v0.4.3 [`656d564`](https://git.odit.services/lfk/backend/commit/656d564baa8c8bf1f63523b0301ad9ff23e08aa4) +- 🧾New changelog file version [CI SKIP] [skip ci] [`f3f5cb4`](https://git.odit.services/lfk/backend/commit/f3f5cb462e4ecf932ad55eb519815222b4e5dd17) - Merge pull request 'Bugfix for @lfk/frontend/#43' (#138) from bugfix/118-encode_jwt_in_mail into dev [`9959172`](https://git.odit.services/lfk/backend/commit/9959172f2ae11cbb7a2b8e97bad432956fc70a80) - Bugfix for @lfk/frontend/#43 [`8f0a396`](https://git.odit.services/lfk/backend/commit/8f0a396dd07937fb7ccfb345d1acbac86eb5d9bb) - 🧾New changelog file version [CI SKIP] [skip ci] [`a18d4d3`](https://git.odit.services/lfk/backend/commit/a18d4d3cee58f8eb9dc428b051a2394bd3ece5c2)