aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/cliqset/xrd/Alias.java11
-rw-r--r--src/main/java/com/cliqset/xrd/Expires.java2
-rw-r--r--src/main/java/com/cliqset/xrd/Link.java14
-rw-r--r--src/main/java/com/cliqset/xrd/Property.java12
-rw-r--r--src/main/java/com/cliqset/xrd/Subject.java10
-rw-r--r--src/main/java/com/cliqset/xrd/Title.java2
-rw-r--r--src/main/java/com/cliqset/xrd/XRD.java6
-rw-r--r--src/main/java/com/cliqset/xrd/package-info.java6
-rw-r--r--src/main/java/com/juick/ActivityPubManager.java4
-rw-r--r--src/main/java/com/juick/EmailManager.java20
-rw-r--r--src/main/java/com/juick/TelegramBotManager.java2
-rw-r--r--src/main/java/com/juick/XMPPManager.java6
-rw-r--r--src/main/java/com/juick/config/ActivityPubClientErrorHandler.java3
-rw-r--r--src/main/java/com/juick/config/ActivityPubConfig.java3
-rw-r--r--src/main/java/com/juick/config/HttpClientConfig.java51
-rw-r--r--src/main/java/com/juick/config/SecurityConfig.java236
-rw-r--r--src/main/java/com/juick/config/WebConfig.java13
-rw-r--r--src/main/java/com/juick/model/Message.java12
-rw-r--r--src/main/java/com/juick/model/Tag.java7
-rw-r--r--src/main/java/com/juick/model/User.java10
-rw-r--r--src/main/java/com/juick/model/package-info.java6
-rw-r--r--src/main/java/com/juick/service/UserServiceImpl.java2
-rw-r--r--src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java17
-rw-r--r--src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java54
-rw-r--r--src/main/java/com/juick/util/adapters/SimpleDateAdapter.java3
-rw-r--r--src/main/java/com/juick/util/xmpp/JidConverter.java4
-rw-r--r--src/main/java/com/juick/util/xmpp/iq/MessageQuery.java2
-rw-r--r--src/main/java/com/juick/util/xmpp/iq/package-info.java8
-rw-r--r--src/main/java/com/juick/www/VaryHandler.java2
-rw-r--r--src/main/java/com/juick/www/WebApp.java7
-rw-r--r--src/main/java/com/juick/www/api/ApiSocialLogin.java2
-rw-r--r--src/main/java/com/juick/www/api/Post.java2
-rw-r--r--src/main/java/com/juick/www/api/Service.java9
-rw-r--r--src/main/java/com/juick/www/controllers/Login.java3
-rw-r--r--src/main/java/com/juick/www/controllers/Settings.java19
-rw-r--r--src/main/java/com/juick/www/controllers/Site.java4
-rw-r--r--src/main/java/com/juick/www/controllers/SocialLogin.java12
-rw-r--r--src/main/java/com/juick/www/filters/AnythingFilter.java16
-rw-r--r--src/main/java/com/juick/www/rss/MessagesView.java12
-rw-r--r--src/main/java/com/juick/www/rss/RepliesView.java14
-rw-r--r--src/main/java/com/mitchellbosecke/pebble/extension/FormatterExtension.java3
-rw-r--r--src/main/java/com/mitchellbosecke/pebble/extension/filters/FormatMessageFilter.java8
-rw-r--r--src/main/java/com/mitchellbosecke/pebble/extension/filters/PrettyTimeFilter.java6
-rw-r--r--src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java6
-rw-r--r--src/main/java/com/mitchellbosecke/pebble/extension/filters/TimestampFilter.java6
-rw-r--r--src/main/java/org/apache/commons/mail/util/MimeMessageParser.java452
46 files changed, 785 insertions, 324 deletions
diff --git a/src/main/java/com/cliqset/xrd/Alias.java b/src/main/java/com/cliqset/xrd/Alias.java
index 49e4052b..3a108f46 100644
--- a/src/main/java/com/cliqset/xrd/Alias.java
+++ b/src/main/java/com/cliqset/xrd/Alias.java
@@ -20,13 +20,14 @@ import java.net.URI;
import java.util.HashMap;
import java.util.Map;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAnyAttribute;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
import javax.xml.namespace.QName;
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAnyAttribute;
+import jakarta.xml.bind.annotation.XmlType;
+import jakarta.xml.bind.annotation.XmlValue;
+
@XmlType(name="Alias", namespace=XRDConstants.XRD_NAMESPACE)
@XmlAccessorType(XmlAccessType.FIELD)
public class Alias {
diff --git a/src/main/java/com/cliqset/xrd/Expires.java b/src/main/java/com/cliqset/xrd/Expires.java
index b4bcdd24..bb6704f8 100644
--- a/src/main/java/com/cliqset/xrd/Expires.java
+++ b/src/main/java/com/cliqset/xrd/Expires.java
@@ -21,7 +21,7 @@ import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;
-import javax.xml.bind.annotation.*;
+import jakarta.xml.bind.annotation.*;
@XmlType(name="Expires", namespace=XRDConstants.XRD_NAMESPACE)
@XmlAccessorType(XmlAccessType.FIELD)
diff --git a/src/main/java/com/cliqset/xrd/Link.java b/src/main/java/com/cliqset/xrd/Link.java
index ec8522f0..020defe6 100644
--- a/src/main/java/com/cliqset/xrd/Link.java
+++ b/src/main/java/com/cliqset/xrd/Link.java
@@ -22,13 +22,13 @@ import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
-import javax.xml.bind.annotation.XmlAnyElement;
-import javax.xml.bind.annotation.XmlAnyAttribute;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAnyElement;
+import jakarta.xml.bind.annotation.XmlAnyAttribute;
+import jakarta.xml.bind.annotation.XmlType;
+import jakarta.xml.bind.annotation.XmlAttribute;
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
import org.w3c.dom.Element;
diff --git a/src/main/java/com/cliqset/xrd/Property.java b/src/main/java/com/cliqset/xrd/Property.java
index 35c7d0cc..f7777c94 100644
--- a/src/main/java/com/cliqset/xrd/Property.java
+++ b/src/main/java/com/cliqset/xrd/Property.java
@@ -18,12 +18,12 @@ package com.cliqset.xrd;
import java.net.URI;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAnyAttribute;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAnyAttribute;
+import jakarta.xml.bind.annotation.XmlAttribute;
+import jakarta.xml.bind.annotation.XmlType;
+import jakarta.xml.bind.annotation.XmlValue;
import javax.xml.namespace.QName;
import java.util.HashMap;
diff --git a/src/main/java/com/cliqset/xrd/Subject.java b/src/main/java/com/cliqset/xrd/Subject.java
index f6815317..d2f6b333 100644
--- a/src/main/java/com/cliqset/xrd/Subject.java
+++ b/src/main/java/com/cliqset/xrd/Subject.java
@@ -16,11 +16,11 @@
package com.cliqset.xrd;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAnyAttribute;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAnyAttribute;
+import jakarta.xml.bind.annotation.XmlType;
+import jakarta.xml.bind.annotation.XmlValue;
import javax.xml.namespace.QName;
import java.net.URI;
diff --git a/src/main/java/com/cliqset/xrd/Title.java b/src/main/java/com/cliqset/xrd/Title.java
index 7d6597bd..4bb43c55 100644
--- a/src/main/java/com/cliqset/xrd/Title.java
+++ b/src/main/java/com/cliqset/xrd/Title.java
@@ -19,7 +19,7 @@ package com.cliqset.xrd;
import java.util.HashMap;
import java.util.Map;
-import javax.xml.bind.annotation.*;
+import jakarta.xml.bind.annotation.*;
import javax.xml.namespace.QName;
@XmlType(name="Title", namespace=XRDConstants.XRD_NAMESPACE)
diff --git a/src/main/java/com/cliqset/xrd/XRD.java b/src/main/java/com/cliqset/xrd/XRD.java
index 393e977b..8fc6f7de 100644
--- a/src/main/java/com/cliqset/xrd/XRD.java
+++ b/src/main/java/com/cliqset/xrd/XRD.java
@@ -17,9 +17,9 @@
package com.cliqset.xrd;
import javax.xml.namespace.QName;
-import javax.xml.bind.annotation.*;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
+import jakarta.xml.bind.annotation.*;
+import jakarta.xml.bind.JAXBContext;
+import jakarta.xml.bind.JAXBException;
import org.w3c.dom.Element;
diff --git a/src/main/java/com/cliqset/xrd/package-info.java b/src/main/java/com/cliqset/xrd/package-info.java
index bd8f0146..dfc11f51 100644
--- a/src/main/java/com/cliqset/xrd/package-info.java
+++ b/src/main/java/com/cliqset/xrd/package-info.java
@@ -26,8 +26,8 @@ package com.cliqset.xrd;
import org.apache.commons.lang3.StringUtils;
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlNsForm;
-import javax.xml.bind.annotation.XmlSchema;
+import jakarta.xml.bind.annotation.XmlNs;
+import jakarta.xml.bind.annotation.XmlNsForm;
+import jakarta.xml.bind.annotation.XmlSchema;
import static com.cliqset.xrd.XRDConstants.XRD_NAMESPACE; \ No newline at end of file
diff --git a/src/main/java/com/juick/ActivityPubManager.java b/src/main/java/com/juick/ActivityPubManager.java
index 613de046..7691aa6c 100644
--- a/src/main/java/com/juick/ActivityPubManager.java
+++ b/src/main/java/com/juick/ActivityPubManager.java
@@ -71,8 +71,8 @@ import com.juick.www.api.activity.model.objects.Image;
import com.juick.www.api.activity.model.objects.Mention;
import com.juick.www.api.activity.model.objects.Note;
import com.juick.www.api.activity.model.objects.Person;
-import com.mitchellbosecke.pebble.PebbleEngine;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.PebbleEngine;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
diff --git a/src/main/java/com/juick/EmailManager.java b/src/main/java/com/juick/EmailManager.java
index 8ef1a270..a62d31f3 100644
--- a/src/main/java/com/juick/EmailManager.java
+++ b/src/main/java/com/juick/EmailManager.java
@@ -22,6 +22,16 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.juick.model.Message;
import com.juick.model.User;
import com.juick.www.api.SystemActivity;
+
+import jakarta.mail.MessagingException;
+import jakarta.mail.Multipart;
+import jakarta.mail.Session;
+import jakarta.mail.Transport;
+import jakarta.mail.internet.InternetAddress;
+import jakarta.mail.internet.MimeBodyPart;
+import jakarta.mail.internet.MimeMessage;
+import jakarta.mail.internet.MimeMultipart;
+
import com.juick.util.HttpBadRequestException;
import com.juick.www.WebApp;
import com.juick.service.EmailService;
@@ -38,14 +48,6 @@ import org.springframework.scheduling.annotation.Async;
import javax.annotation.Nonnull;
import javax.inject.Inject;
-import javax.mail.MessagingException;
-import javax.mail.Multipart;
-import javax.mail.Session;
-import javax.mail.Transport;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeBodyPart;
-import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMultipart;
import java.util.*;
import static com.juick.util.formatters.PlainTextFormatter.formatPost;
@@ -163,7 +165,7 @@ public class EmailManager implements NotificationListener {
};
String fromAddress = StringUtils.isNotEmpty(from) ? from : "juick@juick.com";
message.setFrom(fromAddress);
- message.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(to));
+ message.addRecipient(jakarta.mail.Message.RecipientType.TO, new InternetAddress(to));
message.setSubject(subject);
MimeBodyPart textBodyPart = new MimeBodyPart();
textBodyPart.setContent(textPart, "text/plain; charset=UTF-8");
diff --git a/src/main/java/com/juick/TelegramBotManager.java b/src/main/java/com/juick/TelegramBotManager.java
index 20f31b1b..1dcc7edb 100644
--- a/src/main/java/com/juick/TelegramBotManager.java
+++ b/src/main/java/com/juick/TelegramBotManager.java
@@ -54,7 +54,7 @@ import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
+import jakarta.annotation.PostConstruct;
import javax.inject.Inject;
import java.io.IOException;
import java.net.URI;
diff --git a/src/main/java/com/juick/XMPPManager.java b/src/main/java/com/juick/XMPPManager.java
index 6343378c..0878c450 100644
--- a/src/main/java/com/juick/XMPPManager.java
+++ b/src/main/java/com/juick/XMPPManager.java
@@ -21,6 +21,10 @@ import com.juick.model.User;
import com.juick.util.formatters.PlainTextFormatter;
import com.juick.model.CommandResult;
import com.juick.www.api.SystemActivity;
+
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
+
import com.juick.www.WebApp;
import com.juick.util.xmpp.iq.MessageQuery;
import com.juick.service.MessagesService;
@@ -66,8 +70,6 @@ import rocks.xmpp.extensions.version.SoftwareVersionManager;
import rocks.xmpp.extensions.version.model.SoftwareVersion;
import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
import javax.inject.Inject;
import java.io.IOException;
import java.net.MalformedURLException;
diff --git a/src/main/java/com/juick/config/ActivityPubClientErrorHandler.java b/src/main/java/com/juick/config/ActivityPubClientErrorHandler.java
index ecb81e30..69958bbd 100644
--- a/src/main/java/com/juick/config/ActivityPubClientErrorHandler.java
+++ b/src/main/java/com/juick/config/ActivityPubClientErrorHandler.java
@@ -28,7 +28,6 @@ import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.client.DefaultResponseErrorHandler;
-import javax.annotation.Nonnull;
import javax.inject.Inject;
import java.io.IOException;
import java.net.URI;
@@ -41,7 +40,7 @@ public class ActivityPubClientErrorHandler extends DefaultResponseErrorHandler {
@Inject
private ApplicationEventPublisher applicationEventPublisher;
@Override
- public void handleError(URI contextUri, HttpMethod method, @Nonnull ClientHttpResponse response) throws IOException {
+ public void handleError(URI contextUri, HttpMethod method, ClientHttpResponse response) throws IOException {
logger.warn("HTTP ERROR {} {} : {}", response.getStatusCode().value(),
response.getStatusText(), IOUtils.toString(response.getBody(), StandardCharsets.UTF_8));
if (response.getStatusCode().equals(HttpStatus.GONE)) {
diff --git a/src/main/java/com/juick/config/ActivityPubConfig.java b/src/main/java/com/juick/config/ActivityPubConfig.java
index 89aacff0..fb204aaa 100644
--- a/src/main/java/com/juick/config/ActivityPubConfig.java
+++ b/src/main/java/com/juick/config/ActivityPubConfig.java
@@ -20,7 +20,8 @@ package com.juick.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.juick.ActivityPubManager;
import com.juick.util.ActivityPubRequestInterceptor;
-import org.apache.http.impl.client.CloseableHttpClient;
+
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
diff --git a/src/main/java/com/juick/config/HttpClientConfig.java b/src/main/java/com/juick/config/HttpClientConfig.java
index 22c06ecb..99351828 100644
--- a/src/main/java/com/juick/config/HttpClientConfig.java
+++ b/src/main/java/com/juick/config/HttpClientConfig.java
@@ -1,20 +1,19 @@
package com.juick.config;
import java.util.concurrent.TimeUnit;
-
-import org.apache.http.HeaderElement;
-import org.apache.http.HeaderElementIterator;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.config.CookieSpecs;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.conn.ConnectionKeepAliveStrategy;
-
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.message.BasicHeaderElementIterator;
-import org.apache.http.protocol.HTTP;
-import org.apache.http.protocol.HttpContext;
+
+import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.cookie.StandardCookieSpec;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
+import org.apache.hc.core5.http.HeaderElement;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.message.BasicHeaderElementIterator;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
@@ -55,19 +54,19 @@ public class HttpClientConfig {
public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {
return new ConnectionKeepAliveStrategy() {
@Override
- public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
- HeaderElementIterator it = new BasicHeaderElementIterator
- (response.headerIterator(HTTP.CONN_KEEP_ALIVE));
+ public TimeValue getKeepAliveDuration(HttpResponse response, HttpContext context) {
+ BasicHeaderElementIterator it = new BasicHeaderElementIterator
+ (response.headerIterator("Keep-Alive"));
while (it.hasNext()) {
- HeaderElement he = it.nextElement();
+ HeaderElement he = it.next();
String param = he.getName();
String value = he.getValue();
if (value != null && param.equalsIgnoreCase("timeout")) {
- return Long.parseLong(value) * 1000;
+ return TimeValue.of(Long.parseLong(value) * 1000, TimeUnit.MILLISECONDS);
}
}
- return DEFAULT_KEEP_ALIVE_TIME_MILLIS;
+ return TimeValue.of(DEFAULT_KEEP_ALIVE_TIME_MILLIS, TimeUnit.MILLISECONDS);
}
};
}
@@ -75,10 +74,10 @@ public class HttpClientConfig {
@Bean
public CloseableHttpClient httpClient() {
RequestConfig requestConfig = RequestConfig.custom()
- .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
- .setConnectionRequestTimeout(REQUEST_TIMEOUT)
- .setConnectTimeout(CONNECT_TIMEOUT)
- .setSocketTimeout(SOCKET_TIMEOUT).build();
+ .setCookieSpec(StandardCookieSpec.IGNORE)
+ .setConnectionRequestTimeout(Timeout.of(REQUEST_TIMEOUT, TimeUnit.MILLISECONDS))
+ .setConnectTimeout(Timeout.of(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS))
+ .setResponseTimeout(Timeout.of(SOCKET_TIMEOUT, TimeUnit.MILLISECONDS)).build();
return HttpClients.custom()
.setDefaultRequestConfig(requestConfig)
@@ -96,8 +95,8 @@ public class HttpClientConfig {
try {
if (connectionManager != null) {
LOGGER.trace("run IdleConnectionMonitor - Closing expired and idle connections...");
- connectionManager.closeExpiredConnections();
- connectionManager.closeIdleConnections(CLOSE_IDLE_CONNECTION_WAIT_TIME_SECS, TimeUnit.SECONDS);
+ connectionManager.closeExpired();
+ connectionManager.closeIdle(TimeValue.of(CLOSE_IDLE_CONNECTION_WAIT_TIME_SECS, TimeUnit.SECONDS));
} else {
LOGGER.trace("run IdleConnectionMonitor - Http Client Connection manager is not initialised");
}
diff --git a/src/main/java/com/juick/config/SecurityConfig.java b/src/main/java/com/juick/config/SecurityConfig.java
index 1907c7c5..b5c93906 100644
--- a/src/main/java/com/juick/config/SecurityConfig.java
+++ b/src/main/java/com/juick/config/SecurityConfig.java
@@ -23,20 +23,17 @@ import com.juick.service.security.HTTPSignatureAuthenticationFilter;
import com.juick.service.security.HashParamAuthenticationFilter;
import com.juick.service.security.JuickUserDetailsService;
import com.juick.service.security.entities.JuickUser;
-import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.AuthenticationEntryPoint;
-import org.springframework.security.web.authentication.NullRememberMeServices;
+import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
@@ -46,18 +43,18 @@ import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
-import javax.annotation.Resource;
-import javax.inject.Inject;
import java.util.Arrays;
import java.util.Collections;
-import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
/**
* Created by aalexeev on 11/21/16.
*/
@EnableWebSecurity
+@Configuration
public class SecurityConfig {
- @Resource
+ @Inject
private UserService userService;
private static final String COOKIE_NAME = "juick-remember-me";
@@ -66,6 +63,7 @@ public class SecurityConfig {
public UserDetailsService userDetailsService() {
return new JuickUserDetailsService(userService);
}
+
@Bean
static CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
@@ -81,132 +79,106 @@ public class SecurityConfig {
return source;
}
- @Configuration
+ @Inject
+ private SignatureManager signatureManager;
+
+ @Bean
+ public HashParamAuthenticationFilter apiAuthenticationFilter() {
+ return new HashParamAuthenticationFilter(userService, null);
+ }
+
+ @Bean
+ public AuthenticationEntryPoint juickAuthenticationEntryPoint() {
+ var entryPoint = new BasicAuthenticationEntryPoint();
+ entryPoint.setRealmName("Juick");
+ return entryPoint;
+ }
+
+ @Value("${auth_remember_me_key:secret}")
+ private String rememberMeKey;
+ @Value("${web_domain:localhost}")
+ private String webDomain;
+
+ @Bean
+ public HashParamAuthenticationFilter wwwAuthenticationFilter() {
+ return new HashParamAuthenticationFilter(userService, hashCookieServices());
+ }
+
+ @Bean
+ public RememberMeServices hashCookieServices() {
+ TokenBasedRememberMeServices services = new TokenBasedRememberMeServices(
+ rememberMeKey, userDetailsService());
+
+ services.setCookieName(COOKIE_NAME);
+ services.setCookieDomain(webDomain);
+ services.setAlwaysRemember(true);
+ services.setTokenValiditySeconds(6 * 30 * 24 * 3600);
+ services.setUseSecureCookie(false); // TODO set true if https is supports
+ return services;
+ }
+
+ @Bean
@Order(1)
- public static class ApiConfig extends WebSecurityConfigurerAdapter {
- @Value("${auth_remember_me_key:secret}")
- private String rememberMeKey;
- @Resource
- private UserService userService;
- @Resource
- private SignatureManager signatureManager;
- ApiConfig() {
- super(true);
- }
- @Bean
- RememberMeServices apiTokenServices() {
- return new NullRememberMeServices();
- }
- @Bean
- public HashParamAuthenticationFilter apiAuthenticationFilter() {
- return new HashParamAuthenticationFilter(userService, apiTokenServices());
- }
-
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http.antMatcher("/api/**")
- .addFilterBefore(apiAuthenticationFilter(), BasicAuthenticationFilter.class)
- .addFilterBefore(new HTTPSignatureAuthenticationFilter(signatureManager, userService), BasicAuthenticationFilter.class)
- .authorizeRequests()
- .antMatchers(HttpMethod.OPTIONS).permitAll()
- .antMatchers("/api/", "/api/messages", "/api/avatar", "/api/messages/discussions",
- "/api/users", "/api/thread", "/api/tags", "/api/tlgmbtwbhk", "/api/fbwbhk",
- "/api/skypebotendpoint", "/api/_fblogin", "/api/_vklogin", "/api/_tglogin",
- "/api/_google", "/api/_applelogin", "/api/signup", "/api/inbox", "/api/events", "/api/info/**",
- "/api/nodeinfo/2.0").permitAll()
- .anyRequest().hasRole("USER")
- .and()
- .anonymous().principal(JuickUser.ANONYMOUS_USER).authorities(JuickUser.ANONYMOUS_AUTHORITY)
- .and()
- .httpBasic().authenticationEntryPoint(juickAuthenticationEntryPoint())
- .and().cors().configurationSource(corsConfigurationSource())
- .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
- .and().exceptionHandling().authenticationEntryPoint(juickAuthenticationEntryPoint())
- .and()
- .rememberMe()
- .alwaysRemember(true)
- .tokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(6 * 30))
- .rememberMeServices(apiTokenServices())
- .key(rememberMeKey)
- .and()
- .headers().defaultsDisabled().cacheControl();
- }
-
- @Bean
- public AuthenticationEntryPoint juickAuthenticationEntryPoint() {
- var entryPoint = new BasicAuthenticationEntryPoint();
- entryPoint.setRealmName("Juick");
- return entryPoint;
- }
+ public SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
+ http.securityMatcher("/api/**")
+ .addFilterBefore(apiAuthenticationFilter(), BasicAuthenticationFilter.class)
+ .addFilterBefore(new HTTPSignatureAuthenticationFilter(signatureManager, userService),
+ BasicAuthenticationFilter.class)
+ .authorizeHttpRequests(requests -> requests
+ .requestMatchers(HttpMethod.OPTIONS).permitAll()
+ .requestMatchers("/api/", "/api/messages", "/api/avatar", "/api/messages/discussions",
+ "/api/users", "/api/thread", "/api/tags", "/api/tlgmbtwbhk", "/api/fbwbhk",
+ "/api/skypebotendpoint", "/api/_fblogin", "/api/_vklogin", "/api/_tglogin",
+ "/api/_google", "/api/_applelogin", "/api/signup", "/api/inbox", "/api/events",
+ "/api/info/**",
+ "/api/nodeinfo/2.0")
+ .permitAll()
+ .anyRequest().hasRole("USER"))
+ .anonymous(anonymous -> anonymous.principal(JuickUser.ANONYMOUS_USER)
+ .authorities(JuickUser.ANONYMOUS_AUTHORITY))
+ .httpBasic(httpBasic -> httpBasic.authenticationEntryPoint(juickAuthenticationEntryPoint()))
+ .cors(cors -> cors.configurationSource(corsConfigurationSource()))
+ .sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
+ .exceptionHandling(exceptionHandling -> exceptionHandling.authenticationEntryPoint(juickAuthenticationEntryPoint()))
+ .csrf().disable()
+ .headers().defaultsDisabled().cacheControl();
+ return http.build();
}
- @Configuration
- public static class WebConfig extends WebSecurityConfigurerAdapter {
- @Value("${auth_remember_me_key:secret}")
- private String rememberMeKey;
- @Value("${web_domain:localhost}")
- private String webDomain;
- @Resource
- private UserService userService;
- @Inject
- private UserDetailsService userDetailsService;
- @Bean
- @Qualifier("www")
- public HashParamAuthenticationFilter wwwAuthenticationFilter() {
- return new HashParamAuthenticationFilter(userService, hashCookieServices());
- }
- @Bean
- @Qualifier("www")
- public RememberMeServices hashCookieServices() {
- TokenBasedRememberMeServices services = new TokenBasedRememberMeServices(
- rememberMeKey, userDetailsService);
-
- services.setCookieName(COOKIE_NAME);
- services.setCookieDomain(webDomain);
- services.setAlwaysRemember(true);
- services.setTokenValiditySeconds(6 * 30 * 24 * 3600);
- services.setUseSecureCookie(false); // TODO set true if https is supports
-
- return services;
- }
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http
- .addFilterBefore(wwwAuthenticationFilter(), BasicAuthenticationFilter.class)
- .authorizeRequests()
- .antMatchers("/settings", "/pm/**", "/**/bl", "/_twitter", "/post", "/post2", "/comment")
- .authenticated()
- .antMatchers("/actuator/**").hasRole("ADMIN")
- .anyRequest().permitAll()
- .and()
- .anonymous().principal(JuickUser.ANONYMOUS_USER).authorities(JuickUser.ANONYMOUS_AUTHORITY)
- .and().cors().configurationSource(corsConfigurationSource())
- .and().sessionManagement()
- .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
- .invalidSessionUrl("/")
- .and()
- .logout()
- .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
- .invalidateHttpSession(true)
- .logoutUrl("/logout")
- .logoutSuccessUrl("/")
- .deleteCookies("hash", COOKIE_NAME)
- .and()
- .formLogin()
- .loginPage("/login")
- .permitAll()
- .defaultSuccessUrl("/")
- .loginProcessingUrl("/login")
- .usernameParameter("username")
- .passwordParameter("password")
- .failureUrl("/login?error=1")
- .and()
- .rememberMe()
- .rememberMeCookieDomain(webDomain).key(rememberMeKey)
- .rememberMeServices(hashCookieServices())
- .and()
- .csrf().disable()
- .headers().defaultsDisabled().cacheControl();
- }
+ @Bean
+ public SecurityFilterChain wwwChain(HttpSecurity http) throws Exception {
+ http.addFilterBefore(wwwAuthenticationFilter(), BasicAuthenticationFilter.class)
+ .authorizeHttpRequests(authorize -> authorize
+ .requestMatchers("/settings", "/pm/**", "/**/bl", "/_twitter", "/post", "/post2",
+ "/comment")
+ .authenticated()
+ .requestMatchers("/actuator/**").hasRole("ADMIN")
+ .anyRequest().permitAll())
+ .anonymous(anonymous -> anonymous.principal(JuickUser.ANONYMOUS_USER)
+ .authorities(JuickUser.ANONYMOUS_AUTHORITY))
+ .cors(cors -> cors
+ .configurationSource(corsConfigurationSource()))
+ .sessionManagement(
+ sessionManagement -> sessionManagement
+ .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ .invalidSessionUrl("/"))
+ .logout(logout -> logout
+ .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
+ .invalidateHttpSession(true)
+ .logoutSuccessUrl("/")
+ .deleteCookies("hash", COOKIE_NAME))
+ .formLogin(form -> form.loginPage("/login")
+ .defaultSuccessUrl("/")
+ .loginProcessingUrl("/login")
+ .usernameParameter("username")
+ .passwordParameter("password")
+ .failureUrl("/login?error=1")
+ .permitAll())
+ .csrf(csrf -> csrf.ignoringRequestMatchers("/settings/unsubscribe"))
+ .rememberMe(rememberMe -> rememberMe
+ .rememberMeCookieDomain(webDomain).key(rememberMeKey)
+ .rememberMeServices(hashCookieServices()))
+ .headers().defaultsDisabled().cacheControl();
+ return http.build();
}
}
diff --git a/src/main/java/com/juick/config/WebConfig.java b/src/main/java/com/juick/config/WebConfig.java
index 59f9a99c..bfebd77f 100644
--- a/src/main/java/com/juick/config/WebConfig.java
+++ b/src/main/java/com/juick/config/WebConfig.java
@@ -23,14 +23,16 @@ import com.juick.service.HelpService;
import com.juick.service.StorageService;
import com.juick.service.FileSystemStorageService;
import com.juick.service.UserService;
-import com.mitchellbosecke.pebble.PebbleEngine;
import com.mitchellbosecke.pebble.extension.FormatterExtension;
-import com.mitchellbosecke.pebble.loader.ClasspathLoader;
-import com.mitchellbosecke.pebble.loader.Loader;
-import com.mitchellbosecke.pebble.spring.extension.SpringExtension;
-import com.mitchellbosecke.pebble.spring.servlet.PebbleViewResolver;
import com.overzealous.remark.Options;
import com.overzealous.remark.Remark;
+
+import io.pebbletemplates.pebble.PebbleEngine;
+import io.pebbletemplates.pebble.loader.ClasspathLoader;
+import io.pebbletemplates.pebble.loader.Loader;
+import io.pebbletemplates.spring.extension.SpringExtension;
+import io.pebbletemplates.spring.servlet.PebbleViewResolver;
+
import org.apache.commons.codec.CharEncoding;
import org.commonmark.ext.autolink.AutolinkExtension;
import org.commonmark.node.Link;
@@ -175,6 +177,7 @@ public class WebConfig implements WebMvcConfigurer {
viewResolver.setPrefix("templates");
viewResolver.setSuffix(".html");
viewResolver.setCharacterEncoding(CharEncoding.UTF_8);
+ viewResolver.setExposeRequestAttributes(true);
return viewResolver;
}
@Override
diff --git a/src/main/java/com/juick/model/Message.java b/src/main/java/com/juick/model/Message.java
index 2a5883ac..cfd2582b 100644
--- a/src/main/java/com/juick/model/Message.java
+++ b/src/main/java/com/juick/model/Message.java
@@ -20,11 +20,17 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.juick.util.adapters.SimpleDateAdapter;
+
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAttribute;
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.XmlTransient;
+import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
import org.apache.commons.lang3.builder.ToStringBuilder;
import javax.annotation.Nonnull;
-import javax.xml.bind.annotation.*;
-import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.io.Serializable;
import java.net.URI;
import java.time.Instant;
@@ -120,7 +126,7 @@ public class Message implements Comparable<Message>, Serializable {
}
@Override
- public int compareTo(@Nonnull Message jmsg) throws ClassCastException {
+ public int compareTo(Message jmsg) throws ClassCastException {
if (jmsg == this)
return 0;
diff --git a/src/main/java/com/juick/model/Tag.java b/src/main/java/com/juick/model/Tag.java
index 75266303..e7fcde5d 100644
--- a/src/main/java/com/juick/model/Tag.java
+++ b/src/main/java/com/juick/model/Tag.java
@@ -18,7 +18,12 @@ package com.juick.model;
import com.fasterxml.jackson.annotation.JsonValue;
-import javax.xml.bind.annotation.*;
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.XmlTransient;
+import jakarta.xml.bind.annotation.XmlValue;
+
import java.io.Serializable;
import java.util.Comparator;
import java.util.Objects;
diff --git a/src/main/java/com/juick/model/User.java b/src/main/java/com/juick/model/User.java
index b43257ed..5cc0d125 100644
--- a/src/main/java/com/juick/model/User.java
+++ b/src/main/java/com/juick/model/User.java
@@ -18,14 +18,16 @@ package com.juick.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
+
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAttribute;
+import jakarta.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.XmlTransient;
+
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import javax.annotation.Nonnull;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlTransient;
import java.io.Serializable;
import java.net.URI;
import java.time.Instant;
diff --git a/src/main/java/com/juick/model/package-info.java b/src/main/java/com/juick/model/package-info.java
index be9e6c2b..9e8d4b34 100644
--- a/src/main/java/com/juick/model/package-info.java
+++ b/src/main/java/com/juick/model/package-info.java
@@ -30,6 +30,6 @@ package com.juick.model;
import org.apache.commons.lang3.StringUtils;
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlNsForm;
-import javax.xml.bind.annotation.XmlSchema; \ No newline at end of file
+import jakarta.xml.bind.annotation.XmlNs;
+import jakarta.xml.bind.annotation.XmlNsForm;
+import jakarta.xml.bind.annotation.XmlSchema; \ No newline at end of file
diff --git a/src/main/java/com/juick/service/UserServiceImpl.java b/src/main/java/com/juick/service/UserServiceImpl.java
index 36f37d5e..71f2dc91 100644
--- a/src/main/java/com/juick/service/UserServiceImpl.java
+++ b/src/main/java/com/juick/service/UserServiceImpl.java
@@ -129,7 +129,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService {
return stmt;
},
holder);
- } catch (DuplicateKeyException e) {
+ } catch (DataIntegrityViolationException e) {
throw new UsernameTakenException();
}
diff --git a/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java b/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java
index 4eeb41b4..723cf576 100644
--- a/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java
+++ b/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java
@@ -28,11 +28,10 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
-import javax.annotation.Nonnull;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
@@ -43,15 +42,16 @@ public class HTTPSignatureAuthenticationFilter extends OncePerRequestFilter {
private final SignatureManager signatureManager;
private final UserService userService;
-
public HTTPSignatureAuthenticationFilter(
final SignatureManager signatureManager,
final UserService userService) {
this.signatureManager = signatureManager;
this.userService = userService;
}
+
@Override
- protected void doFilterInternal(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull FilterChain filterChain) throws IOException, ServletException {
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+ throws IOException, ServletException {
if (authenticationIsRequired()) {
Map<String, String> headers = Collections.list(request.getHeaderNames())
.stream()
@@ -63,7 +63,8 @@ public class HTTPSignatureAuthenticationFilter extends OncePerRequestFilter {
if (userUri.length() == 0) {
User userWithPassword = userService.getUserByName(user.getName());
userWithPassword.setAuthHash(userService.getHashByUID(userWithPassword.getUid()));
- Authentication authentication = new UsernamePasswordAuthenticationToken(userWithPassword.getName(), userWithPassword.getCredentials());
+ Authentication authentication = new UsernamePasswordAuthenticationToken(
+ new JuickUser(user), userWithPassword.getCredentials(), JuickUser.USER_AUTHORITY);
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
Authentication authentication = new AnonymousAuthenticationToken(userUri,
diff --git a/src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java b/src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java
index 68ae91ee..0f4ac66f 100644
--- a/src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java
+++ b/src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java
@@ -21,41 +21,40 @@ import com.juick.model.User;
import com.juick.service.UserService;
import com.juick.service.security.entities.JuickUser;
import org.apache.commons.lang3.StringUtils;
+import org.springframework.lang.NonNull;
+import org.springframework.lang.Nullable;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.RememberMeAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.web.authentication.NullRememberMeServices;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.util.Assert;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.WebUtils;
-import javax.annotation.Nonnull;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by aalexeev on 4/5/17.
*/
public class HashParamAuthenticationFilter extends OncePerRequestFilter {
+
public static final String PARAM_NAME = "hash";
private final UserService userService;
private final RememberMeServices rememberMeServices;
-
public HashParamAuthenticationFilter(
- final UserService userService,
- final RememberMeServices rememberMeServices) {
+ @NonNull final UserService userService,
+ @Nullable final RememberMeServices rememberMeServices) {
Assert.notNull(userService, "userService should not be null");
- Assert.notNull(rememberMeServices, "rememberMeServices should not be null");
this.userService = userService;
this.rememberMeServices = rememberMeServices;
@@ -63,28 +62,31 @@ public class HashParamAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(
- @Nonnull HttpServletRequest request,
- @Nonnull HttpServletResponse response,
- @Nonnull FilterChain filterChain) throws ServletException, IOException {
+ HttpServletRequest request,
+ HttpServletResponse response,
+ FilterChain filterChain) throws ServletException, IOException {
String hash = getHashFromRequest(request);
-
if (hash != null && authenticationIsRequired()) {
User user = userService.getUserByHash(hash);
-
if (!user.isAnonymous()) {
User userWithPassword = userService.getUserByName(user.getName());
userWithPassword.setAuthHash(userService.getHashByUID(userWithPassword.getUid()));
- Authentication authentication = rememberMeServices instanceof NullRememberMeServices
- ? new UsernamePasswordAuthenticationToken(userWithPassword.getName(),
- userWithPassword.getCredentials())
- : new RememberMeAuthenticationToken(
- ((AbstractRememberMeServices)rememberMeServices).getKey(),
- new JuickUser(userWithPassword), JuickUser.USER_AUTHORITY);
-
- SecurityContextHolder.getContext().setAuthentication(authentication);
-
- rememberMeServices.loginSuccess(request, response, authentication);
+ if (rememberMeServices != null) {
+ // web login should create cookie
+ var authentication = new RememberMeAuthenticationToken(
+ ((AbstractRememberMeServices) rememberMeServices).getKey(),
+ new JuickUser(userWithPassword), JuickUser.USER_AUTHORITY);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ rememberMeServices.loginSuccess(request, response, authentication);
+ } else {
+ Authentication authentication = new UsernamePasswordAuthenticationToken(
+ new JuickUser(userWithPassword),
+ userWithPassword.getCredentials(),
+ JuickUser.USER_AUTHORITY);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+
+ }
}
}
diff --git a/src/main/java/com/juick/util/adapters/SimpleDateAdapter.java b/src/main/java/com/juick/util/adapters/SimpleDateAdapter.java
index 46d4cc47..664a37a0 100644
--- a/src/main/java/com/juick/util/adapters/SimpleDateAdapter.java
+++ b/src/main/java/com/juick/util/adapters/SimpleDateAdapter.java
@@ -19,7 +19,8 @@ package com.juick.util.adapters;
import com.juick.util.DateFormattersHolder;
-import javax.xml.bind.annotation.adapters.XmlAdapter;
+import jakarta.xml.bind.annotation.adapters.XmlAdapter;
+
import java.time.Instant;
/**
diff --git a/src/main/java/com/juick/util/xmpp/JidConverter.java b/src/main/java/com/juick/util/xmpp/JidConverter.java
index f2add967..4f457164 100644
--- a/src/main/java/com/juick/util/xmpp/JidConverter.java
+++ b/src/main/java/com/juick/util/xmpp/JidConverter.java
@@ -21,12 +21,10 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.Nullable;
import rocks.xmpp.addr.Jid;
-import javax.annotation.Nonnull;
-
public class JidConverter implements Converter<String, Jid> {
@Nullable
@Override
- public Jid convert(@Nonnull String jidStr) {
+ public Jid convert(String jidStr) {
return Jid.of(jidStr);
}
}
diff --git a/src/main/java/com/juick/util/xmpp/iq/MessageQuery.java b/src/main/java/com/juick/util/xmpp/iq/MessageQuery.java
index 8a8d5614..aa1c1573 100644
--- a/src/main/java/com/juick/util/xmpp/iq/MessageQuery.java
+++ b/src/main/java/com/juick/util/xmpp/iq/MessageQuery.java
@@ -17,7 +17,7 @@
package com.juick.util.xmpp.iq;
-import javax.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "query")
public class MessageQuery {
diff --git a/src/main/java/com/juick/util/xmpp/iq/package-info.java b/src/main/java/com/juick/util/xmpp/iq/package-info.java
index 6d0395b1..cf8dcd4d 100644
--- a/src/main/java/com/juick/util/xmpp/iq/package-info.java
+++ b/src/main/java/com/juick/util/xmpp/iq/package-info.java
@@ -19,7 +19,7 @@
@XmlSchema(namespace = "http://juick.com/", elementFormDefault = XmlNsForm.QUALIFIED)
package com.juick.util.xmpp.iq;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlNsForm;
-import javax.xml.bind.annotation.XmlSchema; \ No newline at end of file
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlNsForm;
+import jakarta.xml.bind.annotation.XmlSchema; \ No newline at end of file
diff --git a/src/main/java/com/juick/www/VaryHandler.java b/src/main/java/com/juick/www/VaryHandler.java
index 372847a9..6910823d 100644
--- a/src/main/java/com/juick/www/VaryHandler.java
+++ b/src/main/java/com/juick/www/VaryHandler.java
@@ -20,7 +20,7 @@ package com.juick.www;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletResponse;
@ControllerAdvice
public class VaryHandler {
diff --git a/src/main/java/com/juick/www/WebApp.java b/src/main/java/com/juick/www/WebApp.java
index cebedb9b..a7c5eb8b 100644
--- a/src/main/java/com/juick/www/WebApp.java
+++ b/src/main/java/com/juick/www/WebApp.java
@@ -27,15 +27,16 @@ import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
-import javax.annotation.PostConstruct;
import javax.inject.Inject;
import com.juick.model.Message;
import com.juick.model.Tag;
import com.juick.model.User;
import com.juick.service.TagService;
-import com.mitchellbosecke.pebble.PebbleEngine;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.PebbleEngine;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
+
+import jakarta.annotation.PostConstruct;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
diff --git a/src/main/java/com/juick/www/api/ApiSocialLogin.java b/src/main/java/com/juick/www/api/ApiSocialLogin.java
index ccb9f923..38884cd6 100644
--- a/src/main/java/com/juick/www/api/ApiSocialLogin.java
+++ b/src/main/java/com/juick/www/api/ApiSocialLogin.java
@@ -48,7 +48,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.util.UriComponentsBuilder;
-import javax.annotation.PostConstruct;
+import jakarta.annotation.PostConstruct;
import javax.inject.Inject;
import java.io.IOException;
import java.security.GeneralSecurityException;
diff --git a/src/main/java/com/juick/www/api/Post.java b/src/main/java/com/juick/www/api/Post.java
index bced92bf..9faf883a 100644
--- a/src/main/java/com/juick/www/api/Post.java
+++ b/src/main/java/com/juick/www/api/Post.java
@@ -23,7 +23,7 @@ import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
-import javax.validation.constraints.NotNull;
+import jakarta.validation.constraints.NotNull;
import com.juick.ActivityPubManager;
import com.juick.CommandsManager;
diff --git a/src/main/java/com/juick/www/api/Service.java b/src/main/java/com/juick/www/api/Service.java
index 81b24a23..3bb760ff 100644
--- a/src/main/java/com/juick/www/api/Service.java
+++ b/src/main/java/com/juick/www/api/Service.java
@@ -32,6 +32,11 @@ import com.juick.service.UserService;
import com.juick.service.component.AccountVerificationEvent;
import com.juick.service.security.annotation.Visitor;
import io.swagger.v3.oas.annotations.Hidden;
+import jakarta.mail.Session;
+import jakarta.mail.internet.AddressException;
+import jakarta.mail.internet.InternetAddress;
+import jakarta.mail.internet.MimeMessage;
+
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
@@ -52,10 +57,6 @@ import org.springframework.web.context.request.async.AsyncRequestTimeoutExceptio
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.inject.Inject;
-import javax.mail.Session;
-import javax.mail.internet.AddressException;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
diff --git a/src/main/java/com/juick/www/controllers/Login.java b/src/main/java/com/juick/www/controllers/Login.java
index 41d902de..f78ccef0 100644
--- a/src/main/java/com/juick/www/controllers/Login.java
+++ b/src/main/java/com/juick/www/controllers/Login.java
@@ -20,6 +20,8 @@ import com.juick.model.User;
import com.juick.service.UserService;
import com.juick.service.security.annotation.Visitor;
+import jakarta.servlet.http.HttpSession;
+
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.WebAttributes;
import org.springframework.stereotype.Controller;
@@ -28,7 +30,6 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.inject.Inject;
-import javax.servlet.http.HttpSession;
/**
* @author Ugnich Anton
diff --git a/src/main/java/com/juick/www/controllers/Settings.java b/src/main/java/com/juick/www/controllers/Settings.java
index 1dc5f1c3..1e40b9d1 100644
--- a/src/main/java/com/juick/www/controllers/Settings.java
+++ b/src/main/java/com/juick/www/controllers/Settings.java
@@ -25,15 +25,6 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.inject.Inject;
-import javax.mail.Message;
-import javax.mail.MessagingException;
-import javax.mail.Session;
-import javax.mail.Transport;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import com.juick.model.NotifyOpts;
import com.juick.model.User;
@@ -49,6 +40,16 @@ import com.juick.util.HttpBadRequestException;
import com.juick.util.HttpUtils;
import com.juick.www.WebApp;
+import jakarta.mail.Message;
+import jakarta.mail.MessagingException;
+import jakarta.mail.Session;
+import jakarta.mail.Transport;
+import jakarta.mail.internet.InternetAddress;
+import jakarta.mail.internet.MimeMessage;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
diff --git a/src/main/java/com/juick/www/controllers/Site.java b/src/main/java/com/juick/www/controllers/Site.java
index 5f034b86..46440b2b 100644
--- a/src/main/java/com/juick/www/controllers/Site.java
+++ b/src/main/java/com/juick/www/controllers/Site.java
@@ -24,6 +24,9 @@ import com.juick.util.HttpForbiddenException;
import com.juick.util.HttpNotFoundException;
import com.juick.util.WebUtils;
import com.juick.www.WebApp;
+
+import jakarta.servlet.http.HttpServletRequest;
+
import com.juick.service.*;
import com.juick.service.security.annotation.Visitor;
import com.juick.util.MessageUtils;
@@ -42,7 +45,6 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import javax.inject.Inject;
-import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
diff --git a/src/main/java/com/juick/www/controllers/SocialLogin.java b/src/main/java/com/juick/www/controllers/SocialLogin.java
index f4f8dbfd..dad3d969 100644
--- a/src/main/java/com/juick/www/controllers/SocialLogin.java
+++ b/src/main/java/com/juick/www/controllers/SocialLogin.java
@@ -29,6 +29,13 @@ import com.juick.service.TelegramService;
import com.juick.service.UserService;
import com.juick.service.security.annotation.Visitor;
import com.juick.util.HttpBadRequestException;
+
+import jakarta.annotation.PostConstruct;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
+
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
@@ -46,12 +53,7 @@ import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.util.UriComponentsBuilder;
-import javax.annotation.PostConstruct;
import javax.inject.Inject;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
diff --git a/src/main/java/com/juick/www/filters/AnythingFilter.java b/src/main/java/com/juick/www/filters/AnythingFilter.java
index 7f0950a4..a725a66f 100644
--- a/src/main/java/com/juick/www/filters/AnythingFilter.java
+++ b/src/main/java/com/juick/www/filters/AnythingFilter.java
@@ -19,6 +19,12 @@ package com.juick.www.filters;
import com.juick.model.User;
import com.juick.util.WebUtils;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
import com.juick.service.MessagesService;
import com.juick.service.UserService;
import org.apache.commons.lang3.math.NumberUtils;
@@ -27,11 +33,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponents;
-import javax.annotation.Nonnull;
import javax.inject.Inject;
-import javax.servlet.*;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@@ -42,9 +44,9 @@ public class AnythingFilter extends OncePerRequestFilter {
private UserService userService;
@Override
- public void doFilterInternal(@Nonnull HttpServletRequest servletRequest,
- @Nonnull HttpServletResponse servletResponse,
- @Nonnull FilterChain filterChain) throws IOException, ServletException {
+ public void doFilterInternal(HttpServletRequest servletRequest,
+ HttpServletResponse servletResponse,
+ FilterChain filterChain) throws IOException, ServletException {
String upgrade = servletRequest.getHeader("Connection");
if (upgrade != null && upgrade.equals("Upgrade")) {
filterChain.doFilter(servletRequest, servletResponse);
diff --git a/src/main/java/com/juick/www/rss/MessagesView.java b/src/main/java/com/juick/www/rss/MessagesView.java
index 2c7d4a7d..dde67d7b 100644
--- a/src/main/java/com/juick/www/rss/MessagesView.java
+++ b/src/main/java/com/juick/www/rss/MessagesView.java
@@ -26,11 +26,7 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
-import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
import javax.inject.Inject;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import com.juick.model.Attachment;
import com.juick.model.Message;
@@ -57,6 +53,10 @@ import com.rometools.rome.feed.rss.Guid;
import com.rometools.rome.feed.rss.Image;
import com.rometools.rome.feed.rss.Item;
+import jakarta.annotation.PostConstruct;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -81,8 +81,8 @@ public class MessagesView extends AbstractRssFeedView {
@SuppressWarnings("unchecked")
@Override
- protected List<Item> buildFeedItems(@Nonnull Map<String, Object> model, @Nonnull HttpServletRequest request,
- @Nonnull HttpServletResponse response) {
+ protected List<Item> buildFeedItems(Map<String, Object> model, HttpServletRequest request,
+ HttpServletResponse response) {
List<Message> msgs = (List<Message>) model.get("messages");
return msgs.stream().map(this::createRssItem).collect(Collectors.toList());
}
diff --git a/src/main/java/com/juick/www/rss/RepliesView.java b/src/main/java/com/juick/www/rss/RepliesView.java
index 9cb98c94..83c8e104 100644
--- a/src/main/java/com/juick/www/rss/RepliesView.java
+++ b/src/main/java/com/juick/www/rss/RepliesView.java
@@ -30,15 +30,17 @@ import com.rometools.rome.feed.rss.Channel;
import com.rometools.rome.feed.rss.Description;
import com.rometools.rome.feed.rss.Guid;
import com.rometools.rome.feed.rss.Item;
+
+import jakarta.annotation.PostConstruct;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.view.feed.AbstractRssFeedView;
import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
@@ -59,9 +61,9 @@ public class RepliesView extends AbstractRssFeedView {
@SuppressWarnings("unchecked")
@Override
- protected @Nonnull List<Item> buildFeedItems(@Nonnull Map<String, Object> model,
- @Nonnull HttpServletRequest request,
- @Nonnull HttpServletResponse response) {
+ protected @Nonnull List<Item> buildFeedItems(Map<String, Object> model,
+ HttpServletRequest request,
+ HttpServletResponse response) {
List<ResponseReply> msgs = (List<ResponseReply>)model.get("messages");
return msgs.stream().map(this::createRssItem).collect(Collectors.toList());
}
diff --git a/src/main/java/com/mitchellbosecke/pebble/extension/FormatterExtension.java b/src/main/java/com/mitchellbosecke/pebble/extension/FormatterExtension.java
index 9feca15b..bd8ba19d 100644
--- a/src/main/java/com/mitchellbosecke/pebble/extension/FormatterExtension.java
+++ b/src/main/java/com/mitchellbosecke/pebble/extension/FormatterExtension.java
@@ -19,6 +19,9 @@ package com.mitchellbosecke.pebble.extension;
import com.mitchellbosecke.pebble.extension.filters.*;
+import io.pebbletemplates.pebble.extension.AbstractExtension;
+import io.pebbletemplates.pebble.extension.Filter;
+
import java.util.HashMap;
import java.util.Map;
diff --git a/src/main/java/com/mitchellbosecke/pebble/extension/filters/FormatMessageFilter.java b/src/main/java/com/mitchellbosecke/pebble/extension/filters/FormatMessageFilter.java
index 41c80691..0f4ba034 100644
--- a/src/main/java/com/mitchellbosecke/pebble/extension/filters/FormatMessageFilter.java
+++ b/src/main/java/com/mitchellbosecke/pebble/extension/filters/FormatMessageFilter.java
@@ -19,10 +19,10 @@ package com.mitchellbosecke.pebble.extension.filters;
import com.juick.model.Message;
import com.juick.util.MessageUtils;
-import com.mitchellbosecke.pebble.extension.Filter;
-import com.mitchellbosecke.pebble.extension.escaper.SafeString;
-import com.mitchellbosecke.pebble.template.EvaluationContext;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.extension.Filter;
+import io.pebbletemplates.pebble.extension.escaper.SafeString;
+import io.pebbletemplates.pebble.template.EvaluationContext;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
diff --git a/src/main/java/com/mitchellbosecke/pebble/extension/filters/PrettyTimeFilter.java b/src/main/java/com/mitchellbosecke/pebble/extension/filters/PrettyTimeFilter.java
index 9c79e563..f5d82bfe 100644
--- a/src/main/java/com/mitchellbosecke/pebble/extension/filters/PrettyTimeFilter.java
+++ b/src/main/java/com/mitchellbosecke/pebble/extension/filters/PrettyTimeFilter.java
@@ -18,9 +18,9 @@
package com.mitchellbosecke.pebble.extension.filters;
import com.juick.util.PrettyTimeFormatter;
-import com.mitchellbosecke.pebble.extension.Filter;
-import com.mitchellbosecke.pebble.template.EvaluationContext;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.extension.Filter;
+import io.pebbletemplates.pebble.template.EvaluationContext;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
import java.time.Instant;
import java.util.Date;
diff --git a/src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java b/src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java
index 62518a09..d3a374a2 100644
--- a/src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java
+++ b/src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java
@@ -18,9 +18,9 @@
package com.mitchellbosecke.pebble.extension.filters;
import com.juick.model.Tag;
-import com.mitchellbosecke.pebble.extension.Filter;
-import com.mitchellbosecke.pebble.template.EvaluationContext;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.extension.Filter;
+import io.pebbletemplates.pebble.template.EvaluationContext;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
import java.util.Collection;
import java.util.List;
diff --git a/src/main/java/com/mitchellbosecke/pebble/extension/filters/TimestampFilter.java b/src/main/java/com/mitchellbosecke/pebble/extension/filters/TimestampFilter.java
index 5fc93805..dfe93673 100644
--- a/src/main/java/com/mitchellbosecke/pebble/extension/filters/TimestampFilter.java
+++ b/src/main/java/com/mitchellbosecke/pebble/extension/filters/TimestampFilter.java
@@ -17,9 +17,9 @@
package com.mitchellbosecke.pebble.extension.filters;
-import com.mitchellbosecke.pebble.extension.Filter;
-import com.mitchellbosecke.pebble.template.EvaluationContext;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.extension.Filter;
+import io.pebbletemplates.pebble.template.EvaluationContext;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
import java.time.Instant;
import java.util.Date;
diff --git a/src/main/java/org/apache/commons/mail/util/MimeMessageParser.java b/src/main/java/org/apache/commons/mail/util/MimeMessageParser.java
new file mode 100644
index 00000000..ec36b7cb
--- /dev/null
+++ b/src/main/java/org/apache/commons/mail/util/MimeMessageParser.java
@@ -0,0 +1,452 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.mail.util;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.activation.DataHandler;
+import jakarta.activation.DataSource;
+import jakarta.mail.Message;
+import jakarta.mail.MessagingException;
+import jakarta.mail.Multipart;
+import jakarta.mail.Part;
+import jakarta.mail.internet.ContentType;
+import jakarta.mail.internet.InternetAddress;
+import jakarta.mail.internet.MimeBodyPart;
+import jakarta.mail.internet.MimeMessage;
+import jakarta.mail.internet.MimePart;
+import jakarta.mail.internet.MimeUtility;
+import jakarta.mail.internet.ParseException;
+import jakarta.mail.util.ByteArrayDataSource;
+
+/**
+ * Parses a MimeMessage and stores the individual parts such a plain text,
+ * HTML text and attachments.
+ *
+ * @since 1.3
+ */
+public class MimeMessageParser
+{
+ /** The MimeMessage to convert */
+ private final MimeMessage mimeMessage;
+
+ /** Plain mail content from MimeMessage */
+ private String plainContent;
+
+ /** Html mail content from MimeMessage */
+ private String htmlContent;
+
+ /** List of attachments of MimeMessage */
+ private final List<DataSource> attachmentList;
+
+ /** Attachments stored by their content-id */
+ private final Map<String, DataSource> cidMap;
+
+ /** Is this a Multipart email */
+ private boolean isMultiPart;
+
+ /**
+ * Constructs an instance with the MimeMessage to be extracted.
+ *
+ * @param message the message to parse
+ */
+ public MimeMessageParser(final MimeMessage message)
+ {
+ attachmentList = new ArrayList<>();
+ cidMap = new HashMap<>();
+ this.mimeMessage = message;
+ this.isMultiPart = false;
+ }
+
+ /**
+ * Does the actual extraction.
+ *
+ * @return this instance
+ * @throws Exception parsing the mime message failed
+ */
+ public MimeMessageParser parse() throws Exception
+ {
+ this.parse(null, mimeMessage);
+ return this;
+ }
+
+ /**
+ * @return the 'to' recipients of the message
+ * @throws Exception determining the recipients failed
+ */
+ public List<jakarta.mail.Address> getTo() throws Exception
+ {
+ final jakarta.mail.Address[] recipients = this.mimeMessage.getRecipients(Message.RecipientType.TO);
+ return recipients != null ? Arrays.asList(recipients) : new ArrayList<>();
+ }
+
+ /**
+ * @return the 'cc' recipients of the message
+ * @throws Exception determining the recipients failed
+ */
+ public List<jakarta.mail.Address> getCc() throws Exception
+ {
+ final jakarta.mail.Address[] recipients = this.mimeMessage.getRecipients(Message.RecipientType.CC);
+ return recipients != null ? Arrays.asList(recipients) : new ArrayList<>();
+ }
+
+ /**
+ * @return the 'bcc' recipients of the message
+ * @throws Exception determining the recipients failed
+ */
+ public List<jakarta.mail.Address> getBcc() throws Exception
+ {
+ final jakarta.mail.Address[] recipients = this.mimeMessage.getRecipients(Message.RecipientType.BCC);
+ return recipients != null ? Arrays.asList(recipients) : new ArrayList<>();
+ }
+
+ /**
+ * @return the 'from' field of the message
+ * @throws Exception parsing the mime message failed
+ */
+ public String getFrom() throws Exception
+ {
+ final jakarta.mail.Address[] addresses = this.mimeMessage.getFrom();
+ if (addresses == null || addresses.length == 0)
+ {
+ return null;
+ }
+ return ((InternetAddress) addresses[0]).getAddress();
+ }
+
+ /**
+ * @return the 'replyTo' address of the email
+ * @throws Exception parsing the mime message failed
+ */
+ public String getReplyTo() throws Exception
+ {
+ final jakarta.mail.Address[] addresses = this.mimeMessage.getReplyTo();
+ if (addresses == null || addresses.length == 0)
+ {
+ return null;
+ }
+ return ((InternetAddress) addresses[0]).getAddress();
+ }
+
+ /**
+ * @return the mail subject
+ * @throws Exception parsing the mime message failed
+ */
+ public String getSubject() throws Exception
+ {
+ return this.mimeMessage.getSubject();
+ }
+
+ /**
+ * Extracts the content of a MimeMessage recursively.
+ *
+ * @param parent the parent multi-part
+ * @param part the current MimePart
+ * @throws MessagingException parsing the MimeMessage failed
+ * @throws IOException parsing the MimeMessage failed
+ */
+ protected void parse(final Multipart parent, final MimePart part)
+ throws MessagingException, IOException
+ {
+ if (isMimeType(part, "text/plain") && plainContent == null
+ && !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition()))
+ {
+ plainContent = (String) part.getContent();
+ }
+ else
+ {
+ if (isMimeType(part, "text/html") && htmlContent == null
+ && !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition()))
+ {
+ htmlContent = (String) part.getContent();
+ }
+ else
+ {
+ if (isMimeType(part, "multipart/*"))
+ {
+ this.isMultiPart = true;
+ final Multipart mp = (Multipart) part.getContent();
+ final int count = mp.getCount();
+
+ // iterate over all MimeBodyPart
+
+ for (int i = 0; i < count; i++)
+ {
+ parse(mp, (MimeBodyPart) mp.getBodyPart(i));
+ }
+ }
+ else
+ {
+ final String cid = stripContentId(part.getContentID());
+ final DataSource ds = createDataSource(parent, part);
+ if (cid != null)
+ {
+ this.cidMap.put(cid, ds);
+ }
+ this.attachmentList.add(ds);
+ }
+ }
+ }
+ }
+
+ /**
+ * Strips the content id of any whitespace and angle brackets.
+ * @param contentId the string to strip
+ * @return a stripped version of the content id
+ */
+ private String stripContentId(final String contentId)
+ {
+ if (contentId == null)
+ {
+ return null;
+ }
+ return contentId.trim().replaceAll("[\\<\\>]", "");
+ }
+
+ /**
+ * Checks whether the MimePart contains an object of the given mime type.
+ *
+ * @param part the current MimePart
+ * @param mimeType the mime type to check
+ * @return {@code true} if the MimePart matches the given mime type, {@code false} otherwise
+ * @throws MessagingException parsing the MimeMessage failed
+ * @throws IOException parsing the MimeMessage failed
+ */
+ private boolean isMimeType(final MimePart part, final String mimeType)
+ throws MessagingException, IOException
+ {
+ // Do not use part.isMimeType(String) as it is broken for MimeBodyPart
+ // and does not really check the actual content type.
+
+ try
+ {
+ final ContentType ct = new ContentType(part.getDataHandler().getContentType());
+ return ct.match(mimeType);
+ }
+ catch (final ParseException ex)
+ {
+ return part.getContentType().equalsIgnoreCase(mimeType);
+ }
+ }
+
+ /**
+ * Parses the MimePart to create a DataSource.
+ *
+ * @param parent the parent multi-part
+ * @param part the current part to be processed
+ * @return the DataSource
+ * @throws MessagingException creating the DataSource failed
+ * @throws IOException creating the DataSource failed
+ */
+ protected DataSource createDataSource(final Multipart parent, final MimePart part)
+ throws MessagingException, IOException
+ {
+ final DataHandler dataHandler = part.getDataHandler();
+ final DataSource dataSource = dataHandler.getDataSource();
+ final String contentType = getBaseMimeType(dataSource.getContentType());
+ byte[] content;
+ try (InputStream inputStream = dataSource.getInputStream())
+ {
+ content = this.getContent(inputStream);
+ }
+ final ByteArrayDataSource result = new ByteArrayDataSource(content, contentType);
+ final String dataSourceName = getDataSourceName(part, dataSource);
+ result.setName(dataSourceName);
+ return result;
+ }
+
+ /** @return Returns the mimeMessage. */
+ public MimeMessage getMimeMessage()
+ {
+ return mimeMessage;
+ }
+
+ /** @return Returns the isMultiPart. */
+ public boolean isMultipart()
+ {
+ return isMultiPart;
+ }
+
+ /** @return Returns the plainContent if any */
+ public String getPlainContent()
+ {
+ return plainContent;
+ }
+
+ /** @return Returns the attachmentList. */
+ public List<DataSource> getAttachmentList()
+ {
+ return attachmentList;
+ }
+
+ /**
+ * Returns a collection of all content-ids in the parsed message.
+ * <p>
+ * The content-ids are stripped of any angle brackets, i.e. "part1" instead
+ * of "&lt;part1&gt;".
+ *
+ * @return the collection of content ids.
+ * @since 1.3.4
+ */
+ public Collection<String> getContentIds()
+ {
+ return Collections.unmodifiableSet(cidMap.keySet());
+ }
+
+ /** @return Returns the htmlContent if any */
+ public String getHtmlContent()
+ {
+ return htmlContent;
+ }
+
+ /** @return true if a plain content is available */
+ public boolean hasPlainContent()
+ {
+ return this.plainContent != null;
+ }
+
+ /** @return true if HTML content is available */
+ public boolean hasHtmlContent()
+ {
+ return this.htmlContent != null;
+ }
+
+ /** @return true if attachments are available */
+ public boolean hasAttachments()
+ {
+ return !this.attachmentList.isEmpty();
+ }
+
+ /**
+ * Find an attachment using its name.
+ *
+ * @param name the name of the attachment
+ * @return the corresponding datasource or null if nothing was found
+ */
+ public DataSource findAttachmentByName(final String name)
+ {
+ DataSource dataSource;
+
+ for (final DataSource element : getAttachmentList()) {
+ dataSource = element;
+ if (name.equalsIgnoreCase(dataSource.getName()))
+ {
+ return dataSource;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Find an attachment using its content-id.
+ * <p>
+ * The content-id must be stripped of any angle brackets,
+ * i.e. "part1" instead of "&lt;part1&gt;".
+ *
+ * @param cid the content-id of the attachment
+ * @return the corresponding datasource or null if nothing was found
+ * @since 1.3.4
+ */
+ public DataSource findAttachmentByCid(final String cid)
+ {
+ final DataSource dataSource = cidMap.get(cid);
+ return dataSource;
+ }
+
+ /**
+ * Determines the name of the data source if it is not already set.
+ *
+ * @param part the mail part
+ * @param dataSource the data source
+ * @return the name of the data source or {@code null} if no name can be determined
+ * @throws MessagingException accessing the part failed
+ * @throws UnsupportedEncodingException decoding the text failed
+ */
+ protected String getDataSourceName(final Part part, final DataSource dataSource)
+ throws MessagingException, UnsupportedEncodingException
+ {
+ String result = dataSource.getName();
+
+ if (result == null || result.isEmpty())
+ {
+ result = part.getFileName();
+ }
+
+ if (result != null && !result.isEmpty())
+ {
+ result = MimeUtility.decodeText(result);
+ }
+ else
+ {
+ result = null;
+ }
+
+ return result;
+ }
+
+ /**
+ * Read the content of the input stream.
+ *
+ * @param is the input stream to process
+ * @return the content of the input stream
+ * @throws IOException reading the input stream failed
+ */
+ private byte[] getContent(final InputStream is)
+ throws IOException
+ {
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ final BufferedInputStream isReader = new BufferedInputStream(is);
+ try (BufferedOutputStream osWriter = new BufferedOutputStream(os)) {
+ int ch;
+ while ((ch = isReader.read()) != -1)
+ {
+ osWriter.write(ch);
+ }
+ osWriter.flush();
+ return os.toByteArray();
+ }
+ }
+
+ /**
+ * Parses the mimeType.
+ *
+ * @param fullMimeType the mime type from the mail api
+ * @return the real mime type
+ */
+ private String getBaseMimeType(final String fullMimeType)
+ {
+ final int pos = fullMimeType.indexOf(';');
+ if (pos >= 0)
+ {
+ return fullMimeType.substring(0, pos);
+ }
+ return fullMimeType;
+ }
+}