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 e5a0d0f..180d2cf 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 @@ -77,15 +77,15 @@ public class FlingWebSecurityConfigurer extends WebSecurityConfigurerAdapter { /***********************************/ /** Authorization for: /api/fling **/ /***********************************/ - .authorizeRequests() - .antMatchers(HttpMethod.GET, "/api/fling/{flingId}/**") - .access("@authorizationService.allowFlingAccess(#flingId, authentication)") - .and() .authorizeRequests() .antMatchers(HttpMethod.GET, "/api/fling/share/{shareId}") .access("@authorizationService.allowFlingAccessByShareId(#shareId, authentication)") .and() .authorizeRequests() + .antMatchers(HttpMethod.GET, "/api/fling/{flingId}/**") + .access("@authorizationService.allowFlingAccess(#flingId, authentication)") + .and() + .authorizeRequests() .antMatchers(HttpMethod.POST, "/api/fling/{flingId}/artifact") .access("@authorizationService.allowUpload(#flingId, authentication)") .and() diff --git a/service/fling/src/main/java/net/friedl/fling/service/AuthorizationService.java b/service/fling/src/main/java/net/friedl/fling/service/AuthorizationService.java index a405cfe..e136e31 100644 --- a/service/fling/src/main/java/net/friedl/fling/service/AuthorizationService.java +++ b/service/fling/src/main/java/net/friedl/fling/service/AuthorizationService.java @@ -69,6 +69,11 @@ public class AuthorizationService { } public boolean allowFlingAccessByShareId(String shareId, AbstractAuthenticationToken token) { + if (FlingAuthorities.FLING_ADMIN.verify(token)) { + log.debug("Owner authorized for fling access [shareId = {}]", shareId); + return true; + } + FlingEntity flingEntity = flingRepository.findByShareId(shareId); if(flingEntity == null) { throw new EntityNotFoundException("No entity for shareId="+shareId); } return allowFlingAccess(flingEntity.getId(), token); diff --git a/web/fling/src/components/admin/New.jsx b/web/fling/src/components/admin/New.jsx index 7a8fb30..2f3b43a 100644 --- a/web/fling/src/components/admin/New.jsx +++ b/web/fling/src/components/admin/New.jsx @@ -1,242 +1,267 @@ import log from 'loglevel'; -import React, {useState} from 'react'; +import React, { useState } from 'react'; -import {flingClient} from '../../util/flingclient'; +import { FlingClient, fc } from '../../util/fc'; export default function New(props) { - let defaultState = () => ({name: "", authCode: "", - sharing: {directDownload: true, allowUpload: false, shared: true, shareUrl: ""}, - expiration: {}}); + let defaultState = () => ({ + name: "", authCode: "", + sharing: { directDownload: true, allowUpload: false, shared: true, shareUrl: "" }, + expiration: {} + }); - let [fling, setFling] = useState(defaultState()); - let [shareUrlUnique, setShareUrlUnique] = useState(true); + let [fling, setFling] = useState(defaultState()); + let [shareUrlUnique, setShareUrlUnique] = useState(true); - function toggleSharing(ev) { - let f = {...fling}; - let s = {...fling.sharing}; + function toggleSharing(ev) { + let f = { ...fling }; + let s = { ...fling.sharing }; - if(ev.currentTarget.id === "direct-download") { - if(ev.currentTarget.checked) { - s.directDownload = true; - s.shared = true; - s.allowUpload = false; - } else { - s.directDownload = false; - } - } else if(ev.currentTarget.id === "allow-upload") { - if(ev.currentTarget.checked) { - s.allowUpload = true; - s.shared = true; - s.directDownload = false; - } else { - s.allowUpload = false; - } - } else if(ev.currentTarget.id === "shared") { - if(!ev.currentTarget.checked) { - s.allowUpload = s.directDownload = s.shared = false; - } else { - s.shared = true; - } + if (ev.currentTarget.id === "direct-download") { + if (ev.currentTarget.checked) { + s.directDownload = true; + s.shared = true; + s.allowUpload = false; + } else { + s.directDownload = false; + } + } else if (ev.currentTarget.id === "allow-upload") { + if (ev.currentTarget.checked) { + s.allowUpload = true; + s.shared = true; + s.directDownload = false; + } else { + s.allowUpload = false; + } + } else if (ev.currentTarget.id === "shared") { + if (!ev.currentTarget.checked) { + s.allowUpload = s.directDownload = s.shared = false; + } else { + s.shared = true; + } + } + + f.sharing = s; + + setFling(f); + } + + function handleClose(ev) { + if (ev) ev.preventDefault(); // this is needed, otherwise a submit event is fired + props.closeModalFn(); + } + + function setShareUrl(ev) { + let f = { ...fling }; + let s = { ...fling.sharing }; //TODO: expiration is not cloned + let value = ev.currentTarget.value; + + if (!value) { + setShareUrlUnique(false); + s.shareUrl = value; + f.sharing = s; + setFling(f); + return; + } + + const flingClient = new FlingClient(); + flingClient.getFlingByShareId(ev.currentTarget.value) + .then(result => { + setShareUrlUnique(false); + }).catch(error => { + if(error.status === 404) { + setShareUrlUnique(true); } - + }).finally(() => { + s.shareUrl = value; f.sharing = s; - setFling(f); + }); + } + + function setName(ev) { + let f = { ...fling }; + let value = ev.currentTarget.value; + + f.name = value; + setFling(f); + } + + function setExpirationType(ev) { + let f = { ...fling }; + let e = { ...fling.expiration }; //TODO: sharing is not cloned + let value = ev.currentTarget.value; + + if (value === "never") { + e = {}; + } else { + e.type = value; + e.value = ""; } - function handleClose(ev) { - if(ev) ev.preventDefault(); // this is needed, otherwise a submit event is fired - props.closeModalFn(); + f.expiration = e; + setFling(f); + } + + function setExpirationValue(ev) { + let f = { ...fling }; + let e = { ...fling.expiration }; //TODO: sharing is not cloned + let value = e.type === "time" ? ev.currentTarget.valueAsNumber : ev.currentTarget.value; + + e.value = value; + + f.expiration = e; + setFling(f); + } + + function formatExpirationTime() { + if (!fling.expiration || !fling.expiration.value || fling.expiration.type !== "time") + return ""; + + + let date = new Date(fling.expiration.value); + let fmt = date.toISOString().split("T")[0]; + return fmt; + } + + function setAuthCode(ev) { + let f = { ...fling }; + let value = ev.currentTarget.value; + + f.authCode = value; + setFling(f); + } + + function handleSubmit(ev) { + ev.preventDefault(); + log.info("Creating new filing"); + const flingClient = new FlingClient(); + + let flingEntity = new fc.Fling(fling.name); + flingEntity.directDownload = fling.sharing.directDownload; + flingEntity.allowUpload = fling.sharing.allowUpload; + flingEntity.shared = fling.sharing.shared; + flingEntity.shareId = fling.sharing.shareUrl; + flingEntity.authCode = fling.authCode; + if (fling.expiration.type) { + switch (fling.expiration.type) { + case "time": + flingEntity.expirationTime = fling.expiration.value; + break; + case "clicks": + flingEntity.expirationClicks = fling.expiration.value; + break; + default: + log.warn("Unknown expiration type"); + break; + } } - function setShareUrl(ev) { - let f = {...fling}; - let s = {...fling.sharing}; //TODO: expiration is not cloned - let value = ev.currentTarget.value; + flingClient.postFling({fling: flingEntity}) + .then(() => handleClose()) + .catch(error => log.error(error)) + } - if(!value) { - setShareUrlUnique(false); - s.shareUrl = value; - f.sharing = s; - setFling(f); - return; - } - - flingClient.getFlingByShareId(ev.currentTarget.value) - .then(result => { - if(!result) { - setShareUrlUnique(true); - } else { - setShareUrlUnique(false); - } - - s.shareUrl = value; - f.sharing = s; - setFling(f); - }); - } - - function setName(ev) { - let f = {...fling}; - let value = ev.currentTarget.value; - - f.name = value; - setFling(f); - } - - function setExpirationType(ev) { - let f = {...fling}; - let e = {...fling.expiration}; //TODO: sharing is not cloned - let value = ev.currentTarget.value; - - if(value === "never") { - e = {}; - } else { - e.type = value; - e.value = ""; - } - - f.expiration = e; - setFling(f); - } - - function setExpirationValue(ev) { - let f = {...fling}; - let e = {...fling.expiration}; //TODO: sharing is not cloned - let value = e.type === "time" ? ev.currentTarget.valueAsNumber: ev.currentTarget.value; - - e.value = value; - - f.expiration = e; - setFling(f); - } - - function formatExpirationTime() { - if (!fling.expiration || !fling.expiration.value || fling.expiration.type !== "time") - return ""; - - - let date = new Date(fling.expiration.value); - let fmt = date.toISOString().split("T")[0]; - return fmt; - } - - function setAuthCode(ev) { - let f = {...fling}; - let value = ev.currentTarget.value; - - f.authCode = value; - setFling(f); - } - - function handleSubmit(ev) { - ev.preventDefault(); - log.info("Creating new filing"); - log.info(fling); - flingClient.postFling(fling); - handleClose(); - } - - return( -
-
-
-
-
New Fling
-
-
-
-
-
- -
-
- -
-
-
-
- -
-
- - -
-
- -
-
- -
-
-
- - -
-
-
- -
-
- -
-
-
- -
- -
-
- Expire after - - Clicks -
-
- -
-
- Expire after - -
-
-
-
- -
-
- -
-
- - - - -
-
- -
- - -
- -
-
+ return ( +
+
+
+
+
New Fling
- ); +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ + +
+
+ +
+
+ +
+
+
+ + +
+
+
+ +
+
+ +
+
+
+ +
+ +
+
+ Expire after + + Clicks +
+
+ +
+
+ Expire after + +
+
+
+
+ +
+
+ +
+
+ + + + +
+
+ +
+ + +
+ +
+
+
+ ); }