diff --git a/src/main/java/net/siegeln/cameleer/saas/notification/PasswordResetNotificationService.java b/src/main/java/net/siegeln/cameleer/saas/notification/PasswordResetNotificationService.java index ba833d0..d5bb499 100644 --- a/src/main/java/net/siegeln/cameleer/saas/notification/PasswordResetNotificationService.java +++ b/src/main/java/net/siegeln/cameleer/saas/notification/PasswordResetNotificationService.java @@ -1,6 +1,7 @@ package net.siegeln.cameleer.saas.notification; import net.siegeln.cameleer.saas.identity.LogtoManagementClient; +import net.siegeln.cameleer.saas.provisioning.ProvisioningProperties; import net.siegeln.cameleer.saas.vendor.EmailConnectorService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,11 +28,14 @@ public class PasswordResetNotificationService { private final EmailConnectorService emailConnectorService; private final LogtoManagementClient logtoClient; + private final ProvisioningProperties provisioningProps; public PasswordResetNotificationService(EmailConnectorService emailConnectorService, - LogtoManagementClient logtoClient) { + LogtoManagementClient logtoClient, + ProvisioningProperties provisioningProps) { this.emailConnectorService = emailConnectorService; this.logtoClient = logtoClient; + this.provisioningProps = provisioningProps; } /** @@ -110,8 +114,12 @@ public class PasswordResetNotificationService { String content = new ClassPathResource("email-templates/password-reset-notification.html") .getContentAsString(StandardCharsets.UTF_8); + String watermarkUrl = provisioningProps.publicProtocol() + "://" + + provisioningProps.publicHost() + "/platform/assets/email-watermark.png"; String timestamp = ZonedDateTime.now(ZoneOffset.UTC).format(TIMESTAMP_FMT); - return content.replace("{{timestamp}}", timestamp); + return content + .replace("{{watermarkUrl}}", watermarkUrl) + .replace("{{timestamp}}", timestamp); } } diff --git a/src/main/java/net/siegeln/cameleer/saas/vendor/EmailConnectorService.java b/src/main/java/net/siegeln/cameleer/saas/vendor/EmailConnectorService.java index bb075a6..b8fbffa 100644 --- a/src/main/java/net/siegeln/cameleer/saas/vendor/EmailConnectorService.java +++ b/src/main/java/net/siegeln/cameleer/saas/vendor/EmailConnectorService.java @@ -1,6 +1,7 @@ package net.siegeln.cameleer.saas.vendor; import net.siegeln.cameleer.saas.identity.LogtoManagementClient; +import net.siegeln.cameleer.saas.provisioning.ProvisioningProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; @@ -19,9 +20,11 @@ public class EmailConnectorService { private static final String SMTP_FACTORY_ID = "simple-mail-transfer-protocol"; private final LogtoManagementClient logtoClient; + private final ProvisioningProperties provisioningProps; - public EmailConnectorService(LogtoManagementClient logtoClient) { + public EmailConnectorService(LogtoManagementClient logtoClient, ProvisioningProperties provisioningProps) { this.logtoClient = logtoClient; + this.provisioningProps = provisioningProps; } public record SmtpConfig(String host, int port, String username, String password, String fromEmail) {} @@ -157,11 +160,14 @@ public class EmailConnectorService { return "SignInAndRegister".equals(signInExp.get("signInMode")); } - /** Load an email template from classpath. */ + /** Load an email template from classpath and resolve the watermark URL placeholder. */ private String loadTemplate(String filename) { try { - return new ClassPathResource("email-templates/" + filename) + String content = new ClassPathResource("email-templates/" + filename) .getContentAsString(StandardCharsets.UTF_8); + String watermarkUrl = provisioningProps.publicProtocol() + "://" + + provisioningProps.publicHost() + "/platform/assets/email-watermark.png"; + return content.replace("{{watermarkUrl}}", watermarkUrl); } catch (IOException e) { throw new IllegalStateException("Failed to load email template: " + filename, e); } diff --git a/src/main/resources/email-templates/forgot-password.html b/src/main/resources/email-templates/forgot-password.html index 6f7efc0..20e558e 100644 --- a/src/main/resources/email-templates/forgot-password.html +++ b/src/main/resources/email-templates/forgot-password.html @@ -10,7 +10,9 @@ .wrapper { font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; max-width:480px; margin:0 auto; background:#fff; border-radius:8px; overflow:hidden; border:1px solid #e8e0d4; } .header { background:#C6820E; padding:20px 24px; text-align:center; } .header span { font-size:22px; font-weight:700; color:#fff; letter-spacing:0.5px; } - .content { padding:32px 24px 24px; } + .content { padding:32px 24px 24px; position:relative; overflow:hidden; } + .watermark { position:absolute; top:-30px; right:-50px; width:320px; height:320px; opacity:0.07; pointer-events:none; border:0; outline:none; } + .inner { position:relative; } .title { color:#1a1a1a; font-size:16px; font-weight:600; margin:0 0 8px; } .subtitle { color:#444; font-size:14px; line-height:1.6; margin:0 0 24px; } .code-box { text-align:center; margin:0 0 24px; } @@ -30,6 +32,8 @@ Cameleer.io
+ +

Lost in the dunes?

No worries — enter this code to reset your password and get back on the trail.

@@ -39,6 +43,7 @@

This code expires in 10 minutes. If you didn't request a password reset, you can safely ignore this email.

This password reset was requested for your Cameleer account. Cameleer is an observability platform for Apache Camel integrations providing real-time route tracing, message inspection, and performance monitoring. For security, this code can only be used once. If you continue to have trouble accessing your account, please contact your administrator for assistance.

+
+ +

Quick checkpoint

Here's your verification code. Just making sure it's really you at the reins.

@@ -39,6 +43,7 @@

This code expires in 10 minutes.

You are receiving this email because a verification was requested on your Cameleer account. Cameleer is an observability platform for Apache Camel integrations providing real-time route tracing, message inspection, and performance monitoring. If you did not request this verification, please ignore this email or contact your administrator for assistance.

+
+ +

Your password was reset

Your Cameleer account password was successfully changed on {{timestamp}}.

@@ -36,6 +40,7 @@

If this wasn't you, contact your administrator immediately.

This is an automated security notification from your Cameleer account. Cameleer is an observability platform for Apache Camel integrations providing real-time route tracing, message inspection, and performance monitoring. You are receiving this notification because a password change was completed. For your security, we recommend reviewing your account activity and ensuring your credentials are kept safe.

+
+ +

Welcome to the caravan!

Enter this code to verify your email and claim your spot. The dunes wait for no one.

@@ -39,6 +43,7 @@

This code expires in 10 minutes. If you didn't request this, you can safely ignore this email — no camels were harmed.

Cameleer is an observability platform for Apache Camel integrations. It provides real-time route tracing, message inspection, and performance monitoring to help your team debug and optimize integration flows. Your account gives you access to your dedicated Cameleer instance where you can connect your Camel applications and start monitoring immediately.

+
+ +

Back at the oasis already?

Here's your sign-in code. The caravan master is checking credentials.

@@ -39,6 +43,7 @@

This code expires in 10 minutes.

You are receiving this email because a sign-in attempt was made on your Cameleer account. Cameleer is an observability platform for Apache Camel integrations providing real-time route tracing, message inspection, and performance monitoring. If you did not initiate this sign-in, please ignore this email or contact your administrator.

+