File: safari_data_importer.h

package info (click to toggle)
chromium 141.0.7390.107-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,246,132 kB
  • sloc: cpp: 35,264,965; ansic: 7,169,920; javascript: 4,250,185; python: 1,460,635; asm: 950,788; xml: 751,751; pascal: 187,972; sh: 89,459; perl: 88,691; objc: 79,953; sql: 53,924; cs: 44,622; fortran: 24,137; makefile: 22,313; tcl: 15,277; php: 14,018; yacc: 8,995; ruby: 7,553; awk: 3,720; lisp: 3,096; lex: 1,330; ada: 727; jsp: 228; sed: 36
file content (307 lines) | stat: -rw-r--r-- 12,241 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_USER_DATA_IMPORTER_UTILITY_SAFARI_DATA_IMPORTER_H_
#define COMPONENTS_USER_DATA_IMPORTER_UTILITY_SAFARI_DATA_IMPORTER_H_

#include "base/files/scoped_temp_dir.h"
#include "base/threading/sequence_bound.h"
#include "components/password_manager/core/browser/import/password_importer.h"
#include "components/prefs/pref_service.h"
#include "components/user_data_importer/utility/bookmark_parser.h"
#include "components/user_data_importer/utility/importer_metrics_recorder.h"
#include "components/user_data_importer/utility/parsing_ffi/lib.rs.h"
#include "components/user_data_importer/utility/safari_data_import_client.h"

namespace autofill {
class CreditCard;
class PaymentsDataManager;
}  // namespace autofill

namespace base {
class SequencedTaskRunner;
}  // namespace base

namespace bookmarks {
class BookmarkModel;
}  // namespace bookmarks

namespace history {
class HistoryService;
}  // namespace history

namespace syncer {
class SyncService;
}

class ReadingListModel;

namespace user_data_importer {

struct ImportedBookmarkEntry;

// See impl.
class RustHistoryCallback;

// Main model-layer object for extracting and importing user data from a bundle
// of data exported by Safari. The bundle is a ZIP file containing various data
// types in individual files, the format of which is documented here:
// https://developer.apple.com/documentation/safariservices/importing-data-exported-from-safari?language=objc
// Users of this class must also provide an object implementing the
// `BookmarkParser` interface, which abstracts out certain logic which
// can't live in the components layer (because of platform dependencies).
class SafariDataImporter {
 public:
  using PasswordImportCallback =
      password_manager::PasswordImporter::ImportResultsCallback;
  using PasswordImportResults = password_manager::ImportResults;

  // All arguments passed as pointers are expected to outlive this importer.
  SafariDataImporter(SafariDataImportClient* client,
                     password_manager::SavedPasswordsPresenter* presenter,
                     autofill::PaymentsDataManager* payments_data_manager,
                     history::HistoryService* history_service,
                     bookmarks::BookmarkModel* bookmark_model,
                     ReadingListModel* reading_list_model,
                     syncer::SyncService* sync_service,
                     PrefService* pref_service,
                     std::unique_ptr<BookmarkParser> bookmark_parser,
                     std::string app_locale);
  ~SafariDataImporter();

  // Opens the ZIP file provided in `path` and prepares to import the data
  // (passwords, payment cards, bookmarks, and history) contained inside. Each
  // data type is optional and may or may not be present.
  void PrepareImport(const base::FilePath& path);

  // Logs the file size of the uncompressed ZIP file.
  void LogFileSize(int64_t file_size_bytes);

  // Called after calling `PrepareImport` in order to complete the import
  // process. In case of password conflicts, `selected_password_ids` provides
  // the list of conflicting passwords to import.
  void CompleteImport(const std::vector<int>& selected_password_ids);

  // Called after calling "Import" in order to cancel the import process.
  void CancelImport();

 private:
  friend class SafariDataImporterTest;

  // Encapsulates work which must occur in a blocking context (mainly I/O).
  // Intentionally does not provide access to any state or methods of
  // `SafariDataImporter`.
  class BlockingWorker {
   public:
    explicit BlockingWorker(std::unique_ptr<BookmarkParser> bookmark_parser);
    ~BlockingWorker();

