Skip to content

darkcodi/ffcv

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

60 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ffcv

crates.io docs.rs license Rust

Firefox Configuration Viewer - Parse and query Firefox preference files with ease.

ffcv is both a command-line tool and a Rust library for working with Firefox's prefs.js configuration files. It provides a structured way to parse, query, and understand Firefox settings across all platforms (Linux, macOS, Windows).

Features

  • Complete Parsing - Handles all Firefox preference types:
    • User preferences (user_pref)
    • Default preferences (pref)
    • Locked preferences (lock_pref)
    • Sticky preferences (sticky_pref)
  • Firefox Default Preferences - Extract and merge Firefox's built-in default preferences from omni.ja:
    • Built-in defaults from omni.ja archives
    • Global defaults from greprefs.js
    • User preferences from prefs.js
    • Proper precedence handling (built-ins < globals < user)
    • Source tracking for each preference
  • Firefox Installation Discovery - Automatic Firefox installation detection:
    • Cross-platform support (Linux, macOS, Windows)
    • Multiple Firefox version support (ESR, Release, Beta)
    • Version detection from application.ini
  • Powerful Querying - Filter preferences using glob patterns like "network.*" or "browser.*.enabled"
  • Cross-Platform - Automatic Firefox profile discovery on Linux, macOS, and Windows
  • Rich Data Types - Supports boolean, integer, float, string, and null values
  • Type-Safe API - Convenience trait for easy value type checking and extraction
  • Simple Interface - All public types and functions available at crate root
  • Human-Readable Explanations - Optional explanations for what preferences do
  • Flexible Output - JSON output with customizable formatting
  • Well-Tested - Comprehensive test coverage with robust error handling

Installation

Command-Line Tool

Install via cargo:

cargo install ffcv

This installs the ffcv binary for viewing Firefox configurations from your terminal.

Library Usage

Add to your Cargo.toml:

[dependencies]
ffcv = "1.1.1"

Command-Line Usage

List Firefox Profiles

# List all Firefox profiles on your system
ffcv profile

# Specify a custom Firefox profiles directory
ffcv profile --profiles-dir /custom/path

List Firefox Installations

# List detected Firefox installations
ffcv install

# List all Firefox installations (including multiple versions)
ffcv install --all

# Show detailed information about each installation
ffcv install --all --verbose

View Configuration

# View all preferences (includes Firefox defaults by default)
ffcv config

# View preferences for a specific profile
ffcv config --profile myprofile

# Query specific preferences by glob pattern
ffcv config --query "network.*"
ffcv config --query "browser.*" --query "extensions.*"

# Get a single preference (raw output)
ffcv config --get "network.proxy.type"

# View all preferences including built-in defaults
ffcv config --all

# View only user-modified preferences (default behavior)
ffcv config

# Specify custom Firefox installation directory
ffcv config --install-dir /usr/lib/firefox

# Read from stdin
cat prefs.js | ffcv config --stdin

# Output as JSON (includes source information)
ffcv config --output-type json-array

# Output as simple JSON object (no source information)
ffcv config --output-type json-object

Library Usage

Basic Parsing

use ffcv::parse_prefs_js;
use std::fs;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let content = fs::read_to_string("prefs.js")?;
    let entries = parse_prefs_js(&content)?;

    for entry in entries {
        println!("{:?} = {:?}", entry.key, entry.value);
    }

    Ok(())
}

Query Preferences

use ffcv::{parse_prefs_js, query_preferences};
use std::fs;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let content = fs::read_to_string("prefs.js")?;
    let entries = parse_prefs_js(&content)?;

    // Query network-related preferences
    let network_prefs = query_preferences(&entries, &["network.*"])?;

    // Display matching entries
    for entry in network_prefs {
        println!("{} = {:?}", entry.key, entry.value);
    }

    Ok(())
}

Profile Discovery

use ffcv::list_profiles;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let profiles = list_profiles(None)?;

    for profile in profiles {
        println!("Profile: {}", profile.name);
        println!("  Path: {}", profile.path.display());
        println!("  Default: {}", profile.is_default);
    }

    Ok(())
}

Firefox Installation Discovery

use ffcv::find_firefox_installation;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    if let Some(installation) = find_firefox_installation()? {
        println!("Firefox found at: {}", installation.path.display());
        println!("Version: {}", installation.version);
        println!("Has omni.ja: {}", installation.has_omni_ja);
        println!("Has greprefs.js: {}", installation.has_greprefs);
    } else {
        println!("No Firefox installation found");
    }

    Ok(())
}

