Skip to content

Commit

Permalink
Make sure to ask permissions when requesting camera or microphone
Browse files Browse the repository at this point in the history
Make sure to query the permission manager to ask permissions when
querying the APIs related to microphone and camera.

Following upstream any request originating from HTTP will be ignored.

Please note that CheckMediaAccessPermission was changed to return
false on Android (this was the default behavior before df6e38).

BUG=XWALK-6083
  • Loading branch information
darktears committed Feb 17, 2016
1 parent e9c885d commit bff8b32
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 24 deletions.
156 changes: 146 additions & 10 deletions runtime/browser/media/media_capture_devices_dispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,26 @@

#include "xwalk/runtime/browser/media/media_capture_devices_dispatcher.h"

#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/media_capture_devices.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/media_stream_request.h"
#include "grit/xwalk_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "xwalk/application/browser/application.h"
#include "xwalk/application/browser/application_service.h"
#include "xwalk/runtime/browser/xwalk_browser_context.h"
#include "xwalk/runtime/browser/xwalk_content_settings.h"
#include "xwalk/runtime/common/xwalk_system_locale.h"

#if !defined(OS_ANDROID)
#include "xwalk/runtime/browser/ui/desktop/xwalk_permission_dialog_manager.h"
#endif

using content::BrowserThread;
using content::MediaCaptureDevices;
Expand All @@ -33,46 +50,164 @@ const content::MediaStreamDevice* FindDefaultDeviceWithId(

} // namespace

namespace xwalk {

XWalkMediaCaptureDevicesDispatcher*
XWalkMediaCaptureDevicesDispatcher::GetInstance() {
return base::Singleton<XWalkMediaCaptureDevicesDispatcher>::get();
}

bool ContentTypeIsRequested(ContentSettingsType type,
const content::MediaStreamRequest& request) {
if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)
return request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE;
if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)
return request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE;

return false;
}

int GetDialogMessageText(const content::MediaStreamRequest& request) {
bool audio_requested =
request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE;
bool video_requested =
request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE;
if (audio_requested && video_requested)
return IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO;
if (video_requested)
return IDS_MEDIA_CAPTURE_VIDEO_ONLY;

return IDS_MEDIA_CAPTURE_AUDIO_ONLY;
}

void XWalkMediaCaptureDevicesDispatcher::RunRequestMediaAccessPermission(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback) {
content::MediaStreamDevices devices;
// Based on chrome/browser/media/media_stream_devices_controller.cc.
bool microphone_requested =
(request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE);
bool webcam_requested =
(request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE);
if (microphone_requested || webcam_requested) {
if (ContentTypeIsRequested(
CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, request) ||
ContentTypeIsRequested(
CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, request)) {
switch (request.request_type) {
case content::MEDIA_OPEN_DEVICE_PEPPER_ONLY:
case content::MEDIA_DEVICE_ACCESS:
case content::MEDIA_GENERATE_STREAM:
case content::MEDIA_ENUMERATE_DEVICES:
case content::MEDIA_ENUMERATE_DEVICES: {
#if defined (OS_ANDROID)
// Get the exact audio and video devices if id is specified.
// Or get the default devices when requested device id is empty.
XWalkMediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice(
request.requested_audio_device_id,
request.requested_video_device_id,
microphone_requested,
webcam_requested,
request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE,
request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE,
&devices);
break;
#else
RequestPermissionToUser(web_contents, request, callback);
break;
#endif
}
}
}
#if defined (OS_ANDROID)
callback.Run(devices,
devices.empty() ?
content::MEDIA_DEVICE_NO_HARDWARE :
content::MEDIA_DEVICE_OK,
scoped_ptr<content::MediaStreamUI>());
#endif
}

#if !defined (OS_ANDROID)
void XWalkMediaCaptureDevicesDispatcher::RequestPermissionToUser(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

if (request.security_origin.SchemeIs(url::kHttpScheme))
callback.Run(content::MediaStreamDevices(),
content::MEDIA_DEVICE_PERMISSION_DENIED,
scoped_ptr<content::MediaStreamUI>());

XWalkPermissionDialogManager* permission_dialog_manager =
XWalkPermissionDialogManager::GetPermissionDialogManager(web_contents);

XWalkBrowserContext* browser_context =
static_cast<XWalkBrowserContext*>(web_contents->GetBrowserContext());

PrefService* pref_service =
user_prefs::UserPrefs::Get(browser_context);

application::Application* app =
browser_context->application_service()->GetApplicationByRenderHostID(
web_contents->GetMainFrame()->GetProcess()->GetID());
std::string app_name;
if (app)
app_name = app->data()->Name();

ContentSettingsType content_settings_type =
request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE
? CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
: CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA;

base::string16 dialog_text = l10n_util::GetStringFUTF16(
GetDialogMessageText(request),
base::ASCIIToUTF16(app_name));

permission_dialog_manager->RequestPermission(
content_settings_type,
request.security_origin,
pref_service->GetString(kIntlAcceptLanguage), dialog_text,
base::Bind(
&XWalkMediaCaptureDevicesDispatcher::OnPermissionRequestFinished,
callback, request, web_contents));
}

void XWalkMediaCaptureDevicesDispatcher::OnPermissionRequestFinished(
const content::MediaResponseCallback& callback,
const content::MediaStreamRequest& request,
content::WebContents* web_contents,
bool success) {
content::MediaStreamDevices devices;
bool audio_requested =
request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE;
bool video_requested =
request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE;
// We always request the permission for the audio capture if both audio and
// video are requested (though the dialog clearly shows both),
// let's make sure we set the video as well in the settings.
if (audio_requested && video_requested) {
XWalkContentSettings::GetInstance()->SetPermission(
CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
request.security_origin,
web_contents->GetLastCommittedURL().GetOrigin(),
success ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK);
}
if (success) {
// Get the exact audio and video devices if id is specified.
// Or get the default devices when requested device id is empty.
XWalkMediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice(
request.requested_audio_device_id,
request.requested_video_device_id,
audio_requested,
video_requested,
&devices);
callback.Run(devices,
devices.empty() ?
content::MEDIA_DEVICE_NO_HARDWARE :
content::MEDIA_DEVICE_OK,
scoped_ptr<content::MediaStreamUI>());
} else {
callback.Run(devices,
content::MEDIA_DEVICE_PERMISSION_DENIED,
scoped_ptr<content::MediaStreamUI>());
}
}
#endif

XWalkMediaCaptureDevicesDispatcher::XWalkMediaCaptureDevicesDispatcher() {}

XWalkMediaCaptureDevicesDispatcher::~XWalkMediaCaptureDevicesDispatcher() {}
Expand Down Expand Up @@ -190,7 +325,6 @@ void XWalkMediaCaptureDevicesDispatcher::UpdateMediaReqStateOnUIThread(
state));
}


