ssi_status/
lib.rs

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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
use std::time::Duration;

mod r#impl;
use iref::Uri;
pub use r#impl::*;
pub mod client;

/// Encoded [`StatusMap`].
pub trait EncodedStatusMap {
    type Decoded: StatusMap;
    type DecodeError: std::error::Error;

    fn decode(self) -> Result<Self::Decoded, Self::DecodeError>;
}

#[derive(Debug, Default, Clone, Copy)]
pub struct FromBytesOptions {
    /// Allow unsecured claims.
    pub allow_unsecured: bool,
}

impl FromBytesOptions {
    pub const ALLOW_UNSECURED: Self = Self {
        allow_unsecured: true,
    };
}

pub trait FromBytes<V>: Sized {
    type Error: std::error::Error;

    #[allow(async_fn_in_trait)]
    async fn from_bytes_with(
        bytes: &[u8],
        media_type: &str,
        verification_params: &V,
        options: FromBytesOptions,
    ) -> Result<Self, Self::Error>;

    #[allow(async_fn_in_trait)]
    async fn from_bytes(bytes: &[u8], media_type: &str, verifier: &V) -> Result<Self, Self::Error> {
        Self::from_bytes_with(bytes, media_type, verifier, FromBytesOptions::default()).await
    }
}

#[derive(Debug, thiserror::Error)]
pub enum StatusSizeError {
    #[error("missing status size")]
    Missing,

    #[error("invalid status size")]
    Invalid,
}

/// Status map.
///
/// A status map is a map from [`StatusMapEntry`] to [`StatusMap::Status`].
/// The [`StatusMapEntry`] is generally found in the credential or claims you
/// need to verify.
pub trait StatusMap: Clone {
    /// Key indexing each status in the map.
    type Key;

    /// Status bit size type.
    type StatusSize;

    /// Status type.
    type Status;

    /// Maximum duration an implementer is allowed to cache a
    /// status list.
    fn time_to_live(&self) -> Option<Duration> {
        None
    }

    /// Returns a status using the given status size and key.
    ///
    /// If `status_size` is `None`, it is assumed that the map itself knows the
    /// status size. If it does not, a [`StatusSizeError::Missing`] error is
    /// returned.
    fn get_by_key(
        &self,
        status_size: Option<Self::StatusSize>,
        key: Self::Key,
    ) -> Result<Option<Self::Status>, StatusSizeError>;

    /// Returns the status associated to the given entry.
    fn get_entry<E: StatusMapEntry<Key = Self::Key, StatusSize = Self::StatusSize>>(
        &self,
        entry: &E,
    ) -> Result<Option<Self::Status>, StatusSizeError> {
        self.get_by_key(entry.status_size(), entry.key())
    }
}

pub trait StatusMapEntrySet {
    type Entry<'a>: StatusMapEntry
    where
        Self: 'a;

    fn get_entry(&self, purpose: StatusPurpose<&str>) -> Option<Self::Entry<'_>>;
}

/// Status map entry.
///
/// A status map entry is a reference to a particular status in a status map.
/// It links to a status map, providing a key in this map.
pub trait StatusMapEntry {
    /// Key indexing each status in the referenced status list.
    type Key;

    /// Status map status size type.
    type StatusSize;

    /// URL to the status map.
    fn status_list_url(&self) -> &Uri;

    /// Size of each status in the status map, if it is known by the entry.
    ///
    /// For some [`StatusMap`] implementations such as
    /// [`crate::token_status_list::StatusList`] the status size is stored in
    /// the map, while for some other implementations such as
    /// [`crate::bitstring_status_list::StatusList`] the status size is stored
    /// in the entry
    /// ([`crate::bitstring_status_list::BitstringStatusListEntry`]).
    ///
    /// If this function returns `None`, it is assumed that the status size
    /// will be provided by the status map.
    fn status_size(&self) -> Option<Self::StatusSize>;

    /// Entry key.
    fn key(&self) -> Self::Key;
}

impl<'a, E: StatusMapEntry> StatusMapEntry for &'a E {
    type Key = E::Key;
    type StatusSize = E::StatusSize;

    fn status_list_url(&self) -> &Uri {
        E::status_list_url(*self)
    }

    fn status_size(&self) -> Option<Self::StatusSize> {
        E::status_size(*self)
    }

    fn key(&self) -> Self::Key {
        E::key(*self)
    }
}

pub enum StatusPurpose<T = String> {
    /// Cancel the validity of a verifiable credential.
    ///
    /// This status is not reversible.
    Revocation,

    /// Temporarily prevent the acceptance of a verifiable credential.
    ///
    /// This status is reversible.
    Suspension,

    /// Other purpose whose semantics is not supported by `ssi-status`.
    Other(T),
}