feat: implement permissions for WebDriver BiDi (#11979)

This commit is contained in:
Alex Rudenko 2024-02-23 10:16:58 +01:00 committed by GitHub
parent bba2811ae5
commit 3a467c39cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 94 additions and 34 deletions

View File

@ -94,6 +94,11 @@ This is an exciting step towards a more unified and efficient cross-browser auto
- Page.pdf (only `format`, `height`, `landscape`, `margin`, `pageRanges`, `printBackground`, `scale`, `width` are supported) - Page.pdf (only `format`, `height`, `landscape`, `margin`, `pageRanges`, `printBackground`, `scale`, `width` are supported)
- Page.createPDFStream (only `format`, `height`, `landscape`, `margin`, `pageRanges`, `printBackground`, `scale`, `width` are supported) - Page.createPDFStream (only `format`, `height`, `landscape`, `margin`, `pageRanges`, `printBackground`, `scale`, `width` are supported)
- Permissions (Supported in Chrome only)
- BrowserContext.clearPermissionOverrides()
- BrowserContext.overridePermissions()
## Puppeteer features not yet supported over WebDriver BiDi ## Puppeteer features not yet supported over WebDriver BiDi
- [Request interception](https://pptr.dev/guides/request-interception) - [Request interception](https://pptr.dev/guides/request-interception)
@ -111,11 +116,6 @@ This is an exciting step towards a more unified and efficient cross-browser auto
- HTTPRequest.responseForRequest() - HTTPRequest.responseForRequest()
- Page.setRequestInterception() - Page.setRequestInterception()
- Permissions
- BrowserContext.clearPermissionOverrides()
- BrowserContext.overridePermissions()
- Various emulations (most are supported with Chrome) - Various emulations (most are supported with Chrome)
- Page.emulate() (supported only in Chrome) - Page.emulate() (supported only in Chrome)

View File

@ -6,11 +6,12 @@
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
import type {Permission} from '../api/Browser.js';
import {WEB_PERMISSION_TO_PROTOCOL_PERMISSION} from '../api/Browser.js';
import type {BrowserContextEvents} from '../api/BrowserContext.js'; import type {BrowserContextEvents} from '../api/BrowserContext.js';
import {BrowserContext, BrowserContextEvent} from '../api/BrowserContext.js'; import {BrowserContext, BrowserContextEvent} from '../api/BrowserContext.js';
import {PageEvent, type Page} from '../api/Page.js'; import {PageEvent, type Page} from '../api/Page.js';
import type {Target} from '../api/Target.js'; import type {Target} from '../api/Target.js';
import {UnsupportedOperation} from '../common/Errors.js';
import {EventEmitter} from '../common/EventEmitter.js'; import {EventEmitter} from '../common/EventEmitter.js';
import {debugError} from '../common/util.js'; import {debugError} from '../common/util.js';
import type {Viewport} from '../common/Viewport.js'; import type {Viewport} from '../common/Viewport.js';
@ -62,6 +63,8 @@ export class BidiBrowserContext extends BrowserContext {
] ]
>(); >();
#overrides: Array<{origin: string; permission: Permission}> = [];
private constructor( private constructor(
browser: BidiBrowser, browser: BidiBrowser,
userContext: UserContext, userContext: UserContext,
@ -202,12 +205,58 @@ export class BidiBrowserContext extends BrowserContext {
return this.userContext.id !== UserContext.DEFAULT; return this.userContext.id !== UserContext.DEFAULT;
} }
override overridePermissions(): never { override async overridePermissions(
throw new UnsupportedOperation(); origin: string,
permissions: Permission[]
): Promise<void> {
const permissionsSet = new Set(
permissions.map(permission => {
const protocolPermission =
WEB_PERMISSION_TO_PROTOCOL_PERMISSION.get(permission);
if (!protocolPermission) {
throw new Error('Unknown permission: ' + permission);
}
return permission;
})
);
await Promise.all(
Array.from(WEB_PERMISSION_TO_PROTOCOL_PERMISSION.keys()).map(
permission => {
const result = this.userContext.setPermissions(
origin,
{
name: permission,
},
permissionsSet.has(permission)
? Bidi.Permissions.PermissionState.Granted
: Bidi.Permissions.PermissionState.Denied
);
this.#overrides.push({origin, permission});
// TODO: some permissions are outdated and setting them to denied does
// not work.
if (!permissionsSet.has(permission)) {
return result.catch(debugError);
}
return result;
}
)
);
} }
override clearPermissionOverrides(): never { override async clearPermissionOverrides(): Promise<void> {
throw new UnsupportedOperation(); const promises = this.#overrides.map(({permission, origin}) => {
return this.userContext
.setPermissions(
origin,
{
name: permission,
},
Bidi.Permissions.PermissionState.Prompt
)
.catch(debugError);
});
this.#overrides = [];
await Promise.all(promises);
} }
override get id(): string | undefined { override get id(): string | undefined {

View File

@ -107,6 +107,11 @@ export interface Commands {
returnType: Bidi.EmptyResult; returnType: Bidi.EmptyResult;
}; };
'permissions.setPermission': {
params: Bidi.Permissions.SetPermissionParameters;
returnType: Bidi.EmptyResult;
};
'session.end': { 'session.end': {
params: Bidi.EmptyParams; params: Bidi.EmptyParams;
returnType: Bidi.EmptyResult; returnType: Bidi.EmptyResult;

View File

@ -214,6 +214,24 @@ export class UserContext extends EventEmitter<{
}); });
} }
@throwIfDisposed<UserContext>(context => {
// SAFETY: Disposal implies this exists.
return context.#reason!;
})
async setPermissions(
origin: string,
descriptor: Bidi.Permissions.PermissionDescriptor,
state: Bidi.Permissions.PermissionState
): Promise<void> {
await this.#session.send('permissions.setPermission', {
origin,
descriptor,
state,
// @ts-expect-error not standard implementation.
'goog:userContext': this.#id,
});
}
[disposeSymbol](): void { [disposeSymbol](): void {
this.#reason ??= this.#reason ??=
'User context already closed, probably because the browser disconnected/closed.'; 'User context already closed, probably because the browser disconnected/closed.';

View File

@ -17,12 +17,6 @@
"parameters": ["webDriverBiDi"], "parameters": ["webDriverBiDi"],
"expectations": ["SKIP"] "expectations": ["SKIP"]
}, },
{
"testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions *",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
},
{ {
"testIdPattern": "[device-request-prompt.spec] *", "testIdPattern": "[device-request-prompt.spec] *",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
@ -233,12 +227,6 @@
"parameters": ["firefox", "webDriverBiDi"], "parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"] "expectations": ["FAIL"]
}, },
{
"testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions *",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["chrome", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{ {
"testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should be prompt by default", "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should be prompt by default",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
@ -704,12 +692,6 @@
"parameters": ["webDriverBiDi"], "parameters": ["webDriverBiDi"],
"expectations": ["FAIL"] "expectations": ["FAIL"]
}, },
{
"testIdPattern": "[page.spec] Page Page.setGeolocation should work",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
},
{ {
"testIdPattern": "[page.spec] Page Page.setOfflineMode should emulate navigator.onLine", "testIdPattern": "[page.spec] Page Page.setOfflineMode should emulate navigator.onLine",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
@ -922,6 +904,12 @@
"parameters": ["cdp", "firefox"], "parameters": ["cdp", "firefox"],
"expectations": ["FAIL"] "expectations": ["FAIL"]
}, },
{
"testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should fail when bad permission is given",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["PASS"]
},
{ {
"testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should grant permission when listed", "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should grant permission when listed",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
@ -1572,12 +1560,6 @@
"parameters": ["cdp", "firefox"], "parameters": ["cdp", "firefox"],
"expectations": ["SKIP"] "expectations": ["SKIP"]
}, },
{
"testIdPattern": "[idle_override.spec] Emulate idle state changing idle state emulation causes change of the IdleDetector state",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["chrome", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{ {
"testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails Network redirects should report SecurityDetails", "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails Network redirects should report SecurityDetails",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
@ -2937,6 +2919,12 @@
"parameters": ["cdp", "firefox"], "parameters": ["cdp", "firefox"],
"expectations": ["FAIL"] "expectations": ["FAIL"]
}, },
{
"testIdPattern": "[page.spec] Page Page.setGeolocation should work",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{ {
"testIdPattern": "[page.spec] Page Page.setGeolocation should work", "testIdPattern": "[page.spec] Page Page.setGeolocation should work",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],