blob: 9e58b611dc05dc2aa8df6504e6edb3b0337fee41 [file] [log] [blame]
// Copyright 2014 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_BOOKMARKS_BROWSER_BOOKMARK_CODEC_H_
#define COMPONENTS_BOOKMARKS_BROWSER_BOOKMARK_CODEC_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include "base/uuid.h"
#include "base/values.h"
#include "components/bookmarks/browser/bookmark_node.h"
#include "crypto/hash.h"
#include "crypto/obsolete/md5.h"
namespace bookmarks {
// BookmarkCodec is responsible for encoding and decoding the BookmarkModel
// into JSON values. The encoded values are written to disk via the
// BookmarkStorage.
class BookmarkCodec {
public:
// Creates an instance of the codec. During decoding, if the IDs in the file
// are not unique, we will reassign IDs to make them unique. There are no
// guarantees on how the IDs are reassigned or about doing minimal
// reassignments to achieve uniqueness.
BookmarkCodec();
BookmarkCodec(const BookmarkCodec&) = delete;
BookmarkCodec& operator=(const BookmarkCodec&) = delete;
~BookmarkCodec();
// Encodes the bookmark bar and other folders returning the JSON value.
// Either none or all permanent nodes must be null. The null case it useful to
// encode sync metadata only (which is useful in error cases, when a user may
// contain too many bookmarks in sync, server-side).
base::Value::Dict Encode(
const BookmarkNode* bookmark_bar_node,
const BookmarkNode* other_folder_node,
const BookmarkNode* mobile_folder_node,
std::string sync_metadata_str);
// Decodes the previously encoded value to the specified nodes as well as
// setting `max_node_id` to the greatest node id. Returns true on success,
// false otherwise. If there is an error (such as unexpected version) all
// children are removed from the bookmark bar and other folder nodes. On exit
// `max_node_id` is set to the max id of the nodes.
//
// `already_assigned_ids` can be used to consider certain node ids as
// reserved, and ensure that decoding won't produce nodes that collide with
// these ids. If such collisions exist, ids will be reassigned as if the file
// itself contained id collisions, noticeable via `ids_reassigned()` returning
// true.
bool Decode(const base::Value::Dict& value,
std::set<int64_t> already_assigned_ids,
BookmarkNode* bb_node,
BookmarkNode* other_folder_node,
BookmarkNode* mobile_folder_node,
int64_t* max_node_id,
std::string* sync_metadata_str);
// The required-recovery bit represents whether the on-disk state was corrupt
// and had to be recovered. Scenarios include ID or UUID collisions and
// checksum mismatches.
bool required_recovery() const;
// Returns whether the IDs were reassigned during decoding. Always returns
// false after encoding.
bool ids_reassigned() const { return ids_reassigned_; }
// If IDs are reassigned during decoding, it returns the mapping from old
// (i.e. on-disk) ID to the newly-assigned ones.
std::multimap<int64_t, int64_t> release_reassigned_ids_per_old_id() {
return std::move(reassigned_ids_per_old_id_);
}
// Test-only APIs.
const std::string& ComputedChecksumForTest() const {
return computed_checksum_;
}
const std::string& StoredChecksumForTest() const { return stored_checksum_; }
const std::string& ComputedSha256ChecksumForTest() const {
return computed_sha256_checksum_;
}
const std::string& StoredSha256ChecksumForTest() const {
return stored_sha256_checksum_;
}
std::set<int64_t> release_assigned_ids() { return std::move(ids_); }
// Names of the various keys written to the Value.
static const char kRootsKey[];
static const char kBookmarkBarFolderNameKey[];
static const char kOtherBookmarkFolderNameKey[];
static const char kMobileBookmarkFolderNameKey[];
static const char kVersionKey[];
static const char kChecksumKey[];
static const char kChecksumSHA256Key[];
static const char kIdKey[];
static const char kTypeKey[];
static const char kNameKey[];
static const char kGuidKey[];
static const char kDateAddedKey[];
static const char kURLKey[];
static const char kDateModifiedKey[];
static const char kChildrenKey[];
static const char kMetaInfo[];
// Allows the BookmarkClient to read and a write a string blob from the JSON
// file. That string captures the bookmarks sync metadata.
static const char kSyncMetadata[];
static const char kDateLastUsed[];
// Possible values for kTypeKey.
static const char kTypeURL[];
static const char kTypeFolder[];
private:
// Encodes node and all its children into a Value object and returns it.
base::Value::Dict EncodeNode(const BookmarkNode* node);
// Encodes the given meta info into a Value object and returns it.
base::Value::Dict EncodeMetaInfo(
const BookmarkNode::MetaInfoMap& meta_info_map);
// Helper to perform decoding.
bool DecodeHelper(BookmarkNode* bb_node,
BookmarkNode* other_folder_node,
BookmarkNode* mobile_folder_node,
const base::Value::Dict& value,
std::string* sync_metadata_str);
// Decodes the children of the specified node. Returns true on success.
bool DecodeChildren(const base::Value::List& child_value_list,
BookmarkNode* parent);
// Reassigns bookmark IDs for all nodes.
void ReassignIDs(BookmarkNode* bb_node,
BookmarkNode* other_node,
BookmarkNode* mobile_node);
// Helper to recursively reassign IDs.
void ReassignIDsHelper(BookmarkNode* node);
// Decodes the supplied node from the supplied value, which needs to be a
// dictionary value. Child nodes are created appropriately by way of
// DecodeChildren. If node is NULL a new node is created and added to parent
// (parent must then be non-NULL), otherwise node is used.
bool DecodeNode(const base::Value::Dict& value,
BookmarkNode* parent,
BookmarkNode* node);
// Decodes the meta info from the supplied value. meta_info_map must not be
// nullptr.
bool DecodeMetaInfo(const base::Value::Dict& value,
BookmarkNode::MetaInfoMap* meta_info_map);
// Decodes the meta info from the supplied sub-node dictionary. The values
// found will be inserted in meta_info_map with the given prefix added to the
// start of their keys.
void DecodeMetaInfoHelper(const base::Value::Dict& dict,
const std::string& prefix,
BookmarkNode::MetaInfoMap* meta_info_map);
// Updates the check-sum with the given string.
void UpdateChecksum(const std::string& str);
void UpdateChecksum(const std::u16string& str);
// Updates the check-sum with the given contents of URL/folder bookmark node.
// NOTE: These functions take in individual properties of a bookmark node
// instead of taking in a BookmarkNode for efficiency so that we don't convert
// various data-types to UTF16 strings multiple times - once for serializing
// and once for computing the check-sum.
// The url parameter should be a valid UTF8 string.
void UpdateChecksumWithUrlNode(const std::string& id,
const std::u16string& title,
const std::string& url);
void UpdateChecksumWithFolderNode(const std::string& id,
const std::u16string& title);
// Initializes/Finalizes the checksum.
void InitializeChecksum();
void FinalizeChecksum();
// Whether or not IDs were reassigned by the codec.
bool ids_reassigned_{false};
// Mapping from old ID to new IDs if IDs were reassigned. Note that old IDs
// may contain duplicates, and therefore the mapping could be ambiguous.
std::multimap<int64_t, int64_t> reassigned_ids_per_old_id_;
// Whether or not UUIDs were reassigned by the codec.
bool uuids_reassigned_{false};
// Whether or not IDs are valid. This is initially true, but set to false
// if an id is missing or not unique.
bool ids_valid_{true};
// Contains the id of each of the nodes found in the file. Used to determine
// if we have duplicates.
std::set<int64_t> ids_;
// Contains the UUID of each of the nodes found in the file. Used to determine
// if we have duplicates.
std::set<base::Uuid> uuids_;
// MD5 context used to compute MD5 hash of all bookmark data.
crypto::obsolete::Md5 md5_hasher_;
// SHA context used to compute SHA256 hash of all bookmark data.
// Intended to replace MD5 hasher (crbug.com/426243026)
crypto::hash::Hasher sha256_hasher_{crypto::hash::kSha256};
// MD5 checksum computed during last encoding/decoding call.
std::string computed_checksum_;
// SHA256 checksum computed during last encoding/decoding call.
std::string computed_sha256_checksum_;
// The checksum that's stored in the file. After a call to Encode, the
// computed and stored checksums are the same since the computed checksum is
// stored to the file. After a call to decode, the computed checksum can
// differ from the stored checksum if the file contents were changed by the
// user.
std::string stored_checksum_;
// Same as above but encoded using SHA256 rather than MD5.
std::string stored_sha256_checksum_;
// Maximum ID assigned when decoding data.
int64_t maximum_id_{0};
};
} // namespace bookmarks
#endif // COMPONENTS_BOOKMARKS_BROWSER_BOOKMARK_CODEC_H_