diff --git a/build.gradle b/build.gradle index 0b3c607f2..fc87f6d2b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { - id 'org.springframework.boot' version '3.0.0-M5' - id 'io.spring.dependency-management' version '1.0.14.RELEASE' + id 'org.springframework.boot' version '3.0.0-RC1' + id 'io.spring.dependency-management' version '1.1.0' id "checkstyle" id 'java' } @@ -15,13 +15,9 @@ checkstyle { } repositories { - maven { url 'https://maven.aliyun.com/repository/public/' } - maven { url 'https://maven.aliyun.com/repository/spring/' } - maven { url 'https://repo.spring.io/milestone' } - - mavenLocal() mavenCentral() + maven { url 'https://repo.spring.io/milestone' } } diff --git a/settings.gradle b/settings.gradle index eeb1ee70c..da157adfe 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,7 +1,5 @@ pluginManagement { repositories { - maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } - maven { url 'https://maven.aliyun.com/repository/spring-plugin' } maven { url 'https://repo.spring.io/milestone' } gradlePluginPortal() } diff --git a/src/main/java/run/halo/app/security/CsrfConfigurer.java b/src/main/java/run/halo/app/security/CsrfConfigurer.java index 6f2bf4cd4..6161556ff 100644 --- a/src/main/java/run/halo/app/security/CsrfConfigurer.java +++ b/src/main/java/run/halo/app/security/CsrfConfigurer.java @@ -5,6 +5,7 @@ import static org.springframework.security.web.server.util.matcher.ServerWebExch import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.web.server.csrf.CookieServerCsrfTokenRepository; import org.springframework.security.web.server.csrf.CsrfWebFilter; +import org.springframework.security.web.server.csrf.ServerCsrfTokenRequestAttributeHandler; import org.springframework.security.web.server.util.matcher.AndServerWebExchangeMatcher; import org.springframework.security.web.server.util.matcher.NegatedServerWebExchangeMatcher; import org.springframework.stereotype.Component; @@ -21,6 +22,9 @@ public class CsrfConfigurer implements SecurityConfigurer { )); http.csrf().csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()) + // TODO Use XorServerCsrfTokenRequestAttributeHandler instead when console implements + // the algorithm + .csrfTokenRequestHandler(new ServerCsrfTokenRequestAttributeHandler()) .requireCsrfProtectionMatcher(csrfMatcher); } diff --git a/src/main/java/run/halo/app/security/authentication/pat/PatAuthenticationConverter.java b/src/main/java/run/halo/app/security/authentication/pat/PatAuthenticationConverter.java index c55bdc609..205a23ade 100644 --- a/src/main/java/run/halo/app/security/authentication/pat/PatAuthenticationConverter.java +++ b/src/main/java/run/halo/app/security/authentication/pat/PatAuthenticationConverter.java @@ -1,8 +1,8 @@ package run.halo.app.security.authentication.pat; import org.springframework.security.core.Authentication; -import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; -import org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter; +import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; +import org.springframework.security.oauth2.server.resource.web.server.authentication.ServerBearerTokenAuthenticationConverter; import org.springframework.security.web.server.authentication.ServerAuthenticationConverter; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; diff --git a/src/main/java/run/halo/app/theme/ThemeConfiguration.java b/src/main/java/run/halo/app/theme/ThemeConfiguration.java index 520d2445f..88fc83e5e 100644 --- a/src/main/java/run/halo/app/theme/ThemeConfiguration.java +++ b/src/main/java/run/halo/app/theme/ThemeConfiguration.java @@ -11,11 +11,9 @@ import org.springframework.http.MediaType; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; -import org.thymeleaf.extras.java8time.dialect.Java8TimeDialect; import run.halo.app.infra.properties.HaloProperties; import run.halo.app.infra.utils.FilePathUtils; import run.halo.app.theme.dialect.LinkExpressionObjectDialect; -import run.halo.app.theme.dialect.ThemeJava8TimeDialect; /** * @author guqing @@ -49,11 +47,6 @@ public class ThemeConfiguration { "themes", themeName, "templates", "assets", resource); } - @Bean - Java8TimeDialect java8TimeDialect() { - return new ThemeJava8TimeDialect(); - } - @Bean LinkExpressionObjectDialect linkExpressionObjectDialect() { return new LinkExpressionObjectDialect(); diff --git a/src/main/java/run/halo/app/theme/dialect/DefaultJava8TimeExpressionFactory.java b/src/main/java/run/halo/app/theme/dialect/DefaultJava8TimeExpressionFactory.java deleted file mode 100644 index 2cbc8e8a7..000000000 --- a/src/main/java/run/halo/app/theme/dialect/DefaultJava8TimeExpressionFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -package run.halo.app.theme.dialect; - -import static run.halo.app.theme.ThemeLocaleContextResolver.TIME_ZONE_REQUEST_ATTRIBUTE_NAME; - -import java.util.TimeZone; -import org.thymeleaf.context.IExpressionContext; -import org.thymeleaf.extras.java8time.dialect.Java8TimeExpressionFactory; -import org.thymeleaf.extras.java8time.expression.Temporals; - -/** - * @author guqing - * @since 2.0.0 - */ -public class DefaultJava8TimeExpressionFactory extends Java8TimeExpressionFactory { - private static final String TEMPORAL_EVALUATION_VARIABLE_NAME = "temporals"; - - @Override - public Object buildObject(IExpressionContext context, String expressionObjectName) { - TimeZone timeZone = (TimeZone) context.getVariable(TIME_ZONE_REQUEST_ATTRIBUTE_NAME); - if (timeZone == null) { - timeZone = TimeZone.getDefault(); - } - if (TEMPORAL_EVALUATION_VARIABLE_NAME.equals(expressionObjectName)) { - return new Temporals(context.getLocale(), timeZone.toZoneId()); - } - return null; - } -} diff --git a/src/main/java/run/halo/app/theme/dialect/ThemeJava8TimeDialect.java b/src/main/java/run/halo/app/theme/dialect/ThemeJava8TimeDialect.java deleted file mode 100644 index 87829ef86..000000000 --- a/src/main/java/run/halo/app/theme/dialect/ThemeJava8TimeDialect.java +++ /dev/null @@ -1,18 +0,0 @@ -package run.halo.app.theme.dialect; - -import org.thymeleaf.expression.IExpressionObjectFactory; -import org.thymeleaf.extras.java8time.dialect.Java8TimeDialect; - -/** - * @author guqing - * @since 2.0.0 - */ -public class ThemeJava8TimeDialect extends Java8TimeDialect { - private final IExpressionObjectFactory expressionObjectFactory = - new DefaultJava8TimeExpressionFactory(); - - @Override - public IExpressionObjectFactory getExpressionObjectFactory() { - return expressionObjectFactory; - } -} diff --git a/src/test/java/run/halo/app/theme/dialect/ThemeJava8TimeDialectIntegrationTest.java b/src/test/java/run/halo/app/theme/dialect/ThemeJava8TimeDialectIntegrationTest.java deleted file mode 100644 index 64374da63..000000000 --- a/src/test/java/run/halo/app/theme/dialect/ThemeJava8TimeDialectIntegrationTest.java +++ /dev/null @@ -1,147 +0,0 @@ -package run.halo.app.theme.dialect; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; -import static run.halo.app.theme.ThemeLocaleContextResolver.TIME_ZONE_COOKIE_NAME; - -import java.io.FileNotFoundException; -import java.net.URL; -import java.nio.file.Paths; -import java.time.Instant; -import java.time.ZoneId; -import java.util.Locale; -import java.util.Map; -import java.util.TimeZone; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.boot.test.mock.mockito.SpyBean; -import org.springframework.context.annotation.Bean; -import org.springframework.http.MediaType; -import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.util.ResourceUtils; -import org.springframework.web.reactive.function.server.RequestPredicates; -import org.springframework.web.reactive.function.server.RouterFunction; -import org.springframework.web.reactive.function.server.RouterFunctions; -import org.springframework.web.reactive.function.server.ServerResponse; -import org.thymeleaf.extras.java8time.expression.Temporals; -import reactor.core.publisher.Mono; -import run.halo.app.theme.ThemeContext; -import run.halo.app.theme.ThemeResolver; - -/** - * Tests for {@link ThemeJava8TimeDialect}. - * - * @author guqing - * @since 2.0.0 - */ -@SpringBootTest -@AutoConfigureWebTestClient -class ThemeJava8TimeDialectIntegrationTest { - private static final Instant INSTANT = Instant.now(); - - // @Autowired - @SpyBean - private ThemeResolver themeResolver; - - private URL defaultThemeUrl; - - @Autowired - private WebTestClient webTestClient; - - private TimeZone defaultTimeZone; - - @BeforeEach - void setUp() throws FileNotFoundException { - defaultThemeUrl = ResourceUtils.getURL("classpath:themes/default"); - when(themeResolver.getTheme(any(ServerHttpRequest.class))) - .thenReturn(Mono.just(createDefaultContext())); - defaultTimeZone = TimeZone.getDefault(); - } - - @AfterEach - void tearDown() { - TimeZone.setDefault(defaultTimeZone); - } - - @Test - void temporalsInAmerica() { - TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles"); - TimeZone.setDefault(timeZone); - - assertTemporals(timeZone); - } - - @Test - void temporalsInChina() { - TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai"); - TimeZone.setDefault(timeZone); - - assertTemporals(timeZone); - } - - - @Test - void timeZoneFromCookie() { - TimeZone timeZone = TimeZone.getTimeZone("Africa/Accra"); - String formatTime = timeZoneTemporalFormat(timeZone.toZoneId()); - - webTestClient.get() - .uri("/timezone?language=zh") - .cookie(TIME_ZONE_COOKIE_NAME, timeZone.toZoneId().toString()) - .exchange() - .expectStatus() - .isOk() - .expectBody(String.class) - .isEqualTo(String.format("
%s
\n", formatTime)); - } - - @Test - void invalidTimeZone() { - TimeZone timeZone = TimeZone.getTimeZone("invalid/timezone"); - //the GMT zone if the given ID cannot be understood. - assertThat(timeZone.toZoneId().toString()).isEqualTo("GMT"); - } - - private void assertTemporals(TimeZone timeZone) { - String formatTime = timeZoneTemporalFormat(timeZone.toZoneId()); - webTestClient.get() - .uri("/timezone?language=zh") - .exchange() - .expectStatus() - .isOk() - .expectBody(String.class) - .isEqualTo(String.format("%s
\n", formatTime)); - } - - private String timeZoneTemporalFormat(ZoneId zoneId) { - Temporals temporals = new Temporals(Locale.CHINESE, zoneId); - return temporals.format(INSTANT, "yyyy-MM-dd HH:mm:ss"); - } - - ThemeContext createDefaultContext() { - return ThemeContext.builder() - .name("default") - .path(Paths.get(defaultThemeUrl.getPath())) - .active(true) - .build(); - } - - @TestConfiguration - static class MessageResolverConfig { - - @Bean - RouterFunction