diff --git a/commafeed-server/TODO.md b/commafeed-server/TODO.md
index 192376e1..6c77457f 100644
--- a/commafeed-server/TODO.md
+++ b/commafeed-server/TODO.md
@@ -3,10 +3,9 @@ TODO
MVP:
-- quarkus mailer for smtp
- - https://quarkus.io/guides/mailer
- cookie duration too short
- https://github.com/quarkusio/quarkus/issues/42463
+ - Rewrite cookie with https://quarkus.io/guides/rest#request-or-response-filters in the mean time
- mvn profile instead of -Dquarkus.datasource.db-kind
- update github actions
diff --git a/commafeed-server/pom.xml b/commafeed-server/pom.xml
index 4ab11efd..e01adf79 100644
--- a/commafeed-server/pom.xml
+++ b/commafeed-server/pom.xml
@@ -255,6 +255,10 @@
io.quarkus
quarkus-websockets
+
+ io.quarkus
+ quarkus-mailer
+
io.quarkus
quarkus-hibernate-orm
@@ -331,16 +335,11 @@
passay
1.6.4
-
redis.clients
jedis
5.1.4
-
- com.sun.mail
- jakarta.mail
-
com.rometools
@@ -456,12 +455,6 @@
rest-assured
test
-
- com.icegreen
- greenmail-junit5
- 2.0.1
- test
-
org.awaitility
awaitility
diff --git a/commafeed-server/src/main/java/com/commafeed/CommaFeedConfiguration.java b/commafeed-server/src/main/java/com/commafeed/CommaFeedConfiguration.java
index eb64073f..d1b92360 100644
--- a/commafeed-server/src/main/java/com/commafeed/CommaFeedConfiguration.java
+++ b/commafeed-server/src/main/java/com/commafeed/CommaFeedConfiguration.java
@@ -49,6 +49,14 @@ public interface CommaFeedConfiguration {
@WithDefault("false")
boolean imageProxyEnabled();
+ /**
+ * Enable password recovery via email.
+ *
+ * Quarkus mailer will need to be configured.
+ */
+ @WithDefault("false")
+ boolean passwordRecoveryEnabled();
+
/**
* Message displayed in a notification at the bottom of the page.
*/
@@ -84,11 +92,6 @@ public interface CommaFeedConfiguration {
*/
Websocket websocket();
- /**
- * SMTP settings for password recovery.
- */
- Optional smtp();
-
/**
* Redis settings to enable caching. This is only really useful on instances with a lot of users.
*/
@@ -207,20 +210,6 @@ public interface CommaFeedConfiguration {
boolean createDemoAccount();
}
- interface Smtp {
- String host();
-
- int port();
-
- boolean tls();
-
- String userName();
-
- String password();
-
- String fromAddress();
- }
-
interface Websocket {
/**
* Enable websocket connection so the server can notify the web client that there are new entries for your feeds.
diff --git a/commafeed-server/src/main/java/com/commafeed/backend/service/MailService.java b/commafeed-server/src/main/java/com/commafeed/backend/service/MailService.java
index 758945aa..cef02d1f 100644
--- a/commafeed-server/src/main/java/com/commafeed/backend/service/MailService.java
+++ b/commafeed-server/src/main/java/com/commafeed/backend/service/MailService.java
@@ -1,64 +1,20 @@
package com.commafeed.backend.service;
-import java.util.Optional;
-import java.util.Properties;
-
-import com.commafeed.CommaFeedConfiguration;
-import com.commafeed.CommaFeedConfiguration.Smtp;
import com.commafeed.backend.model.User;
+import io.quarkus.mailer.Mail;
+import io.quarkus.mailer.Mailer;
import jakarta.inject.Singleton;
-import jakarta.mail.Authenticator;
-import jakarta.mail.Message;
-import jakarta.mail.PasswordAuthentication;
-import jakarta.mail.Session;
-import jakarta.mail.Transport;
-import jakarta.mail.internet.InternetAddress;
-import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
-/**
- * Mailing service
- *
- */
@RequiredArgsConstructor
@Singleton
public class MailService {
- private final CommaFeedConfiguration config;
-
- public void sendMail(User user, String subject, String content) throws Exception {
- Optional settings = config.smtp();
- if (settings.isEmpty()) {
- throw new IllegalArgumentException("SMTP settings not configured");
- }
-
- final String username = settings.get().userName();
- final String password = settings.get().password();
- final String fromAddress = Optional.ofNullable(settings.get().fromAddress()).orElse(settings.get().userName());
-
- String dest = user.getEmail();
-
- Properties props = new Properties();
- props.put("mail.smtp.auth", "true");
- props.put("mail.smtp.starttls.enable", String.valueOf(settings.get().tls()));
- props.put("mail.smtp.host", settings.get().host());
- props.put("mail.smtp.port", String.valueOf(settings.get().port()));
-
- Session session = Session.getInstance(props, new Authenticator() {
- @Override
- protected PasswordAuthentication getPasswordAuthentication() {
- return new PasswordAuthentication(username, password);
- }
- });
-
- Message message = new MimeMessage(session);
- message.setFrom(new InternetAddress(fromAddress, "CommaFeed"));
- message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(dest));
- message.setSubject("CommaFeed - " + subject);
- message.setContent(content, "text/html; charset=utf-8");
-
- Transport.send(message);
+ private final Mailer mailer;
+ public void sendMail(User user, String subject, String content) {
+ Mail mail = Mail.withHtml(user.getEmail(), "CommaFeed - " + subject, content);
+ mailer.send(mail);
}
}
diff --git a/commafeed-server/src/main/java/com/commafeed/frontend/resource/ServerREST.java b/commafeed-server/src/main/java/com/commafeed/frontend/resource/ServerREST.java
index 881a7a04..4a6d64d7 100644
--- a/commafeed-server/src/main/java/com/commafeed/frontend/resource/ServerREST.java
+++ b/commafeed-server/src/main/java/com/commafeed/frontend/resource/ServerREST.java
@@ -56,7 +56,7 @@ public class ServerREST {
infos.setGitCommit(version.getGitCommit());
infos.setAllowRegistrations(config.users().allowRegistrations());
infos.setGoogleAnalyticsCode(config.googleAnalyticsTrackingCode().orElse(null));
- infos.setSmtpEnabled(config.smtp().isPresent());
+ infos.setSmtpEnabled(config.passwordRecoveryEnabled());
infos.setDemoAccountEnabled(config.users().createDemoAccount());
infos.setWebsocketEnabled(config.websocket().enabled());
infos.setWebsocketPingInterval(config.websocket().pingInterval().toMillis());
diff --git a/commafeed-server/src/main/java/com/commafeed/frontend/resource/UserREST.java b/commafeed-server/src/main/java/com/commafeed/frontend/resource/UserREST.java
index b391631f..0162c089 100644
--- a/commafeed-server/src/main/java/com/commafeed/frontend/resource/UserREST.java
+++ b/commafeed-server/src/main/java/com/commafeed/frontend/resource/UserREST.java
@@ -267,6 +267,10 @@ public class UserREST {
@Transactional
@Operation(summary = "send a password reset email")
public Response sendPasswordReset(@Valid @Parameter(required = true) PasswordResetRequest req) {
+ if (!config.passwordRecoveryEnabled()) {
+ throw new IllegalArgumentException("Password recovery is not enabled on this CommaFeed instance");
+ }
+
User user = userDAO.findByEmail(req.getEmail());
if (user == null) {
return Response.ok().build();
diff --git a/commafeed-server/src/main/java/com/commafeed/frontend/servlet/LogoutServlet.java b/commafeed-server/src/main/java/com/commafeed/frontend/servlet/LogoutServlet.java
index 09a7b426..592074b4 100644
--- a/commafeed-server/src/main/java/com/commafeed/frontend/servlet/LogoutServlet.java
+++ b/commafeed-server/src/main/java/com/commafeed/frontend/servlet/LogoutServlet.java
@@ -14,18 +14,19 @@ import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.NewCookie;
import jakarta.ws.rs.core.Response;
-import lombok.RequiredArgsConstructor;
@Path("/logout")
@PermitAll
-@RequiredArgsConstructor
@Singleton
public class LogoutServlet {
- @ConfigProperty(name = "quarkus.http.auth.form.cookie-name")
- String cookieName;
-
private final CommaFeedConfiguration config;
+ private final String cookieName;
+
+ public LogoutServlet(CommaFeedConfiguration config, @ConfigProperty(name = "quarkus.http.auth.form.cookie-name") String cookieName) {
+ this.config = config;
+ this.cookieName = cookieName;
+ }
@GET
public Response get() {
diff --git a/commafeed-server/src/main/resources/application.properties b/commafeed-server/src/main/resources/application.properties
index 82a33f85..c8301671 100644
--- a/commafeed-server/src/main/resources/application.properties
+++ b/commafeed-server/src/main/resources/application.properties
@@ -35,12 +35,7 @@ quarkus.shutdown.timeout=5s
%test.quarkus.log.category."liquibase".level=WARN
%test.commafeed.users.create-demo-account=true
%test.commafeed.users.allow-registrations=true
-%test.commafeed.smtp.host=localhost
-%test.commafeed.smtp.port=3025
-%test.commafeed.smtp.tls=false
-%test.commafeed.smtp.user-name=user
-%test.commafeed.smtp.password=pass
-%test.commafeed.smtp.from-address=noreply@commafeed.com
+%test.commafeed.password-recovery-enabled=true
# prod profile overrides
diff --git a/commafeed-server/src/test/java/com/commafeed/integration/rest/UserIT.java b/commafeed-server/src/test/java/com/commafeed/integration/rest/UserIT.java
index ae077b1c..60f6d317 100644
--- a/commafeed-server/src/test/java/com/commafeed/integration/rest/UserIT.java
+++ b/commafeed-server/src/test/java/com/commafeed/integration/rest/UserIT.java
@@ -1,52 +1,44 @@
package com.commafeed.integration.rest;
-import org.junit.jupiter.api.AfterEach;
+import java.util.List;
+
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import com.commafeed.frontend.model.request.PasswordResetRequest;
import com.commafeed.integration.BaseIT;
-import com.icegreen.greenmail.util.GreenMail;
-import com.icegreen.greenmail.util.ServerSetupTest;
+import io.quarkus.mailer.MockMailbox;
import io.quarkus.test.junit.QuarkusTest;
-import jakarta.mail.internet.MimeMessage;
+import io.vertx.ext.mail.MailMessage;
+import jakarta.inject.Inject;
import jakarta.ws.rs.client.Entity;
@QuarkusTest
class UserIT extends BaseIT {
- @Nested
- class PasswordReset {
+ @Inject
+ MockMailbox mailbox;
- private GreenMail greenMail;
+ @BeforeEach
+ void setup() {
+ mailbox.clear();
+ }
- @BeforeEach
- void setup() {
- this.greenMail = new GreenMail(ServerSetupTest.SMTP);
- this.greenMail.start();
- this.greenMail.setUser("noreply@commafeed.com", "user", "pass");
- }
+ @Test
+ void resetPassword() {
+ PasswordResetRequest req = new PasswordResetRequest();
+ req.setEmail("admin@commafeed.com");
- @AfterEach
- void cleanup() {
- this.greenMail.stop();
- }
+ getClient().target(getApiBaseUrl() + "user/passwordReset").request().post(Entity.json(req), Void.TYPE);
- @Test
- void resetPassword() throws Exception {
- PasswordResetRequest req = new PasswordResetRequest();
- req.setEmail("admin@commafeed.com");
+ List mails = mailbox.getMailMessagesSentTo("admin@commafeed.com");
+ Assertions.assertEquals(1, mails.size());
- getClient().target(getApiBaseUrl() + "user/passwordReset").request().post(Entity.json(req), Void.TYPE);
-
- MimeMessage message = greenMail.getReceivedMessages()[0];
- Assertions.assertEquals("CommaFeed - Password recovery", message.getSubject());
- Assertions.assertTrue(message.getContent().toString().startsWith("You asked for password recovery for account 'admin'"));
- Assertions.assertEquals("CommaFeed ", message.getFrom()[0].toString());
- Assertions.assertEquals("admin@commafeed.com", message.getAllRecipients()[0].toString());
- }
+ MailMessage message = mails.get(0);
+ Assertions.assertEquals("CommaFeed - Password recovery", message.getSubject());
+ Assertions.assertTrue(message.getHtml().startsWith("You asked for password recovery for account 'admin'"));
+ Assertions.assertEquals("admin@commafeed.com", message.getTo().get(0));
}
}