1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use bc_components::{PrivateKeyBase, PublicKeyBase, ARID};
use anyhow::Result;

use crate::{known_values, Envelope, Function};

/// Transaction Request Construction
impl Envelope {
    /// Creates an envelope with an `ARID` subject, a `body: «function»`
    /// assertion, and a `'senderPublicKey'` assertion.
    ///
    /// Also adds a `'note'` assertion if `note` is not empty, and a
    /// `'date'` assertion if `date` is not `nil`.
    pub fn into_transaction_request_with_metadata(
        self,
        id: impl AsRef<ARID>,
        sender: impl AsRef<PublicKeyBase>,
        note: impl Into<String>,
        date: Option<dcbor::Date>,
    ) -> Self {
        self.into_request_with_metadata(id, note, date)
            .add_assertion(known_values::SENDER_PUBLIC_KEY, sender.as_ref().clone())
    }

    /// Creates an envelope with an `ARID` subject, a `body: «function»`
    /// assertion, and a `'senderPublicKey'` assertion, then wraps and signs
    /// the envelope with the sender's private key.
    ///
    /// Also adds a `'note'` assertion if `note` is not empty, and a
    /// `'date'` assertion if `date` is not `nil`.
    pub fn into_signed_transaction_request_with_metadata(
        self,
        id: impl AsRef<ARID>,
        sender: &PrivateKeyBase,
        note: impl Into<String>,
        date: Option<dcbor::Date>,
    ) -> Self {
        self.into_transaction_request_with_metadata(id, sender.public_key(), note, date)
            .sign(sender)
    }

    /// Creates an envelope with an `ARID` subject, a `body: «function»`
    /// assertion, and a `'senderPublicKey'` assertion, then wraps and signs the
    /// envelope with the sender's private key, and finally wraps and encrypts
    /// the envelope with the recipient's public key.
    ///
    /// Also adds a `'note'` assertion if `note` is not empty, and a
    /// `'date'` assertion if `date` is not `nil`.
    pub fn into_sealed_transaction_request_with_metadata(
        self,
        id: impl AsRef<ARID>,
        sender: &PrivateKeyBase,
        recipient: &PublicKeyBase,
        note: impl Into<String>,
        date: Option<dcbor::Date>,
    ) -> Result<Envelope> {
        self.into_transaction_request_with_metadata(id, sender.public_key(), note, date)
            .seal(sender, recipient)
    }

    /// Creates an envelope with an `ARID` subject, a `body: «function»`, and a
    /// `'senderPublicKey'` assertion.
    pub fn into_transaction_request(
        self,
        id: impl AsRef<ARID>,
        sender: impl AsRef<PublicKeyBase>,
    ) -> Self {
        self.into_transaction_request_with_metadata(id, sender, "", None)
    }

    /// Creates an envelope with an `ARID` subject, a `body: «function»`, and a
    /// `'senderPublicKey'` assertion, then wraps and signs the envelope with the
    /// sender's private key.
    pub fn into_signed_transaction_request(
        self,
        id: impl AsRef<ARID>,
        sender: &PrivateKeyBase,
    ) -> Self {
        self.into_signed_transaction_request_with_metadata(id, sender, "", None)
    }

    /// Creates an envelope with an `ARID` subject, a `body: «function»`, and a
    /// `'senderPublicKey'` assertion, then wraps and signs the envelope with the
    /// sender's private key, and finally wraps and encrypts the envelope with the
    /// recipient's public key.
    pub fn into_sealed_transaction_request(
        self,
        id: impl AsRef<ARID>,
        sender: &PrivateKeyBase,
        recipient: &PublicKeyBase,
    ) -> Result<Envelope> {
        self.into_sealed_transaction_request_with_metadata(id, sender, recipient, "", None)
    }
}

/// Transaction Request Parsing
impl Envelope {
    /// Parses the transaction request envelope and returns the id, sender,
    /// body, note, and date.
    pub fn parse_transaction_request_with_metadata(&self, expected_function: Option<&Function>) -> Result<(ARID, PublicKeyBase, Envelope, Function, String, Option<dcbor::Date>)> {
        let (id, body, function, note, date) = self.parse_request_with_metadata(expected_function)?;
        let sender: PublicKeyBase = self.extract_object_for_predicate(known_values::SENDER_PUBLIC_KEY)?;
        Ok((id, sender, body, function, note, date))
    }

    /// Parses the signed transaction request envelope and verifies the
    /// signature from the sender, then returns the id, sender, body, note, and
    /// date.
    pub fn parse_signed_transaction_request_with_metadata(&self, expected_function: Option<&Function>) -> Result<(ARID, PublicKeyBase, Envelope, Function, String, Option<dcbor::Date>)> {
        let inner = self.unwrap_envelope()?;
        let (id, sender, body, function, note, date) = inner.parse_transaction_request_with_metadata(expected_function)?;
        self.verify_signature_from(&sender)?;
        Ok((id, sender, body, function, note, date))
    }

    /// Decrypts the sealed transaction request envelope to the recipient,
    /// verifies the signature from the sender, and returns the id, sender,
    /// body, note, and date.
    pub fn parse_sealed_transaction_request_with_metadata(&self, expected_function: Option<&Function>, recipient: &PrivateKeyBase) -> Result<(ARID, PublicKeyBase, Envelope, Function, String, Option<dcbor::Date>)> {
        let signed = self.decrypt(recipient)?;
        let (id, sender, body, function, note, date) = signed.parse_transaction_request_with_metadata(expected_function)?;
        Ok((id, sender, body, function, note, date))
    }

    /// Parses the transaction request envelope and returns the id, sender, and
    /// body.
    pub fn parse_transaction_request(&self, expected_function: Option<&Function>) -> Result<(ARID, PublicKeyBase, Envelope, Function)> {
        let (id, body, function) = self.from_request(expected_function)?;
        let sender: PublicKeyBase = self.extract_object_for_predicate(known_values::SENDER_PUBLIC_KEY)?;
        Ok((id, sender, body, function))
    }

    /// Parses the signed transaction request envelope and verifies the
    /// signature from the sender, then returns the id, sender, and body.
    pub fn parse_signed_transaction_request(&self, expected_function: Option<&Function>) -> Result<(ARID, PublicKeyBase, Envelope, Function)> {
        let inner = self.unwrap_envelope()?;
        let (id, sender, body, function) = inner.parse_transaction_request(expected_function)?;
        self.verify_signature_from(&sender)?;
        Ok((id, sender, body, function))
    }

    /// Decrypts the sealed transaction request envelope to the recipient,
    /// verifies the signature from the sender, and returns the id, sender, and
    /// body.
    pub fn parse_sealed_transaction_request(&self, expected_function: Option<&Function>, recipient: &PrivateKeyBase) -> Result<(ARID, PublicKeyBase, Envelope, Function)> {
        let signed = self.decrypt(recipient)?;
        let (id, sender, body, function) = signed.parse_signed_transaction_request(expected_function)?;
        Ok((id, sender, body, function))
    }
}