Settings and checks for maximum artifact size
Different archive backends may not cope well with large file sizes. Additionally, Fling admins may want to restrict the maximum file size to protect their server.
This commit is contained in:
parent
d4b7f1db30
commit
e424c9ef09
13 changed files with 69 additions and 12 deletions
|
@ -16,7 +16,6 @@ import net.friedl.fling.model.json.PathSerializer;
|
|||
|
||||
@Configuration
|
||||
public class FlingConfiguration {
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
REACT_APP_API=https://fling.friedl.net
|
||||
REACT_APP_LOGLEVEL=warn
|
||||
REACT_APP_FILESIZE=209715200
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
REACT_APP_API=http://localhost:8080/
|
||||
REACT_APP_LOGLEVEL=trace
|
||||
REACT_APP_FILESIZE=209715200
|
||||
|
||||
|
|
5
web/fling/package-lock.json
generated
5
web/fling/package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -100,8 +100,10 @@ export default function FlingArtifacts() {
|
|||
.then(result => {
|
||||
log.debug(`Got ${result.length} artifacts`);
|
||||
for (let artifact of result) {
|
||||
if(artifact.archived) {
|
||||
artifacts.push(<FlingArtifactRow key={artifact.id} artifact={artifact} reloadArtifactsFn={getArtifacts} />);
|
||||
}
|
||||
}
|
||||
|
||||
setArtifacts(artifacts);
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Reference in a new issue