1// Copyright 2014 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 "chrome/utility/extensions/extensions_handler.h"
6
7#include "base/command_line.h"
8#include "base/path_service.h"
9#include "chrome/common/chrome_utility_messages.h"
10#include "chrome/common/extensions/chrome_extensions_client.h"
11#include "chrome/common/extensions/chrome_utility_extensions_messages.h"
12#include "chrome/common/media_galleries/metadata_types.h"
13#include "chrome/utility/chrome_content_utility_client.h"
14#include "chrome/utility/extensions/unpacker.h"
15#include "chrome/utility/media_galleries/image_metadata_extractor.h"
16#include "content/public/common/content_paths.h"
17#include "content/public/utility/utility_thread.h"
18#include "extensions/common/extension.h"
19#include "extensions/common/extension_l10n_util.h"
20#include "extensions/common/extension_utility_messages.h"
21#include "extensions/common/manifest.h"
22#include "extensions/common/update_manifest.h"
23#include "media/base/media.h"
24#include "media/base/media_file_checker.h"
25#include "third_party/zlib/google/zip.h"
26#include "ui/base/ui_base_switches.h"
27
28#if defined(OS_WIN)
29#include "chrome/common/extensions/api/networking_private/networking_private_crypto.h"
30#include "chrome/utility/media_galleries/itunes_pref_parser_win.h"
31#include "components/wifi/wifi_service.h"
32#endif  // defined(OS_WIN)
33
34#if defined(OS_MACOSX)
35#include "chrome/utility/media_galleries/iphoto_library_parser.h"
36#endif  // defined(OS_MACOSX)
37
38#if defined(OS_WIN) || defined(OS_MACOSX)
39#include "chrome/utility/media_galleries/iapps_xml_utils.h"
40#include "chrome/utility/media_galleries/itunes_library_parser.h"
41#include "chrome/utility/media_galleries/picasa_album_table_reader.h"
42#include "chrome/utility/media_galleries/picasa_albums_indexer.h"
43#endif  // defined(OS_WIN) || defined(OS_MACOSX)
44
45namespace extensions {
46
47namespace {
48
49bool Send(IPC::Message* message) {
50  return content::UtilityThread::Get()->Send(message);
51}
52
53void ReleaseProcessIfNeeded() {
54  content::UtilityThread::Get()->ReleaseProcessIfNeeded();
55}
56
57const char kExtensionHandlerUnzipError[] =
58    "Could not unzip extension for install.";
59
60}  // namespace
61
62ExtensionsHandler::ExtensionsHandler() {
63}
64
65ExtensionsHandler::~ExtensionsHandler() {
66}
67
68// static
69void ExtensionsHandler::PreSandboxStartup() {
70  // Initialize libexif for image metadata parsing.
71  metadata::ImageMetadataExtractor::InitializeLibrary();
72
73  // Load media libraries for media file validation.
74  base::FilePath media_path;
75  PathService::Get(content::DIR_MEDIA_LIBS, &media_path);
76  if (!media_path.empty())
77    media::InitializeMediaLibrary(media_path);
78}
79
80void ExtensionsHandler::UtilityThreadStarted() {
81  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
82  std::string lang = command_line->GetSwitchValueASCII(switches::kLang);
83  if (!lang.empty())
84    extension_l10n_util::SetProcessLocale(lang);
85}
86
87bool ExtensionsHandler::OnMessageReceived(const IPC::Message& message) {
88  bool handled = true;
89  IPC_BEGIN_MESSAGE_MAP(ExtensionsHandler, message)
90    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnpackExtension, OnUnpackExtension)
91    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnzipToDir, OnUnzipToDir)
92    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImageBase64, OnDecodeImageBase64)
93    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseJSON, OnParseJSON)
94    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CheckMediaFile, OnCheckMediaFile)
95#if defined(OS_WIN)
96    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseITunesPrefXml,
97                        OnParseITunesPrefXml)
98#endif  // defined(OS_WIN)
99
100#if defined(OS_MACOSX)
101    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseIPhotoLibraryXmlFile,
102                        OnParseIPhotoLibraryXmlFile)
103#endif  // defined(OS_MACOSX)
104
105#if defined(OS_WIN) || defined(OS_MACOSX)
106    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseITunesLibraryXmlFile,
107                        OnParseITunesLibraryXmlFile)
108    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParsePicasaPMPDatabase,
109                        OnParsePicasaPMPDatabase)
110    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_IndexPicasaAlbumsContents,
111                        OnIndexPicasaAlbumsContents)
112#endif  // defined(OS_WIN) || defined(OS_MACOSX)
113
114#if defined(OS_WIN)
115    IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetWiFiCredentials,
116                        OnGetWiFiCredentials)
117#endif  // defined(OS_WIN)
118
119    IPC_MESSAGE_HANDLER(ExtensionUtilityMsg_ParseUpdateManifest,
120                        OnParseUpdateManifest)
121
122    IPC_MESSAGE_UNHANDLED(handled = false)
123  IPC_END_MESSAGE_MAP()
124  return handled;
125}
126
127void ExtensionsHandler::OnUnpackExtension(
128    const base::FilePath& extension_path,
129    const std::string& extension_id,
130    int location,
131    int creation_flags) {
132  CHECK_GT(location, Manifest::INVALID_LOCATION);
133  CHECK_LT(location, Manifest::NUM_LOCATIONS);
134  ExtensionsClient::Set(ChromeExtensionsClient::GetInstance());
135  Unpacker unpacker(extension_path,
136                    extension_id,
137                    static_cast<Manifest::Location>(location),
138                    creation_flags);
139  if (unpacker.Run() && unpacker.DumpImagesToFile() &&
140      unpacker.DumpMessageCatalogsToFile()) {
141    Send(new ChromeUtilityHostMsg_UnpackExtension_Succeeded(
142        *unpacker.parsed_manifest()));
143  } else {
144    Send(new ChromeUtilityHostMsg_UnpackExtension_Failed(
145        unpacker.error_message()));
146  }
147
148  ReleaseProcessIfNeeded();
149}
150
151void ExtensionsHandler::OnUnzipToDir(const base::FilePath& zip_path,
152                                     const base::FilePath& dir) {
153  if (!zip::Unzip(zip_path, dir)) {
154    Send(new ChromeUtilityHostMsg_UnzipToDir_Failed(
155        std::string(kExtensionHandlerUnzipError)));
156  } else {
157    Send(new ChromeUtilityHostMsg_UnzipToDir_Succeeded(dir));
158  }
159
160  ReleaseProcessIfNeeded();
161}
162
163void ExtensionsHandler::OnParseUpdateManifest(const std::string& xml) {
164  UpdateManifest manifest;
165  if (!manifest.Parse(xml)) {
166    Send(new ExtensionUtilityHostMsg_ParseUpdateManifest_Failed(
167        manifest.errors()));
168  } else {
169    Send(new ExtensionUtilityHostMsg_ParseUpdateManifest_Succeeded(
170        manifest.results()));
171  }
172  ReleaseProcessIfNeeded();
173}
174
175void ExtensionsHandler::OnDecodeImageBase64(
176    const std::string& encoded_string) {
177  std::string decoded_string;
178
179  if (!base::Base64Decode(encoded_string, &decoded_string)) {
180    Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
181    return;
182  }
183
184  std::vector<unsigned char> decoded_vector(decoded_string.size());
185  for (size_t i = 0; i < decoded_string.size(); ++i) {
186    decoded_vector[i] = static_cast<unsigned char>(decoded_string[i]);
187  }
188
189  ChromeContentUtilityClient::DecodeImageAndSend(decoded_vector, false);
190}
191
192void ExtensionsHandler::OnParseJSON(const std::string& json) {
193  int error_code;
194  std::string error;
195  base::Value* value = base::JSONReader::ReadAndReturnError(
196      json, base::JSON_PARSE_RFC, &error_code, &error);
197  if (value) {
198    base::ListValue wrapper;
199    wrapper.Append(value);
200    Send(new ChromeUtilityHostMsg_ParseJSON_Succeeded(wrapper));
201  } else {
202    Send(new ChromeUtilityHostMsg_ParseJSON_Failed(error));
203  }
204  ReleaseProcessIfNeeded();
205}
206
207void ExtensionsHandler::OnCheckMediaFile(
208    int64 milliseconds_of_decoding,
209    const IPC::PlatformFileForTransit& media_file) {
210  media::MediaFileChecker checker(
211      IPC::PlatformFileForTransitToFile(media_file));
212  const bool check_success = checker.Start(
213      base::TimeDelta::FromMilliseconds(milliseconds_of_decoding));
214  Send(new ChromeUtilityHostMsg_CheckMediaFile_Finished(check_success));
215  ReleaseProcessIfNeeded();
216}
217
218#if defined(OS_WIN)
219void ExtensionsHandler::OnParseITunesPrefXml(
220    const std::string& itunes_xml_data) {
221  base::FilePath library_path(
222      itunes::FindLibraryLocationInPrefXml(itunes_xml_data));
223  Send(new ChromeUtilityHostMsg_GotITunesDirectory(library_path));
224  ReleaseProcessIfNeeded();
225}
226#endif  // defined(OS_WIN)
227
228#if defined(OS_MACOSX)
229void ExtensionsHandler::OnParseIPhotoLibraryXmlFile(
230    const IPC::PlatformFileForTransit& iphoto_library_file) {
231  iphoto::IPhotoLibraryParser parser;
232  base::File file = IPC::PlatformFileForTransitToFile(iphoto_library_file);
233  bool result = parser.Parse(iapps::ReadFileAsString(file.Pass()));
234  Send(new ChromeUtilityHostMsg_GotIPhotoLibrary(result, parser.library()));
235  ReleaseProcessIfNeeded();
236}
237#endif  // defined(OS_MACOSX)
238
239#if defined(OS_WIN) || defined(OS_MACOSX)
240void ExtensionsHandler::OnParseITunesLibraryXmlFile(
241    const IPC::PlatformFileForTransit& itunes_library_file) {
242  itunes::ITunesLibraryParser parser;
243  base::File file = IPC::PlatformFileForTransitToFile(itunes_library_file);
244  bool result = parser.Parse(iapps::ReadFileAsString(file.Pass()));
245  Send(new ChromeUtilityHostMsg_GotITunesLibrary(result, parser.library()));
246  ReleaseProcessIfNeeded();
247}
248
249void ExtensionsHandler::OnParsePicasaPMPDatabase(
250    const picasa::AlbumTableFilesForTransit& album_table_files) {
251  picasa::AlbumTableFiles files;
252  files.indicator_file =
253      IPC::PlatformFileForTransitToFile(album_table_files.indicator_file);
254  files.category_file =
255      IPC::PlatformFileForTransitToFile(album_table_files.category_file);
256  files.date_file =
257      IPC::PlatformFileForTransitToFile(album_table_files.date_file);
258  files.filename_file =
259      IPC::PlatformFileForTransitToFile(album_table_files.filename_file);
260  files.name_file =
261      IPC::PlatformFileForTransitToFile(album_table_files.name_file);
262  files.token_file =
263      IPC::PlatformFileForTransitToFile(album_table_files.token_file);
264  files.uid_file =
265      IPC::PlatformFileForTransitToFile(album_table_files.uid_file);
266
267  picasa::PicasaAlbumTableReader reader(files.Pass());
268  bool parse_success = reader.Init();
269  Send(new ChromeUtilityHostMsg_ParsePicasaPMPDatabase_Finished(
270      parse_success, reader.albums(), reader.folders()));
271  ReleaseProcessIfNeeded();
272}
273
274void ExtensionsHandler::OnIndexPicasaAlbumsContents(
275    const picasa::AlbumUIDSet& album_uids,
276    const std::vector<picasa::FolderINIContents>& folders_inis) {
277  picasa::PicasaAlbumsIndexer indexer(album_uids);
278  indexer.ParseFolderINI(folders_inis);
279
280  Send(new ChromeUtilityHostMsg_IndexPicasaAlbumsContents_Finished(
281      indexer.albums_images()));
282  ReleaseProcessIfNeeded();
283}
284#endif  // defined(OS_WIN) || defined(OS_MACOSX)
285
286#if defined(OS_WIN)
287void ExtensionsHandler::OnGetWiFiCredentials(const std::string& network_guid) {
288  scoped_ptr<wifi::WiFiService> wifi_service(wifi::WiFiService::Create());
289  wifi_service->Initialize(NULL);
290
291  std::string key_data;
292  std::string error;
293  wifi_service->GetKeyFromSystem(network_guid, &key_data, &error);
294
295  Send(new ChromeUtilityHostMsg_GotWiFiCredentials(key_data, error.empty()));
296}
297#endif  // defined(OS_WIN)
298
299}  // namespace extensions
300