1
1
use crate :: config:: SentryConfig ;
2
+ use http:: header:: AUTHORIZATION ;
2
3
use sentry:: protocol:: Event ;
3
4
use sentry:: { ClientInitGuard , ClientOptions , TransactionContext } ;
4
5
use std:: sync:: Arc ;
@@ -20,6 +21,10 @@ pub fn init() -> Option<ClientInitGuard> {
20
21
}
21
22
} ;
22
23
24
+ Some ( sentry:: init ( options ( config) ) )
25
+ }
26
+
27
+ fn options ( config : SentryConfig ) -> ClientOptions {
23
28
let traces_sampler = move |ctx : & TransactionContext | -> f32 {
24
29
if let Some ( sampled) = ctx. sampled ( ) {
25
30
return if sampled { 1.0 } else { 0.0 } ;
@@ -53,16 +58,22 @@ pub fn init() -> Option<ClientInitGuard> {
53
58
} ;
54
59
55
60
let before_send = |mut event : Event < ' static > | {
56
- // Remove cookies from the request to avoid sending sensitive
57
- // information like the `cargo_session`.
58
61
if let Some ( request) = & mut event. request {
62
+ // Remove cookies from the request to avoid sending sensitive information like the
63
+ // `cargo_session`.
59
64
request. cookies . take ( ) ;
65
+
66
+ // Also remove `Authorization`, just so it never even gets sent to Sentry, even if
67
+ // they're redacting it downstream.
68
+ request
69
+ . headers
70
+ . retain ( |name, _value| AUTHORIZATION != name. as_str ( ) ) ;
60
71
}
61
72
62
73
Some ( event)
63
74
} ;
64
75
65
- let opts = ClientOptions {
76
+ ClientOptions {
66
77
auto_session_tracking : true ,
67
78
dsn : config. dsn ,
68
79
environment : config. environment . map ( Into :: into) ,
@@ -71,7 +82,86 @@ pub fn init() -> Option<ClientInitGuard> {
71
82
session_mode : sentry:: SessionMode :: Request ,
72
83
traces_sampler : Some ( Arc :: new ( traces_sampler) ) ,
73
84
..Default :: default ( )
85
+ }
86
+ }
87
+
88
+ #[ cfg( test) ]
89
+ mod tests {
90
+ use super :: * ;
91
+
92
+ use sentry:: {
93
+ capture_error,
94
+ protocol:: { Request , SpanStatus , Url } ,
95
+ start_transaction,
74
96
} ;
75
97
76
- Some ( sentry:: init ( opts) )
98
+ #[ test]
99
+ fn test_redaction ( ) -> anyhow:: Result < ( ) > {
100
+ let req = Request {
101
+ url : Some ( Url :: parse ( "https://crates.io/api/v1/foo" ) ?) ,
102
+ method : Some ( "GET" . into ( ) ) ,
103
+ data : None ,
104
+ cookies : Some ( "cargo_session=foobar" . into ( ) ) ,
105
+ headers : [
106
+ ( "Authorization" , "secret" ) ,
107
+ ( "authorization" , "another secret" ) ,
108
+ ( "Accept" , "application/json" ) ,
109
+ ]
110
+ . into_iter ( )
111
+ . map ( |( k, v) | ( k. to_string ( ) , v. to_string ( ) ) )
112
+ . collect ( ) ,
113
+ query_string : None ,
114
+ env : Default :: default ( ) ,
115
+ } ;
116
+ let err = std:: io:: Error :: new ( std:: io:: ErrorKind :: Other , "error" ) ;
117
+
118
+ let opts = options ( SentryConfig :: default ( ) ) ;
119
+ let event_req = req. clone ( ) ;
120
+ let mut events = sentry:: test:: with_captured_events_options (
121
+ move || {
122
+ let scope_req = event_req. clone ( ) ;
123
+ sentry:: configure_scope ( |scope| {
124
+ // This is straight up replicated from the implementation of SentryHttpFuture,
125
+ // and is how requests are attached by the Tower middleware.
126
+ scope. add_event_processor ( move |mut event| {
127
+ if event. request . is_none ( ) {
128
+ event. request = Some ( scope_req. clone ( ) ) ;
129
+ }
130
+ Some ( event)
131
+ } ) ;
132
+ } ) ;
133
+
134
+ let ctx = TransactionContext :: new ( "test" , "http.server" ) ;
135
+ let txn = start_transaction ( ctx) ;
136
+ txn. set_request ( event_req) ;
137
+ txn. set_status ( SpanStatus :: InternalError ) ;
138
+
139
+ capture_error ( & err) ;
140
+
141
+ txn. finish ( ) ;
142
+ } ,
143
+ opts,
144
+ ) ;
145
+
146
+ // OK, so there should be exactly one event, and it should match `req` except that its
147
+ // cookies are removed and its headers have been cleaned of all Authorization values. Let's
148
+ // see what we actually have.
149
+ assert_eq ! ( events. len( ) , 1 ) ;
150
+ let event = assert_some ! ( events. pop( ) ) ;
151
+ let event_req = assert_some ! ( event. request) ;
152
+
153
+ // Things that shouldn't change.
154
+ assert_eq ! ( & req. url, & event_req. url) ;
155
+ assert_eq ! ( & req. method, & event_req. method) ;
156
+ assert_eq ! ( & req. data, & event_req. data) ;
157
+ assert_eq ! ( & req. query_string, & event_req. query_string) ;
158
+ assert_eq ! ( & req. env, & event_req. env) ;
159
+
160
+ // Things that should.
161
+ assert_none ! ( & event_req. cookies) ;
162
+ assert_eq ! ( event_req. headers. len( ) , 1 ) ;
163
+ assert_some ! ( event_req. headers. get( "Accept" ) ) ;
164
+
165
+ Ok ( ( ) )
166
+ }
77
167
}
0 commit comments