| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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/browser/profile_resetter/jtl_interpreter.h" | |
| 6 | |
| 7 #include <numeric> | |
| 8 | |
| 9 #include "base/memory/scoped_vector.h" | |
| 10 #include "base/strings/string_number_conversions.h" | |
| 11 #include "base/strings/string_util.h" | |
| 12 #include "chrome/browser/profile_resetter/jtl_foundation.h" | |
| 13 #include "crypto/hmac.h" | |
| 14 #include "crypto/sha2.h" | |
| 15 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | |
| 16 #include "url/gurl.h" | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 class ExecutionContext; | |
| 21 | |
| 22 // An operation in an interpreted program. | |
| 23 class Operation { | |
| 24 public: | |
| 25 virtual ~Operation() {} | |
| 26 // Executes the operation on the specified context and instructs the context | |
| 27 // to continue execution with the next instruction if appropriate. | |
| 28 // Returns true if we should continue with any potential backtracking that | |
| 29 // needs to be done. | |
| 30 virtual bool Execute(ExecutionContext* context) = 0; | |
| 31 }; | |
| 32 | |
| 33 // An execution context of operations. | |
| 34 class ExecutionContext { | |
| 35 public: | |
| 36 // |input| is the root of a dictionary that stores the information the | |
| 37 // sentence is evaluated on. | |
| 38 ExecutionContext(const jtl_foundation::Hasher* hasher, | |
| 39 const std::vector<Operation*>& sentence, | |
| 40 const base::DictionaryValue* input, | |
| 41 base::DictionaryValue* working_memory) | |
| 42 : hasher_(hasher), | |
| 43 sentence_(sentence), | |
| 44 next_instruction_index_(0u), | |
| 45 working_memory_(working_memory), | |
| 46 error_(false) { | |
| 47 stack_.push_back(input); | |
| 48 } | |
| 49 ~ExecutionContext() {} | |
| 50 | |
| 51 // Returns true in case of success. | |
| 52 bool ContinueExecution() { | |
| 53 if (error_ || stack_.empty()) { | |
| 54 error_ = true; | |
| 55 return false; | |
| 56 } | |
| 57 if (next_instruction_index_ >= sentence_.size()) | |
| 58 return true; | |
| 59 | |
| 60 Operation* op = sentence_[next_instruction_index_]; | |
| 61 next_instruction_index_++; | |
| 62 bool continue_traversal = op->Execute(this); | |
| 63 next_instruction_index_--; | |
| 64 return continue_traversal; | |
| 65 } | |
| 66 | |
| 67 std::string GetHash(const std::string& input) { | |
| 68 return hasher_->GetHash(input); | |
| 69 } | |
| 70 | |
| 71 // Calculates the |hash| of a string, integer or double |value|, and returns | |
| 72 // true. Returns false otherwise. | |
| 73 bool GetValueHash(const base::Value& value, std::string* hash) { | |
| 74 DCHECK(hash); | |
| 75 std::string value_as_string; | |
| 76 int tmp_int = 0; | |
| 77 double tmp_double = 0.0; | |
| 78 if (value.GetAsInteger(&tmp_int)) | |
| 79 value_as_string = base::IntToString(tmp_int); | |
| 80 else if (value.GetAsDouble(&tmp_double)) | |
| 81 value_as_string = base::DoubleToString(tmp_double); | |
| 82 else if (!value.GetAsString(&value_as_string)) | |
| 83 return false; | |
| 84 *hash = GetHash(value_as_string); | |
| 85 return true; | |
| 86 } | |
| 87 | |
| 88 const base::Value* current_node() const { return stack_.back(); } | |
| 89 std::vector<const base::Value*>* stack() { return &stack_; } | |
| 90 base::DictionaryValue* working_memory() { return working_memory_; } | |
| 91 bool error() const { return error_; } | |
| 92 | |
| 93 private: | |
| 94 // A hasher used to hash node names in a dictionary. | |
| 95 const jtl_foundation::Hasher* hasher_; | |
| 96 // The sentence to be executed. | |
| 97 const std::vector<Operation*> sentence_; | |
| 98 // Position in |sentence_|. | |
| 99 size_t next_instruction_index_; | |
| 100 // A stack of Values, indicating a navigation path from the root node of | |
| 101 // |input| (see constructor) to the current node on which the | |
| 102 // sentence_[next_instruction_index_] is evaluated. | |
| 103 std::vector<const base::Value*> stack_; | |
| 104 // Memory into which values can be stored by the program. | |
| 105 base::DictionaryValue* working_memory_; | |
| 106 // Whether a runtime error occurred. | |
| 107 bool error_; | |
| 108 DISALLOW_COPY_AND_ASSIGN(ExecutionContext); | |
| 109 }; | |
| 110 | |
| 111 class NavigateOperation : public Operation { | |
| 112 public: | |
| 113 explicit NavigateOperation(const std::string& hashed_key) | |
| 114 : hashed_key_(hashed_key) {} | |
| 115 virtual ~NavigateOperation() {} | |
| 116 virtual bool Execute(ExecutionContext* context) OVERRIDE { | |
| 117 const base::DictionaryValue* dict = NULL; | |
| 118 if (!context->current_node()->GetAsDictionary(&dict)) { | |
| 119 // Just ignore this node gracefully as this navigation is a dead end. | |
| 120 // If this NavigateOperation occurred after a NavigateAny operation, those | |
| 121 // may still be fulfillable, so we allow continuing the execution of the | |
| 122 // sentence on other nodes. | |
| 123 return true; | |
| 124 } | |
| 125 for (base::DictionaryValue::Iterator i(*dict); !i.IsAtEnd(); i.Advance()) { | |
| 126 if (context->GetHash(i.key()) != hashed_key_) | |
| 127 continue; | |
| 128 context->stack()->push_back(&i.value()); | |
| 129 bool continue_traversal = context->ContinueExecution(); | |
| 130 context->stack()->pop_back(); | |
| 131 if (!continue_traversal) | |
| 132 return false; | |
| 133 } | |
| 134 return true; | |
| 135 } | |
| 136 | |
| 137 private: | |
| 138 std::string hashed_key_; | |
| 139 DISALLOW_COPY_AND_ASSIGN(NavigateOperation); | |
| 140 }; | |
| 141 | |
| 142 class NavigateAnyOperation : public Operation { | |
| 143 public: | |
| 144 NavigateAnyOperation() {} | |
| 145 virtual ~NavigateAnyOperation() {} | |
| 146 virtual bool Execute(ExecutionContext* context) OVERRIDE { | |
| 147 const base::DictionaryValue* dict = NULL; | |
| 148 const base::ListValue* list = NULL; | |
| 149 if (context->current_node()->GetAsDictionary(&dict)) { | |
| 150 for (base::DictionaryValue::Iterator i(*dict); | |
| 151 !i.IsAtEnd(); i.Advance()) { | |
| 152 context->stack()->push_back(&i.value()); | |
| 153 bool continue_traversal = context->ContinueExecution(); | |
| 154 context->stack()->pop_back(); | |
| 155 if (!continue_traversal) | |
| 156 return false; | |
| 157 } | |
| 158 } else if (context->current_node()->GetAsList(&list)) { | |
| 159 for (base::ListValue::const_iterator i = list->begin(); | |
| 160 i != list->end(); ++i) { | |
| 161 context->stack()->push_back(*i); | |
| 162 bool continue_traversal = context->ContinueExecution(); | |
| 163 context->stack()->pop_back(); | |
| 164 if (!continue_traversal) | |
| 165 return false; | |
| 166 } | |
| 167 } else { | |
| 168 // Do nothing, just ignore this node. | |
| 169 } | |
| 170 return true; | |
| 171 } | |
| 172 | |
| 173 private: | |
| 174 DISALLOW_COPY_AND_ASSIGN(NavigateAnyOperation); | |
| 175 }; | |
| 176 | |
| 177 class NavigateBackOperation : public Operation { | |
| 178 public: | |
| 179 NavigateBackOperation() {} | |
| 180 virtual ~NavigateBackOperation() {} | |
| 181 virtual bool Execute(ExecutionContext* context) OVERRIDE { | |
| 182 const base::Value* current_node = context->current_node(); | |
| 183 context->stack()->pop_back(); | |
| 184 bool continue_traversal = context->ContinueExecution(); | |
| 185 context->stack()->push_back(current_node); | |
| 186 return continue_traversal; | |
| 187 } | |
| 188 | |
| 189 private: | |
| 190 DISALLOW_COPY_AND_ASSIGN(NavigateBackOperation); | |
| 191 }; | |
| 192 | |
| 193 class StoreValue : public Operation { | |
| 194 public: | |
| 195 StoreValue(const std::string& hashed_name, scoped_ptr<base::Value> value) | |
| 196 : hashed_name_(hashed_name), | |
| 197 value_(value.Pass()) { | |
| 198 DCHECK(base::IsStringUTF8(hashed_name)); | |
| 199 DCHECK(value_); | |
| 200 } | |
| 201 virtual ~StoreValue() {} | |
| 202 virtual bool Execute(ExecutionContext* context) OVERRIDE { | |
| 203 context->working_memory()->Set(hashed_name_, value_->DeepCopy()); | |
| 204 return context->ContinueExecution(); | |
| 205 } | |
| 206 | |
| 207 private: | |
| 208 std::string hashed_name_; | |
| 209 scoped_ptr<base::Value> value_; | |
| 210 DISALLOW_COPY_AND_ASSIGN(StoreValue); | |
| 211 }; | |
| 212 | |
| 213 class CompareStoredValue : public Operation { | |
| 214 public: | |
| 215 CompareStoredValue(const std::string& hashed_name, | |
| 216 scoped_ptr<base::Value> value, | |
| 217 scoped_ptr<base::Value> default_value) | |
| 218 : hashed_name_(hashed_name), | |
| 219 value_(value.Pass()), | |
| 220 default_value_(default_value.Pass()) { | |
| 221 DCHECK(base::IsStringUTF8(hashed_name)); | |
| 222 DCHECK(value_); | |
| 223 DCHECK(default_value_); | |
| 224 } | |
| 225 virtual ~CompareStoredValue() {} | |
| 226 virtual bool Execute(ExecutionContext* context) OVERRIDE { | |
| 227 const base::Value* actual_value = NULL; | |
| 228 if (!context->working_memory()->Get(hashed_name_, &actual_value)) | |
| 229 actual_value = default_value_.get(); | |
| 230 if (!value_->Equals(actual_value)) | |
| 231 return true; | |
| 232 return context->ContinueExecution(); | |
| 233 } | |
| 234 | |
| 235 private: | |
| 236 std::string hashed_name_; | |
| 237 scoped_ptr<base::Value> value_; | |
| 238 scoped_ptr<base::Value> default_value_; | |
| 239 DISALLOW_COPY_AND_ASSIGN(CompareStoredValue); | |
| 240 }; | |
| 241 | |
| 242 template<bool ExpectedTypeIsBooleanNotHashable> | |
| 243 class StoreNodeValue : public Operation { | |
| 244 public: | |
| 245 explicit StoreNodeValue(const std::string& hashed_name) | |
| 246 : hashed_name_(hashed_name) { | |
| 247 DCHECK(base::IsStringUTF8(hashed_name)); | |
| 248 } | |
| 249 virtual ~StoreNodeValue() {} | |
| 250 virtual bool Execute(ExecutionContext* context) OVERRIDE { | |
| 251 scoped_ptr<base::Value> value; | |
| 252 if (ExpectedTypeIsBooleanNotHashable) { | |
| 253 if (!context->current_node()->IsType(base::Value::TYPE_BOOLEAN)) | |
| 254 return true; | |
| 255 value.reset(context->current_node()->DeepCopy()); | |
| 256 } else { | |
| 257 std::string hash; | |
| 258 if (!context->GetValueHash(*context->current_node(), &hash)) | |
| 259 return true; | |
| 260 value.reset(new base::StringValue(hash)); | |
| 261 } | |
| 262 context->working_memory()->Set(hashed_name_, value.release()); | |
| 263 return context->ContinueExecution(); | |
| 264 } | |
| 265 | |
| 266 private: | |
| 267 std::string hashed_name_; | |
| 268 DISALLOW_COPY_AND_ASSIGN(StoreNodeValue); | |
| 269 }; | |
| 270 | |
| 271 // Stores the hash of the registerable domain name -- as in, the portion of the | |
| 272 // domain that is registerable, as opposed to controlled by a registrar; without | |
| 273 // subdomains -- of the URL represented by the current node into working memory. | |
| 274 class StoreNodeRegisterableDomain : public Operation { | |
| 275 public: | |
| 276 explicit StoreNodeRegisterableDomain(const std::string& hashed_name) | |
| 277 : hashed_name_(hashed_name) { | |
| 278 DCHECK(base::IsStringUTF8(hashed_name)); | |
| 279 } | |
| 280 virtual ~StoreNodeRegisterableDomain() {} | |
| 281 virtual bool Execute(ExecutionContext* context) OVERRIDE { | |
| 282 std::string possibly_invalid_url; | |
| 283 std::string domain; | |
| 284 if (!context->current_node()->GetAsString(&possibly_invalid_url) || | |
| 285 !GetRegisterableDomain(possibly_invalid_url, &domain)) | |
| 286 return true; | |
| 287 context->working_memory()->Set( | |
| 288 hashed_name_, new base::StringValue(context->GetHash(domain))); | |
| 289 return context->ContinueExecution(); | |
| 290 } | |
| 291 | |
| 292 private: | |
| 293 // If |possibly_invalid_url| is a valid URL having a registerable domain name | |
| 294 // part, outputs that in |registerable_domain| and returns true. Otherwise, | |
| 295 // returns false. | |
| 296 static bool GetRegisterableDomain(const std::string& possibly_invalid_url, | |
| 297 std::string* registerable_domain) { | |
| 298 namespace domains = net::registry_controlled_domains; | |
| 299 DCHECK(registerable_domain); | |
| 300 GURL url(possibly_invalid_url); | |
| 301 if (!url.is_valid()) | |
| 302 return false; | |
| 303 std::string registry_plus_one = domains::GetDomainAndRegistry( | |
| 304 url.host(), domains::INCLUDE_PRIVATE_REGISTRIES); | |
| 305 size_t registry_length = domains::GetRegistryLength( | |
| 306 url.host(), | |
| 307 domains::INCLUDE_UNKNOWN_REGISTRIES, | |
| 308 domains::INCLUDE_PRIVATE_REGISTRIES); | |
| 309 // Fail unless (1.) the URL has a host part; and (2.) that host part is a | |
| 310 // well-formed domain name consisting of at least one subcomponent; followed | |
| 311 // by either a recognized registry identifier, or exactly one subcomponent, | |
| 312 // which is then assumed to be the unknown registry identifier. | |
| 313 if (registry_length == std::string::npos || registry_length == 0) | |
| 314 return false; | |
| 315 DCHECK_LT(registry_length, registry_plus_one.size()); | |
| 316 // Subtract one to cut off the dot separating the SLD and the registry. | |
| 317 registerable_domain->assign( | |
| 318 registry_plus_one, 0, registry_plus_one.size() - registry_length - 1); | |
| 319 return true; | |
| 320 } | |
| 321 | |
| 322 std::string hashed_name_; | |
| 323 DISALLOW_COPY_AND_ASSIGN(StoreNodeRegisterableDomain); | |
| 324 }; | |
| 325 | |
| 326 class CompareNodeBool : public Operation { | |
| 327 public: | |
| 328 explicit CompareNodeBool(bool value) : value_(value) {} | |
| 329 virtual ~CompareNodeBool() {} | |
| 330 virtual bool Execute(ExecutionContext* context) OVERRIDE { | |
| 331 bool actual_value = false; | |
| 332 if (!context->current_node()->GetAsBoolean(&actual_value)) | |
| 333 return true; | |
| 334 if (actual_value != value_) | |
| 335 return true; | |
| 336 return context->ContinueExecution(); | |
| 337 } | |
| 338 | |
| 339 private: | |
| 340 bool value_; | |
| 341 DISALLOW_COPY_AND_ASSIGN(CompareNodeBool); | |
| 342 }; | |
| 343 | |
| 344 class CompareNodeHash : public Operation { | |
| 345 public: | |
| 346 explicit CompareNodeHash(const std::string& hashed_value) | |
| 347 : hashed_value_(hashed_value) {} | |
| 348 virtual ~CompareNodeHash() {} | |
| 349 virtual bool Execute(ExecutionContext* context) OVERRIDE { | |
| 350 std::string actual_hash; | |
| 351 if (!context->GetValueHash(*context->current_node(), &actual_hash) || | |
| 352 actual_hash != hashed_value_) | |
| 353 return true; | |
| 354 return context->ContinueExecution(); | |
| 355 } | |
| 356 | |
| 357 private: | |
| 358 std::string hashed_value_; | |
| 359 DISALLOW_COPY_AND_ASSIGN(CompareNodeHash); | |
| 360 }; | |
| 361 | |
| 362 class CompareNodeHashNot : public Operation { | |
| 363 public: | |
| 364 explicit CompareNodeHashNot(const std::string& hashed_value) | |
| 365 : hashed_value_(hashed_value) {} | |
| 366 virtual ~CompareNodeHashNot() {} | |
| 367 virtual bool Execute(ExecutionContext* context) OVERRIDE { | |
| 368 std::string actual_hash; | |
| 369 if (context->GetValueHash(*context->current_node(), &actual_hash) && | |
| 370 actual_hash == hashed_value_) | |
| 371 return true; | |
| 372 return context->ContinueExecution(); | |
| 373 } | |
| 374 | |
| 375 private: | |
| 376 std::string hashed_value_; | |
| 377 DISALLOW_COPY_AND_ASSIGN(CompareNodeHashNot); | |
| 378 }; | |
| 379 | |
| 380 template<bool ExpectedTypeIsBooleanNotHashable> | |
| 381 class CompareNodeToStored : public Operation { | |
| 382 public: | |
| 383 explicit CompareNodeToStored(const std::string& hashed_name) | |
| 384 : hashed_name_(hashed_name) {} | |
| 385 virtual ~CompareNodeToStored() {} | |
| 386 virtual bool Execute(ExecutionContext* context) OVERRIDE { | |
| 387 const base::Value* stored_value = NULL; | |
| 388 if (!context->working_memory()->Get(hashed_name_, &stored_value)) | |
| 389 return true; | |
| 390 if (ExpectedTypeIsBooleanNotHashable) { | |
| 391 if (!context->current_node()->IsType(base::Value::TYPE_BOOLEAN) || | |
| 392 !context->current_node()->Equals(stored_value)) | |
| 393 return true; | |
| 394 } else { | |
| 395 std::string actual_hash; | |
| 396 std::string stored_hash; | |
| 397 if (!context->GetValueHash(*context->current_node(), &actual_hash) || | |
| 398 !stored_value->GetAsString(&stored_hash) || | |
| 399 actual_hash != stored_hash) | |
| 400 return true; | |
| 401 } | |
| 402 return context->ContinueExecution(); | |
| 403 } | |
| 404 | |
| 405 private: | |
| 406 std::string hashed_name_; | |
| 407 DISALLOW_COPY_AND_ASSIGN(CompareNodeToStored); | |
| 408 }; | |
| 409 | |
| 410 class CompareNodeSubstring : public Operation { | |
| 411 public: | |
| 412 explicit CompareNodeSubstring(const std::string& hashed_pattern, | |
| 413 size_t pattern_length, | |
| 414 uint32 pattern_sum) | |
| 415 : hashed_pattern_(hashed_pattern), | |
| 416 pattern_length_(pattern_length), | |
| 417 pattern_sum_(pattern_sum) { | |
| 418 DCHECK(pattern_length_); | |
| 419 } | |
| 420 virtual ~CompareNodeSubstring() {} | |
| 421 virtual bool Execute(ExecutionContext* context) OVERRIDE { | |
| 422 std::string value_as_string; | |
| 423 if (!context->current_node()->GetAsString(&value_as_string) || | |
| 424 !pattern_length_ || value_as_string.size() < pattern_length_) | |
| 425 return true; | |
| 426 // Go over the string with a sliding window. Meanwhile, maintain the sum in | |
| 427 // an incremental fashion, and only calculate the SHA-256 hash when the sum | |
| 428 // checks out so as to improve performance. | |
| 429 std::string::const_iterator window_begin = value_as_string.begin(); | |
| 430 std::string::const_iterator window_end = window_begin + pattern_length_ - 1; | |
| 431 uint32 window_sum = | |
| 432 std::accumulate(window_begin, window_end, static_cast<uint32>(0u)); | |
| 433 while (window_end != value_as_string.end()) { | |
| 434 window_sum += *window_end++; | |
| 435 if (window_sum == pattern_sum_ && context->GetHash(std::string( | |
| 436 window_begin, window_end)) == hashed_pattern_) | |
| 437 return context->ContinueExecution(); | |
| 438 window_sum -= *window_begin++; | |
| 439 } | |
| 440 return true; | |
| 441 } | |
| 442 | |
| 443 private: | |
| 444 std::string hashed_pattern_; | |
| 445 size_t pattern_length_; | |
| 446 uint32 pattern_sum_; | |
| 447 DISALLOW_COPY_AND_ASSIGN(CompareNodeSubstring); | |
| 448 }; | |
| 449 | |
| 450 class StopExecutingSentenceOperation : public Operation { | |
| 451 public: | |
| 452 StopExecutingSentenceOperation() {} | |
| 453 virtual ~StopExecutingSentenceOperation() {} | |
| 454 virtual bool Execute(ExecutionContext* context) OVERRIDE { | |
| 455 return false; | |
| 456 } | |
| 457 | |
| 458 private: | |
| 459 DISALLOW_COPY_AND_ASSIGN(StopExecutingSentenceOperation); | |
| 460 }; | |
| 461 | |
| 462 class Parser { | |
| 463 public: | |
| 464 explicit Parser(const std::string& program) | |
| 465 : program_(program), | |
| 466 next_instruction_index_(0u) {} | |
| 467 ~Parser() {} | |
| 468 bool ParseNextSentence(ScopedVector<Operation>* output) { | |
| 469 ScopedVector<Operation> operators; | |
| 470 bool sentence_ended = false; | |
| 471 while (next_instruction_index_ < program_.size() && !sentence_ended) { | |
| 472 uint8 op_code = 0; | |
| 473 if (!ReadOpCode(&op_code)) | |
| 474 return false; | |
| 475 switch (static_cast<jtl_foundation::OpCodes>(op_code)) { | |
| 476 case jtl_foundation::NAVIGATE: { | |
| 477 std::string hashed_key; | |
| 478 if (!ReadHash(&hashed_key)) | |
| 479 return false; | |
| 480 operators.push_back(new NavigateOperation(hashed_key)); | |
| 481 break; | |
| 482 } | |
| 483 case jtl_foundation::NAVIGATE_ANY: | |
| 484 operators.push_back(new NavigateAnyOperation); | |
| 485 break; | |
| 486 case jtl_foundation::NAVIGATE_BACK: | |
| 487 operators.push_back(new NavigateBackOperation); | |
| 488 break; | |
| 489 case jtl_foundation::STORE_BOOL: { | |
| 490 std::string hashed_name; | |
| 491 if (!ReadHash(&hashed_name) || !base::IsStringUTF8(hashed_name)) | |
| 492 return false; | |
| 493 bool value = false; | |
| 494 if (!ReadBool(&value)) | |
| 495 return false; | |
| 496 operators.push_back(new StoreValue( | |
| 497 hashed_name, | |
| 498 scoped_ptr<base::Value>(new base::FundamentalValue(value)))); | |
| 499 break; | |
| 500 } | |
| 501 case jtl_foundation::COMPARE_STORED_BOOL: { | |
| 502 std::string hashed_name; | |
| 503 if (!ReadHash(&hashed_name) || !base::IsStringUTF8(hashed_name)) | |
| 504 return false; | |
| 505 bool value = false; | |
| 506 if (!ReadBool(&value)) | |
| 507 return false; | |
| 508 bool default_value = false; | |
| 509 if (!ReadBool(&default_value)) | |
| 510 return false; | |
| 511 operators.push_back(new CompareStoredValue( | |
| 512 hashed_name, | |
| 513 scoped_ptr<base::Value>(new base::FundamentalValue(value)), | |
| 514 scoped_ptr<base::Value>( | |
| 515 new base::FundamentalValue(default_value)))); | |
| 516 break; | |
| 517 } | |
| 518 case jtl_foundation::STORE_HASH: { | |
| 519 std::string hashed_name; | |
| 520 if (!ReadHash(&hashed_name) || !base::IsStringUTF8(hashed_name)) | |
| 521 return false; | |
| 522 std::string hashed_value; | |
| 523 if (!ReadHash(&hashed_value)) | |
| 524 return false; | |
| 525 operators.push_back(new StoreValue( | |
| 526 hashed_name, | |
| 527 scoped_ptr<base::Value>(new base::StringValue(hashed_value)))); | |
| 528 break; | |
| 529 } | |
| 530 case jtl_foundation::COMPARE_STORED_HASH: { | |
| 531 std::string hashed_name; | |
| 532 if (!ReadHash(&hashed_name) || !base::IsStringUTF8(hashed_name)) | |
| 533 return false; | |
| 534 std::string hashed_value; | |
| 535 if (!ReadHash(&hashed_value)) | |
| 536 return false; | |
| 537 std::string hashed_default_value; | |
| 538 if (!ReadHash(&hashed_default_value)) | |
| 539 return false; | |
| 540 operators.push_back(new CompareStoredValue( | |
| 541 hashed_name, | |
| 542 scoped_ptr<base::Value>(new base::StringValue(hashed_value)), | |
| 543 scoped_ptr<base::Value>( | |
| 544 new base::StringValue(hashed_default_value)))); | |
| 545 break; | |
| 546 } | |
| 547 case jtl_foundation::STORE_NODE_BOOL: { | |
| 548 std::string hashed_name; | |
| 549 if (!ReadHash(&hashed_name) || !base::IsStringUTF8(hashed_name)) | |
| 550 return false; | |
| 551 operators.push_back(new StoreNodeValue<true>(hashed_name)); | |
| 552 break; | |
| 553 } | |
| 554 case jtl_foundation::STORE_NODE_HASH: { | |
| 555 std::string hashed_name; | |
| 556 if (!ReadHash(&hashed_name) || !base::IsStringUTF8(hashed_name)) | |
| 557 return false; | |
| 558 operators.push_back(new StoreNodeValue<false>(hashed_name)); | |
| 559 break; | |
| 560 } | |
| 561 case jtl_foundation::STORE_NODE_REGISTERABLE_DOMAIN_HASH: { | |
| 562 std::string hashed_name; | |
| 563 if (!ReadHash(&hashed_name) || !base::IsStringUTF8(hashed_name)) | |
| 564 return false; | |
| 565 operators.push_back(new StoreNodeRegisterableDomain(hashed_name)); | |
| 566 break; | |
| 567 } | |
| 568 case jtl_foundation::COMPARE_NODE_BOOL: { | |
| 569 bool value = false; | |
| 570 if (!ReadBool(&value)) | |
| 571 return false; | |
| 572 operators.push_back(new CompareNodeBool(value)); | |
| 573 break; | |
| 574 } | |
| 575 case jtl_foundation::COMPARE_NODE_HASH: { | |
| 576 std::string hashed_value; | |
| 577 if (!ReadHash(&hashed_value)) | |
| 578 return false; | |
| 579 operators.push_back(new CompareNodeHash(hashed_value)); | |
| 580 break; | |
| 581 } | |
| 582 case jtl_foundation::COMPARE_NODE_HASH_NOT: { | |
| 583 std::string hashed_value; | |
| 584 if (!ReadHash(&hashed_value)) | |
| 585 return false; | |
| 586 operators.push_back(new CompareNodeHashNot(hashed_value)); | |
| 587 break; | |
| 588 } | |
| 589 case jtl_foundation::COMPARE_NODE_TO_STORED_BOOL: { | |
| 590 std::string hashed_name; | |
| 591 if (!ReadHash(&hashed_name) || !base::IsStringUTF8(hashed_name)) | |
| 592 return false; | |
| 593 operators.push_back(new CompareNodeToStored<true>(hashed_name)); | |
| 594 break; | |
| 595 } | |
| 596 case jtl_foundation::COMPARE_NODE_TO_STORED_HASH: { | |
| 597 std::string hashed_name; | |
| 598 if (!ReadHash(&hashed_name) || !base::IsStringUTF8(hashed_name)) | |
| 599 return false; | |
| 600 operators.push_back(new CompareNodeToStored<false>(hashed_name)); | |
| 601 break; | |
| 602 } | |
| 603 case jtl_foundation::COMPARE_NODE_SUBSTRING: { | |
| 604 std::string hashed_pattern; | |
| 605 uint32 pattern_length = 0, pattern_sum = 0; | |
| 606 if (!ReadHash(&hashed_pattern)) | |
| 607 return false; | |
| 608 if (!ReadUint32(&pattern_length) || pattern_length == 0) | |
| 609 return false; | |
| 610 if (!ReadUint32(&pattern_sum)) | |
| 611 return false; | |
| 612 operators.push_back(new CompareNodeSubstring( | |
| 613 hashed_pattern, pattern_length, pattern_sum)); | |
| 614 break; | |
| 615 } | |
| 616 case jtl_foundation::STOP_EXECUTING_SENTENCE: | |
| 617 operators.push_back(new StopExecutingSentenceOperation); | |
| 618 break; | |
| 619 case jtl_foundation::END_OF_SENTENCE: | |
| 620 sentence_ended = true; | |
| 621 break; | |
| 622 default: | |
| 623 return false; | |
| 624 } | |
| 625 } | |
| 626 output->swap(operators); | |
| 627 return true; | |
| 628 } | |
| 629 | |
| 630 bool HasNextSentence() const { | |
| 631 return next_instruction_index_ < program_.size(); | |
| 632 } | |
| 633 | |
| 634 private: | |
| 635 // Reads an uint8 and returns whether this operation was successful. | |
| 636 bool ReadUint8(uint8* out) { | |
| 637 DCHECK(out); | |
| 638 if (next_instruction_index_ + 1u > program_.size()) | |
| 639 return false; | |
| 640 *out = static_cast<uint8>(program_[next_instruction_index_]); | |
| 641 ++next_instruction_index_; | |
| 642 return true; | |
| 643 } | |
| 644 | |
| 645 // Reads an uint32 and returns whether this operation was successful. | |
| 646 bool ReadUint32(uint32* out) { | |
| 647 DCHECK(out); | |
| 648 if (next_instruction_index_ + 4u > program_.size()) | |
| 649 return false; | |
| 650 *out = 0u; | |
| 651 for (int i = 0; i < 4; ++i) { | |
| 652 *out >>= 8; | |
| 653 *out |= static_cast<uint8>(program_[next_instruction_index_]) << 24; | |
| 654 ++next_instruction_index_; | |
| 655 } | |
| 656 return true; | |
| 657 } | |
| 658 | |
| 659 // Reads an operator code and returns whether this operation was successful. | |
| 660 bool ReadOpCode(uint8* out) { return ReadUint8(out); } | |
| 661 | |
| 662 bool ReadHash(std::string* out) { | |
| 663 DCHECK(out); | |
| 664 if (next_instruction_index_ + jtl_foundation::kHashSizeInBytes > | |
| 665 program_.size()) | |
| 666 return false; | |
| 667 *out = program_.substr(next_instruction_index_, | |
| 668 jtl_foundation::kHashSizeInBytes); | |
| 669 next_instruction_index_ += jtl_foundation::kHashSizeInBytes; | |
| 670 DCHECK(jtl_foundation::Hasher::IsHash(*out)); | |
| 671 return true; | |
| 672 } | |
| 673 | |
| 674 bool ReadBool(bool* out) { | |
| 675 DCHECK(out); | |
| 676 uint8 value = 0; | |
| 677 if (!ReadUint8(&value)) | |
| 678 return false; | |
| 679 if (value == 0) | |
| 680 *out = false; | |
| 681 else if (value == 1) | |
| 682 *out = true; | |
| 683 else | |
| 684 return false; | |
| 685 return true; | |
| 686 } | |
| 687 | |
| 688 std::string program_; | |
| 689 size_t next_instruction_index_; | |
| 690 DISALLOW_COPY_AND_ASSIGN(Parser); | |
| 691 }; | |
| 692 | |
| 693 } // namespace | |
| 694 | |
| 695 JtlInterpreter::JtlInterpreter( | |
| 696 const std::string& hasher_seed, | |
| 697 const std::string& program, | |
| 698 const base::DictionaryValue* input) | |
| 699 : hasher_seed_(hasher_seed), | |
| 700 program_(program), | |
| 701 input_(input), | |
| 702 working_memory_(new base::DictionaryValue), | |
| 703 result_(OK) { | |
| 704 DCHECK(input->IsType(base::Value::TYPE_DICTIONARY)); | |
| 705 } | |
| 706 | |
| 707 JtlInterpreter::~JtlInterpreter() {} | |
| 708 | |
| 709 void JtlInterpreter::Execute() { | |
| 710 jtl_foundation::Hasher hasher(hasher_seed_); | |
| 711 Parser parser(program_); | |
| 712 while (parser.HasNextSentence()) { | |
| 713 ScopedVector<Operation> sentence; | |
| 714 if (!parser.ParseNextSentence(&sentence)) { | |
| 715 result_ = PARSE_ERROR; | |
| 716 return; | |
| 717 } | |
| 718 ExecutionContext context( | |
| 719 &hasher, sentence.get(), input_, working_memory_.get()); | |
| 720 context.ContinueExecution(); | |
| 721 if (context.error()) { | |
| 722 result_ = RUNTIME_ERROR; | |
| 723 return; | |
| 724 } | |
| 725 } | |
| 726 } | |
| 727 | |
| 728 bool JtlInterpreter::GetOutputBoolean(const std::string& unhashed_key, | |
| 729 bool* output) const { | |
| 730 std::string hashed_key = | |
| 731 jtl_foundation::Hasher(hasher_seed_).GetHash(unhashed_key); | |
| 732 return working_memory_->GetBoolean(hashed_key, output); | |
| 733 } | |
| 734 | |
| 735 bool JtlInterpreter::GetOutputString(const std::string& unhashed_key, | |
| 736 std::string* output) const { | |
| 737 std::string hashed_key = | |
| 738 jtl_foundation::Hasher(hasher_seed_).GetHash(unhashed_key); | |
| 739 return working_memory_->GetString(hashed_key, output); | |
| 740 } | |
| 741 | |
| 742 int JtlInterpreter::CalculateProgramChecksum() const { | |
| 743 uint8 digest[3] = {}; | |
| 744 crypto::SHA256HashString(program_, digest, arraysize(digest)); | |
| 745 return static_cast<uint32>(digest[0]) << 16 | | |
| 746 static_cast<uint32>(digest[1]) << 8 | | |
| 747 static_cast<uint32>(digest[2]); | |
| 748 } | |
| OLD | NEW |