    // Creates the zip file Rust archive from file provided by "zip_filename".
    // Returns whether the archive was created successfully; if false, the
    // import has failed and should terminate.
    bool CreateZipFileArchive(std::string zip_filename);

    // Closes the zip file archive when it is no longer needed. Calling this is
    // not mandatory; the archive will be cleaned up on the correct thread when
    // the BlockingWorker is destroyed, if it exists.
    void CloseZipFileArchive();

    // Returns the contents of the file of the desired type contained in the
    // zip file archive. Returns an empty string on failure.
    std::string Unzip(FileType filetype);

    // Returns the uncompressed size of a file within the zip file archive.
    size_t GetUncompressedFileSizeInBytes(FileType filetype);

    // Gets the size of the file at `path`. Returns nullopt on failure.
    std::optional<int64_t> GetInitialFileSize(const base::FilePath& path);

    struct BookmarkUnzipResult {
      std::optional<base::FilePath> path;
      size_t file_size_bytes;

      explicit BookmarkUnzipResult(std::optional<base::FilePath> p,
                                   size_t size);
      ~BookmarkUnzipResult();

      BookmarkUnzipResult(BookmarkUnzipResult&&);
      BookmarkUnzipResult& operator=(BookmarkUnzipResult&&);
      BookmarkUnzipResult(const BookmarkUnzipResult&) = delete;
      BookmarkUnzipResult& operator=(const BookmarkUnzipResult&) = delete;
    };

    // Unzips bookmarks in the ZIP archive and writes the contents to a
    // `bookmarks.html` file in a tmp directory. Returns nullopt if the file
    // could not be created.
    BookmarkUnzipResult WriteBookmarksToTmpFile();

    struct PaymentCardParseResult {
      std::vector<PaymentCardEntry> entries;
      size_t file_size_bytes;

      explicit PaymentCardParseResult(std::vector<PaymentCardEntry> e,
                                      size_t size);
      ~PaymentCardParseResult();

      PaymentCardParseResult(PaymentCardParseResult&&);
      PaymentCardParseResult& operator=(PaymentCardParseResult&&);
      PaymentCardParseResult(const PaymentCardParseResult&) = delete;
      PaymentCardParseResult& operator=(const PaymentCardParseResult&) = delete;
    };

    void ParseBookmarks(
        std::optional<base::FilePath> bookmarks_html,
        BookmarkParser::BookmarkParsingCallback bookmarks_callback);

    // Finds a file containing payment cards in the ZIP archive, parses it, and
    // returns the output. Returns empty on error.
    PaymentCardParseResult ParsePaymentCards();

    // Attempts to import history from the zip file archive.
    // `parse_history_callback` may be called multiple times during this
    // process, as batches of history entries become ready. `done_callback`
    // is called once, at the end.
    void ImportHistory(std::unique_ptr<RustHistoryCallback> callback,
                       size_t history_size_threshold);

    // The model-layer object used to parse bookmarks from an HTML file.
    std::unique_ptr<BookmarkParser> bookmark_parser_;

    // The Rust zip file archive.
    std::optional<rust::Box<ZipFileArchive>> zip_file_archive_;

    // Stores bookmarks data on disk after unzip but before parsing.
    std::unique_ptr<base::ScopedTempDir> bookmarks_temp_dir_;
  };

  // Once the ZIP archive has been created, checks its validity and triggers the
  // next step in the parsing pipeline.
  void OnZipArchiveReady(bool success);

  // Parses the provided `csv_data` and determines if any conflicts with
  // existing passwords will occur. Stops before actually committing any data.
  // Informs `client_` that passwords are ready when done.
  void PreparePasswords(std::string csv_data);

  // Converts payment_cards to autofill::CreditCard objects. Informs `client_`
  // that cards are ready when done.
  void PreparePaymentCards(
      BlockingWorker::PaymentCardParseResult payment_cards);

  // Attempts to parse the provided HTML data. Informs `client_` that bookmarks
  // are ready when done.
  void PrepareBookmarks(BlockingWorker::BookmarkUnzipResult result);

