steam_mobile/web_handler/
confirmation.rs

1use std::fmt::Display;
2use std::fmt::Formatter;
3use std::iter::FromIterator;
4
5use derive_more::Deref;
6use derive_more::IntoIterator;
7use serde::Deserialize;
8use serde_repr::Deserialize_repr;
9use serde_repr::Serialize_repr;
10
11/// A collection of [`Confirmation`]
12#[derive(IntoIterator, Deref, Default, Debug)]
13pub struct Confirmations(#[into_iterator(owned, ref)] pub Vec<Confirmation>);
14
15impl<'a> FromIterator<&'a Confirmation> for Confirmations {
16    fn from_iter<T>(iter: T) -> Self
17    where
18        T: IntoIterator<Item = &'a Confirmation>,
19    {
20        let buffer = iter.into_iter().cloned().collect::<Vec<_>>();
21        Self(buffer)
22    }
23}
24
25/// A pending Steam confirmation.
26#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
27pub struct Confirmation {
28    pub id: String,
29    #[serde(rename = "nonce")]
30    pub key: String,
31    #[serde(rename = "type")]
32    pub kind: EConfirmationType,
33    pub creation_time: i64,
34    pub creator_id: String,
35    pub type_name: String,
36    // from below here, nothing really useful
37    // pub cancel: String,
38    // pub accept: String,
39    // pub icon: String,
40    // pub multi: bool,
41    // pub headline: String,
42    // pub summary: Vec<String>,
43    // pub warn: Option<String>,
44}
45
46impl Display for Confirmation {
47    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
48        write!(f, "Confirmation {} of {:?}", self.key, self.kind)
49    }
50}
51
52impl Confirmation {
53    pub fn has_trade_offer_id(&self, offer_id: u64) -> bool {
54        self.kind == EConfirmationType::Trade && offer_id == self.creator_id.parse::<u64>().unwrap()
55    }
56    pub fn trade_offer_id(&self) -> Option<u64> {
57        if self.kind == EConfirmationType::Trade {
58            self.creator_id.parse().ok()
59        } else {
60            None
61        }
62    }
63}
64
65/// We retrieve [`ConfirmationDetails`] as a json object.
66/// There is also the need to already have a [Confirmation].
67#[derive(Debug, Clone, PartialEq, Eq, Copy)]
68pub struct ConfirmationDetails {
69    /// ID of the trade offer. Has a value if EConfirmationType::Trade
70    pub trade_offer_id: Option<i64>,
71}
72
73/// Kinds of mobile confirmations
74#[derive(Debug, Copy, Clone, Serialize_repr, Deserialize_repr, Eq, PartialEq)]
75#[repr(u8)]
76#[non_exhaustive]
77pub enum EConfirmationType {
78    /// Unknown confirmation
79    Unknown = 0,
80    /// Under rare circumstances this might pop up
81    Generic = 1,
82    /// Confirmation from Trade Offer
83    Trade = 2,
84    /// Confirmation from Steam's Market
85    Market = 3,
86
87    /// Unknown
88    FeatureOptOut = 4,
89    /// Confirmation for a phone number change
90    PhoneNumberChange = 5,
91    /// Confirmation for account recovery
92    AccountRecovery = 6,
93    /// Confirmation for creating a new API Key,
94    APIKey = 9,
95}
96
97impl From<Vec<Confirmation>> for Confirmations {
98    fn from(confirmations_vec: Vec<Confirmation>) -> Self {
99        Self(confirmations_vec)
100    }
101}
102
103#[allow(missing_docs)]
104#[derive(Eq, PartialEq, Copy, Clone, Debug)]
105pub enum ConfirmationAction {
106    Retrieve,
107    Accept,
108    Deny,
109}
110
111impl ConfirmationAction {
112    pub(crate) const fn as_operation(self) -> Option<&'static str> {
113        Some(match self {
114            Self::Accept => "allow",
115            Self::Deny => "cancel",
116            _ => return None,
117        })
118    }
119    pub(crate) const fn as_tag(self) -> &'static str {
120        "conf"
121    }
122}
123
124#[derive(Copy, Clone, Debug)]
125enum EInventoryPrivacy {
126    Unknown,
127    Private,
128    FriendsOnly,
129    Public,
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135
136    fn get_confirmations() -> Confirmations {
137        let confirmations = vec![
138            Confirmation {
139                id: "7676451136".to_string(),
140                key: "18064583892738866189".to_string(),
141                kind: EConfirmationType::Trade,
142                details: Some(ConfirmationDetails {
143                    trade_offer_id: Some(4009687284),
144                }),
145            },
146            Confirmation {
147                id: "7652515663".to_string(),
148                key: "10704556181383316145".to_string(),
149                kind: EConfirmationType::Trade,
150                details: Some(ConfirmationDetails {
151                    trade_offer_id: Some(4000980011),
152                }),
153            },
154            Confirmation {
155                id: "7652555421".to_string(),
156                key: "10704556181383323456".to_string(),
157                kind: EConfirmationType::Trade,
158                details: Some(ConfirmationDetails {
159                    trade_offer_id: Some(4000793103),
160                }),
161            },
162            Confirmation {
163                id: "7652515663".to_string(),
164                key: "20845677815483316145".to_string(),
165                kind: EConfirmationType::Market,
166                details: None,
167            },
168        ];
169        Confirmations::from(confirmations)
170    }
171}