add paseto middleware
This commit is contained in:
parent
17aa139510
commit
b241a3ebd1
|
@ -1608,6 +1608,7 @@ dependencies = [
|
||||||
"egg-mode",
|
"egg-mode",
|
||||||
"elefren",
|
"elefren",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
|
"hex",
|
||||||
"jsonfeed",
|
"jsonfeed",
|
||||||
"kankyo",
|
"kankyo",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
|
|
|
@ -30,6 +30,7 @@ uuid = { version = "0.7", features = ["serde", "v4"] }
|
||||||
rocket_prometheus = "0.7.0"
|
rocket_prometheus = "0.7.0"
|
||||||
prometheus = { version = "0.10", default-features = false, features = ["process"] }
|
prometheus = { version = "0.10", default-features = false, features = ["process"] }
|
||||||
futures-io = "0.3"
|
futures-io = "0.3"
|
||||||
|
hex = "0.4"
|
||||||
|
|
||||||
jsonfeed = { git = "https://github.com/Xe/site" }
|
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 chrono::prelude::*;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use rocket::{
|
use rocket::{
|
||||||
|
@ -16,7 +16,7 @@ use std::io::Read;
|
||||||
|
|
||||||
#[get("/members")]
|
#[get("/members")]
|
||||||
#[instrument(skip(conn), err)]
|
#[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;
|
use schema::members;
|
||||||
let results = members::table
|
let results = members::table
|
||||||
.load::<models::Member>(&*conn)
|
.load::<models::Member>(&*conn)
|
||||||
|
@ -40,6 +40,7 @@ pub fn get_switches(
|
||||||
conn: MainDatabase,
|
conn: MainDatabase,
|
||||||
count: Option<i64>,
|
count: Option<i64>,
|
||||||
page: Option<i64>,
|
page: Option<i64>,
|
||||||
|
tok: paseto::Token,
|
||||||
) -> Result<Json<Vec<FrontChange>>> {
|
) -> Result<Json<Vec<FrontChange>>> {
|
||||||
use schema::{members, switches};
|
use schema::{members, switches};
|
||||||
|
|
||||||
|
@ -73,7 +74,7 @@ pub fn get_switches(
|
||||||
|
|
||||||
#[get("/switches/current")]
|
#[get("/switches/current")]
|
||||||
#[instrument(skip(conn), err)]
|
#[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};
|
use schema::{members, switches};
|
||||||
|
|
||||||
let mut front: Vec<(models::Switch, models::Member)> = switches::table
|
let mut front: Vec<(models::Switch, models::Member)> = switches::table
|
||||||
|
@ -102,6 +103,7 @@ pub fn make_switch(
|
||||||
who: StringBody,
|
who: StringBody,
|
||||||
sc: State<web::switchcounter::Client>,
|
sc: State<web::switchcounter::Client>,
|
||||||
pk: State<web::pluralkit::Client>,
|
pk: State<web::pluralkit::Client>,
|
||||||
|
tok: paseto::Token,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
use schema::{members, switches};
|
use schema::{members, switches};
|
||||||
let who = who.unwrap();
|
let who = who.unwrap();
|
||||||
|
@ -159,7 +161,11 @@ pub fn make_switch(
|
||||||
|
|
||||||
#[get("/switches/<switch_id>")]
|
#[get("/switches/<switch_id>")]
|
||||||
#[instrument(skip(conn), err)]
|
#[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};
|
use schema::{members, switches::dsl::switches};
|
||||||
|
|
||||||
let (switch, member): (models::Switch, models::Member) = switches
|
let (switch, member): (models::Switch, models::Member) = switches
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub const APPLICATION_NAME: &str = concat!(
|
||||||
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
pub mod models;
|
pub mod models;
|
||||||
|
pub mod paseto;
|
||||||
pub mod schema;
|
pub mod schema;
|
||||||
pub mod web;
|
pub mod web;
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use color_eyre::eyre::Result;
|
||||||
use rocket_contrib::helmet::SpaceHelmet;
|
use rocket_contrib::helmet::SpaceHelmet;
|
||||||
use rocket_prometheus::PrometheusMetrics;
|
use rocket_prometheus::PrometheusMetrics;
|
||||||
|
|
||||||
use ::mi::{api, web, MainDatabase, APPLICATION_NAME};
|
use ::mi::{api, paseto, web, MainDatabase, APPLICATION_NAME};
|
||||||
|
|
||||||
#[get("/.within/botinfo")]
|
#[get("/.within/botinfo")]
|
||||||
fn botinfo() -> &'static str {
|
fn botinfo() -> &'static str {
|
||||||
|
@ -42,13 +42,14 @@ fn main() -> Result<()> {
|
||||||
.attach(prometheus.clone())
|
.attach(prometheus.clone())
|
||||||
.attach(MainDatabase::fairing())
|
.attach(MainDatabase::fairing())
|
||||||
.attach(SpaceHelmet::default())
|
.attach(SpaceHelmet::default())
|
||||||
|
.attach(paseto::ed25519_keypair())
|
||||||
.attach(web::pluralkit::Client::fairing())
|
.attach(web::pluralkit::Client::fairing())
|
||||||
.attach(web::switchcounter::Client::fairing())
|
.attach(web::switchcounter::Client::fairing())
|
||||||
.mount("/metrics", prometheus)
|
.mount("/metrics", prometheus)
|
||||||
|
.mount("/", routes![botinfo])
|
||||||
.mount(
|
.mount(
|
||||||
"/",
|
"/api",
|
||||||
routes![
|
routes![
|
||||||
botinfo,
|
|
||||||
api::get_members,
|
api::get_members,
|
||||||
api::get_switches,
|
api::get_switches,
|
||||||
api::get_switch,
|
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