1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "extensions/browser/api/declarative_net_request/filter_list_converter/converter.h"
6 
7 #include "base/check_op.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/json/json_file_value_serializer.h"
12 #include "base/json/json_reader.h"
13 #include "base/optional.h"
14 #include "base/strings/string_util.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace extensions {
18 namespace declarative_net_request {
19 namespace filter_list_converter {
20 namespace {
21 
TestConversion(std::vector<std::string> filter_list_rules,std::string json_result,WriteType write_type)22 void TestConversion(std::vector<std::string> filter_list_rules,
23                     std::string json_result,
24                     WriteType write_type) {
25   base::ScopedTempDir temp_dir;
26   CHECK(temp_dir.CreateUniqueTempDir());
27 
28   base::FilePath input_path = temp_dir.GetPath().AppendASCII("filterlist.txt");
29   std::string filterlist = base::JoinString(filter_list_rules, "\n");
30   CHECK_EQ(filterlist.size(),
31            static_cast<size_t>(base::WriteFile(input_path, filterlist.c_str(),
32                                                filterlist.size())));
33 
34   base::Optional<base::Value> expected_json =
35       base::JSONReader::Read(json_result);
36   CHECK(expected_json.has_value());
37 
38   base::FilePath output_path = temp_dir.GetPath();
39   if (write_type == WriteType::kJSONRuleset)
40     output_path = output_path.AppendASCII("rules.json");
41 
42   ConvertRuleset({input_path}, output_path, write_type, true /* noisy */);
43 
44   base::FilePath output_json_path =
45       temp_dir.GetPath().AppendASCII("rules.json");
46   JSONFileValueDeserializer deserializer(output_json_path);
47   std::unique_ptr<base::Value> actual_json = deserializer.Deserialize(
48       nullptr /* error_code */, nullptr /* error_message */);
49   ASSERT_TRUE(actual_json.get());
50 
51   EXPECT_EQ(*expected_json, *actual_json);
52 
53   if (write_type == WriteType::kExtension) {
54     EXPECT_TRUE(
55         base::PathExists(temp_dir.GetPath().AppendASCII("manifest.json")));
56   }
57 }
58 
59 class FilterListConverterTest : public ::testing::TestWithParam<WriteType> {};
60 
TEST_P(FilterListConverterTest,Convert)61 TEST_P(FilterListConverterTest, Convert) {
62   std::vector<std::string> filter_list_rules = {
63       "||example.com^|$script,image,font",
64       "@@allowed.com$domain=example.com|~sub.example.com",
65       "|https://*.abc.com|$match-case,~image,third-party",
66       "abc.com$~third-party",
67       "@@||yahoo.com^$document,subdocument",
68       "@@||yahoo.com^$document",
69 
70       // This rule is invalid and should be ignored.
71       "@@||yahoo.com^$document,script",
72 
73       "@@||yahoo.com^$subdocument",
74   };
75 
76   std::string expected_result = R"(
77     [ {
78        "action": {
79           "type": "block"
80        },
81        "condition": {
82           "isUrlFilterCaseSensitive": false,
83           "resourceTypes": [ "script", "image", "font" ],
84           "urlFilter": "||example.com^|"
85        },
86        "id": 1,
87        "priority": 1
88     }, {
89        "action": {
90           "type": "allow"
91        },
92        "condition": {
93           "domains": [ "example.com" ],
94           "excludedDomains": [ "sub.example.com" ],
95           "isUrlFilterCaseSensitive": false,
96           "urlFilter": "allowed.com"
97        },
98        "id": 2,
99        "priority": 1
100     }, {
101        "action": {
102           "type": "block"
103        },
104        "condition": {
105           "resourceTypes": [ "other", "script", "stylesheet", "object",
106               "xmlhttprequest", "sub_frame", "ping", "media", "font",
107               "websocket" ],
108           "urlFilter": "|https://*.abc.com|",
109           "domainType": "thirdParty"
110        },
111        "id": 3,
112        "priority": 1
113     }, {
114        "action": {
115           "type": "block"
116        },
117        "condition": {
118           "isUrlFilterCaseSensitive": false,
119           "urlFilter": "abc.com",
120           "domainType": "firstParty"
121        },
122        "id": 4,
123        "priority": 1
124     }, {
125        "action": {
126           "type": "allowAllRequests"
127        },
128        "condition": {
129           "isUrlFilterCaseSensitive": false,
130           "resourceTypes": [ "sub_frame", "main_frame" ],
131           "urlFilter": "||yahoo.com^"
132        },
133        "id": 5,
134        "priority": 1
135     }, {
136        "action": {
137           "type": "allowAllRequests"
138        },
139        "condition": {
140           "isUrlFilterCaseSensitive": false,
141           "resourceTypes": [ "main_frame" ],
142           "urlFilter": "||yahoo.com^"
143        },
144        "id": 6,
145        "priority": 1
146     }, {
147        "action": {
148           "type": "allow"
149        },
150        "condition": {
151           "isUrlFilterCaseSensitive": false,
152           "resourceTypes": [ "sub_frame" ],
153           "urlFilter": "||yahoo.com^"
154        },
155        "id": 7,
156        "priority": 1
157     } ]
158 
159 )";
160 
161   TestConversion(filter_list_rules, expected_result, GetParam());
162 }
163 
164 INSTANTIATE_TEST_SUITE_P(All,
165                          FilterListConverterTest,
166                          ::testing::Values(WriteType::kExtension,
167                                            WriteType::kJSONRuleset));
168 
169 }  // namespace
170 }  // namespace filter_list_converter
171 }  // namespace declarative_net_request
172 }  // namespace extensions
173