feat: add aes256

This commit is contained in:
newt 2024-09-25 02:20:37 +01:00
parent e214b265cd
commit 70cf9174a4
7 changed files with 1121 additions and 17 deletions

5
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,5 @@
{
"files.exclude": {
"target": true
}
}

1039
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -5,8 +5,11 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
aes-gcm = "0.10.3"
axum = "0.7.6" axum = "0.7.6"
color-eyre = "0.6.3" color-eyre = "0.6.3"
rand = "0.8.5"
reqwest = "0.12.7" reqwest = "0.12.7"
serde = { version = "1.0.210", features = ["derive"] } serde = { version = "1.0.210", features = ["derive"] }
sqlx = { version = "0.8.2", features = ["runtime-tokio", "sqlite"] }
tokio = { version = "1.40.0", features = ["full"] } tokio = { version = "1.40.0", features = ["full"] }

BIN
marquee.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

10
readme.md Normal file
View file

@ -0,0 +1,10 @@
<div align="center">
<img src="marquee.jpg">
<h1>uofgcal</h1>
</div>
### todo
- logging
- web dashboard
- key rotation

28
src/auth.rs Normal file
View file

@ -0,0 +1,28 @@
use aes_gcm::{
aead::{
consts::{B0, B1},
generic_array::GenericArray,
Aead,
},
aes::cipher::typenum::{UInt, UTerm},
AeadCore, Aes256Gcm,
};
use color_eyre::{eyre::eyre, Result};
use rand::rngs::OsRng;
pub type Nonce = GenericArray<u8, UInt<UInt<UInt<UInt<UTerm, B1>, B1>, B0>, B0>>;
pub fn encrypt_password(password: &str, cipher: &Aes256Gcm) -> Result<(Vec<u8>, Nonce)> {
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
let ciphertext = cipher
.encrypt(&nonce, password.as_bytes().as_ref())
.map_err(|_| eyre!("Failed to encrypt password"))?;
Ok((ciphertext, nonce))
}
pub fn decrypt_password(ciphertext: &[u8], nonce: &Nonce, cipher: &Aes256Gcm) -> Result<String> {
let password = cipher
.decrypt(nonce, ciphertext.as_ref())
.map_err(|_| eyre!("Failed to decrypt password"))?;
Ok(String::from_utf8(password).map_err(|_| eyre!("Failed to convert password to string"))?)
}

View file

@ -1,3 +1,6 @@
mod auth;
use aes_gcm::{Aes256Gcm, KeyInit};
use axum::{ use axum::{
extract::{Query, State}, extract::{Query, State},
http::StatusCode, http::StatusCode,
@ -6,8 +9,10 @@ use axum::{
Router, Router,
}; };
use color_eyre::Result; use color_eyre::Result;
use rand::rngs::OsRng;
use reqwest::{header, Client}; use reqwest::{header, Client};
use serde::Deserialize; use serde::Deserialize;
use sqlx::{Executor, SqlitePool};
use std::borrow::Cow; use std::borrow::Cow;
use tokio::net::TcpListener; use tokio::net::TcpListener;
@ -20,9 +25,16 @@ struct AuthPayload {
pass: Cow<'static, str>, pass: Cow<'static, str>,
} }
#[derive(Clone)]
struct AppState {
cipher: Aes256Gcm,
client: Client,
pool: SqlitePool,
}
async fn get_calender( async fn get_calender(
Query(auth): Query<AuthPayload>, Query(auth): Query<AuthPayload>,
State(client): State<Client>, State(AppState { client, .. }): State<AppState>,
) -> impl IntoResponse { ) -> impl IntoResponse {
if let Ok(resp) = client if let Ok(resp) = client
.get(CALENDAR_URL) .get(CALENDAR_URL)
@ -57,14 +69,47 @@ async fn get_calender(
async fn main() -> Result<()> { async fn main() -> Result<()> {
color_eyre::install()?; color_eyre::install()?;
// setup the http client and tcp listener // connect to the database
let pool = SqlitePool::connect(if cfg!(debug_assertions) {
"sqlite::memory:"
} else {
"uofgcal.db"
})
.await?;
// ensure the users table exists
let mut handle = pool.acquire().await?;
// todo: rewrite
handle
.execute(
"CREATE TABLE IF NOT EXISTS users (
guid VARCHAR(8) PRIMARY KEY,
nonce BLOB NOT NULL,
pass BLOB NOT NULL
)",
)
.await?;
handle.close().await?;
// prepare state
let client = Client::new(); let client = Client::new();
let tcp_listener = TcpListener::bind(format!("0.0.0.0:{PORT}")).await?; let cipher = Aes256Gcm::new({
// todo: read from disk in production
&Aes256Gcm::generate_key(OsRng)
});
let state = AppState {
cipher,
client,
pool,
};
// start the server // start the server
let tcp_listener = TcpListener::bind(format!("0.0.0.0:{PORT}")).await?;
let router = Router::new() let router = Router::new()
.route("/", get(get_calender)) .route("/", get(get_calender))
.with_state(client); .with_state(state);
axum::serve(tcp_listener, router).await?; axum::serve(tcp_listener, router).await?;
Ok(()) Ok(())