Compare commits

..

No commits in common. "master" and "feature/max-artifact-size" have entirely different histories.

17 changed files with 23 additions and 145 deletions

View file

@ -74,13 +74,12 @@ steps:
- ls -al - ls -al
- cd web/fling - cd web/fling
- npm install && npm run build - npm install && npm run build
- npm install --no-cache @fling/flingclient # make sure flingclient is not cached
- tar czf fling-web-$VERSION.tar.gz build/ - tar czf fling-web-$VERSION.tar.gz build/
- curl --user "$NEXUS_USER:$NEXUS_PASSWORD" - curl --user "$NEXUS_USER:$NEXUS_PASSWORD"
--upload-file ./fling-web-$VERSION.tar.gz --upload-file ./fling-web-$VERSION.tar.gz
https://nexus.friedl.net/repository/build-artifacts/fling-web-$VERSION.tar.gz https://nexus.friedl.net/repository/build-artifacts/fling-web-$VERSION.tar.gz
- name: publish branch - name: publish
image: plugins/docker image: plugins/docker
settings: settings:
username: username:
@ -93,29 +92,6 @@ steps:
tags: 0.1.0-snapshot tags: 0.1.0-snapshot
build_args: build_args:
- VERSION=0.1.0-snapshot - VERSION=0.1.0-snapshot
when:
branch:
exclude:
- master
- name: publish master
image: plugins/docker
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
dockerfile: container/Dockerfile
context: ./container
repo: arminfriedl/fling
tags:
- 0.1.0-snapshot
- latest
build_args:
- VERSION=0.1.0-snapshot
when:
branch:
- master
volumes: volumes:
- name: m2-cache - name: m2-cache

View file

