Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / extensions / browser / computed_hashes.cc
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 "extensions/browser/computed_hashes.h"
6
7 #include "base/base64.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/json/json_reader.h"
11 #include "base/json/json_writer.h"
12 #include "base/stl_util.h"
13 #include "base/values.h"
14 #include "crypto/secure_hash.h"
15 #include "crypto/sha2.h"
16
17 namespace {
18 const char kBlockHashesKey[] = "block_hashes";
19 const char kBlockSizeKey[] = "block_size";
20 const char kFileHashesKey[] = "file_hashes";
21 const char kPathKey[] = "path";
22 const char kVersionKey[] = "version";
23 const int kVersion = 2;
24 }  // namespace
25
26 namespace extensions {
27
28 ComputedHashes::Reader::Reader() {
29 }
30
31 ComputedHashes::Reader::~Reader() {
32 }
33
34 bool ComputedHashes::Reader::InitFromFile(const base::FilePath& path) {
35   std::string contents;
36   if (!base::ReadFileToString(path, &contents))
37     return false;
38
39   base::DictionaryValue* top_dictionary = NULL;
40   scoped_ptr<base::Value> value(base::JSONReader::Read(contents));
41   if (!value.get() || !value->GetAsDictionary(&top_dictionary))
42     return false;
43
44   // For now we don't support forwards or backwards compatability in the
45   // format, so we return false on version mismatch.
46   int version = 0;
47   if (!top_dictionary->GetInteger(kVersionKey, &version) || version != kVersion)
48     return false;
49
50   base::ListValue* all_hashes = NULL;
51   if (!top_dictionary->GetList(kFileHashesKey, &all_hashes))
52     return false;
53
54   for (size_t i = 0; i < all_hashes->GetSize(); i++) {
55     base::DictionaryValue* dictionary = NULL;
56     if (!all_hashes->GetDictionary(i, &dictionary))
57       return false;
58
59     std::string relative_path_utf8;
60     if (!dictionary->GetString(kPathKey, &relative_path_utf8))
61       return false;
62
63     int block_size;
64     if (!dictionary->GetInteger(kBlockSizeKey, &block_size))
65       return false;
66     if (block_size <= 0 || ((block_size % 1024) != 0)) {
67       LOG(ERROR) << "Invalid block size: " << block_size;
68       block_size = 0;
69       return false;
70     }
71
72     base::ListValue* hashes_list = NULL;
73     if (!dictionary->GetList(kBlockHashesKey, &hashes_list))
74       return false;
75
76     base::FilePath relative_path =
77         base::FilePath::FromUTF8Unsafe(relative_path_utf8);
78     relative_path = relative_path.NormalizePathSeparatorsTo('/');
79
80     data_[relative_path] = HashInfo(block_size, std::vector<std::string>());
81     std::vector<std::string>* hashes = &(data_[relative_path].second);
82
83     for (size_t j = 0; j < hashes_list->GetSize(); j++) {
84       std::string encoded;
85       if (!hashes_list->GetString(j, &encoded))
86         return false;
87
88       hashes->push_back(std::string());
89       std::string* decoded = &hashes->back();
90       if (!base::Base64Decode(encoded, decoded)) {
91         hashes->clear();
92         return false;
93       }
94     }
95   }
96   return true;
97 }
98
99 bool ComputedHashes::Reader::GetHashes(const base::FilePath& relative_path,
100                                        int* block_size,
101                                        std::vector<std::string>* hashes) {
102   base::FilePath path = relative_path.NormalizePathSeparatorsTo('/');
103   std::map<base::FilePath, HashInfo>::iterator i = data_.find(path);
104   if (i == data_.end())
105     return false;
106   HashInfo& info = i->second;
107   *block_size = info.first;
108   *hashes = info.second;
109   return true;
110 }
111
112 ComputedHashes::Writer::Writer() : file_list_(new base::ListValue) {
113 }
114
115 ComputedHashes::Writer::~Writer() {
116 }
117
118 void ComputedHashes::Writer::AddHashes(const base::FilePath& relative_path,
119                                        int block_size,
120                                        const std::vector<std::string>& hashes) {
121   base::DictionaryValue* dict = new base::DictionaryValue();
122   base::ListValue* block_hashes = new base::ListValue();
123   file_list_->Append(dict);
124   dict->SetString(kPathKey,
125                   relative_path.NormalizePathSeparatorsTo('/').AsUTF8Unsafe());
126   dict->SetInteger(kBlockSizeKey, block_size);
127   dict->Set(kBlockHashesKey, block_hashes);
128
129   for (std::vector<std::string>::const_iterator i = hashes.begin();
130        i != hashes.end();
131        ++i) {
132     std::string encoded;
133     base::Base64Encode(*i, &encoded);
134     block_hashes->AppendString(encoded);
135   }
136 }
137
138 bool ComputedHashes::Writer::WriteToFile(const base::FilePath& path) {
139   std::string json;
140   base::DictionaryValue top_dictionary;
141   top_dictionary.SetInteger(kVersionKey, kVersion);
142   top_dictionary.Set(kFileHashesKey, file_list_.release());
143
144   if (!base::JSONWriter::Write(&top_dictionary, &json))
145     return false;
146   int written = base::WriteFile(path, json.data(), json.size());
147   if (static_cast<unsigned>(written) != json.size()) {
148     LOG(ERROR) << "Error writing " << path.AsUTF8Unsafe()
149                << " ; write result:" << written << " expected:" << json.size();
150     return false;
151   }
152   return true;
153 }
154
155 void ComputedHashes::ComputeHashesForContent(const std::string& contents,
156                                              size_t block_size,
157                                              std::vector<std::string>* hashes) {
158   size_t offset = 0;
159   // Even when the contents is empty, we want to output at least one hash
160   // block (the hash of the empty string).
161   do {
162     const char* block_start = contents.data() + offset;
163     DCHECK(offset <= contents.size());
164     size_t bytes_to_read = std::min(contents.size() - offset, block_size);
165     scoped_ptr<crypto::SecureHash> hash(
166         crypto::SecureHash::Create(crypto::SecureHash::SHA256));
167     hash->Update(block_start, bytes_to_read);
168
169     hashes->push_back(std::string());
170     std::string* buffer = &(hashes->back());
171     buffer->resize(crypto::kSHA256Length);
172     hash->Finish(string_as_array(buffer), buffer->size());
173
174     // If |contents| is empty, then we want to just exit here.
175     if (bytes_to_read == 0)
176       break;
177
178     offset += bytes_to_read;
179   } while (offset < contents.size());
180 }
181
182 }  // namespace extensions