@@ -31,11 +31,14 @@ extern crate maxminddb;
31
31
extern crate reqwest;
32
32
33
33
use std:: path:: Path ;
34
+ use std:: str;
34
35
use std:: time:: { Duration , Instant } ;
35
36
36
37
use actix:: Arbiter ;
38
+ use actix_web:: dev:: HttpResponseBuilder ;
37
39
use actix_web:: server:: HttpServer ;
38
- use actix_web:: { fs, http, ws, App , Error , HttpRequest , HttpResponse } ;
40
+ use actix_web:: { fs, http, ws, App , AsyncResponder , Error , HttpMessage , HttpRequest , HttpResponse } ;
41
+ use futures:: Future ;
39
42
40
43
mod channelid;
41
44
mod logging;
@@ -77,7 +80,9 @@ fn channel_route(req: &HttpRequest<session::WsChannelSessionState>) -> Result<Ht
77
80
warn ! ( & req. state( ) . log. log,
78
81
"Invalid ChannelID specified: {:?}" , id;
79
82
"remote_ip" => & meta_info. remote) ;
80
- 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 ( ) ) ;
81
86
}
82
87
} ;
83
88
channel_id
@@ -93,6 +98,7 @@ fn channel_route(req: &HttpRequest<session::WsChannelSessionState>) -> Result<Ht
93
98
"remote_ip" => & meta_info. remote
94
99
) ;
95
100
101
+ // Cannot apply headers here.
96
102
ws:: start (
97
103
req,
98
104
session:: WsChannelSession {
@@ -106,24 +112,50 @@ fn channel_route(req: &HttpRequest<session::WsChannelSessionState>) -> Result<Ht
106
112
)
107
113
}
108
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
+
109
127
fn heartbeat ( req : & HttpRequest < session:: WsChannelSessionState > ) -> Result < HttpResponse , Error > {
110
128
// if there's more to check, add it here.
111
129
let body = json ! ( { "status" : "ok" , "version" : env!( "CARGO_PKG_VERSION" ) } ) ;
112
- Ok ( HttpResponse :: Ok ( )
113
- . content_type ( "application/json" )
114
- . body ( body. to_string ( ) ) )
130
+ Ok ( add_headers ( HttpResponse :: Ok ( ) . content_type ( "application/json" ) ) . body ( body. to_string ( ) ) )
115
131
}
116
132
117
133
fn lbheartbeat ( req : & HttpRequest < session:: WsChannelSessionState > ) -> Result < HttpResponse , Error > {
118
134
// load balance heartbeat. Doesn't matter what's returned, aside from a 200
119
- Ok ( HttpResponse :: Ok ( ) . into ( ) )
135
+ Ok ( add_headers ( & mut HttpResponse :: Ok ( ) ) . finish ( ) )
120
136
}
121
137
122
138
fn show_version ( req : & HttpRequest < session:: WsChannelSessionState > ) -> Result < HttpResponse , Error > {
123
139
// Return the contents of the version.json file.
124
- Ok ( HttpResponse :: Ok ( )
125
- . content_type ( "application/json" )
126
- . 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
+ let log = req. state ( ) . log . clone ( ) ;
151
+ req. body ( )
152
+ . from_err ( )
153
+ . and_then ( move |body| {
154
+ let bstr = str:: from_utf8 ( & body) . unwrap ( ) ;
155
+ warn ! ( log. log, "CSP Report" ; "report" => bstr) ;
156
+ Ok ( add_headers ( & mut HttpResponse :: Ok ( ) ) . finish ( ) )
157
+ } )
158
+ . responder ( )
127
159
}
128
160
129
161
fn build_app ( app : App < session:: WsChannelSessionState > ) -> App < session:: WsChannelSessionState > {
@@ -140,6 +172,9 @@ fn build_app(app: App<session::WsChannelSessionState>) -> App<session::WsChannel
140
172
} )
141
173
. resource ( "/__lbheartbeat__" , |r| {
142
174
r. method ( http:: Method :: GET ) . f ( lbheartbeat)
175
+ } )
176
+ . resource ( "/__cspreport__" , |r| {
177
+ r. method ( http:: Method :: POST ) . f ( cspreport)
143
178
} ) ;
144
179
// Only add a static handler if the static directory exists.
145
180
if Path :: new ( "static/" ) . exists ( ) {
0 commit comments