Settings and checks for maximum artifact size #2

Manually merged
armin merged 1 commit from feature/max-artifact-size into master 2020-07-26 08:36:44 +00:00
13 changed files with 69 additions and 12 deletions

View file

@ -16,7 +16,6 @@ import net.friedl.fling.model.json.PathSerializer;
@Configuration
public class FlingConfiguration {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();

View file

@ -4,6 +4,7 @@ import java.io.IOException;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
@ -32,6 +33,8 @@ import net.friedl.fling.service.archive.ArchiveService;
@SecurityRequirement(name = "bearer")
@Validated
public class ArtifactController {
@Value("${fling.max-artifact-size:-1}")
private Long maxArtifactSize;
private ArtifactService artifactService;
private ArchiveService archiveService;
@ -58,6 +61,10 @@ public class ArtifactController {
@PostMapping(path = "/{id}/data")
public void uploadArtifactData(@PathVariable UUID id, HttpServletRequest request)
throws IOException {
if(maxArtifactSize >= 0 && maxArtifactSize < request.getContentLengthLong()) {
throw new IOException("Maximum artifact size exceeded");
}
archiveService.storeArtifact(id, request.getInputStream());
}

View file

@ -70,6 +70,12 @@
"type": "java.util.Long",
"description": "Time until JWT tokens expire",
"sourceType": "net.friedl.fling.security.FlingWebSecurityConfiguration"
},
{
"name": "fling.max-artifact-size",
"type": "java.util.Long",
"description": "Maximum artifact size in bytes. -1 to disable.",
"sourceType": "net.friedl.fling.controller.ArtifactController"
}
]
}

View file

@ -11,7 +11,7 @@ spring:
servlet:
multipart.max-file-size: -1
multipart.max-request-size: -1
logging.level:
root: WARN
net.friedl: TRACE
@ -21,6 +21,7 @@ logging.level:
# spring.http.log-request-details: true
fling:
max-artifact-size: 209715200 # 200 MB
archive.filesystem.archive-path: /home/armin/Desktop/fling
security:
allowed-origins:

View file

@ -16,6 +16,7 @@ logging.level:
root: WARN
fling:
max-artifact-size: 209715200 # 200 MB
archive.filesystem.archive-path: "/var/fling/files"
security:
allowed-origins:

View file

@ -1,2 +1,3 @@
REACT_APP_API=https://fling.friedl.net
REACT_APP_LOGLEVEL=warn
REACT_APP_FILESIZE=209715200

View file

@ -1,2 +1,4 @@
REACT_APP_API=http://localhost:8080/
REACT_APP_LOGLEVEL=trace
REACT_APP_FILESIZE=209715200

View file

@ -13376,6 +13376,11 @@
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
"integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
},
"vanillatoasts": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/vanillatoasts/-/vanillatoasts-1.4.0.tgz",
"integrity": "sha512-DVMPPWVVt/x1B2f4iVpCw3rYDceu1PGRV8ECc3OfUC8By6O14OdXWjKryfaz8UorBuNe8btDIsujp6YP6gDNGA=="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",

View file

