0.1 #1
13 changed files with 103 additions and 12 deletions
|
@ -46,7 +46,7 @@ steps:
|
||||||
dockerfile: container/Dockerfile
|
dockerfile: container/Dockerfile
|
||||||
context: ./container
|
context: ./container
|
||||||
repo: arminfriedl/fling
|
repo: arminfriedl/fling
|
||||||
tags: latest
|
tags: dev
|
||||||
when:
|
when:
|
||||||
branch:
|
branch:
|
||||||
- master
|
- master
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
<bouncycastle.version>1.64</bouncycastle.version>
|
<bouncycastle.version>1.64</bouncycastle.version>
|
||||||
<jwt.version>0.11.1</jwt.version>
|
<jwt.version>0.11.1</jwt.version>
|
||||||
<spring.version>${project.parent.version}</spring.version>
|
<spring.version>${project.parent.version}</spring.version>
|
||||||
|
<fling.api.version>${project.version}</fling.api.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -102,8 +103,12 @@
|
||||||
<build>
|
<build>
|
||||||
<resources>
|
<resources>
|
||||||
<resource>
|
<resource>
|
||||||
<!-- Replace @spring.profiles.active@ in application.yml by setting
|
<!--
|
||||||
in maven profile See also: profiles section -->
|
Replace @...@ placeholder in resources.
|
||||||
|
Replaces:
|
||||||
|
- application.yml | @spring.profiles.active@ | see also: profiles section
|
||||||
|
- application.yml | @fling.api.version@ | see also: properties
|
||||||
|
-->
|
||||||
<directory>src/main/resources</directory>
|
<directory>src/main/resources</directory>
|
||||||
<filtering>true</filtering>
|
<filtering>true</filtering>
|
||||||
</resource>
|
</resource>
|
||||||
|
|
|
@ -16,6 +16,12 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.friedl.fling.model.dto.ArtifactDto;
|
import net.friedl.fling.model.dto.ArtifactDto;
|
||||||
import net.friedl.fling.service.ArtifactService;
|
import net.friedl.fling.service.ArtifactService;
|
||||||
|
@ -24,6 +30,7 @@ import net.friedl.fling.service.archive.ArchiveService;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/artifacts")
|
@RequestMapping("/api/artifacts")
|
||||||
|
@Tag(name = "artifact", description = "Operations on /api/artifacts")
|
||||||
public class ArtifactController {
|
public class ArtifactController {
|
||||||
|
|
||||||
private ArtifactService artifactService;
|
private ArtifactService artifactService;
|
||||||
|
@ -45,6 +52,8 @@ public class ArtifactController {
|
||||||
artifactService.delete(id);
|
artifactService.delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(requestBody = @RequestBody(
|
||||||
|
content = @Content(schema = @Schema(type = "string", format = "binary"))))
|
||||||
@PostMapping(path = "/{id}/data")
|
@PostMapping(path = "/{id}/data")
|
||||||
public void uploadArtifactData(@PathVariable UUID id, HttpServletRequest request) {
|
public void uploadArtifactData(@PathVariable UUID id, HttpServletRequest request) {
|
||||||
try {
|
try {
|
||||||
|
@ -55,6 +64,12 @@ public class ArtifactController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(responses = {
|
||||||
|
@ApiResponse(responseCode = "200",
|
||||||
|
content = @Content(
|
||||||
|
mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||||
|
schema = @Schema(type = "string", format = "binary")))
|
||||||
|
})
|
||||||
@GetMapping(path = "/{id}/data")
|
@GetMapping(path = "/{id}/data")
|
||||||
public ResponseEntity<Resource> downloadArtifact(@PathVariable UUID id) {
|
public ResponseEntity<Resource> downloadArtifact(@PathVariable UUID id) {
|
||||||
ArtifactDto artifactDto = artifactService.getById(id);
|
ArtifactDto artifactDto = artifactService.getById(id);
|
||||||
|
|
|
@ -15,6 +15,11 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import net.friedl.fling.model.dto.ArtifactDto;
|
import net.friedl.fling.model.dto.ArtifactDto;
|
||||||
import net.friedl.fling.model.dto.FlingDto;
|
import net.friedl.fling.model.dto.FlingDto;
|
||||||
import net.friedl.fling.service.ArtifactService;
|
import net.friedl.fling.service.ArtifactService;
|
||||||
|
@ -23,6 +28,7 @@ import net.friedl.fling.service.archive.ArchiveService;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/fling")
|
@RequestMapping("/api/fling")
|
||||||
|
@Tag(name = "fling", description = "Operations on /api/fling")
|
||||||
public class FlingController {
|
public class FlingController {
|
||||||
|
|
||||||
private FlingService flingService;
|
private FlingService flingService;
|
||||||
|
@ -68,6 +74,12 @@ public class FlingController {
|
||||||
flingService.delete(id);
|
flingService.delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(responses = {
|
||||||
|
@ApiResponse(responseCode = "200",
|
||||||
|
content = @Content(
|
||||||
|
mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||||
|
schema = @Schema(type = "string", format = "binary")))
|
||||||
|
})
|
||||||
@GetMapping(path = "/{id}/data")
|
@GetMapping(path = "/{id}/data")
|
||||||
public ResponseEntity<Resource> getFlingData(@PathVariable UUID id) {
|
public ResponseEntity<Resource> getFlingData(@PathVariable UUID id) {
|
||||||
FlingDto flingDto = flingService.getById(id);
|
FlingDto flingDto = flingService.getById(id);
|
||||||
|
|
|
@ -4,6 +4,8 @@ import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema.AccessMode;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -13,18 +15,24 @@ import lombok.NoArgsConstructor;
|
||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@Schema(name = "Artifact")
|
||||||
public class ArtifactDto {
|
public class ArtifactDto {
|
||||||
|
@Schema(accessMode = AccessMode.READ_ONLY, type = "string")
|
||||||
@NotNull
|
@NotNull
|
||||||
private UUID id;
|
private UUID id;
|
||||||
|
|
||||||
|
@Schema(type = "string",
|
||||||
|
description = "Path of the artifact")
|
||||||
@NotNull
|
@NotNull
|
||||||
private Path path;
|
private Path path;
|
||||||
|
|
||||||
|
@Schema(type = "integer", format = "int64",
|
||||||
|
description = "Upload time in milliseconds since the unix epoch 01.01.1970 00:00:00 UTC")
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private Instant uploadTime = Instant.now();
|
private Instant uploadTime = Instant.now();
|
||||||
|
|
||||||
private String archiveId;
|
@Schema(accessMode = AccessMode.READ_ONLY, type = "boolean",
|
||||||
|
description = "Whether the artifact was successfully persisted in the archive.")
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private Boolean archived = false;
|
private Boolean archived = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package net.friedl.fling.model.dto;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema.AccessMode;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -12,32 +14,46 @@ import lombok.NoArgsConstructor;
|
||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@Schema(name = "Fling")
|
||||||
public class FlingDto {
|
public class FlingDto {
|
||||||
|
@Schema(accessMode = AccessMode.READ_ONLY, type = "string")
|
||||||
@NotNull
|
@NotNull
|
||||||
private UUID id;
|
private UUID id;
|
||||||
|
|
||||||
|
@Schema(description = "Name of the fling")
|
||||||
@NotNull
|
@NotNull
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@Schema(type = "integer", format = "int64",
|
||||||
|
description = "Creation time in milliseconds since the unix epoch 01.01.1970 00:00:00 UTC")
|
||||||
@NotNull
|
@NotNull
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private Instant creationTime = Instant.now();
|
private Instant creationTime = Instant.now();
|
||||||
|
|
||||||
|
@Schema(description = "Share id of the fling. Used in the share link.")
|
||||||
@NotNull
|
@NotNull
|
||||||
private String shareId;
|
private String shareId;
|
||||||
|
|
||||||
|
@Schema(description = "Authentication code for password protecting a fling.")
|
||||||
private String authCode;
|
private String authCode;
|
||||||
|
|
||||||
|
@Schema(description = "Whether users should be redirected to fling download when accessing the "
|
||||||
|
+ "fling by share id")
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private Boolean directDownload = false;
|
private Boolean directDownload = false;
|
||||||
|
|
||||||
|
@Schema(description = "Allow uploads to the fling by users")
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private Boolean allowUpload = false;
|
private Boolean allowUpload = false;
|
||||||
|
|
||||||
|
@Schema(description = "Whether the fling is accessible by users via the share id")
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private Boolean shared = true;
|
private Boolean shared = true;
|
||||||
|
|
||||||
|
@Schema(description = "How many clicks are left until the fling access by share id is disallowed")
|
||||||
private Integer expirationClicks;
|
private Integer expirationClicks;
|
||||||
|
|
||||||
|
@Schema(type = "integer", format = "int64",
|
||||||
|
description = "Expiration time in milliseconds since the unix epoch 01.01.1970 00:00:00 UTC")
|
||||||
private Instant expirationTime;
|
private Instant expirationTime;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ import io.jsonwebtoken.Jwts;
|
||||||
import io.jsonwebtoken.security.Keys;
|
import io.jsonwebtoken.security.Keys;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@Data
|
@Data
|
||||||
|
@Configuration
|
||||||
@ConfigurationProperties("fling.security")
|
@ConfigurationProperties("fling.security")
|
||||||
public class FlingSecurityConfiguration {
|
public class FlingSecurityConfiguration {
|
||||||
private List<String> allowedOrigins;
|
private List<String> allowedOrigins;
|
||||||
|
|
|
@ -5,11 +5,13 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import net.friedl.fling.security.authentication.dto.OwnerAuthDto;
|
import net.friedl.fling.security.authentication.dto.OwnerAuthDto;
|
||||||
import net.friedl.fling.security.authentication.dto.UserAuthDto;
|
import net.friedl.fling.security.authentication.dto.UserAuthDto;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api")
|
@RequestMapping("/api/auth")
|
||||||
|
@Tag(name = "auth", description = "Operations on /api/auth")
|
||||||
public class AuthenticationController {
|
public class AuthenticationController {
|
||||||
|
|
||||||
private AuthenticationService authenticationService;
|
private AuthenticationService authenticationService;
|
||||||
|
@ -19,12 +21,12 @@ public class AuthenticationController {
|
||||||
this.authenticationService = authenticationService;
|
this.authenticationService = authenticationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(path = "/auth/owner")
|
@PostMapping(path = "/owner")
|
||||||
public String authenticateOwner(@RequestBody OwnerAuthDto ownerAuthDto) {
|
public String authenticateOwner(@RequestBody OwnerAuthDto ownerAuthDto) {
|
||||||
return authenticationService.authenticate(ownerAuthDto);
|
return authenticationService.authenticate(ownerAuthDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/auth/user")
|
@PostMapping("/user")
|
||||||
public String authenticateUser(@RequestBody UserAuthDto userAuthDto) {
|
public String authenticateUser(@RequestBody UserAuthDto userAuthDto) {
|
||||||
return authenticationService.authenticate(userAuthDto);
|
return authenticationService.authenticate(userAuthDto);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package net.friedl.fling.security.authentication.dto;
|
package net.friedl.fling.security.authentication.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@Schema(name = "OwnerAuth")
|
||||||
public class OwnerAuthDto {
|
public class OwnerAuthDto {
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package net.friedl.fling.security.authentication.dto;
|
package net.friedl.fling.security.authentication.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@Schema(name = "UserAuth")
|
||||||
public class UserAuthDto {
|
public class UserAuthDto {
|
||||||
String shareId;
|
String shareId;
|
||||||
String code;
|
String code;
|
||||||
|
|
|
@ -9,9 +9,32 @@
|
||||||
"name": "fling.security",
|
"name": "fling.security",
|
||||||
"type": "net.friedl.fling.security.FlingWebSecurityConfiguration",
|
"type": "net.friedl.fling.security.FlingWebSecurityConfiguration",
|
||||||
"sourceType": "net.friedl.fling.security.FlingWebSecurityConfiguration"
|
"sourceType": "net.friedl.fling.security.FlingWebSecurityConfiguration"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fling.api",
|
||||||
|
"type": "net.friedl.fling.controller.OpenApiConfiguration",
|
||||||
|
"sourceType": "net.friedl.fling.controller.OpenApiConfiguration"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": [
|
"properties": [
|
||||||
|
{
|
||||||
|
"name": "fling.api.version",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "Fling API version",
|
||||||
|
"sourceType": "net.friedl.fling.controller.OpenApiConfiguration"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fling.api.server-url",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "Base URL for the fling api",
|
||||||
|
"sourceType": "net.friedl.fling.controller.OpenApiConfiguration"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fling.api.server-description",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for the server to be shown in OAS",
|
||||||
|
"sourceType": "net.friedl.fling.controller.OpenApiConfiguration"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "fling.archive.filesystem.archive-path",
|
"name": "fling.archive.filesystem.archive-path",
|
||||||
"type": "java.lang.String",
|
"type": "java.lang.String",
|
||||||
|
|
|
@ -31,4 +31,8 @@ fling:
|
||||||
admin-user: "${FLING_ADMIN_USER:admin}"
|
admin-user: "${FLING_ADMIN_USER:admin}"
|
||||||
admin-password: "${FLING_ADMIN_PASSWORD:123}"
|
admin-password: "${FLING_ADMIN_PASSWORD:123}"
|
||||||
signing-key: "${FLING_SIGNING_KEY:changeitchangeitchangeitchangeit}"
|
signing-key: "${FLING_SIGNING_KEY:changeitchangeitchangeitchangeit}"
|
||||||
jwt-expiration: "${FLING_JWT_EXPIRATION:180000}"
|
jwt-expiration: "${FLING_JWT_EXPIRATION:180000}"
|
||||||
|
api:
|
||||||
|
version: "0"
|
||||||
|
server-url: "http://localhost:8080"
|
||||||
|
server-description: "API server for dev"
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
spring.profiles.active: "@spring.profiles.active@" # To be replaced by maven according to profile settings
|
# To be replaced by maven
|
||||||
|
spring.profiles.active: "@spring.profiles.active@"
|
||||||
|
fling.api.version: "@fling.api.version@"
|
Loading…
Reference in a new issue