dubp_documents/revocation/
v10.rs

1//  Copyright (C) 2020  Éloïs SANCHEZ.
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Affero General Public License as
5// published by the Free Software Foundation, either version 3 of the
6// License, or (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU Affero General Public License for more details.
12//
13// You should have received a copy of the GNU Affero General Public License
14// along with this program.  If not, see <https://www.gnu.org/licenses/>.
15
16//! Wrappers around Revocation documents V//  Copyright (C) 2020  Éloïs SANCHEZ.
17//
18// This program is free software: you can redistribute it and/or modify
19// it under the terms of the GNU Affero General Public License as
20// published by the Free Software Foundation, either version 3 of the
21// License, or (at your option) any later version.
22//
23// This program is distributed in the hope that it will be useful,
24// but WITHOUT ANY WARRANTY; without even the implied warranty of
25// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26// GNU Affero General Public License for more details.
27//
28// You should have received a copy of the GNU Affero General Public License
29// along with this program.  If not, see <https://www.gnu.org/licenses/>.
30
31//! Wrappers around Revocation documents V10.
32
33use crate::*;
34
35#[derive(Debug, Copy, Clone, Deserialize, Serialize, PartialEq, Eq)]
36/// Wrap an Compact Revocation document (in block content)
37pub struct CompactRevocationDocumentV10 {
38    /// Issuer
39    pub issuer: ed25519::PublicKey,
40    /// Signature
41    pub signature: ed25519::Signature,
42}
43
44impl CompactTextDocument for CompactRevocationDocumentV10 {
45    fn as_compact_text(&self) -> String {
46        format!(
47            "{issuer}:{signature}",
48            issuer = self.issuer,
49            signature = self.signature,
50        )
51    }
52}
53
54#[derive(Clone, Debug, Deserialize, Hash, Serialize, PartialEq, Eq)]
55/// Revocation document for jsonification
56pub struct CompactRevocationDocumentV10Stringified {
57    /// Document issuer
58    pub issuer: String,
59    /// Document signature
60    pub signature: String,
61}
62
63impl ToStringObject for CompactRevocationDocumentV10 {
64    type StringObject = CompactRevocationDocumentV10Stringified;
65    /// Transforms an object into a json object
66    fn to_string_object(&self) -> CompactRevocationDocumentV10Stringified {
67        CompactRevocationDocumentV10Stringified {
68            issuer: format!("{}", self.issuer),
69            signature: format!("{}", self.signature),
70        }
71    }
72}
73
74/// Wrap an Revocation document.
75///
76/// Must be created by parsing a text document or using a builder.
77#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
78pub struct RevocationDocumentV10 {
79    /// Document as text.
80    ///
81    /// Is used to check signatures, and other values mut be extracted from it.
82    text: String,
83
84    /// Name of the currency.
85    currency: String,
86    /// Document issuer.
87    issuer: ed25519::PublicKey,
88    /// Username of target identity.
89    identity_username: String,
90    /// Target Identity document blockstamp.
91    identity_blockstamp: Blockstamp,
92    /// Target Identity document signature.
93    identity_sig: ed25519::Signature,
94    /// Document signature.
95    signature: ed25519::Signature,
96}
97
98#[derive(Clone, Debug, Deserialize, Hash, Serialize, PartialEq, Eq)]
99/// Revocation document for jsonification
100pub struct RevocationDocumentV10Stringified {
101    /// Name of the currency.
102    currency: String,
103    /// Document issuer
104    issuer: String,
105    /// Username of target identity
106    identity_username: String,
107    /// Target Identity document blockstamp.
108    identity_blockstamp: String,
109    /// Target Identity document signature.
110    identity_sig: String,
111    /// Document signature
112    signature: String,
113}
114
115impl ToStringObject for RevocationDocumentV10 {
116    type StringObject = RevocationDocumentV10Stringified;
117    /// Transforms an object into a json object
118    fn to_string_object(&self) -> RevocationDocumentV10Stringified {
119        RevocationDocumentV10Stringified {
120            currency: self.currency.clone(),
121            issuer: self.issuer.to_base58(),
122            identity_username: self.identity_username.clone(),
123            identity_blockstamp: format!("{}", self.identity_blockstamp),
124            identity_sig: format!("{}", self.identity_sig),
125            signature: self.signature.to_base64(),
126        }
127    }
128}
129
130impl RevocationDocumentV10 {
131    /// Username of target identity
132    pub fn identity_username(&self) -> &str {
133        &self.identity_username
134    }
135}
136
137impl Document for RevocationDocumentV10 {
138    type PublicKey = ed25519::PublicKey;
139
140    fn version(&self) -> usize {
141        10
142    }
143
144    fn currency(&self) -> &str {
145        &self.currency
146    }
147
148    fn blockstamp(&self) -> Blockstamp {
149        unimplemented!()
150    }
151
152    fn issuers(&self) -> SmallVec<[Self::PublicKey; 1]> {
153        svec![self.issuer]
154    }
155
156    fn signatures(&self) -> SmallVec<[<Self::PublicKey as PublicKey>::Signature; 1]> {
157        svec![self.signature]
158    }
159
160    fn as_bytes(&self) -> BeefCow<[u8]> {
161        BeefCow::borrowed(self.as_text().as_bytes())
162    }
163}
164
165impl TextDocument for RevocationDocumentV10 {
166    type CompactTextDocument_ = CompactRevocationDocumentV10;
167
168    fn as_text(&self) -> &str {
169        &self.text
170    }
171
172    fn to_compact_document(&self) -> Cow<Self::CompactTextDocument_> {
173        Cow::Owned(CompactRevocationDocumentV10 {
174            issuer: self.issuer,
175            signature: self.signature,
176        })
177    }
178}
179
180/// Revocation document builder.
181#[derive(Debug, Copy, Clone)]
182pub struct RevocationDocumentV10Builder<'a> {
183    /// Document currency.
184    pub currency: &'a str,
185    /// Revocation issuer.
186    pub issuer: ed25519::PublicKey,
187    /// Username of target Identity.
188    pub identity_username: &'a str,
189    /// Blockstamp of target Identity.
190    pub identity_blockstamp: Blockstamp,
191    /// Signature of target Identity.
192    pub identity_sig: ed25519::Signature,
193}
194
195impl<'a> TextDocumentBuilder for RevocationDocumentV10Builder<'a> {
196    type Document = RevocationDocumentV10;
197    type Signator = ed25519::Signator;
198
199    fn build_with_text_and_sigs(
200        self,
201        text: String,
202        signatures: SmallVec<
203            [<<Self::Document as Document>::PublicKey as PublicKey>::Signature; 1],
204        >,
205    ) -> RevocationDocumentV10 {
206        RevocationDocumentV10 {
207            text,
208            currency: self.currency.to_string(),
209            issuer: self.issuer,
210            identity_username: self.identity_username.to_string(),
211            identity_blockstamp: self.identity_blockstamp,
212            identity_sig: self.identity_sig,
213            signature: signatures[0],
214        }
215    }
216
217    fn generate_text(&self) -> String {
218        format!(
219            "Version: 10
220Type: Revocation
221Currency: {currency}
222Issuer: {issuer}
223IdtyUniqueID: {idty_uid}
224IdtyTimestamp: {idty_blockstamp}
225IdtySignature: {idty_sig}
226",
227            currency = self.currency,
228            issuer = self.issuer,
229            idty_uid = self.identity_username,
230            idty_blockstamp = self.identity_blockstamp,
231            idty_sig = self.identity_sig,
232        )
233    }
234}
235
236#[cfg(test)]
237mod tests {
238    use super::*;
239    use smallvec::smallvec;
240    use std::str::FromStr;
241    use unwrap::unwrap;
242
243    #[test]
244    fn generate_real_document() {
245        let keypair = ed25519::KeyPairFromSeed32Generator::generate(unwrap!(
246            Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"),
247            "fail to build Seed32"
248        ));
249        let pubkey = keypair.public_key();
250        let signator = keypair.generate_signator();
251
252        let sig = unwrap!(ed25519::Signature::from_base64(
253            "gBD2mCr7E/tW8u3wqVK7IWtQB6IKxddg13UMl9ypVsv/VhqhAFTBba9BwoK5t6H9eqF1d+4sCB3WY2eJ/yuUAg==",
254        ), "Fail to build Signature");
255
256        let identity_blockstamp = unwrap!(
257            Blockstamp::from_str(
258                "0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
259            ),
260            "Fail to build Blockstamp"
261        );
262
263        let identity_sig = unwrap!(ed25519::Signature::from_base64(
264            "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
265        ), "Fail to build Signature");
266
267        let builder = RevocationDocumentV10Builder {
268            currency: "g1",
269            issuer: pubkey,
270            identity_username: "tic",
271            identity_blockstamp,
272            identity_sig,
273        };
274
275        println!(
276            "Signatures = {:?}",
277            builder
278                .build_and_sign(vec![keypair.generate_signator()])
279                .signatures()
280        );
281
282        assert!(builder
283            .build_with_signature(smallvec![sig])
284            .verify_signatures()
285            .is_ok());
286
287        assert!(builder
288            .build_and_sign(vec![signator])
289            .verify_signatures()
290            .is_ok());
291    }
292}