Skip to content
File

Blob: firmware/vendor/str0m/tests/pii.rs

rust175 lines
1//! If this test fails, it indicates that an IP address or other personally
2//! identifiable information (PII) was logged. Ensure that sensitive values
3//! checked by this test are wrapped using the `Pii` wrapper.
4//! Run this test with:
5//! ```shell
6//! cargo test --test pii --features pii
7//! ```
8 
9mod common;
10#[cfg(feature = "pii")]
11mod pii_log_redaction {
12 use common::{connect_l_r, init_crypto_default, progress};
13 use std::collections::VecDeque;
14 use std::time::Duration;
15 
16 use str0m::format::Codec;
17 use str0m::media::MediaKind;
18 use str0m::rtp::{ExtensionValues, RtpWrite, Ssrc};
19 use str0m::{Event, RtcError};
20 
21 use super::*;
22 use regex::Regex;
23 use std::sync::Once;
24 use tracing::{Event as TracingEvent, Subscriber};
25 use tracing_subscriber::prelude::*;
26 use tracing_subscriber::{Layer, Registry, layer::Context};
27 
28 static INIT: Once = Once::new();
29 
30 struct AssertNoIpLayer {
31 ipv4: Regex,
32 ipv6: Regex,
33 }
34 
35 impl<S: Subscriber> Layer<S> for AssertNoIpLayer {
36 fn on_event(&self, event: &TracingEvent<'_>, _ctx: Context<'_, S>) {
37 let mut visitor = StringVisitor::default();
38 event.record(&mut visitor);
39 let msg = visitor.0;
40 if self.ipv4.is_match(&msg) {
41 panic!("IPv4 address found in log: {}", msg);
42 }
43 if self.ipv6.is_match(&msg) {
44 panic!("IPv6 address found in log: {}", msg);
45 }
46 }
47 }
48 
49 #[derive(Default)]
50 struct StringVisitor(String);
51 impl tracing::field::Visit for StringVisitor {
52 fn record_debug(&mut self, _field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
53 use std::fmt::Write;
54 let _ = write!(&mut self.0, "{:?}", value);
55 }
56 fn record_str(&mut self, _field: &tracing::field::Field, value: &str) {
57 self.0.push_str(value);
58 }
59 }
60 
61 fn install_assert_no_ip_layer() {
62 INIT.call_once(|| {
63 let ipv4 = Regex::new(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b").unwrap();
64 let ipv6 = Regex::new(r"\b([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}\b").unwrap();
65 let layer = AssertNoIpLayer { ipv4, ipv6 }
66 .with_filter(tracing_subscriber::filter::LevelFilter::DEBUG);
67 let subscriber = Registry::default().with(layer);
68 tracing::subscriber::set_global_default(subscriber).expect("set global subscriber");
69 });
70 }
71 
72 #[test]
73 fn pii_test() -> Result<(), RtcError> {
74 install_assert_no_ip_layer();
75 init_crypto_default();
76 
77 let (mut l, mut r) = connect_l_r();
78 
79 let mid = "aud".into();
80 
81 // In this example we are using MID only (no RID) to identify the incoming media.
82 let ssrc_tx: Ssrc = 42.into();
83 
84 l.direct_api().declare_media(mid, MediaKind::Audio);
85 
86 l.direct_api().declare_stream_tx(ssrc_tx, None, mid, None);
87 
88 r.direct_api().declare_media(mid, MediaKind::Audio);
89 
90 let max = l.last.max(r.last);
91 l.last = max;
92 r.last = max;
93 
94 let params = l.params_opus();
95 let ssrc = l.direct_api().stream_tx_by_mid(mid, None).unwrap().ssrc();
96 assert_eq!(params.spec().codec, Codec::Opus);
97 let pt = params.pt();
98 
99 let to_write: Vec<&[u8]> = vec![
100 // 1
101 &[0x1, 0x2, 0x3, 0x4],
102 // 3
103 &[0x9, 0xa, 0xb, 0xc],
104 // 2
105 &[0x5, 0x6, 0x7, 0x8],
106 ];
107 
108 let mut to_write: VecDeque<_> = to_write.into();
109 
110 let mut write_at = l.last + Duration::from_millis(300);
111 
112 let mut counts: Vec<u64> = vec![0, 3, 1];
113 
114 loop {
115 if l.start + l.duration() > write_at {
116 write_at = l.last + Duration::from_millis(300);
117 if let Some(packet) = to_write.pop_front() {
118 let wallclock = l.start + l.duration();
119 
120 let mut direct = l.direct_api();
121 let stream = direct.stream_tx(&ssrc).unwrap();
122 
123 let count = counts.remove(0);
124 let time = (count * 1000 + 47_000_000) as u32;
125 let seq_no = (47_000 + count).into();
126 
127 let exts = ExtensionValues {
128 audio_level: Some(-42 - count as i8),
129 voice_activity: Some(false),
130 ..Default::default()
131 };
132 
133 stream.write_rtp(
134 RtpWrite::new(pt, seq_no, time, wallclock, packet).ext_vals(exts),
135 );
136 }
137 }
138 
139 progress(&mut l, &mut r)?;
140 
141 if l.duration() > Duration::from_secs(10) {
142 break;
143 }
144 }
145 
146 let media: Vec<_> = r
147 .events
148 .iter()
149 .filter_map(|(_, e)| {
150 if let Event::RtpPacket(v) = e {
151 Some(v)
152 } else {
153 None
154 }
155 })
156 .collect();
157 
158 assert_eq!(media.len(), 3);
159 
160 assert!(l.media(mid).is_some());
161 assert!(l.direct_api().stream_tx_by_mid(mid, None).is_some());
162 l.direct_api().remove_media(mid);
163 assert!(l.media(mid).is_none());
164 assert!(l.direct_api().stream_tx_by_mid(mid, None).is_none());
165 
166 assert!(r.media(mid).is_some());
167 assert!(r.direct_api().stream_rx_by_mid(mid, None).is_some());
168 r.direct_api().remove_media(mid);
169 assert!(r.media(mid).is_none());
170 assert!(r.direct_api().stream_rx_by_mid(mid, None).is_none());
171 
172 Ok(())
173 }
174}