void XWalkMediaCaptureDevicesDispatcher::SetTestAudioCaptureDevices(
const MediaStreamDevices& devices) {
test_audio_devices_ = devices;
Expand All @@ -200,3 +334,5 @@ void XWalkMediaCaptureDevicesDispatcher::SetTestVideoCaptureDevices(
const MediaStreamDevices& devices) {
test_video_devices_ = devices;
}

} // namespace xwalk
14 changes: 14 additions & 0 deletions runtime/browser/media/media_capture_devices_dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/common/media_stream_request.h"

namespace xwalk {
// This singleton is used to receive updates about media events from the content
// layer. Based on chrome/browser/media/media_capture_devices_dispatcher.[h|cc].
class XWalkMediaCaptureDevicesDispatcher : public content::MediaObserver {
Expand Down Expand Up @@ -91,6 +92,17 @@ class XWalkMediaCaptureDevicesDispatcher : public content::MediaObserver {
XWalkMediaCaptureDevicesDispatcher();
~XWalkMediaCaptureDevicesDispatcher() override;

#if !defined (OS_ANDROID)
static void OnPermissionRequestFinished(
const content::MediaResponseCallback& callback,
const content::MediaStreamRequest& request,
content::WebContents* web_contents,
bool success);
static void RequestPermissionToUser(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback);
#endif
// Called by the MediaObserver() functions, executed on UI thread.
void NotifyAudioDevicesChangedOnUIThread();
void NotifyVideoDevicesChangedOnUIThread();
Expand All @@ -111,4 +123,6 @@ class XWalkMediaCaptureDevicesDispatcher : public content::MediaObserver {
base::ObserverList<Observer> observers_;
};

} // namespace xwalk

#endif // XWALK_RUNTIME_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_
26 changes: 22 additions & 4 deletions runtime/browser/runtime.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "components/app_modal/javascript_dialog_manager.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
Expand All @@ -30,6 +32,7 @@
#include "xwalk/runtime/browser/xwalk_autofill_manager.h"
#include "xwalk/runtime/browser/xwalk_browser_context.h"
#include "xwalk/runtime/browser/xwalk_content_browser_client.h"
#include "xwalk/runtime/browser/xwalk_content_settings.h"
#include "xwalk/runtime/browser/xwalk_runner.h"
#include "xwalk/runtime/common/xwalk_notification_types.h"
#include "xwalk/runtime/common/xwalk_switches.h"
Expand Down Expand Up @@ -340,10 +343,25 @@ bool Runtime::CheckMediaAccessPermission(
const GURL& security_origin,
content::MediaStreamType type) {
// Requested by Pepper Flash plugin and mediaDevices.enumerateDevices().
// FIXME(huningxin): current code grants the access by default. It should
// follow the generic permssions mechanism (XWALK-5475). Open XWALK-6083 to
// track it.
return true;
#if defined (OS_ANDROID)
return false;
#else
// This function may be called for a media request coming from
// from WebRTC/mediaDevices. These requests can't be made from HTTP.
if (security_origin.SchemeIs(url::kHttpScheme))
return false;

ContentSettingsType content_settings_type =
type == content::MEDIA_DEVICE_AUDIO_CAPTURE
? CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
: CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA;
ContentSetting content_setting =
XWalkContentSettings::GetInstance()->GetPermission(
content_settings_type,
security_origin,
web_contents_->GetLastCommittedURL().GetOrigin());
return content_setting == CONTENT_SETTING_ALLOW;
#endif
}

void Runtime::LoadProgressChanged(content::WebContents* source,
Expand Down
7 changes: 1 addition & 6 deletions runtime/browser/runtime_geolocation_permission_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,7 @@ RuntimeGeolocationPermissionContext::RequestGeolocationPermission(
#else
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
XWalkPermissionDialogManager* permission_dialog_manager =
XWalkPermissionDialogManager::FromWebContents(web_contents);
if (!permission_dialog_manager) {
XWalkPermissionDialogManager::CreateForWebContents(web_contents);
permission_dialog_manager =
XWalkPermissionDialogManager::FromWebContents(web_contents);
}
XWalkPermissionDialogManager::GetPermissionDialogManager(web_contents);

PrefService* pref_service =
user_prefs::UserPrefs::Get(XWalkBrowserContext::GetDefault());
Expand Down
21 changes: 17 additions & 4 deletions runtime/browser/ui/desktop/xwalk_permission_dialog_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@ XWalkPermissionDialogManager::~XWalkPermissionDialogManager() {
CancelPermissionRequest();
}

XWalkPermissionDialogManager*
XWalkPermissionDialogManager::GetPermissionDialogManager(
content::WebContents* web_contents) {
XWalkPermissionDialogManager* permission_dialog_manager =
XWalkPermissionDialogManager::FromWebContents(web_contents);
if (!permission_dialog_manager) {
XWalkPermissionDialogManager::CreateForWebContents(web_contents);
permission_dialog_manager =
XWalkPermissionDialogManager::FromWebContents(web_contents);
}
return permission_dialog_manager;
}

void XWalkPermissionDialogManager::WebContentsDestroyed() {
CancelPermissionRequest();
web_contents_->RemoveUserData(UserDataKey());
Expand Down Expand Up @@ -60,10 +73,10 @@ void XWalkPermissionDialogManager::RequestPermission(
default: {
app_modal::AppModalDialogQueue::GetInstance()->AddDialog(
new XWalkPermissionModalDialog(
web_contents_,
message_text,
base::Bind(&XWalkPermissionDialogManager::OnPermissionDialogClosed,
base::Unretained(this), type, origin_url, callback)));
web_contents_,
message_text,
base::Bind(&XWalkPermissionDialogManager::OnPermissionDialogClosed,
base::Unretained(this), type, origin_url, callback)));
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions runtime/browser/ui/desktop/xwalk_permission_dialog_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ class XWalkPermissionDialogManager
: public content::WebContentsObserver,
public content::WebContentsUserData<XWalkPermissionDialogManager> {
public:
static XWalkPermissionDialogManager* GetPermissionDialogManager(
content::WebContents* web_contents);
void RequestPermission(
ContentSettingsType type,
const GURL& origin_url,
Expand Down
3 changes: 3 additions & 0 deletions runtime/browser/xwalk_browser_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ class XWalkBrowserContext
void UpdateAcceptLanguages(const std::string& accept_languages);
void set_save_form_data(bool enable) { save_form_data_ = enable; }
bool save_form_data() const { return save_form_data_; }
application::ApplicationService* application_service() const {
return application_service_;
}
void set_application_service(
application::ApplicationService* application_service) {
application_service_ = application_service;
Expand Down
15 changes: 15 additions & 0 deletions runtime/resources/xwalk_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,21 @@
$1<ex>maps.google.com</ex>
</ph> wants to use your computer's location.
</message>
<message name="IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO" desc="Question asked on the dialog whenever a web page requests access to the computer's microphone and camera.">
<ph name="HOST">
$1<ex>html5rocks.com</ex>
</ph> wants to use your camera and microphone.
</message>
<message name="IDS_MEDIA_CAPTURE_AUDIO_ONLY" desc="Question asked on the dialog whenever a web page requests access to the computer's microphone.">
<ph name="HOST">
$1<ex>html5rocks.com</ex>
</ph> wants to use your microphone.
</message>
<message name="IDS_MEDIA_CAPTURE_VIDEO_ONLY" desc="Question asked on the dialog whenever a web page requests access to the computer's camera.">
<ph name="HOST">
$1<ex>html5rocks.com</ex>
</ph> wants to use your camera.
</message>
<message name="IDS_PERMISSION_ALLOW" desc="Label on button to allow a permissions request.">
Allow
</message>
Expand Down

0 comments on commit bff8b32

Please sign in to comment.