@ -1,68 +0,0 @@
**12.01.2021: Fling has moved to the attic**
Fling was a good learning experiment for a non-trivial React app with a REST
backend. However, it never really got any traction and I'm not using it anymore.
Other projects are more important to me and maintaining Fling does not make any
sense. As of now docker containers are deleted and the artifacts are not
distributed anymore. You are free to fork and build your own version but no more
work will be done in this repository.
Alternatives:
- If you are looking for mature self-hosted file sharing solution,
[ownCloud](https://owncloud.com/) is in many ways similar to Fling and then
some.
- If you want an even simpler solution for sharing files over http,
[dirl](https://github.com/arminfriedl/dirl) might meet your needs.
# Fling
Fling is a self-hosted file share. It is simple like USB without missing out on
the good parts of a web app:
- Just drop files on a Fling and share the URL
- Choose your own name for your share-URL
- Share a direct download link
- Let others upload files
- Protect your fling by a password - no registration required
- Let a fling expire after a date or a number of clicks
# API
Fling is distributed as both, a backend service and a web interface. You can use
the backend on its own with any [HTTP client](examples).
Per default Fling publishes a Swagger UI page and an OpenAPI spec. You can find
them here:
``` http
http://<host>:<port>/swagger-ui.html
http://<host>:<port>/v3/api-docs
```
If starting the fling container locally, the default `<host>:<port>` is
http://localhost:3000. You can also find a recent version of it via
https://fling.friedl.net/swagger-ui.html and
https://fling.friedl.net/v3/api-docs.
# Starting Fling from Docker
A Fling container is provided at https://hub.docker.com/repository/docker/arminfriedl/fling.
1. Run `docker run --rm -p3000:3000 arminfriedl/fling`
2. Go to the default http://localhost:3000
3. Log in with `adminName:adminPassword`.
## Configuring Fling
The Fling container can be configured by environment variables.
The web interface configuration ([config.js](web/fling/public/config.js)/[config.js.template](container/var/www/fling/config.js.template)) will be
filled by `envsubst` when the container starts up.
``` sh
# The base URL of the Fling API service
FLING_API_BASE=http://localhost:3000
# Log level of the application
FLING_LOG_LEVEL=warn
# Max. upload size in bytes. Checked on client side.
FLING_FILESIZE=209715200
```
The Fling service configuration is a standard spring configuration. It can be
set by environement variables or any other [configuration externalization supported by spring boot]
(https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config)).
Refer to the [application-prod.yml](service/fling/src/main/resources/application-prod.yml) for configuration options.

View file

@ -2,11 +2,7 @@ FROM alpine:latest
ARG VERSION ARG VERSION
ENV FLING_API_BASE http://localhost:3000 RUN apk add --update --no-cache nginx openjdk11-jre && \
ENV FLING_LOG_LEVEL warn
ENV FLING_FILESIZE 209715200
RUN apk add --update --no-cache nginx openjdk11-jre gettext && \
mkdir -p /var/fling/files && \ mkdir -p /var/fling/files && \
mkdir -p /tmp/fling && \ mkdir -p /tmp/fling && \
wget -O /tmp/fling/service.jar "https://nexus.friedl.net/service/rest/v1/search/assets/download?sort=version&maven.groupId=net.friedl&maven.artifactId=fling&maven.baseVersion=$(echo -n $VERSION | tr [:lower:] [:upper:])&maven.extension=jar" && \ wget -O /tmp/fling/service.jar "https://nexus.friedl.net/service/rest/v1/search/assets/download?sort=version&maven.groupId=net.friedl&maven.artifactId=fling&maven.baseVersion=$(echo -n $VERSION | tr [:lower:] [:upper:])&maven.extension=jar" && \
@ -18,8 +14,7 @@ RUN apk add --update --no-cache nginx openjdk11-jre gettext && \
mv /tmp/fling/service.jar ./service.jar mv /tmp/fling/service.jar ./service.jar
COPY ./etc/nginx/conf.d /etc/nginx/conf.d COPY ./etc/nginx/conf.d /etc/nginx/conf.d
COPY ./var/www/fling/config.js.template /var/www/fling/config.js.template COPY ./entrypoint.sh ./usr/local/bin/entrypoint.sh
COPY ./entrypoint.sh /usr/local/bin/entrypoint.sh
VOLUME /var/fling/ VOLUME /var/fling/

View file

@ -6,6 +6,4 @@ mkdir /var/run/nginx # nginx fails with /var/run/nginx/nginx.pid not found in al
nginx nginx
cat /var/www/fling/config.js.template | envsubst > /var/www/fling/config.js
java ${FL_JVM_OPTS} -jar service.jar java ${FL_JVM_OPTS} -jar service.jar

View file

@ -61,23 +61,6 @@ server {
proxy_set_header Connection "upgrade"; proxy_set_header Connection "upgrade";
} }
# handle openapi requests by openapi servlet
location /swagger-ui {
proxy_pass http://localhost:8080;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
# Required for web sockets to function
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# always respond with index.html for unknown paths # always respond with index.html for unknown paths
# (routing is client side) # (routing is client side)
location / { location / {

View file

@ -1,5 +0,0 @@
window['flingconfig'] = {
API_BASE: "${FLING_API_BASE}",
LOG_LEVEL: "${FLING_LOG_LEVEL}",
FILESIZE: "${FLING_FILESIZE}"
}

View file

@ -20,8 +20,7 @@ fling:
archive.filesystem.archive-path: "/var/fling/files" archive.filesystem.archive-path: "/var/fling/files"
security: security:
allowed-origins: allowed-origins:
- "https://fling.friedl.net" - "https://friedl.net"
- "http://localhost:3000"
- "http://localhost:3000" - "http://localhost:3000"
- "http://localhost:5000" - "http://localhost:5000"
- "http://10.0.2.2:5000" - "http://10.0.2.2:5000"
@ -32,4 +31,4 @@ fling:
api: api:
version: "0.1.0-snapshot" version: "0.1.0-snapshot"
server-url: "http://localhost:8080" server-url: "http://localhost:8080"
server-description: "API server for dev" server-description: "API server for dev"

View file

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

View file

@ -1,5 +0,0 @@
window['flingconfig'] = {
API_BASE: "http://localhost:8080",
LOG_LEVEL: "warn",
FILESIZE: 209715200
}

View file

@ -4,7 +4,6 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="%PUBLIC_URL%/fling.ico"> <link rel="shortcut icon" href="%PUBLIC_URL%/fling.ico">
<script src="%PUBLIC_URL%/config.js"></script>
<!-- <!--
Notice the use of %PUBLIC_URL% in the tag above. Notice the use of %PUBLIC_URL% in the tag above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.

View file

@ -22,7 +22,7 @@ function FlingArtifactControl(props) {
// the browser downloads the file fine, it also reloads the page, hence // the browser downloads the file fine, it also reloads the page, hence
// loosing all logs and state // loosing all logs and state
let frame = document.createElement("iframe"); let frame = document.createElement("iframe");
let url = `${window['flingconfig'].API_BASE.replace(/\/+$/, '')}/api/artifacts/${props.artifact.id}/data?derivedToken=${token}`; let url = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/artifacts/${props.artifact.id}/data?derivedToken=${token}`;
log.trace(`Generated download url: ${url}`); log.trace(`Generated download url: ${url}`);
frame.src = url; frame.src = url;
iframeContainer.current.appendChild(frame); iframeContainer.current.appendChild(frame);

View file

@ -23,6 +23,12 @@ export default function Navbar() {
Fling Fling
</a> </a>
</section> </section>
<section className="navbar-center">
<div className="input-group input-inline">
<input className="form-input input-sm" type="text" placeholder="Search" />
<button className="btn btn-sm btn-link input-group-btn"><i className="icon icon-search"/></button>
</div>
</section>
<section className="navbar-section navbar-control"> <section className="navbar-section navbar-control">
<button className="btn btn-sm btn-link" onClick={handleOnClick}><i className="icon icon-plus"/> New</button> <button className="btn btn-sm btn-link" onClick={handleOnClick}><i className="icon icon-plus"/> New</button>
<a className="btn btn-sm btn-link" href="/admin/login"><i className="icon icon-shutdown"/> Logout</a> <a className="btn btn-sm btn-link" href="/admin/login"><i className="icon icon-shutdown"/> Logout</a>

View file

@ -82,7 +82,7 @@ export default function Upload() {
stopEvent(ev); stopEvent(ev);
ev.persist(); ev.persist();
let maxSize = window['flingconfig'].FILESIZE; let maxSize = process.env.REACT_APP_FILESIZE;
let evFiles = fileListToArray(ev.dataTransfer.files); let evFiles = fileListToArray(ev.dataTransfer.files);
for (let i = evFiles.length - 1; i >= 0; i--) { for (let i = evFiles.length - 1; i >= 0; i--) {
@ -211,7 +211,7 @@ export default function Upload() {
</div> </div>
<div className="upload-command-line m-2"> <div className="upload-command-line m-2">
<span className="total-upload">Total Size: {totalSize()}</span> <span className="total-upload">Total Size: {totalSize()}</span>
<span className="total-upload">{`Max: ${prettifyBytes(window['flingconfig'].FILESIZE)}`}</span> <span className="total-upload">{`Max: ${prettifyBytes(process.env.REACT_APP_FILESIZE)}`}</span>
<button className="btn btn-primary btn-upload" onClick={handleUpload}>Upload</button> <button className="btn btn-primary btn-upload" onClick={handleUpload}>Upload</button>
</div> </div>
</div> </div>

View file

@ -16,7 +16,7 @@ export default function FlingUser(props) {
let authClient = new AuthClient(); let authClient = new AuthClient();
authClient.deriveToken({ singleUse: true }) authClient.deriveToken({ singleUse: true })
.then(token => { .then(token => {
let url = `${window['flingconfig'].API_BASE.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`; let url = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`;
log.trace(`Generated download url for link: ${url}`); log.trace(`Generated download url for link: ${url}`);
setDownloadUrl(url); setDownloadUrl(url);
}) })
@ -28,7 +28,7 @@ export default function FlingUser(props) {
// the browser downloads the file fine, it also reloads the page, hence // the browser downloads the file fine, it also reloads the page, hence
// loosing all logs and state // loosing all logs and state
let frame = document.createElement("iframe"); let frame = document.createElement("iframe");
let url = `${window['flingconfig'].API_BASE.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`; let url = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`;
log.trace(`Generated download url: ${url}`); log.trace(`Generated download url: ${url}`);
frame.src = url; frame.src = url;
iframeContainer.current.appendChild(frame); iframeContainer.current.appendChild(frame);

View file

@ -123,7 +123,7 @@ function Upload(props) {
stopEvent(ev); stopEvent(ev);
ev.persist(); ev.persist();
let maxSize = window['flingconfig'].FILESIZE; let maxSize = process.env.REACT_APP_FILESIZE;
let evFiles = fileListToArray(ev.dataTransfer.files); let evFiles = fileListToArray(ev.dataTransfer.files);
for (let i = evFiles.length - 1; i >= 0; i--) { for (let i = evFiles.length - 1; i >= 0; i--) {
@ -252,7 +252,7 @@ function Upload(props) {
</div> </div>
<div className="upload-command-line m-2"> <div className="upload-command-line m-2">
<span className="total-upload">Total Size: {totalSize()}</span> <span className="total-upload">Total Size: {totalSize()}</span>
<span className="total-upload">{`Max: ${prettifyBytes(window['flingconfig'].FILESIZE)}`}</span> <span className="total-upload">{`Max: ${prettifyBytes(process.env.REACT_APP_FILESIZE)}`}</span>
<button className="btn btn-primary btn-upload" onClick={handleUpload}>Upload</button> <button className="btn btn-primary btn-upload" onClick={handleUpload}>Upload</button>
</div> </div>
</div> </div>
@ -290,7 +290,7 @@ export default function FlingUserList(props) {
// the browser downloads the file fine, it also reloads the page, hence // the browser downloads the file fine, it also reloads the page, hence
// loosing all logs and state // loosing all logs and state
let frame = document.createElement("iframe"); let frame = document.createElement("iframe");
let url = `${window['flingconfig'].API_BASE.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`; let url = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`;
log.trace(`Generated download url: ${url}`); log.trace(`Generated download url: ${url}`);
frame.src = url; frame.src = url;
setInProgress(false); setInProgress(false);

View file

@ -21,8 +21,8 @@ import * as serviceWorker from './serviceWorker';
/* Logging Setup */ /* Logging Setup */
log.setDefaultLevel(log.levels.TRACE); log.setDefaultLevel(log.levels.TRACE);
if (window['flingconfig'].LOG_LEVEL) { if (process.env.REACT_APP_LOGLEVEL) {
log.setLevel(window['flingconfig'].LOG_LEVEL); log.setLevel(process.env.REACT_APP_LOGLEVEL);
} }
/* Store setup */ /* Store setup */

View file

@ -9,7 +9,7 @@ import * as fc from '@fling/flingclient';
*/ */
let clientConfig = (token) => { let clientConfig = (token) => {
let config = new fc.ApiClient(); let config = new fc.ApiClient();
config.basePath = window['flingconfig'].API_BASE.replace(/\/+$/, ''); config.basePath = process.env.REACT_APP_API.replace(/\/+$/, '');
token = token || sessionStorage.getItem('token'); token = token || sessionStorage.getItem('token');
if (token) { config.authentications['bearer'].accessToken = token; } if (token) { config.authentications['bearer'].accessToken = token; }