mirror of https://github.com/halo-dev/halo
fix: missing ServerWebExchange in plugin template processor extension (#6877)
#### What type of PR is this? /kind bug /area core /milestone 2.20.x #### What this PR does / why we need it: 修复由 #6680 导致的插件模板处理扩展中无法获取到请求上下文的问题 #6680 修复了插件可以在模板处理扩展中通过请求上下文获取到 Halo 的 ApplicationContext 的问题 但这也引入了新的问题就是导致模板处理扩展无法获取到请求上下文,此 PR 通过判断传递给插件的 ITemplateContext 是否为 IWebContext,如果是则包装为 SecureTemplateWebContext 传递给插件,以解决此问题 #### Which issue(s) this PR fixes: Fixes #6875 #### Does this PR introduce a user-facing change? ```release-note 修复插件模板处理扩展中无法获取到请求上下文的问题 ```pull/6880/head
parent
ecc7c07d08
commit
c577deb6ee
|
@ -45,6 +45,6 @@ public class CommentElementTagProcessor extends AbstractElementTagProcessor {
|
||||||
structureHandler.replaceWith("", false);
|
structureHandler.replaceWith("", false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
commentWidget.render(new SecureTemplateContext(context), tag, structureHandler);
|
commentWidget.render(SecureTemplateContextWrapper.wrap(context), tag, structureHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class GlobalHeadInjectionProcessor extends AbstractElementModelProcessor
|
||||||
// apply processors to modelToInsert
|
// apply processors to modelToInsert
|
||||||
getTemplateHeadProcessors(context)
|
getTemplateHeadProcessors(context)
|
||||||
.concatMap(processor -> processor.process(
|
.concatMap(processor -> processor.process(
|
||||||
new SecureTemplateContext(context), modelToInsert, structureHandler)
|
SecureTemplateContextWrapper.wrap(context), modelToInsert, structureHandler)
|
||||||
)
|
)
|
||||||
.then()
|
.then()
|
||||||
.block();
|
.block();
|
||||||
|
|
|
@ -57,7 +57,8 @@ public class HaloPostTemplateHandler extends AbstractTemplateHandler {
|
||||||
var context = getContext();
|
var context = getContext();
|
||||||
for (ElementTagPostProcessor elementTagPostProcessor : postProcessors) {
|
for (ElementTagPostProcessor elementTagPostProcessor : postProcessors) {
|
||||||
tagProcessorChain = tagProcessorChain.flatMap(
|
tagProcessorChain = tagProcessorChain.flatMap(
|
||||||
tag -> elementTagPostProcessor.process(new SecureTemplateContext(context), tag)
|
tag -> elementTagPostProcessor.process(
|
||||||
|
SecureTemplateContextWrapper.wrap(context), tag)
|
||||||
.defaultIfEmpty(tag)
|
.defaultIfEmpty(tag)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package run.halo.app.theme.dialect;
|
||||||
|
|
||||||
|
import org.thymeleaf.context.Contexts;
|
||||||
|
import org.thymeleaf.context.ITemplateContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap the delegate template context to a secure template context according to whether it is a
|
||||||
|
* WebContext.
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @since 2.20.4
|
||||||
|
*/
|
||||||
|
public class SecureTemplateContextWrapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap the delegate template context to a secure template context.
|
||||||
|
*/
|
||||||
|
static SecureTemplateContext wrap(ITemplateContext delegate) {
|
||||||
|
if (Contexts.isWebContext(delegate)) {
|
||||||
|
return new SecureTemplateWebContext(delegate);
|
||||||
|
}
|
||||||
|
return new SecureTemplateContext(delegate);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package run.halo.app.theme.dialect;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.thymeleaf.context.ITemplateContext;
|
||||||
|
import org.thymeleaf.context.IWebContext;
|
||||||
|
import org.thymeleaf.web.IWebExchange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Secure template web context.
|
||||||
|
* <p>It's used to prevent some dangerous variables such as {@link ApplicationContext} from being
|
||||||
|
* accessed.
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @see SecureTemplateContext
|
||||||
|
* @since 2.20.4
|
||||||
|
*/
|
||||||
|
class SecureTemplateWebContext extends SecureTemplateContext implements IWebContext {
|
||||||
|
private final IWebContext delegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The delegate must be an instance of IWebContext to create a SecureTemplateWebContext.
|
||||||
|
*/
|
||||||
|
public SecureTemplateWebContext(ITemplateContext delegate) {
|
||||||
|
super(delegate);
|
||||||
|
if (delegate instanceof IWebContext webContext) {
|
||||||
|
this.delegate = webContext;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("The delegate must be an instance of IWebContext");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IWebExchange getExchange() {
|
||||||
|
return delegate.getExchange();
|
||||||
|
}
|
||||||
|
}
|
|
@ -63,7 +63,7 @@ public class TemplateFooterElementTagProcessor extends AbstractElementTagProcess
|
||||||
|
|
||||||
getTemplateFooterProcessors(context)
|
getTemplateFooterProcessors(context)
|
||||||
.concatMap(processor -> processor.process(
|
.concatMap(processor -> processor.process(
|
||||||
new SecureTemplateContext(context), tag, structureHandler, modelToInsert)
|
SecureTemplateContextWrapper.wrap(context), tag, structureHandler, modelToInsert)
|
||||||
)
|
)
|
||||||
.then()
|
.then()
|
||||||
.block();
|
.block();
|
||||||
|
|
|
@ -82,7 +82,8 @@ class HaloPostTemplateHandlerTest {
|
||||||
void shouldHandleStandaloneElementIfOneElementTagProcessorProvided() {
|
void shouldHandleStandaloneElementIfOneElementTagProcessorProvided() {
|
||||||
var processor = mock(ElementTagPostProcessor.class);
|
var processor = mock(ElementTagPostProcessor.class);
|
||||||
var newTag = mock(IStandaloneElementTag.class);
|
var newTag = mock(IStandaloneElementTag.class);
|
||||||
when(processor.process(new SecureTemplateContext(templateContext), standaloneElementTag))
|
when(processor.process(SecureTemplateContextWrapper.wrap(templateContext),
|
||||||
|
standaloneElementTag))
|
||||||
.thenReturn(Mono.just(newTag));
|
.thenReturn(Mono.just(newTag));
|
||||||
when(extensionGetter.getExtensionList(ElementTagPostProcessor.class))
|
when(extensionGetter.getExtensionList(ElementTagPostProcessor.class))
|
||||||
.thenReturn(List.of(processor));
|
.thenReturn(List.of(processor));
|
||||||
|
@ -97,7 +98,8 @@ class HaloPostTemplateHandlerTest {
|
||||||
void shouldHandleStandaloneElementIfTagTypeChanged() {
|
void shouldHandleStandaloneElementIfTagTypeChanged() {
|
||||||
var processor = mock(ElementTagPostProcessor.class);
|
var processor = mock(ElementTagPostProcessor.class);
|
||||||
var newTag = mock(IStandaloneElementTag.class);
|
var newTag = mock(IStandaloneElementTag.class);
|
||||||
when(processor.process(new SecureTemplateContext(templateContext), standaloneElementTag))
|
when(processor.process(SecureTemplateContextWrapper.wrap(templateContext),
|
||||||
|
standaloneElementTag))
|
||||||
.thenReturn(Mono.just(newTag));
|
.thenReturn(Mono.just(newTag));
|
||||||
when(extensionGetter.getExtensionList(ElementTagPostProcessor.class))
|
when(extensionGetter.getExtensionList(ElementTagPostProcessor.class))
|
||||||
.thenReturn(List.of(processor));
|
.thenReturn(List.of(processor));
|
||||||
|
@ -114,9 +116,10 @@ class HaloPostTemplateHandlerTest {
|
||||||
var processor2 = mock(ElementTagPostProcessor.class);
|
var processor2 = mock(ElementTagPostProcessor.class);
|
||||||
var newTag1 = mock(IStandaloneElementTag.class);
|
var newTag1 = mock(IStandaloneElementTag.class);
|
||||||
var newTag2 = mock(IStandaloneElementTag.class);
|
var newTag2 = mock(IStandaloneElementTag.class);
|
||||||
when(processor1.process(new SecureTemplateContext(templateContext), standaloneElementTag))
|
when(processor1.process(SecureTemplateContextWrapper.wrap(templateContext),
|
||||||
|
standaloneElementTag))
|
||||||
.thenReturn(Mono.just(newTag1));
|
.thenReturn(Mono.just(newTag1));
|
||||||
when(processor2.process(new SecureTemplateContext(templateContext), newTag1))
|
when(processor2.process(SecureTemplateContextWrapper.wrap(templateContext), newTag1))
|
||||||
.thenReturn(Mono.just(newTag2));
|
.thenReturn(Mono.just(newTag2));
|
||||||
when(extensionGetter.getExtensionList(ElementTagPostProcessor.class))
|
when(extensionGetter.getExtensionList(ElementTagPostProcessor.class))
|
||||||
.thenReturn(List.of(processor1, processor2));
|
.thenReturn(List.of(processor1, processor2));
|
||||||
|
@ -131,7 +134,8 @@ class HaloPostTemplateHandlerTest {
|
||||||
void shouldNotHandleIfProcessedTagTypeChanged() {
|
void shouldNotHandleIfProcessedTagTypeChanged() {
|
||||||
var processor = mock(ElementTagPostProcessor.class);
|
var processor = mock(ElementTagPostProcessor.class);
|
||||||
var newTag = mock(IOpenElementTag.class);
|
var newTag = mock(IOpenElementTag.class);
|
||||||
when(processor.process(new SecureTemplateContext(templateContext), standaloneElementTag))
|
when(processor.process(SecureTemplateContextWrapper.wrap(templateContext),
|
||||||
|
standaloneElementTag))
|
||||||
.thenReturn(Mono.just(newTag));
|
.thenReturn(Mono.just(newTag));
|
||||||
when(extensionGetter.getExtensionList(ElementTagPostProcessor.class))
|
when(extensionGetter.getExtensionList(ElementTagPostProcessor.class))
|
||||||
.thenReturn(List.of(processor));
|
.thenReturn(List.of(processor));
|
||||||
|
|
Loading…
Reference in New Issue