зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1699480 - Add setPermission, update onContentPermissionRequest to use ContentPermission, and let Gecko manage and persist permissions in GV. r=agi,geckoview-reviewers,owlish
Differential Revision: https://phabricator.services.mozilla.com/D112042
This commit is contained in:
Родитель
dbd1cacb9f
Коммит
648ddb2f54
|
@ -127,16 +127,6 @@ static const nsLiteralCString kPreloadPermissions[] = {
|
|||
// removed. See bug 1428130.
|
||||
"cookie"_ns};
|
||||
|
||||
// Certain permissions should never be persisted to disk under GeckoView; it's
|
||||
// the responsibility of the app to manage storing these beyond the scope of
|
||||
// a single session.
|
||||
#ifdef ANDROID
|
||||
static const nsLiteralCString kGeckoViewRestrictedPermissions[] = {
|
||||
"MediaManagerVideo"_ns, "geolocation"_ns,
|
||||
"desktop-notification"_ns, "persistent-storage"_ns,
|
||||
"trackingprotection"_ns, "trackingprotection-pb"_ns};
|
||||
#endif
|
||||
|
||||
// NOTE: nullptr can be passed as aType - if it is this function will return
|
||||
// "false" unconditionally.
|
||||
bool IsPreloadPermission(const nsACString& aType) {
|
||||
|
@ -554,11 +544,6 @@ bool IsExpandedPrincipal(nsIPrincipal* aPrincipal) {
|
|||
bool IsPersistentExpire(uint32_t aExpire, const nsACString& aType) {
|
||||
bool res = (aExpire != nsIPermissionManager::EXPIRE_SESSION &&
|
||||
aExpire != nsIPermissionManager::EXPIRE_POLICY);
|
||||
#ifdef ANDROID
|
||||
for (const auto& perm : kGeckoViewRestrictedPermissions) {
|
||||
res = res && !perm.Equals(aType);
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
E10SUtils: "resource://gre/modules/E10SUtils.jsm",
|
||||
GeckoViewUtils: "resource://gre/modules/GeckoViewUtils.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
});
|
||||
|
@ -245,31 +246,37 @@ class GeckoViewPermission {
|
|||
.sendRequestForResult({
|
||||
type: "GeckoView:ContentPermission",
|
||||
uri: aRequest.principal.URI.displaySpec,
|
||||
principal: E10SUtils.serializePrincipal(aRequest.principal),
|
||||
perm: perm.type,
|
||||
value: perm.capability,
|
||||
contextId:
|
||||
aRequest.principal.originAttributes.geckoViewSessionContextId ?? null,
|
||||
privateMode: aRequest.principal.privateBrowsingId != 0,
|
||||
})
|
||||
.then(granted => {
|
||||
if (!granted) {
|
||||
return false;
|
||||
.then(value => {
|
||||
if (value == Services.perms.ALLOW_ACTION) {
|
||||
// Ask for app permission after asking for content permission.
|
||||
if (perm.type === "geolocation") {
|
||||
return this.getAppPermissions(dispatcher, [
|
||||
PERM_ACCESS_FINE_LOCATION,
|
||||
]);
|
||||
}
|
||||
}
|
||||
// Ask for app permission after asking for content permission.
|
||||
if (perm.type === "geolocation") {
|
||||
return this.getAppPermissions(dispatcher, [
|
||||
PERM_ACCESS_FINE_LOCATION,
|
||||
]);
|
||||
}
|
||||
return true;
|
||||
return value;
|
||||
})
|
||||
.catch(error => {
|
||||
Cu.reportError("Permission error: " + error);
|
||||
return /* granted */ false;
|
||||
return /* value */ Services.perms.DENY_ACTION;
|
||||
})
|
||||
.then(granted => {
|
||||
(granted ? aRequest.allow : aRequest.cancel)();
|
||||
.then(value => {
|
||||
(value == Services.perms.ALLOW_ACTION
|
||||
? aRequest.allow
|
||||
: aRequest.cancel)();
|
||||
Services.perms.addFromPrincipal(
|
||||
aRequest.principal,
|
||||
perm.type,
|
||||
granted ? Services.perms.ALLOW_ACTION : Services.perms.DENY_ACTION,
|
||||
Services.perms.EXPIRE_SESSION
|
||||
value,
|
||||
Services.perms.EXPIRE_NEVER
|
||||
);
|
||||
// Manually release the target request here to facilitate garbage collection.
|
||||
aRequest = undefined;
|
||||
|
|
|
@ -103,6 +103,7 @@ class GeckoViewStartup {
|
|||
"GeckoView:ClearHostData",
|
||||
"GeckoView:GetAllPermissions",
|
||||
"GeckoView:GetPermissionsByURI",
|
||||
"GeckoView:SetPermission",
|
||||
],
|
||||
});
|
||||
|
||||
|
|
|
@ -25,9 +25,9 @@ class OpenWindowTest : BaseSessionTest() {
|
|||
|
||||
// Grant "desktop notification" permission
|
||||
mainSession.delegateUntilTestEnd(object : Callbacks.PermissionDelegate {
|
||||
override fun onContentPermissionRequest(session: GeckoSession, uri: String?, type: Int, callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
assertThat("Should grant DESKTOP_NOTIFICATIONS permission", type, equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
callback.grant()
|
||||
override fun onContentPermissionRequest(session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission): GeckoResult<Int>? {
|
||||
assertThat("Should grant DESKTOP_NOTIFICATIONS permission", perm.permission, equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
package org.mozilla.geckoview.test
|
||||
|
||||
import org.mozilla.geckoview.GeckoResult
|
||||
import org.mozilla.geckoview.GeckoSession
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.RejectedPromiseException
|
||||
|
@ -160,12 +161,12 @@ class PermissionDelegateTest : BaseSessionTest() {
|
|||
// Ensure the content permission is asked first, before the Android permission.
|
||||
@AssertCalled(count = 1, order = [1])
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, uri: String?, type: Int,
|
||||
callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
assertThat("URI should match", uri, endsWith(url))
|
||||
assertThat("Type should match", type,
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("URI should match", perm.uri, endsWith(url))
|
||||
assertThat("Type should match", perm.permission,
|
||||
equalTo(GeckoSession.PermissionDelegate.PERMISSION_GEOLOCATION))
|
||||
callback.grant()
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
}
|
||||
|
||||
@AssertCalled(count = 1, order = [2])
|
||||
|
@ -230,9 +231,9 @@ class PermissionDelegateTest : BaseSessionTest() {
|
|||
mainSession.delegateDuringNextWait(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, uri: String?, type: Int,
|
||||
callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
callback.reject()
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_DENY)
|
||||
}
|
||||
|
||||
@AssertCalled(count = 0)
|
||||
|
@ -289,12 +290,12 @@ class PermissionDelegateTest : BaseSessionTest() {
|
|||
mainSession.delegateDuringNextWait(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, uri: String?, type: Int,
|
||||
callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
assertThat("URI should match", uri, endsWith(url))
|
||||
assertThat("Type should match", type,
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("URI should match", perm.uri, endsWith(url))
|
||||
assertThat("Type should match", perm.permission,
|
||||
equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
callback.grant()
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -342,9 +343,9 @@ class PermissionDelegateTest : BaseSessionTest() {
|
|||
mainSession.delegateDuringNextWait(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, uri: String?, type: Int,
|
||||
callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
callback.reject()
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_DENY)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -393,10 +394,11 @@ class PermissionDelegateTest : BaseSessionTest() {
|
|||
|
||||
mainSession.waitUntilCalled(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 2)
|
||||
override fun onContentPermissionRequest(session: GeckoSession, uri: String?, type: Int, callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
override fun onContentPermissionRequest(session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
val expectedType = if (sessionRule.currentCall.counter == 1) GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY_AUDIBLE else GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE
|
||||
assertThat("Type should match", type, equalTo(expectedType))
|
||||
callback.reject()
|
||||
assertThat("Type should match", perm.permission, equalTo(expectedType))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_DENY)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -100,8 +100,8 @@ public class TestRunnerActivity extends Activity {
|
|||
|
||||
private GeckoSession.PermissionDelegate mPermissionDelegate = new GeckoSession.PermissionDelegate() {
|
||||
@Override
|
||||
public void onContentPermissionRequest(@NonNull final GeckoSession session, @Nullable final String uri, final int type, @NonNull final Callback callback) {
|
||||
callback.grant();
|
||||
public GeckoResult<Integer> onContentPermissionRequest(@NonNull final GeckoSession session, @NonNull GeckoSession.PermissionDelegate.ContentPermission perm) {
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,9 +25,10 @@ class WebNotificationTest : BaseSessionTest() {
|
|||
|
||||
// Grant "desktop notification" permission
|
||||
mainSession.delegateUntilTestEnd(object : Callbacks.PermissionDelegate {
|
||||
override fun onContentPermissionRequest(session: GeckoSession, uri: String?, type: Int, callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
assertThat("Should grant DESKTOP_NOTIFICATIONS permission", type, equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
callback.grant()
|
||||
override fun onContentPermissionRequest(session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("Should grant DESKTOP_NOTIFICATIONS permission", perm.permission, equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -60,9 +60,10 @@ class WebPushTest : BaseSessionTest() {
|
|||
sessionRule.setPrefsUntilTestEnd(mapOf("dom.webnotifications.requireuserinteraction" to false))
|
||||
// Grant "desktop notification" permission
|
||||
mainSession.delegateUntilTestEnd(object : Callbacks.PermissionDelegate {
|
||||
override fun onContentPermissionRequest(session: GeckoSession, uri: String?, type: Int, callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
assertThat("Should grant DESKTOP_NOTIFICATIONS permission", type, equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
callback.grant()
|
||||
override fun onContentPermissionRequest(session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("Should grant DESKTOP_NOTIFICATIONS permission", perm.permission, equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -716,33 +716,13 @@ public class GeckoSession {
|
|||
GeckoSession.this, message.getStringArray("perms"),
|
||||
new PermissionCallback("android", callback));
|
||||
} else if ("GeckoView:ContentPermission".equals(event)) {
|
||||
final String typeString = message.getString("perm");
|
||||
final int type;
|
||||
if ("geolocation".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_GEOLOCATION;
|
||||
} else if ("desktop-notification".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION;
|
||||
} else if ("persistent-storage".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_PERSISTENT_STORAGE;
|
||||
} else if ("xr".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_XR;
|
||||
} else if ("midi".equals(typeString)) {
|
||||
// We can get this from WPT and presumably other content, but Gecko
|
||||
// doesn't support Web MIDI.
|
||||
callback.sendError("Unsupported");
|
||||
final GeckoResult<Integer> res = delegate.onContentPermissionRequest(GeckoSession.this, new PermissionDelegate.ContentPermission(message));
|
||||
if (res == null) {
|
||||
callback.sendSuccess(PermissionDelegate.ContentPermission.VALUE_PROMPT);
|
||||
return;
|
||||
} else if ("autoplay-media-inaudible".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE;
|
||||
} else if ("autoplay-media-audible".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_AUTOPLAY_AUDIBLE;
|
||||
} else if ("media-key-system-access".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_MEDIA_KEY_SYSTEM_ACCESS;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown permission request: " + typeString);
|
||||
}
|
||||
delegate.onContentPermissionRequest(
|
||||
GeckoSession.this, message.getString("uri"),
|
||||
type, new PermissionCallback(typeString, callback));
|
||||
|
||||
callback.resolveTo(res);
|
||||
} else if ("GeckoView:MediaPermission".equals(event)) {
|
||||
final GeckoBundle[] videoBundles = message.getBundleArray("video");
|
||||
final GeckoBundle[] audioBundles = message.getBundleArray("audio");
|
||||
|
@ -5495,6 +5475,12 @@ public class GeckoSession {
|
|||
*/
|
||||
final public @Value int value;
|
||||
|
||||
/**
|
||||
* The context ID associated with the permission if any.
|
||||
* @see GeckoSessionSettings.Builder#contextId
|
||||
*/
|
||||
final public @Nullable String contextId;
|
||||
|
||||
final private String mPrincipal;
|
||||
|
||||
protected ContentPermission() {
|
||||
|
@ -5503,6 +5489,7 @@ public class GeckoSession {
|
|||
this.permission = PERMISSION_GEOLOCATION;
|
||||
this.value = VALUE_ALLOW;
|
||||
this.mPrincipal = "";
|
||||
this.contextId = null;
|
||||
}
|
||||
|
||||
private ContentPermission(final @NonNull GeckoBundle bundle) {
|
||||
|
@ -5510,10 +5497,11 @@ public class GeckoSession {
|
|||
this.mPrincipal = bundle.getString("principal");
|
||||
this.privateMode = bundle.getBoolean("privateMode");
|
||||
|
||||
final String permission = bundle.getString("type");
|
||||
final String permission = bundle.getString("perm");
|
||||
this.permission = convertType(permission);
|
||||
|
||||
this.value = bundle.getInt("value");
|
||||
this.contextId = StorageController.retrieveUnsafeSessionContextId(bundle.getString("contextId"));
|
||||
}
|
||||
|
||||
private static int convertType(final @NonNull String type) {
|
||||
|
@ -5536,6 +5524,27 @@ public class GeckoSession {
|
|||
}
|
||||
}
|
||||
|
||||
private static String convertType(final int type) {
|
||||
switch (type) {
|
||||
case PERMISSION_GEOLOCATION:
|
||||
return "geolocation";
|
||||
case PERMISSION_DESKTOP_NOTIFICATION:
|
||||
return "desktop-notification";
|
||||
case PERMISSION_PERSISTENT_STORAGE:
|
||||
return "persistent-storage";
|
||||
case PERMISSION_XR:
|
||||
return "xr";
|
||||
case PERMISSION_AUTOPLAY_INAUDIBLE:
|
||||
return "autoplay-media-inaudible";
|
||||
case PERMISSION_AUTOPLAY_AUDIBLE:
|
||||
return "autoplay-media-audible";
|
||||
case PERMISSION_MEDIA_KEY_SYSTEM_ACCESS:
|
||||
return "media-key-system-access";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ static @NonNull ArrayList<ContentPermission> fromBundleArray(final @NonNull GeckoBundle[] bundleArray) {
|
||||
final ArrayList<ContentPermission> res = new ArrayList<ContentPermission>();
|
||||
if (bundleArray == null) {
|
||||
|
@ -5551,6 +5560,17 @@ public class GeckoSession {
|
|||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* package */ @NonNull GeckoBundle toGeckoBundle() {
|
||||
final GeckoBundle res = new GeckoBundle(5);
|
||||
res.putString("uri", uri);
|
||||
res.putString("principal", mPrincipal);
|
||||
res.putBoolean("privateMode", privateMode);
|
||||
res.putString("perm", convertType(permission));
|
||||
res.putInt("value", value);
|
||||
res.putString("contextId", contextId);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5599,18 +5619,14 @@ public class GeckoSession {
|
|||
* from being redisplayed to the user.
|
||||
*
|
||||
* @param session GeckoSession instance requesting the permission.
|
||||
* @param uri The URI of the content requesting the permission.
|
||||
* @param type The type of the requested permission; possible values are,
|
||||
* PERMISSION_GEOLOCATION
|
||||
* PERMISSION_DESKTOP_NOTIFICATION
|
||||
* PERMISSION_PERSISTENT_STORAGE
|
||||
* PERMISSION_XR
|
||||
* @param callback Callback interface.
|
||||
* @param perm An {@link ContentPermission} describing the permission being requested and its current status.
|
||||
*
|
||||
* @return A {@link GeckoResult} resolving to one of {@link ContentPermission#VALUE_PROMPT VALUE_*}, determining
|
||||
* the response to the permission request and updating the permissions for this site.
|
||||
*/
|
||||
@UiThread
|
||||
default void onContentPermissionRequest(@NonNull final GeckoSession session, @Nullable final String uri,
|
||||
@Permission final int type, @NonNull final Callback callback) {
|
||||
callback.reject();
|
||||
default @Nullable GeckoResult<Integer> onContentPermissionRequest(@NonNull final GeckoSession session, @NonNull ContentPermission perm) {
|
||||
return GeckoResult.fromValue(ContentPermission.VALUE_PROMPT);
|
||||
}
|
||||
|
||||
class MediaSource {
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.mozilla.geckoview;
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -168,7 +169,7 @@ public final class StorageController {
|
|||
"GeckoView:ClearSessionContextData", bundle);
|
||||
}
|
||||
|
||||
/* package */ static @NonNull String createSafeSessionContextId(
|
||||
/* package */ static @Nullable String createSafeSessionContextId(
|
||||
final @Nullable String contextId) {
|
||||
if (contextId == null) {
|
||||
return null;
|
||||
|
@ -184,6 +185,18 @@ public final class StorageController {
|
|||
.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
/* package */ static @Nullable String retrieveUnsafeSessionContextId(
|
||||
final @Nullable String contextId) {
|
||||
if (contextId == null || contextId.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if ("gvctxempty".equals(contextId)) {
|
||||
return "";
|
||||
}
|
||||
final byte[] bytes = new BigInteger(contextId.substring(5), 16).toByteArray();
|
||||
return new String(bytes, Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all currently stored permissions.
|
||||
*
|
||||
|
@ -199,7 +212,7 @@ public final class StorageController {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get all currently stored permissions for a given URI.
|
||||
* Get all currently stored permissions for a given URI and default (unset) context ID.
|
||||
*
|
||||
* @param uri A String representing the URI to get permissions for.
|
||||
*
|
||||
|
@ -208,11 +221,39 @@ public final class StorageController {
|
|||
*/
|
||||
@AnyThread
|
||||
public @NonNull GeckoResult<List<ContentPermission>> getPermissions(final @NonNull String uri) {
|
||||
final GeckoBundle msg = new GeckoBundle(1);
|
||||
return getPermissions(uri, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all currently stored permissions for a given URI and context ID.
|
||||
*
|
||||
* @param uri A String representing the URI to get permissions for.
|
||||
* @param contextId A String specifying the context ID.
|
||||
*
|
||||
* @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 @Nullable String contextId) {
|
||||
final GeckoBundle msg = new GeckoBundle(2);
|
||||
msg.putString("uri", uri);
|
||||
msg.putString("contextId", createSafeSessionContextId(contextId));
|
||||
return EventDispatcher.getInstance().queryBundle("GeckoView:GetPermissionsByURI", msg).map(bundle -> {
|
||||
final GeckoBundle[] permsArray = bundle.getBundleArray("permissions");
|
||||
return ContentPermission.fromBundleArray(permsArray);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new value for an existing permission.
|
||||
*
|
||||
* @param perm A {@link ContentPermission} that you wish to update the value of.
|
||||
* @param value The new value for the permission.
|
||||
*/
|
||||
@AnyThread
|
||||
public void setPermission(final @NonNull ContentPermission perm, final @ContentPermission.Value int value) {
|
||||
final GeckoBundle msg = perm.toGeckoBundle();
|
||||
msg.putInt("newValue", value);
|
||||
EventDispatcher.getInstance().dispatch("GeckoView:SetPermission", msg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -869,30 +869,32 @@ final class BasicGeckoViewPrompt implements GeckoSession.PromptDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
public void onPermissionPrompt(final GeckoSession session, final String title,
|
||||
final GeckoSession.PermissionDelegate.Callback callback) {
|
||||
public GeckoResult<Integer> onPermissionPrompt(final GeckoSession session, final String title,
|
||||
final GeckoSession.PermissionDelegate.ContentPermission perm) {
|
||||
final Activity activity = mActivity;
|
||||
final GeckoResult<Integer> res = new GeckoResult<>();
|
||||
if (activity == null) {
|
||||
callback.reject();
|
||||
return;
|
||||
res.complete(GeckoSession.PermissionDelegate.ContentPermission.VALUE_PROMPT);
|
||||
return res;
|
||||
}
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setTitle(title)
|
||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final DialogInterface dialog, final int which) {
|
||||
callback.reject();
|
||||
res.complete(GeckoSession.PermissionDelegate.ContentPermission.VALUE_DENY);
|
||||
}
|
||||
})
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final DialogInterface dialog, final int which) {
|
||||
callback.grant();
|
||||
res.complete(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW);
|
||||
}
|
||||
});
|
||||
|
||||
final AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
return res;
|
||||
}
|
||||
|
||||
public void onSlowScriptPrompt(GeckoSession geckoSession, String title, GeckoResult<SlowScriptResponse> reportAction) {
|
||||
|
|
|
@ -1779,51 +1779,39 @@ public class GeckoViewActivity
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onContentPermissionRequest(final GeckoSession session, final String uri,
|
||||
final int type, final Callback callback) {
|
||||
public GeckoResult<Integer> onContentPermissionRequest(final GeckoSession session, final ContentPermission perm) {
|
||||
final int resId;
|
||||
Callback contentPermissionCallback = callback;
|
||||
if (PERMISSION_GEOLOCATION == type) {
|
||||
resId = R.string.request_geolocation;
|
||||
} else if (PERMISSION_DESKTOP_NOTIFICATION == type) {
|
||||
if (mShowNotificationsRejected) {
|
||||
Log.w(LOGTAG, "Desktop notifications already denied by user.");
|
||||
callback.reject();
|
||||
return;
|
||||
}
|
||||
resId = R.string.request_notification;
|
||||
contentPermissionCallback = new ExampleNotificationCallback(callback);
|
||||
} else if (PERMISSION_PERSISTENT_STORAGE == type) {
|
||||
if (mAcceptedPersistentStorage.contains(uri)) {
|
||||
Log.w(LOGTAG, "Persistent Storage for " + uri + " already granted by user.");
|
||||
callback.grant();
|
||||
return;
|
||||
}
|
||||
resId = R.string.request_storage;
|
||||
contentPermissionCallback = new ExamplePersistentStorageCallback(callback, uri);
|
||||
} else if (PERMISSION_XR == type) {
|
||||
resId = R.string.request_xr;
|
||||
} else if (PERMISSION_AUTOPLAY_AUDIBLE == type || PERMISSION_AUTOPLAY_INAUDIBLE == type) {
|
||||
if (!mAllowAutoplay.value()) {
|
||||
Log.d(LOGTAG, "Rejecting autoplay request");
|
||||
callback.reject();
|
||||
} else {
|
||||
Log.d(LOGTAG, "Granting autoplay request");
|
||||
callback.grant();
|
||||
}
|
||||
return;
|
||||
} else if (PERMISSION_MEDIA_KEY_SYSTEM_ACCESS == type) {
|
||||
resId = R.string.request_media_key_system_access;
|
||||
} else {
|
||||
Log.w(LOGTAG, "Unknown permission: " + type);
|
||||
callback.reject();
|
||||
return;
|
||||
switch (perm.permission) {
|
||||
case PERMISSION_GEOLOCATION:
|
||||
resId = R.string.request_geolocation;
|
||||
break;
|
||||
case PERMISSION_DESKTOP_NOTIFICATION:
|
||||
resId = R.string.request_notification;
|
||||
break;
|
||||
case PERMISSION_PERSISTENT_STORAGE:
|
||||
resId = R.string.request_storage;
|
||||
break;
|
||||
case PERMISSION_XR:
|
||||
resId = R.string.request_xr;
|
||||
break;
|
||||
case PERMISSION_AUTOPLAY_AUDIBLE:
|
||||
case PERMISSION_AUTOPLAY_INAUDIBLE:
|
||||
if (!mAllowAutoplay.value()) {
|
||||
return GeckoResult.fromValue(ContentPermission.VALUE_DENY);
|
||||
} else {
|
||||
return GeckoResult.fromValue(ContentPermission.VALUE_ALLOW);
|
||||
}
|
||||
case PERMISSION_MEDIA_KEY_SYSTEM_ACCESS:
|
||||
resId = R.string.request_media_key_system_access;
|
||||
break;
|
||||
default:
|
||||
return GeckoResult.fromValue(ContentPermission.VALUE_DENY);
|
||||
}
|
||||
|
||||
final String title = getString(resId, Uri.parse(uri).getAuthority());
|
||||
final String title = getString(resId, Uri.parse(perm.uri).getAuthority());
|
||||
final BasicGeckoViewPrompt prompt = (BasicGeckoViewPrompt)
|
||||
mTabSessionManager.getCurrentSession().getPromptDelegate();
|
||||
prompt.onPermissionPrompt(session, title, contentPermissionCallback);
|
||||
return prompt.onPermissionPrompt(session, title, perm);
|
||||
}
|
||||
|
||||
private String[] normalizeMediaName(final MediaSource[] sources) {
|
||||
|
|
|
@ -567,8 +567,9 @@ class GeckoViewNavigation extends GeckoViewModule {
|
|||
return {
|
||||
uri: Services.io.createExposableURI(p.principal.URI).displaySpec,
|
||||
principal: E10SUtils.serializePrincipal(p.principal),
|
||||
type: p.type,
|
||||
perm: p.type,
|
||||
value: p.capability,
|
||||
contextId: p.principal.originAttributes.geckoViewSessionContextId,
|
||||
privateMode: p.principal.privateBrowsingId != 0,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -115,8 +115,9 @@ const GeckoViewStorageController = {
|
|||
return {
|
||||
uri: Services.io.createExposableURI(p.principal.URI).displaySpec,
|
||||
principal: E10SUtils.serializePrincipal(p.principal),
|
||||
type: p.type,
|
||||
perm: p.type,
|
||||
value: p.capability,
|
||||
contextId: p.principal.originAttributes.geckoViewSessionContextId,
|
||||
privateMode: p.principal.privateBrowsingId != 0,
|
||||
};
|
||||
});
|
||||
|
@ -125,23 +126,34 @@ const GeckoViewStorageController = {
|
|||
}
|
||||
case "GeckoView:GetPermissionsByURI": {
|
||||
const uri = Services.io.newURI(aData.uri);
|
||||
const prin = Services.scriptSecurityManager.createContentPrincipal(
|
||||
const principal = Services.scriptSecurityManager.createContentPrincipal(
|
||||
uri,
|
||||
{}
|
||||
aData.contextId ? { geckoViewSessionContextId: aData.contextId } : {}
|
||||
);
|
||||
const rawPerms = Services.perms.getAllForPrincipal(prin);
|
||||
const rawPerms = Services.perms.getAllForPrincipal(principal);
|
||||
const permissions = rawPerms.map(p => {
|
||||
return {
|
||||
uri: Services.io.createExposableURI(p.principal.URI).displaySpec,
|
||||
principal: E10SUtils.serializePrincipal(p.principal),
|
||||
type: p.type,
|
||||
perm: p.type,
|
||||
value: p.capability,
|
||||
contextId: p.principal.originAttributes.geckoViewSessionContextId,
|
||||
privateMode: p.principal.privateBrowsingId != 0,
|
||||
};
|
||||
});
|
||||
aCallback.onSuccess({ permissions });
|
||||
break;
|
||||
}
|
||||
case "GeckoView:SetPermission": {
|
||||
const principal = E10SUtils.deserializePrincipal(aData.principal);
|
||||
Services.perms.addFromPrincipal(
|
||||
principal,
|
||||
aData.perm,
|
||||
aData.newValue,
|
||||
Ci.nsIPermissionManager.EXPIRE_NEVER
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче