feat: add aes256
This commit is contained in:
parent
e214b265cd
commit
70cf9174a4
7 changed files with 1121 additions and 17 deletions
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"files.exclude": {
|
||||||
|
"target": true
|
||||||
|
}
|
||||||
|
}
|
1039
Cargo.lock
generated
1039
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -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
BIN
marquee.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 151 KiB |
10
readme.md
Normal file
10
readme.md
Normal 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
28
src/auth.rs
Normal 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"))?)
|
||||||
|
}
|
53
src/main.rs
53
src/main.rs
|
@ -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(())
|
||||||
|
|
Loading…
Reference in a new issue