diff --git a/service/fling/src/main/java/net/friedl/fling/model/dto/FlingDto.java b/service/fling/src/main/java/net/friedl/fling/model/dto/FlingDto.java index 9c437af..0be3fc4 100644 --- a/service/fling/src/main/java/net/friedl/fling/model/dto/FlingDto.java +++ b/service/fling/src/main/java/net/friedl/fling/model/dto/FlingDto.java @@ -15,6 +15,8 @@ public class FlingDto { private Long id; + private Instant creationTime; + @JsonIgnore private Boolean directDownload; @@ -91,4 +93,9 @@ public class FlingDto { return expiration; } + + @JsonProperty("creationTime") + public Long getJsonUploadTime() { + return creationTime.toEpochMilli(); + } } diff --git a/service/fling/src/main/java/net/friedl/fling/security/AuthorizationService.java b/service/fling/src/main/java/net/friedl/fling/security/AuthorizationService.java index ab98525..6c06ab4 100644 --- a/service/fling/src/main/java/net/friedl/fling/security/AuthorizationService.java +++ b/service/fling/src/main/java/net/friedl/fling/security/AuthorizationService.java @@ -1,14 +1,18 @@ package net.friedl.fling.security; +import java.util.NoSuchElementException; + import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import lombok.extern.slf4j.Slf4j; import net.friedl.fling.security.authentication.FlingToken; import net.friedl.fling.security.authentication.dto.UserAuthDto; import net.friedl.fling.service.FlingService; +@Slf4j @Service public class AuthorizationService { private FlingService flingService; @@ -18,11 +22,13 @@ public class AuthorizationService { this.flingService = flingService; } - public boolean allowUpload(Long flingId) { - return flingService - .findFlingById(flingId) - .orElseThrow() - .getAllowUpload(); + public boolean allowUpload(Long flingId, FlingToken authentication) { + if (authentication.getGrantedFlingAuthority().getAuthority().equals(FlingAuthority.FLING_OWNER.name())) { + return true; + } + + return flingService.findFlingById(flingId).orElseThrow().getAllowUpload() + && authentication.getGrantedFlingAuthority().getFlingId().equals(flingId); } public boolean allowFlingAccess(UserAuthDto userAuth, String shareUrl) { @@ -30,7 +36,7 @@ public class AuthorizationService { } public boolean allowFlingAccess(Long flingId, FlingToken authentication) { - if(authentication.getGrantedFlingAuthority().getAuthority().equals(FlingAuthority.FLING_OWNER.name())) { + if (authentication.getGrantedFlingAuthority().getAuthority().equals(FlingAuthority.FLING_OWNER.name())) { return true; } @@ -38,14 +44,22 @@ public class AuthorizationService { } public boolean allowFlingAccess(FlingToken authentication, HttpServletRequest request) { - if(authentication.getGrantedFlingAuthority().getAuthority().equals(FlingAuthority.FLING_OWNER.name())) { + if (authentication.getGrantedFlingAuthority().getAuthority().equals(FlingAuthority.FLING_OWNER.name())) { return true; } var shareId = request.getParameter("shareId"); - var flingId = shareId != null - ? flingService.findFlingByShareId(shareId).orElseThrow().getId() - : request.getParameter("flingId"); + + Long flingId; + + try { + flingId = shareId != null + ? flingService.findFlingByShareId(shareId).orElseThrow().getId() + : Long.parseLong(request.getParameter("flingId")); + } catch (NumberFormatException | NoSuchElementException e) { + log.warn("Invalid shareId [shareId=\"{}\"] or flingId [flingId=\"{}\"] found", request.getParameter("shareId"), request.getParameter("flingId")); + flingId = null; + } return authentication.getGrantedFlingAuthority().getFlingId().equals(flingId); } diff --git a/service/fling/src/main/java/net/friedl/fling/security/FlingWebSecurityConfigurer.java b/service/fling/src/main/java/net/friedl/fling/security/FlingWebSecurityConfigurer.java index 9a5b5df..892139c 100644 --- a/service/fling/src/main/java/net/friedl/fling/security/FlingWebSecurityConfigurer.java +++ b/service/fling/src/main/java/net/friedl/fling/security/FlingWebSecurityConfigurer.java @@ -68,7 +68,7 @@ public class FlingWebSecurityConfigurer extends WebSecurityConfigurerAdapter { .and() .authorizeRequests() .antMatchers(HttpMethod.POST, "/api/artifacts/{flingId}/**") - .access("hasAuthority('"+FlingAuthority.FLING_USER.name()+"') and @authorizationService.allowUpload(#flingId)") + .access("@authorizationService.allowUpload(#flingId, authentication)") .and() .authorizeRequests() // TODO: This is still insecure since URLs are not encrypted @@ -82,6 +82,12 @@ public class FlingWebSecurityConfigurer extends WebSecurityConfigurerAdapter { .regexMatchers(HttpMethod.GET, "\\/api\\/fling\\?(shareId=|flingId=)[a-zA-Z0-9]+") .access("@authorizationService.allowFlingAccess(authentication, request)") .and() + .authorizeRequests() + // TODO: Security by request parameters is just not well supported with spring security + // TODO: Change API + .regexMatchers(HttpMethod.GET, "\\/api\\/artifacts\\?(shareId=|flingId=)[a-zA-Z0-9]+") + .access("@authorizationService.allowFlingAccess(authentication, request)") + .and() .authorizeRequests() .antMatchers(HttpMethod.GET, "/api/fling/{flingId}/**") .access("@authorizationService.allowFlingAccess(#flingId, authentication)") diff --git a/service/fling/src/main/resources/application-local.yml b/service/fling/src/main/resources/application-local.yml index 0a62b0d..ffaf6ee 100644 --- a/service/fling/src/main/resources/application-local.yml +++ b/service/fling/src/main/resources/application-local.yml @@ -25,6 +25,8 @@ fling: allowed-origins: - "https://friedl.net" - "http://localhost:3000" + - "http://localhost:5000" + - "http://10.0.2.2:5000" admin-user: "${FLING_ADMIN_USER:admin}" admin-password: "${FLING_ADMIN_PASSWORD:123}" signing-key: "${FLING_SIGNING_KEY:changeitchangeitchangeitchangeit}" diff --git a/web/fling/package.json b/web/fling/package.json index b7e4bd3..20e6ba4 100644 --- a/web/fling/package.json +++ b/web/fling/package.json @@ -8,6 +8,7 @@ "@testing-library/user-event": "^7.2.1", "axios": "^0.19.2", "classnames": "^2.2.6", + "core-js": "^3.6.5", "jwt-decode": "^2.2.0", "loglevel": "^1.6.8", "node-sass": "^4.14.0", @@ -27,7 +28,7 @@ "eject": "react-scripts eject" }, "eslintConfig": { - "extends": "react-app" + "extends": "react-app" }, "browserslist": { "production": [ diff --git a/web/fling/src/components/LandingPage.jsx b/web/fling/src/components/LandingPage.jsx index d59e82e..4f2d774 100644 --- a/web/fling/src/components/LandingPage.jsx +++ b/web/fling/src/components/LandingPage.jsx @@ -44,8 +44,12 @@ export default function LandingPage() {