//! User resolution handlers — username <-> identity key lookups, //! key revocation, and KT audit. use std::sync::Arc; use bytes::Bytes; use prost::Message; use quicproquo_proto::qpq::v1; use quicproquo_rpc::method::{HandlerResult, RequestContext}; use crate::domain::types::{ AuditKeyTransparencyReq, CheckRevocationReq, ResolveIdentityReq, ResolveUserReq, RevokeKeyReq, }; use crate::domain::users::UserService; use super::{domain_err, require_auth, ServerState}; fn user_svc(state: &Arc) -> UserService { UserService { store: Arc::clone(&state.store), kt_log: Arc::clone(&state.kt_log), revocation_log: Arc::clone(&state.revocation_log), } } pub async fn handle_resolve_user(state: Arc, ctx: RequestContext) -> HandlerResult { let _identity_key = match require_auth(&state, &ctx) { Ok(ik) => ik, Err(e) => return e, }; let req = match v1::ResolveUserRequest::decode(ctx.payload) { Ok(r) => r, Err(e) => { return HandlerResult::err( quicproquo_rpc::error::RpcStatus::BadRequest, &format!("decode: {e}"), ) } }; let svc = user_svc(&state); let domain_req = ResolveUserReq { username: req.username, }; match svc.resolve_user(domain_req) { Ok(resp) => { let proto = v1::ResolveUserResponse { identity_key: resp.identity_key, inclusion_proof: resp.inclusion_proof, }; HandlerResult::ok(Bytes::from(proto.encode_to_vec())) } Err(e) => domain_err(e), } } pub async fn handle_resolve_identity( state: Arc, ctx: RequestContext, ) -> HandlerResult { let _identity_key = match require_auth(&state, &ctx) { Ok(ik) => ik, Err(e) => return e, }; let req = match v1::ResolveIdentityRequest::decode(ctx.payload) { Ok(r) => r, Err(e) => { return HandlerResult::err( quicproquo_rpc::error::RpcStatus::BadRequest, &format!("decode: {e}"), ) } }; let svc = user_svc(&state); let domain_req = ResolveIdentityReq { identity_key: req.identity_key, }; match svc.resolve_identity(domain_req) { Ok(resp) => { let proto = v1::ResolveIdentityResponse { username: resp.username, }; HandlerResult::ok(Bytes::from(proto.encode_to_vec())) } Err(e) => domain_err(e), } } pub async fn handle_revoke_key(state: Arc, ctx: RequestContext) -> HandlerResult { let _identity_key = match require_auth(&state, &ctx) { Ok(ik) => ik, Err(e) => return e, }; let req = match v1::RevokeKeyRequest::decode(ctx.payload) { Ok(r) => r, Err(e) => { return HandlerResult::err( quicproquo_rpc::error::RpcStatus::BadRequest, &format!("decode: {e}"), ) } }; let svc = user_svc(&state); let domain_req = RevokeKeyReq { identity_key: req.identity_key, reason: req.reason, }; match svc.revoke_key(domain_req) { Ok(resp) => { let proto = v1::RevokeKeyResponse { success: resp.success, leaf_index: resp.leaf_index, }; HandlerResult::ok(Bytes::from(proto.encode_to_vec())) } Err(e) => domain_err(e), } } pub async fn handle_check_revocation( state: Arc, ctx: RequestContext, ) -> HandlerResult { let _identity_key = match require_auth(&state, &ctx) { Ok(ik) => ik, Err(e) => return e, }; let req = match v1::CheckRevocationRequest::decode(ctx.payload) { Ok(r) => r, Err(e) => { return HandlerResult::err( quicproquo_rpc::error::RpcStatus::BadRequest, &format!("decode: {e}"), ) } }; let svc = user_svc(&state); let domain_req = CheckRevocationReq { identity_key: req.identity_key, }; match svc.check_revocation(domain_req) { Ok(resp) => { let proto = v1::CheckRevocationResponse { revoked: resp.revoked, reason: resp.reason, timestamp_ms: resp.timestamp_ms, }; HandlerResult::ok(Bytes::from(proto.encode_to_vec())) } Err(e) => domain_err(e), } } pub async fn handle_audit_key_transparency( state: Arc, ctx: RequestContext, ) -> HandlerResult { let _identity_key = match require_auth(&state, &ctx) { Ok(ik) => ik, Err(e) => return e, }; let req = match v1::AuditKeyTransparencyRequest::decode(ctx.payload) { Ok(r) => r, Err(e) => { return HandlerResult::err( quicproquo_rpc::error::RpcStatus::BadRequest, &format!("decode: {e}"), ) } }; let svc = user_svc(&state); let domain_req = AuditKeyTransparencyReq { start: req.start, end: req.end, }; match svc.audit_key_transparency(domain_req) { Ok(resp) => { let proto = v1::AuditKeyTransparencyResponse { entries: resp .entries .into_iter() .map(|e| v1::LogEntry { index: e.index, leaf_hash: e.leaf_hash, }) .collect(), tree_size: resp.tree_size, root: resp.root, }; HandlerResult::ok(Bytes::from(proto.encode_to_vec())) } Err(e) => domain_err(e), } }