1use bitflags::bitflags;
3use serde::{Deserialize, Serialize};
4use sos_core::device::DevicePublicKey;
5use sos_core::events::{
6 AccountEvent, Event, EventKind, ReadEvent, WriteEvent,
7};
8use sos_core::{events::LogEvent, AccountId, SecretId, UtcDateTime, VaultId};
9
10bitflags! {
11 pub struct AuditLogFlags: u16 {
13 const DATA = 0b00000001;
15 const DATA_VAULT = 0b00000010;
17 const DATA_SECRET = 0b00000100;
19 const MOVE_SECRET = 0b00001000;
21 const DEVICE = 0b00010000;
23 }
24}
25
26#[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq)]
43#[serde(rename_all = "camelCase")]
44pub struct AuditEvent {
45 pub(crate) time: UtcDateTime,
47 #[serde(rename = "type")]
49 pub(crate) event_kind: EventKind,
50 pub(crate) account_id: AccountId,
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub(crate) data: Option<AuditData>,
55}
56
57impl AuditEvent {
58 pub fn new(
60 date_time: UtcDateTime,
61 event_kind: EventKind,
62 account_id: AccountId,
63 data: Option<AuditData>,
64 ) -> Self {
65 Self {
66 time: date_time,
67 event_kind,
68 account_id,
69 data,
70 }
71 }
72
73 pub fn account_id(&self) -> &AccountId {
75 &self.account_id
76 }
77
78 pub fn time(&self) -> &UtcDateTime {
80 &self.time
81 }
82
83 pub fn event_kind(&self) -> EventKind {
85 self.event_kind
86 }
87
88 pub fn data(&self) -> Option<&AuditData> {
90 self.data.as_ref()
91 }
92
93 pub(crate) fn log_flags(&self) -> AuditLogFlags {
94 if let Some(data) = &self.data {
95 let mut flags = AuditLogFlags::empty();
96 flags.set(AuditLogFlags::DATA, true);
97 match data {
98 AuditData::Vault(_) => {
99 flags.set(AuditLogFlags::DATA_VAULT, true);
100 }
101 AuditData::Secret(_, _) => {
102 flags.set(AuditLogFlags::DATA_VAULT, true);
103 flags.set(AuditLogFlags::DATA_SECRET, true);
104 }
105 AuditData::MoveSecret { .. } => {
106 flags.set(AuditLogFlags::MOVE_SECRET, true);
107 }
108 AuditData::Device { .. } => {
109 flags.set(AuditLogFlags::DEVICE, true);
110 }
111 }
112 flags
113 } else {
114 AuditLogFlags::empty()
115 }
116 }
117}
118
119impl From<(&AccountId, &Event)> for AuditEvent {
120 fn from(value: (&AccountId, &Event)) -> Self {
121 let (account_id, event) = value;
122 match event {
123 Event::CreateAccount(account_id) => AuditEvent::new(
124 Default::default(),
125 EventKind::CreateAccount,
126 *account_id,
127 None,
128 ),
129 Event::MoveSecret(_, _, _) => {
130 panic!("move secret audit event must be constructed")
131 }
132 Event::DeleteAccount(account_id) => AuditEvent::new(
133 Default::default(),
134 EventKind::DeleteAccount,
135 *account_id,
136 None,
137 ),
138 _ => {
139 let audit_data = match event {
140 Event::Account(event) => {
141 event.folder_id().map(AuditData::Vault)
142 }
143 Event::Folder(event, _) => {
144 event.folder_id().map(AuditData::Vault)
145 }
146 Event::Read(vault_id, event) => match event {
147 ReadEvent::ReadVault => {
148 Some(AuditData::Vault(*vault_id))
149 }
150 ReadEvent::ReadSecret(secret_id) => {
151 Some(AuditData::Secret(*vault_id, *secret_id))
152 }
153 ReadEvent::Noop => None,
154 },
155 Event::Write(vault_id, event) => match event {
156 WriteEvent::CreateVault(_)
157 | WriteEvent::SetVaultName(_)
158 | WriteEvent::SetVaultFlags(_)
159 | WriteEvent::SetVaultMeta(_) => {
160 Some(AuditData::Vault(*vault_id))
161 }
162 WriteEvent::CreateSecret(secret_id, _) => {
163 Some(AuditData::Secret(*vault_id, *secret_id))
164 }
165 WriteEvent::UpdateSecret(secret_id, _) => {
166 Some(AuditData::Secret(*vault_id, *secret_id))
167 }
168 WriteEvent::DeleteSecret(secret_id) => {
169 Some(AuditData::Secret(*vault_id, *secret_id))
170 }
171 WriteEvent::Noop => None,
172 },
173 _ => None,
174 };
175
176 if let Some(audit_data) = audit_data {
177 AuditEvent::new(
178 Default::default(),
179 event.event_kind(),
180 *account_id,
181 Some(audit_data),
182 )
183 } else {
184 unreachable!("{:#?}", event);
185 }
186 }
187 }
188 }
189}
190
191impl From<(&AccountId, &AccountEvent)> for AuditEvent {
192 fn from(value: (&AccountId, &AccountEvent)) -> Self {
193 let (account_id, event) = value;
194 let audit_data = event.folder_id().map(AuditData::Vault);
195 AuditEvent::new(
196 Default::default(),
197 event.event_kind(),
198 *account_id,
199 audit_data,
200 )
201 }
202}
203
204#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
206#[serde(rename_all = "camelCase")]
207pub enum AuditData {
208 Vault(VaultId),
210 Secret(VaultId, SecretId),
212 MoveSecret {
214 from_vault_id: VaultId,
216 from_secret_id: SecretId,
218 to_vault_id: VaultId,
220 to_secret_id: SecretId,
222 },
223 Device(DevicePublicKey),
225}
226
227impl Default for AuditData {
228 fn default() -> Self {
229 let zero = [0u8; 16];
230 Self::Vault(VaultId::from_bytes(zero))
231 }
232}