work on version downloads

This commit is contained in:
Jake Potrebic 2021-04-12 19:12:53 -07:00
parent 04fd9bea16
commit e375ea6dc1
No known key found for this signature in database
GPG Key ID: 7C58557EC9C421F8
24 changed files with 386 additions and 60 deletions

View File

@ -29,7 +29,7 @@ export default class ProjectVersionPageParent extends HangarProjectMixin {
async asyncData({ $api, $util, params, error, redirect, route }: Context) {
const versions = await $api
.requestInternal<HangarVersion[]>(`versions/version/${params.author}/${params.slug}/versions/${params.version}`)
.requestInternal<HangarVersion[]>(`versions/version/${params.author}/${params.slug}/versions/${params.version}`, false)
.catch<any>($util.handlePageRequestError);
if (typeof versions === 'undefined' || versions.length < 1) {
return error({

View File

@ -30,6 +30,7 @@ public class ProjectsConfig {
private String checkInterval = "1h";
private String draftExpire = "1d";
private int userGridPageSize = 30;
@DurationUnit(ChronoUnit.MINUTES)
private Duration unsafeDownloadMaxAge = Duration.ofMinutes(10);
public String getNameRegex() {

View File

@ -17,10 +17,11 @@ import io.papermc.hangar.security.annotations.permission.PermissionRequired;
import io.papermc.hangar.security.annotations.visibility.VisibilityRequired;
import io.papermc.hangar.security.annotations.visibility.VisibilityRequired.Type;
import io.papermc.hangar.service.api.VersionsApiService;
import io.papermc.hangar.service.internal.versions.DownloadService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ResponseBody;
import java.time.OffsetDateTime;
import java.util.List;
@ -28,37 +29,52 @@ import java.util.Map;
@Anyone
@Controller
@ResponseBody
public class VersionsController implements IVersionsController {
private final DownloadService downloadService;
private final VersionsApiService versionsApiService;
@Autowired
public VersionsController(VersionsApiService versionsApiService) {
public VersionsController(DownloadService downloadService, VersionsApiService versionsApiService) {
this.downloadService = downloadService;
this.versionsApiService = versionsApiService;
}
@Override
@VisibilityRequired(type = Type.VERSION, args = "{#author, #slug, #versionString, #platform}")
public ResponseEntity<Version> getVersion(String author, String slug, String versionString, Platform platform) {
return ResponseEntity.ok(versionsApiService.getVersion(author, slug, versionString, platform));
public Version getVersion(String author, String slug, String versionString, Platform platform) {
return versionsApiService.getVersion(author, slug, versionString, platform);
}
@Override
@VisibilityRequired(type = Type.PROJECT, args = "{#author, #slug}")
public ResponseEntity<List<Version>> getVersions(String author, String slug, String name) {
return ResponseEntity.ok(versionsApiService.getVersions(author, slug, name));
public List<Version> getVersions(String author, String slug, String name) {
return versionsApiService.getVersions(author, slug, name);
}
@Override
@VisibilityRequired(type = Type.PROJECT, args = "{#author, #slug}")
@ApplicableFilters({VersionChannelFilter.class, VersionPlatformFilter.class, VersionTagFilter.class})
public ResponseEntity<PaginatedResult<Version>> getVersions(String author, String slug, @NotNull RequestPagination pagination) {
return ResponseEntity.ok(versionsApiService.getVersions(author, slug, pagination));
public PaginatedResult<Version> getVersions(String author, String slug, @NotNull RequestPagination pagination) {
return versionsApiService.getVersions(author, slug, pagination);
}
@Override
@PermissionRequired(type = PermissionType.PROJECT, perms = NamedPermission.IS_SUBJECT_MEMBER, args = "{#author, #slug}")
public ResponseEntity<Map<String, VersionStats>> getVersionStats(String author, String slug, String versionString, Platform platform, @NotNull OffsetDateTime fromDate, @NotNull OffsetDateTime toDate) {
return ResponseEntity.ok(versionsApiService.getVersionStats(author, slug, versionString, platform, fromDate, toDate));
public Map<String, VersionStats> getVersionStats(String author, String slug, String versionString, Platform platform, @NotNull OffsetDateTime fromDate, @NotNull OffsetDateTime toDate) {
return versionsApiService.getVersionStats(author, slug, versionString, platform, fromDate, toDate);
}
@Override
@VisibilityRequired(type = Type.VERSION, args = "{#author, #slug, #versionString, #platform}")
public String confirmVersionDownload(String author, String slug, String versionString, Platform platform) {
return downloadService.createConfirmationToken(author, slug, versionString, platform);
}
@Override
@VisibilityRequired(type = Type.VERSION, args = "{#author, #slug, #versionString, #platform}")
public Object downloadVersion(String author, String slug, String versionString, Platform platform, String token) {
return downloadService.getVersionFile(author, slug, versionString, platform, token);
}
}

View File

@ -4,10 +4,7 @@ import io.papermc.hangar.model.api.PaginatedResult;
import io.papermc.hangar.model.api.project.version.Version;
import io.papermc.hangar.model.api.project.version.VersionStats;
import io.papermc.hangar.model.api.requests.RequestPagination;
import io.papermc.hangar.model.common.NamedPermission;
import io.papermc.hangar.model.common.PermissionType;
import io.papermc.hangar.model.common.Platform;
import io.papermc.hangar.security.annotations.permission.PermissionRequired;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
@ -16,7 +13,6 @@ import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.Authorization;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@ -30,6 +26,7 @@ import java.util.Map;
@RequestMapping(path = "/api/v1", produces = MediaType.APPLICATION_JSON_VALUE)
public interface IVersionsController {
// TODO implement version creation via API
/* @ApiOperation(
value = "Creates a new version",
nickname = "deployVersion",
@ -42,7 +39,7 @@ public interface IVersionsController {
@ApiResponse(code = 401, message = "Api session missing, invalid or expired"),
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint")
})
@PostMapping(value = "/projects/{author}/{slug}/versions", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@PostMapping(path = "/projects/{author}/{slug}/versions", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
ResponseEntity<Version> deployVersion()*/
@ApiOperation(
@ -57,12 +54,11 @@ public interface IVersionsController {
@ApiResponse(code = 401, message = "Api session missing, invalid or expired"),
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint")
})
@GetMapping(value = "/projects/{author}/{slug}/versions/{name}/{platform}/")
ResponseEntity<Version> getVersion(@ApiParam("The author of the project to return the version for") @PathVariable String author,
@ApiParam("The slug of the project to return") @PathVariable String slug,
@ApiParam("The name of the version to return") @PathVariable("name") String versionString,
@ApiParam("The platform of the version to return") @PathVariable Platform platform
);
@GetMapping("/projects/{author}/{slug}/versions/{name}/{platform}/")
Version getVersion(@ApiParam("The author of the project to return the version for") @PathVariable String author,
@ApiParam("The slug of the project to return") @PathVariable String slug,
@ApiParam("The name of the version to return") @PathVariable("name") String versionString,
@ApiParam("The platform of the version to return") @PathVariable Platform platform);
@ApiOperation(
value = "Returns versions of a project with the specified version string",
@ -76,11 +72,10 @@ public interface IVersionsController {
@ApiResponse(code = 401, message = "Api session missing, invalid or expired"),
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint")
})
@GetMapping(value = "/projects/{author}/{slug}/versions/{name}")
ResponseEntity<List<Version>> getVersions(@ApiParam("The author of the project to return the versions for") @PathVariable String author,
@ApiParam("The slug of the project to return") @PathVariable String slug,
@ApiParam("The name of the versions to return") @PathVariable("name") String versionString
);
@GetMapping("/projects/{author}/{slug}/versions/{name}")
List<Version> getVersions(@ApiParam("The author of the project to return the versions for") @PathVariable String author,
@ApiParam("The slug of the project to return") @PathVariable String slug,
@ApiParam("The name of the versions to return") @PathVariable("name") String versionString);
@ApiOperation(
value = "Returns the versions of a project",
@ -95,10 +90,9 @@ public interface IVersionsController {
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint")
})
@GetMapping("/projects/{author}/{slug}/versions")
ResponseEntity<PaginatedResult<Version>> getVersions(@ApiParam("The author of the project to return versions for") @PathVariable String author,
@ApiParam("The slug of the project to return versions for") @PathVariable String slug,
@ApiParam("Pagination information") @NotNull RequestPagination pagination
);
PaginatedResult<Version> getVersions(@ApiParam("The author of the project to return versions for") @PathVariable String author,
@ApiParam("The slug of the project to return versions for") @PathVariable String slug,
@ApiParam("Pagination information") @NotNull RequestPagination pagination);
@ApiOperation(
value = "Returns the stats for a version",
@ -113,13 +107,50 @@ public interface IVersionsController {
@ApiResponse(code = 401, message = "Api session missing, invalid or expired"),
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint")
})
@GetMapping(value = "/projects/{author}/{slug}/versions/{name}/{platform}/stats", produces = MediaType.APPLICATION_JSON_VALUE)
@PermissionRequired(type = PermissionType.PROJECT, perms = NamedPermission.IS_SUBJECT_MEMBER, args = "{#author, #slug}")
ResponseEntity<Map<String, VersionStats>> getVersionStats(@ApiParam("The author of the version to return the stats for") @PathVariable String author,
@ApiParam("The slug of the project to return stats for") @PathVariable String slug,
@ApiParam("The version to return the stats for") @PathVariable("name") String versionString,
@ApiParam("The platform of the version to return") @PathVariable Platform platform,
@ApiParam(value = "The first date to include in the result", required = true) @RequestParam @NotNull OffsetDateTime fromDate,
@ApiParam(value = "The last date to include in the result", required = true) @RequestParam @NotNull OffsetDateTime toDate
);
@GetMapping("/projects/{author}/{slug}/versions/{name}/{platform}/stats")
Map<String, VersionStats> getVersionStats(@ApiParam("The author of the version to return the stats for") @PathVariable String author,
@ApiParam("The slug of the project to return stats for") @PathVariable String slug,
@ApiParam("The version to return the stats for") @PathVariable("name") String versionString,
@ApiParam("The platform of the version to return") @PathVariable Platform platform,
@ApiParam(value = "The first date to include in the result", required = true) @RequestParam @NotNull OffsetDateTime fromDate,
@ApiParam(value = "The last date to include in the result", required = true) @RequestParam @NotNull OffsetDateTime toDate);
@ApiOperation(
value = "Gets a confirmation token for downloading a version",
nickname = "confirmVersionDownload",
notes = "Retrieves a token to use for downloading a version which requires user confirmation",
authorizations = @Authorization("Session"),
tags = "Versions"
)
@ApiResponses({
@ApiResponse(code = 200, message = "Ok"),
@ApiResponse(code = 401, message = "Api session missing, invalid or expired"),
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint")
})
@GetMapping("/projects/{author}/{slug}/versions/{name}/{platform}/download/confirm")
String confirmVersionDownload(@ApiParam("The author of the project to return the version for") @PathVariable String author,
@ApiParam("The slug of the project to return") @PathVariable String slug,
@ApiParam("The name of the version to return") @PathVariable("name") String versionString,
@ApiParam("The platform of the version to return") @PathVariable Platform platform);
@ApiOperation(
value = "Downloads a version",
nickname = "downloadVersion",
notes = "Downloads the file for a specific platform of a version. Requires visibility of the project and version.",
authorizations = @Authorization("Session"),
tags = "Versions"
)
@ApiResponses({
@ApiResponse(code = 200, message = "Ok"),
@ApiResponse(code = 303, message = "Version has an external download url"),
@ApiResponse(code = 401, message = "Api session missing, invalid or expired"),
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint"),
@ApiResponse(code = 412, message = "Requires confirmation token, and none found on request")
})
@GetMapping("/projects/{author}/{slug}/versions/{name}/{platform}/download")
Object downloadVersion(@ApiParam("The author of the project to return the version for") @PathVariable String author,
@ApiParam("The slug of the project to return") @PathVariable String slug,
@ApiParam("The name of the version to return") @PathVariable("name") String versionString,
@ApiParam("The platform of the version to return") @PathVariable Platform platform,
@ApiParam(value = "The confirmation token") @RequestParam(required = false) String token);
}

View File

@ -58,6 +58,7 @@ import java.util.UUID;
import java.util.function.Supplier;
@Controller("oldVersionsController")
@Deprecated(forRemoval = true)
public class VersionsController extends HangarController {
private final VersionService versionService;

View File

@ -1,7 +1,7 @@
package io.papermc.hangar.db.dao.internal.table.versions;
package io.papermc.hangar.db.dao.internal.table.versions.dependencies;
import io.papermc.hangar.model.common.Platform;
import io.papermc.hangar.model.db.versions.ProjectVersionDependencyTable;
import io.papermc.hangar.model.db.versions.dependencies.ProjectVersionDependencyTable;
import org.jdbi.v3.core.enums.EnumByOrdinal;
import org.jdbi.v3.sqlobject.config.KeyColumn;
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;

View File

@ -1,7 +1,7 @@
package io.papermc.hangar.db.dao.internal.table.versions;
package io.papermc.hangar.db.dao.internal.table.versions.dependencies;
import io.papermc.hangar.model.common.Platform;
import io.papermc.hangar.model.db.versions.ProjectVersionPlatformDependencyTable;
import io.papermc.hangar.model.db.versions.dependencies.ProjectVersionPlatformDependencyTable;
import org.jdbi.v3.core.enums.EnumByOrdinal;
import org.jdbi.v3.sqlobject.config.KeyColumn;
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;

View File

@ -0,0 +1,27 @@
package io.papermc.hangar.db.dao.internal.table.versions.downloads;
import io.papermc.hangar.model.db.versions.downloads.ProjectVersionDownloadWarningTable;
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.customizer.Timestamped;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import org.springframework.stereotype.Repository;
import java.net.InetAddress;
@Repository
@RegisterConstructorMapper(ProjectVersionDownloadWarningTable.class)
public interface ProjectVersionDownloadWarningsDAO {
@Timestamped
@SqlUpdate("INSERT INTO project_version_download_warnings (created_at, expires_at, token, version_id, address, download_id) VALUES (:now, :expiresAt, :token, :versionId, :address, :downloadId)")
void insert(@BindBean ProjectVersionDownloadWarningTable projectVersionDownloadWarningTable);
@SqlQuery(" SELECT * " +
" FROM project_version_download_warnings " +
" WHERE token = :token AND" +
" address = :address AND" +
" version_id = :versionId")
ProjectVersionDownloadWarningTable findWarning(String token, InetAddress address, long versionId);
}

View File

@ -0,0 +1,19 @@
package io.papermc.hangar.db.dao.internal.table.versions.downloads;
import io.papermc.hangar.model.db.versions.downloads.ProjectVersionUnsafeDownloadTable;
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.customizer.Timestamped;
import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import org.springframework.stereotype.Repository;
@Repository
@RegisterConstructorMapper(ProjectVersionUnsafeDownloadTable.class)
public interface ProjectVersionUnsafeDownloadsDAO {
@Timestamped
@GetGeneratedKeys
@SqlUpdate("INSERT INTO project_version_unsafe_downloads (created_at, user_id, address) VALUES (:now, :userId, :address)")
ProjectVersionUnsafeDownloadTable insert(@BindBean ProjectVersionUnsafeDownloadTable projectVersionUnsafeDownloadTable);
}

View File

@ -7,6 +7,7 @@ import org.jdbi.v3.core.enums.EnumByOrdinal;
import java.net.InetAddress;
import java.time.OffsetDateTime;
@Deprecated(forRemoval = true)
public class ProjectVersionUnsafeDownloadsTable {
private long id;

View File

@ -1,4 +1,4 @@
package io.papermc.hangar.model.db.versions;
package io.papermc.hangar.model.db.versions.dependencies;
import io.papermc.hangar.model.common.Platform;
import org.jdbi.v3.core.enums.EnumByOrdinal;

View File

@ -1,4 +1,4 @@
package io.papermc.hangar.model.db.versions;
package io.papermc.hangar.model.db.versions.dependencies;
import org.jdbi.v3.core.mapper.reflect.JdbiConstructor;

View File

@ -1,4 +1,4 @@
package io.papermc.hangar.model.db.versions;
package io.papermc.hangar.model.db.versions.dependencies;
import io.papermc.hangar.model.db.Table;

View File

@ -0,0 +1,82 @@
package io.papermc.hangar.model.db.versions.downloads;
import io.papermc.hangar.model.db.Table;
import org.jdbi.v3.core.mapper.reflect.JdbiConstructor;
import java.net.InetAddress;
import java.time.OffsetDateTime;
import java.util.UUID;
public class ProjectVersionDownloadWarningTable extends Table {
private final OffsetDateTime expiresAt;
private final UUID token;
private final long versionId;
private final InetAddress address;
private boolean confirmed;
private Long downloadId;
public ProjectVersionDownloadWarningTable(OffsetDateTime expiresAt, UUID token, long versionId, InetAddress address) {
this.expiresAt = expiresAt;
this.token = token;
this.versionId = versionId;
this.address = address;
this.confirmed = false;
this.downloadId = null;
}
@JdbiConstructor
public ProjectVersionDownloadWarningTable(OffsetDateTime createdAt, long id, OffsetDateTime expiresAt, UUID token, long versionId, InetAddress address, boolean confirmed, Long downloadId) {
super(createdAt, id);
this.expiresAt = expiresAt;
this.token = token;
this.versionId = versionId;
this.address = address;
this.confirmed = confirmed;
this.downloadId = downloadId;
}
public OffsetDateTime getExpiresAt() {
return expiresAt;
}
public UUID getToken() {
return token;
}
public long getVersionId() {
return versionId;
}
public InetAddress getAddress() {
return address;
}
public boolean isConfirmed() {
return confirmed;
}
public void setConfirmed(boolean confirmed) {
this.confirmed = confirmed;
}
public Long getDownloadId() {
return downloadId;
}
public void setDownloadId(Long downloadId) {
this.downloadId = downloadId;
}
@Override
public String toString() {
return "ProjectVersionDownloadWarningTable{" +
"expiresAt=" + expiresAt +
", token=" + token +
", versionId=" + versionId +
", address=" + address +
", confirmed=" + confirmed +
", downloadId=" + downloadId +
"} " + super.toString();
}
}

View File

@ -0,0 +1,41 @@
package io.papermc.hangar.model.db.versions.downloads;
import io.papermc.hangar.model.db.Table;
import org.jdbi.v3.core.mapper.reflect.JdbiConstructor;
import java.net.InetAddress;
import java.time.OffsetDateTime;
public class ProjectVersionUnsafeDownloadTable extends Table {
private final Long userId;
private final InetAddress address;
public ProjectVersionUnsafeDownloadTable(Long userId, InetAddress address) {
this.userId = userId;
this.address = address;
}
@JdbiConstructor
public ProjectVersionUnsafeDownloadTable(OffsetDateTime createdAt, long id, Long userId, InetAddress address) {
super(createdAt, id);
this.userId = userId;
this.address = address;
}
public Long getUserId() {
return userId;
}
public InetAddress getAddress() {
return address;
}
@Override
public String toString() {
return "ProjectVersionUnsafeDownloadTable{" +
"userId=" + userId +
", address=" + address +
"} " + super.toString();
}
}

View File

@ -1,5 +1,6 @@
package io.papermc.hangar.modelold;
@Deprecated(forRemoval = true)
public enum DownloadType {
/**

View File

@ -0,0 +1,103 @@
package io.papermc.hangar.service.internal.versions;
import io.papermc.hangar.HangarComponent;
import io.papermc.hangar.db.dao.HangarDao;
import io.papermc.hangar.db.dao.internal.table.projects.ProjectsDAO;
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionsDAO;
import io.papermc.hangar.db.dao.internal.table.versions.downloads.ProjectVersionDownloadWarningsDAO;
import io.papermc.hangar.db.dao.internal.table.versions.downloads.ProjectVersionUnsafeDownloadsDAO;
import io.papermc.hangar.exceptions.HangarApiException;
import io.papermc.hangar.model.common.Platform;
import io.papermc.hangar.model.common.projects.ReviewState;
import io.papermc.hangar.model.db.projects.ProjectTable;
import io.papermc.hangar.model.db.versions.ProjectVersionTable;
import io.papermc.hangar.model.db.versions.downloads.ProjectVersionDownloadWarningTable;
import io.papermc.hangar.model.db.versions.downloads.ProjectVersionUnsafeDownloadTable;
import io.papermc.hangar.service.internal.admin.StatService;
import io.papermc.hangar.service.internal.uploads.ProjectFiles;
import io.papermc.hangar.util.RequestUtil;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.view.RedirectView;
import java.nio.file.Path;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.UUID;
@Service
public class DownloadService extends HangarComponent {
private final StatService statService;
private final ProjectFiles projectFiles;
private final ProjectsDAO projectsDAO;
private final ProjectVersionsDAO projectVersionsDAO;
private final ProjectVersionUnsafeDownloadsDAO projectVersionUnsafeDownloadsDAO;
private final ProjectVersionDownloadWarningsDAO projectVersionDownloadWarningsDAO;
@Autowired
public DownloadService(StatService statService, ProjectFiles projectFiles, HangarDao<ProjectsDAO> projectsDAO, HangarDao<ProjectVersionsDAO> projectVersionsDAO, HangarDao<ProjectVersionUnsafeDownloadsDAO> projectVersionUnsafeDownloadsDAO, HangarDao<ProjectVersionDownloadWarningsDAO> projectVersionDownloadWarningsDAO) {
this.statService = statService;
this.projectFiles = projectFiles;
this.projectsDAO = projectsDAO.get();
this.projectVersionsDAO = projectVersionsDAO.get();
this.projectVersionUnsafeDownloadsDAO = projectVersionUnsafeDownloadsDAO.get();
this.projectVersionDownloadWarningsDAO = projectVersionDownloadWarningsDAO.get();
}
public String createConfirmationToken(String author, String slug, String versionString, Platform platform) {
ProjectVersionTable pvt = projectVersionsDAO.getProjectVersionTable(author, slug, versionString, platform);
UUID token = UUID.randomUUID();
OffsetDateTime expiresAt = OffsetDateTime.now().plus(config.projects.getUnsafeDownloadMaxAge().toMillis(), ChronoUnit.MILLIS);
projectVersionDownloadWarningsDAO.insert(new ProjectVersionDownloadWarningTable(
expiresAt,
token,
pvt.getId(),
RequestUtil.getRemoteInetAddress(request)
));
return token.toString();
}
public Object getVersionFile(String author, String slug, String versionString, Platform platform, @Nullable String token) {
ProjectVersionTable pvt = projectVersionsDAO.getProjectVersionTable(author, slug, versionString, platform);
if (pvt == null) {
throw new HangarApiException(HttpStatus.NOT_FOUND);
}
ProjectTable project = projectsDAO.getById(pvt.getProjectId());
if (!isConfirmed(pvt, token)) {
throw new HangarApiException(HttpStatus.PRECONDITION_FAILED);
}
statService.addVersionDownload(pvt);
if (pvt.getExternalUrl() != null) {
response.setStatus(HttpStatus.SEE_OTHER.value());
return new RedirectView(pvt.getExternalUrl());
}
Path path = projectFiles.getVersionDir(project.getOwnerName(), project.getName(), versionString, platform);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + pvt.getFileName() + "\"");
return new FileSystemResource(path);
}
private boolean isConfirmed(ProjectVersionTable pvt, @Nullable String token) {
if (pvt.getReviewState() == ReviewState.REVIEWED || (pvt.getExternalUrl() != null && config.security.checkSafe(pvt.getExternalUrl()))) {
return true;
}
if (token == null) {
return false;
}
var downloadWarning = projectVersionDownloadWarningsDAO.findWarning(token, RequestUtil.getRemoteInetAddress(request), pvt.getId());
if (downloadWarning == null) {
return false;
}
var unsafeDownload = projectVersionUnsafeDownloadsDAO.insert(new ProjectVersionUnsafeDownloadTable(getHangarUserId(), RequestUtil.getRemoteInetAddress(request)));
downloadWarning.setConfirmed(true);
downloadWarning.setDownloadId(unsafeDownload.getId());
return true;
}
}

View File

@ -4,9 +4,9 @@ import io.papermc.hangar.HangarComponent;
import io.papermc.hangar.db.dao.HangarDao;
import io.papermc.hangar.db.dao.internal.table.PlatformVersionDAO;
import io.papermc.hangar.db.dao.internal.table.projects.ProjectsDAO;
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionDependenciesDAO;
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionPlatformDependenciesDAO;
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionsDAO;
import io.papermc.hangar.db.dao.internal.table.versions.dependencies.ProjectVersionDependenciesDAO;
import io.papermc.hangar.db.dao.internal.table.versions.dependencies.ProjectVersionPlatformDependenciesDAO;
import io.papermc.hangar.db.dao.v1.VersionsApiDAO;
import io.papermc.hangar.exceptions.HangarApiException;
import io.papermc.hangar.model.api.color.TagColor;
@ -17,9 +17,9 @@ import io.papermc.hangar.model.common.Platform;
import io.papermc.hangar.model.db.PlatformVersionTable;
import io.papermc.hangar.model.db.projects.ProjectChannelTable;
import io.papermc.hangar.model.db.projects.ProjectTable;
import io.papermc.hangar.model.db.versions.ProjectVersionDependencyTable;
import io.papermc.hangar.model.db.versions.ProjectVersionPlatformDependencyTable;
import io.papermc.hangar.model.db.versions.ProjectVersionTagTable;
import io.papermc.hangar.model.db.versions.dependencies.ProjectVersionDependencyTable;
import io.papermc.hangar.model.db.versions.dependencies.ProjectVersionPlatformDependencyTable;
import io.papermc.hangar.model.internal.api.requests.versions.UpdatePlatformVersions;
import io.papermc.hangar.model.internal.api.requests.versions.UpdatePluginDependencies;
import io.papermc.hangar.model.internal.logs.LogAction;

View File

@ -3,9 +3,9 @@ package io.papermc.hangar.service.internal.versions;
import io.papermc.hangar.HangarComponent;
import io.papermc.hangar.db.dao.HangarDao;
import io.papermc.hangar.db.dao.internal.table.PlatformVersionDAO;
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionDependenciesDAO;
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionPlatformDependenciesDAO;
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionsDAO;
import io.papermc.hangar.db.dao.internal.table.versions.dependencies.ProjectVersionDependenciesDAO;
import io.papermc.hangar.db.dao.internal.table.versions.dependencies.ProjectVersionPlatformDependenciesDAO;
import io.papermc.hangar.db.dao.v1.VersionsApiDAO;
import io.papermc.hangar.exceptions.HangarApiException;
import io.papermc.hangar.model.api.project.version.FileInfo;
@ -15,10 +15,10 @@ import io.papermc.hangar.model.common.projects.Visibility;
import io.papermc.hangar.model.db.PlatformVersionTable;
import io.papermc.hangar.model.db.projects.ProjectChannelTable;
import io.papermc.hangar.model.db.projects.ProjectTable;
import io.papermc.hangar.model.db.versions.ProjectVersionDependencyTable;
import io.papermc.hangar.model.db.versions.ProjectVersionPlatformDependencyTable;
import io.papermc.hangar.model.db.versions.ProjectVersionTable;
import io.papermc.hangar.model.db.versions.ProjectVersionTagTable;
import io.papermc.hangar.model.db.versions.dependencies.ProjectVersionDependencyTable;
import io.papermc.hangar.model.db.versions.dependencies.ProjectVersionPlatformDependencyTable;
import io.papermc.hangar.model.internal.logs.LogAction;
import io.papermc.hangar.model.internal.logs.contexts.VersionContext;
import io.papermc.hangar.model.internal.versions.PendingVersion;
@ -28,6 +28,7 @@ import io.papermc.hangar.service.internal.projects.ChannelService;
import io.papermc.hangar.service.internal.projects.ProjectService;
import io.papermc.hangar.service.internal.uploads.ProjectFiles;
import io.papermc.hangar.service.internal.users.NotificationService;
import io.papermc.hangar.service.internal.versions.plugindata.PluginDataService;
import io.papermc.hangar.service.internal.versions.plugindata.PluginFileWithData;
import io.papermc.hangar.service.internal.visibility.ProjectVisibilityService;
import io.papermc.hangar.util.CryptoUtils;

View File

@ -1,10 +1,7 @@
package io.papermc.hangar.service.internal.versions;
package io.papermc.hangar.service.internal.versions.plugindata;
import io.papermc.hangar.exceptions.HangarApiException;
import io.papermc.hangar.model.common.Platform;
import io.papermc.hangar.service.internal.versions.plugindata.DataValue;
import io.papermc.hangar.service.internal.versions.plugindata.PluginFileData;
import io.papermc.hangar.service.internal.versions.plugindata.PluginFileWithData;
import io.papermc.hangar.service.internal.versions.plugindata.handler.FileTypeHandler;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -10,6 +10,7 @@ import org.springframework.stereotype.Service;
import java.net.InetAddress;
@Service
@Deprecated(forRemoval = true)
public class DownloadsService {
private final HangarDao<ProjectVersionUnsafeDownloadsDao> projectVersionUnsafeDownloadsDao;

View File

@ -0,0 +1,3 @@
ALTER TABLE project_version_unsafe_downloads DROP COLUMN download_type;
ALTER TABLE project_version_download_warnings RENAME expiration TO expiresAt;

View File

@ -0,0 +1 @@
ALTER TABLE project_version_download_warnings RENAME expiresat TO expires_at;

View File

@ -1,7 +1,7 @@
package io.papermc.hangar.serviceold.plugindata;
import io.papermc.hangar.exceptions.HangarException;
import io.papermc.hangar.service.internal.versions.PluginDataService;
import io.papermc.hangar.service.internal.versions.plugindata.PluginDataService;
import io.papermc.hangar.service.internal.versions.plugindata.PluginFileData;
import io.papermc.hangar.service.internal.versions.plugindata.handler.PaperPluginFileHandler;
import io.papermc.hangar.service.internal.versions.plugindata.handler.VelocityFileHandler;