feat: added forwarding of '/admin/backup' calls to the admin worker
Build and Deploy / build-docker (push) Successful in 5m19s Details

This commit is contained in:
antifallobst 2023-11-24 01:28:05 +01:00
parent 5928f5b0b5
commit a3f58ccc39
Signed by: antifallobst
GPG Key ID: 2B4F402172791BAF
7 changed files with 401 additions and 15 deletions

306
Cargo.lock generated
View File

@ -589,6 +589,16 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "core-foundation-sys" name = "core-foundation-sys"
version = "0.8.4" version = "0.8.4"
@ -832,6 +842,21 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]] [[package]]
name = "form_urlencoded" name = "form_urlencoded"
version = "1.2.0" version = "1.2.0"
@ -853,9 +878,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.28" version = "0.3.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
[[package]] [[package]]
name = "futures-executor" name = "futures-executor"
@ -881,30 +906,42 @@ dependencies = [
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.28" version = "0.3.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
[[package]]
name = "futures-macro"
version = "0.3.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.28",
]
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.28" version = "0.3.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.28" version = "0.3.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.28" version = "0.3.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-io", "futures-io",
"futures-macro",
"futures-sink", "futures-sink",
"futures-task", "futures-task",
"memchr", "memchr",
@ -1085,6 +1122,17 @@ dependencies = [
"itoa", "itoa",
] ]
[[package]]
name = "http-body"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
dependencies = [
"bytes",
"http",
"pin-project-lite",
]
[[package]] [[package]]
name = "httparse" name = "httparse"
version = "1.8.0" version = "1.8.0"
@ -1103,6 +1151,43 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hyper"
version = "0.14.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"socket2 0.4.9",
"tokio",
"tower-service",
"tracing",
"want",
]
[[package]]
name = "hyper-tls"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
"hyper",
"native-tls",
"tokio",
"tokio-native-tls",
]
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.57" version = "0.1.57"
@ -1521,6 +1606,24 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "native-tls"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]] [[package]]
name = "nerdcult_api" name = "nerdcult_api"
version = "0.1.0" version = "0.1.0"
@ -1532,14 +1635,17 @@ dependencies = [
"base64 0.21.3", "base64 0.21.3",
"chrono", "chrono",
"env_logger", "env_logger",
"futures-util",
"libinjection", "libinjection",
"log", "log",
"mail-send", "mail-send",
"regex", "regex",
"reqwest",
"serde", "serde",
"sha2", "sha2",
"sqlx", "sqlx",
"tokio", "tokio",
"tokio-stream",
"uuid", "uuid",
] ]
@ -1626,6 +1732,32 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "openssl"
version = "0.10.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800"
dependencies = [
"bitflags 2.4.0",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.28",
]
[[package]] [[package]]
name = "openssl-probe" name = "openssl-probe"
version = "0.1.5" version = "0.1.5"
@ -1634,9 +1766,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.91" version = "0.9.96"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac" checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -1894,6 +2026,46 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
[[package]]
name = "reqwest"
version = "0.11.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
dependencies = [
"base64 0.21.3",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"hyper-tls",
"ipnet",
"js-sys",
"log",
"mime",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
"serde",
"serde_json",
"serde_urlencoded",
"system-configuration",
"tokio",
"tokio-native-tls",
"tokio-util",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"winreg",
]
[[package]] [[package]]
name = "resolv-conf" name = "resolv-conf"
version = "0.7.0" version = "0.7.0"
@ -2034,6 +2206,15 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "schannel"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
dependencies = [
"windows-sys",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"
@ -2050,6 +2231,29 @@ dependencies = [
"untrusted", "untrusted",
] ]
[[package]]
name = "security-framework"
version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.18" version = "1.0.18"
@ -2460,6 +2664,27 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "system-configuration"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.7.1" version = "3.7.1"
@ -2586,6 +2811,16 @@ dependencies = [
"syn 2.0.28", "syn 2.0.28",
] ]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
]
[[package]] [[package]]
name = "tokio-rustls" name = "tokio-rustls"
version = "0.23.4" version = "0.23.4"
@ -2616,6 +2851,7 @@ dependencies = [
"futures-core", "futures-core",
"pin-project-lite", "pin-project-lite",
"tokio", "tokio",
"tokio-util",
] ]
[[package]] [[package]]
@ -2632,6 +2868,12 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "tower-service"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.37" version = "0.1.37"
@ -2718,6 +2960,12 @@ dependencies = [
"webpki-roots 0.22.6", "webpki-roots 0.22.6",
] ]
[[package]]
name = "try-lock"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.16.0" version = "1.16.0"
@ -2795,6 +3043,15 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "want"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
dependencies = [
"try-lock",
]
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.10.0+wasi-snapshot-preview1" version = "0.10.0+wasi-snapshot-preview1"
@ -2832,6 +3089,18 @@ dependencies = [
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.87" version = "0.2.87"
@ -2861,6 +3130,19 @@ version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "wasm-streams"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7"
dependencies = [
"futures-util",
"js-sys",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.64" version = "0.3.64"

View File

@ -7,6 +7,7 @@ edition = "2021"
[dependencies] [dependencies]
tokio = { version = "1.29", features = ["macros", "rt-multi-thread", "sync"] } tokio = { version = "1.29", features = ["macros", "rt-multi-thread", "sync"] }
tokio-stream = { version = "0.1.3", features = ["sync"] }
anyhow = "1.0" anyhow = "1.0"
actix-web = "4" actix-web = "4"
serde = { version = "1.0.183", features = ["derive"] } serde = { version = "1.0.183", features = ["derive"] }
@ -22,3 +23,5 @@ mail-send = "0.4.0"
regex = "1.9.3" regex = "1.9.3"
argon2 = "0.5.2" argon2 = "0.5.2"
base64 = "0.21.3" base64 = "0.21.3"
reqwest = { version = "0.11.22", features = ["stream"] }
futures-util = "0.3.29"

95
src/api/admin/calls.rs Normal file
View File

@ -0,0 +1,95 @@
use crate::accounts::{Account, AccountFlags};
use crate::api::ApiState;
use crate::tokens::AuthToken;
use actix_web::{error, http::Method, web, Error, HttpRequest, HttpResponse};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use anyhow::Result;
use futures_util::StreamExt as _;
use tokio::sync::mpsc;
use tokio_stream::wrappers::UnboundedReceiverStream;
pub async fn backup_forward(
req: HttpRequest,
mut payload: web::Payload,
method: Method,
data: web::Data<ApiState>,
auth: BearerAuth,
) -> Result<HttpResponse, Error> {
let token = match AuthToken::check(&data.pool, auth.token())
.await
.map_err(|e| {
log::error!("Failed to forward admin request: {e}");
error::ErrorInternalServerError("")
})? {
Some(t) => t,
None => return Ok(HttpResponse::Unauthorized().finish()),
};
let account = Account::from_id(&data.pool, token.account.id()).await.map_err(|e| {
log::error!("Failed to forward admin request: {e}");
error::ErrorInternalServerError("")
})?.ok_or_else(|| {
log::error!("Failed to forward admin request: the authorized account was not found, but the token was valid");
error::ErrorInternalServerError("")
})?;
if !account.has_flag(AccountFlags::Admin) {
return Ok(HttpResponse::Forbidden().finish());
}
// using http here is fine, because this call stays on the host
let url = format!(
"http://{}/{}",
std::env::var("ADMIN_WORKER_HOST").map_err(|e| {
log::error!("Failed to forward admin request: {e}");
error::ErrorInternalServerError("")
})?,
req.uri()
.to_string()
.split_once("/admin/")
.ok_or_else(|| {
log::error!("Failed to forward admin request: failed to split URI");
error::ErrorInternalServerError("URI splitting error")
})?
.1
);
let client = reqwest::Client::new();
let (tx, rx) = mpsc::unbounded_channel();
actix_web::rt::spawn(async move {
while let Some(chunk) = payload.next().await {
tx.send(chunk).unwrap();
}
});
let forwarded_req = client
.request(method, url)
.body(reqwest::Body::wrap_stream(UnboundedReceiverStream::new(rx)))
.header(
"Authorization",
format!(
"Bearer {}",
std::env::var("ADMIN_WORKER_TOKEN").map_err(|e| {
log::error!("Failed to forward admin request: {e}");
error::ErrorInternalServerError("")
})?,
),
)
.header("Content-Type", "application/json");
let res = forwarded_req.send().await.map_err(|e| {
log::error!("Failed to forward admin request: {e}");
error::ErrorInternalServerError("forwarding error")
})?;
let mut client_resp = HttpResponse::build(res.status());
// Remove `Connection` as per
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection#Directives
for (header_name, header_value) in res.headers().iter().filter(|(h, _)| *h != "connection") {
client_resp.insert_header((header_name.clone(), header_value.clone()));
}
Ok(client_resp.streaming(res.bytes_stream()))
}

1
src/api/admin/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod calls;

View File

@ -1,4 +1,5 @@
mod account; mod account;
mod admin;
mod project; mod project;
mod user; mod user;
@ -7,7 +8,7 @@ use anyhow::Result;
use log::info; use log::info;
use sqlx::postgres::PgPool; use sqlx::postgres::PgPool;
struct ApiState { pub struct ApiState {
pool: PgPool, pool: PgPool,
} }
@ -98,6 +99,9 @@ pub async fn start(port: u16, pool: PgPool) -> Result<()> {
.service(project::calls::info) .service(project::calls::info)
.service(project::calls::delete) .service(project::calls::delete)
.service(user::calls::info) .service(user::calls::info)
.service(
web::scope("/admin/backup").default_service(web::to(admin::calls::backup_forward)),
)
.app_data(web::Data::new(ApiState { pool: pool.clone() })) .app_data(web::Data::new(ApiState { pool: pool.clone() }))
}) })
.bind(("0.0.0.0", port))? .bind(("0.0.0.0", port))?

View File

@ -18,10 +18,11 @@ async fn main() -> Result<()> {
check_envs(vec![ check_envs(vec![
"DATABASE_URL", "DATABASE_URL",
"SMTP_PASSWORD",
"SMTP_HOST_URL", "SMTP_HOST_URL",
"SMTP_USER", "SMTP_USER",
"SMTP_PASSWORD", "SMTP_PASSWORD",
"ADMIN_WORKER_HOST",
"ADMIN_WORKER_TOKEN",
])?; ])?;
let pool = PgPool::connect(&std::env::var("DATABASE_URL").unwrap()).await?; let pool = PgPool::connect(&std::env::var("DATABASE_URL").unwrap()).await?;

View File

@ -47,7 +47,7 @@ impl AuthToken {
Ok(token) Ok(token)
} }
pub async fn check(pool: &PgPool, alphanumeric_token: &String) -> Result<Option<Self>> { pub async fn check(pool: &PgPool, alphanumeric_token: &str) -> Result<Option<Self>> {
let query_result = sqlx::query_as!( let query_result = sqlx::query_as!(
Self, Self,
r#"SELECT * FROM AuthTokens WHERE token = $1;"#, r#"SELECT * FROM AuthTokens WHERE token = $1;"#,