Skip to content

Commit

Permalink
feat: implement permissions (#1645)
Browse files Browse the repository at this point in the history
Spec: https://www.w3.org/TR/permissions/#automation-webdriver-bidi
Tests: web-platform-tests/wpt#43802

---------

Co-authored-by: Maksim Sadym <69349599+sadym-chromium@users.noreply.github.com>
  • Loading branch information
OrKoN and sadym-chromium authored Jan 17, 2024
1 parent 3db89f0 commit 29c7b0b
Show file tree
Hide file tree
Showing 12 changed files with 317 additions and 1 deletion.
10 changes: 10 additions & 0 deletions src/bidiMapper/BidiNoOpParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type {
Script,
Session,
Storage,
Permissions,
} from '../protocol/protocol.js';

import type {BidiCommandParameterParser} from './BidiParser.js';
Expand Down Expand Up @@ -157,6 +158,15 @@ export class BidiNoOpParser implements BidiCommandParameterParser {
}
// keep-sorted end

// Permissions domain
// keep-sorted start block=yes
parseSetPermissionsParams(
params: unknown
): Permissions.SetPermissionParameters {
return params as Permissions.SetPermissionParameters;
}
// keep-sorted end

// Session domain
// keep-sorted start block=yes
parseSubscribeParams(params: unknown): Session.SubscriptionRequest {
Expand Down
8 changes: 8 additions & 0 deletions src/bidiMapper/BidiParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {
Cdp,
Input,
Network,
Permissions,
Script,
Session,
Storage,
Expand Down Expand Up @@ -62,6 +63,13 @@ export interface BidiCommandParameterParser {
parseSetFilesParams(params: unknown): Input.SetFilesParameters;
// keep-sorted end

// PermissionsDomain domain
// keep-sorted start block=yes
parseSetPermissionsParams(
params: unknown
): Permissions.SetPermissionParameters;
// keep-sorted end block=yes

// Network domain
// keep-sorted start block=yes
parseAddInterceptParams(params: unknown): Network.AddInterceptParameters;
Expand Down
11 changes: 11 additions & 0 deletions src/bidiMapper/CommandProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import type {BrowsingContextStorage} from './domains/context/BrowsingContextStor
import {InputProcessor} from './domains/input/InputProcessor.js';
import {NetworkProcessor} from './domains/network/NetworkProcessor.js';
import {NetworkStorage} from './domains/network/NetworkStorage.js';
import {PermissionsProcessor} from './domains/permissions/PermissionsProcessor.js';
import {PreloadScriptStorage} from './domains/script/PreloadScriptStorage.js';
import type {RealmStorage} from './domains/script/RealmStorage.js';
import {ScriptProcessor} from './domains/script/ScriptProcessor.js';
Expand All @@ -63,6 +64,7 @@ export class CommandProcessor extends EventEmitter<CommandProcessorEventsMap> {
#cdpProcessor: CdpProcessor;
#inputProcessor: InputProcessor;
#networkProcessor: NetworkProcessor;
#permissionsProcessor: PermissionsProcessor;
#scriptProcessor: ScriptProcessor;
#sessionProcessor: SessionProcessor;
#storageProcessor: StorageProcessor;
Expand Down Expand Up @@ -118,6 +120,7 @@ export class CommandProcessor extends EventEmitter<CommandProcessorEventsMap> {
browsingContextStorage,
networkStorage
);
this.#permissionsProcessor = new PermissionsProcessor(browserCdpClient);
this.#scriptProcessor = new ScriptProcessor(
browsingContextStorage,
realmStorage,
Expand Down Expand Up @@ -260,6 +263,14 @@ export class CommandProcessor extends EventEmitter<CommandProcessorEventsMap> {
);
// keep-sorted end

// Permissions domain
// keep-sorted start block=yes
case 'permissions.setPermission':
return await this.#permissionsProcessor.setPermissions(
this.#parser.parseSetPermissionsParams(command.params)
);
// keep-sorted end

// Script domain
// keep-sorted start block=yes
case 'script.addPreloadScript':
Expand Down
56 changes: 56 additions & 0 deletions src/bidiMapper/domains/permissions/PermissionsProcessor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* Copyright 2024 Google LLC.
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import type {CdpClient} from '../../../cdp/CdpClient.js';
import {
InvalidArgumentException,
type EmptyResult,
type Permissions,
} from '../../../protocol/protocol.js';

export class PermissionsProcessor {
#browserCdpClient: CdpClient;

constructor(browserCdpClient: CdpClient) {
this.#browserCdpClient = browserCdpClient;
}

async setPermissions(
params: Permissions.SetPermissionParameters
): Promise<EmptyResult> {
try {
await this.#browserCdpClient.sendCommand('Browser.setPermission', {
origin: params.origin,
permission: {
name: params.descriptor.name,
},
setting: params.state,
});
} catch (err) {
if (
(err as Error).message ===
`Permission can't be granted to opaque origins.`
) {
// Return success if the origin is not valid (does not match any
// existing origins).
return {};
}
throw new InvalidArgumentException((err as Error).message);
}
return {};
}
}
10 changes: 10 additions & 0 deletions src/bidiTab/BidiParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {
Cdp,
Input,
Network,
Permissions,
Script,
Session,
Storage,
Expand Down Expand Up @@ -132,6 +133,15 @@ export class BidiParser implements BidiCommandParameterParser {
}
// keep-sorted end

// Permissions domain
// keep-sorted start block=yes
parseSetPermissionsParams(
params: unknown
): Permissions.SetPermissionParameters {
return Parser.Permissions.parseSetPermissionsParams(params);
}
// keep-sorted end

// Script domain
// keep-sorted start block=yes
parseAddPreloadScriptParams(
Expand Down
58 changes: 58 additions & 0 deletions src/protocol-parser/generated/webdriver-bidi-permissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Copyright 2024 Google LLC.
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* THIS FILE IS AUTOGENERATED. Run `npm run bidi-types` to regenerate.
* @see https://github.com/w3c/webdriver-bidi/blob/master/index.bs
*/
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck Some types may be circular.

import z from 'zod';

export const PermissionsCommandSchema = z.lazy(
() => Permissions.SetPermissionSchema
);
export namespace Permissions {
export const PermissionDescriptorSchema = z.lazy(() =>
z.object({
name: z.string(),
})
);
}
export namespace Permissions {
export const PermissionStateSchema = z.lazy(() =>
z.enum(['granted', 'denied', 'prompt'])
);
}
export namespace Permissions {
export const SetPermissionSchema = z.lazy(() =>
z.object({
method: z.literal('permissions.setPermission'),
params: Permissions.SetPermissionParametersSchema,
})
);
}
export namespace Permissions {
export const SetPermissionParametersSchema = z.lazy(() =>
z.object({
descriptor: Permissions.PermissionDescriptorSchema,
state: Permissions.PermissionStateSchema,
origin: z.string(),
})
);
}
12 changes: 12 additions & 0 deletions src/protocol-parser/protocol-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {z, type ZodType} from 'zod';
import type * as Protocol from '../protocol/protocol.js';
import {InvalidArgumentException} from '../protocol/protocol.js';

import * as WebDriverBidiPermissions from './generated/webdriver-bidi-permissions.js';
import * as WebDriverBidi from './generated/webdriver-bidi.js';

export function parseObject<T extends ZodType>(
Expand Down Expand Up @@ -344,3 +345,14 @@ export namespace Cdp {
return parseObject(params, GetSessionRequestSchema);
}
}

export namespace Permissions {
export function parseSetPermissionsParams(
params: unknown
): Protocol.Permissions.SetPermissionParameters {
return parseObject(
params,
WebDriverBidiPermissions.Permissions.SetPermissionParametersSchema
) as Protocol.Permissions.SetPermissionParameters;
}
}
11 changes: 10 additions & 1 deletion src/protocol/chromium-bidi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/

import type * as Cdp from './cdp.js';
import type * as WebDriverBidiPermissions from './generated/webdriver-bidi-permissions.js';
import type * as WebDriverBidi from './generated/webdriver-bidi.js';

export type EventNames =
Expand Down Expand Up @@ -87,7 +88,15 @@ export namespace Network {
}
}

export type Command = (WebDriverBidi.Command | Cdp.Command) & {
export type Command = (
| WebDriverBidi.Command
| Cdp.Command
| ({
// id is defined by the main WebDriver BiDi spec and extension specs do
// not re-define it. Therefore, it's not part of generated types.
id: WebDriverBidi.JsUint;
} & WebDriverBidiPermissions.PermissionsCommand)
) & {
channel?: WebDriverBidi.Script.Channel;
};

Expand Down
47 changes: 47 additions & 0 deletions src/protocol/generated/webdriver-bidi-permissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright 2024 Google LLC.
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* THIS FILE IS AUTOGENERATED. Run `npm run bidi-types` to regenerate.
* @see https://github.com/w3c/webdriver-bidi/blob/master/index.bs
*/
export type PermissionsCommand = Permissions.SetPermission;
export namespace Permissions {
export type PermissionDescriptor = {
name: string;
};
}
export namespace Permissions {
export const enum PermissionState {
Granted = 'granted',
Denied = 'denied',
Prompt = 'prompt',
}
}
export namespace Permissions {
export type SetPermission = {
method: 'permissions.setPermission';
params: Permissions.SetPermissionParameters;
};
}
export namespace Permissions {
export type SetPermissionParameters = {
descriptor: Permissions.PermissionDescriptor;
state: Permissions.PermissionState;
origin: string;
};
}
1 change: 1 addition & 0 deletions src/protocol/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export * as Cdp from './cdp.js';
export * as ChromiumBidi from './chromium-bidi.js';
export * from './generated/webdriver-bidi.js';
export * from './ErrorResponse.js';
export * from './generated/webdriver-bidi-permissions.js';
58 changes: 58 additions & 0 deletions tests/permissions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2024 Google LLC.
# Copyright (c) Microsoft Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from urllib.parse import urlparse

from test_helpers import execute_command


def get_origin(url):
""" Return the origin for the given url."""
parts = urlparse(url)
return parts.scheme + '://' + parts.netloc


async def query_permission(websocket, context_id, name):
""" Queries a permission via the script.callFunction command."""

result = await execute_command(
websocket, {
"method": "script.callFunction",
"params": {
"functionDeclaration": """() => {
return navigator.permissions.query({ name: '%s' })
.then(val => val.state, err => err.message)
}""" % name,
"target": {
"context": context_id
},
"awaitPromise": True,
}
})

return result['result']['value']


async def set_permission(websocket, origin, descriptor, state):
""" Set a permission via the permissions.setPermission command."""
return await execute_command(
websocket, {
'method': 'permissions.setPermission',
'params': {
'origin': origin,
'descriptor': descriptor,
'state': state
}
})
Loading

0 comments on commit 29c7b0b

Please sign in to comment.