Newer
Older
This repository contains one modular Go project:
- `qr-share`: Server handling image uploads -- serving with expiring URLS, watermarking and padding
- `storage`: Internal HTTP service for handling image uploads from `api`
- `gateway`: Public HTTP service for serving uploaded images from `storage` with URL verification
- `cleanup`: generic cleanup handler based on timestamp in filename, runs on the compute node to remove uploaded images.
- `api`: Server handling communication between comfyui <> end devices
- x86_64 GNU/Linux host, tested on NixOS 24.05 x86_64 host with a 6.10.8 kernel.
- GNU make, tested with 4.4.1.
- GNU coreutils, tested with 9.5.
- GNU findutils for `find`, tested with 4.9.0.
- Golang (CGO is not used), please refer to the `go.mod` for the required version.
You can likely substitute all of these dependencies with equivalents from, e.g., busybox or BSD, but only the above were actively tested.
This project is only tested/ developed for one specific environment, this is NOT a project you should deploy without reading all contained code.
You may then build the binary: `make build`
To start a local server with all roles (assuming `127.0.0.1:8195` points to a comfy ui server): `make dev`
> A warning for anyone trying to read the code:
> This was written during a crunch.
> The quality deterioated a lot during this and my attempts at repairing parts afterward were cut short (time/other reponsibilities).
> It was finished just in time and serves it purpose (and really only it, nothing else).
QR share is modularized into two distinct subcomponents, each offering their own HTTP API:
- `console`: acting as the adminstrativ frontend that is used by `gateway` for uploading images.
This component also handles deleting expired images in the background.
It may only be accessible to `gateway` and does not have any built-in auth/autz.
- `public`: acting as the publicly available frontend for serving images created by `console`.
It may be publicly available for users to access their generated images.
Both components are contained in the main binary, you may use the `-roles` CLI flag to start either component.
A single process may run both components at a time however this is not recommended outside local development.
Both components need access to a shared state directory where uploaded files are supposed to be stored.
This represents the only persistent state for both servers.
`console` requires read and write permissions, however `public` only requires read permissions for this directory.
The files in this directory follow the naming scheme `{epoch(expiry)}-{fnv1a(promptID)}-{number}.png`, where:
- `epoch(expiry)`: is the UNIX timestamp in seconds of the expiry date for the file (creation time + 15 minutes)
- `fnv1a(promptID)`: is a 64-bit [FNV-1A](https://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function) hash of the prompt ID specified during creation.
This hash is not intended to obscure/ hide the prompt ID but instead allows URLs to be shorter (shrinking 256 byte UUID to 64 byte hash).
- `number`: the image number (for workflows who output multiple images, usually between 0-3)
### Signed URLs
> Givent that we expose derivative images of people's faces I wanted to ensure that our URLs are safe against enumeration attacks[^1].
> To do this, we borrow the concept of signed URLs from S3 services, like AWS S3.
Both `gateway` and `console` don't share any explicit in-process state but instead use signed URLs for out-of band URL verification.
This is done via an embedded ed25519 signature in the URLs created by `console`.
This signature covers the expiration time, hashed prompt ID and image number.
To enable this both need to have acess to a keypair of ed25519 keys, where:
- `console`: requires the private key and
- `gateway`: requires the public key
To make their generation and usage convenient, `console` and `gateway` expect ed25519 keys in the same format as openssh.
This means, you can utilise `ssh-keygen -t ed25519` to generate a keypair directly.
Samples of known-working keys are supplied in `samples`.
[^1]:
An attack enumerates publicly available endpoints to find confidential information, like a shared image.
This may be done by guessing the URL parameters directly via a guided brute-force approach.
## `api` - ComfyUI gateway
`api` is a convenient frontend for the comfy UI API that wraps all the varying comfyUI messages in standardised messages.
It offers a websocket-based API for submitting prompts and receiving update messages.
This websocket API offers a concept of named clients to enable sticky reconnects for mobile end devices.
Gateway requires access to `qr-share`'s `console` for sharing the output from workflows.
This component does not have any builtin auth/autz and expects to have them handled by a reverse proxy.
It also is built for well-behaved clients and is only supposed to be used with the flutter client.
`api` also offers a _metrics_ server that exposes a [prometheus](https://prometheus.io/)-compatible endpoint.
This endpoint exposes metrics about processed workflow numbers, printed images and connected clients.
The metrics are fully anonymous and only intended to allow use basic bookkeeping of consumed ressources.
Optionally, the metrics server may also expose the [HTTP API for pprof](https://pkg.go.dev/net/http/pprof) for debugging.
This can be utilised to, e.g., get an overview of running goroutines or memory allocations.
## Open-Source
This project is open-source but not open-contribution.
It was created for our internal use at NHR@ZIB and is mainly open-source to provide transparency over data processing.
All source code is licensed under the [GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.en.html) 3.0 license, see the `LICENSE` file for the full text.