Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: user static resource req and fonts url api #518

Merged
merged 5 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 9 additions & 1 deletion CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@

# 0.11.7

## 新特性

- 新增`StaticEndpoint`支持获取所有字体URL的接口,所有字体放在用户工作目录下的字体目录`statics/fonts`里

## 优化

- 静态文件加载逻辑,通过URL访问`/static/**`,支持在下列三种目录加载静态文件:
1. 用户工作目录下的静态目录`statics`目录下
2. `ClassPath`的`static`目录下
3. `ClassPath`的`templates/static`目录下
- [WIP] 条目收藏形式优化,一次性提交收藏类型和标签

## 插件
Expand All @@ -14,7 +22,7 @@

- [WIP] 拉取条目时,转换对应的标签

### 安全修复
## 安全修复

- console crypto-js: [crypto-js PBKDF2 1,000 times weaker than specified in 1993 and 1.3M times weaker than current standard #18](https://github.com/ikaros-dev/ikaros/security/dependabot/18)
- console axios: [Axios Cross-Site Request Forgery Vulnerability #21](https://github.com/ikaros-dev/ikaros/security/dependabot/21)
Expand Down
2 changes: 2 additions & 0 deletions api/src/main/java/run/ikaros/api/constant/AppConst.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public interface AppConst {
String LOGOUT_SUCCESS_LOCATION = "/console/?logout";
Duration BLOCK_TIMEOUT = Duration.ofMillis(2000L);
String CACHE_DIR_NAME = "caches";
String STATIC_DIR_NAME = "statics";
String STATIC_FONT_DIR_NAME = "fonts";

/**
* currentTime / TotalTime .
Expand Down
10 changes: 8 additions & 2 deletions server/src/main/java/run/ikaros/server/config/WebFluxConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import static org.springframework.util.ResourceUtils.FILE_URL_PREFIX;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static run.ikaros.api.constant.AppConst.STATIC_DIR_NAME;

import java.io.File;
import java.net.URI;
import java.time.Duration;
import java.util.List;
Expand Down Expand Up @@ -127,9 +129,13 @@ public void addResourceHandlers(ResourceHandlerRegistry registry) {
.addResolver(new EncodedResourceResolver())
.addResolver(new PathResourceResolver());

// Add thymeleaf static resource
// Add user and thymeleaf static resource
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/templates/static/");
.addResourceLocations(
"file:" + ikarosProperties.getWorkDir().resolve(STATIC_DIR_NAME)
+ File.separatorChar,
"classpath:/static/",
"classpath:/templates/static/");

// Register theme static files path
// /theme/{name}/static => classpath:/templates/theme/{name}/static/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package run.ikaros.server.core.statics;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.fn.builders.apiresponse.Builder;
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import run.ikaros.api.constant.AppConst;
import run.ikaros.api.constant.OpenApiConst;
import run.ikaros.api.infra.properties.IkarosProperties;
import run.ikaros.server.endpoint.CoreEndpoint;

@Slf4j
@Component
public class StaticEndpoint implements CoreEndpoint {
private final IkarosProperties ikarosProperties;

public StaticEndpoint(IkarosProperties ikarosProperties) {
this.ikarosProperties = ikarosProperties;
}

@Override
public RouterFunction<ServerResponse> endpoint() {
var tag = OpenApiConst.CORE_VERSION + "/static";
return SpringdocRouteBuilder.route()
.GET("/static/fonts", this::listStaticsFonts,
builder -> builder.operationId("ListStaticsFonts")
.tag(tag).description("List font dir all fonts in work statics dir.")
.response(Builder.responseBuilder().implementationArray(String.class)))
.build();
}

private Mono<ServerResponse> listStaticsFonts(ServerRequest request) {
final String fontBaseUrl = "/static/" + AppConst.STATIC_FONT_DIR_NAME + '/';
Path staticsDirPath = ikarosProperties.getWorkDir().resolve(AppConst.STATIC_DIR_NAME);
if (Files.notExists(staticsDirPath)) {
try {
Files.createDirectory(staticsDirPath);
} catch (IOException e) {
throw new RuntimeException(e);
}
return ServerResponse.notFound().build();
}
Path staticsFontsDirPath = staticsDirPath.resolve(AppConst.STATIC_FONT_DIR_NAME);
if (Files.notExists(staticsFontsDirPath)) {
try {
Files.createDirectory(staticsFontsDirPath);
} catch (IOException e) {
throw new RuntimeException(e);
}
return ServerResponse.notFound().build();
}

File[] files = staticsFontsDirPath.toFile().listFiles();

if (Objects.isNull(files)) {
return ServerResponse.notFound().build();
}

List<String> fontUrls = Arrays.stream(files)
.map(File::getName)
.map(name -> fontBaseUrl + name)
.toList();
return ServerResponse.ok().bodyValue(fontUrls);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import reactor.core.publisher.Mono;
import run.ikaros.api.constant.OpenApiConst;
import run.ikaros.api.constant.SecurityConst;

@Slf4j
Expand All @@ -15,6 +16,12 @@ public class RequestAuthorizationManager
@Override
public Mono<AuthorizationDecision> check(Mono<Authentication> authentication,
AuthorizationContext object) {
boolean urlStartWithApiStatic =
object.getExchange().getRequest().getURI().getPath()
.startsWith("/api/" + OpenApiConst.CORE_VERSION + "/static/");
if (urlStartWithApiStatic) {
return authentication.map(auth -> new AuthorizationDecision(true));
}
return authentication.map(auth -> new AuthorizationDecision(
auth.getAuthorities()
.contains(new SimpleGrantedAuthority(
Expand Down