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"
|
||||
|
||||
[dependencies]
|
||||
aes-gcm = "0.10.3"
|
||||
axum = "0.7.6"
|
||||
color-eyre = "0.6.3"
|
||||
rand = "0.8.5"
|
||||
reqwest = "0.12.7"
|
||||
serde = { version = "1.0.210", features = ["derive"] }
|
||||
sqlx = { version = "0.8.2", features = ["runtime-tokio", "sqlite"] }
|
||||
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::{
|
||||
extract::{Query, State},
|
||||
http::StatusCode,
|
||||
|
@ -6,8 +9,10 @@ use axum::{
|
|||
Router,
|
||||
};
|
||||
use color_eyre::Result;
|
||||
use rand::rngs::OsRng;
|
||||
use reqwest::{header, Client};
|
||||
use serde::Deserialize;
|
||||
use sqlx::{Executor, SqlitePool};
|
||||
use std::borrow::Cow;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
|
@ -20,9 +25,16 @@ struct AuthPayload {
|
|||
pass: Cow<'static, str>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct AppState {
|
||||
cipher: Aes256Gcm,
|
||||
client: Client,
|
||||
pool: SqlitePool,
|
||||
}
|
||||
|
||||
async fn get_calender(
|
||||
Query(auth): Query<AuthPayload>,
|
||||
State(client): State<Client>,
|
||||
State(AppState { client, .. }): State<AppState>,
|
||||
) -> impl IntoResponse {
|
||||
if let Ok(resp) = client
|
||||
.get(CALENDAR_URL)
|
||||
|
@ -57,14 +69,47 @@ async fn get_calender(
|
|||
async fn main() -> Result<()> {
|
||||
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 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
|
||||
let tcp_listener = TcpListener::bind(format!("0.0.0.0:{PORT}")).await?;
|
||||
let router = Router::new()
|
||||
.route("/", get(get_calender))
|
||||
.with_state(client);
|
||||
.with_state(state);
|
||||
|
||||
axum::serve(tcp_listener, router).await?;
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue