diff --git a/Cargo.toml b/Cargo.toml index 36932c2..a5e93aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,12 @@ name = "beteran_common_rust" path = "./src/lib.rs" [dependencies] +jsonwebtoken = { version = "8" } +lazy_static = { version = "1" } +prost = { version = "0" } serde = { version = "1", features = ["derive"] } serde_json = { version = "1" } -prost = { version = "0" } +time = { version = "0" } beteran-protobuf-rust = { git = "https://gitlab.loafle.net/bet/beteran-protobuf-rust.git", tag = "v0.1.74-snapshot" } diff --git a/resources/private.pem b/resources/private.pem new file mode 100644 index 0000000..b2ed0da --- /dev/null +++ b/resources/private.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAw/GvSFLy8K5uT79REy5lJtIS+Y9uAP1SJEyLvAqWfdPh9YO5 +QCnYPp1uCqL3xWozkhrQWUbaYkO+65vjmYcGBMlzO+7KvZcHh4wr8ybA03M6Yy6J +SbnXRQvVm2Bvp2Z1B0dkT11CtZxiaNywYFvMhh5+zEbsrbFkzN5zI+hNpyg4uaaQ +Y5Oy2jGW3zuOIy/i0qzs3pCHWDAk0d5hpGvflUIj7BOQtl7CcFoB8tMp6F2fi8t9 +m/Qa0yvQz8CNf7pdDqprUlm509wKzB4HgX8aG5SMwMlfuQjvT3jQNLRnHJFDghdZ +uCaop8IKf4PVGjuLo0SEebYzVEYfzLQrHemoRwIDAQABAoIBAA7y+XSDH5XNOQ1M +g1r7RyxXCquPjcz1hrbOQDrwc9rVt3+LtS54As+EI0kcddrR521WLl8hULf+gypm +kk68RnFHDUudREqCo0hsIU5DvqJjQCkg+8hsLUhPRtS73sjewD7162lCrDw+2iM1 +8x7m4gu5d+MN5jC6P/6BWjd7GbGO9Yvnz1avKLwwNgLoivZn1S88FAXE8wEgAG4j +evlHX6BaAaOkMyocaB67nNWyZQi/+prxRtdYdCqTV2wyrDVVFgh/1P70nijVUU5X +UKQFZWOOmaRLiy5iL36XgMtnToTPMboF+MZuRbmQfxgifYFxqObuX+8cleylPilh +MgayeUECgYEA/5CPPzlhaHEehXPnG/UvXPHWuuWFMwNWkKl2yNnBFA/0uB46bKXp +kgVrA6Yhu0IbyXZGc6YL4QDNGgiRvEBQ4JTrd1McSMr/iCesdjxQcoq12Z97yX0r +iriyL7siwMaoMKwD5N2WqovTlFBB+p/tDwDnLKeTxUXbaQ55k/HZ17sCgYEAxEcg +kl5K5Xo6r8ZVyKi9Kiz1KHUacevWocUUzPoPgqBAnx/g/AKNpqGg/JgZVK8C/uT8 +9du6lJkNGezCQKic7GuE6wxDu7Zajr43dNZH+kGc5cWyYBFmt7KuFQ/jD804nGZF +SM0YLTixzqA5yEEBXKe5+INCh8xPIH2LhFYFKuUCgYAgzZFVcCwMl9hvEL1tXT9D +EteZDbTXI2qNDvNsPGcICDRFHbwqDfG5CHD/+ucBfi7K4R+R4JJNwyiQWuE55Jd8 +/CBtJIHQ5h1+gHkmg/9fdGZ7FHlzF1nraGGWttJzJAyakrm9OqQIKAJ0Wwjc/oIT +Fu6VUL0q6RiMl4sLblOj2QKBgFzFQZ/s8XmFTDfIhsNQ/hfxJ+73aoht8ASGIk6/ +4pTbKbAMYUq76jfYLT82pMJh9giEMwwBzy5tKMQYI7hr+b/FEg4Gvfz7M9JEFfIj +VeHzITV5O9YsY2BwE9fgqnHNjfReYmEGj2bQZTpEgQslrn8cx8muQMPuzXeN32Ot +RMQBAoGAeV9lVry9F5gB8rlOBlbPOz8wldx5hjs5TvwLnZVdyfwsjmAKEKKNTdma +AxH8Zkz0U/EMOzbmlc0hRSzwtM4ApH3E4TiQctyCAGxS9OY/AeW6TU0o+H2cyktR +LJkeETFJfaqynSBfSY2qX2YzsG5tlc8oITf8QKwKQ9WbrTHLQjs= +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/resources/public.pem b/resources/public.pem new file mode 100644 index 0000000..a54921a --- /dev/null +++ b/resources/public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw/GvSFLy8K5uT79REy5l +JtIS+Y9uAP1SJEyLvAqWfdPh9YO5QCnYPp1uCqL3xWozkhrQWUbaYkO+65vjmYcG +BMlzO+7KvZcHh4wr8ybA03M6Yy6JSbnXRQvVm2Bvp2Z1B0dkT11CtZxiaNywYFvM +hh5+zEbsrbFkzN5zI+hNpyg4uaaQY5Oy2jGW3zuOIy/i0qzs3pCHWDAk0d5hpGvf +lUIj7BOQtl7CcFoB8tMp6F2fi8t9m/Qa0yvQz8CNf7pdDqprUlm509wKzB4HgX8a +G5SMwMlfuQjvT3jQNLRnHJFDghdZuCaop8IKf4PVGjuLo0SEebYzVEYfzLQrHemo +RwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/src/jwt/mod.rs b/src/jwt/mod.rs new file mode 100644 index 0000000..e9cc2f5 --- /dev/null +++ b/src/jwt/mod.rs @@ -0,0 +1,75 @@ +use serde::{Deserialize, Serialize}; +use std::fmt; + +lazy_static! { + static ref ENCODING_KEY: jsonwebtoken::EncodingKey = + jsonwebtoken::EncodingKey::from_rsa_pem(include_bytes!("../../resources/private.pem")) + .expect("ENCODING_KEY"); + static ref DECODING_KEY: jsonwebtoken::DecodingKey = + jsonwebtoken::DecodingKey::from_rsa_pem(include_bytes!("../../resources/public.pem")) + .expect("DECODING_KEY"); +} + +#[derive(Debug)] +pub enum Error { + Encoding(String), + Decoding(String), +} + +impl std::error::Error for Error {} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::Encoding(e) => write!(f, "Encoding Error: {}", e), + Error::Decoding(e) => write!(f, "Decoding Error: {}", e), + } + } +} + +// #[derive(Debug, Serialize, Deserialize)] +// struct Claims { +// aud: String, // Optional. Audience +// exp: usize, // Required (validate_exp defaults to true in validation). Expiration time (as UTC timestamp) +// iat: usize, // Optional. Issued at (as UTC timestamp) +// iss: String, // Optional. Issuer +// nbf: usize, // Optional. Not Before (as UTC timestamp) +// sub: String, // Optional. Subject (whom token refers to) +// } + +#[derive(Debug, Serialize, Deserialize)] +pub struct Claims { + pub iss: String, + pub iat: i64, + pub exp: i64, + pub session_id: String, +} + +pub fn encode(issuer: &str, session_id: &str) -> Result { + use jsonwebtoken::{encode, Algorithm, Header}; + + let header = Header::new(Algorithm::RS256); + + let issued_at = time::OffsetDateTime::now_utc(); + let expiration_at = issued_at + time::Duration::days(1); + let claims = Claims { + iss: issuer.to_string(), + iat: issued_at.unix_timestamp(), + exp: expiration_at.unix_timestamp(), + session_id: session_id.to_string(), + }; + + let token = + encode(&header, &claims, &ENCODING_KEY).map_err(|e| Error::Encoding(e.to_string()))?; + + Ok(token) +} + +pub fn decode(token: &str) -> Result { + use jsonwebtoken::{decode, Algorithm, Validation}; + + let token_data = decode::(token, &DECODING_KEY, &Validation::new(Algorithm::RS256)) + .map_err(|e| Error::Decoding(e.to_string()))?; + + Ok(token_data.claims) +} diff --git a/src/lib.rs b/src/lib.rs index 861942d..bea0987 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,6 @@ +#[macro_use] +extern crate lazy_static; + pub mod error; -pub mod models; +pub mod jwt; +pub mod pagination; diff --git a/src/models/mod.rs b/src/models/mod.rs deleted file mode 100644 index bc8665b..0000000 --- a/src/models/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod pagination; diff --git a/src/models/pagination/mod.rs b/src/pagination/mod.rs similarity index 100% rename from src/models/pagination/mod.rs rename to src/pagination/mod.rs