Use X-Accel-Redirect to serve keys.

This commit is contained in:
Justus Winter 2019-03-01 12:58:17 +01:00
parent fc192a1f37
commit 53c086600a
No known key found for this signature in database
GPG Key ID: 686F55B4AB2B3386
2 changed files with 64 additions and 12 deletions

View File

@ -71,6 +71,9 @@ pub struct Opt {
default_value = "noreply@localhost"
)]
from: String,
/// Use NGINX'es X-Accel-Redirect feature.
#[structopt(long = "use-x-accel-redirect")]
x_accel_redirect: bool,
}
fn main() {

View File

@ -1,6 +1,6 @@
use rocket;
use rocket::fairing::AdHoc;
use rocket::http::Status;
use rocket::http::{Header, Status};
use rocket::request::{self, FromRequest, Request};
use rocket::response::status::Custom;
use rocket::response::NamedFile;
@ -59,6 +59,8 @@ enum MyResponse {
Plain(String),
#[response(status = 200, content_type = "application/pgp-keys")]
Key(String, ContentDisposition),
#[response(status = 200, content_type = "application/pgp-keys")]
XAccelRedirect(&'static str, Header<'static>, ContentDisposition),
#[response(status = 500, content_type = "html")]
ServerError(Template),
NotFound(Flash<Redirect>),
@ -88,6 +90,29 @@ impl MyResponse {
})
}
pub fn x_accel_redirect(path: PathBuf, fp: &Fingerprint) -> Self {
use rocket::http::hyper::header::{ContentDisposition, DispositionType,
DispositionParam, Charset};
// The path is relative to our base directory, but we need to
// get it relative to base/public.
let mut path = path.into_os_string().into_string().expect("valid UTF8");
// Drop the first component.
assert!(path.starts_with("public/"));
path.drain(..6);
MyResponse::XAccelRedirect(
"",
Header::new("X-Accel-Redirect", path),
ContentDisposition {
disposition: DispositionType::Attachment,
parameters: vec![
DispositionParam::Filename(
Charset::Us_Ascii, None,
(fp.to_string() + ".asc").into_bytes()),
],
})
}
pub fn ise(e: failure::Error) -> Self {
let ctx = templates::FiveHundred{
error: format!("{}", e),
@ -167,6 +192,7 @@ struct StaticDir(String);
pub struct Domain(String);
pub struct From(String);
pub struct MailTemplates(Handlebars);
pub struct XAccelRedirect(bool);
impl<'a, 'r> FromRequest<'a, 'r> for queries::Hkp {
type Error = ();
@ -238,7 +264,9 @@ impl<'a, 'r> FromRequest<'a, 'r> for queries::Hkp {
fn key_to_response<'a>(db: rocket::State<Polymorphic>,
query_string: String, domain: String,
query: Query,
machine_readable: bool) -> MyResponse {
machine_readable: bool,
x_accel_redirect: rocket::State<XAccelRedirect>)
-> MyResponse {
let fp = if let Some(fp) = db.lookup_primary_fingerprint(&query) {
fp
} else {
@ -246,6 +274,12 @@ fn key_to_response<'a>(db: rocket::State<Polymorphic>,
};
if machine_readable {
if x_accel_redirect.0 {
if let Some(path) = db.lookup_path(&query) {
return MyResponse::x_accel_redirect(path, &fp);
}
}
return match db.by_fpr(&fp) {
Some(armored) => MyResponse::key(armored, &fp.into()),
None => MyResponse::not_found(None, None),
@ -350,33 +384,39 @@ fn key_to_hkp_index<'a>(db: rocket::State<Polymorphic>, query: Query)
}
#[get("/vks/by-fingerprint/<fpr>")]
fn by_fingerprint(db: rocket::State<Polymorphic>, domain: rocket::State<Domain>, fpr: String) -> MyResponse {
fn by_fingerprint(db: rocket::State<Polymorphic>, domain: rocket::State<Domain>,
x_accel_redirect: rocket::State<XAccelRedirect>,
fpr: String) -> MyResponse {
let query = match Fingerprint::from_str(&fpr) {
Ok(fpr) => Query::ByFingerprint(fpr),
Err(e) => return MyResponse::ise(e),
};
key_to_response(db, fpr, domain.0.clone(), query, true)
key_to_response(db, fpr, domain.0.clone(), query, true, x_accel_redirect)
}
#[get("/vks/by-email/<email>")]
fn by_email(db: rocket::State<Polymorphic>, domain: rocket::State<Domain>, email: String) -> MyResponse {
fn by_email(db: rocket::State<Polymorphic>, domain: rocket::State<Domain>,
x_accel_redirect: rocket::State<XAccelRedirect>,
email: String) -> MyResponse {
let query = match Email::from_str(&email) {
Ok(email) => Query::ByEmail(email),
Err(e) => return MyResponse::ise(e),
};
key_to_response(db, email, domain.0.clone(), query, true)
key_to_response(db, email, domain.0.clone(), query, true, x_accel_redirect)
}
#[get("/vks/by-keyid/<kid>")]
fn by_keyid(db: rocket::State<Polymorphic>, domain: rocket::State<Domain>, kid: String) -> MyResponse {
fn by_keyid(db: rocket::State<Polymorphic>, domain: rocket::State<Domain>,
x_accel_redirect: rocket::State<XAccelRedirect>,
kid: String) -> MyResponse {
let query = match KeyID::from_str(&kid) {
Ok(keyid) => Query::ByKeyID(keyid),
Err(e) => return MyResponse::ise(e),
};
key_to_response(db, kid, domain.0.clone(), query, true)
key_to_response(db, kid, domain.0.clone(), query, true, x_accel_redirect)
}
#[get("/vks/verify/<token>")]
@ -502,9 +542,9 @@ fn files(file: PathBuf, static_dir: State<StaticDir>) -> Option<NamedFile> {
}
#[get("/pks/lookup")]
fn lookup(
db: rocket::State<Polymorphic>, domain: rocket::State<Domain>, key: Option<queries::Hkp>,
) -> MyResponse {
fn lookup(db: rocket::State<Polymorphic>, domain: rocket::State<Domain>,
x_accel_redirect: rocket::State<XAccelRedirect>,
key: Option<queries::Hkp>) -> MyResponse {
let query_string = key.as_ref().map(|k| format!("{}", k));
let (query, index, machine_readable) = match key {
Some(queries::Hkp::Fingerprint { fpr, index, machine_readable }) =>
@ -528,7 +568,8 @@ fn lookup(
} else {
key_to_response(db,
query_string.expect("key was Some if we made it here"),
domain.0.clone(), query, machine_readable)
domain.0.clone(), query, machine_readable,
x_accel_redirect)
}
}
@ -600,6 +641,7 @@ pub fn serve(opt: &Opt, db: Polymorphic) -> Result<()> {
)
.extra("domain", opt.domain.clone())
.extra("from", opt.from.clone())
.extra("x-accel-redirect", opt.x_accel_redirect)
.finalize()?;
rocket_factory(rocket::custom(config), db).launch();
@ -646,6 +688,12 @@ fn rocket_factory(rocket: rocket::Rocket, db: Polymorphic) -> rocket::Rocket {
Ok(rocket.manage(From(from)))
}))
.attach(AdHoc::on_attach("x-accel-redirect", |rocket| {
let x_accel_redirect =
rocket.config().get_bool("x-accel-redirect").unwrap();
Ok(rocket.manage(XAccelRedirect(x_accel_redirect)))
}))
.attach(AdHoc::on_attach("mail_templates", |rocket| {
let dir: PathBuf = rocket
.config()
@ -721,6 +769,7 @@ mod tests {
)
.extra("domain", "domain")
.extra("from", "from")
.extra("x-accel-redirect", false)
.finalize()?;
Ok((root, config))
}