From a4c19b5f1fa409295335d65b50e49d8decad9792 Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Sat, 1 Aug 2026 21:56:05 +0200 Subject: [PATCH] Add api key, gpg key, and move flatpakrepo --- README.md | 14 ++++++++++++++ src/flatpak.rs | 2 +- src/main.rs | 12 ++++++++++++ src/upload.rs | 18 +++++++++++++++++- 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 957f10c..04af39d 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,17 @@ A minimal HTTP server for hosting an OSTree/Flatpak repository, written in Rust Includes a non-standard route for uploading flatpak bundles: curl -v -XPOST -T ./org.example.Example.aarch64.flatpak http://localhost:3000/flatpak-bundle/upload + +## Missing features + +flatpak-repo does not generate an ostree folder for you. Create one like this: + + ostree init --repo=~/my-repo --mode=archive-z2 + +flatpak-repo does not generate gpg keys for you. + +flatpak-repo does not generate a `flatpakrepo` file for you, but expects one to be places in the repo folder. + +add the flatpak remo like this: + + sudo flatpak remote-add --from https:///flatpakrepo diff --git a/src/flatpak.rs b/src/flatpak.rs index 0dab8c9..d442fae 100644 --- a/src/flatpak.rs +++ b/src/flatpak.rs @@ -42,7 +42,7 @@ pub async fn flatpak_headers_middleware(req: Request, next: Next) -> Respo } pub async fn serve_flatpakrepo(repo_path: PathBuf) -> impl IntoResponse { - let path = repo_path.join("example.flatpakrepo"); + let path = repo_path.join("flatpakrepo"); match tokio::fs::read_to_string(&path).await { Ok(contents) => ( [(header::CONTENT_TYPE, "application/octet-stream")], diff --git a/src/main.rs b/src/main.rs index a06490a..2e5d966 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,8 @@ mod util; #[derive(Default)] struct SrvState { repo: Mutex, + api_key: String, + gpg_key_id: String, } type SharedState = Arc; @@ -33,6 +35,14 @@ struct Opt { #[clap(long, env = "FR_REPO_PATH")] repo: PathBuf, + /// GPG key id for signing the repository + #[clap(long, env = "FR_GPG_KEY_ID")] + gpg: String, + + /// API key for uploading flatpak + #[clap(long, env = "FR_API_KEY")] + api_key: String, + #[clap(long, env = "RUST_LOG", default_value = "debug")] log_level: String, } @@ -60,6 +70,8 @@ async fn main() -> anyhow::Result<()> { let state = SrvState { repo: Mutex::new(repo.clone()), + gpg_key_id: opt.gpg, + api_key: opt.api_key, }; let state: SharedState = Arc::new(state); diff --git a/src/upload.rs b/src/upload.rs index e55cdd6..f1dd79e 100644 --- a/src/upload.rs +++ b/src/upload.rs @@ -1,15 +1,30 @@ use anyhow::Context; -use axum::{body::Body, extract::State, http::StatusCode}; +use axum::{ + body::Body, + extract::{Query, State}, + http::StatusCode, +}; use futures::{StreamExt, future::ready, stream}; +use serde::Deserialize; use tempfile::NamedTempFile; use tokio::{io::AsyncWriteExt, process::Command, task::block_in_place}; use crate::{SharedState, util::e}; +#[derive(Deserialize)] +pub struct Params { + key: String, +} + pub async fn flatpak_bundle( State(state): State, + Query(params): Query, body: Body, ) -> Result<(), StatusCode> { + if params.key != state.api_key { + return Err(StatusCode::UNAUTHORIZED); + } + let mut stream = body.into_data_stream(); // Get first chunks @@ -61,6 +76,7 @@ pub async fn flatpak_bundle( tracing::info!("Importing {tmp_path:?} into repo {:?}", &*repo); let output = Command::new("flatpak") .arg("build-import-bundle") + .args(["--gpg-sign", &state.gpg_key_id]) .args([&*repo, &tmp_path]) .output() .await