mirror of
https://gitlab.com/keys.openpgp.org/hagrid.git
synced 2025-10-06 00:23:08 +02:00
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,4 @@
|
||||
/node_modules
|
||||
/Rocket.toml
|
||||
/target
|
||||
**/*.rs.bk
|
||||
/dist/public/by-*
|
||||
|
21
README.md
21
README.md
@@ -16,13 +16,14 @@ keys, user IDs and tokens. To run it, supply the absolute path to where you
|
||||
want the database to live and the absolute path to the template directory.
|
||||
|
||||
```bash
|
||||
cargo run --bin hagrid -- dist
|
||||
cp Rocket.toml.dist Rocket.toml
|
||||
cargo run --bin hagrid
|
||||
```
|
||||
|
||||
This will spawn a web server listening on port 8080.
|
||||
|
||||
Hagrid uses `sendmail` for mailing, so you also need a working local mailer
|
||||
setup. The FROM field of the mails can be configured with the `-F` switch.
|
||||
setup.
|
||||
|
||||
Usage
|
||||
-----
|
||||
@@ -125,20 +126,20 @@ After compilation a binary is placed in `target/release/` called
|
||||
cp target/release/hagrid /usr/local/bin
|
||||
```
|
||||
|
||||
To deploy the key server copy all
|
||||
directories under `public/` to a writable location. Then start the server with
|
||||
the _absolute_ path to the directory as argument:
|
||||
To deploy the key server copy all directories under `dist/` to a
|
||||
writable location, and create a suitable configuration file.
|
||||
|
||||
```bash
|
||||
mkdir /var/lib/hagrid
|
||||
cp -R dist/* /var/lib/hagrid
|
||||
hagrid /var/lib/hagrid
|
||||
cp Rocket.toml.dist /var/lib/hagrid/Rocket.toml
|
||||
$EDITOR /var/lib/hagrid/Rocket.toml
|
||||
/usr/bin/env --chdir=/var/lib/hagrid ROCKET_ENV=production hagrid
|
||||
```
|
||||
|
||||
This will spawn the server in foreground, listening on `0.0.0.0:8080`. The
|
||||
`--listen` argument can be used to change port and listen address. The server
|
||||
will put all keys and runtime data under the base folder (`/var/lib/hagrid`
|
||||
in the above example).
|
||||
This will spawn the server in foreground. The server will put all
|
||||
keys and runtime data under the base folder (`/var/lib/hagrid` in the
|
||||
above example).
|
||||
|
||||
Reverse Proxy
|
||||
-------------
|
||||
|
20
Rocket.toml.dist
Normal file
20
Rocket.toml.dist
Normal file
@@ -0,0 +1,20 @@
|
||||
[global]
|
||||
address = "0.0.0.0"
|
||||
port = 8080
|
||||
template_dir = "dist/templates"
|
||||
state_dir = "dist"
|
||||
|
||||
[development]
|
||||
domain = "localhost"
|
||||
from = "noreply@localhost"
|
||||
x-accel-redirect = false
|
||||
|
||||
[staging]
|
||||
domain = "keys.openpgp.org"
|
||||
from = "noreply@keys.openpgp.org"
|
||||
x-accel-redirect = true
|
||||
|
||||
[production]
|
||||
domain = "keys.openpgp.org"
|
||||
from = "noreply@keys.openpgp.org"
|
||||
x-accel-redirect = true
|
47
src/main.rs
47
src/main.rs
@@ -22,7 +22,6 @@ extern crate sequoia_openpgp;
|
||||
extern crate handlebars;
|
||||
extern crate lettre;
|
||||
extern crate lettre_email;
|
||||
extern crate structopt;
|
||||
extern crate tempfile;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -34,43 +33,8 @@ extern crate hagrid_database as database;
|
||||
mod mail;
|
||||
mod web;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(
|
||||
name = "hagrid",
|
||||
about = "Hagrid - The verifying OpenPGP key server."
|
||||
)]
|
||||
pub struct Opt {
|
||||
/// More verbose output. Disabled when running as daemon.
|
||||
#[structopt(short = "v", long = "verbose")]
|
||||
verbose: bool,
|
||||
/// Daemonize after startup.
|
||||
#[structopt(short = "d", long = "daemon")]
|
||||
daemon: bool,
|
||||
/// Base directory
|
||||
#[structopt(parse(from_os_str))]
|
||||
base: PathBuf,
|
||||
/// Port and address to listen on.
|
||||
#[structopt(short = "l", long = "listen", default_value = "0.0.0.0:8080")]
|
||||
listen: String,
|
||||
/// FQDN of the server. Used in templates.
|
||||
#[structopt(short = "D", long = "domain", default_value = "localhost")]
|
||||
domain: String,
|
||||
#[structopt(
|
||||
short = "F",
|
||||
long = "from",
|
||||
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() {
|
||||
if let Err(e) = real_main() {
|
||||
if let Err(e) = web::serve() {
|
||||
let mut cause = e.as_fail();
|
||||
eprint!("{}", cause);
|
||||
while let Some(c) = cause.cause() {
|
||||
@@ -81,12 +45,3 @@ fn main() {
|
||||
::std::process::exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
fn real_main() -> Result<()> {
|
||||
use database::{Filesystem, Polymorphic};
|
||||
|
||||
let mut opt = Opt::from_args();
|
||||
opt.base = opt.base.canonicalize()?;
|
||||
let db = Filesystem::new(&opt.base)?;
|
||||
web::serve(&opt, Polymorphic::Filesystem(db))
|
||||
}
|
||||
|
@@ -17,7 +17,6 @@ use mail;
|
||||
use database::{Database, Polymorphic, Query};
|
||||
use database::types::{Email, Fingerprint, KeyID};
|
||||
use Result;
|
||||
use Opt;
|
||||
|
||||
use std::result;
|
||||
use std::str::FromStr;
|
||||
@@ -627,51 +626,11 @@ fn apidoc() -> Template {
|
||||
Template::render("apidoc", templates::General::default())
|
||||
}
|
||||
|
||||
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)
|
||||
.root(opt.base.clone())
|
||||
.extra(
|
||||
"template_dir",
|
||||
opt.base
|
||||
.join("templates")
|
||||
.to_str()
|
||||
.ok_or(failure::err_msg("Template path invalid"))?,
|
||||
)
|
||||
.extra(
|
||||
"state_dir",
|
||||
opt.base.to_str()
|
||||
.ok_or(failure::err_msg("Static path invalid"))?,
|
||||
)
|
||||
.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();
|
||||
Ok(())
|
||||
pub fn serve() -> Result<()> {
|
||||
Err(rocket_factory(rocket::ignite())?.launch().into())
|
||||
}
|
||||
|
||||
fn rocket_factory(rocket: rocket::Rocket, db: Polymorphic) -> rocket::Rocket {
|
||||
fn rocket_factory(rocket: rocket::Rocket) -> Result<rocket::Rocket> {
|
||||
let routes = routes![
|
||||
// infra
|
||||
root,
|
||||
@@ -695,7 +654,11 @@ fn rocket_factory(rocket: rocket::Rocket, db: Polymorphic) -> rocket::Rocket {
|
||||
apidoc,
|
||||
];
|
||||
|
||||
rocket
|
||||
use database::{Filesystem, Polymorphic};
|
||||
let db = Polymorphic::Filesystem(
|
||||
Filesystem::new(&PathBuf::from(rocket.config().get_str("state_dir")?))?
|
||||
);
|
||||
Ok(rocket
|
||||
.attach(Template::fairing())
|
||||
.attach(AdHoc::on_attach("state", |rocket| {
|
||||
let state_dir: PathBuf = rocket.config().get_str("state_dir")
|
||||
@@ -748,7 +711,7 @@ fn rocket_factory(rocket: rocket::Rocket, db: Polymorphic) -> rocket::Rocket {
|
||||
}))
|
||||
}))
|
||||
.mount("/", routes)
|
||||
.manage(db)
|
||||
.manage(db))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -819,10 +782,7 @@ mod tests {
|
||||
#[test]
|
||||
fn basics() {
|
||||
let (_tmpdir, config) = configuration().unwrap();
|
||||
|
||||
let db = Polymorphic::Filesystem(
|
||||
Filesystem::new(config.root().unwrap().to_path_buf()).unwrap());
|
||||
let rocket = rocket_factory(rocket::custom(config), db);
|
||||
let rocket = rocket_factory(rocket::custom(config)).unwrap();
|
||||
let client = Client::new(rocket).expect("valid rocket instance");
|
||||
|
||||
// Check that we see the landing page.
|
||||
@@ -854,9 +814,7 @@ mod tests {
|
||||
// eprintln!("LEAKING: {:?}", tmpdir);
|
||||
// ::std::mem::forget(_tmpdir);
|
||||
|
||||
let db = Polymorphic::Filesystem(
|
||||
Filesystem::new(config.root().unwrap().to_path_buf()).unwrap());
|
||||
let rocket = rocket_factory(rocket::custom(config), db);
|
||||
let rocket = rocket_factory(rocket::custom(config)).unwrap();
|
||||
let client = Client::new(rocket).expect("valid rocket instance");
|
||||
|
||||
// Generate a key and upload it.
|
||||
@@ -911,9 +869,7 @@ mod tests {
|
||||
let (tmpdir, config) = configuration().unwrap();
|
||||
let filemail_into = tmpdir.path().join("filemail");
|
||||
|
||||
let db = Polymorphic::Filesystem(
|
||||
Filesystem::new(config.root().unwrap().to_path_buf()).unwrap());
|
||||
let rocket = rocket_factory(rocket::custom(config), db);
|
||||
let rocket = rocket_factory(rocket::custom(config)).unwrap();
|
||||
let client = Client::new(rocket).expect("valid rocket instance");
|
||||
|
||||
// Generate two keys and upload them.
|
||||
@@ -1086,9 +1042,7 @@ mod tests {
|
||||
// eprintln!("LEAKING: {:?}", tmpdir);
|
||||
// ::std::mem::forget(tmpdir);
|
||||
|
||||
let db = Polymorphic::Filesystem(
|
||||
Filesystem::new(config.root().unwrap().to_path_buf()).unwrap());
|
||||
let rocket = rocket_factory(rocket::custom(config), db);
|
||||
let rocket = rocket_factory(rocket::custom(config)).unwrap();
|
||||
let client = Client::new(rocket).expect("valid rocket instance");
|
||||
|
||||
// Generate a key and upload it.
|
||||
@@ -1140,9 +1094,7 @@ mod tests {
|
||||
let (tmpdir, config) = configuration().unwrap();
|
||||
let filemail_into = tmpdir.path().join("filemail");
|
||||
|
||||
let db = Polymorphic::Filesystem(
|
||||
Filesystem::new(config.root().unwrap().to_path_buf()).unwrap());
|
||||
let rocket = rocket_factory(rocket::custom(config), db);
|
||||
let rocket = rocket_factory(rocket::custom(config)).unwrap();
|
||||
let client = Client::new(rocket).expect("valid rocket instance");
|
||||
|
||||
// Generate two keys and upload them.
|
||||
|
Reference in New Issue
Block a user