mirror of
https://forge.fsky.io/oneflux/omegafox.git
synced 2026-02-10 06:32:05 -08:00
Launcher: Add --addon option to CLI
This commit is contained in:
parent
8e5144abe0
commit
077f6acf47
4 changed files with 217 additions and 37 deletions
137
launcher/addon.go
Normal file
137
launcher/addon.go
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getDebugPort(args *[]string) int {
|
||||
debugPort := parseArgs("-start-debugger-server", "", args, false)
|
||||
|
||||
var debugPortInt int
|
||||
var err error
|
||||
if debugPort == "" {
|
||||
// Create new debugger server port
|
||||
debugPortInt = getOpenPort()
|
||||
// Add -start-debugger-server {debugPort} to args
|
||||
*args = append(*args, "-start-debugger-server", strconv.Itoa(debugPortInt))
|
||||
} else {
|
||||
debugPortInt, err = strconv.Atoi(debugPort)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing debug port. Must be an integer: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
return debugPortInt
|
||||
}
|
||||
|
||||
func confirmPaths(paths []string) {
|
||||
// Confirm paths are valid
|
||||
for _, path := range paths {
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
fmt.Printf("Error: %s is not a valid addon path.\n", path)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getOpenPort() int {
|
||||
// Generate an open port
|
||||
ln, err := net.Listen("tcp", ":0") // listen on a random port
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
addr := ln.Addr().(*net.TCPAddr) // type assert to *net.TCPAddr to get the Port
|
||||
return addr.Port
|
||||
}
|
||||
|
||||
// Firefox addon loader
|
||||
// Ported from this Nodejs implementation:
|
||||
// https://github.com/microsoft/playwright/issues/7297#issuecomment-1211763085
|
||||
func loadFirefoxAddon(port int, addonPath string) bool {
|
||||
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", "localhost", port))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
success := false
|
||||
|
||||
send := func(data map[string]string) error {
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fmt.Fprintf(conn, "%d:%s", len(jsonData), jsonData)
|
||||
return err
|
||||
}
|
||||
|
||||
err = send(map[string]string{
|
||||
"to": "root",
|
||||
"type": "getRoot",
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
onMessage := func(message map[string]interface{}) bool {
|
||||
if addonsActor, ok := message["addonsActor"].(string); ok {
|
||||
err := send(map[string]string{
|
||||
"to": addonsActor,
|
||||
"type": "installTemporaryAddon",
|
||||
"addonPath": addonPath,
|
||||
})
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := message["addon"]; ok {
|
||||
success = true
|
||||
return true
|
||||
}
|
||||
|
||||
if _, ok := message["error"]; ok {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(conn)
|
||||
for {
|
||||
lengthStr, err := reader.ReadString(':')
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
length, err := strconv.Atoi(strings.TrimSuffix(lengthStr, ":"))
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
jsonData := make([]byte, length)
|
||||
_, err = reader.Read(jsonData)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
var message map[string]interface{}
|
||||
err = json.Unmarshal(jsonData, &message)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if onMessage(message) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return success
|
||||
}
|
||||
|
|
@ -13,9 +13,21 @@ import (
|
|||
)
|
||||
|
||||
func main() {
|
||||
configPath, remainingArgs := parseArgs(os.Args[1:]) // Parse args arguments
|
||||
args := os.Args[1:]
|
||||
|
||||
configMap := readAndParseConfig(configPath) // Read and parse the config file
|
||||
configPath := parseArgs("--config", "{}", &args, true)
|
||||
addons := parseArgs("--addons", "[]", &args, true)
|
||||
|
||||
// Read and parse the config file
|
||||
var configMap map[string]interface{}
|
||||
parseJson(configPath, &configMap)
|
||||
|
||||
// If addons are passed, handle them
|
||||
var addonsList []string
|
||||
parseJson(addons, &addonsList)
|
||||
|
||||
// Confirm addon paths are valid
|
||||
confirmPaths(addonsList)
|
||||
|
||||
userAgentOS := determineUserAgentOS(configMap) // Determine the user agent OS
|
||||
|
||||
|
|
@ -29,58 +41,47 @@ func main() {
|
|||
fmt.Printf("Error setting executable permissions: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
runCamoufox(execName, remainingArgs)
|
||||
runCamoufox(execName, args, addonsList)
|
||||
}
|
||||
|
||||
func parseArgs(args []string) (string, []string) {
|
||||
// Parse the arguments
|
||||
var configPath string
|
||||
var remainingArgs []string
|
||||
|
||||
for i := 0; i < len(args); i++ {
|
||||
if args[i] == "--config" {
|
||||
if i+1 < len(args) {
|
||||
configPath = args[i+1]
|
||||
remainingArgs = append(args[:i], args[i+2:]...)
|
||||
break
|
||||
} else {
|
||||
fmt.Println("Error: --config flag requires a value")
|
||||
os.Exit(1)
|
||||
}
|
||||
func parseArgs(param string, defaultValue string, args *[]string, removeFromArgs bool) string {
|
||||
for i := 0; i < len(*args); i++ {
|
||||
if (*args)[i] != param {
|
||||
continue
|
||||
}
|
||||
if i+1 < len(*args) {
|
||||
value := (*args)[i+1]
|
||||
if removeFromArgs {
|
||||
*args = append((*args)[:i], (*args)[i+2:]...)
|
||||
}
|
||||
return value
|
||||
}
|
||||
fmt.Printf("Error: %s flag requires a value\n", param)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// If no config data is provided, fallback to an empty object
|
||||
if configPath == "" {
|
||||
configPath = "{}"
|
||||
}
|
||||
|
||||
return configPath, remainingArgs
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func readAndParseConfig(configInput string) map[string]interface{} {
|
||||
func parseJson(argv string, target interface{}) {
|
||||
// Unmarshal the config input into a map
|
||||
var configData []byte
|
||||
var data []byte
|
||||
|
||||
// Check if the input is a file path or inline JSON
|
||||
if _, err := os.Stat(configInput); err == nil {
|
||||
configData, err = os.ReadFile(configInput)
|
||||
if _, err := os.Stat(argv); err == nil {
|
||||
data, err = os.ReadFile(argv)
|
||||
if err != nil {
|
||||
fmt.Printf("Error reading config file: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
// Assume it's inline JSON
|
||||
configData = []byte(configInput)
|
||||
data = []byte(argv)
|
||||
}
|
||||
|
||||
var configMap map[string]interface{}
|
||||
if err := json.Unmarshal(configData, &configMap); err != nil {
|
||||
if err := json.Unmarshal(data, target); err != nil {
|
||||
fmt.Printf("Invalid JSON in config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return configMap
|
||||
}
|
||||
|
||||
func determineUserAgentOS(configMap map[string]interface{}) string {
|
||||
|
|
|
|||
|
|
@ -4,12 +4,14 @@ import (
|
|||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getExecutableName() string {
|
||||
|
|
@ -66,7 +68,32 @@ func filterOutput(r io.Reader, w io.Writer) {
|
|||
}
|
||||
}
|
||||
|
||||
func runCamoufox(execName string, args []string) {
|
||||
func tryLoadAddons(debugPortInt int, addonsList []string) {
|
||||
// Wait for the server to be open
|
||||
for {
|
||||
conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%d", debugPortInt))
|
||||
if err == nil {
|
||||
conn.Close()
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
// Load addons
|
||||
for _, addon := range addonsList {
|
||||
loadFirefoxAddon(debugPortInt, addon)
|
||||
}
|
||||
}
|
||||
|
||||
// Run Camoufox
|
||||
func runCamoufox(execName string, args []string, addonsList []string) {
|
||||
// If addons are specified, get the debug port
|
||||
var debugPortInt int
|
||||
if len(addonsList) > 0 {
|
||||
debugPortInt = getDebugPort(&args)
|
||||
}
|
||||
|
||||
// Print args
|
||||
cmd := exec.Command(execName, args...)
|
||||
|
||||
setProcessGroupID(cmd)
|
||||
|
|
@ -91,6 +118,10 @@ func runCamoufox(execName string, args []string) {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
if len(addonsList) > 0 {
|
||||
go tryLoadAddons(debugPortInt, addonsList)
|
||||
}
|
||||
|
||||
// Channel to signal when the subprocess has finished
|
||||
subprocessDone := make(chan struct{})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,16 @@
|
|||
// Camoufox functionality
|
||||
|
||||
pref("gfx.bundled-fonts.activate", 1);
|
||||
|
||||
pref("devtools.debugger.remote-enabled", true);
|
||||
pref("devtools.debugger.prompt-connection", false);
|
||||
pref("privacy.userContext.enabled", true);
|
||||
|
||||
pref("browser.sessionstore.max_resumed_crashes", 0);
|
||||
pref("browser.sessionstore.restore_on_demand", false);
|
||||
pref("browser.sessionstore.restore_tabs_lazily", false);
|
||||
|
||||
|
||||
// Debloat and speed up Camoufox.
|
||||
|
||||
// Debloat (from Peskyfox)
|
||||
|
|
@ -285,7 +298,6 @@ pref("privacy.partition.network_state", false); // Disable network seperations
|
|||
pref("accessibility.force_disabled", 1);
|
||||
pref("browser.sessionstore.max_tabs_undo", 0);
|
||||
pref("browser.sessionstore.max_windows_undo", 0);
|
||||
pref("browser.sessionstore.resume_from_crash", false);
|
||||
pref("browser.sessionstore.resuming_after_os_restart", false);
|
||||
pref("browser.sessionstore.resume_session_once", false);
|
||||
pref("browser.sessionstore.upgradeBackup.maxUpgradeBackups", 0);
|
||||
|
|
@ -406,7 +418,6 @@ pref("userChrome.icon.global_menu", true);
|
|||
pref("userChrome.icon.global_menubar", true);
|
||||
pref("userChrome.icon.1-25px_stroke", true);
|
||||
|
||||
pref("gfx.bundled-fonts.activate", 1);
|
||||
|
||||
// =================================================================
|
||||
// THESE ARE THE PROPERTIES THAT MUST BE ENABLED FOR JUGGLER TO WORK
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue