From e424c9ef09ef0215da868658ee877907fdf536ce Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sun, 26 Jul 2020 10:34:05 +0200 Subject: [PATCH] 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. --- .../net/friedl/fling/FlingConfiguration.java | 1 - .../fling/controller/ArtifactController.java | 7 +++++ .../spring-configuration-metadata.json | 6 ++++ .../src/main/resources/application-local.yml | 3 +- .../src/main/resources/application-prod.yml | 1 + web/fling/.env | 1 + web/fling/.env.development.local | 2 ++ web/fling/package-lock.json | 5 ++++ web/fling/package.json | 3 +- .../src/components/admin/FlingArtifacts.jsx | 4 ++- web/fling/src/components/admin/Upload.jsx | 18 ++++++++++-- .../src/components/user/FlingUserList.jsx | 29 +++++++++++++++---- web/fling/src/index.js | 1 + 13 files changed, 69 insertions(+), 12 deletions(-) diff --git a/service/fling/src/main/java/net/friedl/fling/FlingConfiguration.java b/service/fling/src/main/java/net/friedl/fling/FlingConfiguration.java index 485d4e4..ceff877 100644 --- a/service/fling/src/main/java/net/friedl/fling/FlingConfiguration.java +++ b/service/fling/src/main/java/net/friedl/fling/FlingConfiguration.java @@ -16,7 +16,6 @@ import net.friedl.fling.model.json.PathSerializer; @Configuration public class FlingConfiguration { - @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); diff --git a/service/fling/src/main/java/net/friedl/fling/controller/ArtifactController.java b/service/fling/src/main/java/net/friedl/fling/controller/ArtifactController.java index e6e126f..7cedd55 100644 --- a/service/fling/src/main/java/net/friedl/fling/controller/ArtifactController.java +++ b/service/fling/src/main/java/net/friedl/fling/controller/ArtifactController.java @@ -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()); } diff --git a/service/fling/src/main/resources/META-INF/spring-configuration-metadata.json b/service/fling/src/main/resources/META-INF/spring-configuration-metadata.json index fd20a97..38cf357 100644 --- a/service/fling/src/main/resources/META-INF/spring-configuration-metadata.json +++ b/service/fling/src/main/resources/META-INF/spring-configuration-metadata.json @@ -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" } ] } \ No newline at end of file diff --git a/service/fling/src/main/resources/application-local.yml b/service/fling/src/main/resources/application-local.yml index 43108ed..1ea4f2d 100644 --- a/service/fling/src/main/resources/application-local.yml +++ b/service/fling/src/main/resources/application-local.yml @@ -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: diff --git a/service/fling/src/main/resources/application-prod.yml b/service/fling/src/main/resources/application-prod.yml index d7bdb3e..389537b 100644 --- a/service/fling/src/main/resources/application-prod.yml +++ b/service/fling/src/main/resources/application-prod.yml @@ -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: diff --git a/web/fling/.env b/web/fling/.env index e605af4..f01232d 100644 --- a/web/fling/.env +++ b/web/fling/.env @@ -1,2 +1,3 @@ REACT_APP_API=https://fling.friedl.net REACT_APP_LOGLEVEL=warn +REACT_APP_FILESIZE=209715200 diff --git a/web/fling/.env.development.local b/web/fling/.env.development.local index ecf9b5b..3d23ba8 100644 --- a/web/fling/.env.development.local +++ b/web/fling/.env.development.local @@ -1,2 +1,4 @@ REACT_APP_API=http://localhost:8080/ REACT_APP_LOGLEVEL=trace +REACT_APP_FILESIZE=209715200 + diff --git a/web/fling/package-lock.json b/web/fling/package-lock.json index dd87126..f3f2f9b 100644 --- a/web/fling/package-lock.json +++ b/web/fling/package-lock.json @@ -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", diff --git a/web/fling/package.json b/web/fling/package.json index 62946c6..6e521cc 100644 --- a/web/fling/package.json +++ b/web/fling/package.json @@ -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", diff --git a/web/fling/src/components/admin/FlingArtifacts.jsx b/web/fling/src/components/admin/FlingArtifacts.jsx index 0e71e5b..6b26de1 100644 --- a/web/fling/src/components/admin/FlingArtifacts.jsx +++ b/web/fling/src/components/admin/FlingArtifacts.jsx @@ -100,7 +100,9 @@ export default function FlingArtifacts() { .then(result => { log.debug(`Got ${result.length} artifacts`); for (let artifact of result) { - artifacts.push(); + if(artifact.archived) { + artifacts.push(); + } } setArtifacts(artifacts); diff --git a/web/fling/src/components/admin/Upload.jsx b/web/fling/src/components/admin/Upload.jsx index 2996c46..ab174ad 100644 --- a/web/fling/src/components/admin/Upload.jsx +++ b/web/fling/src/components/admin/Upload.jsx @@ -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() {
Total Size: {totalSize()} + {`Max: ${prettifyBytes(process.env.REACT_APP_FILESIZE)}`}
diff --git a/web/fling/src/components/user/FlingUserList.jsx b/web/fling/src/components/user/FlingUserList.jsx index 9d213c3..ccb6a66 100644 --- a/web/fling/src/components/user/FlingUserList.jsx +++ b/web/fling/src/components/user/FlingUserList.jsx @@ -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) {
Total Size: {totalSize()} + {`Max: ${prettifyBytes(process.env.REACT_APP_FILESIZE)}`}
@@ -303,10 +320,10 @@ export default function FlingUserList(props) {
  • Files
  • - { props.fling.allowUpload + {props.fling.allowUpload ?
  • - Upload -
  • + Upload + : <> } diff --git a/web/fling/src/index.js b/web/fling/src/index.js index 1172ef8..4f7cc84 100644 --- a/web/fling/src/index.js +++ b/web/fling/src/index.js @@ -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'; -- 2.45.2