Bug 1044736 - Part 6. Widget should only require embed-widgets permission. r=fabrice

As discussed on dev-webapi[1] the app that wants to use widgets only
need the "embed-widgets" permission to use <iframe mozbrowser mozwidget>

If the app also wants to implement a browser, it could request the
"browser" separately. A <iframe mozbrowser mozwidget> will have
restricted mozbrowser API defined on the prototype if the embedder has
the "brower" permission; they will always throw when used.

[1]: https://groups.google.com/d/msg/mozilla.dev.webapi/uQweGWtVKRA/Bj1jZq3LN-0J

--HG--
rename : dom/apps/tests/test_widget.html => dom/apps/tests/test_widget_browser.html
This commit is contained in:
Kan-Ru Chen (陳侃如) 2014-11-21 18:56:28 +08:00
parent be64833b75
commit b61618c420
7 changed files with 82 additions and 14 deletions

View File

@ -1,6 +1,7 @@
var gWidgetManifestURL = 'http://test/tests/dom/apps/tests/file_app.sjs?apptype=widget&getmanifest=true'; var gWidgetManifestURL = 'http://test/tests/dom/apps/tests/file_app.sjs?apptype=widget&getmanifest=true';
var gInvalidWidgetManifestURL = 'http://test/tests/dom/apps/tests/file_app.sjs?apptype=invalidWidget&getmanifest=true'; var gInvalidWidgetManifestURL = 'http://test/tests/dom/apps/tests/file_app.sjs?apptype=invalidWidget&getmanifest=true';
var gApp; var gApp;
var gHasBrowserPermission;
function onError() { function onError() {
ok(false, "Error callback invoked"); ok(false, "Error callback invoked");
@ -82,21 +83,34 @@ function testApp(isValidWidget) {
function testLimitedBrowserAPI(ifr) { function testLimitedBrowserAPI(ifr) {
var securitySensitiveCalls = [ var securitySensitiveCalls = [
'sendMouseEvent', { api: 'sendMouseEvent' , args: ['mousedown', 0, 0, 0, 0, 0] },
'sendTouchEvent', { api: 'sendTouchEvent' , args: ['touchstart', [0], [0], [0], [1], [1], [0], [1], 1, 0] },
'goBack', { api: 'goBack' , args: [] },
'goForward', { api: 'goForward' , args: [] },
'reload', { api: 'reload' , args: [] },
'stop', { api: 'stop' , args: [] },
'download', { api: 'download' , args: ['http://example.org'] },
'purgeHistory', { api: 'purgeHistory' , args: [] },
'getScreenshot', { api: 'getScreenshot' , args: [0, 0] },
'zoom', { api: 'zoom' , args: [0.1] },
'getCanGoBack', { api: 'getCanGoBack' , args: [] },
'getCanGoForward' { api: 'getCanGoForward' , args: [] },
{ api: 'getContentDimensions', args: [] }
]; ];
securitySensitiveCalls.forEach( function(call) { securitySensitiveCalls.forEach( function(call) {
is(typeof ifr[call], "undefined", call + " should be hidden for widget"); if (gHasBrowserPermission) {
isnot(typeof ifr[call.api], "undefined", call.api + " should be defined");
var didThrow;
try {
ifr[call.api].apply(ifr, call.args);
} catch (e) {
ok(e instanceof DOMException, "throw right exception type");
didThrow = e.code;
}
is(didThrow, DOMException.INVALID_NODE_TYPE_ERR, "call " + call.api + " should throw exception");
} else {
is(typeof ifr[call.api], "undefined", call.api + " should be hidden for widget");
}
}); });
} }
@ -154,7 +168,7 @@ var tests = [
// Permissions // Permissions
function() { function() {
SpecialPowers.pushPermissions( SpecialPowers.pushPermissions(
[{ "type": "browser", "allow": 1, "context": document }, [{ "type": "browser", "allow": gHasBrowserPermission ? 1 : 0, "context": document },
{ "type": "embed-widgets", "allow": 1, "context": document }, { "type": "embed-widgets", "allow": 1, "context": document },
{ "type": "webapps-manage", "allow": 1, "context": document }], runTest); { "type": "webapps-manage", "allow": 1, "context": document }], runTest);
}, },

View File

@ -45,3 +45,5 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
[test_web_app_install.html] [test_web_app_install.html]
[test_widget.html] [test_widget.html]
skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
[test_widget_browser.html]
skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app

View File

@ -11,6 +11,7 @@
<div id="container"></div> <div id="container"></div>
<script type="application/javascript;version=1.7"> <script type="application/javascript;version=1.7">
SimpleTest.waitForExplicitFinish(); SimpleTest.waitForExplicitFinish();
gHasBrowserPermission = false;
runTest(); runTest();
</script> </script>
</body> </body>

View File

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for DataStore - basic operation on a readonly db</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="file_test_widget.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="container"></div>
<script type="application/javascript;version=1.7">
SimpleTest.waitForExplicitFinish();
gHasBrowserPermission = true;
runTest();
</script>
</body>
</html>

View File

@ -114,6 +114,16 @@ nsBrowserElement::IsBrowserElementOrThrow(ErrorResult& aRv)
return false; return false;
} }
bool
nsBrowserElement::IsNotWidgetOrThrow(ErrorResult& aRv)
{
if (!mOwnerIsWidget) {
return true;
}
aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
return false;
}
void void
nsBrowserElement::InitBrowserElementAPI() nsBrowserElement::InitBrowserElementAPI()
{ {
@ -122,6 +132,8 @@ nsBrowserElement::InitBrowserElementAPI()
NS_ENSURE_TRUE_VOID(frameLoader); NS_ENSURE_TRUE_VOID(frameLoader);
nsresult rv = frameLoader->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp); nsresult rv = frameLoader->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp);
NS_ENSURE_SUCCESS_VOID(rv); NS_ENSURE_SUCCESS_VOID(rv);
rv = frameLoader->GetOwnerIsWidget(&mOwnerIsWidget);
NS_ENSURE_SUCCESS_VOID(rv);
if (!isBrowserOrApp) { if (!isBrowserOrApp) {
return; return;
@ -134,6 +146,7 @@ nsBrowserElement::InitBrowserElementAPI()
} }
nsBrowserElement::nsBrowserElement() nsBrowserElement::nsBrowserElement()
: mOwnerIsWidget(false)
{ {
mObserver = new BrowserShownObserver(this); mObserver = new BrowserShownObserver(this);
mObserver->AddObserver(); mObserver->AddObserver();
@ -210,6 +223,7 @@ nsBrowserElement::SendMouseEvent(const nsAString& aType,
ErrorResult& aRv) ErrorResult& aRv)
{ {
NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv)); NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
nsresult rv = mBrowserElementAPI->SendMouseEvent(aType, nsresult rv = mBrowserElementAPI->SendMouseEvent(aType,
aX, aX,
@ -237,6 +251,7 @@ nsBrowserElement::SendTouchEvent(const nsAString& aType,
ErrorResult& aRv) ErrorResult& aRv)
{ {
NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv)); NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
if (aIdentifiers.Length() != aCount || if (aIdentifiers.Length() != aCount ||
aXs.Length() != aCount || aXs.Length() != aCount ||
@ -269,6 +284,7 @@ void
nsBrowserElement::GoBack(ErrorResult& aRv) nsBrowserElement::GoBack(ErrorResult& aRv)
{ {
NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv)); NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
nsresult rv = mBrowserElementAPI->GoBack(); nsresult rv = mBrowserElementAPI->GoBack();
@ -281,6 +297,7 @@ void
nsBrowserElement::GoForward(ErrorResult& aRv) nsBrowserElement::GoForward(ErrorResult& aRv)
{ {
NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv)); NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
nsresult rv = mBrowserElementAPI->GoForward(); nsresult rv = mBrowserElementAPI->GoForward();
@ -293,6 +310,7 @@ void
nsBrowserElement::Reload(bool aHardReload, ErrorResult& aRv) nsBrowserElement::Reload(bool aHardReload, ErrorResult& aRv)
{ {
NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv)); NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
nsresult rv = mBrowserElementAPI->Reload(aHardReload); nsresult rv = mBrowserElementAPI->Reload(aHardReload);
@ -305,6 +323,7 @@ void
nsBrowserElement::Stop(ErrorResult& aRv) nsBrowserElement::Stop(ErrorResult& aRv)
{ {
NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv)); NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
nsresult rv = mBrowserElementAPI->Stop(); nsresult rv = mBrowserElementAPI->Stop();
@ -319,6 +338,7 @@ nsBrowserElement::Download(const nsAString& aUrl,
ErrorResult& aRv) ErrorResult& aRv)
{ {
NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr); NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr);
nsCOMPtr<nsIDOMDOMRequest> req; nsCOMPtr<nsIDOMDOMRequest> req;
AutoJSAPI jsapi; AutoJSAPI jsapi;
@ -342,6 +362,7 @@ already_AddRefed<DOMRequest>
nsBrowserElement::PurgeHistory(ErrorResult& aRv) nsBrowserElement::PurgeHistory(ErrorResult& aRv)
{ {
NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr); NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr);
nsCOMPtr<nsIDOMDOMRequest> req; nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = mBrowserElementAPI->PurgeHistory(getter_AddRefs(req)); nsresult rv = mBrowserElementAPI->PurgeHistory(getter_AddRefs(req));
@ -361,6 +382,7 @@ nsBrowserElement::GetScreenshot(uint32_t aWidth,
ErrorResult& aRv) ErrorResult& aRv)
{ {
NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr); NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr);
nsCOMPtr<nsIDOMDOMRequest> req; nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = mBrowserElementAPI->GetScreenshot(aWidth, aHeight, aMimeType, nsresult rv = mBrowserElementAPI->GetScreenshot(aWidth, aHeight, aMimeType,
@ -382,6 +404,8 @@ void
nsBrowserElement::Zoom(float aZoom, ErrorResult& aRv) nsBrowserElement::Zoom(float aZoom, ErrorResult& aRv)
{ {
NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv)); NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
nsresult rv = mBrowserElementAPI->Zoom(aZoom); nsresult rv = mBrowserElementAPI->Zoom(aZoom);
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
@ -393,6 +417,7 @@ already_AddRefed<DOMRequest>
nsBrowserElement::GetCanGoBack(ErrorResult& aRv) nsBrowserElement::GetCanGoBack(ErrorResult& aRv)
{ {
NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr); NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr);
nsCOMPtr<nsIDOMDOMRequest> req; nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = mBrowserElementAPI->GetCanGoBack(getter_AddRefs(req)); nsresult rv = mBrowserElementAPI->GetCanGoBack(getter_AddRefs(req));
@ -409,6 +434,7 @@ already_AddRefed<DOMRequest>
nsBrowserElement::GetCanGoForward(ErrorResult& aRv) nsBrowserElement::GetCanGoForward(ErrorResult& aRv)
{ {
NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr); NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr);
nsCOMPtr<nsIDOMDOMRequest> req; nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = mBrowserElementAPI->GetCanGoForward(getter_AddRefs(req)); nsresult rv = mBrowserElementAPI->GetCanGoForward(getter_AddRefs(req));
@ -425,6 +451,7 @@ already_AddRefed<DOMRequest>
nsBrowserElement::GetContentDimensions(ErrorResult& aRv) nsBrowserElement::GetContentDimensions(ErrorResult& aRv)
{ {
NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr); NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr);
nsCOMPtr<nsIDOMDOMRequest> req; nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = mBrowserElementAPI->GetContentDimensions(getter_AddRefs(req)); nsresult rv = mBrowserElementAPI->GetContentDimensions(getter_AddRefs(req));

View File

@ -96,6 +96,8 @@ protected:
private: private:
void InitBrowserElementAPI(); void InitBrowserElementAPI();
bool IsBrowserElementOrThrow(ErrorResult& aRv); bool IsBrowserElementOrThrow(ErrorResult& aRv);
bool IsNotWidgetOrThrow(ErrorResult& aRv);
bool mOwnerIsWidget;
class BrowserShownObserver; class BrowserShownObserver;
friend class BrowserShownObserver; friend class BrowserShownObserver;

View File

@ -307,6 +307,10 @@ nsGenericHTMLFrameElement::GetReallyIsBrowserOrApp(bool *aOut)
uint32_t permission = nsIPermissionManager::DENY_ACTION; uint32_t permission = nsIPermissionManager::DENY_ACTION;
nsresult rv = permMgr->TestPermissionFromPrincipal(principal, "browser", &permission); nsresult rv = permMgr->TestPermissionFromPrincipal(principal, "browser", &permission);
NS_ENSURE_SUCCESS(rv, NS_OK); NS_ENSURE_SUCCESS(rv, NS_OK);
if (permission != nsIPermissionManager::ALLOW_ACTION) {
rv = permMgr->TestPermissionFromPrincipal(principal, "embed-widgets", &permission);
NS_ENSURE_SUCCESS(rv, NS_OK);
}
*aOut = permission == nsIPermissionManager::ALLOW_ACTION; *aOut = permission == nsIPermissionManager::ALLOW_ACTION;
return NS_OK; return NS_OK;
} }