| Index: chrome/browser/safe_browsing/safe_browsing_api_handler_util.cc
|
| diff --git a/chrome/browser/safe_browsing/safe_browsing_api_handler_util.cc b/chrome/browser/safe_browsing/safe_browsing_api_handler_util.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..897ad4079be90a83be1f1818220afd87eabcad7e
|
| --- /dev/null
|
| +++ b/chrome/browser/safe_browsing/safe_browsing_api_handler_util.cc
|
| @@ -0,0 +1,167 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/safe_browsing/safe_browsing_api_handler_util.h"
|
| +
|
| +#include <stddef.h>
|
| +
|
| +#include <string>
|
| +
|
| +#include "base/json/json_reader.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/metrics/histogram_macros.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "base/values.h"
|
| +#include "chrome/browser/safe_browsing/metadata.pb.h"
|
| +#include "chrome/browser/safe_browsing/safe_browsing_util.h"
|
| +
|
| +
|
| +namespace safe_browsing {
|
| +namespace {
|
| +
|
| +// JSON metatdata keys. These are are fixed in the Java-side API.
|
| +const char kJsonKeyMatches[] = "matches";
|
| +const char kJsonKeyThreatType[] = "threat_type";
|
| +
|
| +// Do not reorder or delete. Make sure changes are reflected in
|
| +// SB2RemoteCallThreatSubType.
|
| +enum UmaThreatSubType {
|
| + UMA_THREAT_SUB_TYPE_NOT_SET = 0,
|
| + UMA_THREAT_SUB_TYPE_LANDING = 1,
|
| + UMA_THREAT_SUB_TYPE_DISTRIBUTION = 2,
|
| + UMA_THREAT_SUB_TYPE_UNKNOWN = 3,
|
| + UMA_THREAT_SUB_TYPE_MAX_VALUE
|
| +};
|
| +
|
| +void ReportUmaThreatSubType(SBThreatType threat_type,
|
| + UmaThreatSubType sub_type) {
|
| + if (threat_type == SB_THREAT_TYPE_URL_MALWARE) {
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + "SB2.RemoteCall.ThreatSubType.PotentiallyHarmfulApp", sub_type,
|
| + UMA_THREAT_SUB_TYPE_MAX_VALUE);
|
| + } else {
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + "SB2.RemoteCall.ThreatSubType.SocialEngineering", sub_type,
|
| + UMA_THREAT_SUB_TYPE_MAX_VALUE);
|
| + }
|
| +}
|
| +
|
| +// Parse the extra key/value pair(s) added by Safe Browsing backend. To make
|
| +// it binary compatible with the Pver3 metadata that UIManager expects to
|
| +// deserialize, we convert it to a MalwarePatternType.
|
| +//
|
| +// TODO(nparker): When chrome desktop is converted to use Pver4, convert this
|
| +// to the new proto instead.
|
| +const std::string ParseExtraMetadataToPB(const base::DictionaryValue* match,
|
| + SBThreatType threat_type) {
|
| + std::string pattern_key;
|
| + if (threat_type == SB_THREAT_TYPE_URL_MALWARE) {
|
| + pattern_key = "pha_pattern_type";
|
| + } else {
|
| + DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING);
|
| + pattern_key = "se_pattern_type";
|
| + }
|
| +
|
| + std::string pattern_type;
|
| + if (!match->GetString(pattern_key, &pattern_type)) {
|
| + ReportUmaThreatSubType(threat_type, UMA_THREAT_SUB_TYPE_NOT_SET);
|
| + return std::string();
|
| + }
|
| +
|
| + MalwarePatternType pb;
|
| + if (pattern_type == "LANDING") {
|
| + pb.set_pattern_type(MalwarePatternType::LANDING);
|
| + ReportUmaThreatSubType(threat_type, UMA_THREAT_SUB_TYPE_LANDING);
|
| + } else if (pattern_type == "DISTRIBUTION") {
|
| + pb.set_pattern_type(MalwarePatternType::DISTRIBUTION);
|
| + ReportUmaThreatSubType(threat_type, UMA_THREAT_SUB_TYPE_DISTRIBUTION);
|
| + } else {
|
| + ReportUmaThreatSubType(threat_type, UMA_THREAT_SUB_TYPE_UNKNOWN);
|
| + return std::string();
|
| + }
|
| +
|
| + return pb.SerializeAsString();
|
| +}
|
| +
|
| +int GetThreatSeverity(int java_threat_num) {
|
| + // Assign higher numbers to more severe threats.
|
| + switch (java_threat_num) {
|
| + case JAVA_THREAT_TYPE_POTENTIALLY_HARMFUL_APPLICATION:
|
| + return 2;
|
| + case JAVA_THREAT_TYPE_SOCIAL_ENGINEERING:
|
| + return 1;
|
| + default:
|
| + // Unknown threat type
|
| + return -1;
|
| + }
|
| +}
|
| +
|
| +SBThreatType JavaToSBThreatType(int java_threat_num) {
|
| + switch (java_threat_num) {
|
| + case JAVA_THREAT_TYPE_POTENTIALLY_HARMFUL_APPLICATION:
|
| + return SB_THREAT_TYPE_URL_MALWARE;
|
| + case JAVA_THREAT_TYPE_SOCIAL_ENGINEERING:
|
| + return SB_THREAT_TYPE_URL_PHISHING;
|
| + default:
|
| + // Unknown threat type
|
| + return SB_THREAT_TYPE_SAFE;
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +
|
| +// Valid examples:
|
| +// {"matches":[{"threat_type":"5"}]}
|
| +// or
|
| +// {"matches":[{"threat_type":"4"},
|
| +// {"threat_type":"5", "se_pattern_type":"LANDING"}]}
|
| +UmaRemoteCallResult ParseJsonToThreatAndPB(const std::string& metadata_str,
|
| + SBThreatType* worst_threat,
|
| + std::string* metadata_pb_str) {
|
| + *worst_threat = SB_THREAT_TYPE_SAFE; // Default to safe.
|
| + *metadata_pb_str = std::string();
|
| +
|
| + if (metadata_str.empty())
|
| + return UMA_STATUS_JSON_EMPTY;
|
| +
|
| + // Pick out the "matches" list.
|
| + scoped_ptr<base::Value> value = base::JSONReader::Read(metadata_str);
|
| + const base::ListValue* matches;
|
| + if (!value.get() || !value->IsType(base::Value::TYPE_DICTIONARY) ||
|
| + !(static_cast<base::DictionaryValue*>(value.get()))
|
| + ->GetList(kJsonKeyMatches, &matches)) {
|
| + return UMA_STATUS_JSON_FAILED_TO_PARSE;
|
| + }
|
| +
|
| + // Go through each matched threat type and pick the most severe.
|
| + int worst_threat_num = -1;
|
| + const base::DictionaryValue* worst_match = nullptr;
|
| + for (size_t i = 0; i < matches->GetSize(); i++) {
|
| + // Get the threat number
|
| + const base::DictionaryValue* match;
|
| + std::string threat_num_str;
|
| + int java_threat_num = -1;
|
| + if (!matches->GetDictionary(i, &match) ||
|
| + !match->GetString(kJsonKeyThreatType, &threat_num_str) ||
|
| + !base::StringToInt(threat_num_str, &java_threat_num)) {
|
| + continue; // Skip malformed list entries
|
| + }
|
| +
|
| + if (GetThreatSeverity(java_threat_num) >
|
| + GetThreatSeverity(worst_threat_num)) {
|
| + worst_threat_num = java_threat_num;
|
| + worst_match = match;
|
| + }
|
| + }
|
| +
|
| + *worst_threat = JavaToSBThreatType(worst_threat_num);
|
| + if (*worst_threat == SB_THREAT_TYPE_SAFE || !worst_match)
|
| + return UMA_STATUS_JSON_UNKNOWN_THREAT;
|
| + *metadata_pb_str = ParseExtraMetadataToPB(worst_match, *worst_threat);
|
| +
|
| + return UMA_STATUS_UNSAFE; // success
|
| +}
|
| +
|
| +} // namespace safe_browsing
|
|
|