From 4c19356188542ab8403597dc3c3c62f7f6e85e68 Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Sat, 1 Mar 2025 22:34:38 +0100 Subject: [PATCH] verfication email & new auth domain --- bizmatch-server/src/mail/mail.controller.ts | 12 +- bizmatch-server/src/mail/mail.module.ts | 32 +-- bizmatch-server/src/mail/mail.service.ts | 60 +++++ .../src/mail/templates/email-verification.hbs | 249 ++++++++++++++++++ bizmatch/src/app/services/auth.service.ts | 16 +- bizmatch/src/app/services/mail.service.ts | 30 ++- bizmatch/src/environments/environment.base.ts | 3 +- 7 files changed, 367 insertions(+), 35 deletions(-) create mode 100644 bizmatch-server/src/mail/templates/email-verification.hbs diff --git a/bizmatch-server/src/mail/mail.controller.ts b/bizmatch-server/src/mail/mail.controller.ts index 570f4ab..887d0c4 100644 --- a/bizmatch-server/src/mail/mail.controller.ts +++ b/bizmatch-server/src/mail/mail.controller.ts @@ -18,7 +18,17 @@ export class MailController { return await this.mailService.sendRequest(mailInfo); } } - + @Post('verify-email') + async sendVerificationEmail(@Body() data: { + email: string, + redirectConfig: { + protocol: string, + hostname: string, + port?: number + } + }): Promise { + return await this.mailService.sendVerificationEmail(data.email, data.redirectConfig); + } @UseGuards(OptionalAuthGuard) @Post('subscriptionConfirmation') async sendSubscriptionConfirmation(@Body() user: User): Promise { diff --git a/bizmatch-server/src/mail/mail.module.ts b/bizmatch-server/src/mail/mail.module.ts index 3a6c135..d9c420d 100644 --- a/bizmatch-server/src/mail/mail.module.ts +++ b/bizmatch-server/src/mail/mail.module.ts @@ -11,8 +11,6 @@ import { UserModule } from '../user/user.module'; import { UserService } from '../user/user.service'; import { MailController } from './mail.controller'; import { MailService } from './mail.service'; -// const __filename = fileURLToPath(import.meta.url); -// const __dirname = path.dirname(__filename); @Module({ imports: [ @@ -20,32 +18,6 @@ import { MailService } from './mail.service'; UserModule, GeoModule, FirebaseAdminModule, - // ConfigModule.forFeature(mailConfig), - // MailerModule.forRoot({ - // transport: { - // host: 'email-smtp.us-east-2.amazonaws.com', - // secure: false, - // port: 587, - // auth: { - // user: user, //'AKIAU6GDWVAQ2QNFLNWN', - // pass: password, //'BDE9nZv/ARbpotim1mIOir52WgIbpSi9cv1oJoH8oEf7', - // }, - // }, - // defaults: { - // from: '"No Reply" ', - // }, - // template: { - // dir: join(__dirname, 'templates'), - // adapter: new HandlebarsAdapter({ - // eq: function (a, b) { - // return a === b; - // }, - // }), - // options: { - // strict: true, - // }, - // }, - // }), MailerModule.forRootAsync({ useFactory: () => ({ transport: { @@ -53,8 +25,8 @@ import { MailService } from './mail.service'; secure: false, port: 587, auth: { - user: process.env.AMAZON_USER, //'AKIAU6GDWVAQ2QNFLNWN', - pass: process.env.AMAZON_PASSWORD, //'BDE9nZv/ARbpotim1mIOir52WgIbpSi9cv1oJoH8oEf7', + user: process.env.AMAZON_USER, + pass: process.env.AMAZON_PASSWORD, }, }, defaults: { diff --git a/bizmatch-server/src/mail/mail.service.ts b/bizmatch-server/src/mail/mail.service.ts index 2903515..106e949 100644 --- a/bizmatch-server/src/mail/mail.service.ts +++ b/bizmatch-server/src/mail/mail.service.ts @@ -1,5 +1,6 @@ import { MailerService } from '@nestjs-modules/mailer'; import { BadRequestException, Injectable } from '@nestjs/common'; +import { getAuth } from 'firebase-admin/auth'; import { join } from 'path'; import { ZodError } from 'zod'; import { SenderSchema, ShareByEMail, ShareByEMailSchema, User } from '../models/db.model'; @@ -52,6 +53,65 @@ export class MailService { }, }); } + async sendVerificationEmail( + email: string, + redirectConfig: { protocol: string, hostname: string, port?: number } + ): Promise { + try { + // Firebase Auth-Instanz holen + const auth = getAuth(); + + // Baue den Redirect-URL aus den übergebenen Parametern + let continueUrl = `${redirectConfig.protocol}://${redirectConfig.hostname}`; + if (redirectConfig.port) { + continueUrl += `:${redirectConfig.port}`; + } + continueUrl += '/auth/verify-email-success'; // Beispiel für einen Weiterleitungspfad + + // Custom Verification Link generieren + const firebaseActionLink = await auth.generateEmailVerificationLink(email, { + url: continueUrl, + handleCodeInApp: false, + }); + + // Extrahiere den oobCode aus dem Firebase Link + const actionLinkUrl = new URL(firebaseActionLink); + const oobCode = actionLinkUrl.searchParams.get('oobCode'); + + if (!oobCode) { + throw new BadRequestException('Failed to generate verification code'); + } + + // Erstelle die benutzerdefinierte URL mit dem oobCode + let customActionLink = `${redirectConfig.protocol}://${redirectConfig.hostname}`; + if (redirectConfig.port) { + customActionLink += `:${redirectConfig.port}`; + } + + // Ersetze die Platzhalter mit den tatsächlichen Werten + customActionLink += `/email-authorized?email=${encodeURIComponent(email)}&mode=verifyEmail&oobCode=${oobCode}`; + + // Zufallszahl für die E-Mail generieren + const randomNumber = Math.floor(Math.random() * 10000); + + // E-Mail senden + await this.mailerService.sendMail({ + to: email, + from: '"Bizmatch Team" ', + subject: 'Verify your email address', + template: join(__dirname, '../..', 'mail/templates/email-verification.hbs'), + context: { + actionLink: customActionLink, + randomNumber: randomNumber + }, + }); + + return; + } catch (error) { + console.error('Error sending verification email:', error); + throw new BadRequestException('Failed to send verification email'); + } + } async sendRequest(mailInfo: MailInfo): Promise { try { SenderSchema.parse(mailInfo.sender); diff --git a/bizmatch-server/src/mail/templates/email-verification.hbs b/bizmatch-server/src/mail/templates/email-verification.hbs new file mode 100644 index 0000000..bd35996 --- /dev/null +++ b/bizmatch-server/src/mail/templates/email-verification.hbs @@ -0,0 +1,249 @@ + + + + + + + + + Email address verification + + + + + + + + + + + +
+
+ Hello, click on the button below to verify your email address +
+ +
+ + + \ No newline at end of file diff --git a/bizmatch/src/app/services/auth.service.ts b/bizmatch/src/app/services/auth.service.ts index 89b548f..56d7cb5 100644 --- a/bizmatch/src/app/services/auth.service.ts +++ b/bizmatch/src/app/services/auth.service.ts @@ -2,9 +2,10 @@ import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { Injectable, inject } from '@angular/core'; import { FirebaseApp } from '@angular/fire/app'; -import { GoogleAuthProvider, UserCredential, createUserWithEmailAndPassword, getAuth, sendEmailVerification, signInWithEmailAndPassword, signInWithPopup } from 'firebase/auth'; +import { GoogleAuthProvider, UserCredential, createUserWithEmailAndPassword, getAuth, signInWithEmailAndPassword, signInWithPopup } from 'firebase/auth'; import { firstValueFrom } from 'rxjs'; import { environment } from '../../environments/environment'; +import { MailService } from './mail.service'; @Injectable({ providedIn: 'root', @@ -13,6 +14,7 @@ export class AuthService { private app = inject(FirebaseApp); private auth = getAuth(this.app); private http = inject(HttpClient); + private mailService = inject(MailService); // Registrierung mit Email und Passwort async registerWithEmail(email: string, password: string): Promise { @@ -41,7 +43,17 @@ async registerWithEmail(email: string, password: string): Promise { + console.log('Verification email sent successfully'); + // Erfolgsmeldung anzeigen + }, + error: (error) => { + console.error('Error sending verification email', error); + // Fehlermeldung anzeigen + } + }); } // Token, RefreshToken und ggf. photoURL speichern diff --git a/bizmatch/src/app/services/mail.service.ts b/bizmatch/src/app/services/mail.service.ts index 71617ba..b9173d2 100644 --- a/bizmatch/src/app/services/mail.service.ts +++ b/bizmatch/src/app/services/mail.service.ts @@ -1,6 +1,6 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { lastValueFrom } from 'rxjs'; +import { lastValueFrom, Observable } from 'rxjs'; import { ShareByEMail } from '../../../../bizmatch-server/src/models/db.model'; import { ErrorResponse, MailInfo } from '../../../../bizmatch-server/src/models/main.model'; import { environment } from '../../environments/environment'; @@ -18,4 +18,32 @@ export class MailService { async mailToFriend(shareByEMail: ShareByEMail): Promise { return await lastValueFrom(this.http.post(`${this.apiBaseUrl}/bizmatch/mail/send2Friend`, shareByEMail)); } + /** + * Sendet eine E-Mail-Verifizierung an die angegebene E-Mail-Adresse + * @param email Die E-Mail-Adresse des Benutzers + * @param redirectConfig Konfiguration für die Weiterleitung nach Verifizierung + * @returns Observable mit der API-Antwort + */ + sendVerificationEmail( + email: string, + redirectConfig?: { + protocol?: string, + hostname?: string, + port?: number + } + ): Observable { + // Extrahiere aktuelle URL-Informationen, wenn nicht explizit angegeben + const currentUrl = new URL(window.location.href); + + const config = { + protocol: redirectConfig?.protocol || currentUrl.protocol.replace(':', ''), + hostname: redirectConfig?.hostname || currentUrl.hostname, + port: redirectConfig?.port || (currentUrl.port ? parseInt(currentUrl.port) : undefined) + }; + + return this.http.post(`${this.apiBaseUrl}/bizmatch/mail/verify-email`, { + email, + redirectConfig: config + }); + } } diff --git a/bizmatch/src/environments/environment.base.ts b/bizmatch/src/environments/environment.base.ts index f440557..2f02d29 100644 --- a/bizmatch/src/environments/environment.base.ts +++ b/bizmatch/src/environments/environment.base.ts @@ -14,7 +14,8 @@ export const environment_base = { ipinfo_token: '7029590fb91214', firebaseConfig: { apiKey: 'AIzaSyBqVutQqdgUzwD9tKiKJrJq2Q6rD1hNdzw', - authDomain: 'bizmatch-net.firebaseapp.com', + //authDomain: 'bizmatch-net.firebaseapp.com', + authDomain: 'auth.bizmatch.net', projectId: 'bizmatch-net', storageBucket: 'bizmatch-net.firebasestorage.app', messagingSenderId: '1065122571067',