  // Receives the result of the first pass of the password importer, which
  // parses passwords and identifies any conflicts, then pauses. Informs the
  // client that passwords are ready.
  void OnPasswordsParsed(const password_manager::ImportResults& results);

  // Receives the result of parsing bookmarks, stores them for later use,
  // and informs the client that bookmarks are ready.
  void OnBookmarksParsed(BookmarkParser::BookmarkParsingResult result);

  // Logs an error and indicates to the client that no bookmarks are available.
  void OnBookmarkParsingError(BookmarkParser::BookmarkParsingError error);

  // Calls `history_callback` with an approximation of the number of URLs
  // contained in one or more files with total size `file_size_bytes`.
  void PrepareHistory(size_t file_size_bytes);

  // Transforms the SafariHistoryEntry objects into URLRow objects and uses the
  // history service to import them.
  void ImportHistoryEntries(std::vector<SafariHistoryEntry> history_entries);

  // Invoked if parsing of history fails. Forwards the results to `client_`.
  void OnHistoryImportFailed();

  // Invoked once parsing of history is completed. Forwards the results to
  // `client_`.
  void OnHistoryImportCompleted();

  // Invoked once parsing of passwords is completed. Forwards the results to
  // `client_`.
  void OnPasswordImportCompleted(
      const password_manager::ImportResults& results);

  // Imports Credit Cards to the Payments Data Manager.
  void ContinueImportPaymentCards();

  // Imports bookmarks and reading list entries from pending data into the
  // corresponding BookmarkModel and ReadingListModel.
  void ContinueImportBookmarks();

  // Invoked when all import processing tasks have concluded. Logs metrics.
  void OnImportComplete();

  // Objects used by this importer to do work (esp. parsing)

  // A queue for tasks which may block (e.g., I/O).
  scoped_refptr<base::SequencedTaskRunner> blocking_queue_;

  // An instance of BlockingWorker which is bound to `blocking_queue_`.
  base::SequenceBound<BlockingWorker> blocking_worker_;

  // The password importer used to import passwords and resolve conflicts.
  std::unique_ptr<password_manager::PasswordImporter> password_importer_;

  // Interaction with UI layer

  // The client to inform when various processing events occur.
  const raw_ref<SafariDataImportClient> client_;

  // Model-layer objects used to actually save imported data

  // The payments data manager.
  const raw_ref<autofill::PaymentsDataManager> payments_data_manager_;

  // Service used to import history URLs.
  const raw_ref<history::HistoryService> history_service_;

  // Service used to import bookmarks.
  const raw_ref<bookmarks::BookmarkModel> bookmark_model_;

  // Service used to import reading lists.
  const raw_ref<ReadingListModel> reading_list_model_;

  // Stores pointer to `SyncService` instance.
  raw_ptr<syncer::SyncService> sync_service_;

  // The PrefService that this instance uses to read and write preferences.
  // Must outlive this instance.
  raw_ptr<PrefService> pref_service_ = nullptr;

  // Internal state

  // Stores the credit cards parsed from the "PaymentCards" JSON file.
  std::vector<autofill::CreditCard> cards_to_import_;

  // Bookmarks which have been parsed, but not yet committed to permanent
  // storage.
  std::vector<ImportedBookmarkEntry> pending_bookmarks_;

  // Reading List entries which have been parsed, but not yet committed to
  // permanent storage.
  std::vector<ImportedBookmarkEntry> pending_reading_list_;

  // Helper object which logs metrics about the import flow.
  ImporterMetricsRecorder metrics_recorder_;

  // The application locale, used to set credit card information.
  const std::string app_locale_;

  // Number of URLs imported during the history import process.
  size_t history_urls_imported_;

  // Maximum size the history entries vector can reach before calling
  // "ParseHistoryCallback". Can be modified for testing purposes.
  size_t history_size_threshold_ = 1000;

  // Creates WeakPtr to this. Use with caution across sequence boundaries.
  base::WeakPtrFactory<SafariDataImporter> weak_factory_{this};
};

}  // namespace user_data_importer

#endif  // COMPONENTS_USER_DATA_IMPORTER_UTILITY_SAFARI_DATA_IMPORTER_H_