1 // Copyright (c) 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/extensions/activity_log/activity_actions.h" 6 7 #include <string> 8 9 #include "base/command_line.h" 10 #include "base/json/json_string_value_serializer.h" 11 #include "base/logging.h" 12 #include "base/memory/singleton.h" 13 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_util.h" 15 #include "base/strings/stringprintf.h" 16 #include "chrome/browser/extensions/activity_log/activity_action_constants.h" 17 #include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h" 18 #include "chrome/browser/ui/browser.h" 19 #include "chrome/common/chrome_switches.h" 20 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/web_contents.h" 22 #include "sql/statement.h" 23 24 namespace constants = activity_log_constants; 25 26 namespace { 27 28 std::string Serialize(const base::Value* value) { 29 std::string value_as_text; 30 if (!value) { 31 value_as_text = "null"; 32 } else { 33 JSONStringValueSerializer serializer(&value_as_text); 34 serializer.SerializeAndOmitBinaryValues(*value); 35 } 36 return value_as_text; 37 } 38 39 } // namespace 40 41 namespace extensions { 42 43 using api::activity_log_private::BlockedChromeActivityDetail; 44 using api::activity_log_private::ChromeActivityDetail; 45 using api::activity_log_private::DomActivityDetail; 46 using api::activity_log_private::ExtensionActivity; 47 48 Action::Action(const std::string& extension_id, 49 const base::Time& time, 50 const ActionType action_type, 51 const std::string& api_name) 52 : extension_id_(extension_id), 53 time_(time), 54 action_type_(action_type), 55 api_name_(api_name), 56 page_incognito_(false), 57 arg_incognito_(false) {} 58 59 Action::~Action() {} 60 61 // TODO(mvrable): As an optimization, we might return this directly if the 62 // refcount is one. However, there are likely to be other stray references in 63 // many cases that will prevent this optimization. 64 scoped_refptr<Action> Action::Clone() const { 65 scoped_refptr<Action> clone( 66 new Action(extension_id(), time(), action_type(), api_name())); 67 if (args()) 68 clone->set_args(make_scoped_ptr(args()->DeepCopy())); 69 clone->set_page_url(page_url()); 70 clone->set_page_title(page_title()); 71 clone->set_page_incognito(page_incognito()); 72 clone->set_arg_url(arg_url()); 73 clone->set_arg_incognito(arg_incognito()); 74 if (other()) 75 clone->set_other(make_scoped_ptr(other()->DeepCopy())); 76 return clone; 77 } 78 79 void Action::set_args(scoped_ptr<ListValue> args) { 80 args_.reset(args.release()); 81 } 82 83 ListValue* Action::mutable_args() { 84 if (!args_.get()) { 85 args_.reset(new ListValue()); 86 } 87 return args_.get(); 88 } 89 90 void Action::set_page_url(const GURL& page_url) { 91 page_url_ = page_url; 92 } 93 94 void Action::set_arg_url(const GURL& arg_url) { 95 arg_url_ = arg_url; 96 } 97 98 void Action::set_other(scoped_ptr<DictionaryValue> other) { 99 other_.reset(other.release()); 100 } 101 102 DictionaryValue* Action::mutable_other() { 103 if (!other_.get()) { 104 other_.reset(new DictionaryValue()); 105 } 106 return other_.get(); 107 } 108 109 std::string Action::SerializePageUrl() const { 110 return (page_incognito() ? constants::kIncognitoUrl : "") + page_url().spec(); 111 } 112 113 void Action::ParsePageUrl(const std::string& url) { 114 set_page_incognito(StartsWithASCII(url, constants::kIncognitoUrl, true)); 115 if (page_incognito()) 116 set_page_url(GURL(url.substr(strlen(constants::kIncognitoUrl)))); 117 else 118 set_page_url(GURL(url)); 119 } 120 121 std::string Action::SerializeArgUrl() const { 122 return (arg_incognito() ? constants::kIncognitoUrl : "") + arg_url().spec(); 123 } 124 125 void Action::ParseArgUrl(const std::string& url) { 126 set_arg_incognito(StartsWithASCII(url, constants::kIncognitoUrl, true)); 127 if (arg_incognito()) 128 set_arg_url(GURL(url.substr(strlen(constants::kIncognitoUrl)))); 129 else 130 set_arg_url(GURL(url)); 131 } 132 133 scoped_ptr<ExtensionActivity> Action::ConvertToExtensionActivity() { 134 scoped_ptr<ExtensionActivity> result(new ExtensionActivity); 135 136 result->extension_id.reset(new std::string(extension_id())); 137 result->time.reset(new double(time().ToJsTime())); 138 139 switch (action_type()) { 140 case ACTION_API_CALL: 141 case ACTION_API_EVENT: { 142 ChromeActivityDetail* details = new ChromeActivityDetail; 143 if (action_type() == ACTION_API_CALL) { 144 details->api_activity_type = 145 ChromeActivityDetail::API_ACTIVITY_TYPE_CALL; 146 } else { 147 details->api_activity_type = 148 ChromeActivityDetail::API_ACTIVITY_TYPE_EVENT_CALLBACK; 149 } 150 details->api_call.reset(new std::string(api_name())); 151 details->args.reset(new std::string(Serialize(args()))); 152 details->extra.reset(new std::string(Serialize(other()))); 153 154 result->activity_type = ExtensionActivity::ACTIVITY_TYPE_CHROME; 155 result->chrome_activity_detail.reset(details); 156 break; 157 } 158 159 case ACTION_API_BLOCKED: { 160 BlockedChromeActivityDetail* details = new BlockedChromeActivityDetail; 161 details->api_call.reset(new std::string(api_name())); 162 details->args.reset(new std::string(Serialize(args()))); 163 details->extra.reset(new std::string(Serialize(other()))); 164 // TODO(mvrable): details->reason isn't filled in; fix this after 165 // converting logging to using the types from 166 // BlockedChromeActivityDetail::Reason. 167 details->reason = BlockedChromeActivityDetail::REASON_NONE; 168 169 result->activity_type = ExtensionActivity::ACTIVITY_TYPE_BLOCKED_CHROME; 170 result->blocked_chrome_activity_detail.reset(details); 171 break; 172 } 173 174 case ACTION_DOM_EVENT: 175 case ACTION_DOM_ACCESS: 176 case ACTION_CONTENT_SCRIPT: 177 case ACTION_WEB_REQUEST: { 178 DomActivityDetail* details = new DomActivityDetail; 179 180 if (action_type() == ACTION_WEB_REQUEST) { 181 details->dom_activity_type = 182 DomActivityDetail::DOM_ACTIVITY_TYPE_WEBREQUEST; 183 } else if (action_type() == ACTION_CONTENT_SCRIPT) { 184 details->dom_activity_type = 185 DomActivityDetail::DOM_ACTIVITY_TYPE_INSERTED; 186 } else { 187 // TODO(mvrable): This ought to be filled in properly, but since the 188 // API will change soon don't worry about it now. 189 details->dom_activity_type = 190 DomActivityDetail::DOM_ACTIVITY_TYPE_NONE; 191 } 192 details->api_call.reset(new std::string(api_name())); 193 details->args.reset(new std::string(Serialize(args()))); 194 details->extra.reset(new std::string(Serialize(other()))); 195 if (page_incognito()) { 196 details->url.reset(new std::string(constants::kIncognitoUrl)); 197 } else { 198 details->url.reset(new std::string(page_url().spec())); 199 if (!page_title().empty()) 200 details->url_title.reset(new std::string(page_title())); 201 } 202 203 result->activity_type = ExtensionActivity::ACTIVITY_TYPE_DOM; 204 result->dom_activity_detail.reset(details); 205 break; 206 } 207 208 default: 209 LOG(WARNING) << "Bad activity log entry read from database (type=" 210 << action_type_ << ")!"; 211 } 212 213 return result.Pass(); 214 } 215 216 std::string Action::PrintForDebug() const { 217 std::string result = "ID=" + extension_id() + " CATEGORY="; 218 switch (action_type_) { 219 case ACTION_API_CALL: 220 result += "api_call"; 221 break; 222 case ACTION_API_EVENT: 223 result += "api_event_callback"; 224 break; 225 case ACTION_WEB_REQUEST: 226 result += "webrequest"; 227 break; 228 case ACTION_CONTENT_SCRIPT: 229 result += "content_script"; 230 break; 231 case ACTION_API_BLOCKED: 232 result += "api_blocked"; 233 break; 234 case ACTION_DOM_EVENT: 235 result += "dom_event"; 236 break; 237 case ACTION_DOM_ACCESS: 238 result += "dom_access"; 239 break; 240 default: 241 result += base::StringPrintf("type%d", static_cast<int>(action_type_)); 242 } 243 244 result += " API=" + api_name_; 245 if (args_.get()) { 246 result += " ARGS=" + Serialize(args_.get()); 247 } 248 if (page_url_.is_valid()) { 249 if (page_incognito_) 250 result += " PAGE_URL=(incognito)" + page_url_.spec(); 251 else 252 result += " PAGE_URL=" + page_url_.spec(); 253 } 254 if (!page_title_.empty()) { 255 StringValue title(page_title_); 256 result += " PAGE_TITLE=" + Serialize(&title); 257 } 258 if (arg_url_.is_valid()) { 259 if (arg_incognito_) 260 result += " ARG_URL=(incognito)" + arg_url_.spec(); 261 else 262 result += " ARG_URL=" + arg_url_.spec(); 263 } 264 if (other_.get()) { 265 result += " OTHER=" + Serialize(other_.get()); 266 } 267 268 return result; 269 } 270 271 } // namespace extensions 272