[package]
name = "frogue"
version = "0.1.0+alpha.1"
edition = "2024"
[dependencies]
actix-web = "4.15.0"
# Signed cookie sessions, stateless: the browser carries the session and the
# server verifies its signature rather than looking anything up.
actix-session = { version = "0.11.0", features = ["cookie-session"] }
# Multipart form data for file uploads (ticket attachments).
actix-multipart = "0.7"
# Stream combinators for reading multipart fields.
futures-util = "0.3"
# argon2id, the current standard for hashing passwords. Pure Rust.
argon2 = "0.5.3"
# Timestamps for the columns the entities already express as
# `DateTimeWithTimeZone`; the SSH server records when a key was last used.
chrono = "0.4.45"
# HTML as Rust code: elements and attributes are checked at compile time and
# interpolated text is escaped, so a user name cannot become markup.
maud = "0.27.0"
# A readme is markdown, rendered to HTML for the repository page. The HTML is
# sanitized with `ammonia` before it is embedded, since a repository's content
# is not the server's to trust.
pulldown-cmark = "0.13.4"
ammonia = "4.2.0"
miette = {version = "7.6.0", features = ["fancy"]}
# The migrations are a library so the server can apply them at startup; the
# `migration` CLI binary remains for generating and inspecting them.
migration = { path = "../migration" }
opentelemetry = "0.33.0"
# OTLP over HTTP rather than gRPC. Both are understood by Jaeger and by any
# collector. See `telemetry::OtlpExporter::from_env` for the runtime that makes
# the export actually complete.
#
# `hyper-client` is the asynchronous HTTP client. The default client for this
# transport is `reqwest-blocking`, which needs no runtime but cannot be driven
# concurrently; the asynchronous clients are what the export runtime in
# `telemetry` can drive.
opentelemetry-otlp = { version = "0.33.0", default-features = false, features = ["http-proto", "hyper-client", "trace"] }
# No `experimental_*` features: the stable `BatchSpanProcessor` is enough once
# `telemetry::ExportOnRuntime` gives it a runtime to drive the exporter with.
# `internal-logs` is what makes the SDK report export failures, and it emits
# through `tracing`, so `RUST_LOG` decides what is shown.
opentelemetry_sdk = { version = "0.33.0", default-features = false, features = [
"internal-logs",
"trace",
] }
# Randomness for generating the SSH host key on first start.
rand = "0.10"
# The SSH server git clients talk to. `default-features = false` drops the
# default `aws-lc-rs` backend, which drags in cmake and a heavy C build; `ring`
# together with the pure-Rust `rsa` crate covers the host key and the client
# keys we accept.
russh = { version = "0.64", default-features = false, features = ["ring", "rsa"] }
# Colouring source files on the server, so a file's page needs no JavaScript
# to show it the way an editor would. `default-fancy` picks the pure-Rust
# regex engine for the same reason the russh choice above does: the default
# `onig` backend is a C library. The cost is the syntax and theme dumps it
# embeds - a few megabytes of the binary.
syntect = { version = "5", default-features = false, features = ["default-fancy"] }
# A file's media type, from its name, for the raw file endpoint. Already in
# the dependency tree behind `rust-embed`'s `mime-guess` feature; named here
# because the raw endpoint uses it directly.
mime_guess = "2"
sea-orm = { version = "2.0.3", features = ["sqlx-sqlite", "runtime-tokio-rustls", "macros", "with-chrono", "with-uuid"] }
serde = { version = "1.0.229", features = ["derive"] }
serde_json = "1.0.151"
# Strong validators for the embedded static assets, hashed once at startup by
# `static_files`. Both are already in the tree - `sha2` behind `cookie` and
# `sqlx`, `hex` behind `ssh-key` and `sqlx-macros` - and are named here because
# this crate now uses them directly.
sha2 = "0.10"
hex = "0.4"
sqlx = { version = "0.9.0", features = ["chrono", "runtime-tokio", "sqlite", "uuid"] }
thiserror = "2.0.20"
# `rt` and `time` are for the span export runtime that `telemetry` owns; the
# rest serve the SSH listener, which spawns `git upload-pack`/`receive-pack`
# and shuttles their standard streams over the channel.
tokio = { version = "1.53.1", features = [
"io-util",
"macros",
"net",
"process",
"rt",
"rt-multi-thread",
"time",
] }
toml = "1.1.6"
tracing = "0.1.44"
tracing-actix-web = "0.7.25"
tracing-opentelemetry = "0.34.0"
tracing-subscriber = { version = "0.3.23", features = ["env-filter", "json"] }
uuid = { version = "1.26.1", features = ["v4"] }
# A terminal UI for the SSH registration flow and future interactive features.
# ratatui renders to any terminal backend; crossterm handles the input parsing
# and escape sequences over the SSH channel rather than a real tty.
ratatui = { version = "0.29", default-features = false, features = ["crossterm"] }
crossterm = "0.28"
# ActivityPub actor keypairs: RSA-2048, pure-Rust, already in the tree
# transitively via russh. Used for signing and verifying HTTP signatures.
# The `sha2` feature re-exports the correct sha2 version for signing.
rsa = { version = "=0.10.0-rc.18", features = ["sha2"] }
# rand_core provides OsRng for key generation
rand_core = "0.10"
# PKCS#8 and SPKI traits for PEM encoding/decoding of RSA keys.
pkcs8 = "0.11"
spki = "0.8"
# Base64 encoding for HTTP signatures and ActivityPub documents.
base64 = "0.22"
# URL parsing for extracting the host from FROGUE_PUBLIC_URL.
url = "2"
# HTTP client for fetching remote ActivityPub actors when verifying signatures
# and for delivering activities to followers' inboxes.
reqwest = { version = "0.13", default-features = false, features = ["rustls", "json"] }
# Parsing and formatting HTTP Date headers for HTTP Signatures.
httpdate = "1"
# The static assets (logo, stylesheet) are compiled into the binary, so serving
# them does not depend on a `static/` directory next to the process.
# `debug-embed` embeds them in debug builds too, rather than reading the source
# tree at runtime; `mime-guess` is what fills in `Metadata::mimetype`.
rust-embed = { version = "8.5.0", features = ["debug-embed", "mime-guess"] }
[dev-dependencies]
# `macros` and `rt`/`rt-multi-thread` are for the async integration tests.
tokio = { version = "1.53.1", features = ["macros", "rt-multi-thread"] }