aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCara Salter <cara@devcara.com>2022-06-28 07:47:29 -0400
committerCara Salter <cara@devcara.com>2022-06-28 07:47:29 -0400
commit2dea604581cafbfbb73443ec2449cda391d12ab7 (patch)
treea1cb6a43f6ca0ac79de0bf525d776057156b500e
parent8de1eae2b49d763dcac55b8a2a84673475a35e63 (diff)
downloadsolard-2dea604581cafbfbb73443ec2449cda391d12ab7.tar.gz
solard-2dea604581cafbfbb73443ec2449cda391d12ab7.zip
auth: Initial implementation of auth/begin
-rw-r--r--Cargo.lock9
-rw-r--r--Cargo.toml4
-rw-r--r--src/errors.rs21
-rw-r--r--src/handlers/auth.rs55
4 files changed, 77 insertions, 12 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7242c13..504227c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -499,6 +499,12 @@ dependencies = [
]
[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
name = "http"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1320,13 +1326,16 @@ version = "0.3.0"
dependencies = [
"axum",
"axum-macros",
+ "chrono",
"color-eyre",
"eyre",
+ "hex",
"hyper",
"kankyo",
"paseto",
"rand",
"reqwest",
+ "ring",
"serde",
"solarlib",
"thiserror",
diff --git a/Cargo.toml b/Cargo.toml
index 0b2ead9..6792e7a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,9 +22,13 @@ kankyo = "0.3"
axum-macros = "0.2"
paseto = "2"
+ring = "0.16"
+hex = "0.4"
rand = "0.8"
+chrono = "0.4"
+
[dependencies.solarlib]
git = "https://git.carathe.dev/solard/solarlib"
branch = "master"
diff --git a/src/errors.rs b/src/errors.rs
index cbec046..f6e00e2 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -1,3 +1,5 @@
+use hex::FromHexError;
+use ring::error::KeyRejected;
use thiserror::Error;
use axum::response::{Response, IntoResponse};
@@ -5,6 +7,8 @@ use axum::http::StatusCode;
use axum::body;
use axum::Json;
+use ring::error::Unspecified as RingUnspecified;
+
#[derive(Debug, Error)]
pub enum ServiceError {
#[error("Solarlib error: {0}")]
@@ -28,12 +32,25 @@ pub enum ServiceError {
#[error("Generic: {0}")]
Generic(String),
- #[error("Paseto: {0}")]
- Paseto(#[from] pasetors::errors::Error),
+ #[error("Invalid PASETO Key: {0}")]
+ PasetoInvalid(#[from] KeyRejected),
+}
+
+impl From<FromHexError> for ServiceError {
+ fn from(_: FromHexError) -> Self {
+ ServiceError::Generic(String::from("Could not convert from hex"))
+ }
}
+impl From<RingUnspecified> for ServiceError {
+ fn from(_: RingUnspecified) -> Self {
+ ServiceError::Generic("Unspecified RNG error".to_string())
+ }
+}
pub type StringResult<T = &'static str> = std::result::Result<T, ServiceError>;
+pub type TokenResult<T = String> = std::result::Result<T, ServiceError>;
+
pub type JsonResult<T> = std::result::Result<T, ServiceError>;
pub type NoneResult = std::result::Result<(), ServiceError>;
diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs
index a9ac394..8d65b05 100644
--- a/src/handlers/auth.rs
+++ b/src/handlers/auth.rs
@@ -1,11 +1,14 @@
-use std::collections::HashMap;
+use std::{collections::HashMap, fs::{self, File}};
use axum::{extract::Query, Extension};
use axum_macros::debug_handler;
-use pasetors::{claims::Claims, keys::{AsymmetricKeyPair, Generate}, version4::V4};
+use chrono::{Utc, TimeZone, Datelike};
+use ring::{rand::SystemRandom, signature::Ed25519KeyPair};
use uuid::Uuid;
-use crate::{errors::{NoneResult, ServiceError}, State};
+use std::io::Write;
+
+use crate::{errors::{NoneResult, ServiceError, StringResult, TokenResult}, State};
/**
@@ -14,21 +17,53 @@ use crate::{errors::{NoneResult, ServiceError}, State};
* for future authentication
*/
#[debug_handler]
-pub async fn begin(Query(params): Query<HashMap<String, String>>, Extension(state): Extension<State>) -> NoneResult {
+pub async fn begin(Query(params): Query<HashMap<String, String>>, Extension(state): Extension<State>) -> TokenResult {
if let Some(k) = params.get("key") {
if k == &state.gen_key {
- let mut claims = Claims::new()?;
- claims.non_expiring();
- claims.audience("solard")?;
- claims.add_additional("uuid", Uuid::new_v4().to_string())?;
+ let dt = Utc::now();
+ let exp = Utc
+ .ymd(dt.year() + 1, dt.month(), dt.day())
+ .and_hms(0, 0, 0);
+ let kp = load_or_gen_keypair()?;
+
+ let token = match paseto::tokens::PasetoBuilder::new()
+ .set_ed25519_key(&kp)
+ .set_issued_at(Some(dt))
+ .set_expiration(&exp)
+ .set_issuer("solard")
+ .set_audience("solard")
+ .set_not_before(&Utc::now())
+ .build() {
+ Ok(token) => token,
+ Err(_) => {
+ return Err(ServiceError::Generic(String::from("could not generate paseto key")));
+ }
+ };
- let kp = AsymmetricKeyPair::<V4>::generate()?;
+ return Ok(token.to_string());
+
} else {
return Err(ServiceError::NotAuthorized);
}
} else {
return Err(ServiceError::Generic("No key supplied".to_string()));
}
+}
+
+
+fn load_or_gen_keypair() -> Result<Ed25519KeyPair, ServiceError> {
+ let kp: Ed25519KeyPair;
+ if let Ok(c) = fs::read_to_string(".keypair") {
+ kp = Ed25519KeyPair::from_pkcs8(&hex::decode(c)?)?;
+ } else {
+ let srand = SystemRandom::new();
+ let pkcs8 = Ed25519KeyPair::generate_pkcs8(&srand)?;
+
+ let mut file = File::open(".keypair").unwrap();
+ file.write(pkcs8.as_ref());
+
+ kp = Ed25519KeyPair::from_pkcs8(pkcs8.as_ref())?;
+ }
- Ok(())
+ Ok(kp)
}