@@ -3,6 +3,7 @@ package extensions
33import (
44 "bytes"
55 "context"
6+ "encoding/json"
67 "fmt"
78 "io"
89 "net/http"
@@ -286,6 +287,14 @@ func buildWebBotAuthExtension(ctx context.Context, browserExtDir, hostURL, keyDa
286287 extractedDir := filepath .Dir (filepath .Dir (browserExtDir ))
287288
288289 // Install dependencies
290+ // Clean up package-lock.json and node_modules first to avoid npm optional dependency bug
291+ // See: https://github.com/npm/cli/issues/4828
292+ pterm .Info .Println ("Cleaning up any existing npm artifacts..." )
293+ packageLockPath := filepath .Join (extractedDir , "package-lock.json" )
294+ nodeModulesPath := filepath .Join (extractedDir , "node_modules" )
295+ _ = os .Remove (packageLockPath )
296+ _ = os .RemoveAll (nodeModulesPath )
297+
289298 pterm .Info .Println ("Installing dependencies (this may take a minute)..." )
290299 npmInstall := exec .CommandContext (ctx , "npm" , "install" )
291300 npmInstall .Dir = extractedDir
@@ -305,6 +314,15 @@ func buildWebBotAuthExtension(ctx context.Context, browserExtDir, hostURL, keyDa
305314 return "" , fmt .Errorf ("npm run build (workspaces) failed: %w" , err )
306315 }
307316
317+ // Fix source manifest.json to remove invalid MV3 permissions BEFORE building
318+ // This must happen before npm run build:chrome so the .crx will have valid permissions
319+ // The source manifest is at platform/mv3/chromium/manifest.json
320+ sourceManifestDir := filepath .Join (browserExtDir , "platform" , "mv3" , "chromium" )
321+ pterm .Info .Println ("Fixing source manifest for MV3 compatibility..." )
322+ if err := fixManifestPermissions (sourceManifestDir ); err != nil {
323+ return "" , fmt .Errorf ("failed to fix source manifest: %w" , err )
324+ }
325+
308326 // Build the extension
309327 pterm .Info .Println ("Building extension..." )
310328 npmBuild := exec .CommandContext (ctx , "npm" , "run" , "build:chrome" )
@@ -393,6 +411,68 @@ func injectJWKIntoBackgroundTs(backgroundTsPath, jwkData string) error {
393411 return nil
394412}
395413
414+ // fixManifestPermissions removes invalid MV3 permissions from manifest.json
415+ // The upstream web-bot-auth extension has "webRequestBlocking" which is not valid in MV3
416+ func fixManifestPermissions (outputDir string ) error {
417+ manifestPath := filepath .Join (outputDir , "manifest.json" )
418+
419+ data , err := os .ReadFile (manifestPath )
420+ if err != nil {
421+ return fmt .Errorf ("failed to read manifest.json: %w" , err )
422+ }
423+
424+ var manifest map [string ]interface {}
425+ if err := json .Unmarshal (data , & manifest ); err != nil {
426+ return fmt .Errorf ("failed to parse manifest.json: %w" , err )
427+ }
428+
429+ // Check for and remove invalid MV3 permissions
430+ invalidPermissions := []string {"webRequestBlocking" }
431+ modified := false
432+
433+ if permissions , ok := manifest ["permissions" ].([]interface {}); ok {
434+ var validPermissions []interface {}
435+ for _ , perm := range permissions {
436+ permStr , ok := perm .(string )
437+ if ! ok {
438+ validPermissions = append (validPermissions , perm )
439+ continue
440+ }
441+
442+ isInvalid := false
443+ for _ , invalid := range invalidPermissions {
444+ if permStr == invalid {
445+ isInvalid = true
446+ pterm .Warning .Printf ("Removing invalid MV3 permission: %s\n " , permStr )
447+ modified = true
448+ break
449+ }
450+ }
451+ if ! isInvalid {
452+ validPermissions = append (validPermissions , perm )
453+ }
454+ }
455+ manifest ["permissions" ] = validPermissions
456+ }
457+
458+ if ! modified {
459+ return nil
460+ }
461+
462+ // Write back the fixed manifest with proper formatting
463+ fixedData , err := json .MarshalIndent (manifest , "" , " " )
464+ if err != nil {
465+ return fmt .Errorf ("failed to marshal fixed manifest: %w" , err )
466+ }
467+
468+ if err := os .WriteFile (manifestPath , fixedData , defaultFileMode ); err != nil {
469+ return fmt .Errorf ("failed to write fixed manifest: %w" , err )
470+ }
471+
472+ pterm .Success .Println ("Fixed manifest.json for MV3 compatibility" )
473+ return nil
474+ }
475+
396476// copyExtensionArtifacts copies built extension files to the output directory
397477func copyExtensionArtifacts (browserExtDir , outputDir string ) error {
398478 pterm .Info .Println ("Copying extension files to output directory..." )
@@ -418,6 +498,11 @@ func copyExtensionArtifacts(browserExtDir, outputDir string) error {
418498 }
419499 }
420500
501+ // Fix manifest.json to remove invalid MV3 permissions
502+ if err := fixManifestPermissions (outputDir ); err != nil {
503+ return fmt .Errorf ("failed to fix manifest permissions: %w" , err )
504+ }
505+
421506 updateXMLSrc := filepath .Join (browserExtDir , "dist" , "web-ext-artifacts" , "update.xml" )
422507 updateXMLDst := filepath .Join (outputDir , "update.xml" )
423508 if err := util .CopyFile (updateXMLSrc , updateXMLDst ); err != nil {
0 commit comments