@@ -34,8 +34,10 @@ use std::path::Path;
34
34
use std:: time:: { Duration , Instant } ;
35
35
36
36
use actix:: Arbiter ;
37
+ use actix_web:: dev:: HttpResponseBuilder ;
37
38
use actix_web:: server:: HttpServer ;
38
- use actix_web:: { fs, http, ws, App , Error , HttpRequest , HttpResponse } ;
39
+ use actix_web:: { fs, http, ws, App , AsyncResponder , Error , HttpMessage , HttpRequest , HttpResponse } ;
40
+ use futures:: Future ;
39
41
40
42
mod channelid;
41
43
mod logging;
@@ -78,7 +80,9 @@ fn channel_route(req: &HttpRequest<session::WsChannelSessionState>) -> Result<Ht
78
80
warn ! ( & req. state( ) . log. log,
79
81
"Invalid ChannelID specified: {:?}" , id;
80
82
"remote_ip" => & meta_info. remote) ;
81
- return Ok ( HttpResponse :: new ( http:: StatusCode :: NOT_FOUND ) ) ;
83
+ let mut resp =
84
+ HttpResponse :: new ( http:: StatusCode :: NOT_FOUND ) . into_builder ( ) ;
85
+ return Ok ( add_headers ( & mut resp) . finish ( ) ) ;
82
86
}
83
87
} ;
84
88
channel_id
@@ -94,6 +98,7 @@ fn channel_route(req: &HttpRequest<session::WsChannelSessionState>) -> Result<Ht
94
98
"remote_ip" => & meta_info. remote
95
99
) ;
96
100
101
+ // Cannot apply headers here.
97
102
ws:: start (
98
103
req,
99
104
session:: WsChannelSession {
@@ -107,24 +112,52 @@ fn channel_route(req: &HttpRequest<session::WsChannelSessionState>) -> Result<Ht
107
112
)
108
113
}
109
114
115
+ /// Inject the FoxSec headers into all HTTP responses
116
+ fn add_headers < ' a > ( resp : & ' a mut HttpResponseBuilder ) -> & ' a mut HttpResponseBuilder {
117
+ resp. header (
118
+ "Content-Security-Policy" ,
119
+ "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; report-uri /__cspreport__" ,
120
+ )
121
+ . header ( "X-Content-Type-Options" , "nosniff" )
122
+ . header ( "X-Frame-Options" , "deny" )
123
+ . header ( "X-XSS-Protection" , "1; mode=block" )
124
+ . header ( "Strict-Transport-Security" , "max-age=63072000" )
125
+ }
126
+
110
127
fn heartbeat ( req : & HttpRequest < session:: WsChannelSessionState > ) -> Result < HttpResponse , Error > {
111
128
// if there's more to check, add it here.
112
129
let body = json ! ( { "status" : "ok" , "version" : env!( "CARGO_PKG_VERSION" ) } ) ;
113
- Ok ( HttpResponse :: Ok ( )
114
- . content_type ( "application/json" )
115
- . body ( body. to_string ( ) ) )
130
+ Ok ( add_headers ( HttpResponse :: Ok ( ) . content_type ( "application/json" ) ) . body ( body. to_string ( ) ) )
116
131
}
117
132
118
133
fn lbheartbeat ( req : & HttpRequest < session:: WsChannelSessionState > ) -> Result < HttpResponse , Error > {
119
134
// load balance heartbeat. Doesn't matter what's returned, aside from a 200
120
- Ok ( HttpResponse :: Ok ( ) . into ( ) )
135
+ Ok ( add_headers ( & mut HttpResponse :: Ok ( ) ) . finish ( ) )
121
136
}
122
137
123
138
fn show_version ( req : & HttpRequest < session:: WsChannelSessionState > ) -> Result < HttpResponse , Error > {
124
139
// Return the contents of the version.json file.
125
- Ok ( HttpResponse :: Ok ( )
126
- . content_type ( "application/json" )
127
- . body ( include_str ! ( "../version.json" ) ) )
140
+ Ok (
141
+ add_headers ( & mut HttpResponse :: Ok ( ) . content_type ( "application/json" ) )
142
+ . body ( include_str ! ( "../version.json" ) ) ,
143
+ )
144
+ }
145
+
146
+ /// Dump the "CSP report" as a warning message.
147
+ fn cspreport (
148
+ req : & HttpRequest < session:: WsChannelSessionState > ,
149
+ ) -> Box < Future < Item = HttpResponse , Error = Error > > {
150
+ use std:: str;
151
+
152
+ let log = req. state ( ) . log . clone ( ) ;
153
+ req. body ( )
154
+ . from_err ( )
155
+ . and_then ( move |body| {
156
+ let bstr = str:: from_utf8 ( & body) . unwrap ( ) ;
157
+ warn ! ( log. log, "CSP Report" ; "report" => bstr) ;
158
+ Ok ( add_headers ( & mut HttpResponse :: Ok ( ) ) . finish ( ) )
159
+ } )
160
+ . responder ( )
128
161
}
129
162
130
163
fn build_app ( app : App < session:: WsChannelSessionState > ) -> App < session:: WsChannelSessionState > {
@@ -141,6 +174,9 @@ fn build_app(app: App<session::WsChannelSessionState>) -> App<session::WsChannel
141
174
} )
142
175
. resource ( "/__lbheartbeat__" , |r| {
143
176
r. method ( http:: Method :: GET ) . f ( lbheartbeat)
177
+ } )
178
+ . resource ( "/__cspreport__" , |r| {
179
+ r. method ( http:: Method :: POST ) . f ( cspreport)
144
180
} ) ;
145
181
// Only add a static handler if the static directory exists.
146
182
if Path :: new ( "static/" ) . exists ( ) {
0 commit comments