From b70195bfe12646c9c1b7482cdac3682651789ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Berthaud-M=C3=BCller?= Date: Sun, 24 Apr 2022 10:50:46 +0200 Subject: [PATCH] delete old files --- src/models/dns.bak.rs | 480 ---------------------------------------- src/models/users.bak.rs | 414 ---------------------------------- 2 files changed, 894 deletions(-) delete mode 100644 src/models/dns.bak.rs delete mode 100644 src/models/users.bak.rs diff --git a/src/models/dns.bak.rs b/src/models/dns.bak.rs deleted file mode 100644 index c9d13b8..0000000 --- a/src/models/dns.bak.rs +++ /dev/null @@ -1,480 +0,0 @@ -use std::{convert::{TryFrom, TryInto}, future::Future, net::{Ipv6Addr, Ipv4Addr}, pin::Pin, task::{Context, Poll}}; -use std::fmt; -use std::ops::{Deref, DerefMut}; - - -use rocket::{Request, State, http::Status, request::{FromParam, FromRequest, Outcome}}; - -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -use tokio::{net::TcpStream as TokioTcpStream, task}; - -use trust_dns_client::{client::AsyncClient, error::ClientError, op::DnsResponse, serialize::binary::BinEncoder, tcp::TcpClientStream}; -use trust_dns_proto::error::{ProtoError}; -use trust_dns_proto::iocompat::AsyncIoTokioAsStd; - - -use super::trust_dns_types::{self, Name}; -use crate::config::Config; - - -#[derive(Deserialize, Serialize, Clone)] -#[serde(tag = "Type")] -#[serde(rename_all = "UPPERCASE")] -pub enum RData { - #[serde(rename_all = "PascalCase")] - A { - address: Ipv4Addr - }, - #[serde(rename_all = "PascalCase")] - AAAA { - address: Ipv6Addr - }, - #[serde(rename_all = "PascalCase")] - CAA { - issuer_critical: bool, - value: String, - property_tag: String, - }, - #[serde(rename_all = "PascalCase")] - CNAME { - target: SerdeName - }, - // HINFO(HINFO), - // HTTPS(SVCB), - #[serde(rename_all = "PascalCase")] - MX { - preference: u16, - mail_exchanger: SerdeName - }, - // NAPTR(NAPTR), - #[serde(rename_all = "PascalCase")] - NULL { - data: String - }, - #[serde(rename_all = "PascalCase")] - NS { - target: SerdeName - }, - // OPENPGPKEY(OPENPGPKEY), - // OPT(OPT), - #[serde(rename_all = "PascalCase")] - PTR { - target: SerdeName - }, - #[serde(rename_all = "PascalCase")] - SOA { - master_server_name: SerdeName, - maintainer_name: SerdeName, - refresh: i32, - retry: i32, - expire: i32, - minimum: u32, - serial: u32 - }, - #[serde(rename_all = "PascalCase")] - SRV { - server: SerdeName, - port: u16, - priority: u16, - weight: u16, - }, - #[serde(rename_all = "PascalCase")] - SSHFP { - algorithm: u8, - digest_type: u8, - fingerprint: String, - }, - // SVCB(SVCB), - // TLSA(TLSA), - #[serde(rename_all = "PascalCase")] - TXT { - text: String - }, - - // TODO: Eventually allow deserialization of DNSSEC records - #[serde(skip)] - DNSSEC(trust_dns_types::DNSSECRData), - #[serde(rename_all = "PascalCase")] - Unknown { - code: u16, - data: String, - }, - // ZERO, - - // TODO: DS -} - -impl From for RData { - fn from(rdata: trust_dns_types::RData) -> RData { - match rdata { - trust_dns_types::RData::A(address) => RData::A { address }, - trust_dns_types::RData::AAAA(address) => RData::AAAA { address }, - // Still a draft, no iana number yet, I don't to put something that is not currently supported so that's why NULL and not unknown. - // TODO: probably need better error here, I don't know what to do about that as this would require to change the From for something else. - // (empty data because I'm lazy) - trust_dns_types::RData::ANAME(_) => RData::NULL { - data: String::new() - }, - trust_dns_types::RData::CNAME(target) => RData::CNAME { - target: SerdeName(target) - }, - trust_dns_types::RData::CAA(caa) => RData::CAA { - issuer_critical: caa.issuer_critical(), - value: format!("{}", CAAValue(caa.value())), - property_tag: caa.tag().as_str().to_string(), - }, - trust_dns_types::RData::MX(mx) => RData::MX { - preference: mx.preference(), - mail_exchanger: SerdeName(mx.exchange().clone()) - }, - trust_dns_types::RData::NULL(null) => RData::NULL { - data: base64::encode(null.anything().map(|data| data.to_vec()).unwrap_or_default()) - }, - trust_dns_types::RData::NS(target) => RData::NS { - target: SerdeName(target) - }, - trust_dns_types::RData::PTR(target) => RData::PTR { - target: SerdeName(target) - }, - trust_dns_types::RData::SOA(soa) => RData::SOA { - master_server_name: SerdeName(soa.mname().clone()), - maintainer_name: SerdeName(soa.rname().clone()), - refresh: soa.refresh(), - retry: soa.retry(), - expire: soa.expire(), - minimum: soa.minimum(), - serial: soa.serial() - }, - trust_dns_types::RData::SRV(srv) => RData::SRV { - server: SerdeName(srv.target().clone()), - port: srv.port(), - priority: srv.priority(), - weight: srv.weight(), - }, - trust_dns_types::RData::SSHFP(sshfp) => RData::SSHFP { - algorithm: sshfp.algorithm().into(), - digest_type: sshfp.fingerprint_type().into(), - fingerprint: trust_dns_types::sshfp::HEX.encode(sshfp.fingerprint()), - }, - //TODO: This might alter data if not utf8 compatible, probably need to be replaced - //TODO: check whether concatenating txt data is harmful or not - trust_dns_types::RData::TXT(txt) => RData::TXT { text: format!("{}", txt) }, - trust_dns_types::RData::DNSSEC(data) => RData::DNSSEC(data), - rdata => { - let code = rdata.to_record_type().into(); - let mut data = Vec::new(); - let mut encoder = BinEncoder::new(&mut data); - // TODO: need better error handling (use TryFrom ?) - rdata.emit(&mut encoder).expect("could not encode data"); - - RData::Unknown { - code, - data: base64::encode(data), - } - } - } - } -} - -impl TryFrom for trust_dns_types::RData { - type Error = ProtoError; - - fn try_from(rdata: RData) -> Result { - Ok(match rdata { - RData::A { address } => trust_dns_types::RData::A(address), - RData::AAAA { address } => trust_dns_types::RData::AAAA(address), - // TODO: Round trip test all types below (currently not tested...) - RData::CAA { issuer_critical, value, property_tag } => { - let property = trust_dns_types::caa::Property::from(property_tag); - let caa_value = { - // TODO: duplicate of trust_dns_client::serialize::txt::rdata_parser::caa::parse - // because caa::read_value is private - match property { - trust_dns_types::caa::Property::Issue | trust_dns_types::caa::Property::IssueWild => { - let value = trust_dns_types::caa::read_issuer(value.as_bytes())?; - trust_dns_types::caa::Value::Issuer(value.0, value.1) - } - trust_dns_types::caa::Property::Iodef => { - let url = trust_dns_types::caa::read_iodef(value.as_bytes())?; - trust_dns_types::caa::Value::Url(url) - } - trust_dns_types::caa::Property::Unknown(_) => trust_dns_types::caa::Value::Unknown(value.as_bytes().to_vec()), - } - }; - trust_dns_types::RData::CAA(trust_dns_types::caa::CAA { - issuer_critical, - tag: property, - value: caa_value, - }) - }, - RData::CNAME { target } => trust_dns_types::RData::CNAME(target.into_inner()), - RData::MX { preference, mail_exchanger } => trust_dns_types::RData::MX( - trust_dns_types::mx::MX::new(preference, mail_exchanger.into_inner()) - ), - RData::NULL { data } => trust_dns_types::RData::NULL( - trust_dns_types::null::NULL::with( - base64::decode(data).map_err(|e| ProtoError::from(format!("{}", e)))? - ) - ), - RData::NS { target } => trust_dns_types::RData::NS(target.into_inner()), - RData::PTR { target } => trust_dns_types::RData::PTR(target.into_inner()), - RData::SOA { - master_server_name, - maintainer_name, - refresh, - retry, - expire, - minimum, - serial - } => trust_dns_types::RData::SOA( - trust_dns_types::soa::SOA::new( - master_server_name.into_inner(), - maintainer_name.into_inner(), - serial, - refresh, - retry, - expire, - minimum, - ) - ), - RData::SRV { server, port, priority, weight } => trust_dns_types::RData::SRV( - trust_dns_types::srv::SRV::new(priority, weight, port, server.into_inner()) - ), - RData::SSHFP { algorithm, digest_type, fingerprint } => trust_dns_types::RData::SSHFP( - trust_dns_types::sshfp::SSHFP::new( - // NOTE: This allows unassigned algorithms - trust_dns_types::sshfp::Algorithm::from(algorithm), - trust_dns_types::sshfp::FingerprintType::from(digest_type), - trust_dns_types::sshfp::HEX.decode(fingerprint.as_bytes()).map_err(|e| ProtoError::from(format!("{}", e)))? - ) - ), - RData::TXT { text } => trust_dns_types::RData::TXT(trust_dns_types::txt::TXT::new(vec![text])), - // TODO: Error out for DNSSEC? Prefer downstream checks? - RData::DNSSEC(_) => todo!(), - // TODO: Disallow unknown? (could be used to bypass unsopported types?) Prefer downstream checks? - RData::Unknown { code, data } => todo!(), - }) - } -} - -struct CAAValue<'a>(&'a trust_dns_types::caa::Value); - -// trust_dns Display implementation panics if no parameters -// Implementation based on caa::emit_value -// Also the quotes are strips to render in JSON -impl<'a> fmt::Display for CAAValue<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - match self.0 { - trust_dns_types::caa::Value::Issuer(name, parameters) => { - - if let Some(name) = name { - write!(f, "{}", name)?; - } - - if name.is_none() && parameters.is_empty() { - write!(f, ";")?; - } - - for value in parameters { - write!(f, "; {}", value)?; - } - } - trust_dns_types::caa::Value::Url(url) => write!(f, "{}", url)?, - trust_dns_types::caa::Value::Unknown(v) => write!(f, "{:?}", v)?, - } - Ok(()) - } -} - -#[derive(Deserialize, Serialize, Clone)] -pub enum DNSClass { - IN, - CH, - HS, - NONE, - ANY, - OPT(u16), -} - -impl From for DNSClass { - fn from(dns_class: trust_dns_types::DNSClass) -> DNSClass { - match dns_class { - trust_dns_types::DNSClass::IN => DNSClass::IN, - trust_dns_types::DNSClass::CH => DNSClass::CH, - trust_dns_types::DNSClass::HS => DNSClass::HS, - trust_dns_types::DNSClass::NONE => DNSClass::NONE, - trust_dns_types::DNSClass::ANY => DNSClass::ANY, - trust_dns_types::DNSClass::OPT(v) => DNSClass::OPT(v), - } - } -} - -impl From for trust_dns_types::DNSClass { - fn from(dns_class: DNSClass) -> trust_dns_types::DNSClass { - match dns_class { - DNSClass::IN => trust_dns_types::DNSClass::IN, - DNSClass::CH => trust_dns_types::DNSClass::CH, - DNSClass::HS => trust_dns_types::DNSClass::HS, - DNSClass::NONE => trust_dns_types::DNSClass::NONE, - DNSClass::ANY => trust_dns_types::DNSClass::ANY, - DNSClass::OPT(v) => trust_dns_types::DNSClass::OPT(v), - } - } -} - - -// Reimplement this type here as ClientReponse in trust-dns crate have private fields -pub struct ClientResponse(pub(crate) R) -where - R: Future> + Send + Unpin + 'static; - -impl Future for ClientResponse -where - R: Future> + Send + Unpin + 'static, -{ - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // This is from the future_utils crate, we simply reuse the reexport from Rocket - rocket::futures::FutureExt::poll_unpin(&mut self.0, cx).map_err(ClientError::from) - } -} - - - -#[derive(Deserialize, Serialize, Clone)] -pub struct Record { - #[serde(rename = "Name")] - pub name: SerdeName, - // TODO: Make class optional, default to IN - #[serde(rename = "Class")] - pub dns_class: DNSClass, - #[serde(rename = "TTL")] - pub ttl: u32, - #[serde(flatten)] - pub rdata: RData, -} - -impl From for Record { - fn from(record: trust_dns_types::Record) -> Record { - Record { - name: SerdeName(record.name().clone()), - dns_class: record.dns_class().into(), - ttl: record.ttl(), - rdata: record.into_data().into(), - } - } -} - -impl TryFrom for trust_dns_types::Record { - type Error = ProtoError; - - fn try_from(record: Record) -> Result { - let mut trust_dns_record = trust_dns_types::Record::from_rdata(record.name.into_inner(), record.ttl, record.rdata.try_into()?); - trust_dns_record.set_dns_class(record.dns_class.into()); - Ok(trust_dns_record) - } -} - -#[derive(Debug, Clone)] -pub struct SerdeName(Name); - -impl<'de> Deserialize<'de> for SerdeName { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de> - { - use serde::de::Error; - - String::deserialize(deserializer) - .and_then(|string| - Name::from_utf8(&string) - .map_err(|e| Error::custom(e.to_string())) - ).map( SerdeName) - } -} - -impl Deref for SerdeName { - type Target = Name; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Serialize for SerdeName { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer - { - self.0.to_utf8().serialize(serializer) - } -} - -impl SerdeName { - fn into_inner(self) -> Name { - self.0 - } -} - - -#[derive(Debug, Deserialize)] -pub struct AbsoluteName(SerdeName); - -impl<'r> FromParam<'r> for AbsoluteName { - type Error = ProtoError; - - fn from_param(param: &'r str) -> Result { - let mut name = Name::from_utf8(¶m)?; - if !name.is_fqdn() { - name.set_fqdn(true); - } - Ok(AbsoluteName(SerdeName(name))) - } -} - -impl Deref for AbsoluteName { - type Target = Name; - fn deref(&self) -> &Self::Target { - &self.0.0 - } -} -pub struct DnsClient(AsyncClient); - -impl Deref for DnsClient { - type Target = AsyncClient; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for DnsClient { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - - -#[rocket::async_trait] -impl<'r> FromRequest<'r> for DnsClient { - type Error = (); - async fn from_request(request: &'r Request<'_>) -> Outcome { - let config = try_outcome!(request.guard::>().await); - let (stream, handle) = TcpClientStream::>::new(config.dns.server); - let client = AsyncClient::with_timeout( - stream, - handle, - std::time::Duration::from_secs(5), - None); - let (client, bg) = match client.await { - Err(e) => { - println!("Failed to connect to DNS server {:#?}", e); - return Outcome::Failure((Status::InternalServerError, ())) - }, - Ok(c) => c - }; - task::spawn(bg); - Outcome::Success(DnsClient(client)) - } -} diff --git a/src/models/users.bak.rs b/src/models/users.bak.rs deleted file mode 100644 index d19142c..0000000 --- a/src/models/users.bak.rs +++ /dev/null @@ -1,414 +0,0 @@ -use uuid::Uuid; -use diesel::prelude::*; -use diesel::result::Error as DieselError; -use diesel_derive_enum::DbEnum; -use rocket::{State, request::{FromRequest, Request, Outcome}}; -use serde::{Serialize, Deserialize}; -use chrono::serde::ts_seconds; -use chrono::prelude::{DateTime, Utc}; -use chrono::Duration; -// TODO: Maybe just use argon2 crate directly -use djangohashers::{make_password_with_algorithm, check_password, HasherError, Algorithm}; -use jsonwebtoken::{ - encode, decode, - Header, Validation, - Algorithm as JwtAlgorithm, EncodingKey, DecodingKey, - errors::Result as JwtResult, - errors::ErrorKind as JwtErrorKind -}; - -use crate::schema::*; -use crate::DbConn; -use crate::config::Config; -use crate::models::errors::{ErrorResponse, make_500}; -use crate::models::dns::AbsoluteName; - -const BEARER: &str = "Bearer "; -const AUTH_HEADER: &str = "Authorization"; - - -#[derive(Debug, DbEnum, Deserialize, Clone)] -#[serde(rename_all = "lowercase")] -pub enum Role { - #[db_rename = "admin"] - Admin, - #[db_rename = "zoneadmin"] - ZoneAdmin, -} - -// TODO: Store Uuid instead of string?? -#[derive(Debug, Queryable, Identifiable, Insertable)] -#[table_name = "user"] -pub struct User { - pub id: String, -} - -#[derive(Debug, Queryable, Identifiable, Insertable)] -#[table_name = "localuser"] -#[primary_key(user_id)] -pub struct LocalUser { - pub user_id: String, - pub username: String, - pub password: String, - pub role: Role, -} - -#[derive(Debug, Queryable, Identifiable, Insertable)] -#[table_name = "user_zone"] -#[primary_key(user_id, zone_id)] -pub struct UserZone { - pub user_id: String, - pub zone_id: String, -} - -#[derive(Debug, Serialize, Queryable, Identifiable, Insertable)] -#[table_name = "zone"] -pub struct Zone { - #[serde(skip)] - pub id: String, - pub name: String, -} - -#[derive(Debug, Deserialize)] -pub struct CreateUserRequest { - pub username: String, - pub password: String, - pub email: String, - pub role: Option -} - -#[derive(Debug, Deserialize)] -pub struct AddZoneMemberRequest { - pub id: String, -} - -#[derive(Debug, Deserialize)] -pub struct CreateZoneRequest { - pub name: AbsoluteName, -} - -// pub struct LdapUserAssociation { -// user_id: Uuid, -// ldap_id: String -// } - -#[derive(Debug, Serialize, Deserialize)] -pub struct AuthClaims { - pub jti: String, - pub sub: String, - #[serde(with = "ts_seconds")] - pub exp: DateTime, - #[serde(with = "ts_seconds")] - pub iat: DateTime, -} - -#[derive(Debug, Serialize)] -pub struct AuthTokenResponse { - pub token: String -} - -#[derive(Debug, Deserialize)] -pub struct AuthTokenRequest { - pub username: String, - pub password: String, -} - -#[derive(Debug)] -pub struct UserInfo { - pub id: String, - pub role: Role, - pub username: String, -} - -impl UserInfo { - pub fn is_admin(&self) -> bool { - matches!(self.role, Role::Admin) - } - - pub fn check_admin(&self) -> Result<(), UserError> { - if self.is_admin() { - Ok(()) - } else { - Err(UserError::PermissionDenied) - } - } - - pub fn get_zone(&self, conn: &diesel::SqliteConnection, zone_name: &str) -> Result { - use crate::schema::user_zone::dsl::*; - use crate::schema::zone::dsl::*; - - let (res_zone, _): (Zone, UserZone) = zone.inner_join(user_zone) - .filter(name.eq(zone_name)) - .filter(user_id.eq(&self.id)) - .get_result(conn) - .map_err(|e| match e { - DieselError::NotFound => UserError::ZoneNotFound, - other => UserError::DbError(other) - })?; - - Ok(res_zone) - } - - pub fn get_zones(&self, conn: &diesel::SqliteConnection) -> Result, UserError> { - use crate::schema::user_zone::dsl::*; - use crate::schema::zone::dsl::*; - - let res: Vec<(Zone, UserZone)> = zone.inner_join(user_zone) - .filter(user_id.eq(&self.id)) - .get_results(conn) - .map_err(UserError::DbError)?; - - Ok(res.into_iter().map(|(z, _)| z).collect()) - } -} - -#[rocket::async_trait] -impl<'r> FromRequest<'r> for UserInfo { - type Error = ErrorResponse; - - async fn from_request(request: &'r Request<'_>) -> Outcome { - let auth_header = match request.headers().get_one(AUTH_HEADER) { - None => return Outcome::Forward(()), - Some(auth_header) => auth_header, - }; - - let token = if auth_header.starts_with(BEARER) { - auth_header.trim_start_matches(BEARER) - } else { - return ErrorResponse::from(UserError::MalformedHeader).into() - }; - - let config = try_outcome!(request.guard::>().await.map_failure(make_500)); - let conn = try_outcome!(request.guard::().await.map_failure(make_500)); - - let token_data = AuthClaims::decode( - token, &config.web_app.secret - ).map_err(|e| match e.into_kind() { - JwtErrorKind::ExpiredSignature => UserError::ExpiredToken, - _ => UserError::BadToken, - }); - - let token_data = match token_data { - Err(e) => return ErrorResponse::from(e).into(), - Ok(data) => data - }; - - let user_id = token_data.sub; - - conn.run(move |c| { - match LocalUser::get_user_by_uuid(c, &user_id) { - Err(UserError::NotFound) => ErrorResponse::from(UserError::NotFound).into(), - Err(e) => ErrorResponse::from(e).into(), - Ok(d) => Outcome::Success(d), - } - }).await - } -} - -#[derive(Debug)] -pub enum UserError { - ZoneNotFound, - NotFound, - UserConflict, - BadCreds, - BadToken, - ExpiredToken, - MalformedHeader, - PermissionDenied, - DbError(DieselError), - PasswordError(HasherError), -} - -impl From for UserError { - fn from(e: HasherError) -> Self { - UserError::PasswordError(e) - } -} - -impl From for UserError { - fn from(e: DieselError) -> Self { - UserError::DbError(e) - } -} - -impl LocalUser { - pub fn create_user(conn: &diesel::SqliteConnection, user_request: CreateUserRequest) -> Result { - use crate::schema::localuser::dsl::*; - use crate::schema::user::dsl::*; - - let new_user_id = Uuid::new_v4().to_simple().to_string(); - - let new_user = User { - id: new_user_id.clone(), - }; - - let new_localuser = LocalUser { - user_id: new_user_id, - username: user_request.username.clone(), - password: make_password_with_algorithm(&user_request.password, Algorithm::Argon2), - // TODO: Use role from request - role: Role::ZoneAdmin, - }; - - let res = UserInfo { - id: new_user.id.clone(), - role: new_localuser.role.clone(), - username: new_localuser.username.clone(), - }; - - conn.immediate_transaction(|| -> diesel::QueryResult<()> { - diesel::insert_into(user) - .values(new_user) - .execute(conn)?; - - diesel::insert_into(localuser) - .values(new_localuser) - .execute(conn)?; - - Ok(()) - }).map_err(|e| match e { - DieselError::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _) => UserError::UserConflict, - other => UserError::DbError(other) - })?; - - Ok(res) - } - - pub fn get_user_by_creds( - conn: &diesel::SqliteConnection, - request_username: &str, - request_password: &str - ) -> Result { - - use crate::schema::localuser::dsl::*; - use crate::schema::user::dsl::*; - - let (client_user, client_localuser): (User, LocalUser) = user.inner_join(localuser) - .filter(username.eq(request_username)) - .get_result(conn) - .map_err(|e| match e { - DieselError::NotFound => UserError::BadCreds, - other => UserError::DbError(other) - })?; - - if !check_password(&request_password, &client_localuser.password)? { - return Err(UserError::BadCreds); - } - - Ok(UserInfo { - id: client_user.id, - role: client_localuser.role, - username: client_localuser.username, - }) - } - - pub fn get_user_by_uuid(conn: &diesel::SqliteConnection, request_user_id: &str) -> Result { - use crate::schema::localuser::dsl::*; - use crate::schema::user::dsl::*; - - let (client_user, client_localuser): (User, LocalUser) = user.inner_join(localuser) - .filter(id.eq(request_user_id)) - .get_result(conn) - .map_err(|e| match e { - DieselError::NotFound => UserError::NotFound, - other => UserError::DbError(other) - })?; - - Ok(UserInfo { - id: client_user.id, - role: client_localuser.role, - username: client_localuser.username, - }) - } - -} - -impl AuthClaims { - pub fn new(user_info: &UserInfo, token_duration: Duration) -> AuthClaims { - let jti = Uuid::new_v4().to_simple().to_string(); - let iat = Utc::now(); - let exp = iat + token_duration; - - AuthClaims { - jti, - sub: user_info.id.clone(), - exp, - iat, - } - } - - pub fn decode(token: &str, secret: &str) -> JwtResult { - decode::( - token, - &DecodingKey::from_secret(secret.as_ref()), - &Validation::new(JwtAlgorithm::HS256) - ).map(|data| data.claims) - } - - pub fn encode(self, secret: &str) -> JwtResult { - encode(&Header::default(), &self, &EncodingKey::from_secret(secret.as_ref())) - } -} - -// NOTE: Should probably not be implemented here -// also, "UserError" seems like a misleading name -impl Zone { - pub fn get_all(conn: &diesel::SqliteConnection) -> Result, UserError> { - use crate::schema::zone::dsl::*; - - zone.get_results(conn) - .map_err(UserError::DbError) - } - - pub fn get_by_name(conn: &diesel::SqliteConnection, zone_name: &str) -> Result { - use crate::schema::zone::dsl::*; - - zone.filter(name.eq(zone_name)) - .get_result(conn) - .map_err(|e| match e { - DieselError::NotFound => UserError::ZoneNotFound, - other => UserError::DbError(other) - }) - } - - pub fn create_zone(conn: &diesel::SqliteConnection, zone_request: CreateZoneRequest) -> Result { - use crate::schema::zone::dsl::*; - - let new_zone = Zone { - id: Uuid::new_v4().to_simple().to_string(), - name: zone_request.name.to_utf8(), - }; - - diesel::insert_into(zone) - .values(&new_zone) - .execute(conn) - .map_err(|e| match e { - DieselError::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _) => UserError::UserConflict, - other => UserError::DbError(other) - })?; - Ok(new_zone) - } - - - pub fn add_member(&self, conn: &diesel::SqliteConnection, new_member: &UserInfo) -> Result<(), UserError> { - use crate::schema::user_zone::dsl::*; - - let new_user_zone = UserZone { - zone_id: self.id.clone(), - user_id: new_member.id.clone() - }; - - let res = diesel::insert_into(user_zone) - .values(new_user_zone) - .execute(conn); - - match res { - // If user has already access to the zone, safely ignore the conflit - // TODO: use 'on conflict do nothing' in postgres when we get there - Err(DieselError::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _)) => (), - Err(e) => return Err(e.into()), - Ok(_) => () - }; - Ok(()) - } -}