Merge All Preferences

use ffcv::{merge_all_preferences, MergeConfig};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = MergeConfig {
        include_builtins: true,   // Include omni.ja defaults
        include_globals: true,    // Include greprefs.js
        include_user: true,       // Include user prefs.js
        continue_on_error: true,  // Don't fail if some sources are missing
    };

    let merged = merge_all_preferences(
        &profile_path,
        None,  // Auto-detect Firefox installation
        &config
    )?;

    println!("Loaded {} preferences", merged.entries.len());
    println!("Sources: {:?}", merged.loaded_sources);

    if !merged.warnings.is_empty() {
        println!("Warnings:");
        for warning in &merged.warnings {
            println!("  - {}", warning);
        }
    }

    Ok(())
}

Working with Preference Values

use ffcv::{PrefEntry, PrefValue, PrefValueExt};

fn process_entry(entry: PrefEntry) {
    // Use convenience methods from PrefValueExt trait
    if let Some(enabled) = entry.value.as_bool() {
        if enabled {
            println!("{} is enabled", entry.key);
        } else {
            println!("{} is disabled", entry.key);
        }
    } else if let Some(n) = entry.value.as_int() {
        println!("{} = {} (integer)", entry.key, n);
    } else if let Some(s) = entry.value.as_string() {
        println!("{} = \"{}\"", entry.key, s);
    } else {
        println!("{} = {:?}", entry.key, entry.value);
    }
}

Finding a Specific Profile

use ffcv::find_profile_path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Find a specific Firefox profile by name
    let profile_path = find_profile_path("default", None)?;

    println!("Profile path: {}", profile_path.display());

    Ok(())
}

API Design

ffcv provides a clean, simplified API with all public types and functions available at the crate root:

Core Types:

  • PrefEntry - A single preference entry with key, value, type, and source
  • PrefType - The type of preference (User, Default, Locked, Sticky)
  • PrefValue - The value of a preference (Bool, Int, Float, String, Null)
  • PrefValueExt - Convenience trait for type-safe value access
  • PrefSource - Where a preference came from (BuiltIn, GlobalDefault, User, SystemPolicy)
  • FirefoxInstallation - Metadata about a Firefox installation
  • MergedPreferences - Combined preferences from multiple sources

Core Functions:

  • parse_prefs_js() - Parse preference file contents
  • parse_prefs_js_file() - Parse directly from a file path
  • query_preferences() - Filter preferences by glob patterns
  • merge_all_preferences() - Merge preferences from all sources
  • list_profiles() - List all Firefox profiles
  • find_profile_path() - Find a specific profile by name
  • find_firefox_installation() - Auto-detect Firefox installation
  • get_prefs_path() - Get the prefs.js path for a profile

All functions return Result<T, Error> for proper error handling.

Preference Types

Firefox uses several types of preferences:

  • User Preferences (user_pref) - Set by the user
  • Default Preferences (pref) - Application defaults
  • Locked Preferences (lock_pref) - Administratively locked, cannot be changed
  • Sticky Preferences (sticky_pref) - User preferences that persist across updates

Each preference has a value type:

  • Boolean (true/false)
  • Integer (64-bit)
  • Float (64-bit)
  • String (including JSON-encoded data)
  • Null

Environment Variables

ffcv respects the following environment variables for Firefox profile discovery:

  • FIREFOX_BIN - Path to Firefox binary
  • MOZ_PROFILES_DIR - Custom Firefox profiles directory
  • PROGRAMFILES - Windows Program Files directory (for Firefox detection)
  • HOME - User home directory (Unix-like systems)
  • APPDATA - Application Data directory (Windows)

Documentation

Full API documentation is available on docs.rs.

To build and view the documentation locally:

cargo doc --open

Platform Support

ffcv is tested and supported on:

  • Linux (x86_64, ARM64)
  • macOS (x86_64, ARM64/Apple Silicon)
  • Windows (x86_64)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is dual-licensed under either:

You may choose either license for your use.

Version 1.0

ffcv provides a stable and well-tested API. The library offers a clean, simplified interface with comprehensive Firefox preference parsing capabilities. All public types and functions are available at the crate root for easy importing.

Acknowledgments

Built for the Rust community to make Firefox configuration management easier and more programmatic.

Inspired by the need for better tools to understand and manage Firefox's extensive preference system.