httpd: Refactor auth and session handling
Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
This commit is contained in:
parent
3d0a68eeb5
commit
58eeb3ab91
|
|
@ -33,7 +33,7 @@ type SessionId = String;
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
profile: Arc<Profile>,
|
profile: Arc<Profile>,
|
||||||
sessions: Arc<RwLock<HashMap<SessionId, auth::AuthState>>>,
|
sessions: Arc<RwLock<HashMap<SessionId, auth::Session>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
|
|
|
||||||
|
|
@ -11,25 +11,17 @@ impl Serialize for DateTime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Serialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum AuthState {
|
pub enum AuthState {
|
||||||
Authorized(Session),
|
Authorized,
|
||||||
Unauthorized(Session),
|
Unauthorized,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
pub status: String,
|
pub status: AuthState,
|
||||||
pub public_key: PublicKey,
|
pub public_key: PublicKey,
|
||||||
pub issued_at: DateTime,
|
pub issued_at: DateTime,
|
||||||
pub expires_at: DateTime,
|
pub expires_at: DateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<AuthState> for Session {
|
|
||||||
fn from(other: AuthState) -> Self {
|
|
||||||
match other {
|
|
||||||
AuthState::Authorized(s) => s,
|
|
||||||
AuthState::Unauthorized(s) => s,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use std::convert::Into;
|
|
||||||
use std::iter::repeat_with;
|
use std::iter::repeat_with;
|
||||||
|
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
|
|
@ -46,17 +45,20 @@ async fn session_create_handler(State(ctx): State<Context>) -> impl IntoResponse
|
||||||
.checked_add(UNAUTHORIZED_SESSIONS_EXPIRATION)
|
.checked_add(UNAUTHORIZED_SESSIONS_EXPIRATION)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let session = Session {
|
let session = Session {
|
||||||
status: String::from("unauthorized"),
|
status: AuthState::Unauthorized,
|
||||||
public_key: *signer.public_key(),
|
public_key: *signer.public_key(),
|
||||||
issued_at: DateTime(OffsetDateTime::now_utc()),
|
issued_at: DateTime(OffsetDateTime::now_utc()),
|
||||||
expires_at: DateTime(expiration_time),
|
expires_at: DateTime(expiration_time),
|
||||||
};
|
};
|
||||||
let mut sessions = ctx.sessions.write().await;
|
let mut sessions = ctx.sessions.write().await;
|
||||||
sessions.insert(session_id.clone(), AuthState::Unauthorized(session));
|
sessions.insert(session_id.clone(), session.clone());
|
||||||
|
|
||||||
Ok::<_, Error>(Json(
|
Ok::<_, Error>(Json(json!({
|
||||||
json!({"sessionId": session_id, "publicKey": signer.public_key()}),
|
"sessionId": session_id,
|
||||||
))
|
"publicKey": session.public_key,
|
||||||
|
"issuedAt": session.issued_at,
|
||||||
|
"expiresAt": session.expires_at
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a session.
|
/// Get a session.
|
||||||
|
|
@ -66,12 +68,14 @@ async fn session_handler(
|
||||||
Path(session_id): Path<String>,
|
Path(session_id): Path<String>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let sessions = ctx.sessions.read().await;
|
let sessions = ctx.sessions.read().await;
|
||||||
let auth_state = sessions.get(&session_id).ok_or(Error::NotFound)?;
|
let session = sessions.get(&session_id).ok_or(Error::NotFound)?;
|
||||||
let session = Session::from(auth_state.clone());
|
|
||||||
|
|
||||||
Ok::<_, Error>(Json(
|
Ok::<_, Error>(Json(json!({
|
||||||
json!({"publicKey": session.public_key, "issuedAt": session.issued_at, "expiresAt": session.expires_at}),
|
"status": session.status,
|
||||||
))
|
"publicKey": session.public_key,
|
||||||
|
"issuedAt": session.issued_at,
|
||||||
|
"expiresAt": session.expires_at
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update session.
|
/// Update session.
|
||||||
|
|
@ -83,11 +87,11 @@ async fn session_signin_handler(
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let mut sessions = ctx.sessions.write().await;
|
let mut sessions = ctx.sessions.write().await;
|
||||||
let session = sessions.get(&session_id).ok_or(Error::NotFound)?;
|
let session = sessions.get(&session_id).ok_or(Error::NotFound)?;
|
||||||
if let AuthState::Unauthorized(s) = session {
|
if session.status == AuthState::Unauthorized {
|
||||||
if s.public_key != request.pk {
|
if session.public_key != request.pk {
|
||||||
return Err(Error::Auth("Invalid public key"));
|
return Err(Error::Auth("Invalid public key"));
|
||||||
}
|
}
|
||||||
if s.expires_at <= DateTime(OffsetDateTime::now_utc()) {
|
if session.expires_at <= DateTime(OffsetDateTime::now_utc()) {
|
||||||
return Err(Error::Auth("Session expired"));
|
return Err(Error::Auth("Session expired"));
|
||||||
}
|
}
|
||||||
let payload = format!("{}:{}", session_id, request.pk);
|
let payload = format!("{}:{}", session_id, request.pk);
|
||||||
|
|
@ -99,14 +103,14 @@ async fn session_signin_handler(
|
||||||
.checked_add(AUTHORIZED_SESSIONS_EXPIRATION)
|
.checked_add(AUTHORIZED_SESSIONS_EXPIRATION)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let session = Session {
|
let session = Session {
|
||||||
status: String::from("authorized"),
|
status: AuthState::Authorized,
|
||||||
public_key: request.pk,
|
public_key: request.pk,
|
||||||
issued_at: DateTime(OffsetDateTime::now_utc()),
|
issued_at: session.issued_at.to_owned(),
|
||||||
expires_at: DateTime(expiration_time),
|
expires_at: DateTime(expiration_time),
|
||||||
};
|
};
|
||||||
sessions.insert(session_id.clone(), AuthState::Authorized(session));
|
sessions.insert(session_id.clone(), session);
|
||||||
|
|
||||||
return Ok::<_, Error>(());
|
return Ok::<_, Error>(Json(json!({ "success": true })));
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(Error::Auth("Session already authorized"))
|
Err(Error::Auth("Session already authorized"))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue