diff --git a/src/main/java/run/halo/alist/config/AListProperties.java b/src/main/java/run/halo/alist/config/AListProperties.java index 5f8bf95..7972e04 100644 --- a/src/main/java/run/halo/alist/config/AListProperties.java +++ b/src/main/java/run/halo/alist/config/AListProperties.java @@ -22,13 +22,9 @@ public class AListProperties { */ private String site; /** - * AList 挂载路径. + * AList 基本路径下文件夹的路径. */ private String path; - /** - * AList 基本路径. - */ - private String basePath; /** * Secret name. */ diff --git a/src/main/java/run/halo/alist/controller/PolicyConfigValidationController.java b/src/main/java/run/halo/alist/controller/PolicyConfigValidationController.java index 9e61035..e88cad3 100644 --- a/src/main/java/run/halo/alist/controller/PolicyConfigValidationController.java +++ b/src/main/java/run/halo/alist/controller/PolicyConfigValidationController.java @@ -1,6 +1,5 @@ package run.halo.alist.controller; -import java.util.Objects; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.core.ParameterizedTypeReference; @@ -8,12 +7,13 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import run.halo.alist.endpoint.AListAttachmentHandler; import run.halo.alist.config.AListProperties; import run.halo.alist.dto.AListResult; -import run.halo.alist.dto.response.AListStorageListRes; +import run.halo.alist.dto.request.AListGetFileInfoReq; +import run.halo.alist.dto.response.AListGetCurrentUserInfoRes; +import run.halo.alist.dto.response.AListGetFileInfoRes; +import run.halo.alist.endpoint.AListAttachmentHandler; import run.halo.alist.exception.AListIllegalArgumentException; import run.halo.app.plugin.ApiVersion; @@ -39,31 +39,68 @@ public Mono validatePolicyConfig(@RequestBody AListProperties properties) .flatMap(token -> handler.getWebClients() .get(properties.getSite()) .get() - .uri("/api/admin/storage/list") + .uri("/api/me") .header(HttpHeaders.AUTHORIZATION, token) .retrieve() .bodyToMono( - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>() { }) .flatMap(response -> { - if (response.getCode().equals("200")) { - return Flux.fromIterable(response.getData().getContent()) - .filter(volume -> Objects.equals(volume.getMountPath(), - properties.getPath())) - .switchIfEmpty(Mono.error(new AListIllegalArgumentException( - "The mount path does not exist"))) - .all(volume -> !volume.isDisabled()) - .filter(isValid -> isValid) - .switchIfEmpty(Mono.error(new AListIllegalArgumentException( - "The storage is disabled"))) - .then(); - } else if (response.getCode().equals("403")) { + if (!response.getCode().equals("200")) { + return Mono.error(new AListIllegalArgumentException( + "Wrong Username Or Password")); + } + AListGetCurrentUserInfoRes userInfo = response.getData(); + if (userInfo.isDisabled()) { return Mono.error(new AListIllegalArgumentException( - "You are not an admin")); + "User is disabled")); } - return Mono.error(new AListIllegalArgumentException( - "Wrong Username Or Password")); - })) + return handler.getWebClients() + .get(properties.getSite()) + .post() + .uri("/api/fs/get") + .header(HttpHeaders.AUTHORIZATION, token) + .body(Mono.just(AListGetFileInfoReq.builder() + .path("/") + .build()), + AListGetFileInfoReq.class) + .retrieve() + .bodyToMono( + new ParameterizedTypeReference>() { + }) + .flatMap(res -> { + // 验证当前基本路径是否可用 + if (!res.getCode().equals("200")) { + return Mono.error( + new AListIllegalArgumentException(res.getMessage())); + } + // 管理员用户拥有所有权限 + if (userInfo.getRole() == 2) { + return Mono.empty(); + } + // 普通用户验证权限 + int permission = userInfo.getPermission(); + StringBuilder sb = new StringBuilder(); + if ((permission & 2) == 0) { + sb.append(" 无需密码访问权限"); + } + if ((permission & 8) == 0) { + sb.append(" 创建目录或上传权限 "); + } + if ((permission & 128) == 0) { + sb.append(" 删除权限 "); + } + if (!sb.isEmpty()) { + sb.append("未开启"); + return Mono.error( + new AListIllegalArgumentException(sb.toString())); + } + return Mono.empty(); + }); + + }) + + ) ); } } diff --git a/src/main/java/run/halo/alist/dto/response/AListGetCurrentUserInfoRes.java b/src/main/java/run/halo/alist/dto/response/AListGetCurrentUserInfoRes.java new file mode 100644 index 0000000..8c25679 --- /dev/null +++ b/src/main/java/run/halo/alist/dto/response/AListGetCurrentUserInfoRes.java @@ -0,0 +1,36 @@ +package run.halo.alist.dto.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author Roozen + * @version 1.0 + * 2024/8/2 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AListGetCurrentUserInfoRes { + private int id; + private String username; + private String password; + /** + * 基本路径 + */ + @JsonProperty("base_path") + private String basePath; + private int role; + private boolean disabled; + private int permission; + @JsonProperty("sso_id") + private String ssoId; + /** + * 是否开启二步验证 + */ + private boolean otp; +} diff --git a/src/main/java/run/halo/alist/endpoint/AListAttachmentHandler.java b/src/main/java/run/halo/alist/endpoint/AListAttachmentHandler.java index c4b2820..c967823 100644 --- a/src/main/java/run/halo/alist/endpoint/AListAttachmentHandler.java +++ b/src/main/java/run/halo/alist/endpoint/AListAttachmentHandler.java @@ -24,6 +24,7 @@ import org.springframework.http.codec.multipart.FilePart; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientRequestException; import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriUtils; import reactor.core.publisher.Mono; @@ -33,6 +34,7 @@ import run.halo.alist.dto.request.AListGetFileInfoReq; import run.halo.alist.dto.request.AListLoginReq; import run.halo.alist.dto.request.AListRemoveFileReq; +import run.halo.alist.dto.response.AListGetCurrentUserInfoRes; import run.halo.alist.dto.response.AListGetFileInfoRes; import run.halo.alist.dto.response.AListLoginRes; import run.halo.alist.dto.response.AListUploadAsTaskRes; @@ -117,11 +119,8 @@ public Mono upload(UploadContext uploadContext) { var metadata = new Metadata(); metadata.setName(UUID.randomUUID().toString()); metadata.setAnnotations( - Map.of(Constant.EXTERNAL_LINK_ANNO_KEY, - UriUtils.encodePath( - properties.getSite() + "/d" + properties.getPath() + "/" - + file.name(), - StandardCharsets.UTF_8))); + Map.of(Constant.EXTERNAL_LINK_ANNO_KEY, "")); + var spec = new Attachment.AttachmentSpec(); SimpleFilePart simpleFilePart = (SimpleFilePart) file; spec.setDisplayName(simpleFilePart.filename()); @@ -183,7 +182,9 @@ public Mono auth(AListProperties properties) { .retrieve() .bodyToMono( new ParameterizedTypeReference>() { - }); + }) + .onErrorMap(WebClientRequestException.class, + e -> new AListIllegalArgumentException(e.getMessage())); }).flatMap(response -> { if (response.getCode().equals("200")) { log.info("[AList Info] : Login successfully"); @@ -198,7 +199,12 @@ public Mono auth(AListProperties properties) { private AListProperties getProperties(ConfigMap configMap) { var settingJson = configMap.getData().getOrDefault("default", "{}"); - return JsonUtils.jsonToObject(settingJson, AListProperties.class); + AListProperties aListProperties = + JsonUtils.jsonToObject(settingJson, AListProperties.class); + if (aListProperties.getPath().equals("/")) { + aListProperties.setPath(""); + } + return aListProperties; } @Override @@ -264,16 +270,25 @@ public Mono getPermalink(Attachment attachment, Policy policy, ConfigMap co } return Mono.error(new AListRequestErrorException(response.getMessage())); })) - .map(response -> UriComponentsBuilder.fromHttpUrl(properties.getSite()) - .path("/d{path}{basePath}/{name}") - .queryParamIfPresent("sign", - Optional.ofNullable(response.getData().getSign()).filter(s -> !s.isEmpty())) - .buildAndExpand( - properties.getPath(), - properties.getBasePath(), - response.getData().getName() - ) - .toUri()); + .flatMap(response -> webClients.get(properties.getSite()) + .get() + .uri("/api/me") + .header(HttpHeaders.AUTHORIZATION, + tokenCache.getIfPresent(properties.getTokenKey())) + .retrieve() + .bodyToMono( + new ParameterizedTypeReference>() { + }) + .map(res -> UriComponentsBuilder.fromHttpUrl(properties.getSite()) + .path("/d{basePath}{path}/{name}") + .queryParamIfPresent("sign", + Optional.ofNullable(response.getData().getSign()).filter(s -> !s.isEmpty())) + .buildAndExpand( + res.getData().getBasePath(), + properties.getPath(), + response.getData().getName() + ) + .toUri())); } boolean shouldHandle(Policy policy) { diff --git a/src/main/resources/extensions/policy-template-alist.yaml b/src/main/resources/extensions/policy-template-alist.yaml index 564170b..bfd8947 100644 --- a/src/main/resources/extensions/policy-template-alist.yaml +++ b/src/main/resources/extensions/policy-template-alist.yaml @@ -26,12 +26,7 @@ spec: - $formkit: text name: path label: 挂载路径 - validation: required - help: AList 存储中的挂载路径,必须以 / 开头,如 /aliyun - - $formkit: text - name: basePath - label: 基本路径 - help: 所填用户的基本路径,可在 AList 管理 -> 用户 查看,必须以 / 开头,如 /aliyun,为 / 时留空即可 + help: 所填用户基本路径(可在 AList 管理 -> 用户 查看)下文件夹的路径,必须以 / 开头,支持多级目录如 /picture/2024,则全路径为{基本路径}/picture/2024,上传文件时会自动创建不存在的目录,为 / 时留空即可 - $formkit: secret name: secretName required: true