2018-08-16 18:35:19 +00:00
|
|
|
use rocket;
|
2018-10-18 14:26:25 +00:00
|
|
|
use rocket::{State, Outcome};
|
2018-09-19 20:24:38 +00:00
|
|
|
use rocket::http::Status;
|
|
|
|
use rocket::request::{self, Request, FromRequest};
|
|
|
|
use rocket::response::status::Custom;
|
2019-01-15 17:30:35 +00:00
|
|
|
use rocket::response::{Response, NamedFile};
|
2018-10-18 14:26:25 +00:00
|
|
|
use rocket::fairing::AdHoc;
|
2018-12-25 19:06:28 +00:00
|
|
|
use rocket_contrib::templates::Template;
|
2019-01-10 13:45:11 +00:00
|
|
|
|
|
|
|
use handlebars::Handlebars;
|
2018-10-18 14:26:25 +00:00
|
|
|
use std::path::{Path, PathBuf};
|
2018-08-16 18:35:19 +00:00
|
|
|
|
|
|
|
mod upload;
|
|
|
|
|
2018-10-24 17:45:11 +00:00
|
|
|
use database::{Polymorphic, Database};
|
2019-01-04 13:07:14 +00:00
|
|
|
use types::{Fingerprint, Email, KeyID};
|
2018-09-19 20:24:38 +00:00
|
|
|
use errors::Result;
|
|
|
|
use Opt;
|
|
|
|
|
|
|
|
use std::str::FromStr;
|
|
|
|
use std::result;
|
|
|
|
|
|
|
|
mod queries {
|
2018-10-24 17:45:11 +00:00
|
|
|
use types::{Fingerprint, Email};
|
2018-09-19 20:24:38 +00:00
|
|
|
|
2018-10-24 17:45:11 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Hkp {
|
2019-01-08 18:01:45 +00:00
|
|
|
Fingerprint{ fpr: Fingerprint, index: bool },
|
|
|
|
Email{ email: Email, index: bool },
|
2018-09-19 20:24:38 +00:00
|
|
|
}
|
2018-08-16 18:35:19 +00:00
|
|
|
}
|
|
|
|
|
2018-09-19 20:24:38 +00:00
|
|
|
mod templates {
|
|
|
|
#[derive(Serialize)]
|
|
|
|
pub struct Verify {
|
|
|
|
pub verified: bool,
|
|
|
|
pub userid: String,
|
|
|
|
pub fpr: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
|
pub struct Delete {
|
|
|
|
pub token: String,
|
|
|
|
pub fpr: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
|
pub struct Confirm {
|
|
|
|
pub deleted: bool,
|
|
|
|
}
|
2018-08-16 18:35:19 +00:00
|
|
|
}
|
|
|
|
|
2018-10-18 14:26:25 +00:00
|
|
|
struct StaticDir(String);
|
2018-11-02 10:50:57 +00:00
|
|
|
pub struct Domain(String);
|
2019-01-09 12:35:47 +00:00
|
|
|
pub struct From(String);
|
2019-01-10 13:45:11 +00:00
|
|
|
pub struct MailTemplates(Handlebars);
|
2018-10-18 14:26:25 +00:00
|
|
|
|
2018-10-24 17:44:36 +00:00
|
|
|
impl<'a, 'r> FromRequest<'a, 'r> for queries::Hkp {
|
|
|
|
type Error = ();
|
|
|
|
|
|
|
|
fn from_request(request: &'a Request<'r>) -> request::Outcome<queries::Hkp, ()> {
|
|
|
|
use rocket::request::FormItems;
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
let query = request.uri().query().unwrap_or("");
|
2018-12-25 19:06:28 +00:00
|
|
|
let fields = FormItems::from(query).map(|item| {
|
|
|
|
|
|
|
|
let (k, v) = item.key_value();
|
|
|
|
|
2018-10-24 17:44:36 +00:00
|
|
|
let key = k.url_decode().unwrap_or_default();
|
|
|
|
let value = v.url_decode().unwrap_or_default();
|
|
|
|
(key, value)
|
|
|
|
}).collect::<HashMap<_,_>>();
|
|
|
|
|
2019-01-08 18:01:45 +00:00
|
|
|
if fields.len() >= 2 && fields.get("op").map(|x| x == "get" || x == "index").unwrap_or(false) {
|
|
|
|
let index = fields.get("op").map(|x| x == "index")
|
|
|
|
.unwrap_or(false);
|
2018-10-24 17:44:36 +00:00
|
|
|
let search = fields.get("search").cloned().unwrap_or_default();
|
2018-11-02 10:55:07 +00:00
|
|
|
let maybe_fpr = Fingerprint::from_str(&search);
|
2018-10-24 17:44:36 +00:00
|
|
|
|
2018-11-02 10:55:07 +00:00
|
|
|
if let Ok(fpr) = maybe_fpr {
|
2019-01-08 18:01:45 +00:00
|
|
|
Outcome::Success(queries::Hkp::Fingerprint{
|
|
|
|
fpr: fpr, index: index
|
|
|
|
})
|
2018-10-24 17:44:36 +00:00
|
|
|
} else {
|
|
|
|
match Email::from_str(&search) {
|
2019-01-08 18:01:45 +00:00
|
|
|
Ok(email) => Outcome::Success(queries::Hkp::Email{
|
|
|
|
email: email, index: index
|
|
|
|
}),
|
2018-10-24 17:44:36 +00:00
|
|
|
Err(_) => Outcome::Failure((Status::BadRequest, ())),
|
2018-08-16 18:35:19 +00:00
|
|
|
}
|
2018-09-19 20:24:38 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Outcome::Failure((Status::BadRequest, ()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-15 17:30:35 +00:00
|
|
|
fn key_to_response<'a,'b>(bytes: &'a[u8]) -> Response<'b> {
|
2018-09-19 20:24:38 +00:00
|
|
|
use std::io::Write;
|
2018-11-25 14:03:27 +00:00
|
|
|
use sequoia_openpgp::armor::{Writer, Kind};
|
2019-01-15 17:30:35 +00:00
|
|
|
use std::io::Cursor;
|
|
|
|
use rocket::http::{Status, ContentType};
|
2018-09-19 20:24:38 +00:00
|
|
|
|
2018-10-25 15:37:33 +00:00
|
|
|
let key = || -> Result<String> {
|
|
|
|
let mut buffer = Vec::default();
|
|
|
|
{
|
|
|
|
let mut writer = Writer::new(&mut buffer, Kind::PublicKey, &[])?;
|
|
|
|
writer.write_all(&bytes)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(String::from_utf8(buffer)?)
|
|
|
|
}();
|
|
|
|
|
|
|
|
match key {
|
2019-01-15 17:30:35 +00:00
|
|
|
Ok(s) =>
|
|
|
|
Response::build()
|
|
|
|
.status(Status::Ok)
|
|
|
|
.header(ContentType::new("application", "pgp-keys"))
|
|
|
|
.sized_body(Cursor::new(s))
|
|
|
|
.finalize(),
|
2018-10-25 15:37:33 +00:00
|
|
|
Err(_) =>
|
2019-01-15 17:30:35 +00:00
|
|
|
Response::build()
|
|
|
|
.status(Status::InternalServerError)
|
|
|
|
.header(ContentType::Plain)
|
|
|
|
.sized_body(Cursor::new("Failed to ASCII armor key"))
|
|
|
|
.finalize(),
|
2018-10-25 15:37:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-02 10:48:02 +00:00
|
|
|
#[get("/by-fpr/<fpr>")]
|
2018-10-25 15:37:33 +00:00
|
|
|
fn by_fpr(db: rocket::State<Polymorphic>, fpr: String)
|
2019-01-15 17:30:35 +00:00
|
|
|
-> Response
|
2018-10-25 15:37:33 +00:00
|
|
|
{
|
2019-01-15 17:30:35 +00:00
|
|
|
use std::io::Cursor;
|
|
|
|
use rocket::http::{Status, ContentType};
|
|
|
|
|
2018-10-25 15:37:33 +00:00
|
|
|
let maybe_key = match Fingerprint::from_str(&fpr) {
|
|
|
|
Ok(ref fpr) => db.by_fpr(fpr),
|
|
|
|
Err(_) => None,
|
2018-09-19 20:24:38 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
match maybe_key {
|
2019-01-15 17:30:35 +00:00
|
|
|
Some(ref bytes) => key_to_response(bytes),
|
|
|
|
None =>
|
|
|
|
Response::build()
|
|
|
|
.status(Status::NotFound)
|
|
|
|
.header(ContentType::Plain)
|
|
|
|
.sized_body(Cursor::new("No such key :-("))
|
|
|
|
.finalize(),
|
2018-10-25 15:37:33 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-19 20:24:38 +00:00
|
|
|
|
2018-11-02 10:48:02 +00:00
|
|
|
#[get("/by-email/<email>")]
|
2018-10-25 15:37:33 +00:00
|
|
|
fn by_email(db: rocket::State<Polymorphic>, email: String)
|
2019-01-15 17:30:35 +00:00
|
|
|
-> Response
|
2018-10-25 15:37:33 +00:00
|
|
|
{
|
2019-01-15 17:30:35 +00:00
|
|
|
use std::io::Cursor;
|
|
|
|
use rocket::http::{Status, ContentType};
|
|
|
|
|
2018-10-25 15:37:33 +00:00
|
|
|
let maybe_key = match Email::from_str(&email) {
|
|
|
|
Ok(ref email) => db.by_email(email),
|
|
|
|
Err(_) => None,
|
|
|
|
};
|
2018-09-19 20:24:38 +00:00
|
|
|
|
2018-10-25 15:37:33 +00:00
|
|
|
match maybe_key {
|
2019-01-15 17:30:35 +00:00
|
|
|
Some(ref bytes) => key_to_response(bytes),
|
|
|
|
None =>
|
|
|
|
Response::build()
|
|
|
|
.status(Status::NotFound)
|
|
|
|
.header(ContentType::Plain)
|
|
|
|
.sized_body(Cursor::new("No such key :-("))
|
|
|
|
.finalize(),
|
2018-09-19 20:24:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-04 13:07:14 +00:00
|
|
|
#[get("/by-kid/<kid>")]
|
|
|
|
fn by_kid(db: rocket::State<Polymorphic>, kid: String)
|
2019-01-15 17:30:35 +00:00
|
|
|
-> Response
|
2019-01-04 13:07:14 +00:00
|
|
|
{
|
2019-01-15 17:30:35 +00:00
|
|
|
use std::io::Cursor;
|
|
|
|
use rocket::http::{Status, ContentType};
|
|
|
|
|
2019-01-04 13:07:14 +00:00
|
|
|
let maybe_key = match KeyID::from_str(&kid) {
|
|
|
|
Ok(ref key) => db.by_kid(key),
|
|
|
|
Err(_) => None,
|
|
|
|
};
|
|
|
|
|
|
|
|
match maybe_key {
|
2019-01-15 17:30:35 +00:00
|
|
|
Some(ref bytes) => {
|
|
|
|
key_to_response(bytes)
|
|
|
|
}
|
|
|
|
None =>
|
|
|
|
Response::build()
|
|
|
|
.status(Status::NotFound)
|
|
|
|
.header(ContentType::Plain)
|
|
|
|
.sized_body(Cursor::new("No such key :-("))
|
|
|
|
.finalize(),
|
2019-01-04 13:07:14 +00:00
|
|
|
}
|
2019-01-15 17:30:35 +00:00
|
|
|
|
2019-01-04 13:07:14 +00:00
|
|
|
}
|
|
|
|
|
2018-11-02 10:48:02 +00:00
|
|
|
#[get("/vks/verify/<token>")]
|
2018-09-19 20:24:38 +00:00
|
|
|
fn verify(db: rocket::State<Polymorphic>, token: String)
|
|
|
|
-> result::Result<Template, Custom<String>>
|
|
|
|
{
|
|
|
|
match db.verify_token(&token) {
|
|
|
|
Ok(Some((userid, fpr))) => {
|
|
|
|
let context = templates::Verify{
|
|
|
|
verified: true,
|
|
|
|
userid: userid.to_string(),
|
|
|
|
fpr: fpr.to_string(),
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Template::render("verify", context))
|
|
|
|
}
|
|
|
|
Ok(None) | Err(_) => {
|
|
|
|
let context = templates::Verify{
|
|
|
|
verified: false,
|
|
|
|
userid: "".into(),
|
|
|
|
fpr: "".into(),
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Template::render("verify", context))
|
2018-08-16 18:35:19 +00:00
|
|
|
}
|
2018-09-19 20:24:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-02 10:50:57 +00:00
|
|
|
#[get("/vks/delete/<fpr>")]
|
|
|
|
fn delete(db: rocket::State<Polymorphic>, fpr: String,
|
2019-01-10 13:45:11 +00:00
|
|
|
tmpl: State<MailTemplates>, domain: State<Domain>, from: State<From>)
|
2018-09-19 20:24:38 +00:00
|
|
|
-> result::Result<Template, Custom<String>>
|
|
|
|
{
|
2018-11-02 10:50:57 +00:00
|
|
|
use mail::send_confirmation_mail;
|
|
|
|
|
2018-09-19 20:24:38 +00:00
|
|
|
let fpr = match Fingerprint::from_str(&fpr) {
|
|
|
|
Ok(fpr) => fpr,
|
|
|
|
Err(_) => {
|
|
|
|
return Err(Custom(Status::BadRequest,
|
|
|
|
"Invalid fingerprint".to_string()));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
match db.request_deletion(fpr.clone()) {
|
2018-11-02 10:53:49 +00:00
|
|
|
Ok((token,uids)) => {
|
2018-09-19 20:24:38 +00:00
|
|
|
let context = templates::Delete{
|
|
|
|
fpr: fpr.to_string(),
|
2018-11-02 10:53:49 +00:00
|
|
|
token: token.clone(),
|
2018-09-19 20:24:38 +00:00
|
|
|
};
|
|
|
|
|
2018-11-02 10:53:49 +00:00
|
|
|
for uid in uids {
|
2019-01-09 12:35:47 +00:00
|
|
|
send_confirmation_mail(&uid, &token, &tmpl.0, &domain.0, &from.0)
|
2019-01-08 18:01:45 +00:00
|
|
|
.map_err(|err| {
|
|
|
|
Custom(Status::InternalServerError,
|
|
|
|
format!("{:?}", err))
|
|
|
|
})?;
|
2018-11-02 10:53:49 +00:00
|
|
|
}
|
|
|
|
|
2018-09-19 20:24:38 +00:00
|
|
|
Ok(Template::render("delete", context))
|
|
|
|
}
|
|
|
|
Err(e) => Err(Custom(Status::InternalServerError,
|
|
|
|
format!("{}", e))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-02 10:48:02 +00:00
|
|
|
#[get("/vks/confirm/<token>")]
|
2018-09-19 20:24:38 +00:00
|
|
|
fn confirm(db: rocket::State<Polymorphic>, token: String)
|
|
|
|
-> result::Result<Template, Custom<String>>
|
|
|
|
{
|
|
|
|
match db.confirm_deletion(&token) {
|
|
|
|
Ok(true) => {
|
|
|
|
let context = templates::Confirm{
|
|
|
|
deleted: true,
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Template::render("confirm", context))
|
|
|
|
}
|
|
|
|
Ok(false) | Err(_) => {
|
|
|
|
let context = templates::Confirm{
|
|
|
|
deleted: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Template::render("confirm", context))
|
|
|
|
}
|
|
|
|
}
|
2018-08-16 18:35:19 +00:00
|
|
|
}
|
|
|
|
|
2018-11-02 10:48:02 +00:00
|
|
|
#[get("/assets/<file..>")]
|
2018-10-18 14:26:25 +00:00
|
|
|
fn files(file: PathBuf, static_dir: State<StaticDir>) -> Option<NamedFile> {
|
2018-11-02 10:48:02 +00:00
|
|
|
NamedFile::open(Path::new(&static_dir.0).join("assets").join(file)).ok()
|
2018-10-18 14:26:25 +00:00
|
|
|
}
|
|
|
|
|
2018-10-24 17:44:36 +00:00
|
|
|
#[get("/pks/lookup")]
|
2018-11-02 10:48:02 +00:00
|
|
|
fn lookup(db: rocket::State<Polymorphic>, key: Option<queries::Hkp>)
|
2018-10-24 17:44:36 +00:00
|
|
|
-> result::Result<String, Custom<String>>
|
|
|
|
{
|
|
|
|
use std::io::Write;
|
2019-01-08 18:01:45 +00:00
|
|
|
use sequoia_openpgp::RevocationStatus;
|
|
|
|
use sequoia_openpgp::{TPK, parse::Parse};
|
2018-11-25 14:03:27 +00:00
|
|
|
use sequoia_openpgp::armor::{Writer, Kind};
|
2018-10-24 17:44:36 +00:00
|
|
|
|
2019-01-08 18:01:45 +00:00
|
|
|
let (maybe_key,index) = match key {
|
|
|
|
Some(queries::Hkp::Fingerprint{ ref fpr, index }) => {
|
|
|
|
(db.by_fpr(fpr),index)
|
|
|
|
}
|
|
|
|
Some(queries::Hkp::Email{ ref email, index }) => {
|
|
|
|
(db.by_email(email),index)
|
|
|
|
}
|
2018-10-24 17:44:36 +00:00
|
|
|
None => { return Ok("nothing to do".to_string()); }
|
|
|
|
};
|
|
|
|
|
|
|
|
match maybe_key {
|
2019-01-08 18:01:45 +00:00
|
|
|
Some(ref bytes) if !index => {
|
2018-10-24 17:44:36 +00:00
|
|
|
let key = || -> Result<String> {
|
|
|
|
let mut buffer = Vec::default();
|
|
|
|
{
|
2019-01-08 18:01:45 +00:00
|
|
|
let mut writer = Writer::new(&mut buffer, Kind::PublicKey,
|
|
|
|
&[])?;
|
2018-10-24 17:44:36 +00:00
|
|
|
writer.write_all(&bytes)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(String::from_utf8(buffer)?)
|
|
|
|
}();
|
|
|
|
|
|
|
|
match key {
|
|
|
|
Ok(s) => Ok(s),
|
|
|
|
Err(_) =>
|
|
|
|
Err(Custom(Status::InternalServerError,
|
|
|
|
"Failed to ASCII armor key".to_string())),
|
|
|
|
}
|
|
|
|
}
|
2019-01-08 18:01:45 +00:00
|
|
|
None if !index => Ok("No such key :-(".to_string()),
|
|
|
|
|
|
|
|
Some(ref bytes) if index => {
|
|
|
|
let tpk = TPK::from_bytes(bytes)
|
|
|
|
.map_err(|e| Custom(Status::InternalServerError,
|
|
|
|
format!("{}", e)))?;
|
|
|
|
let mut out = String::default();
|
|
|
|
let p = tpk.primary();
|
|
|
|
|
|
|
|
let ctime = tpk
|
|
|
|
.primary_key_signature()
|
|
|
|
.and_then(|x| x.signature_creation_time())
|
|
|
|
.map(|x| format!("{}", x.to_timespec().sec))
|
|
|
|
.unwrap_or_default();
|
|
|
|
let extime = tpk
|
|
|
|
.primary_key_signature()
|
|
|
|
.and_then(|x| x.signature_expiration_time())
|
|
|
|
.map(|x| format!("{}", x))
|
|
|
|
.unwrap_or_default();
|
|
|
|
let is_exp = tpk
|
|
|
|
.primary_key_signature()
|
|
|
|
.and_then(|x| {
|
|
|
|
if x.signature_expired() { "e" } else { "" }.into()
|
|
|
|
})
|
|
|
|
.unwrap_or_default();
|
|
|
|
let is_rev =
|
2019-01-18 18:04:35 +00:00
|
|
|
if tpk.revoked(None) != RevocationStatus::NotAsFarAsWeKnow {
|
2019-01-08 18:01:45 +00:00
|
|
|
"r"
|
|
|
|
} else {
|
|
|
|
""
|
|
|
|
};
|
|
|
|
let algo: u8 = p.pk_algo().into();
|
|
|
|
|
|
|
|
out.push_str("info:1:1\r\n");
|
|
|
|
out.push_str(&format!("pub:{}:{}:{}:{}:{}:{}{}\r\n",
|
|
|
|
p.fingerprint().to_string().replace(" ",""),
|
|
|
|
algo,
|
|
|
|
p.mpis().bits(),
|
|
|
|
ctime,extime,is_exp,is_rev));
|
|
|
|
|
|
|
|
for uid in tpk.userids() {
|
|
|
|
let u =
|
|
|
|
url::form_urlencoded::byte_serialize(uid.userid().userid())
|
|
|
|
.fold(String::default(),|acc,x| acc + x);
|
|
|
|
let ctime = uid
|
|
|
|
.binding_signature()
|
|
|
|
.and_then(|x| x.signature_creation_time())
|
|
|
|
.map(|x| format!("{}", x.to_timespec().sec))
|
|
|
|
.unwrap_or_default();
|
|
|
|
let extime = uid
|
|
|
|
.binding_signature()
|
|
|
|
.and_then(|x| x.signature_expiration_time())
|
|
|
|
.map(|x| format!("{}", x))
|
|
|
|
.unwrap_or_default();
|
|
|
|
let is_exp = uid
|
|
|
|
.binding_signature()
|
|
|
|
.and_then(|x| {
|
|
|
|
if x.signature_expired() { "e" } else { "" }.into()
|
|
|
|
})
|
|
|
|
.unwrap_or_default();
|
|
|
|
let is_rev =
|
2019-01-18 18:04:35 +00:00
|
|
|
if uid.revoked(None) != RevocationStatus::NotAsFarAsWeKnow {
|
2019-01-08 18:01:45 +00:00
|
|
|
"r"
|
|
|
|
} else {
|
|
|
|
""
|
|
|
|
};
|
|
|
|
|
|
|
|
out.push_str(&format!("uid:{}:{}:{}:{}{}\r\n",
|
|
|
|
u,ctime,extime,is_exp,is_rev));
|
|
|
|
}
|
|
|
|
Ok(out)
|
|
|
|
}
|
|
|
|
None if index => {
|
|
|
|
Ok("info:1:0\r\n".into())
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => unreachable!(),
|
2018-10-24 17:44:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-16 18:35:19 +00:00
|
|
|
#[get("/")]
|
2018-09-19 20:24:38 +00:00
|
|
|
fn root() -> Template {
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
Template::render("index", HashMap::<String, String>::default())
|
2018-08-16 18:35:19 +00:00
|
|
|
}
|
|
|
|
|
2018-09-19 20:24:38 +00:00
|
|
|
pub fn serve(opt: &Opt, db: Polymorphic) -> Result<()> {
|
|
|
|
use rocket::config::{Config, Environment};
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
|
|
|
let (addr, port) = match opt.listen.find(':') {
|
|
|
|
Some(p) => {
|
|
|
|
let addr = opt.listen[0..p].to_string();
|
|
|
|
let port = if p < opt.listen.len() - 1 {
|
|
|
|
u16::from_str(&opt.listen[p+1..]).ok().unwrap_or(8080)
|
|
|
|
} else {
|
|
|
|
8080
|
|
|
|
};
|
|
|
|
|
|
|
|
(addr, port)
|
|
|
|
}
|
|
|
|
None => (opt.listen.to_string(), 8080)
|
|
|
|
};
|
|
|
|
|
|
|
|
let config = Config::build(Environment::Staging)
|
|
|
|
.address(addr)
|
|
|
|
.port(port)
|
|
|
|
.workers(2)
|
2018-11-02 10:48:02 +00:00
|
|
|
.root(opt.base.clone())
|
2019-01-08 18:01:45 +00:00
|
|
|
.extra("template_dir", opt.base.join("templates").to_str()
|
|
|
|
.ok_or("Template path invalid")?)
|
|
|
|
.extra("static_dir", opt.base.join("public").to_str()
|
|
|
|
.ok_or("Static path invalid")?)
|
2018-11-02 10:50:57 +00:00
|
|
|
.extra("domain", opt.domain.clone())
|
2019-01-09 12:35:47 +00:00
|
|
|
.extra("from", opt.from.clone())
|
2018-09-19 20:24:38 +00:00
|
|
|
.finalize()?;
|
|
|
|
let routes = routes![
|
2018-11-02 10:48:02 +00:00
|
|
|
// infra
|
|
|
|
root,
|
|
|
|
files,
|
|
|
|
// nginx-supported lookup
|
2018-10-25 15:37:33 +00:00
|
|
|
by_email,
|
|
|
|
by_fpr,
|
2019-01-04 13:07:14 +00:00
|
|
|
by_kid,
|
2018-11-02 10:48:02 +00:00
|
|
|
// HKP
|
|
|
|
lookup,
|
|
|
|
upload::multipart_upload,
|
|
|
|
// verification & deletion
|
2018-09-19 20:24:38 +00:00
|
|
|
verify,
|
|
|
|
delete,
|
|
|
|
confirm,
|
|
|
|
];
|
|
|
|
|
2018-12-25 19:06:28 +00:00
|
|
|
rocket::custom(config)
|
2018-09-19 20:24:38 +00:00
|
|
|
.attach(Template::fairing())
|
2018-12-25 19:06:28 +00:00
|
|
|
.attach(AdHoc::on_attach("static_dir", |rocket| {
|
2018-10-18 14:26:25 +00:00
|
|
|
let static_dir = rocket.config()
|
|
|
|
.get_str("static_dir")
|
|
|
|
.unwrap()
|
|
|
|
.to_string();
|
|
|
|
|
|
|
|
Ok(rocket.manage(StaticDir(static_dir)))
|
|
|
|
}))
|
2018-12-25 19:06:28 +00:00
|
|
|
.attach(AdHoc::on_attach("domain", |rocket| {
|
2019-01-09 12:35:47 +00:00
|
|
|
let domain = rocket.config()
|
2018-11-02 10:50:57 +00:00
|
|
|
.get_str("domain")
|
|
|
|
.unwrap()
|
|
|
|
.to_string();
|
|
|
|
|
2019-01-09 12:35:47 +00:00
|
|
|
Ok(rocket.manage(Domain(domain)))
|
|
|
|
}))
|
|
|
|
.attach(AdHoc::on_attach("from", |rocket| {
|
|
|
|
let from = rocket.config()
|
|
|
|
.get_str("from")
|
|
|
|
.unwrap()
|
|
|
|
.to_string();
|
|
|
|
|
|
|
|
Ok(rocket.manage(From(from)))
|
2018-11-02 10:50:57 +00:00
|
|
|
}))
|
2019-01-10 13:45:11 +00:00
|
|
|
.attach(AdHoc::on_attach("mail_templates", |rocket| {
|
|
|
|
let dir: PathBuf = rocket.config()
|
|
|
|
.get_str("template_dir")
|
|
|
|
.unwrap()
|
|
|
|
.to_string()
|
|
|
|
.into();
|
|
|
|
let confirm_html = dir.join("confirm-email-html.hbs");
|
|
|
|
let confirm_txt = dir.join("confirm-email-txt.hbs");
|
|
|
|
let verify_html = dir.join("verify-email-html.hbs");
|
|
|
|
let verify_txt = dir.join("verify-email-txt.hbs");
|
|
|
|
let mut handlebars = Handlebars::new();
|
|
|
|
|
|
|
|
handlebars.register_template_file("confirm-html", confirm_html).unwrap();
|
|
|
|
handlebars.register_template_file("confirm-txt", confirm_txt).unwrap();
|
|
|
|
handlebars.register_template_file("verify-html", verify_html).unwrap();
|
|
|
|
handlebars.register_template_file("verify-txt", verify_txt).unwrap();
|
|
|
|
|
|
|
|
Ok(rocket.manage(MailTemplates(handlebars)))
|
|
|
|
}))
|
2018-11-02 10:50:57 +00:00
|
|
|
|
2018-09-19 20:24:38 +00:00
|
|
|
.mount("/", routes)
|
|
|
|
.manage(db)
|
|
|
|
.launch();
|
|
|
|
Ok(())
|
2018-08-16 18:35:19 +00:00
|
|
|
}
|