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 |