0.1 #1

Merged
armin merged 30 commits from 0.1 into master 2020-07-26 00:51:55 +00:00
3 changed files with 259 additions and 229 deletions
Showing only changes of commit c07a7866ce - Show all commits

View file

@ -77,14 +77,14 @@ public class FlingWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
/***********************************/ /***********************************/
/** Authorization for: /api/fling **/ /** Authorization for: /api/fling **/
/***********************************/ /***********************************/
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/api/fling/{flingId}/**")
.access("@authorizationService.allowFlingAccess(#flingId, authentication)")
.and()
.authorizeRequests() .authorizeRequests()
.antMatchers(HttpMethod.GET, "/api/fling/share/{shareId}") .antMatchers(HttpMethod.GET, "/api/fling/share/{shareId}")
.access("@authorizationService.allowFlingAccessByShareId(#shareId, authentication)") .access("@authorizationService.allowFlingAccessByShareId(#shareId, authentication)")
.and() .and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/api/fling/{flingId}/**")
.access("@authorizationService.allowFlingAccess(#flingId, authentication)")
.and()
.authorizeRequests() .authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/fling/{flingId}/artifact") .antMatchers(HttpMethod.POST, "/api/fling/{flingId}/artifact")
.access("@authorizationService.allowUpload(#flingId, authentication)") .access("@authorizationService.allowUpload(#flingId, authentication)")

View file

@ -69,6 +69,11 @@ public class AuthorizationService {
} }
public boolean allowFlingAccessByShareId(String shareId, AbstractAuthenticationToken token) { 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); FlingEntity flingEntity = flingRepository.findByShareId(shareId);
if(flingEntity == null) { throw new EntityNotFoundException("No entity for shareId="+shareId); } if(flingEntity == null) { throw new EntityNotFoundException("No entity for shareId="+shareId); }
return allowFlingAccess(flingEntity.getId(), token); return allowFlingAccess(flingEntity.getId(), token);

View file

@ -1,38 +1,40 @@
import log from 'loglevel'; 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) { export default function New(props) {
let defaultState = () => ({name: "", authCode: "", let defaultState = () => ({
sharing: {directDownload: true, allowUpload: false, shared: true, shareUrl: ""}, name: "", authCode: "",
expiration: {}}); sharing: { directDownload: true, allowUpload: false, shared: true, shareUrl: "" },
expiration: {}
});
let [fling, setFling] = useState(defaultState()); let [fling, setFling] = useState(defaultState());
let [shareUrlUnique, setShareUrlUnique] = useState(true); let [shareUrlUnique, setShareUrlUnique] = useState(true);
function toggleSharing(ev) { function toggleSharing(ev) {
let f = {...fling}; let f = { ...fling };
let s = {...fling.sharing}; let s = { ...fling.sharing };
if(ev.currentTarget.id === "direct-download") { if (ev.currentTarget.id === "direct-download") {
if(ev.currentTarget.checked) { if (ev.currentTarget.checked) {
s.directDownload = true; s.directDownload = true;
s.shared = true; s.shared = true;
s.allowUpload = false; s.allowUpload = false;
} else { } else {
s.directDownload = false; s.directDownload = false;
} }
} else if(ev.currentTarget.id === "allow-upload") { } else if (ev.currentTarget.id === "allow-upload") {
if(ev.currentTarget.checked) { if (ev.currentTarget.checked) {
s.allowUpload = true; s.allowUpload = true;
s.shared = true; s.shared = true;
s.directDownload = false; s.directDownload = false;
} else { } else {
s.allowUpload = false; s.allowUpload = false;
} }
} else if(ev.currentTarget.id === "shared") { } else if (ev.currentTarget.id === "shared") {
if(!ev.currentTarget.checked) { if (!ev.currentTarget.checked) {
s.allowUpload = s.directDownload = s.shared = false; s.allowUpload = s.directDownload = s.shared = false;
} else { } else {
s.shared = true; s.shared = true;
@ -45,16 +47,16 @@ export default function New(props) {
} }
function handleClose(ev) { function handleClose(ev) {
if(ev) ev.preventDefault(); // this is needed, otherwise a submit event is fired if (ev) ev.preventDefault(); // this is needed, otherwise a submit event is fired
props.closeModalFn(); props.closeModalFn();
} }
function setShareUrl(ev) { function setShareUrl(ev) {
let f = {...fling}; let f = { ...fling };
let s = {...fling.sharing}; //TODO: expiration is not cloned let s = { ...fling.sharing }; //TODO: expiration is not cloned
let value = ev.currentTarget.value; let value = ev.currentTarget.value;
if(!value) { if (!value) {
setShareUrlUnique(false); setShareUrlUnique(false);
s.shareUrl = value; s.shareUrl = value;
f.sharing = s; f.sharing = s;
@ -62,14 +64,15 @@ export default function New(props) {
return; return;
} }
const flingClient = new FlingClient();
flingClient.getFlingByShareId(ev.currentTarget.value) flingClient.getFlingByShareId(ev.currentTarget.value)
.then(result => { .then(result => {
if(!result) {
setShareUrlUnique(true);
} else {
setShareUrlUnique(false); setShareUrlUnique(false);
}).catch(error => {
if(error.status === 404) {
setShareUrlUnique(true);
} }
}).finally(() => {
s.shareUrl = value; s.shareUrl = value;
f.sharing = s; f.sharing = s;
setFling(f); setFling(f);
@ -77,7 +80,7 @@ export default function New(props) {
} }
function setName(ev) { function setName(ev) {
let f = {...fling}; let f = { ...fling };
let value = ev.currentTarget.value; let value = ev.currentTarget.value;
f.name = value; f.name = value;
@ -85,11 +88,11 @@ export default function New(props) {
} }
function setExpirationType(ev) { function setExpirationType(ev) {
let f = {...fling}; let f = { ...fling };
let e = {...fling.expiration}; //TODO: sharing is not cloned let e = { ...fling.expiration }; //TODO: sharing is not cloned
let value = ev.currentTarget.value; let value = ev.currentTarget.value;
if(value === "never") { if (value === "never") {
e = {}; e = {};
} else { } else {
e.type = value; e.type = value;
@ -101,9 +104,9 @@ export default function New(props) {
} }
function setExpirationValue(ev) { function setExpirationValue(ev) {
let f = {...fling}; let f = { ...fling };
let e = {...fling.expiration}; //TODO: sharing is not cloned let e = { ...fling.expiration }; //TODO: sharing is not cloned
let value = e.type === "time" ? ev.currentTarget.valueAsNumber: ev.currentTarget.value; let value = e.type === "time" ? ev.currentTarget.valueAsNumber : ev.currentTarget.value;
e.value = value; e.value = value;
@ -122,7 +125,7 @@ export default function New(props) {
} }
function setAuthCode(ev) { function setAuthCode(ev) {
let f = {...fling}; let f = { ...fling };
let value = ev.currentTarget.value; let value = ev.currentTarget.value;
f.authCode = value; f.authCode = value;
@ -132,13 +135,35 @@ export default function New(props) {
function handleSubmit(ev) { function handleSubmit(ev) {
ev.preventDefault(); ev.preventDefault();
log.info("Creating new filing"); log.info("Creating new filing");
log.info(fling); const flingClient = new FlingClient();
flingClient.postFling(fling);
handleClose(); 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;
}
} }
return( flingClient.postFling({fling: flingEntity})
<div className={`modal ${props.active ? "active": ""}`}> .then(() => handleClose())
.catch(error => log.error(error))
}
return (
<div className={`modal ${props.active ? "active" : ""}`}>
<div className="modal-overlay" aria-label="Close" onClick={handleClose}></div> <div className="modal-overlay" aria-label="Close" onClick={handleClose}></div>
<div className="modal-container"> <div className="modal-container">
<div className="modal-header"> <div className="modal-header">
@ -151,7 +176,7 @@ export default function New(props) {
<label className="form-label" htmlFor="input-name">Name</label> <label className="form-label" htmlFor="input-name">Name</label>
</div> </div>
<div className="col-9 col-sm-12"> <div className="col-9 col-sm-12">
<input className="form-input" type="text" id="input-name" value={fling.name} onChange={setName}/> <input className="form-input" type="text" id="input-name" value={fling.name} onChange={setName} />
</div> </div>
</div> </div>
<div className="form-group"> <div className="form-group">
@ -160,7 +185,7 @@ export default function New(props) {
</div> </div>
<div className="col-9 col-sm-12"> <div className="col-9 col-sm-12">
<input className="form-input" type="text" id="input-share-url" value={fling.sharing.shareUrl} onChange={setShareUrl} /> <input className="form-input" type="text" id="input-share-url" value={fling.sharing.shareUrl} onChange={setShareUrl} />
<i className={`icon icon-cross text-error ${shareUrlUnique ? "d-hide": "d-visible"}`} /> <i className={`icon icon-cross text-error ${shareUrlUnique ? "d-hide" : "d-visible"}`} />
</div> </div>
</div> </div>
@ -171,7 +196,7 @@ export default function New(props) {
<div className="col-9 col-sm-12"> <div className="col-9 col-sm-12">
<div className="input-group"> <div className="input-group">
<input className="form-input" type="text" value={fling.authCode} onChange={setAuthCode} /> <input className="form-input" type="text" value={fling.authCode} onChange={setAuthCode} />
<label className="form-switch ml-2 tooltip tooltip-left" data-tooltip={fling.authCode ? "Clear passcode to\ndisable protection": "Set passcode to\nenable protection"} > <label className="form-switch ml-2 tooltip tooltip-left" data-tooltip={fling.authCode ? "Clear passcode to\ndisable protection" : "Set passcode to\nenable protection"} >
<input type="checkbox" checked={!!fling.authCode} readOnly /> <input type="checkbox" checked={!!fling.authCode} readOnly />
<i className="form-icon" /> Protected <i className="form-icon" /> Protected
</label> </label>
@ -192,7 +217,7 @@ export default function New(props) {
</select> </select>
</div> </div>
<div className={fling.expiration.type === "clicks" ? "d-visible": "d-hide"}> <div className={fling.expiration.type === "clicks" ? "d-visible" : "d-hide"}>
<div className="input-group"> <div className="input-group">
<span className="input-group-addon">Expire after</span> <span className="input-group-addon">Expire after</span>
<input className="form-input" type="number" value={fling.expiration.value || ""} onChange={setExpirationValue} /> <input className="form-input" type="number" value={fling.expiration.value || ""} onChange={setExpirationValue} />
@ -200,7 +225,7 @@ export default function New(props) {
</div> </div>
</div> </div>
<div className={fling.expiration.type === "time" ? "d-visible": "d-hide"}> <div className={fling.expiration.type === "time" ? "d-visible" : "d-hide"}>
<div className="input-group"> <div className="input-group">
<span className="input-group-addon">Expire after</span> <span className="input-group-addon">Expire after</span>
<input className="form-input" type="date" value={formatExpirationTime()} onChange={setExpirationValue} /> <input className="form-input" type="date" value={formatExpirationTime()} onChange={setExpirationValue} />
@ -216,15 +241,15 @@ export default function New(props) {
<div className="col-9 col-sm-12"> <div className="col-9 col-sm-12">
<label className="form-switch form-inline"> <label className="form-switch form-inline">
<input type="checkbox" id="shared" checked={fling.sharing.shared} onChange={toggleSharing}/> <input type="checkbox" id="shared" checked={fling.sharing.shared} onChange={toggleSharing} />
<i className="form-icon" /> Shared <i className="form-icon" /> Shared
</label> </label>
<label className="form-switch form-inline"> <label className="form-switch form-inline">
<input type="checkbox" id="allow-upload" checked={fling.sharing.allowUpload} onChange={toggleSharing}/> <input type="checkbox" id="allow-upload" checked={fling.sharing.allowUpload} onChange={toggleSharing} />
<i className="form-icon" /> Uploads <i className="form-icon" /> Uploads
</label> </label>
<label className="form-switch form-inline"> <label className="form-switch form-inline">
<input type="checkbox" id="direct-download" checked={fling.sharing.directDownload} onChange={toggleSharing}/> <input type="checkbox" id="direct-download" checked={fling.sharing.directDownload} onChange={toggleSharing} />
<i className="form-icon" /> Direct Download <i className="form-icon" /> Direct Download
</label> </label>
</div> </div>