1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
// Copyright (c) 2012 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.
// Implements the Chrome Extensions Tab Capture API.
#include "chrome/browser/extensions/api/tab_capture/tab_capture_api.h"
#include <set>
#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
#include "chrome/browser/extensions/extension_renderer_state.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "extensions/common/features/feature.h"
#include "extensions/common/features/feature_provider.h"
#include "extensions/common/features/simple_feature.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/switches.h"
using extensions::api::tab_capture::MediaStreamConstraint;
namespace TabCapture = extensions::api::tab_capture;
namespace GetCapturedTabs = TabCapture::GetCapturedTabs;
namespace extensions {
namespace {
const char kCapturingSameTab[] = "Cannot capture a tab with an active stream.";
const char kFindingTabError[] = "Error finding tab to capture.";
const char kNoAudioOrVideo[] = "Capture failed. No audio or video requested.";
const char kGrantError[] =
"Extension has not been invoked for the current page (see activeTab "
"permission). Chrome pages cannot be captured.";
// Keys/values for media stream constraints.
const char kMediaStreamSource[] = "chromeMediaSource";
const char kMediaStreamSourceId[] = "chromeMediaSourceId";
const char kMediaStreamSourceTab[] = "tab";
// Whitelisted extensions that do not check for a browser action grant because
// they provide API's.
const char* whitelisted_extensions[] = {
"enhhojjnijigcajfphajepfemndkmdlo", // Dev
"pkedcjkdefgpdelpbcmbmeomcjbeemfm", // Trusted Tester
"fmfcbgogabcbclcofgocippekhfcmgfj", // Staging
"hfaagokkkhdbgiakmmlclaapfelnkoah", // Canary
"F155646B5D1CA545F7E1E4E20D573DFDD44C2540", // Trusted Tester (public)
"16CA7A47AAE4BE49B1E75A6B960C3875E945B264" // Release
};
} // namespace
bool TabCaptureCaptureFunction::RunSync() {
scoped_ptr<api::tab_capture::Capture::Params> params =
TabCapture::Capture::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params.get());
// Figure out the active WebContents and retrieve the needed ids.
Browser* target_browser = chrome::FindAnyBrowser(
GetProfile(), include_incognito(), chrome::GetActiveDesktop());
if (!target_browser) {
error_ = kFindingTabError;
return false;
}
content::WebContents* target_contents =
target_browser->tab_strip_model()->GetActiveWebContents();
if (!target_contents) {
error_ = kFindingTabError;
return false;
}
const Extension* extension = GetExtension();
const std::string& extension_id = extension->id();
const int tab_id = SessionID::IdForTab(target_contents);
// Make sure either we have been granted permission to capture through an
// extension icon click or our extension is whitelisted.
if (!extension->permissions_data()->HasAPIPermissionForTab(
tab_id, APIPermission::kTabCaptureForTab) &&
CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kWhitelistedExtensionID) != extension_id &&
!SimpleFeature::IsIdInList(
extension_id,
std::set<std::string>(
whitelisted_extensions,
whitelisted_extensions + arraysize(whitelisted_extensions)))) {
error_ = kGrantError;
return false;
}
content::RenderViewHost* const rvh = target_contents->GetRenderViewHost();
int render_process_id = rvh->GetProcess()->GetID();
int routing_id = rvh->GetRoutingID();
// Create a constraints vector. We will modify all the constraints in this
// vector to append our chrome specific constraints.
std::vector<MediaStreamConstraint*> constraints;
bool has_audio = params->options.audio.get() && *params->options.audio.get();
bool has_video = params->options.video.get() && *params->options.video.get();
if (!has_audio && !has_video) {
error_ = kNoAudioOrVideo;
return false;
}
if (has_audio) {
if (!params->options.audio_constraints.get())
params->options.audio_constraints.reset(new MediaStreamConstraint);
constraints.push_back(params->options.audio_constraints.get());
}
if (has_video) {
if (!params->options.video_constraints.get())
params->options.video_constraints.reset(new MediaStreamConstraint);
constraints.push_back(params->options.video_constraints.get());
}
// Device id we use for Tab Capture.
std::string device_id =
base::StringPrintf("%i:%i", render_process_id, routing_id);
// Append chrome specific tab constraints.
for (std::vector<MediaStreamConstraint*>::iterator it = constraints.begin();
it != constraints.end(); ++it) {
base::DictionaryValue* constraint = &(*it)->mandatory.additional_properties;
constraint->SetString(kMediaStreamSource, kMediaStreamSourceTab);
constraint->SetString(kMediaStreamSourceId, device_id);
}
extensions::TabCaptureRegistry* registry =
extensions::TabCaptureRegistry::Get(GetProfile());
if (!registry->AddRequest(render_process_id,
routing_id,
extension_id,
tab_id,
tab_capture::TAB_CAPTURE_STATE_NONE)) {
error_ = kCapturingSameTab;
return false;
}
// Copy the result from our modified input parameters. This will be
// intercepted by custom bindings which will build and send the special
// WebRTC user media request.
base::DictionaryValue* result = new base::DictionaryValue();
result->MergeDictionary(params->options.ToValue().get());
SetResult(result);
return true;
}
bool TabCaptureGetCapturedTabsFunction::RunSync() {
extensions::TabCaptureRegistry* registry =
extensions::TabCaptureRegistry::Get(GetProfile());
const TabCaptureRegistry::RegistryCaptureInfo& captured_tabs =
registry->GetCapturedTabs(GetExtension()->id());
base::ListValue *list = new base::ListValue();
for (TabCaptureRegistry::RegistryCaptureInfo::const_iterator it =
captured_tabs.begin(); it != captured_tabs.end(); ++it) {
scoped_ptr<tab_capture::CaptureInfo> info(new tab_capture::CaptureInfo());
info->tab_id = it->first;
info->status = it->second;
list->Append(info->ToValue().release());
}
SetResult(list);
return true;
}
} // namespace extensions
|