use crate::error::{handle_rejection, Error}; use crate::schema::{Db, Transaction}; use std::convert::Infallible; // use anyhow::{anyhow, Context, Result}; use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation}; use serde::{Deserialize, Serialize}; // use std::fmt::Display; // use thiserror::Error; use warp::header::headers_cloned; use warp::http::header::{HeaderMap, HeaderValue, AUTHORIZATION}; use warp::http::StatusCode; use warp::reject; use warp::reject::Reject; use warp::reject::Rejection; use warp::Filter; const BEARER: &str = "Bearer "; const PUBLIC_KEY_PEM: &str = "-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4nU0G4WjkmcQUx0hq6LQ uV5Q+ACmUFL/OjoYMDwC/O/6pCd1UZgCfgHN2xEffDPznzcTn8OiFRxr4oWyBiny rUpnY4mhy0SQUwoeCw7YkcHAyhCjNT74aR/ohX0MCj0qRRdbt5ZQXM/GC3HJuXE1 ptSuhFgQxziItamn8maoJ6JUSVEXVO1NOrrjoM3r7Q+BK2B+sX4/bLZ+VG5g1q2n EbFdTHS6pHqtZNHQndTmEKwRfh0RYtzEzOXuO6e1gQY42Tujkof40dhGCIU7TeIG GHwdFxy1niLkXwtHNjV7lnIOkTbx6+sSPamRfQAlZqUWM2Lf5o+7h3qWP3ENB138 sQIDAQAB -----END PUBLIC KEY-----"; // const private_key_pem: &str = "-----BEGIN RSA PRIVATE KEY----- // MIIEpAIBAAKCAQEA4nU0G4WjkmcQUx0hq6LQuV5Q+ACmUFL/OjoYMDwC/O/6pCd1 // UZgCfgHN2xEffDPznzcTn8OiFRxr4oWyBinyrUpnY4mhy0SQUwoeCw7YkcHAyhCj // NT74aR/ohX0MCj0qRRdbt5ZQXM/GC3HJuXE1ptSuhFgQxziItamn8maoJ6JUSVEX // VO1NOrrjoM3r7Q+BK2B+sX4/bLZ+VG5g1q2nEbFdTHS6pHqtZNHQndTmEKwRfh0R // YtzEzOXuO6e1gQY42Tujkof40dhGCIU7TeIGGHwdFxy1niLkXwtHNjV7lnIOkTbx // 6+sSPamRfQAlZqUWM2Lf5o+7h3qWP3ENB138sQIDAQABAoIBAD23nYTmrganag6M // wPFrBSGP79c3Lhx0EjUHQjJbGKFgsdltG48qM3ut+DF9ACy0Z+/7bbC7+39vaIOq // 1jLR2d6aiYTaLKseO4s2FawD1sgamvU3BZPsXn0gAhnnU5Gyy8Nas1dccvhoc9wI // neaZUPrvucQ90AzLfo6r9yacDbYHB1lOyomApUvpJxOgHISGEtc9qGPDrdH19aF0 // 8fCv2bbQRh+TChgN3IB0o5w0wXaI7YAyAouAv/AzHCoEMpt7OGjFTkjh/ujlPL9O // +FLuJNsQRHDN0gJo2pcvwGwDCsioMixQ9bZ7ZrUu2BNpEQygyeSbj9ZI1iRvhosO // JU3rwEECgYEA9MppTYA6A9WQbCCwPH1QMpUAmPNVSWVhUVag4lGOEhdCDRcz9ook // DohQMKctiEB1luKuvDokxo0uMOfMO9/YwjsRB7qjQip7Th1zMJIjD+A+juLzHK4r // /RiRtWYGAnF8mptDvE+93JsPb3C/lQLvIhio5GQYWBqPJu6SpeosIskCgYEA7NPi // Gbffzr2UQhW8BNKmctEEh8yFRVojFo3wwwWxSNUVXGSmSm31CL+Q8h817R+2OkPV // 1ZMUOBU4UJiqFt28kIvTDFqbAJlJQGCpY2mY7OLQiD2A+TVLcFrHmoCaPfCAK1Qd // hQ0PmFK7Mf8qClpA3E5chop/WfKQfiu46sZv1qkCgYAhGdXPcw1lQ1W6KVlrdI6J // qHhiNlVMDXdxZkNvFxQdAiQeXQrbxaZGiMw/J/wSNpUwCAsUzM/4QVMDrfSCDCzl // ZtNQtj4pTlFKKNVQthIjrXEIJUw2jp7IJLBfVSJu5iWxSlmId0f3MsiNizN81N69 // P5Rm/doE3+KHoy8VXGsHcQKBgQCkNh62enqjHWypjex6450qS6f6iWN3PRLLVsw0 // TcQpniZblCaBwVCAKmRUnjOEIdL2/4ZLutnwMTaFG/YEOOfAylMiY8jKV38lNmD9 // X4D78CFr9klxgvS2CRwSE03f2NzmLkLxuKaxldvaxPTfjMkgeO1LFMlNExYBhkuH // 7uQpUQKBgQCKX6qMNh2gSdgG7qyxfTFZ4y5EGOBoKe/dE+IcVF3Vnh6DZVbCAbBL // 5EdFWZSrCnDjA4xiKW55mwp95Ud9EZsZAb13L8V9t82eK+UDBoWlb7VRNYpda/x1 // 5/i4qQJ28x2UNJDStpYFpnp4Ba1lvXjKngIbDPkjU+hbBJ+BNGAIeg== // -----END RSA PRIVATE KEY-----"; /// sub: Subject, user identifier /// exp: Expiration date, Unix Time, epoch /// puk: Public Key? Not 100% on this #[derive(Debug, Serialize, Deserialize)] struct Claims { sub: String, exp: usize, puk: String, } #[derive(Debug)] struct RateLimited; #[derive(Debug, Clone)] pub struct Pubkey { a: String, } impl Reject for RateLimited {} pub fn with_auth( db: Db, t: Transaction, ) -> impl Filter + Clone { headers_cloned() .map(move |headers: HeaderMap| (db.clone(), headers, t.source.clone())) .and_then(authorize) } async fn authorize( (db, headers, source): (Db, HeaderMap, String), ) -> Result { match jwt_from_header(&headers) { Ok(jwt) => { let decoded = decode::( &jwt, // TODO: what key are we using here? pass db/pw store here to get the claimant's public key <10-04-21, yigit> // &DecodingKey::from_rsa_pem(db.users.read().get(&source).unwrap().pubkey.as_bytes()).unwrap(), &Validation::new(Algorithm::HS512), ) .map_err(|_| reject::custom(Error::JWTTokenError)) .unwrap(); Ok(Pubkey { a: decoded.claims.puk, }) } Err(e) => return Err(warp::reject::custom(RateLimited)), } } fn jwt_from_header(headers: &HeaderMap) -> Result { let header = match headers.get(AUTHORIZATION) { Some(v) => v, None => return Err(Error::NoAuthHeaderError), }; let auth_header = match std::str::from_utf8(header.as_bytes()) { Ok(v) => v, Err(_) => return Err(Error::NoAuthHeaderError), }; if !auth_header.starts_with(BEARER) { return Err(Error::InvalidAuthHeaderError); } Ok(auth_header.trim_start_matches(BEARER).to_owned()) }