Skip to content

Commit bdd0ff1

Browse files
committed
update to build packed web bot auth extension
1 parent e271fbc commit bdd0ff1

1 file changed

Lines changed: 82 additions & 26 deletions

File tree

cmd/extensions.go

Lines changed: 82 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -437,46 +437,93 @@ func (e ExtensionsCmd) BuildWebBotAuth(ctx context.Context, in ExtensionsBuildWe
437437
return fmt.Errorf("npm run build failed: %w", err)
438438
}
439439

440-
// Run npm run build:chrome in the browser-extension directory
440+
// Run npm run bundle:chrome in the browser-extension directory (builds and packs as CRX)
441441
extDir := filepath.Join(repoDir, "examples", "browser-extension")
442-
pterm.Info.Println("Building extension (npm run build:chrome)...")
443-
npmBuild := exec.CommandContext(ctx, "npm", "run", "build:chrome")
444-
npmBuild.Dir = extDir
445-
npmBuild.Stdout = os.Stdout
446-
npmBuild.Stderr = os.Stderr
447-
if err := npmBuild.Run(); err != nil {
448-
return fmt.Errorf("npm run build:chrome failed: %w", err)
442+
pterm.Info.Println("Building and bundling extension (npm run bundle:chrome)...")
443+
npmBundle := exec.CommandContext(ctx, "npm", "run", "bundle:chrome")
444+
npmBundle.Dir = extDir
445+
npmBundle.Stdout = os.Stdout
446+
npmBundle.Stderr = os.Stderr
447+
if err := npmBundle.Run(); err != nil {
448+
return fmt.Errorf("npm run bundle:chrome failed: %w", err)
449449
}
450450

451-
// Copy built extension to output directory
451+
// Create unpacked subdirectory for the extension files (used for upload)
452+
unpackedDir := filepath.Join(outDir, "unpacked")
453+
if err := os.MkdirAll(unpackedDir, 0o755); err != nil {
454+
return fmt.Errorf("failed to create unpacked directory: %w", err)
455+
}
456+
457+
// Copy built extension files to unpacked/
452458
builtDir := filepath.Join(extDir, "dist", "mv3", "chromium")
453-
manifestSrc := filepath.Join(extDir, "platform", "mv3", "chromium", "manifest.json")
454459

455460
// Copy background.mjs
456461
bgSrc := filepath.Join(builtDir, "background.mjs")
457-
if err := copyFile(bgSrc, filepath.Join(outDir, "background.mjs")); err != nil {
462+
if err := copyFile(bgSrc, filepath.Join(unpackedDir, "background.mjs")); err != nil {
458463
return fmt.Errorf("failed to copy background.mjs: %w", err)
459464
}
460465

461-
// Read manifest and add version (the build script doesn't add it, only bundle does)
462-
manifestData, err := os.ReadFile(manifestSrc)
463-
if err != nil {
464-
return fmt.Errorf("failed to read manifest.json: %w", err)
466+
// Copy manifest.json (bundle:chrome already adds version)
467+
manifestSrc := filepath.Join(builtDir, "manifest.json")
468+
if err := copyFile(manifestSrc, filepath.Join(unpackedDir, "manifest.json")); err != nil {
469+
return fmt.Errorf("failed to copy manifest.json: %w", err)
470+
}
471+
472+
// Copy CRX bundle artifacts
473+
artifactsDir := filepath.Join(extDir, "dist", "web-ext-artifacts")
474+
crxSrc := filepath.Join(artifactsDir, "http-message-signatures-extension.crx")
475+
if err := copyFile(crxSrc, filepath.Join(outDir, "extension.crx")); err != nil {
476+
return fmt.Errorf("failed to copy extension.crx: %w", err)
465477
}
466-
var manifest map[string]interface{}
467-
if err := json.Unmarshal(manifestData, &manifest); err != nil {
468-
return fmt.Errorf("failed to parse manifest.json: %w", err)
478+
479+
updateXMLSrc := filepath.Join(artifactsDir, "update.xml")
480+
if err := copyFile(updateXMLSrc, filepath.Join(outDir, "update.xml")); err != nil {
481+
return fmt.Errorf("failed to copy update.xml: %w", err)
469482
}
470-
manifest["version"] = "1.0.0"
471-
manifestOut, err := json.MarshalIndent(manifest, "", " ")
472-
if err != nil {
473-
return fmt.Errorf("failed to marshal manifest.json: %w", err)
483+
484+
// Copy policy files
485+
policyDir := filepath.Join(extDir, "policy")
486+
policyJSONSrc := filepath.Join(policyDir, "policy.json")
487+
if err := copyFile(policyJSONSrc, filepath.Join(outDir, "policy.json")); err != nil {
488+
return fmt.Errorf("failed to copy policy.json: %w", err)
474489
}
475-
if err := os.WriteFile(filepath.Join(outDir, "manifest.json"), manifestOut, 0o644); err != nil {
476-
return fmt.Errorf("failed to write manifest.json: %w", err)
490+
491+
plistSrc := filepath.Join(policyDir, "com.google.Chrome.managed.plist")
492+
if err := copyFile(plistSrc, filepath.Join(outDir, "com.google.Chrome.managed.plist")); err != nil {
493+
return fmt.Errorf("failed to copy plist: %w", err)
494+
}
495+
496+
// Copy RSA private key (useful for re-signing later)
497+
privateKeySrc := filepath.Join(extDir, "private_key.pem")
498+
if err := copyFile(privateKeySrc, filepath.Join(outDir, "private_key.pem")); err != nil {
499+
return fmt.Errorf("failed to copy private_key.pem: %w", err)
500+
}
501+
502+
// Extract extension ID from update.xml and save it
503+
updateXMLData, err := os.ReadFile(updateXMLSrc)
504+
if err == nil {
505+
// Parse extension ID from update.xml (it's in the appid attribute)
506+
xmlStr := string(updateXMLData)
507+
if idx := strings.Index(xmlStr, `appid="`); idx != -1 {
508+
start := idx + 7
509+
if end := strings.Index(xmlStr[start:], `"`); end != -1 {
510+
extID := xmlStr[start : start+end]
511+
if err := os.WriteFile(filepath.Join(outDir, "extension-id.txt"), []byte(extID), 0o644); err != nil {
512+
pterm.Warning.Printf("Failed to write extension-id.txt: %v\n", err)
513+
}
514+
}
515+
}
477516
}
478517

479-
pterm.Success.Printf("Built extension to: %s\n", outDir)
518+
pterm.Success.Printf("Built extension bundle to: %s\n", outDir)
519+
pterm.Info.Println("Bundle contents:")
520+
pterm.Info.Println(" - extension.crx (packed extension for policy installation)")
521+
pterm.Info.Println(" - update.xml (Chrome update manifest)")
522+
pterm.Info.Println(" - policy.json (Linux/Chrome OS policy file)")
523+
pterm.Info.Println(" - com.google.Chrome.managed.plist (macOS policy file)")
524+
pterm.Info.Println(" - private_key.pem (RSA key for re-signing)")
525+
pterm.Info.Println(" - extension-id.txt (Chrome extension ID)")
526+
pterm.Info.Println(" - unpacked/ (unpacked extension files)")
480527

481528
// Optionally upload
482529
if in.Upload {
@@ -485,7 +532,7 @@ func (e ExtensionsCmd) BuildWebBotAuth(ctx context.Context, in ExtensionsBuildWe
485532
name = "web-bot-auth"
486533
}
487534
pterm.Info.Printf("Uploading extension as '%s'...\n", name)
488-
if err := e.Upload(ctx, ExtensionsUploadInput{Dir: outDir, Name: name}); err != nil {
535+
if err := e.Upload(ctx, ExtensionsUploadInput{Dir: unpackedDir, Name: name}); err != nil {
489536
return err
490537
}
491538
}
@@ -641,6 +688,15 @@ var extensionsBuildWebBotAuthCmd = &cobra.Command{
641688
This command downloads and builds Cloudflare's web-bot-auth browser extension,
642689
which adds RFC 9421 HTTP Message Signatures to all outgoing requests.
643690
691+
The output includes:
692+
- extension.crx (packed extension for policy installation)
693+
- update.xml (Chrome update manifest)
694+
- policy.json (Linux/Chrome OS policy file)
695+
- com.google.Chrome.managed.plist (macOS policy file)
696+
- private_key.pem (RSA key for re-signing)
697+
- extension-id.txt (Chrome extension ID)
698+
- unpacked/ (unpacked extension files for Kernel upload)
699+
644700
By default, it uses the RFC9421 test key that works with Cloudflare's test site
645701
at https://http-message-signatures-example.research.cloudflare.com/
646702

0 commit comments

Comments
 (0)