Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,13 @@
"expectations": ["SKIP"],
"comment": "We can't connect to a browser started with pipe:true"
},
{
"testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.setPermission should support * as origin",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"],
"comment": "Origin (*) is not supported for setPermission in BiDi"
},
{
"testIdPattern": "[browsercontext.spec] BrowserContext should fire target events",
"platforms": ["darwin", "linux", "win32"],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System.Threading.Tasks;
using NUnit.Framework;
using PuppeteerSharp.Nunit;

namespace PuppeteerSharp.Tests.BrowserContextTests
{
public class BrowserContextSetPermissionTests : PuppeteerPageBaseTest
{
public BrowserContextSetPermissionTests() : base()
{
}

private Task<string> GetPermissionAsync(IPage page, string name)
=> page.EvaluateFunctionAsync<string>(
"name => navigator.permissions.query({ name }).then(result => result.state)",
name);

[Test, PuppeteerTest("browsercontext.spec", "BrowserContext BrowserContext.setPermission", "should set permission")]
public async Task ShouldSetPermission()
{
await Page.GoToAsync(TestConstants.EmptyPage);

await Context.SetPermissionAsync(TestConstants.EmptyPage, new PermissionEntry
{
Permission = new PermissionDescriptor { Name = "geolocation" },
State = PermissionState.Granted,
});
Assert.That(await GetPermissionAsync(Page, "geolocation"), Is.EqualTo("granted"));

await Context.SetPermissionAsync(TestConstants.EmptyPage, new PermissionEntry
{
Permission = new PermissionDescriptor { Name = "geolocation" },
State = PermissionState.Denied,
});
Assert.That(await GetPermissionAsync(Page, "geolocation"), Is.EqualTo("denied"));

await Context.SetPermissionAsync(TestConstants.EmptyPage, new PermissionEntry
{
Permission = new PermissionDescriptor { Name = "geolocation" },
State = PermissionState.Prompt,
});
Assert.That(await GetPermissionAsync(Page, "geolocation"), Is.EqualTo("prompt"));
}

[Test, PuppeteerTest("browsercontext.spec", "BrowserContext BrowserContext.setPermission", "should support * as origin")]
public async Task ShouldSupportStarAsOrigin()
{
await Page.GoToAsync(TestConstants.EmptyPage);

await Context.SetPermissionAsync("*", new PermissionEntry
{
Permission = new PermissionDescriptor { Name = "geolocation" },
State = PermissionState.Granted,
});
Assert.That(await GetPermissionAsync(Page, "geolocation"), Is.EqualTo("granted"));

await Context.SetPermissionAsync("*", new PermissionEntry
{
Permission = new PermissionDescriptor { Name = "geolocation" },
State = PermissionState.Denied,
});
Assert.That(await GetPermissionAsync(Page, "geolocation"), Is.EqualTo("denied"));

await Context.SetPermissionAsync("*", new PermissionEntry
{
Permission = new PermissionDescriptor { Name = "geolocation" },
State = PermissionState.Prompt,
});
Assert.That(await GetPermissionAsync(Page, "geolocation"), Is.EqualTo("prompt"));
}

[Test, PuppeteerTest("browsercontext.spec", "BrowserContext BrowserContext.setPermission", "should support multiple permissions")]
public async Task ShouldSupportMultiplePermissions()
{
await Page.GoToAsync(TestConstants.EmptyPage);

await Context.SetPermissionAsync(
TestConstants.EmptyPage,
new PermissionEntry { Permission = new PermissionDescriptor { Name = "geolocation" }, State = PermissionState.Granted },
new PermissionEntry { Permission = new PermissionDescriptor { Name = "midi" }, State = PermissionState.Granted });
Assert.That(await GetPermissionAsync(Page, "geolocation"), Is.EqualTo("granted"));
Assert.That(await GetPermissionAsync(Page, "midi"), Is.EqualTo("granted"));

await Context.SetPermissionAsync(
TestConstants.EmptyPage,
new PermissionEntry { Permission = new PermissionDescriptor { Name = "geolocation" }, State = PermissionState.Denied },
new PermissionEntry { Permission = new PermissionDescriptor { Name = "midi" }, State = PermissionState.Denied });
Assert.That(await GetPermissionAsync(Page, "geolocation"), Is.EqualTo("denied"));
Assert.That(await GetPermissionAsync(Page, "midi"), Is.EqualTo("denied"));

await Context.SetPermissionAsync(
TestConstants.EmptyPage,
new PermissionEntry { Permission = new PermissionDescriptor { Name = "geolocation" }, State = PermissionState.Prompt },
new PermissionEntry { Permission = new PermissionDescriptor { Name = "midi" }, State = PermissionState.Prompt });
Assert.That(await GetPermissionAsync(Page, "geolocation"), Is.EqualTo("prompt"));
Assert.That(await GetPermissionAsync(Page, "midi"), Is.EqualTo("prompt"));
}
}
}
46 changes: 42 additions & 4 deletions lib/PuppeteerSharp/Bidi/BidiBrowserContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
using Microsoft.Extensions.Logging;
using PuppeteerSharp.Bidi.Core;
using PuppeteerSharp.Helpers;
using WebDriverBiDi.Permissions;
using BidiPermissionState = WebDriverBiDi.Permissions.PermissionState;

namespace PuppeteerSharp.Bidi;

Expand Down Expand Up @@ -66,8 +66,8 @@ public override async Task OverridePermissionsAsync(string origin, IEnumerable<O
foreach (OverridePermission permission in Enum.GetValues(typeof(OverridePermission)))
{
var state = permissionsSet.Contains(permission)
? PermissionState.Granted
: PermissionState.Denied;
? BidiPermissionState.Granted
: BidiPermissionState.Denied;

var permissionName = GetPermissionName(permission);

Expand Down Expand Up @@ -96,14 +96,51 @@ public override async Task OverridePermissionsAsync(string origin, IEnumerable<O
await Task.WhenAll(tasks).ConfigureAwait(false);
}

/// <inheritdoc />
public override async Task SetPermissionAsync(string origin, params PermissionEntry[] permissions)
{
if (origin == "*")
{
throw new PuppeteerException("Origin (*) is not supported by WebDriver BiDi");
}

await Task.WhenAll(permissions.Select(entry =>
{
if (entry.Permission.AllowWithoutSanitization == true)
{
throw new PuppeteerException("allowWithoutSanitization is not supported by WebDriver BiDi");
}

if (entry.Permission.PanTiltZoom == true)
{
throw new PuppeteerException("panTiltZoom is not supported by WebDriver BiDi");
}

if (entry.Permission.UserVisibleOnly == true)
{
throw new PuppeteerException("userVisibleOnly is not supported by WebDriver BiDi");
}

var state = entry.State switch
{
PermissionState.Granted => BidiPermissionState.Granted,
PermissionState.Denied => BidiPermissionState.Denied,
PermissionState.Prompt => BidiPermissionState.Prompt,
_ => throw new ArgumentOutOfRangeException(nameof(entry), entry.State, "Unknown permission state"),
};

return UserContext.SetPermissionsAsync(origin, entry.Permission.Name, state);
})).ConfigureAwait(false);
}

/// <inheritdoc />
public override async Task ClearPermissionOverridesAsync()
{
var tasks = new List<Task>();
foreach (var (origin, permission) in _overrides.ToArray())
{
var permissionName = GetPermissionName(permission);
tasks.Add(UserContext.SetPermissionsAsync(origin, permissionName, PermissionState.Prompt)
tasks.Add(UserContext.SetPermissionsAsync(origin, permissionName, BidiPermissionState.Prompt)
.ContinueWith(
t =>
{
Expand Down Expand Up @@ -231,6 +268,7 @@ private static string GetPermissionName(OverridePermission permission)
OverridePermission.IdleDetection => "idle-detection",
OverridePermission.PersistentStorage => "persistent-storage",
OverridePermission.LocalNetworkAccess => "local-network-access",
OverridePermission.LocalFonts => "local-fonts",
_ => throw new ArgumentOutOfRangeException(nameof(permission), permission, "Unknown permission"),
};
}
Expand Down
5 changes: 3 additions & 2 deletions lib/PuppeteerSharp/Bidi/Core/UserContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
using System.Threading.Tasks;
using WebDriverBiDi.Browser;
using WebDriverBiDi.BrowsingContext;
using WebDriverBiDi.Permissions;
using BidiPermissionState = WebDriverBiDi.Permissions.PermissionState;
using SetPermissionCommandParameters = WebDriverBiDi.Permissions.SetPermissionCommandParameters;

namespace PuppeteerSharp.Bidi.Core;

Expand Down Expand Up @@ -132,7 +133,7 @@ public async Task RemoveAsync()
public async Task SetPermissionsAsync(
string origin,
string permissionName,
PermissionState state)
BidiPermissionState state)
{
await Session.Driver.Permissions.SetPermissionAsync(
new SetPermissionCommandParameters(permissionName, state, origin)
Expand Down
4 changes: 4 additions & 0 deletions lib/PuppeteerSharp/Browser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ public void UnregisterCustomQueryHandler(string name)
public void ClearCustomQueryHandlers()
=> CustomQuerySelectorRegistry.Default.ClearCustomQueryHandlers();

/// <inheritdoc/>
public Task SetPermissionAsync(string origin, params PermissionEntry[] permissions)
=> DefaultContext.SetPermissionAsync(origin, permissions);

/// <inheritdoc/>
public Task<ICDPSession> CreateCDPSessionAsync() => Target.CreateCDPSessionAsync();

Expand Down
3 changes: 3 additions & 0 deletions lib/PuppeteerSharp/BrowserContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ public Task<ITarget> WaitForTargetAsync(Func<ITarget, bool> predicate, WaitForOp
/// <inheritdoc/>
public abstract Task OverridePermissionsAsync(string origin, IEnumerable<OverridePermission> permissions);

/// <inheritdoc/>
public abstract Task SetPermissionAsync(string origin, params PermissionEntry[] permissions);

/// <inheritdoc/>
public abstract Task ClearPermissionOverridesAsync();

Expand Down
24 changes: 24 additions & 0 deletions lib/PuppeteerSharp/Cdp/CdpBrowserContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,30 @@ public override Task OverridePermissionsAsync(string origin, IEnumerable<Overrid
Permissions = permissions.ToArray(),
});

/// <inheritdoc/>
public override async Task SetPermissionAsync(string origin, params PermissionEntry[] permissions)
{
await Task.WhenAll(permissions.Select(entry =>
{
var protocolPermission = new BrowserPermissionDescriptor
{
Name = entry.Permission.Name,
UserVisibleOnly = entry.Permission.UserVisibleOnly,
Sysex = entry.Permission.Sysex,
AllowWithoutSanitization = entry.Permission.AllowWithoutSanitization,
PanTiltZoom = entry.Permission.PanTiltZoom,
};

return _connection.SendAsync("Browser.setPermission", new BrowserSetPermissionRequest
{
Origin = origin == "*" ? null : origin,
BrowserContextId = Id,
Permission = protocolPermission,
Setting = entry.State,
});
})).ConfigureAwait(false);
}

/// <inheritdoc/>
public override Task ClearPermissionOverridesAsync()
=> _connection.SendAsync("Browser.resetPermissions", new BrowserResetPermissionsRequest
Expand Down
15 changes: 15 additions & 0 deletions lib/PuppeteerSharp/Cdp/Messaging/BrowserPermissionDescriptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace PuppeteerSharp.Cdp.Messaging
{
internal class BrowserPermissionDescriptor
{
public string Name { get; set; }

public bool? UserVisibleOnly { get; set; }

public bool? Sysex { get; set; }

public bool? PanTiltZoom { get; set; }

public bool? AllowWithoutSanitization { get; set; }
}
}
13 changes: 13 additions & 0 deletions lib/PuppeteerSharp/Cdp/Messaging/BrowserSetPermissionRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace PuppeteerSharp.Cdp.Messaging
{
internal class BrowserSetPermissionRequest
{
public string Origin { get; set; }

public string BrowserContextId { get; set; }

public BrowserPermissionDescriptor Permission { get; set; }

public PermissionState Setting { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ namespace PuppeteerSharp.Helpers.Json;
[JsonSerializable(typeof(BrowserGetWindowBoundsResponse))]
[JsonSerializable(typeof(BrowserGetWindowForTargetResponse))]
[JsonSerializable(typeof(BrowserGrantPermissionsRequest))]
[JsonSerializable(typeof(BrowserPermissionDescriptor))]
[JsonSerializable(typeof(BrowserResetPermissionsRequest))]
[JsonSerializable(typeof(BrowserSetPermissionRequest))]
[JsonSerializable(typeof(BrowserSetContentsSizeRequest))]
[JsonSerializable(typeof(BrowserSetWindowBoundsRequest))]
[JsonSerializable(typeof(BoundingBox[]))]
Expand Down
8 changes: 8 additions & 0 deletions lib/PuppeteerSharp/IBrowser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,14 @@ public interface IBrowser : IDisposable, IAsyncDisposable
/// <remarks>Only supported in headless mode. Fails if the primary screen ID is specified.</remarks>
Task RemoveScreenAsync(string screenId);

/// <summary>
/// Sets the permission for a specific origin on the default browser context.
/// </summary>
/// <param name="origin">The origin to set the permission for, e.g. "https://example.com". Use "*" for all origins (CDP only).</param>
/// <param name="permissions">The permissions to set.</param>
/// <returns>The task.</returns>
Task SetPermissionAsync(string origin, params PermissionEntry[] permissions);

/// <summary>
/// Creates a Chrome Devtools Protocol session attached to the browser.
/// </summary>
Expand Down
8 changes: 8 additions & 0 deletions lib/PuppeteerSharp/IBrowserContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ public interface IBrowserContext : IDisposable, IAsyncDisposable
/// <seealso href="https://developer.mozilla.org/en-US/docs/Glossary/Origin"/>
Task OverridePermissionsAsync(string origin, IEnumerable<OverridePermission> permissions);

/// <summary>
/// Sets the permission for a specific origin.
/// </summary>
/// <param name="origin">The origin to set the permission for, e.g. "https://example.com". Use "*" for all origins (CDP only).</param>
/// <param name="permissions">The permissions to set.</param>
/// <returns>The task.</returns>
Task SetPermissionAsync(string origin, params PermissionEntry[] permissions);

/// <summary>
/// An array of all pages inside the browser context.
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions lib/PuppeteerSharp/OverridePermission.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,11 @@ public enum OverridePermission
/// </summary>
[EnumMember(Value = "local-network-access")]
LocalNetworkAccess,

/// <summary>
/// Local Fonts.
/// </summary>
[EnumMember(Value = "local-fonts")]
LocalFonts,
}
}
33 changes: 33 additions & 0 deletions lib/PuppeteerSharp/PermissionDescriptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace PuppeteerSharp
{
/// <summary>
/// Describes a permission to set via <see cref="IBrowserContext.SetPermissionAsync"/>.
/// </summary>
public class PermissionDescriptor
{
/// <summary>
/// Gets or sets the permission name (e.g. "geolocation", "midi", "notifications").
/// </summary>
public string Name { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the permission should only apply to user-visible operations.
/// </summary>
public bool? UserVisibleOnly { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to enable system exclusive access (MIDI).
/// </summary>
public bool? Sysex { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to enable pan-tilt-zoom controls (camera).
/// </summary>
public bool? PanTiltZoom { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to allow writing without sanitization (clipboard).
/// </summary>
public bool? AllowWithoutSanitization { get; set; }
}
}
Loading
Loading