use crate::error::Error; use crate::schema::{Db, Transaction}; use anyhow::{anyhow, Context, Result}; use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation}; use serde::{Deserialize, Serialize}; use thiserror::Error; use warp::header::headers_cloned; use warp::http::header::{HeaderMap, HeaderValue, AUTHORIZATION}; use warp::reject; use warp::reject::Reject; use warp::{Filter, Rejection}; 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(Error, Debug)] // pub enum Nope { // #[error("Invalid header")] // InvalidHeader { // expected: String, // found: String, // }, // } // impl warp::reject::Reject for Nope {} #[derive(Debug)] struct LessThanTenError {} impl Reject for LessThanTenError {} // impl From for Rejection { // fn from(other: LessThanTenError) -> Self { // warp::reject::custom(other) // } // } pub fn with_auth( db: Db, t: Transaction, ) -> impl Filter + Clone { headers_cloned() .map(move |headers: HeaderMap| (db.clone(), headers)) .and_then(authorize) } async fn authorize((db, headers): (Db, HeaderMap)) -> 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(PUBLIC_KEY_PEM.as_bytes()).unwrap(), &Validation::new(Algorithm::HS512), ) .map_err(|_| reject::custom(Error::JWTTokenError)) .unwrap(); Ok(decoded.claims.puk) } Err(e) => return Err(anyhow!("missing!")), // warp error } } 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()) }