I am developing a Chrome extension using the Blazor.BrowserExtension package. The goal is to manipulate Gmail’s DOM by injecting Razor components and invoking C# methods from custom.js (content script). Below are the relevant parts of my implementation:
manifest.json:
{
"manifest_version": 3,
"name": "Test Extension",
"description": "My browser extension built with Blazor WebAssembly",
"version": "0.1",
"background": {
"service_worker": "content/BackgroundWorker.js",
"type": "module"
},
"permissions": [
"activeTab",
"scripting",
"storage"
],
"host_permissions": [
"https://mail.google.com/*"
],
"action": {
"default_popup": "popup.html"
},
"options_ui": {
"page": "options.html",
"open_in_tab": true
},
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'",
"script-src": "'self' 'unsafe-inline' 'unsafe-eval'",
"object-src": "'self'"
},
"content_scripts": [
{
"matches": ["https://mail.google.com/mail/*"],
"js": ["framework/blazor.webassembly.js","content/custom.js"],
"run_at": "document_idle"
}
],
"web_accessible_resources": [
{
"resources": [
"framework/*",
"content/*",
"wwwroot/*"
],
"matches": [ "https://mail.google.com/*" ]
}
]
}
Program.cs:
using Blazor.BrowserExtension;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Test.Components;
namespace Test
{
public static class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.UseBrowserExtension(browserExtension =>
{
if (browserExtension.Mode == BrowserExtensionMode.ContentScript)
{
builder.RootComponents.RegisterForJavaScript<ButtonComponent>("CustomButton");
}
if (browserExtension.Mode == BrowserExtensionMode.Background)
{
builder.RootComponents.AddBackgroundWorker<BackgroundWorker>();
}
else
{
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
}
});
builder.Services.AddScoped<ITestService, TestService>();
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
}
}
}
ButtonComponent.razor:
@page "/button.html"
@inject IJSRuntime JSRuntime
<button @onclick="HandleClick" class="gmail-button">
@ButtonText
</button>
<style>
.gmail-button { /* styling here */ }
</style>
@code {
[Parameter]
public string ButtonText { get; set; } = "Click Me";
private async Task HandleClick()
{
await JSRuntime.InvokeVoidAsync("alert", "Blazor Button Clicked!");
}
}
custom.js:
(async () => {
const sendButtonContainer = document.querySelector(".dC");
if (!sendButtonContainer) {
console.error("Send button container not found.");
}
const blazorScript = document.createElement("script");
blazorScript.src = chrome.runtime.getURL("framework/blazor.webassembly.js");
blazorScript.type = "text/javascript";
blazorScript.onload = async () => {
console.log("Blazor WebAssembly script loaded.");
await Blazor.start();
const blazorContainer = document.createElement("div");
blazorContainer.id = "blazor-custom-container";
sendButtonContainer.appendChild(blazorContainer);
Blazor.rootComponents.add(blazorContainer, 'CustomButton', {
ButtonText: "Blazor Action"
});
console.log("Blazor component added.");
};
blazorScript.onerror = () => {
console.error("Failed to load Blazor WebAssembly script.");
};
document.head.appendChild(blazorScript);
})();
When I run this, I encounter the following errors:
- blazor.webassembly.js:1 Refused to load the script ‘https://mail.google.com/mail/u/0/framework/dotnet.js’ because it violates the Content Security Policy directive: “script-src ‘self’ ‘wasm-unsafe-eval’ …”
- Uncaught (in promise) Error: Failed to start platform. Reason: TypeError: Failed to fetch dynamically imported module: https://mail.google.com/mail/u/0/framework/dotnet.js
- Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of “text/html”.
- blazor.webassembly.js:1 Uncaught (in promise) Error: Failed to start platform.
My Question:
- Is it possible to use Blazor.BrowserExtension to inject Razor components into Gmail’s DOM?
- Are these errors related to limitations with Blazor.BrowserExtension in handling Gmail’s CSP or resource restrictions?
- Should I switch to a pure JavaScript implementation for DOM manipulation in this case?
Any guidance would be appreciated.