Cleanup
This commit is contained in:
parent
2cb2004840
commit
5ad6a1986d
6 changed files with 21 additions and 30 deletions
18
src/auth.rs
18
src/auth.rs
|
|
@ -1,6 +1,6 @@
|
|||
use axum::{
|
||||
extract::{FromRequestParts, State},
|
||||
http::{header, request::Parts, StatusCode},
|
||||
extract::FromRequestParts,
|
||||
http::{header, request::Parts},
|
||||
};
|
||||
use jsonwebtoken::{decode, DecodingKey, Validation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -9,10 +9,6 @@ use worker::Env;
|
|||
|
||||
use crate::error::AppError;
|
||||
|
||||
// Secret key for signing JWTs. In a real application, this should be a strong,
|
||||
// securely stored secret from the Worker's environment variables.
|
||||
const JWT_SECRET: &str = "a-very-secure-secret-key-that-should-be-in-env";
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Claims {
|
||||
pub sub: String, // User ID
|
||||
|
|
@ -26,13 +22,11 @@ pub struct Claims {
|
|||
pub amr: Vec<String>,
|
||||
}
|
||||
|
||||
impl<S> FromRequestParts<S> for Claims
|
||||
where
|
||||
S: Send + Sync,
|
||||
impl FromRequestParts<Arc<Env>> for Claims
|
||||
{
|
||||
type Rejection = AppError;
|
||||
|
||||
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request_parts(parts: &mut Parts, state: &Arc<Env>) -> Result<Self, Self::Rejection> {
|
||||
// Extract the token from the authorization header
|
||||
let token = parts
|
||||
.headers
|
||||
|
|
@ -47,8 +41,10 @@ where
|
|||
})
|
||||
.ok_or_else(|| AppError::Unauthorized("Missing or invalid token".to_string()))?;
|
||||
|
||||
let secret = state.secret("JWT_SECRET")?;
|
||||
|
||||
// Decode and validate the token
|
||||
let decoding_key = DecodingKey::from_secret(JWT_SECRET.as_ref());
|
||||
let decoding_key = DecodingKey::from_secret(secret.to_string().as_ref());
|
||||
let token_data = decode::<Claims>(&token, &decoding_key, &Validation::default())
|
||||
.map_err(|_| AppError::Unauthorized("Invalid token".to_string()))?;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ pub async fn prelogin(
|
|||
.ok_or_else(|| AppError::BadRequest("Missing email".to_string()))?;
|
||||
let db = db::get_db(&env)?;
|
||||
|
||||
log::info!("Getting kdf for user {email:?}");
|
||||
let stmt = db.prepare("SELECT kdf_iterations FROM users WHERE email = ?1");
|
||||
let query = stmt.bind(&[email.into()])?;
|
||||
let kdf_iterations: Option<i32> = query
|
||||
|
|
@ -29,7 +28,6 @@ pub async fn prelogin(
|
|||
.await
|
||||
.map_err(|_| AppError::Database)?;
|
||||
|
||||
log::info!("Returning {kdf_iterations:?}");
|
||||
Ok(Json(PreloginResponse {
|
||||
kdf: 0, // PBKDF2
|
||||
kdf_iterations: kdf_iterations.unwrap_or(600_000),
|
||||
|
|
@ -41,9 +39,20 @@ pub async fn register(
|
|||
State(env): State<Arc<Env>>,
|
||||
Json(payload): Json<RegisterRequest>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
log::info!("Get db");
|
||||
let allowed_emails = env
|
||||
.secret("ALLOWED_EMAILS")
|
||||
.map_err(|_| AppError::Internal)?;
|
||||
let allowed_emails = allowed_emails
|
||||
.as_ref()
|
||||
.as_string()
|
||||
.ok_or_else(|| AppError::Internal)?;
|
||||
if allowed_emails
|
||||
.split(",")
|
||||
.all(|email| email.trim() != payload.email)
|
||||
{
|
||||
return Err(AppError::Unauthorized("Not allowed to signup".to_string()));
|
||||
}
|
||||
let db = db::get_db(&env)?;
|
||||
log::info!("db got");
|
||||
let now = Utc::now().to_rfc3339();
|
||||
let user = User {
|
||||
id: Uuid::new_v4().to_string(),
|
||||
|
|
@ -62,7 +71,6 @@ pub async fn register(
|
|||
updated_at: now,
|
||||
};
|
||||
|
||||
log::info!("User {user:?}");
|
||||
let query = query!(
|
||||
&db,
|
||||
"INSERT INTO users (id, name, email, master_password_hash, key, private_key, public_key, kdf_iterations, security_stamp, created_at, updated_at)
|
||||
|
|
@ -79,13 +87,11 @@ pub async fn register(
|
|||
user.created_at,
|
||||
user.updated_at
|
||||
).map_err(|error|{
|
||||
log::error!("failed {error:?}");
|
||||
AppError::Database
|
||||
})?
|
||||
.run()
|
||||
.await
|
||||
.map_err(|error|{
|
||||
log::error!("failed {error:?}");
|
||||
AppError::Database
|
||||
})?;
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ pub async fn token(
|
|||
State(env): State<Arc<Env>>,
|
||||
Form(payload): Form<TokenRequest>,
|
||||
) -> Result<Json<TokenResponse>, AppError> {
|
||||
log::info!("Token payload {payload:?}");
|
||||
if payload.grant_type != "password" {
|
||||
return Err(AppError::BadRequest("Unsupported grant_type".to_string()));
|
||||
}
|
||||
|
|
@ -64,7 +63,6 @@ pub async fn token(
|
|||
|
||||
let db = db::get_db(&env)?;
|
||||
|
||||
log::info!("Lookup user");
|
||||
let user: Value = db
|
||||
.prepare("SELECT * FROM users WHERE email = ?1")
|
||||
.bind(&[payload.username.to_lowercase().into()])?
|
||||
|
|
@ -72,17 +70,14 @@ pub async fn token(
|
|||
.await
|
||||
.map_err(|_| AppError::Unauthorized("Invalid credentials".to_string()))?
|
||||
.ok_or_else(|| AppError::Unauthorized("Invalid credentials".to_string()))?;
|
||||
log::info!("User is {user:?}");
|
||||
let user: User = serde_json::from_value(user).map_err(|_| AppError::Internal)?;
|
||||
// Securely compare the provided hash with the stored hash
|
||||
if !constant_time_eq(
|
||||
user.master_password_hash.as_bytes(),
|
||||
password_hash.as_bytes(),
|
||||
) {
|
||||
log::info!("Password is incorrect");
|
||||
return Err(AppError::Unauthorized("Invalid credentials".to_string()));
|
||||
}
|
||||
log::info!("Password matched");
|
||||
|
||||
// Create JWT claims
|
||||
let now = Utc::now();
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ pub async fn get_sync_data(
|
|||
let user_id = claims.sub;
|
||||
let db = db::get_db(&env)?;
|
||||
|
||||
log::info!("Fetch user");
|
||||
// Fetch profile
|
||||
let user: User = db
|
||||
.prepare("SELECT * FROM users WHERE id = ?1")
|
||||
|
|
@ -32,7 +31,6 @@ pub async fn get_sync_data(
|
|||
.await?
|
||||
.ok_or_else(|| AppError::NotFound("User not found".to_string()))?;
|
||||
|
||||
log::info!("Fetch folders");
|
||||
// Fetch folders
|
||||
let folders: Vec<Folder> = db
|
||||
.prepare("SELECT * FROM folders WHERE user_id = ?1")
|
||||
|
|
@ -41,7 +39,6 @@ pub async fn get_sync_data(
|
|||
.await?
|
||||
.results()?;
|
||||
|
||||
log::info!("Fetch ciphers");
|
||||
// Fetch ciphers
|
||||
let ciphers: Vec<Value> = db
|
||||
.prepare("SELECT * FROM ciphers WHERE user_id = ?1")
|
||||
|
|
@ -64,7 +61,6 @@ pub async fn get_sync_data(
|
|||
.map(|cipher| cipher.into())
|
||||
.collect::<Vec<Cipher>>();
|
||||
|
||||
log::info!("Fetch time");
|
||||
let time = chrono::DateTime::parse_from_rfc3339(&user.created_at)
|
||||
.map_err(|_| AppError::Internal)?
|
||||
.to_rfc3339_opts(chrono::SecondsFormat::Micros, true);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use axum::Router;
|
||||
use tower_http::cors::{Any, CorsLayer};
|
||||
use tower_service::Service;
|
||||
use worker::*;
|
||||
|
|
@ -19,7 +18,7 @@ pub async fn main(
|
|||
) -> Result<axum::http::Response<axum::body::Body>> {
|
||||
// Set up logging
|
||||
console_error_panic_hook::set_once();
|
||||
console_log::init_with_level(log::Level::Debug);
|
||||
let _ = console_log::init_with_level(log::Level::Debug);
|
||||
|
||||
// Allow all origins for CORS, which is typical for a public API like Bitwarden's.
|
||||
let cors = CorsLayer::new()
|
||||
|
|
|
|||
|
|
@ -170,7 +170,6 @@ impl Serialize for Cipher {
|
|||
response_map.insert("creationDate".to_string(), json!(self.created_at));
|
||||
response_map.insert("deletedDate".to_string(), json!(self.deleted_at));
|
||||
|
||||
log::debug!("Response data is {:?}", self.data);
|
||||
if let Some(data_obj) = self.data.as_object() {
|
||||
let data_clone = data_obj.clone();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue