known devices, finish migration?

This commit is contained in:
lda committed 2026-04-26 16:32:40 +07:00 Verified
1 parent 65a0891308
commit 7129d587cc
7 files changed
+927 -183

No files matched your search

+175 -1
View File
@@ -7,7 +7,7 @@ use tracing::{info, warn};
use crate::api::json_error;
use crate::runtime::{AppState, SessionEvent};
use crate::state::AuditEventInput;
use crate::state::{AuditEventInput, DeviceIdentifierInput, KnownDeviceInput};
#[derive(Debug, Deserialize)]
pub struct EnrollRequest {
@@ -72,6 +72,48 @@ pub struct StateStatsResponse {
pub expired_enroll_token_count: usize,
}
#[derive(Debug, Deserialize)]
pub struct CreateKnownDeviceRequest {
pub display_name: String,
#[serde(default)]
pub pinned: bool,
pub notes: Option<String>,
#[serde(default)]
pub identifiers: Vec<DeviceIdentifierRequest>,
}
#[derive(Debug, Deserialize)]
pub struct DeviceIdentifierRequest {
pub kind: String,
pub value: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct KnownDeviceResponse {
pub device_id: String,
pub display_name: String,
pub pinned: bool,
pub created_at_unix: u64,
pub updated_at_unix: u64,
pub notes: Option<String>,
pub identifiers: Vec<DeviceIdentifierResponse>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DeviceIdentifierResponse {
pub identifier_key: String,
pub device_id: String,
pub kind: String,
pub value: String,
pub created_at_unix: u64,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ForgetKnownDeviceResponse {
pub device_id: String,
pub forgotten: bool,
}
pub async fn healthz() -> &'static str {
"ok"
}
@@ -407,6 +449,116 @@ pub async fn set_agent_nickname(
}
}
pub async fn create_known_device(
State(state): State<AppState>,
Json(req): Json<CreateKnownDeviceRequest>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
let input = KnownDeviceInput {
display_name: req.display_name,
pinned: req.pinned,
notes: req.notes,
identifiers: req
.identifiers
.into_iter()
.map(|identifier| DeviceIdentifierInput {
kind: identifier.kind,
value: identifier.value,
})
.collect(),
};
match state.store.create_known_device(input).await {
Ok(device) => Ok((StatusCode::CREATED, Json(known_device_response(device)))),
Err(err) => {
warn!(error = %err, "failed to create known device");
Err(json_error(
StatusCode::BAD_REQUEST,
"create_known_device_failed",
&err.to_string(),
))
}
}
}
pub async fn list_known_devices(
State(state): State<AppState>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
match state.store.list_known_devices().await {
Ok(devices) => Ok((
StatusCode::OK,
Json(
devices
.into_iter()
.map(known_device_response)
.collect::<Vec<_>>(),
),
)),
Err(err) => {
warn!(error = %err, "failed to list known devices");
Err(json_error(
StatusCode::INTERNAL_SERVER_ERROR,
"list_known_devices_failed",
&err.to_string(),
))
}
}
}
pub async fn forget_known_device(
State(state): State<AppState>,
AxumPath(device_id): AxumPath<String>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
match state.store.forget_known_device(&device_id).await {
Ok(forgotten) => Ok((
StatusCode::OK,
Json(ForgetKnownDeviceResponse {
device_id,
forgotten,
}),
)),
Err(err) => {
warn!(error = %err, "failed to forget known device");
Err(json_error(
StatusCode::INTERNAL_SERVER_ERROR,
"forget_known_device_failed",
&err.to_string(),
))
}
}
}
pub async fn attach_device_identifier(
State(state): State<AppState>,
AxumPath(device_id): AxumPath<String>,
Json(req): Json<DeviceIdentifierRequest>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
let input = DeviceIdentifierInput {
kind: req.kind,
value: req.value,
};
match state
.store
.attach_device_identifier(&device_id, input)
.await
{
Ok(Some(device)) => Ok((StatusCode::OK, Json(known_device_response(device)))),
Ok(None) => Err(json_error(
StatusCode::NOT_FOUND,
"known_device_not_found",
"known device not found",
)),
Err(err) => {
warn!(error = %err, "failed to attach device identifier");
Err(json_error(
StatusCode::BAD_REQUEST,
"attach_device_identifier_failed",
&err.to_string(),
))
}
}
}
pub async fn state_stats(
State(state): State<AppState>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
@@ -431,3 +583,25 @@ pub async fn state_stats(
}
}
}
fn known_device_response(device: crate::state::KnownDevice) -> KnownDeviceResponse {
KnownDeviceResponse {
device_id: device.device_id,
display_name: device.display_name,
pinned: device.pinned,
created_at_unix: device.created_at_unix,
updated_at_unix: device.updated_at_unix,
notes: device.notes,
identifiers: device
.identifiers
.into_iter()
.map(|identifier| DeviceIdentifierResponse {
identifier_key: identifier.identifier_key,
device_id: identifier.device_id,
kind: identifier.kind,
value: identifier.value,
created_at_unix: identifier.created_at_unix,
})
.collect(),
}
}