mirror of
https://codeberg.org/tyy/aspm
synced 2024-12-22 15:59:29 -07:00
naja-server: fix update bug, enable h2c, add logging, add docker configs; naja-lib: add insecure option when debug_assertions are enabled; nana-cli: add insecure option when debug_assertions are enabled
This commit is contained in:
parent
0c5452a1b8
commit
a6b7790107
11 changed files with 117 additions and 16 deletions
5
.dockerignore
Normal file
5
.dockerignore
Normal file
|
@ -0,0 +1,5 @@
|
|||
.vscode/*
|
||||
./keys
|
||||
./target
|
||||
./*.jwk
|
||||
./README.md
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
/target
|
||||
*.jw[tk]
|
||||
/server-data
|
30
Cargo.lock
generated
30
Cargo.lock
generated
|
@ -1222,6 +1222,29 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"humantime",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
|
@ -1703,6 +1726,12 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.4.0"
|
||||
|
@ -2339,6 +2368,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"actix-web",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"naja-lib",
|
||||
"sea-orm",
|
||||
"serde",
|
||||
|
|
26
Dockerfile
Normal file
26
Dockerfile
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Using the `rust-musl-builder` as base image, instead of
|
||||
# the official Rust toolchain
|
||||
FROM clux/muslrust:1.79.0-stable AS chef
|
||||
USER root
|
||||
# Install cargo-chef
|
||||
RUN cargo install cargo-chef --locked
|
||||
WORKDIR /app
|
||||
|
||||
FROM chef AS planner
|
||||
COPY . .
|
||||
# Cache all dependencies for the server
|
||||
RUN cargo chef prepare --recipe-path recipe.json --bin naja-server
|
||||
|
||||
FROM chef AS builder
|
||||
COPY --from=planner /app/recipe.json recipe.json
|
||||
# Build dependencies
|
||||
RUN cargo chef cook --release --target x86_64-unknown-linux-musl --recipe-path recipe.json --package naja-server
|
||||
COPY . .
|
||||
# Build main binary
|
||||
RUN cargo build --release --target x86_64-unknown-linux-musl --package naja-server
|
||||
|
||||
FROM alpine AS runtime
|
||||
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/naja-server /usr/local/bin/
|
||||
HEALTHCHECK --interval=10s --timeout=3s \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:$NAJA_BIND_PORT/ || exit 1
|
||||
CMD ["/usr/local/bin/naja-server"]
|
|
@ -29,12 +29,16 @@ pub struct AspeDeleteCommand {
|
|||
/// The ASPE server to upload this profile to
|
||||
#[clap(value_parser = Host::parse)]
|
||||
server: Host,
|
||||
/// (dev only) If the ASPE server is insecure (not HTTPS)
|
||||
#[cfg(debug_assertions)]
|
||||
#[arg(long)]
|
||||
insecure: bool,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl NajaSubcommand for AspeDeleteCommand {
|
||||
async fn execute(self, state: crate::CliState) -> Result<(), anyhow::Error> {
|
||||
let server = AspeServer::new(self.server)
|
||||
let server = AspeServer::new(self.server, #[cfg(debug_assertions)] self.insecure)
|
||||
.await
|
||||
.context("Unable to parse provided server into ASPE server, please verify that it is a valid ASPE server")?;
|
||||
|
||||
|
|
|
@ -38,12 +38,16 @@ pub struct AspeUploadCommand {
|
|||
/// If passed, this command will only create new keys on the server, rather than updating if the key already exists
|
||||
#[clap(long)]
|
||||
no_update: bool,
|
||||
/// (dev only) If the ASPE server is insecure (not HTTPS)
|
||||
#[cfg(debug_assertions)]
|
||||
#[arg(long)]
|
||||
insecure: bool,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl NajaSubcommand for AspeUploadCommand {
|
||||
async fn execute(self, state: crate::CliState) -> Result<(), anyhow::Error> {
|
||||
let server = AspeServer::new(self.server)
|
||||
let server = AspeServer::new(self.server, #[cfg(debug_assertions)] self.insecure)
|
||||
.await
|
||||
.context("Unable to parse provided server into ASPE server, please verify that it is a valid ASPE server")?;
|
||||
|
||||
|
|
|
@ -21,6 +21,10 @@ pub struct ProfilesImportCommand {
|
|||
/// The alias to give to the imported profile
|
||||
#[clap(trailing_var_arg = true)]
|
||||
alias: Vec<String>,
|
||||
/// (dev only) If the ASPE server is insecure (not HTTPS)
|
||||
#[cfg(debug_assertions)]
|
||||
#[arg(long)]
|
||||
insecure: bool,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
|
@ -32,7 +36,7 @@ impl NajaSubcommand for ProfilesImportCommand {
|
|||
(host.to_string(), fingerprint.to_string())
|
||||
})
|
||||
}) {
|
||||
Some((host, fingerprint)) => match aspe::AspeServer::new(Host::parse(&host).unwrap())
|
||||
Some((host, fingerprint)) => match aspe::AspeServer::new(Host::parse(&host).unwrap(), #[cfg(debug_assertions)] self.insecure)
|
||||
.await?
|
||||
.fetch_profile(&fingerprint)
|
||||
.await
|
||||
|
|
|
@ -20,6 +20,7 @@ pub struct AspeVersion {
|
|||
#[derive(Clone)]
|
||||
pub struct AspeServer {
|
||||
pub host: Host,
|
||||
insecure: bool, // This is here for developing with local ASPE servers, but cannot actually be set to true in release binaries
|
||||
client: reqwest::Client,
|
||||
}
|
||||
|
||||
|
@ -78,16 +79,18 @@ impl From<reqwest::Error> for AspeFetchFailure {
|
|||
|
||||
impl AspeServer {
|
||||
/// Creates a new [AspeServer] instance given the specified domain. A domain and ONLY a domain should be provided (no scheme, no path, etc).
|
||||
pub async fn new(host: Host) -> anyhow::Result<Self> {
|
||||
pub async fn new(host: Host, #[cfg(debug_assertions)] insecure: bool) -> anyhow::Result<Self> {
|
||||
#[cfg(not(debug_assertions))] let insecure = false;
|
||||
let server = Self {
|
||||
host,
|
||||
insecure,
|
||||
client: reqwest::Client::builder()
|
||||
.user_agent(format!(
|
||||
"naja-lib/{version} ({repo})",
|
||||
version = env!("CARGO_PKG_VERSION"),
|
||||
repo = env!("CARGO_PKG_REPOSITORY")
|
||||
))
|
||||
.https_only(true)
|
||||
.https_only(!insecure)
|
||||
.build()?,
|
||||
};
|
||||
|
||||
|
@ -101,7 +104,8 @@ impl AspeServer {
|
|||
pub async fn version(&self) -> Result<(), reqwest::Error> {
|
||||
self.client
|
||||
.get(format!(
|
||||
"https://{host}/.well-known/aspe/version",
|
||||
"{scheme}://{host}/.well-known/aspe/version",
|
||||
scheme = if self.insecure { "http" } else { "https" },
|
||||
host = self.host
|
||||
))
|
||||
.header(
|
||||
|
@ -119,7 +123,8 @@ impl AspeServer {
|
|||
pub async fn post_request(&self, jws: impl Into<String>) -> Result<(), AspeRequestFailure> {
|
||||
self.client
|
||||
.post(format!(
|
||||
"https://{host}/.well-known/aspe/post",
|
||||
"{scheme}://{host}/.well-known/aspe/post",
|
||||
scheme = if self.insecure { "http" } else { "https" },
|
||||
host = self.host
|
||||
))
|
||||
.header(
|
||||
|
@ -141,8 +146,9 @@ impl AspeServer {
|
|||
let res = self
|
||||
.client
|
||||
.get(format!(
|
||||
"https://{host}/.well-known/aspe/id/{fingerprint}",
|
||||
"{scheme}://{host}/.well-known/aspe/id/{fingerprint}",
|
||||
host = self.host,
|
||||
scheme = if self.insecure { "http" } else { "https" },
|
||||
fingerprint = fingerprint.as_ref()
|
||||
))
|
||||
.header(
|
||||
|
@ -167,12 +173,12 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn building_aspe_server_succeeds() {
|
||||
AspeServer::new(Host::Domain(String::from("keyoxide.org"))).await.expect("Contructing an AspeServer should succeed");
|
||||
AspeServer::new(Host::Domain(String::from("keyoxide.org")), false).await.expect("Contructing an AspeServer should succeed");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn building_invalid_aspe_server_fails() {
|
||||
let result = AspeServer::new(Host::Domain(String::from("example.com"))).await;
|
||||
let result = AspeServer::new(Host::Domain(String::from("example.com")), false).await;
|
||||
assert!(result.is_err(), "Constructing an AspeServer with an invalid domain should fail")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,3 +12,4 @@ sea-orm = { version = "0.12", features = ["sqlx-sqlite", "runtime-tokio-rustls",
|
|||
serde = { version = "1.0.204", features = ["derive"] }
|
||||
naja-lib = { path = "../naja-lib" }
|
||||
migrations = { path = "../server-migrations", package = "server-migrations" }
|
||||
env_logger = "0.11.3"
|
||||
|
|
|
@ -3,9 +3,10 @@ mod entities;
|
|||
|
||||
use std::{fs, io, path::PathBuf};
|
||||
|
||||
use actix_web::{get, http::header, post, web, App, HttpResponse, HttpServer, Responder};
|
||||
use actix_web::{get, http::header, middleware::Logger, post, web, App, HttpResponse, HttpServer, Responder};
|
||||
use clap::Parser;
|
||||
use entities::{prelude::*, profiles};
|
||||
use env_logger::Env;
|
||||
use migrations::{Migrator, MigratorTrait as _};
|
||||
use naja_lib::{
|
||||
aspe::requests::{AspeRequest, AspeRequestVariant},
|
||||
|
@ -13,7 +14,7 @@ use naja_lib::{
|
|||
utils::jwt::{JwtDeserializationError, JwtSerialize},
|
||||
};
|
||||
use sea_orm::{
|
||||
ActiveValue, ColumnTrait as _, Database, DatabaseConnection, DbErr, EntityTrait, QueryFilter,
|
||||
ActiveValue, Database, DatabaseConnection, DbErr, EntityTrait,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
|
@ -69,14 +70,16 @@ async fn main() -> io::Result<()> {
|
|||
domain: args.domain,
|
||||
};
|
||||
|
||||
env_logger::init_from_env(Env::default().default_filter_or("info"));
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.wrap(Logger::default())
|
||||
.app_data(web::Data::new(state.clone()))
|
||||
.service(version)
|
||||
.service(get_by_fingerprint)
|
||||
.service(post_request)
|
||||
})
|
||||
.bind((args.bind_address, args.port))?
|
||||
.bind_auto_h2c((args.bind_address, args.port))?
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
|
@ -164,10 +167,9 @@ async fn post_request(
|
|||
Ok(_) => {
|
||||
// Must be AspeRequestvariant::Update { .. }
|
||||
match Profiles::update(profiles::ActiveModel {
|
||||
fingerprint: ActiveValue::Unchanged(key.fingerprint.to_owned()),
|
||||
jwt: ActiveValue::Set(profile_jws.to_owned()),
|
||||
..Default::default()
|
||||
})
|
||||
.filter(profiles::Column::Fingerprint.eq(&key.fingerprint))
|
||||
.exec(&state.db)
|
||||
.await
|
||||
{
|
||||
|
|
18
docker-compose.dev.yml
Normal file
18
docker-compose.dev.yml
Normal file
|
@ -0,0 +1,18 @@
|
|||
services:
|
||||
server:
|
||||
image: naja-server
|
||||
build:
|
||||
dockerfile: Dockerfile
|
||||
network: host
|
||||
environment:
|
||||
NAJA_DATA_PATH: /home/naja/.local/share/naja-server/
|
||||
NAJA_BIND_ADDRESS: 0.0.0.0
|
||||
NAJA_BIND_PORT: 80
|
||||
NAJA_DOMAIN: localhost
|
||||
RUST_LOG: actix_web=debug,actix_server=info
|
||||
ports:
|
||||
- 80:80
|
||||
restart: always
|
||||
container_name: naja-server
|
||||
volumes:
|
||||
- ./server-data:/home/naja/.local/share/naja-server/
|
Loading…
Reference in a new issue