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 <vector>
6 
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/logging.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "extensions/browser/api/declarative_net_request/filter_list_converter/converter.h"
15 
16 namespace {
17 
18 const char kSwitchInputFilterlistFiles[] = "input_filterlists";
19 const char kSwitchOutputPath[] = "output_path";
20 const char kSwitchOutputType[] = "output_type";
21 const char kOutputTypeExtension[] = "extension";
22 const char kOutputTypeJSON[] = "json";
23 const base::FilePath::CharType kJSONExtension[] = FILE_PATH_LITERAL(".json");
24 
25 const char kHelpMsg[] = R"(
26   filter_list_converter --input_filterlists=[<path1>, <path2>]
27           --output_path=<path> --output_type=<extension,json>
28 
29   Filter List Converter is a tool to convert filter list files in the text
30   format to a JSON file in a format supported by the Declarative Net Request
31   API. It can either output the complete extension or just the JSON ruleset.
32 
33   --input_filterlists = List of input paths to text filter list files.
34   --output_path = The output path. The parent directory should exist.
35   --output_type = Optional switch. One of "extension" or "json". "json" is the
36                   default.
37 )";
38 
39 namespace filter_list_converter =
40     extensions::declarative_net_request::filter_list_converter;
41 
PrintHelp()42 void PrintHelp() {
43   LOG(ERROR) << kHelpMsg;
44 }
45 
46 }  // namespace
47 
main(int argc,char * argv[])48 int main(int argc, char* argv[]) {
49   base::CommandLine::Init(argc, argv);
50   base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
51 
52   if (!command_line.HasSwitch(kSwitchInputFilterlistFiles) ||
53       !command_line.HasSwitch(kSwitchOutputPath)) {
54     PrintHelp();
55     return 1;
56   }
57 
58   std::vector<base::FilePath> input_paths;
59   base::CommandLine::StringType comma_separated_paths =
60       command_line.GetSwitchValueNative(kSwitchInputFilterlistFiles);
61 
62 #if defined(OS_WIN)
63   base::CommandLine::StringType separator = base::ASCIIToUTF16(",");
64 #else
65   base::CommandLine::StringType separator(",");
66 #endif
67 
68   for (const auto& piece : base::SplitStringPiece(
69            comma_separated_paths, separator, base::TRIM_WHITESPACE,
70            base::SPLIT_WANT_NONEMPTY)) {
71     base::FilePath path(piece);
72 
73     if (!base::PathExists(path)) {
74       LOG(ERROR) << "Input path " << piece << " does not exist.";
75       return 1;
76     }
77 
78     input_paths.push_back(path);
79   }
80   if (input_paths.empty()) {
81     LOG(ERROR) << base::StringPrintf(
82         "No valid input files specified using '%s'.",
83         kSwitchInputFilterlistFiles);
84     return 1;
85   }
86 
87   filter_list_converter::WriteType write_type =
88       filter_list_converter::kJSONRuleset;
89   if (command_line.HasSwitch(kSwitchOutputType)) {
90     std::string output_type =
91         command_line.GetSwitchValueASCII(kSwitchOutputType);
92     if (output_type == kOutputTypeExtension) {
93       write_type = filter_list_converter::kExtension;
94     } else if (output_type == kOutputTypeJSON) {
95       write_type = filter_list_converter::kJSONRuleset;
96     } else {
97       LOG(ERROR) << base::StringPrintf("Invalid value for switch '%s'",
98                                        kSwitchOutputType);
99       return 1;
100     }
101   }
102 
103   base::FilePath output_path =
104       command_line.GetSwitchValuePath(kSwitchOutputPath);
105   bool invalid_output_path = false;
106   switch (write_type) {
107     case filter_list_converter::kExtension:
108       invalid_output_path = !base::DirectoryExists(output_path);
109       break;
110     case filter_list_converter::kJSONRuleset:
111       invalid_output_path = output_path.Extension() != kJSONExtension;
112       invalid_output_path |= !base::DirectoryExists(output_path.DirName());
113       break;
114   }
115   if (invalid_output_path) {
116     LOG(ERROR) << "Invalid output path " << output_path.value();
117     return 1;
118   }
119 
120   if (!filter_list_converter::ConvertRuleset(input_paths, output_path,
121                                              write_type)) {
122     LOG(ERROR) << "Conversion failed.";
123     return 1;
124   }
125 
126   return 0;
127 }
128