- Created patch-upgrading-guide.md with step-by-step instructions for updating patches across Firefox versions - Covers understanding patch system, preparation, general workflow, and common reject types - Includes historical context patch merging section (no longer applicable after Firefox 146) - Documents testing, validation, best practices, and complete example session - Provides troubleshooting section for common issues and API changes - Details
16 KiB
Firefox Patch Upgrading Guide for LLMs
This guide provides step-by-step instructions for updating Camoufox patches when upgrading Firefox versions. Patches frequently break due to Firefox API changes, file reorganizations, and line number shifts.
All patches are located in the patches/ directory. There are no separate context patches to merge—per-context functionality is already built into the patches.
Table of Contents
- Understanding the Patch System
- Preparation
- General Workflow
- Fixing Common Reject Types
- Context Patch Merging (Historical - skip for future updates)
- Testing and Validation
- Best Practices
Understanding the Patch System
Patch Categories
All Camoufox patches are in the patches/ directory:
- Core Patches:
0-playwright.patch,1-leak-fixes.patch, etc. - Feature Patches:
webrtc-ip-spoofing.patch,anti-font-fingerprinting.patch, etc. - All patches now include per-user-context (per-Playwright-context) support built-in
Historical Note: Context patches (e.g., font-fingerprinting.context.patch, webrtc.context.patch) were previously separate but have been merged into their base patches as of Firefox 146. You will not find .context.patch files in the repository.
Key Infrastructure Files
- RoverfoxStorageManager.cpp/h: Thread-safe key-value storage for per-context data
- Manager Classes: FontSpacingSeedManager, WebRTCIPManager, etc.
- Window.webidl: Exposes JavaScript APIs to Playwright
Preparation
1. Reset to Clean State
IMPORTANT: Always use make clean to reset to fresh Firefox source:
make clean
DO NOT use git reset or git clean commands directly in the Firefox source directory - these can delete untracked files needed for the build.
2. Identify Patches to Update
Check which patches exist:
ls patches/*.patch
3. Understand Patch Dependencies
Some patches depend on others being applied first:
1-leak-fixes.patchrequires0-playwright.patch- Check the Makefile or patch comments for dependency chains
General Workflow
Step 1: Apply Base Patch and Identify Rejects
cd camoufox-<version>
patch -p1 < ../patches/patch-name.patch
Find reject files:
find . -name '*.rej' -type f
Step 2: Analyze Each Reject File
Read the reject file to understand what failed:
cat path/to/file.cpp.rej
Reject files show:
@@lines: Line numbers where patch expected to apply-lines: What the patch expected to find (old code)+lines: What the patch wanted to add (new code)
Step 3: Locate the Correct Position in Firefox Code
The line numbers in rejects are usually wrong for the new Firefox version. You need to:
- Search for unique context around the reject
- Understand what the patch is doing
- Find equivalent location in new Firefox code
Step 4: Apply Changes Manually
Use the Edit tool to apply the rejected changes to the correct location.
Step 5: Remove Reject Files
After fixing all rejects:
rm -f path/to/file.cpp.rej
find . -name '*.rej' -type f # Verify all removed
Step 6: Generate Updated Patch
# Add any new files first
git add new/file.cpp new/file.h
# Generate patch with both staged and unstaged changes
git diff --cached --binary > /tmp/patch-name.patch
git diff --binary >> /tmp/patch-name.patch
# Copy to patches directory
cp /tmp/patch-name.patch ../patches/patch-name.patch
Step 7: Verify Patch Applies Cleanly
cd ..
make clean
cd camoufox-<version>
patch -p1 < ../patches/patch-name.patch
find . -name '*.rej' -type f # Should return nothing
Fixing Common Reject Types
Type 1: Include Directive Rejects
Symptom: Reject shows failed #include additions
Example Reject:
@@ -325,6 +325,7 @@
#include "xpcpublic.h"
+#include "WebRTCIPManager.h"
#include "nsDocShell.h"
How to Fix:
- Read the actual file to find the includes section
- Search for nearby includes (e.g.,
xpcpublic.h) - Add the new include in the appropriate location
- Firefox include order: system headers, then Mozilla headers, alphabetically within groups
Example:
// Find this in the actual file:
#include "xpcpublic.h"
// Add the missing includes after it:
#include "xpcpublic.h"
#include "WebRTCIPManager.h"
#include "nsDocShell.h"
#include "mozilla/OriginAttributes.h"
Type 2: Function Signature Changes
Symptom: Reject shows function call with changed parameters
Example Reject:
- mouseOrPointerEvent.mButton = aButton;
+ mouseOrPointerEvent.mJugglerEventId = aMouseEventData.mJugglerEventId;
Common Causes:
- Firefox refactored the API
- Parameters moved from individual args to struct/data object
- Parameter order changed
How to Fix:
- Search for the function definition in Firefox source
- Understand the new API structure
- Port the patch logic to the new API
Example - Firefox 146 Mouse Event Refactoring:
Old Firefox 144 API (individual parameters):
void SynthesizeMouseEvent(int x, int y, int button, ...)
New Firefox 146 API (structured data):
void SynthesizeMouseEvent(SynthesizeMouseEventData& aData,
SynthesizeMouseEventOptions& aOptions)
Port the patch:
// Old patch code:
mouseEvent.mButton = aButton;
mouseEvent.jugglerEventId = aJugglerEventId;
// New patch code for Firefox 146:
mouseOrPointerEvent.mButton = aMouseEventData.mButton;
mouseOrPointerEvent.mJugglerEventId = aMouseEventData.mJugglerEventId;
mouseOrPointerEvent.convertToPointer = aOptions.mConvertToPointer;
Type 3: Missing Context - Code Moved
Symptom: Reject shows context that doesn't exist in the file
How to Fix:
- Use grep to search for unique function names or variables in the reject
- Find where Firefox moved the code
- Apply the patch to the new location
# Search across the codebase
grep -r "FunctionName" camoufox-<version>/ --include="*.cpp"
Type 4: New Parameter Added to Function Calls
Symptom: Reject shows function call, but Firefox added/removed parameters
Example - MakeTextRun userContextId:
Old call:
MakeTextRun(text, len, drawTarget, appUnitsPerDevPixel, flags, recorder);
New Firefox expects:
MakeTextRun(text, len, drawTarget, appUnitsPerDevPixel, flags, recorder, userContextId);
How to Fix:
- Extract userContextId from available context (Document, PresContext, etc.)
- Add proper extraction code before the call
- Pass userContextId as the last parameter
Standard userContextId Extraction Pattern:
uint32_t userContextId = 0;
if (mozilla::dom::Document* doc = presContext->Document()) {
if (nsIPrincipal* principal = doc->NodePrincipal()) {
auto* bp = mozilla::BasePrincipal::Cast(principal);
if (bp) {
userContextId = bp->OriginAttributesRef().mUserContextId;
}
}
}
// Now pass userContextId to the function
MakeTextRun(..., userContextId);
Type 5: Line Number Shifts (No Code Changes)
Symptom: Reject shows patch tried to apply at wrong line number, but code is identical
How to Fix:
Simply apply the patch manually at the correct line number. The code hasn't changed, just the location.
Context Patch Merging (Historical - Not Applicable for Future Updates)
NOTE: As of Firefox 146, all context patches have been merged into their base patches. This section is kept for historical reference and understanding how the patches evolved. Future Firefox updates will only need to update patches in the patches/ directory.
Historical Context: Context patches previously added per-user-context functionality to base patches. The workflow was different from simple patch updates.
Historical Goal
Merge all changes from *.context.patch into the corresponding base patch so there's only one comprehensive patch file.
Historical Example: font-fingerprinting.context.patch → anti-font-fingerprinting.patch
Workflow
-
Reset to clean Firefox:
make clean -
Apply base patch first:
cd camoufox-<version> patch -p1 < ../patches/anti-font-fingerprinting.patch -
Apply context patch on top:
patch -p1 < ../font-fingerprinting.context.patch -
Fix any rejects (usually include conflicts since base patch may have some overlapping changes)
-
Generate combined patch:
# Add new files (e.g., FontSpacingSeedManager.cpp/h) git add dom/base/FontSpacingSeedManager.cpp git add dom/base/FontSpacingSeedManager.h git add dom/base/RoverfoxStorageManager.cpp git add dom/base/RoverfoxStorageManager.h # Generate combined patch git diff --cached --binary > /tmp/anti-font-fingerprinting.patch git diff --binary >> /tmp/anti-font-fingerprinting.patch # Replace base patch cp /tmp/anti-font-fingerprinting.patch ../patches/anti-font-fingerprinting.patch -
Verify combined patch:
cd .. make clean cd camoufox-<version> patch -p1 < ../patches/anti-font-fingerprinting.patch find . -name '*.rej' -type f # Should be empty
What Context Patches Add
Context patches typically add:
-
Manager classes (e.g., FontSpacingSeedManager, WebRTCIPManager):
- Store per-context settings using RoverfoxStorageManager
- Provide WebIDL-compatible enable/disable checks
- Handle self-destructing functions
-
Window.webidl functions:
- JavaScript APIs exposed to Playwright
- Examples:
setFontSpacingSeed(),setWebRTCIPv4()
-
nsGlobalWindowInner.cpp implementations:
- Extract userContextId from window/document/docshell
- Call manager classes
- Self-destruct logic (remove function after first use)
-
Core logic changes:
- Replace global config (MaskConfig) with per-context manager
- Pass userContextId through call chains
- Query manager for per-context values
Testing and Validation
Minimal Verification
After updating a patch, always verify:
-
Patch applies cleanly:
make clean cd camoufox-<version> patch -p1 < ../patches/patch-name.patch find . -name '*.rej' -type f -
No reject files remain
-
Build compiles (if feasible):
cd .. make build
Full Testing
For critical patches, test with actual Playwright scenarios after building.
Best Practices
DO:
- ✅ Always use
make cleanto reset Firefox source - ✅ Read and understand what the patch is trying to do before fixing rejects
- ✅ Search for API changes in Firefox release notes when functions have changed
- ✅ Use grep/search extensively to find where code moved
- ✅ Extract userContextId properly using the standard pattern
- ✅ Test patches apply cleanly before considering them done
- ✅ Keep commits atomic - one patch fix per session
- ✅ Document major API changes you discover
DON'T:
- ❌ Don't use
git resetorgit cleanon Firefox source directory - ❌ Don't leave TODO comments - fix things properly as you go
- ❌ Don't guess parameter values - extract them properly or investigate
- ❌ Don't skip verification - always test the patch applies cleanly
- ❌ Don't batch multiple patch updates - do them one at a time
- ❌ Don't assume line numbers are correct in reject files
- ❌ Don't ignore warnings during patch application
Common Pitfalls
- Assuming reject line numbers are accurate: They're usually wrong in new Firefox versions
- Not understanding API changes: Firefox refactors often - read the new code
- Forgetting to add new files: Use
git addbefore generating patch - Not testing on clean source: Always verify with
make clean - Leaving reject files: Remove all
.rejfiles after fixing
Example: Complete Patch Update Session
Here's a complete example of updating 0-playwright.patch from Firefox 144 to Firefox 146:
1. Reset and Apply
make clean
cd camoufox-146.0.1-beta.25
patch -p1 < ../patches/0-playwright.patch
2. Find Rejects
find . -name '*.rej' -type f
Output shows 20 reject files.
3. Analyze First Reject
cat dom/base/Navigator.cpp.rej
Shows parameter order changed in GetAcceptLanguages.
4. Fix the Reject
Search for the function in the actual file, understand the new signature, apply changes manually.
5. Repeat for All Rejects
Work through each reject systematically.
6. Discover API Change
Firefox 146 refactored mouse events from individual parameters to SynthesizeMouseEventData and SynthesizeMouseEventOptions. Port all mouse event logic to new API.
7. Remove Rejects
rm -f dom/base/Navigator.cpp.rej dom/base/Element.cpp.rej ...
find . -name '*.rej' -type f # Verify empty
8. Generate New Patch
git diff --binary > /tmp/0-playwright.patch
cp /tmp/0-playwright.patch ../patches/0-playwright.patch
9. Verify
cd ..
make clean
cd camoufox-146.0.1-beta.25
patch -p1 < ../patches/0-playwright.patch
find . -name '*.rej' -type f # Should be empty
Appendix: Firefox Source Navigation
Finding Files
# Find files by name
find . -name "Navigator.cpp" -type f
# Find files containing a symbol
grep -r "GetAcceptLanguages" . --include="*.cpp"
# Find class definitions
grep -r "class Navigator" . --include="*.h"
Understanding Firefox Code Structure
dom/: DOM implementationdom/base/: Core DOM classes (Window, Document, Navigator, etc.)dom/webidl/: WebIDL interface definitionsdom/media/webrtc/: WebRTC implementation
gfx/: Graphics and font renderinggfx/thebes/: Text rendering (fonts, glyphs, shaping)
layout/: Layout enginelayout/generic/: Text frameslayout/mathml/: MathML rendering
Common Firefox Patterns
User Context ID Extraction:
uint32_t userContextId = 0;
if (Document* doc = GetDocument()) {
if (nsIPrincipal* principal = doc->NodePrincipal()) {
auto* bp = mozilla::BasePrincipal::Cast(principal);
if (bp) {
userContextId = bp->OriginAttributesRef().mUserContextId;
}
}
}
Three-tier userContextId fallback (for WebIDL functions):
// 1) Document's principal (preferred)
if (Document* doc = win->GetDoc()) {
if (nsIPrincipal* p = doc->NodePrincipal()) {
userContextId = p->OriginAttributesRef().mUserContextId;
}
}
// 2) DocShell origin attributes
if (userContextId == 0) {
if (nsIDocShell* ds = win->GetDocShell()) {
auto* concrete = static_cast<nsDocShell*>(ds);
userContextId = concrete->GetOriginAttributes().mUserContextId;
}
}
// 3) Top browsing context
if (userContextId == 0) {
if (BrowsingContext* bc = win->GetBrowsingContext()) {
RefPtr<BrowsingContext> top = bc->Top();
// ... extract from top window
}
}
Summary Checklist
When updating patches for a new Firefox version:
- Use
make cleanto reset to fresh Firefox source - Apply patch and identify all reject files
- Analyze each reject to understand what changed
- Search Firefox source for moved/refactored code
- Fix rejects by porting logic to new Firefox APIs
- Extract userContextId properly using standard patterns
- Don't leave TODO comments - fix everything immediately
- Remove all
.rejfiles after fixing - Add any new files with
git add - Generate new patch with
git diff --cached --binary+git diff --binary - Verify patch applies cleanly to fresh source
- Document any major API changes discovered
Additional Resources
- Firefox source: https://searchfox.org/
- Firefox API documentation: https://firefox-source-docs.mozilla.org/
- Mercurial repository: https://hg.mozilla.org/mozilla-central/
Last Updated: December 2025 (Firefox 146 upgrade)