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 } 749