@ -22,7 +22,8 @@
"react-scripts": "3.4.1",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"spectre.css": "^0.5.8"
"spectre.css": "^0.5.8",
"vanillatoasts": "^1.4.0"
},
"scripts": {
"start": "react-scripts start",

View file

@ -100,7 +100,9 @@ export default function FlingArtifacts() {
.then(result => {
log.debug(`Got ${result.length} artifacts`);
for (let artifact of result) {
artifacts.push(<FlingArtifactRow key={artifact.id} artifact={artifact} reloadArtifactsFn={getArtifacts} />);
if(artifact.archived) {
artifacts.push(<FlingArtifactRow key={artifact.id} artifact={artifact} reloadArtifactsFn={getArtifacts} />);
}
}
setArtifacts(artifacts);

View file

@ -1,4 +1,5 @@
import log from 'loglevel';
import VanillaToasts from 'vanillatoasts';
import React, { useState, useEffect, useRef } from 'react';
import { useSelector } from "react-redux";
@ -81,9 +82,21 @@ export default function Upload() {
stopEvent(ev);
ev.persist();
let evFiles = ev.dataTransfer.files;
let maxSize = process.env.REACT_APP_FILESIZE;
let evFiles = fileListToArray(ev.dataTransfer.files);
if (!evFiles) {
for (let i = evFiles.length - 1; i >= 0; i--) {
if (maxSize && maxSize >= 0 && evFiles[i].size > maxSize) {
VanillaToasts.create({
title: "Maximum file size exceeded",
text: `${evFiles[i].name} exceeds the maximum file size of ${prettifyBytes(maxSize)}`,
type: "warning"
});
evFiles.splice(i, 1);
};
}
if (evFiles.lenght === 0) {
console.warn("Dropzone triggered without files");
return;
}
@ -198,6 +211,7 @@ export default function Upload() {
</div>
<div className="upload-command-line m-2">
<span className="total-upload">Total Size: {totalSize()}</span>
<span className="total-upload">{`Max: ${prettifyBytes(process.env.REACT_APP_FILESIZE)}`}</span>
<button className="btn btn-primary btn-upload" onClick={handleUpload}>Upload</button>
</div>
</div>

View file

@ -1,4 +1,5 @@
import log from 'loglevel';
import VanillaToasts from 'vanillatoasts';
import React, { useState, useEffect, useRef } from 'react';
import { Switch, Route, useLocation, Link } from "react-router-dom";
@ -17,7 +18,10 @@ function Artifacts(props) {
let flingClient = new FlingClient();
flingClient.getArtifacts(props.fling.id)
.then(artifacts => setArtifacts(artifacts));
.then(artifacts => {
artifacts = artifacts.filter(a => a.archived)
setArtifacts(artifacts)
});
}, [props.fling]);
function renderArtifact(artifact) {
@ -119,9 +123,21 @@ function Upload(props) {
stopEvent(ev);
ev.persist();
let evFiles = ev.dataTransfer.files;
let maxSize = process.env.REACT_APP_FILESIZE;
let evFiles = fileListToArray(ev.dataTransfer.files);
if (!evFiles) {
for (let i = evFiles.length - 1; i >= 0; i--) {
if (maxSize && maxSize >= 0 && evFiles[i].size > maxSize) {
VanillaToasts.create({
title: "Maximum file size exceeded",
text: `${evFiles[i].name} exceeds the maximum file size of ${prettifyBytes(maxSize)}`,
type: "warning"
});
evFiles.splice(i, 1);
};
}
if (evFiles.length === 0) {
console.warn("Dropzone triggered without files");
return;
}
@ -236,6 +252,7 @@ function Upload(props) {
</div>
<div className="upload-command-line m-2">
<span className="total-upload">Total Size: {totalSize()}</span>
<span className="total-upload">{`Max: ${prettifyBytes(process.env.REACT_APP_FILESIZE)}`}</span>
<button className="btn btn-primary btn-upload" onClick={handleUpload}>Upload</button>
</div>
</div>
@ -303,10 +320,10 @@ export default function FlingUserList(props) {
<li className={`tab-item ${location.pathname !== path("upload") ? "active" : ""}`}>
<Link to={path("files")}>Files</Link>
</li>
{ props.fling.allowUpload
{props.fling.allowUpload
? <li className={`tab-item ${location.pathname === path("upload") ? "active" : ""}`}>
<Link to={path("upload")}>Upload</Link>
</li>
<Link to={path("upload")}>Upload</Link>
</li>
: <></>
}

View file

@ -14,6 +14,7 @@ import { BrowserRouter } from "react-router-dom";
import App from './App';
import 'vanillatoasts/vanillatoasts.css';
import "./style/fling.scss";
import * as serviceWorker from './serviceWorker';