Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / safe_browsing / safe_browsing_api_handler_util.cc
blob899b83f4cf734c49bbf87a3d296c395f305a2358
1 // Copyright 2015 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.
5 #include "chrome/browser/safe_browsing/safe_browsing_api_handler_util.h"
7 #include <string>
9 #include "base/json/json_reader.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/safe_browsing/metadata.pb.h"
15 #include "chrome/browser/safe_browsing/safe_browsing_util.h"
18 namespace safe_browsing {
19 namespace {
21 // JSON metatdata keys. These are are fixed in the Java-side API.
22 const char kJsonKeyMatches[] = "matches";
23 const char kJsonKeyThreatType[] = "threat_type";
25 // Do not reorder or delete. Make sure changes are reflected in
26 // SB2RemoteCallThreatSubType.
27 enum UmaThreatSubType {
28 UMA_THREAT_SUB_TYPE_NOT_SET = 0,
29 UMA_THREAT_SUB_TYPE_LANDING = 1,
30 UMA_THREAT_SUB_TYPE_DISTRIBUTION = 2,
31 UMA_THREAT_SUB_TYPE_UNKNOWN = 3,
32 UMA_THREAT_SUB_TYPE_MAX_VALUE
35 void ReportUmaThreatSubType(SBThreatType threat_type,
36 UmaThreatSubType sub_type) {
37 if (threat_type == SB_THREAT_TYPE_URL_MALWARE) {
38 UMA_HISTOGRAM_ENUMERATION(
39 "SB2.RemoteCall.ThreatSubType.PotentiallyHarmfulApp", sub_type,
40 UMA_THREAT_SUB_TYPE_MAX_VALUE);
41 } else {
42 UMA_HISTOGRAM_ENUMERATION(
43 "SB2.RemoteCall.ThreatSubType.SocialEngineering", sub_type,
44 UMA_THREAT_SUB_TYPE_MAX_VALUE);
48 // Parse the extra key/value pair(s) added by Safe Browsing backend. To make
49 // it binary compatible with the Pver3 metadata that UIManager expects to
50 // deserialize, we convert it to a MalwarePatternType.
52 // TODO(nparker): When chrome desktop is converted to use Pver4, convert this
53 // to the new proto instead.
54 const std::string ParseExtraMetadataToPB(const base::DictionaryValue* match,
55 SBThreatType threat_type) {
56 std::string pattern_key;
57 if (threat_type == SB_THREAT_TYPE_URL_MALWARE) {
58 pattern_key = "pha_pattern_type";
59 } else {
60 DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING);
61 pattern_key = "se_pattern_type";
64 std::string pattern_type;
65 if (!match->GetString(pattern_key, &pattern_type)) {
66 ReportUmaThreatSubType(threat_type, UMA_THREAT_SUB_TYPE_NOT_SET);
67 return std::string();
70 MalwarePatternType pb;
71 if (pattern_type == "LANDING") {
72 pb.set_pattern_type(MalwarePatternType::LANDING);
73 ReportUmaThreatSubType(threat_type, UMA_THREAT_SUB_TYPE_LANDING);
74 } else if (pattern_type == "DISTRIBUTION") {
75 pb.set_pattern_type(MalwarePatternType::DISTRIBUTION);
76 ReportUmaThreatSubType(threat_type, UMA_THREAT_SUB_TYPE_DISTRIBUTION);
77 } else {
78 ReportUmaThreatSubType(threat_type, UMA_THREAT_SUB_TYPE_UNKNOWN);
79 return std::string();
82 return pb.SerializeAsString();
85 int GetThreatSeverity(int java_threat_num) {
86 // Assign higher numbers to more severe threats.
87 switch (java_threat_num) {
88 case JAVA_THREAT_TYPE_POTENTIALLY_HARMFUL_APPLICATION:
89 return 2;
90 case JAVA_THREAT_TYPE_SOCIAL_ENGINEERING:
91 return 1;
92 default:
93 // Unknown threat type
94 return -1;
98 SBThreatType JavaToSBThreatType(int java_threat_num) {
99 switch (java_threat_num) {
100 case JAVA_THREAT_TYPE_POTENTIALLY_HARMFUL_APPLICATION:
101 return SB_THREAT_TYPE_URL_MALWARE;
102 case JAVA_THREAT_TYPE_SOCIAL_ENGINEERING:
103 return SB_THREAT_TYPE_URL_PHISHING;
104 default:
105 // Unknown threat type
106 return SB_THREAT_TYPE_SAFE;
110 } // namespace
113 // Valid examples:
114 // {"matches":[{"threat_type":"5"}]}
115 // or
116 // {"matches":[{"threat_type":"4"},
117 // {"threat_type":"5", "se_pattern_type":"LANDING"}]}
118 UmaRemoteCallResult ParseJsonToThreatAndPB(const std::string& metadata_str,
119 SBThreatType* worst_threat,
120 std::string* metadata_pb_str) {
121 *worst_threat = SB_THREAT_TYPE_SAFE; // Default to safe.
122 *metadata_pb_str = std::string();
124 if (metadata_str.empty())
125 return UMA_STATUS_JSON_EMPTY;
127 // Pick out the "matches" list.
128 scoped_ptr<base::Value> value = base::JSONReader::Read(metadata_str);
129 const base::ListValue* matches;
130 if (!value.get() || !value->IsType(base::Value::TYPE_DICTIONARY) ||
131 !(static_cast<base::DictionaryValue*>(value.get()))
132 ->GetList(kJsonKeyMatches, &matches)) {
133 return UMA_STATUS_JSON_FAILED_TO_PARSE;
136 // Go through each matched threat type and pick the most severe.
137 int worst_threat_num = -1;
138 const base::DictionaryValue* worst_match = nullptr;
139 for (size_t i = 0; i < matches->GetSize(); i++) {
140 // Get the threat number
141 const base::DictionaryValue* match;
142 std::string threat_num_str;
143 int java_threat_num = -1;
144 if (!matches->GetDictionary(i, &match) ||
145 !match->GetString(kJsonKeyThreatType, &threat_num_str) ||
146 !base::StringToInt(threat_num_str, &java_threat_num)) {
147 continue; // Skip malformed list entries
150 if (GetThreatSeverity(java_threat_num) >
151 GetThreatSeverity(worst_threat_num)) {
152 worst_threat_num = java_threat_num;
153 worst_match = match;
157 *worst_threat = JavaToSBThreatType(worst_threat_num);
158 if (*worst_threat == SB_THREAT_TYPE_SAFE || !worst_match)
159 return UMA_STATUS_JSON_UNKNOWN_THREAT;
160 *metadata_pb_str = ParseExtraMetadataToPB(worst_match, *worst_threat);
162 return UMA_STATUS_UNSAFE; // success
165 } // namespace safe_browsing