Redacts sensitive profile values and optionally records alias-to-original mappings.
| 456 | |
| 457 | // Redacts sensitive profile values and optionally records alias-to-original mappings. |
| 458 | static Status RedactQueryProfileWithAliases(const string_view& profile_text, |
| 459 | const Value& source_json, |
| 460 | unordered_map<string, string>& alias_to_original, string* redacted) { |
| 461 | DCHECK(redacted != nullptr); |
| 462 | unordered_map<string, string> global_aliases; |
| 463 | |
| 464 | const vector<string> sql_statements = |
| 465 | CollectInfoStringValuesByKeys(source_json, {"Sql Statement"}); |
| 466 | for (size_t idx = 0; idx < sql_statements.size(); ++idx) { |
| 467 | const string& sql_statement = sql_statements[idx]; |
| 468 | if (sql_statement.empty()) continue; |
| 469 | const string placeholder = BuildRedactedSqlPlaceholder(idx + 1); |
| 470 | const string escaped_sql = JsonEscapeString(sql_statement); |
| 471 | global_aliases.emplace(escaped_sql, placeholder); |
| 472 | global_aliases.emplace(sql_statement, placeholder); |
| 473 | // Unredaction runs against serialized JSON text, so restore escaped representation. |
| 474 | alias_to_original.emplace(placeholder, escaped_sql); |
| 475 | } |
| 476 | |
| 477 | vector<string> user_values = CollectInfoStringValuesByKeys( |
| 478 | source_json, {"User", "Connected User", "Delegated User"}); |
| 479 | vector<string> emails = CollectRegexMatches(profile_text, EMAIL_RE, 0); |
| 480 | vector<string> user_kvs = CollectRegexMatches(profile_text, USER_KV_RE, 1); |
| 481 | user_values.insert(user_values.end(), make_move_iterator(emails.begin()), |
| 482 | make_move_iterator(emails.end())); |
| 483 | user_values.insert(user_values.end(), make_move_iterator(user_kvs.begin()), |
| 484 | make_move_iterator(user_kvs.end())); |
| 485 | const size_t username_count = |
| 486 | AddAliasesByPrefix(user_values, "user", &global_aliases, &alias_to_original); |
| 487 | |
| 488 | vector<string> all_ip_tokens = CollectRegexMatches(profile_text, IPV4_RE); |
| 489 | vector<string> ipv6_tokens = CollectIpv6Matches(profile_text); |
| 490 | all_ip_tokens.insert(all_ip_tokens.end(), make_move_iterator(ipv6_tokens.begin()), |
| 491 | make_move_iterator(ipv6_tokens.end())); |
| 492 | const size_t ip_count = |
| 493 | AddAliasesByPrefix(all_ip_tokens, "ip", &global_aliases, &alias_to_original); |
| 494 | |
| 495 | vector<string> contexts = CollectIdentifierContextsFromJsonProfile(source_json); |
| 496 | auto [table_tokens, column_tokens] = ExtractTableAndColumnTokens(contexts); |
| 497 | const size_t table_count = |
| 498 | AddAliasesByPrefix(table_tokens, "table", &global_aliases, &alias_to_original); |
| 499 | const size_t column_count = |
| 500 | AddAliasesByPrefix(column_tokens, "column", &global_aliases, &alias_to_original); |
| 501 | |
| 502 | const vector<string> host_tokens = ExtractHostTokensFromPerHostSections(source_json); |
| 503 | const size_t host_count = |
| 504 | AddAliasesByPrefix(host_tokens, "host", &global_aliases, &alias_to_original); |
| 505 | |
| 506 | Status status = ApplyAliasMap(global_aliases, profile_text, redacted); |
| 507 | if (!status.ok()) return status; |
| 508 | |
| 509 | VLOG(1) << "Query profile redaction complete. Extracted items : " |
| 510 | << "SQL statements: " << sql_statements.size() << ", " |
| 511 | << "Users: " << username_count << ", " |
| 512 | << "IPs: " << ip_count << ", " |
| 513 | << "Tables: " << table_count << ", " |
| 514 | << "Columns: " << column_count << ", " |
| 515 | << "Hosts: " << host_count << ". " |
no test coverage detected