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 6c06ab4..b4c3f1e 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
@@ -10,16 +10,19 @@ 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.ArtifactService;
import net.friedl.fling.service.FlingService;
@Slf4j
@Service
public class AuthorizationService {
private FlingService flingService;
+ private ArtifactService artifactService;
@Autowired
- public AuthorizationService(FlingService flingService) {
+ public AuthorizationService(FlingService flingService, ArtifactService artifactService) {
this.flingService = flingService;
+ this.artifactService = artifactService;
}
public boolean allowUpload(Long flingId, FlingToken authentication) {
@@ -27,8 +30,14 @@ public class AuthorizationService {
return true;
}
- return flingService.findFlingById(flingId).orElseThrow().getAllowUpload()
- && authentication.getGrantedFlingAuthority().getFlingId().equals(flingId);
+ var uploadAllowed = flingService.findFlingById(flingId).orElseThrow().getAllowUpload();
+
+ return uploadAllowed && authentication.getGrantedFlingAuthority().getFlingId().equals(flingId);
+ }
+
+ public boolean allowPatchingArtifact(Long artifactId, FlingToken authentication) {
+ var flingId = artifactService.findArtifact(artifactId).orElseThrow().getFling().getId();
+ return allowUpload(flingId, authentication);
}
public boolean allowFlingAccess(UserAuthDto userAuth, String shareUrl) {
@@ -57,7 +66,8 @@ public class AuthorizationService {
? 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"));
+ log.warn("Invalid shareId [shareId=\"{}\"] or flingId [flingId=\"{}\"] found",
+ request.getParameter("shareId"), request.getParameter("flingId"));
flingId = null;
}
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 892139c..158033c 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
@@ -70,6 +70,10 @@ public class FlingWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
.antMatchers(HttpMethod.POST, "/api/artifacts/{flingId}/**")
.access("@authorizationService.allowUpload(#flingId, authentication)")
.and()
+ .authorizeRequests()
+ .antMatchers(HttpMethod.PATCH, "/api/artifacts/{artifactId}")
+ .access("@authorizationService.allowPatchingArtifact(#artifactId, authentication)")
+ .and()
.authorizeRequests()
// TODO: This is still insecure since URLs are not encrypted
// TODO: iframe requests don't send the bearer, use cookie instead
diff --git a/web/fling/src/App.jsx b/web/fling/src/App.jsx
index 1accc0c..d3dcb83 100644
--- a/web/fling/src/App.jsx
+++ b/web/fling/src/App.jsx
@@ -22,7 +22,7 @@ export default () => {
-
+
Not implemented
diff --git a/web/fling/src/components/user/FlingUser.jsx b/web/fling/src/components/user/FlingUser.jsx
index 874efca..4b6dc55 100644
--- a/web/fling/src/components/user/FlingUser.jsx
+++ b/web/fling/src/components/user/FlingUser.jsx
@@ -19,7 +19,9 @@ export default function FlingUser() {
return(
- {fling.sharing && fling.sharing.directDownload ? : }
+ {fling.sharing && fling.sharing.directDownload
+ ?
+ : }
);
}
diff --git a/web/fling/src/components/user/FlingUserList.jsx b/web/fling/src/components/user/FlingUserList.jsx
index bfde251..c61e46a 100644
--- a/web/fling/src/components/user/FlingUserList.jsx
+++ b/web/fling/src/components/user/FlingUserList.jsx
@@ -1,10 +1,13 @@
import log from 'loglevel';
import React, {useState, useEffect, useRef} from 'react';
-import {useParams, BrowserRouter} from 'react-router-dom';
+import {Switch, Route, Redirect, BrowserRouter, useLocation, useParams, Link} from "react-router-dom";
import {flingClient, artifactClient} from '../../util/flingclient';
+import upload from '../resources/upload.svg';
+import drop from '../resources/drop.svg';
+
function Artifacts(props) {
let [artifacts, setArtifacts] = useState([]);
@@ -60,7 +63,220 @@ function Artifacts(props) {
);
}
+function Upload(props) {
+ let fileInputRef = useRef(null);
+ let [files, setFiles] = useState([]);
+ let [dragging, setDragging] = useState(false);
+ let [dragCount, setDragCount] = useState(0);
+
+ useEffect(() => {
+ // prevent browser from trying to open the file when drag event
+ // not recognized properly
+ window.addEventListener("dragover",function(e){
+ e.preventDefault();
+ },false);
+ window.addEventListener("drop",function(e){
+ e.preventDefault();
+ },false);
+ });
+
+ function fileList() {
+ function readableBytes(bytes) {
+ if(bytes <= 0) return "0 KB";
+
+ var i = Math.floor(Math.log(bytes) / Math.log(1024)),
+ sizes = ['Byte', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
+
+ return (bytes / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + sizes[i];
+ }
+
+ let fileList = [];
+ files.forEach((file,idx) => {
+ if(!file.uploaded) {
+ fileList.push(
+
+
+
+
deleteFile(idx)}/>
+ {file.name}
+ {(new Date(file.lastModified)).toLocaleString()+", "+readableBytes(file.size)}
+
+
+
+ );
+ }
+ });
+
+ return fileList;
+ }
+
+ function deleteFile(idx) {
+ let f = [...files];
+ f.splice(idx, 1);
+ setFiles(f);
+ }
+
+ function totalSize() {
+ function readableBytes(bytes) {
+ if(bytes <= 0) return "0 KB";
+
+ var i = Math.floor(Math.log(bytes) / Math.log(1024)),
+ sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
+
+ return (bytes / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + sizes[i];
+ }
+
+ let totalSize = 0;
+ for(let file of files) {
+ totalSize += file.size;
+ }
+
+ return readableBytes(totalSize);
+ }
+
+ function handleClick(ev) {
+ fileInputRef.current.click();
+ }
+
+ function handleFileInputChange(ev) {
+ let fileInputFiles = fileInputRef.current.files;
+ if (!fileInputFiles) {
+ console.warn("No files selected");
+ return;
+ }
+
+ setFiles([...files, ...fileInputFiles]);
+ }
+
+ function handleDrop(ev) {
+ stopEvent(ev);
+ ev.persist();
+
+ let evFiles = ev.dataTransfer.files;
+
+ if (!evFiles) {
+ console.warn("Dropzone triggered without files");
+ return;
+ }
+
+ setFiles([...files, ...fileListToArray(evFiles)]);
+ setDragging(false);
+ setDragCount(0);
+ }
+
+ function fileListToArray(fileList) {
+ if(fileList === undefined || fileList === null) {
+ return [];
+ }
+
+ let arr = [];
+ for (let i=0; i i.name).join(',')+"]");
+ }
+
+ function setFileUploaded(idx) {
+ let f = [...files];
+ f[idx].uploaded = true;
+ setFiles(f);
+ }
+
+ function handleUpload() {
+ let f = [...files];
+
+ files.forEach((file, idx) => {
+ artifactClient.postArtifact(props.fling.id, file)
+ .then(response => {
+ setFileUploaded(idx);
+ });
+ });
+ }
+
+ function zoneContent(dragging) {
+ if(dragging){
+ return(
+ <>
+
+ Drop now!
+ >
+ );
+ }else {
+ return(
+ <>
+
+ Click or Drop
+ >
+ );
+ }
+ }
+
+ return(
+
+ {logFiles()}
+
+
+
+
+
+ {zoneContent(dragging)}
+
+
+
+
+
+
+
+
+ Total Size: {totalSize()}
+
+
+
+
+
+
+ );
+}
+
export default function FlingUserList(props) {
+ let location = useLocation();
+
let iframeContainer = useRef(null);
let [infoText, setInfoText] = useState("");
let [inProgress, setInProgress] = useState(false);
@@ -117,9 +333,16 @@ export default function FlingUserList(props) {
});
}
+ function path(tail) {
+ if(props.fling && props.fling.sharing) {
+ return `/f/${props.fling.sharing.shareUrl}/${tail}`;
+ }
+
+ return "";
+ }
+
return(
<>
-
@@ -129,11 +352,11 @@ export default function FlingUserList(props) {
- -
- Files
+
-
+ Files
- -
- Upload
+
-
+ Upload
-
@@ -150,7 +373,11 @@ export default function FlingUserList(props) {