add paseto middleware
This commit is contained in:
parent
17aa139510
commit
b241a3ebd1
|
@ -1608,6 +1608,7 @@ dependencies = [
|
|||
"egg-mode",
|
||||
"elefren",
|
||||
"futures-io",
|
||||
"hex",
|
||||
"jsonfeed",
|
||||
"kankyo",
|
||||
"log 0.4.11",
|
||||
|
|
|
@ -30,6 +30,7 @@ uuid = { version = "0.7", features = ["serde", "v4"] }
|
|||
rocket_prometheus = "0.7.0"
|
||||
prometheus = { version = "0.10", default-features = false, features = ["process"] }
|
||||
futures-io = "0.3"
|
||||
hex = "0.4"
|
||||
|
||||
jsonfeed = { git = "https://github.com/Xe/site" }
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{models, schema, web, MainDatabase};
|
||||
use crate::{models, paseto, schema, web, MainDatabase};
|
||||
use chrono::prelude::*;
|
||||
use diesel::prelude::*;
|
||||
use rocket::{
|
||||
|
@ -16,7 +16,7 @@ use std::io::Read;
|
|||
|
||||
#[get("/members")]
|
||||
#[instrument(skip(conn), err)]
|
||||
pub fn get_members(conn: MainDatabase) -> Result<Json<Vec<models::Member>>> {
|
||||
pub fn get_members(tok: paseto::Token, conn: MainDatabase) -> Result<Json<Vec<models::Member>>> {
|
||||
use schema::members;
|
||||
let results = members::table
|
||||
.load::<models::Member>(&*conn)
|
||||
|
@ -40,6 +40,7 @@ pub fn get_switches(
|
|||
conn: MainDatabase,
|
||||
count: Option<i64>,
|
||||
page: Option<i64>,
|
||||
tok: paseto::Token,
|
||||
) -> Result<Json<Vec<FrontChange>>> {
|
||||
use schema::{members, switches};
|
||||
|
||||
|
@ -73,7 +74,7 @@ pub fn get_switches(
|
|||
|
||||
#[get("/switches/current")]
|
||||
#[instrument(skip(conn), err)]
|
||||
pub fn get_current_front(conn: MainDatabase) -> Result<Json<FrontChange>> {
|
||||
pub fn get_current_front(conn: MainDatabase, tok: paseto::Token) -> Result<Json<FrontChange>> {
|
||||
use schema::{members, switches};
|
||||
|
||||
let mut front: Vec<(models::Switch, models::Member)> = switches::table
|
||||
|
@ -102,6 +103,7 @@ pub fn make_switch(
|
|||
who: StringBody,
|
||||
sc: State<web::switchcounter::Client>,
|
||||
pk: State<web::pluralkit::Client>,
|
||||
tok: paseto::Token,
|
||||
) -> Result<String> {
|
||||
use schema::{members, switches};
|
||||
let who = who.unwrap();
|
||||
|
@ -159,7 +161,11 @@ pub fn make_switch(
|
|||
|
||||
#[get("/switches/<switch_id>")]
|
||||
#[instrument(skip(conn), err)]
|
||||
pub fn get_switch(conn: MainDatabase, switch_id: String) -> Result<Json<FrontChange>> {
|
||||
pub fn get_switch(
|
||||
tok: paseto::Token,
|
||||
conn: MainDatabase,
|
||||
switch_id: String,
|
||||
) -> Result<Json<FrontChange>> {
|
||||
use schema::{members, switches::dsl::switches};
|
||||
|
||||
let (switch, member): (models::Switch, models::Member) = switches
|
||||
|
|
|
@ -20,6 +20,7 @@ pub const APPLICATION_NAME: &str = concat!(
|
|||
|
||||
pub mod api;
|
||||
pub mod models;
|
||||
pub mod paseto;
|
||||
pub mod schema;
|
||||
pub mod web;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ use color_eyre::eyre::Result;
|
|||
use rocket_contrib::helmet::SpaceHelmet;
|
||||
use rocket_prometheus::PrometheusMetrics;
|
||||
|
||||
use ::mi::{api, web, MainDatabase, APPLICATION_NAME};
|
||||
use ::mi::{api, paseto, web, MainDatabase, APPLICATION_NAME};
|
||||
|
||||
#[get("/.within/botinfo")]
|
||||
fn botinfo() -> &'static str {
|
||||
|
@ -42,13 +42,14 @@ fn main() -> Result<()> {
|
|||
.attach(prometheus.clone())
|
||||
.attach(MainDatabase::fairing())
|
||||
.attach(SpaceHelmet::default())
|
||||
.attach(paseto::ed25519_keypair())
|
||||
.attach(web::pluralkit::Client::fairing())
|
||||
.attach(web::switchcounter::Client::fairing())
|
||||
.mount("/metrics", prometheus)
|
||||
.mount("/", routes![botinfo])
|
||||
.mount(
|
||||
"/",
|
||||
"/api",
|
||||
routes![
|
||||
botinfo,
|
||||
api::get_members,
|
||||
api::get_switches,
|
||||
api::get_switch,
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
use paseto::tokens::{validate_public_token, PasetoPublicKey};
|
||||
use paseto::PasetoBuilder;
|
||||
use ring::signature::Ed25519KeyPair;
|
||||
use rocket::{
|
||||
fairing::AdHoc,
|
||||
http::Status,
|
||||
request::{self, FromRequest, Request},
|
||||
Outcome, State,
|
||||
};
|
||||
use rusty_ulid::generate_ulid_string;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub fn ed25519_keypair() -> AdHoc {
|
||||
AdHoc::on_attach("ed25519 keypair for paseto", |rocket| {
|
||||
let cfg = rocket.config();
|
||||
let table = cfg.get_table("paseto").unwrap();
|
||||
let private = table["private"].as_str().unwrap().to_string();
|
||||
let private = hex::decode(&private).unwrap();
|
||||
let public = table["public"].as_str().unwrap().to_string();
|
||||
let public = hex::decode(&public).unwrap();
|
||||
let kp = Ed25519KeyPair::from_seed_and_public_key(&private, &public).unwrap();
|
||||
|
||||
let token = PasetoBuilder::new()
|
||||
.set_ed25519_key(kp)
|
||||
.set_issued_at(None)
|
||||
.set_issuer("manual API call".into())
|
||||
.set_audience("wizards".into())
|
||||
.set_jti(generate_ulid_string())
|
||||
.set_subject("Within".into())
|
||||
.build()
|
||||
.unwrap();
|
||||
debug!("token: {}", token);
|
||||
|
||||
Ok(rocket
|
||||
.manage(Ed25519KeyPair::from_seed_and_public_key(&private, &public).unwrap())
|
||||
.manage(PasetoPublicKey::ED25519KeyPair(
|
||||
Ed25519KeyPair::from_seed_and_public_key(&private, &public).unwrap(),
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Token {
|
||||
pub jti: String,
|
||||
pub sub: String,
|
||||
pub aud: String,
|
||||
}
|
||||
|
||||
impl<'a, 'r> FromRequest<'a, 'r> for Token {
|
||||
type Error = ();
|
||||
|
||||
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
|
||||
let keys: Vec<_> = request.headers().get("authorization").collect();
|
||||
match keys.len() {
|
||||
1 => {
|
||||
let tok = keys[0];
|
||||
let paseto_key = request.guard::<State<PasetoPublicKey>>().unwrap();
|
||||
|
||||
match validate_public_token(tok, None, &paseto_key) {
|
||||
Ok(val) => {
|
||||
let tok: Token = serde_json::from_value(val).unwrap();
|
||||
Outcome::Success(tok)
|
||||
}
|
||||
Err(why) => {
|
||||
error!("paseto error: {}", why);
|
||||
Outcome::Failure((Status::Unauthorized, ()))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Outcome::Failure((Status::Unauthorized, ())),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue