1 //  ██████╗  █████╗ ███████╗███████╗██╗███╗   ██╗ ██████╗
2 //  ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗  ██║██╔════╝
3 //  ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║  ███╗
4 //  ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║   ██║
5 //  ██║     ██║  ██║███████║███████║██║██║ ╚████║╚██████╔╝
6 //  ╚═╝     ╚═╝  ╚═╝╚══════╝╚══════╝╚═╝╚═╝  ╚═══╝ ╚═════╝
7 
8 #[cfg(test)]
9 mod passing {
10     use assert_cmd::prelude::*;
11     use std::env;
12     use std::process::Command;
13 
14     #[test]
isolate_data_url()15     fn isolate_data_url() {
16         let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap();
17         let out = cmd
18             .arg("-M")
19             .arg("-I")
20             .arg("data:text/html,Hello%2C%20World!")
21             .output()
22             .unwrap();
23 
24         // STDERR should be empty
25         assert_eq!(String::from_utf8_lossy(&out.stderr), "");
26 
27         // STDOUT should contain isolated HTML
28         assert_eq!(
29             String::from_utf8_lossy(&out.stdout),
30             "<html><head>\
31             <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:;\"></meta>\
32             </head><body>Hello, World!</body></html>\n"
33         );
34 
35         // Exit code should be 0
36         out.assert().code(0);
37     }
38 
39     #[test]
remove_css_from_data_url()40     fn remove_css_from_data_url() {
41         let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap();
42         let out = cmd
43             .arg("-M")
44             .arg("-c")
45             .arg("data:text/html,<style>body{background-color:pink}</style>Hello")
46             .output()
47             .unwrap();
48 
49         // STDERR should be empty
50         assert_eq!(String::from_utf8_lossy(&out.stderr), "");
51 
52         // STDOUT should contain HTML with no CSS
53         assert_eq!(
54             String::from_utf8_lossy(&out.stdout),
55             "<html><head>\
56             <meta http-equiv=\"Content-Security-Policy\" content=\"style-src 'none';\"></meta>\
57             <style></style>\
58             </head><body>Hello</body></html>\n"
59         );
60 
61         // Exit code should be 0
62         out.assert().code(0);
63     }
64 
65     #[test]
remove_fonts_from_data_url()66     fn remove_fonts_from_data_url() {
67         let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap();
68         let out = cmd
69             .arg("-M")
70             .arg("-F")
71             .arg("data:text/html,<style>@font-face { font-family: myFont; src: url(font.woff); }</style>Hi")
72             .output()
73             .unwrap();
74 
75         // STDERR should be empty
76         assert_eq!(String::from_utf8_lossy(&out.stderr), "");
77 
78         // STDOUT should contain HTML with no web fonts
79         assert_eq!(
80             String::from_utf8_lossy(&out.stdout),
81             "<html><head>\
82             <meta http-equiv=\"Content-Security-Policy\" content=\"font-src 'none';\"></meta>\
83             <style></style>\
84             </head><body>Hi</body></html>\n"
85         );
86 
87         // Exit code should be 0
88         out.assert().code(0);
89     }
90 
91     #[test]
remove_frames_from_data_url()92     fn remove_frames_from_data_url() {
93         let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap();
94         let out = cmd
95             .arg("-M")
96             .arg("-f")
97             .arg("data:text/html,<iframe src=\"https://duckduckgo.com\"></iframe>Hi")
98             .output()
99             .unwrap();
100 
101         // STDERR should be empty
102         assert_eq!(String::from_utf8_lossy(&out.stderr), "");
103 
104         // STDOUT should contain HTML with no iframes
105         assert_eq!(
106             String::from_utf8_lossy(&out.stdout),
107             "<html><head>\
108             <meta http-equiv=\"Content-Security-Policy\" content=\"frame-src 'none'; child-src 'none';\"></meta>\
109             </head><body><iframe src=\"\"></iframe>Hi</body></html>\n"
110         );
111 
112         // Exit code should be 0
113         out.assert().code(0);
114     }
115 
116     #[test]
remove_images_from_data_url()117     fn remove_images_from_data_url() {
118         let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap();
119         let out = cmd
120             .arg("-M")
121             .arg("-i")
122             .arg("data:text/html,<img src=\"https://google.com\"/>Hi")
123             .output()
124             .unwrap();
125 
126         // STDERR should be empty
127         assert_eq!(String::from_utf8_lossy(&out.stderr), "");
128 
129         // STDOUT should contain HTML with no images
130         assert_eq!(
131             String::from_utf8_lossy(&out.stdout),
132             format!(
133                 "<html>\
134                 <head>\
135                 <meta http-equiv=\"Content-Security-Policy\" content=\"img-src data:;\"></meta>\
136                 </head>\
137                 <body>\
138                 <img src=\"{empty_image}\">\
139                 Hi\
140                 </body>\
141                 </html>\n",
142                 empty_image = empty_image!()
143             )
144         );
145 
146         // Exit code should be 0
147         out.assert().code(0);
148     }
149 
150     #[test]
remove_js_from_data_url()151     fn remove_js_from_data_url() {
152         let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap();
153         let out = cmd
154             .arg("-M")
155             .arg("-j")
156             .arg("data:text/html,<script>alert(2)</script>Hi")
157             .output()
158             .unwrap();
159 
160         // STDERR should be empty
161         assert_eq!(String::from_utf8_lossy(&out.stderr), "");
162 
163         // STDOUT should contain HTML with no JS
164         assert_eq!(
165             String::from_utf8_lossy(&out.stdout),
166             "<html>\
167             <head>\
168             <meta http-equiv=\"Content-Security-Policy\" content=\"script-src 'none';\"></meta>\
169             <script></script></head>\
170             <body>Hi</body>\
171             </html>\n"
172         );
173 
174         // Exit code should be 0
175         out.assert().code(0);
176     }
177 }
178 
179 //  ███████╗ █████╗ ██╗██╗     ██╗███╗   ██╗ ██████╗
180 //  ██╔════╝██╔══██╗██║██║     ██║████╗  ██║██╔════╝
181 //  █████╗  ███████║██║██║     ██║██╔██╗ ██║██║  ███╗
182 //  ██╔══╝  ██╔══██║██║██║     ██║██║╚██╗██║██║   ██║
183 //  ██║     ██║  ██║██║███████╗██║██║ ╚████║╚██████╔╝
184 //  ╚═╝     ╚═╝  ╚═╝╚═╝╚══════╝╚═╝╚═╝  ╚═══╝ ╚═════╝
185 
186 #[cfg(test)]
187 mod failing {
188     use assert_cmd::prelude::*;
189     use std::env;
190     use std::process::Command;
191 
192     #[test]
bad_input_data_url()193     fn bad_input_data_url() {
194         let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap();
195         let out = cmd.arg("data:,Hello%2C%20World!").output().unwrap();
196 
197         // STDERR should contain error description
198         assert_eq!(
199             String::from_utf8_lossy(&out.stderr),
200             "Unsupported document media type\n"
201         );
202 
203         // STDOUT should contain HTML
204         assert_eq!(String::from_utf8_lossy(&out.stdout), "");
205 
206         // Exit code should be 1
207         out.assert().code(1);
208     }
209 
210     #[test]
security_disallow_local_assets_within_data_url_targets()211     fn security_disallow_local_assets_within_data_url_targets() {
212         let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap();
213         let out = cmd
214             .arg("-M")
215             .arg("data:text/html,%3Cscript%20src=\"src/tests/data/basic/local-script.js\"%3E%3C/script%3E")
216             .output()
217             .unwrap();
218 
219         // STDERR should be empty
220         assert_eq!(String::from_utf8_lossy(&out.stderr), "");
221 
222         // STDOUT should contain HTML with no JS in it
223         assert_eq!(
224             String::from_utf8_lossy(&out.stdout),
225             "<html><head><script src=\"data:application/javascript;base64,\"></script></head><body></body></html>\n"
226         );
227 
228         // Exit code should be 0
229         out.assert().code(0);
230     }
231 }
232