ephemeral logins

This commit is contained in:
Aiden McClelland
2024-07-26 12:29:59 -06:00
parent e0b47feb8b
commit a3b94816f9
9 changed files with 87 additions and 29 deletions

View File

@@ -185,6 +185,8 @@ pub struct LoginParams {
#[serde(rename = "__auth_userAgent")] // from Auth middleware
user_agent: Option<String>,
#[serde(default)]
ephemeral: bool,
#[serde(default)]
#[ts(type = "any")]
metadata: Value,
}
@@ -195,28 +197,46 @@ pub async fn login_impl(
LoginParams {
password,
user_agent,
ephemeral,
metadata,
}: LoginParams,
) -> Result<LoginRes, Error> {
let password = password.unwrap_or_default().decrypt(&ctx)?;
ctx.db
.mutate(|db| {
check_password_against_db(db, &password)?;
let hash_token = HashSessionToken::new();
db.as_private_mut().as_sessions_mut().insert(
hash_token.hashed(),
&Session {
if ephemeral {
check_password_against_db(&ctx.db.peek().await, &password)?;
let hash_token = HashSessionToken::new();
ctx.ephemeral_sessions.mutate(|s| {
s.0.insert(
hash_token.hashed().clone(),
Session {
logged_in: Utc::now(),
last_active: Utc::now(),
user_agent,
metadata,
},
)?;
)
});
Ok(hash_token.to_login_res())
} else {
ctx.db
.mutate(|db| {
check_password_against_db(db, &password)?;
let hash_token = HashSessionToken::new();
db.as_private_mut().as_sessions_mut().insert(
hash_token.hashed(),
&Session {
logged_in: Utc::now(),
last_active: Utc::now(),
user_agent,
metadata,
},
)?;
Ok(hash_token.to_login_res())
})
.await
Ok(hash_token.to_login_res())
})
.await
}
}
#[derive(Deserialize, Serialize, Parser, TS)]
@@ -329,9 +349,15 @@ pub async fn list(
ctx: RpcContext,
ListParams { session, .. }: ListParams,
) -> Result<SessionList, Error> {
let mut sessions = ctx.db.peek().await.into_private().into_sessions().de()?;
ctx.ephemeral_sessions.mutate(|s| {
sessions
.0
.extend(s.0.iter().map(|(k, v)| (k.clone(), v.clone())))
});
Ok(SessionList {
current: HashSessionToken::from_token(session).hashed().clone(),
sessions: ctx.db.peek().await.into_private().into_sessions().de()?,
sessions,
})
}

View File

@@ -17,6 +17,7 @@ use tracing::instrument;
use super::setup::CURRENT_SECRET;
use crate::account::AccountInfo;
use crate::auth::Sessions;
use crate::context::config::ServerConfig;
use crate::db::model::Database;
use crate::dependencies::compute_dependency_config_errs;
@@ -34,6 +35,7 @@ use crate::service::ServiceMap;
use crate::shutdown::Shutdown;
use crate::system::get_mem_info;
use crate::util::lshw::{lshw, LshwDevice};
use crate::util::sync::SyncMutex;
pub struct RpcContextSeed {
is_closed: AtomicBool,
@@ -42,6 +44,7 @@ pub struct RpcContextSeed {
pub ethernet_interface: String,
pub datadir: PathBuf,
pub disk_guid: Arc<String>,
pub ephemeral_sessions: SyncMutex<Sessions>,
pub db: TypedPatchDb<Database>,
pub sync_db: watch::Sender<u64>,
pub account: RwLock<AccountInfo>,
@@ -213,6 +216,7 @@ impl RpcContext {
find_eth_iface().await?
},
disk_guid,
ephemeral_sessions: SyncMutex::new(Sessions::new()),
sync_db: watch::Sender::new(db.sequence().await),
db,
account: RwLock::new(account),

View File

@@ -51,6 +51,11 @@ impl HasLoggedOutSessions {
for sid in &to_log_out {
ctx.open_authed_continuations.kill(sid)
}
ctx.ephemeral_sessions.mutate(|s| {
for sid in &to_log_out {
s.0.remove(sid);
}
});
ctx.db
.mutate(|db| {
let sessions = db.as_private_mut().as_sessions_mut();
@@ -110,20 +115,29 @@ impl HasValidSession {
ctx: &RpcContext,
) -> Result<Self, Error> {
let session_hash = session_token.hashed();
ctx.db
.mutate(|db| {
db.as_private_mut()
.as_sessions_mut()
.as_idx_mut(session_hash)
.ok_or_else(|| {
Error::new(eyre!("UNAUTHORIZED"), crate::ErrorKind::Authorization)
})?
.mutate(|s| {
s.last_active = Utc::now();
Ok(())
})
})
.await?;
if !ctx.ephemeral_sessions.mutate(|s| {
if let Some(session) = s.0.get_mut(session_hash) {
session.last_active = Utc::now();
true
} else {
false
}
}) {
ctx.db
.mutate(|db| {
db.as_private_mut()
.as_sessions_mut()
.as_idx_mut(session_hash)
.ok_or_else(|| {
Error::new(eyre!("UNAUTHORIZED"), crate::ErrorKind::Authorization)
})?
.mutate(|s| {
s.last_active = Utc::now();
Ok(())
})
})
.await?;
}
Ok(Self(SessionType::Session(session_token)))
}

View File

@@ -49,6 +49,7 @@ pub mod net;
pub mod rpc;
pub mod rpc_client;
pub mod serde;
pub mod sync;
#[derive(Clone, Copy, Debug, ::serde::Deserialize, ::serde::Serialize)]
pub enum Never {}

View File

@@ -0,0 +1,9 @@
pub struct SyncMutex<T>(std::sync::Mutex<T>);
impl<T> SyncMutex<T> {
pub fn new(t: T) -> Self {
Self(std::sync::Mutex::new(t))
}
pub fn mutate<F: FnOnce(&mut T) -> U, U>(&self, f: F) -> U {
f(&mut *self.0.lock().unwrap())
}
}

View File

@@ -1,4 +1,8 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { PasswordType } from "./PasswordType"
export type LoginParams = { password: PasswordType | null; metadata: any }
export type LoginParams = {
password: PasswordType | null
ephemeral: boolean
metadata: any
}

View File

@@ -40,6 +40,7 @@ export class LoginPage {
await this.api.login({
password: this.password,
metadata: { platforms: getPlatforms() },
ephemeral: window.location.host === 'localhost',
})
this.password = ''

View File

@@ -33,6 +33,7 @@ export module RR {
export type LoginReq = {
password: string
metadata: SessionMetadata
ephemeral?: boolean
} // auth.login - unauthed
export type loginRes = null

View File

@@ -73,8 +73,6 @@ export class ConfigService {
const hostnameInfo =
hosts[ui.addressInfo.hostId]?.hostnameInfo[ui.addressInfo.internalPort]
console.debug(hostnameInfo)
if (!hostnameInfo) return ''
const addressInfo = ui.addressInfo