cat_gateway/service/api/documents/common/
mod.rs1use std::collections::HashMap;
5
6use catalyst_signed_doc::CatalystSignedDocument;
7
8use crate::{
9 db::event::{error::NotFoundError, signed_docs::FullSignedDoc},
10 service::common::auth::rbac::token::CatalystRBACTokenV1,
11 settings::Settings,
12};
13
14pub(crate) async fn get_document_cbor_bytes(
16 document_id: &uuid::Uuid,
17 version: Option<&uuid::Uuid>,
18) -> anyhow::Result<Vec<u8>> {
19 let db_doc = FullSignedDoc::retrieve(document_id, version).await?;
21 Ok(db_doc.raw().to_vec())
22}
23
24pub(crate) struct DocProvider;
27
28impl catalyst_signed_doc::providers::CatalystSignedDocumentProvider for DocProvider {
29 async fn try_get_doc(
30 &self,
31 doc_ref: &catalyst_signed_doc::DocumentRef,
32 ) -> anyhow::Result<Option<CatalystSignedDocument>> {
33 let id = doc_ref.id().uuid();
34 let ver = doc_ref.ver().uuid();
35 match get_document_cbor_bytes(&id, Some(&ver)).await {
36 Ok(doc_cbor_bytes) => Ok(Some(doc_cbor_bytes.as_slice().try_into()?)),
37 Err(err) if err.is::<NotFoundError>() => Ok(None),
38 Err(err) => Err(err),
39 }
40 }
41
42 fn future_threshold(&self) -> Option<std::time::Duration> {
43 let signed_doc_cfg = Settings::signed_doc_cfg();
44 Some(signed_doc_cfg.future_threshold())
45 }
46
47 fn past_threshold(&self) -> Option<std::time::Duration> {
48 let signed_doc_cfg = Settings::signed_doc_cfg();
49 Some(signed_doc_cfg.past_threshold())
50 }
51}
52
53impl catalyst_signed_doc_v1::providers::CatalystSignedDocumentProvider for DocProvider {
54 async fn try_get_doc(
55 &self,
56 doc_ref: &catalyst_signed_doc_v1::DocumentRef,
57 ) -> anyhow::Result<Option<catalyst_signed_doc_v1::CatalystSignedDocument>> {
58 let id = doc_ref.id.uuid();
59 let ver = doc_ref.ver.uuid();
60 match get_document_cbor_bytes(&id, Some(&ver)).await {
61 Ok(doc_cbor_bytes) => Ok(Some(doc_cbor_bytes.as_slice().try_into()?)),
62 Err(err) if err.is::<NotFoundError>() => Ok(None),
63 Err(err) => Err(err),
64 }
65 }
66
67 fn future_threshold(&self) -> Option<std::time::Duration> {
68 <Self as catalyst_signed_doc::providers::CatalystSignedDocumentProvider>::future_threshold(
69 self,
70 )
71 }
72
73 fn past_threshold(&self) -> Option<std::time::Duration> {
74 <Self as catalyst_signed_doc::providers::CatalystSignedDocumentProvider>::past_threshold(
75 self,
76 )
77 }
78}
79
80pub(crate) struct VerifyingKeyProvider(
84 HashMap<catalyst_signed_doc::CatalystId, ed25519_dalek::VerifyingKey>,
85);
86
87impl catalyst_signed_doc::providers::VerifyingKeyProvider for VerifyingKeyProvider {
88 async fn try_get_key(
89 &self,
90 kid: &catalyst_signed_doc::CatalystId,
91 ) -> anyhow::Result<Option<ed25519_dalek::VerifyingKey>> {
92 Ok(self.0.get(kid).copied())
93 }
94}
95
96impl VerifyingKeyProvider {
97 pub(crate) async fn try_from_kids(
122 token: &mut CatalystRBACTokenV1,
123 kids: &[catalyst_signed_doc::CatalystId],
124 ) -> anyhow::Result<Self> {
125 if kids.len() > 1 {
126 anyhow::bail!("Multi-signature document is currently unsupported");
127 }
128
129 if kids
130 .iter()
131 .any(|kid| kid.as_short_id() != token.catalyst_id().as_short_id())
132 {
133 anyhow::bail!("RBAC Token CatID does not match with the document KIDs");
134 }
135
136 let Some(reg_chain) = token.reg_chain().await? else {
137 anyhow::bail!("Failed to retrieve a registration from corresponding Catalyst ID");
138 };
139
140 let result = kids.iter().map(|kid| {
141 if !kid.is_signature_key() {
142 anyhow::bail!("Invalid KID {kid}: KID must be a signing key not an encryption key");
143 }
144
145 let (kid_role_index, kid_rotation) = kid.role_and_rotation();
146 let (latest_pk, rotation) = reg_chain
147 .get_latest_signing_pk_for_role(&kid_role_index)
148 .ok_or_else(|| {
149 anyhow::anyhow!(
150 "Failed to get last signing key for the proposer role for {kid} Catalyst ID"
151 )
152 })?;
153
154 if rotation != kid_rotation {
155 anyhow::bail!("Invalid KID {kid}: KID's rotation ({kid_rotation}) is not the latest rotation ({rotation})");
156 }
157
158 Ok((kid.clone(), latest_pk))
159 })
160 .collect::<Result<_, _>>()?;
161
162 Ok(Self(result))
163 }
164}