biscuit_auth/token/
third_party.rs

1use ed25519_dalek::Signer;
2use prost::Message;
3
4use crate::{
5    builder::BlockBuilder,
6    crypto::PublicKey,
7    datalog::SymbolTable,
8    error,
9    format::{convert::token_block_to_proto_block, schema, SerializedBiscuit},
10    KeyPair, PrivateKey,
11};
12
13/// Third party block request
14#[derive(Debug)]
15pub struct ThirdPartyRequest {
16    pub(crate) previous_key: PublicKey,
17}
18
19impl ThirdPartyRequest {
20    pub(crate) fn from_container(
21        container: &SerializedBiscuit,
22    ) -> Result<ThirdPartyRequest, error::Token> {
23        if container.proof.is_sealed() {
24            return Err(error::Token::AppendOnSealed);
25        }
26
27        let previous_key = container
28            .blocks
29            .last()
30            .unwrap_or(&container.authority)
31            .next_key;
32
33        Ok(ThirdPartyRequest { previous_key })
34    }
35
36    pub fn serialize(&self) -> Result<Vec<u8>, error::Token> {
37        let previous_key = self.previous_key.to_proto();
38
39        let request = schema::ThirdPartyBlockRequest {
40            previous_key,
41            public_keys: Vec::new(),
42        };
43        let mut v = Vec::new();
44
45        request.encode(&mut v).map(|_| v).map_err(|e| {
46            error::Token::Format(error::Format::SerializationError(format!(
47                "serialization error: {:?}",
48                e
49            )))
50        })
51    }
52
53    pub fn serialize_base64(&self) -> Result<String, error::Token> {
54        Ok(base64::encode_config(self.serialize()?, base64::URL_SAFE))
55    }
56
57    pub fn deserialize(slice: &[u8]) -> Result<Self, error::Token> {
58        let data = schema::ThirdPartyBlockRequest::decode(slice).map_err(|e| {
59            error::Format::DeserializationError(format!("deserialization error: {:?}", e))
60        })?;
61
62        let previous_key = PublicKey::from_proto(&data.previous_key)?;
63
64        if !data.public_keys.is_empty() {
65            return Err(error::Token::Format(error::Format::DeserializationError(
66                "public keys were provided in third-party block request".to_owned(),
67            )));
68        }
69
70        Ok(ThirdPartyRequest { previous_key })
71    }
72
73    pub fn deserialize_base64<T>(slice: T) -> Result<Self, error::Token>
74    where
75        T: AsRef<[u8]>,
76    {
77        let decoded = base64::decode_config(slice, base64::URL_SAFE)?;
78        Self::deserialize(&decoded)
79    }
80
81    /// Creates a [`ThirdPartyBlock`] signed with the third party service's [`PrivateKey`]
82    pub fn create_block(
83        self,
84        private_key: &PrivateKey,
85        block_builder: BlockBuilder,
86    ) -> Result<ThirdPartyBlock, error::Token> {
87        let symbols = SymbolTable::new();
88        let mut block = block_builder.build(symbols);
89        block.version = super::MAX_SCHEMA_VERSION;
90
91        let mut v = Vec::new();
92        token_block_to_proto_block(&block)
93            .encode(&mut v)
94            .map_err(|e| {
95                error::Format::SerializationError(format!("serialization error: {:?}", e))
96            })?;
97        let payload = v.clone();
98
99        v.extend(&(crate::format::schema::public_key::Algorithm::Ed25519 as i32).to_le_bytes());
100        v.extend(self.previous_key.to_bytes());
101
102        let keypair = KeyPair::from(private_key);
103        let signature = keypair
104            .kp
105            .try_sign(&v)
106            .map_err(|s| s.to_string())
107            .map_err(error::Signature::InvalidSignatureGeneration)
108            .map_err(error::Format::Signature)?;
109
110        let public_key = keypair.public();
111        let content = schema::ThirdPartyBlockContents {
112            payload,
113            external_signature: schema::ExternalSignature {
114                signature: signature.to_bytes().to_vec(),
115                public_key: public_key.to_proto(),
116            },
117        };
118
119        Ok(ThirdPartyBlock(content))
120    }
121}
122
123/// Signed third party block content
124///
125/// this must be integrated with the token that created the [`ThirdPartyRequest`]
126/// using [`Biscuit::append_third_party`](crate::Biscuit::append_third_party)
127#[derive(Clone, Debug)]
128pub struct ThirdPartyBlock(pub(crate) schema::ThirdPartyBlockContents);
129
130impl ThirdPartyBlock {
131    pub fn serialize(&self) -> Result<Vec<u8>, error::Token> {
132        let mut buffer = vec![];
133        self.0.encode(&mut buffer).map(|_| buffer).map_err(|e| {
134            error::Token::Format(error::Format::SerializationError(format!(
135                "serialization error: {:?}",
136                e
137            )))
138        })
139    }
140
141    pub fn serialize_base64(&self) -> Result<String, error::Token> {
142        Ok(base64::encode_config(self.serialize()?, base64::URL_SAFE))
143    }
144}