зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1697633 - Update onLocationChange to include permission reporting; add getAllPermissions and getPermissions to StorageController. r=agi,geckoview-reviewers,owlish
Differential Revision: https://phabricator.services.mozilla.com/D107927
This commit is contained in:
Родитель
a0f12f0bd5
Коммит
ab0bb6167e
|
@ -107,6 +107,8 @@ class GeckoViewStartup {
|
|||
"GeckoView:ClearData",
|
||||
"GeckoView:ClearSessionContextData",
|
||||
"GeckoView:ClearHostData",
|
||||
"GeckoView:GetAllPermissions",
|
||||
"GeckoView:GetPermissionsByURI",
|
||||
],
|
||||
});
|
||||
|
||||
|
|
|
@ -899,7 +899,8 @@ package org.mozilla.geckoview {
|
|||
method @UiThread default public void onCanGoForward(@NonNull GeckoSession, boolean);
|
||||
method @Nullable @UiThread default public GeckoResult<String> onLoadError(@NonNull GeckoSession, @Nullable String, @NonNull WebRequestError);
|
||||
method @Nullable @UiThread default public GeckoResult<AllowOrDeny> onLoadRequest(@NonNull GeckoSession, @NonNull GeckoSession.NavigationDelegate.LoadRequest);
|
||||
method @UiThread default public void onLocationChange(@NonNull GeckoSession, @Nullable String);
|
||||
method @DeprecationSchedule(id="location-permissions",version=92) @UiThread default public void onLocationChange(@NonNull GeckoSession, @Nullable String);
|
||||
method @UiThread default public void onLocationChange(@NonNull GeckoSession, @Nullable String, @NonNull List<GeckoSession.PermissionDelegate.ContentPermission>);
|
||||
method @Nullable @UiThread default public GeckoResult<GeckoSession> onNewSession(@NonNull GeckoSession, @NonNull String);
|
||||
method @Nullable @UiThread default public GeckoResult<AllowOrDeny> onSubframeLoadRequest(@NonNull GeckoSession, @NonNull GeckoSession.NavigationDelegate.LoadRequest);
|
||||
field public static final int LOAD_REQUEST_IS_REDIRECT = 8388608;
|
||||
|
@ -936,6 +937,17 @@ package org.mozilla.geckoview {
|
|||
method @UiThread default public void reject();
|
||||
}
|
||||
|
||||
public static class GeckoSession.PermissionDelegate.ContentPermission {
|
||||
ctor protected ContentPermission();
|
||||
field public static final int VALUE_ALLOW = 1;
|
||||
field public static final int VALUE_DENY = 2;
|
||||
field public static final int VALUE_PROMPT = 3;
|
||||
field public final int permission;
|
||||
field public final boolean privateMode;
|
||||
field @NonNull public final String uri;
|
||||
field public final int value;
|
||||
}
|
||||
|
||||
public static interface GeckoSession.PermissionDelegate.MediaCallback {
|
||||
method @UiThread default public void grant(@Nullable String, @Nullable String);
|
||||
method @UiThread default public void grant(@Nullable GeckoSession.PermissionDelegate.MediaSource, @Nullable GeckoSession.PermissionDelegate.MediaSource);
|
||||
|
@ -1642,6 +1654,8 @@ package org.mozilla.geckoview {
|
|||
method @AnyThread @NonNull public GeckoResult<Void> clearData(long);
|
||||
method @AnyThread public void clearDataForSessionContext(@NonNull String);
|
||||
method @AnyThread @NonNull public GeckoResult<Void> clearDataFromHost(@NonNull String, long);
|
||||
method @AnyThread @NonNull public GeckoResult<List<GeckoSession.PermissionDelegate.ContentPermission>> getAllPermissions();
|
||||
method @AnyThread @NonNull public GeckoResult<List<GeckoSession.PermissionDelegate.ContentPermission>> getPermissions(@NonNull String);
|
||||
}
|
||||
|
||||
public static class StorageController.ClearFlags {
|
||||
|
|
|
@ -1171,7 +1171,7 @@ class NavigationDelegateTest : BaseSessionTest() {
|
|||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onLocationChange(session: GeckoSession, url: String?) {
|
||||
override fun onLocationChange(session: GeckoSession, url: String?, perms : MutableList<GeckoSession.PermissionDelegate.ContentPermission>) {
|
||||
assertThat("URL should match", url, endsWith(HELLO2_HTML_PATH))
|
||||
}
|
||||
})
|
||||
|
@ -1190,7 +1190,7 @@ class NavigationDelegateTest : BaseSessionTest() {
|
|||
}
|
||||
|
||||
@AssertCalled(count = 1, order = [2])
|
||||
override fun onLocationChange(session: GeckoSession, url: String?) {
|
||||
override fun onLocationChange(session: GeckoSession, url: String?, perms : MutableList<GeckoSession.PermissionDelegate.ContentPermission>) {
|
||||
assertThat("URL should match", url, endsWith(HELLO_HTML_PATH))
|
||||
}
|
||||
|
||||
|
@ -1224,7 +1224,7 @@ class NavigationDelegateTest : BaseSessionTest() {
|
|||
}
|
||||
|
||||
@AssertCalled(count = 1, order = [2])
|
||||
override fun onLocationChange(session: GeckoSession, url: String?) {
|
||||
override fun onLocationChange(session: GeckoSession, url: String?, perms : MutableList<GeckoSession.PermissionDelegate.ContentPermission>) {
|
||||
assertThat("URL should match", url, endsWith(HELLO2_HTML_PATH))
|
||||
}
|
||||
|
||||
|
@ -1949,7 +1949,7 @@ class NavigationDelegateTest : BaseSessionTest() {
|
|||
}
|
||||
|
||||
@AssertCalled(count = 1)
|
||||
override fun onLocationChange(session: GeckoSession, url: String?) {
|
||||
override fun onLocationChange(session: GeckoSession, url: String?, perms : MutableList<GeckoSession.PermissionDelegate.ContentPermission>) {
|
||||
assertThat("URI should match", url, endsWith("#test1"))
|
||||
}
|
||||
})
|
||||
|
@ -1965,7 +1965,7 @@ class NavigationDelegateTest : BaseSessionTest() {
|
|||
}
|
||||
|
||||
@AssertCalled(count = 1)
|
||||
override fun onLocationChange(session: GeckoSession, url: String?) {
|
||||
override fun onLocationChange(session: GeckoSession, url: String?, perms : MutableList<GeckoSession.PermissionDelegate.ContentPermission>) {
|
||||
assertThat("URI should match", url, endsWith("#test2"))
|
||||
}
|
||||
})
|
||||
|
|
|
@ -32,7 +32,7 @@ class ProgressDelegateTest : BaseSessionTest() {
|
|||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate,
|
||||
Callbacks.NavigationDelegate {
|
||||
@AssertCalled
|
||||
override fun onLocationChange(session: GeckoSession, url: String?) {
|
||||
override fun onLocationChange(session: GeckoSession, url: String?, perms : MutableList<GeckoSession.PermissionDelegate.ContentPermission>) {
|
||||
assertThat("LocationChange is called", url, endsWith(path))
|
||||
}
|
||||
@AssertCalled
|
||||
|
@ -361,7 +361,7 @@ class ProgressDelegateTest : BaseSessionTest() {
|
|||
|
||||
session.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
|
||||
@AssertCalled
|
||||
override fun onLocationChange(session: GeckoSession, url: String?) {
|
||||
override fun onLocationChange(session: GeckoSession, url: String?, perms : MutableList<GeckoSession.PermissionDelegate.ContentPermission>) {
|
||||
assertThat("URI should match", url, equalTo(startUri))
|
||||
}
|
||||
})
|
||||
|
@ -379,7 +379,7 @@ class ProgressDelegateTest : BaseSessionTest() {
|
|||
session.goBack()
|
||||
|
||||
session.waitUntilCalled(object: Callbacks.NavigationDelegate {
|
||||
override fun onLocationChange(session: GeckoSession, url: String?) {
|
||||
override fun onLocationChange(session: GeckoSession, url: String?, perms : MutableList<GeckoSession.PermissionDelegate.ContentPermission>) {
|
||||
assertThat("History should be preserved", url, equalTo(helloUri))
|
||||
}
|
||||
})
|
||||
|
|
|
@ -34,6 +34,7 @@ import android.view.Surface;
|
|||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class TestRunnerActivity extends Activity {
|
||||
private static final String LOGTAG = "TestRunnerActivity";
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.security.cert.CertificateException;
|
|||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.AbstractSequentialList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
@ -466,8 +467,11 @@ public class GeckoSession {
|
|||
Log.d(LOGTAG, "handleMessage " + event + " uri=" + message.getString("uri"));
|
||||
if ("GeckoView:LocationChange".equals(event)) {
|
||||
if (message.getBoolean("isTopLevel")) {
|
||||
final GeckoBundle[] perms = message.getBundleArray("permissions");
|
||||
final List<PermissionDelegate.ContentPermission> permList =
|
||||
PermissionDelegate.ContentPermission.fromBundleArray(perms);
|
||||
delegate.onLocationChange(GeckoSession.this,
|
||||
message.getString("uri"));
|
||||
message.getString("uri"), permList);
|
||||
}
|
||||
delegate.onCanGoBack(GeckoSession.this,
|
||||
message.getBoolean("canGoBack"));
|
||||
|
@ -3645,8 +3649,20 @@ public class GeckoSession {
|
|||
* @param url The resource being loaded.
|
||||
*/
|
||||
@UiThread
|
||||
@DeprecationSchedule(id = "location-permissions", version = 92)
|
||||
default void onLocationChange(@NonNull final GeckoSession session, @Nullable final String url) {}
|
||||
|
||||
/**
|
||||
* A view has started loading content from the network.
|
||||
* @param session The GeckoSession that initiated the callback.
|
||||
* @param url The resource being loaded.
|
||||
* @param perms The permissions currently associated with this url.
|
||||
*/
|
||||
@UiThread
|
||||
default void onLocationChange(@NonNull GeckoSession session, @Nullable String url, final @NonNull List<PermissionDelegate.ContentPermission> perms) {
|
||||
session.getNavigationDelegate().onLocationChange(session, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* The view's ability to go back has changed.
|
||||
* @param session The GeckoSession that initiated the callback.
|
||||
|
@ -5365,6 +5381,110 @@ public class GeckoSession {
|
|||
*/
|
||||
int PERMISSION_MEDIA_KEY_SYSTEM_ACCESS = 6;
|
||||
|
||||
/**
|
||||
* Represents a content permission -- including the type of permission,
|
||||
* the present value of the permission, the URL the permission pertains to,
|
||||
* and other information.
|
||||
*/
|
||||
class ContentPermission {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({VALUE_PROMPT, VALUE_DENY, VALUE_ALLOW})
|
||||
/* package */ @interface Value {}
|
||||
|
||||
/**
|
||||
* The corresponding permission is currently set to default/prompt behavior.
|
||||
*/
|
||||
final public static int VALUE_PROMPT = 3;
|
||||
|
||||
/**
|
||||
* The corresponding permission is currently set to deny.
|
||||
*/
|
||||
final public static int VALUE_DENY = 2;
|
||||
|
||||
/**
|
||||
* The corresponding permission is currently set to allow.
|
||||
*/
|
||||
final public static int VALUE_ALLOW = 1;
|
||||
|
||||
/**
|
||||
* The URI associated with this content permission.
|
||||
*/
|
||||
final public @NonNull String uri;
|
||||
|
||||
/**
|
||||
* A boolean indicating whether this content permission is associated with
|
||||
* private browsing.
|
||||
*/
|
||||
final public boolean privateMode;
|
||||
|
||||
/**
|
||||
* The type of this permission; one of {@link #PERMISSION_GEOLOCATION PERMISSION_*}.
|
||||
*/
|
||||
final public int permission;
|
||||
|
||||
/**
|
||||
* The value of the permission; one of {@link #VALUE_PROMPT VALUE_}.
|
||||
*/
|
||||
final public @Value int value;
|
||||
|
||||
final private String mPrincipal;
|
||||
|
||||
protected ContentPermission() {
|
||||
this.uri = "";
|
||||
this.privateMode = false;
|
||||
this.permission = PERMISSION_GEOLOCATION;
|
||||
this.value = VALUE_ALLOW;
|
||||
this.mPrincipal = "";
|
||||
}
|
||||
|
||||
private ContentPermission(final @NonNull GeckoBundle bundle) {
|
||||
this.uri = bundle.getString("uri");
|
||||
this.mPrincipal = bundle.getString("principal");
|
||||
this.privateMode = bundle.getBoolean("privateMode");
|
||||
|
||||
final String permission = bundle.getString("type");
|
||||
this.permission = convertType(permission);
|
||||
|
||||
this.value = bundle.getInt("value");
|
||||
}
|
||||
|
||||
private static int convertType(final @NonNull String type) {
|
||||
if ("geolocation".equals(type)) {
|
||||
return PERMISSION_GEOLOCATION;
|
||||
} else if ("desktop-notification".equals(type)) {
|
||||
return PERMISSION_DESKTOP_NOTIFICATION;
|
||||
} else if ("persistent-storage".equals(type)) {
|
||||
return PERMISSION_PERSISTENT_STORAGE;
|
||||
} else if ("xr".equals(type)) {
|
||||
return PERMISSION_XR;
|
||||
} else if ("autoplay-media-inaudible".equals(type)) {
|
||||
return PERMISSION_AUTOPLAY_INAUDIBLE;
|
||||
} else if ("autoplay-media-audible".equals(type)) {
|
||||
return PERMISSION_AUTOPLAY_AUDIBLE;
|
||||
} else if ("media-key-system-access".equals(type)) {
|
||||
return PERMISSION_MEDIA_KEY_SYSTEM_ACCESS;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ static @NonNull ArrayList<ContentPermission> fromBundleArray(final @NonNull GeckoBundle[] bundleArray) {
|
||||
final ArrayList<ContentPermission> res = new ArrayList<ContentPermission>();
|
||||
if (bundleArray == null) {
|
||||
return res;
|
||||
}
|
||||
|
||||
for (final GeckoBundle bundle : bundleArray) {
|
||||
final ContentPermission temp = new ContentPermission(bundle);
|
||||
if (temp.permission == -1 || temp.value < 1 || temp.value > 3) {
|
||||
continue;
|
||||
}
|
||||
res.add(temp);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface for notifying the result of a permission request.
|
||||
*/
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.mozilla.geckoview;
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
|
@ -18,6 +19,7 @@ import androidx.annotation.Nullable;
|
|||
|
||||
import org.mozilla.gecko.EventDispatcher;
|
||||
import org.mozilla.gecko.util.GeckoBundle;
|
||||
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.ContentPermission;
|
||||
|
||||
/**
|
||||
* Manage runtime storage data.
|
||||
|
@ -181,4 +183,36 @@ public final class StorageController {
|
|||
return String.format("gvctx%x", new BigInteger(contextId.getBytes()))
|
||||
.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all currently stored permissions.
|
||||
*
|
||||
* @return A {@link GeckoResult} that will complete with a list of all
|
||||
* currently stored {@link ContentPermission}s.
|
||||
*/
|
||||
@AnyThread
|
||||
public @NonNull GeckoResult<List<ContentPermission>> getAllPermissions() {
|
||||
return EventDispatcher.getInstance().queryBundle("GeckoView:GetAllPermissions").map(bundle -> {
|
||||
final GeckoBundle[] permsArray = bundle.getBundleArray("permissions");
|
||||
return ContentPermission.fromBundleArray(permsArray);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all currently stored permissions for a given URI.
|
||||
*
|
||||
* @param uri A String representing the URI to get permissions for.
|
||||
*
|
||||
* @return A {@link GeckoResult} that will complete with a list of all
|
||||
* currently stored {@link ContentPermission}s for the URI.
|
||||
*/
|
||||
@AnyThread
|
||||
public @NonNull GeckoResult<List<ContentPermission>> getPermissions(final @NonNull String uri) {
|
||||
final GeckoBundle msg = new GeckoBundle(1);
|
||||
msg.putString("uri", uri);
|
||||
return EventDispatcher.getInstance().queryBundle("GeckoView:GetPermissionsByURI", msg).map(bundle -> {
|
||||
final GeckoBundle[] permsArray = bundle.getBundleArray("permissions");
|
||||
return ContentPermission.fromBundleArray(permsArray);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,20 @@ exclude: true
|
|||
|
||||
⚠️ breaking change and deprecation notices
|
||||
|
||||
## v89
|
||||
- Added [`ContentPermission`][89.1], which is used to report what permissions content
|
||||
is loaded with in `onLocationChange`.
|
||||
- Added [`StorageController.getPermissions`][89.2] and [`StorageController.getAllPermissions`][89.3],
|
||||
allowing inspection of what permissions have been set for a given URI and for all URIs.
|
||||
- ⚠️ Deprecated [`NavigationDelegate.onLocationChange`][89.4], to be removed in v92. The
|
||||
new `onLocationChange` callback simply adds permissions information, migration of existing
|
||||
functionality should only require updating the function signature.
|
||||
|
||||
[89.1]: {{javadoc_uri}}/GeckoSession.PermissionDelegate.ContentPermission.html
|
||||
[89.2]: {{javadoc_uri}}/StorageController.html#getPermissions-java.lang.String-
|
||||
[89.3]: {{javadoc_uri}}/StorageController.html#getAllPermissions--
|
||||
[89.4]: {{javadoc_uri}}/GeckoSession.NavigationDelegate.html#onLocationChange-org.mozilla.geckoview.GeckoSession-java.lang.String-
|
||||
|
||||
## v88
|
||||
- Added [`WebExtension.Download#update`][88.1] that can be used to
|
||||
implement the WebExtension `downloads` API. This method is used to communicate
|
||||
|
@ -934,4 +948,4 @@ to allow adding gecko profiler markers.
|
|||
[65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
|
||||
[65.25]: {{javadoc_uri}}/GeckoResult.html
|
||||
|
||||
[api-version]: f6ad9d26fbb3880d60970a1f25e406096c9efca0
|
||||
[api-version]: 638023f7c8ddb3ccf732df09b0bdee4416c04237
|
||||
|
|
|
@ -1872,7 +1872,7 @@ public class GeckoViewActivity
|
|||
|
||||
private class ExampleNavigationDelegate implements GeckoSession.NavigationDelegate {
|
||||
@Override
|
||||
public void onLocationChange(GeckoSession session, final String url) {
|
||||
public void onLocationChange(GeckoSession session, final String url, final List<GeckoSession.PermissionDelegate.ContentPermission> perms) {
|
||||
mToolbarView.getLocationView().setText(url);
|
||||
TabSession tabSession = mTabSessionManager.getSession(session);
|
||||
if (tabSession != null) {
|
||||
|
|
|
@ -558,12 +558,29 @@ class GeckoViewNavigation extends GeckoViewModule {
|
|||
return;
|
||||
}
|
||||
|
||||
let permissions;
|
||||
if (this.browser.contentPrincipal) {
|
||||
const rawPerms = Services.perms.getAllForPrincipal(
|
||||
this.browser.contentPrincipal
|
||||
);
|
||||
permissions = rawPerms.map(p => {
|
||||
return {
|
||||
uri: Services.io.createExposableURI(p.principal.URI).displaySpec,
|
||||
principal: E10SUtils.serializePrincipal(p.principal),
|
||||
type: p.type,
|
||||
value: p.capability,
|
||||
privateMode: p.principal.privateBrowsingId != 0,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const message = {
|
||||
type: "GeckoView:LocationChange",
|
||||
uri: fixedURI.displaySpec,
|
||||
canGoBack: this.browser.canGoBack,
|
||||
canGoForward: this.browser.canGoForward,
|
||||
isTopLevel: aWebProgress.isTopLevel,
|
||||
permissions,
|
||||
};
|
||||
|
||||
this.eventDispatcher.sendRequest(message);
|
||||
|
|
|
@ -13,6 +13,9 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|||
const { PrincipalsCollector } = ChromeUtils.import(
|
||||
"resource://gre/modules/PrincipalsCollector.jsm"
|
||||
);
|
||||
const { E10SUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/E10SUtils.jsm"
|
||||
);
|
||||
|
||||
const { debug, warn } = GeckoViewUtils.initLogging(
|
||||
"GeckoViewStorageController"
|
||||
|
@ -107,6 +110,39 @@ const GeckoViewStorageController = {
|
|||
this.clearHostData(aData.host, aData.flags, aCallback);
|
||||
break;
|
||||
}
|
||||
case "GeckoView:GetAllPermissions": {
|
||||
const rawPerms = Services.perms.all;
|
||||
const permissions = rawPerms.map(p => {
|
||||
return {
|
||||
uri: Services.io.createExposableURI(p.principal.URI).displaySpec,
|
||||
principal: E10SUtils.serializePrincipal(p.principal),
|
||||
type: p.type,
|
||||
value: p.capability,
|
||||
privateMode: p.principal.privateBrowsingId != 0,
|
||||
};
|
||||
});
|
||||
aCallback.onSuccess({ permissions });
|
||||
break;
|
||||
}
|
||||
case "GeckoView:GetPermissionsByURI": {
|
||||
const uri = Services.io.newURI(aData.uri);
|
||||
const prin = Services.scriptSecurityManager.createContentPrincipal(
|
||||
uri,
|
||||
{}
|
||||
);
|
||||
const rawPerms = Services.perms.getAllForPrincipal(prin);
|
||||
const permissions = rawPerms.map(p => {
|
||||
return {
|
||||
uri: Services.io.createExposableURI(p.principal.URI).displaySpec,
|
||||
principal: E10SUtils.serializePrincipal(p.principal),
|
||||
type: p.type,
|
||||
value: p.capability,
|
||||
privateMode: p.principal.privateBrowsingId != 0,
|
||||
};
|
||||
});
|
||||
aCallback.onSuccess({ permissions });
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче