mirror of
https://forge.fsky.io/oneflux/omegafox.git
synced 2026-02-10 11:42:03 -08:00
remove deprecated legacy launcher
This commit is contained in:
parent
a5a458a3f4
commit
591f056478
14 changed files with 6 additions and 949 deletions
|
|
@ -1,6 +0,0 @@
|
||||||
## Deprecated Assets
|
|
||||||
|
|
||||||
##### 2024-11-21
|
|
||||||
|
|
||||||
- Old launcher has been deprecated due to it not supporting non-Linux platforms, and for using FF's debugging protocol to load addons [#90](https://github.com/daijro/camoufox/issues/90).
|
|
||||||
- `generate-locales.sh` (based on [LibreWolf's locale build system](https://gitlab.com/librewolf-community/browser/source/-/blob/3dc56de7b0665724bf3842198cebe961c42a81e0/scripts/generate-locales.sh)) was deprecated due to "Camoufox" leaking to the page [#90](https://github.com/daijro/camoufox/issues/90).
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [ $# -ne 2 ]; then
|
|
||||||
echo "Usage: $0 <arch> <os>"
|
|
||||||
echo "arch: x86_64, i686, arm64"
|
|
||||||
echo "os: linux, windows, macos"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
ARCH=$1
|
|
||||||
OS=$2
|
|
||||||
|
|
||||||
case $ARCH in
|
|
||||||
x86_64) GOARCH=amd64 ;;
|
|
||||||
i686) GOARCH=386 ;;
|
|
||||||
arm64) GOARCH=arm64 ;;
|
|
||||||
*) echo "Invalid architecture"; exit 1 ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
case $OS in
|
|
||||||
linux) GOOS=linux ;;
|
|
||||||
windows) GOOS=windows ;;
|
|
||||||
macos) GOOS=darwin ;;
|
|
||||||
*) echo "Invalid OS"; exit 1 ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
[ "$OS" = "windows" ] && OUTPUT="launch.exe" || OUTPUT="launch"
|
|
||||||
|
|
||||||
rm -rf ./dist launch launch.exe
|
|
||||||
|
|
||||||
echo Building launcher...
|
|
||||||
GOOS=$GOOS GOARCH=$GOARCH go build -o dist/$OUTPUT || exit 1
|
|
||||||
|
|
||||||
echo "Complete: launcher/dist/$OUTPUT"
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,166 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"os/signal"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getExecutableName() string {
|
|
||||||
// Get the executable name based on the OS
|
|
||||||
switch normalizeOS(runtime.GOOS) {
|
|
||||||
case "linux":
|
|
||||||
return getPath("camoufox-bin")
|
|
||||||
case "macos":
|
|
||||||
return getPath("Camoufox.app")
|
|
||||||
case "windows":
|
|
||||||
return getPath("camoufox.exe")
|
|
||||||
default:
|
|
||||||
// This should never be reached due to the check in normalizeOS
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setExecutablePermissions(execPath string) error {
|
|
||||||
// Set executable permissions if needed
|
|
||||||
switch normalizeOS(runtime.GOOS) {
|
|
||||||
case "macos":
|
|
||||||
return filepath.Walk(execPath, func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return maybeSetPermission(path, 0755)
|
|
||||||
})
|
|
||||||
case "linux":
|
|
||||||
return maybeSetPermission(execPath, 0755)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func maybeSetPermission(path string, mode os.FileMode) error {
|
|
||||||
info, err := os.Stat(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
currentMode := info.Mode().Perm()
|
|
||||||
if currentMode != mode {
|
|
||||||
return os.Chmod(path, mode)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterOutput(r io.Reader, w io.Writer) {
|
|
||||||
scanner := bufio.NewScanner(r)
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
if !ExclusionRegex.MatchString(line) {
|
|
||||||
fmt.Fprintln(w, line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run Camoufox
|
|
||||||
func runCamoufox(execName string, args []string, addonsList []string, stderrPath string) {
|
|
||||||
// If addons are specified, get the debug port
|
|
||||||
var debugPortInt int
|
|
||||||
if len(addonsList) > 0 {
|
|
||||||
debugPortInt = getDebugPort(&args)
|
|
||||||
}
|
|
||||||
|
|
||||||
// For macOS, use "open" command to launch the app
|
|
||||||
if normalizeOS(runtime.GOOS) == "macos" {
|
|
||||||
args = append([]string{"-a", execName}, args...)
|
|
||||||
execName = "open"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print args
|
|
||||||
cmd := exec.Command(execName, args...)
|
|
||||||
|
|
||||||
setProcessGroupID(cmd)
|
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error creating stdout pipe: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
stderr, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error creating stderr pipe: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up signal handling
|
|
||||||
sigChan := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
fmt.Printf("Error starting %s: %v\n", execName, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(addonsList) > 0 {
|
|
||||||
go tryLoadAddons(debugPortInt, addonsList)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Channel to signal when the subprocess has finished
|
|
||||||
subprocessDone := make(chan struct{})
|
|
||||||
|
|
||||||
// Start a goroutine to handle signals
|
|
||||||
go func() {
|
|
||||||
select {
|
|
||||||
case <-sigChan:
|
|
||||||
killProcessGroup(cmd)
|
|
||||||
case <-subprocessDone:
|
|
||||||
// Subprocess has finished, exit the Go process
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
done := make(chan bool)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
filterOutput(stdout, os.Stdout)
|
|
||||||
done <- true
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
// If stderrPath is not empty, write to the file
|
|
||||||
fmt.Printf("Setting stderr to file: %s\n", stderrPath)
|
|
||||||
if stderrPath != "" {
|
|
||||||
file, err := os.Create(stderrPath)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error creating stderr file: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
filterOutput(stderr, file)
|
|
||||||
}
|
|
||||||
filterOutput(stderr, os.Stderr)
|
|
||||||
}()
|
|
||||||
|
|
||||||
<-done
|
|
||||||
<-done
|
|
||||||
|
|
||||||
// Wait for the command to finish
|
|
||||||
if err := cmd.Wait(); err != nil {
|
|
||||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
|
||||||
// If the subprocess exited with an error, use its exit code
|
|
||||||
os.Exit(exitErr.ExitCode())
|
|
||||||
} else {
|
|
||||||
fmt.Printf("Error running %s: %v\n", execName, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal that the subprocess has finished
|
|
||||||
close(subprocessDone)
|
|
||||||
|
|
||||||
// Wait here to allow the signal handling goroutine to exit the process
|
|
||||||
select {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
module launch
|
|
||||||
|
|
||||||
go 1.23.0
|
|
||||||
|
|
||||||
require github.com/mileusna/useragent v1.3.4
|
|
||||||
|
|
||||||
require github.com/goccy/go-json v0.10.3
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
|
||||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
|
||||||
github.com/mileusna/useragent v1.3.4 h1:MiuRRuvGjEie1+yZHO88UBYg8YBC/ddF6T7F56i3PCk=
|
|
||||||
github.com/mileusna/useragent v1.3.4/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc=
|
|
||||||
|
|
@ -1,157 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Gets the debug port from the args, or creates a new one if not provided
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirm paths are valid
|
|
||||||
func confirmPaths(paths []string) {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate an open port
|
|
||||||
func getOpenPort() int {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Waits for the server to start, then loads the addons
|
|
||||||
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 {
|
|
||||||
go loadFirefoxAddon(debugPortInt, addon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
@ -1,219 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
json "github.com/goccy/go-json"
|
|
||||||
"github.com/mileusna/useragent"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
args := os.Args[1:]
|
|
||||||
|
|
||||||
configPath := parseArgs("--config", "{}", &args, true)
|
|
||||||
addons := parseArgs("--addons", "[]", &args, true)
|
|
||||||
excludeAddons := parseArgs("--exclude-addons", "[]", &args, true)
|
|
||||||
stderrPath := parseArgs("--stderr", "", &args, true)
|
|
||||||
|
|
||||||
//*** PARSE CONFIG ***//
|
|
||||||
|
|
||||||
// Read and parse the config file
|
|
||||||
var configMap map[string]interface{}
|
|
||||||
parseJson(configPath, &configMap)
|
|
||||||
validateConfig(configMap)
|
|
||||||
|
|
||||||
// Add "debug: True" to the config
|
|
||||||
if stderrPath != "" {
|
|
||||||
configMap["debug"] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
//*** PARSE ADDONS ***//
|
|
||||||
|
|
||||||
// If addons are passed, handle them
|
|
||||||
var addonsList []string
|
|
||||||
parseJson(addons, &addonsList)
|
|
||||||
|
|
||||||
// Confirm addon paths are valid
|
|
||||||
confirmPaths(addonsList)
|
|
||||||
|
|
||||||
// Add the default addons, excluding the ones specified in --exclude-addons
|
|
||||||
var excludeAddonsList []string
|
|
||||||
parseJson(excludeAddons, &excludeAddonsList)
|
|
||||||
|
|
||||||
addDefaultAddons(excludeAddonsList, &addonsList)
|
|
||||||
|
|
||||||
//*** FONTS ***//
|
|
||||||
|
|
||||||
// Determine the target OS
|
|
||||||
userAgentOS := determineUserAgentOS(configMap)
|
|
||||||
// Add OS specific fonts
|
|
||||||
updateFonts(configMap, userAgentOS)
|
|
||||||
|
|
||||||
//*** LAUNCH ***//
|
|
||||||
|
|
||||||
setEnvironmentVariables(configMap, userAgentOS)
|
|
||||||
|
|
||||||
// Run the Camoufox executable
|
|
||||||
execName := getExecutableName()
|
|
||||||
if err := setExecutablePermissions(execName); err != nil {
|
|
||||||
fmt.Printf("Error setting executable permissions: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
runCamoufox(execName, args, addonsList, stderrPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the absolute path relative to the launcher
|
|
||||||
func getPath(path string) string {
|
|
||||||
execPath, err := os.Executable()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error getting executable path: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
execDir := filepath.Dir(execPath)
|
|
||||||
|
|
||||||
addonPath := filepath.Join(execDir, path)
|
|
||||||
return addonPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parses & removes an argument from the args list
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// fileExists checks if a file exists
|
|
||||||
func fileExists(path string) bool {
|
|
||||||
_, err := os.Stat(path)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parses a JSON string or file into a map
|
|
||||||
func parseJson(argv string, target interface{}) {
|
|
||||||
// Unmarshal the config input into a map
|
|
||||||
var data []byte
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// Check if the input is a file path or inline JSON
|
|
||||||
if fileExists(argv) {
|
|
||||||
data, err = os.ReadFile(argv)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error reading JSON file: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Assume it's inline JSON
|
|
||||||
data = []byte(argv)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(data, target); err != nil {
|
|
||||||
fmt.Printf("Invalid JSON: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determines the target OS from the user agent string if provided
|
|
||||||
func determineUserAgentOS(configMap map[string]interface{}) string {
|
|
||||||
// Determine the OS from the user agent string if provided
|
|
||||||
defaultOS := normalizeOS(runtime.GOOS)
|
|
||||||
if ua, ok := configMap["navigator.userAgent"].(string); ok {
|
|
||||||
parsedUA := useragent.Parse(ua)
|
|
||||||
if parsedUA.OS != "" {
|
|
||||||
return normalizeOS(parsedUA.OS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return defaultOS
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the OS name as {macos, windows, linux}
|
|
||||||
func normalizeOS(osName string) string {
|
|
||||||
osName = strings.ToLower(osName)
|
|
||||||
switch {
|
|
||||||
case osName == "darwin" || strings.Contains(osName, "mac"):
|
|
||||||
return "macos"
|
|
||||||
case strings.Contains(osName, "win"):
|
|
||||||
return "windows"
|
|
||||||
default:
|
|
||||||
return "linux"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add fonts associated with the OS to the config map
|
|
||||||
func updateFonts(configMap map[string]interface{}, userAgentOS string) {
|
|
||||||
fonts, ok := configMap["fonts"].([]interface{})
|
|
||||||
if !ok {
|
|
||||||
fonts = []interface{}{}
|
|
||||||
}
|
|
||||||
existingFonts := make(map[string]bool)
|
|
||||||
for _, font := range fonts {
|
|
||||||
if f, ok := font.(string); ok {
|
|
||||||
existingFonts[f] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, font := range FontsByOS[userAgentOS] {
|
|
||||||
if !existingFonts[font] {
|
|
||||||
fonts = append(fonts, font)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
configMap["fonts"] = fonts
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the config map with the fonts and environment variables
|
|
||||||
func setEnvironmentVariables(configMap map[string]interface{}, userAgentOS string) {
|
|
||||||
updatedConfigData, err := json.Marshal(configMap)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error updating config: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate utf8
|
|
||||||
if !utf8.Valid(updatedConfigData) {
|
|
||||||
fmt.Println("Config is not valid UTF-8")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split the config into chunks of 2047 characters if the OS is Windows,
|
|
||||||
// otherwise split into 32767 characters
|
|
||||||
var chunkSize int
|
|
||||||
if normalizeOS(runtime.GOOS) == "windows" {
|
|
||||||
chunkSize = 2047
|
|
||||||
} else {
|
|
||||||
chunkSize = 32767
|
|
||||||
}
|
|
||||||
|
|
||||||
configStr := string(updatedConfigData)
|
|
||||||
for i := 0; i < len(configStr); i += chunkSize {
|
|
||||||
end := i + chunkSize
|
|
||||||
if end > len(configStr) {
|
|
||||||
end = len(configStr)
|
|
||||||
}
|
|
||||||
chunk := configStr[i:end]
|
|
||||||
envName := fmt.Sprintf("CAMOU_CONFIG_%d", (i/chunkSize)+1)
|
|
||||||
if err := os.Setenv(envName, chunk); err != nil {
|
|
||||||
fmt.Printf("Error setting %s: %v\n", envName, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if normalizeOS(runtime.GOOS) == "linux" {
|
|
||||||
fontconfigPath := getPath(filepath.Join("fontconfig", userAgentOS))
|
|
||||||
os.Setenv("FONTCONFIG_PATH", fontconfigPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
//go:build !windows
|
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os/exec"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func setProcessGroupID(cmd *exec.Cmd) {
|
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
|
||||||
}
|
|
||||||
|
|
||||||
func killProcessGroup(cmd *exec.Cmd) {
|
|
||||||
syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
//go:build windows
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os/exec"
|
|
||||||
)
|
|
||||||
|
|
||||||
func setProcessGroupID(cmd *exec.Cmd) {
|
|
||||||
// Windows doesn't support process groups in the same way
|
|
||||||
}
|
|
||||||
|
|
||||||
func killProcessGroup(cmd *exec.Cmd) {
|
|
||||||
cmd.Process.Kill()
|
|
||||||
}
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Property struct {
|
|
||||||
Property string `json:"property"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateConfig(configMap map[string]interface{}) {
|
|
||||||
properties := loadProperties()
|
|
||||||
|
|
||||||
// Create a map for quick lookup of property types
|
|
||||||
propertyTypes := make(map[string]string)
|
|
||||||
for _, prop := range properties {
|
|
||||||
propertyTypes[prop.Property] = prop.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, value := range configMap {
|
|
||||||
expectedType, exists := propertyTypes[key]
|
|
||||||
if !exists {
|
|
||||||
fmt.Printf("Warning: Unknown property %s in config\n", key)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !validateType(value, expectedType) {
|
|
||||||
fmt.Printf("Invalid type for property %s. Expected %s, got %T\n", key, expectedType, value)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadProperties() []Property {
|
|
||||||
// Get the path to the properties.json file
|
|
||||||
var propertiesPath string
|
|
||||||
if normalizeOS(runtime.GOOS) == "macos" {
|
|
||||||
propertiesPath = getPath("Camoufox.app/Contents/Resources/properties.json")
|
|
||||||
} else {
|
|
||||||
propertiesPath = getPath("properties.json")
|
|
||||||
}
|
|
||||||
var properties []Property
|
|
||||||
// Parse the JSON file
|
|
||||||
parseJson(propertiesPath, &properties)
|
|
||||||
return properties
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateType(value interface{}, expectedType string) bool {
|
|
||||||
switch expectedType {
|
|
||||||
case "str":
|
|
||||||
_, ok := value.(string)
|
|
||||||
return ok
|
|
||||||
case "int":
|
|
||||||
v, ok := value.(float64)
|
|
||||||
return ok && v == math.Trunc(v)
|
|
||||||
case "uint":
|
|
||||||
v, ok := value.(float64)
|
|
||||||
return ok && v == math.Trunc(v) && v >= 0
|
|
||||||
case "double":
|
|
||||||
_, ok := value.(float64)
|
|
||||||
return ok
|
|
||||||
case "bool":
|
|
||||||
_, ok := value.(bool)
|
|
||||||
return ok
|
|
||||||
case "array":
|
|
||||||
return reflect.TypeOf(value).Kind() == reflect.Slice
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,146 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"archive/zip"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Downloads and extracts the default addons
|
|
||||||
func addDefaultAddons(excludeList []string, addonsList *[]string) {
|
|
||||||
// Build a map from DefaultAddons, excluding keys found in excludeAddonsList
|
|
||||||
addonsMap := make(map[string]string)
|
|
||||||
for name, url := range DefaultAddons {
|
|
||||||
if len(excludeList) == 0 || !contains(excludeList, name) {
|
|
||||||
addonsMap[name] = url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Download if not already downloaded
|
|
||||||
maybeDownloadAddons(addonsMap, addonsList)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Downloads and extracts the addon
|
|
||||||
func downloadAndExtract(url, extractPath string) error {
|
|
||||||
// Create a temporary file to store the downloaded zip
|
|
||||||
tempFile, err := os.CreateTemp("", "camoufox-addon-*.zip")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create temp file: %w", err)
|
|
||||||
}
|
|
||||||
defer os.Remove(tempFile.Name()) // Clean up the temp file when done
|
|
||||||
|
|
||||||
// Download the zip file
|
|
||||||
resp, err := http.Get(url)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to download addon: %w", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
// Write the body to the temp file
|
|
||||||
_, err = io.Copy(tempFile, resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to write addon to temp file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the file before unzipping
|
|
||||||
tempFile.Close()
|
|
||||||
|
|
||||||
// Extract the zip file
|
|
||||||
err = unzip(tempFile.Name(), extractPath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to extract addon: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extracts the zip file
|
|
||||||
func unzip(src, dest string) error {
|
|
||||||
r, err := zip.OpenReader(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer r.Close()
|
|
||||||
|
|
||||||
for _, f := range r.File {
|
|
||||||
fpath := filepath.Join(dest, f.Name)
|
|
||||||
|
|
||||||
if f.FileInfo().IsDir() {
|
|
||||||
os.MkdirAll(fpath, os.ModePerm)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
rc, err := f.Open()
|
|
||||||
if err != nil {
|
|
||||||
outFile.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = io.Copy(outFile, rc)
|
|
||||||
outFile.Close()
|
|
||||||
rc.Close()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks if a slice contains a string
|
|
||||||
func contains(slice []string, item string) bool {
|
|
||||||
for _, s := range slice {
|
|
||||||
if s == item {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the absolute path to the target addon location
|
|
||||||
func getAddonPath(addonName string) string {
|
|
||||||
return getPath(filepath.Join("addons", addonName))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Downloads and extracts the addons
|
|
||||||
func maybeDownloadAddons(addons map[string]string, addonsList *[]string) {
|
|
||||||
for addonName, url := range addons {
|
|
||||||
// Get the addon path
|
|
||||||
addonPath := getAddonPath(addonName)
|
|
||||||
|
|
||||||
// Check if the addon is already extracted
|
|
||||||
if _, err := os.Stat(addonPath); !os.IsNotExist(err) {
|
|
||||||
// Add the existing addon path to addonsList
|
|
||||||
*addonsList = append(*addonsList, addonPath)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Addon doesn't exist, create directory and download
|
|
||||||
err := os.MkdirAll(addonPath, 0755)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Failed to create directory for %s: %v\n", addonName, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
err = downloadAndExtract(url, addonPath)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Failed to download and extract %s: %v\n", addonName, err)
|
|
||||||
} else {
|
|
||||||
fmt.Printf("Successfully downloaded and extracted %s\n", addonName)
|
|
||||||
// Add the new addon directory path to addonsList
|
|
||||||
*addonsList = append(*addonsList, addonPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
#!/usr/bin/bash
|
|
||||||
|
|
||||||
if [ ! -f browser/locales/shipped-locales ]; then
|
|
||||||
echo "ERROR: Run this script from the root of the Camoufox source code"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -rf browser/locales/l10n
|
|
||||||
mkdir browser/locales/l10n
|
|
||||||
|
|
||||||
N=8
|
|
||||||
for i in $(seq $N); do echo; done
|
|
||||||
total=$(wc -l < browser/locales/shipped-locales)
|
|
||||||
|
|
||||||
echo_status() {
|
|
||||||
printf "\033[$((($N - $n) + 1))A$@ %40s\r\033[$((($N - $n) + 1))B"
|
|
||||||
}
|
|
||||||
|
|
||||||
generate_locale() {
|
|
||||||
if echo " en-US ca ja " | grep -q " $1 "; then
|
|
||||||
echo_status "Skipping locale \"$1\""
|
|
||||||
sleep 1
|
|
||||||
echo_status
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
echo_status "Downloading locale \"$1\""
|
|
||||||
wget -q -O browser/locales/l10n/$1.zip https://hg.mozilla.org/l10n-central/$1/archive/tip.zip
|
|
||||||
echo_status "Extracting locale \"$1\""
|
|
||||||
7z x -y -obrowser/locales/l10n browser/locales/l10n/$1.zip > /dev/null
|
|
||||||
mv browser/locales/l10n/$1-*/ browser/locales/l10n/$1/
|
|
||||||
rm -f browser/locales/l10n/$1.zip
|
|
||||||
echo_status "Generating locale \"$1\""
|
|
||||||
mv browser/locales/l10n/$1/browser/branding/official browser/locales/l10n/$1/browser/branding/camoufox
|
|
||||||
find browser/locales/l10n/$1 -type f -exec sed -i -e 's/Mozilla Firefox/Camoufox/g' {} \;
|
|
||||||
find browser/locales/l10n/$1 -type f -exec sed -i -e 's/Mozilla/Camoufox/g' {} \;
|
|
||||||
find browser/locales/l10n/$1 -type f -exec sed -i -e 's/Firefox/Camoufox/g' {} \;
|
|
||||||
echo_status "Done"
|
|
||||||
sleep 0.3
|
|
||||||
echo_status
|
|
||||||
}
|
|
||||||
|
|
||||||
while read in; do
|
|
||||||
((n=n%N)); ((n++==0)) && wait
|
|
||||||
generate_locale $in &
|
|
||||||
done < browser/locales/shipped-locales
|
|
||||||
|
|
||||||
wait
|
|
||||||
|
|
||||||
printf "\033[$(($N))A\rGenerated $total locales %-40s\n"
|
|
||||||
|
|
@ -668,11 +668,11 @@ defaultPref("dom.ipc.keepProcessesAlive.web", 0);
|
||||||
defaultPref("javascript.options.wasm_shared_memory", false);
|
defaultPref("javascript.options.wasm_shared_memory", false);
|
||||||
|
|
||||||
// Disable TLS 1.0 and 1.1
|
// Disable TLS 1.0 and 1.1
|
||||||
user_pref("security.tls.version.min", 3); // 3 = TLS 1.2
|
defaultPref("security.tls.version.min", 3); // 3 = TLS 1.2
|
||||||
user_pref("security.tls.version.max", 4); // 4 = TLS 1.3
|
defaultPref("security.tls.version.max", 4); // 4 = TLS 1.3
|
||||||
|
|
||||||
// Disable weak ciphers
|
// Disable weak ciphers
|
||||||
user_pref("security.ssl3.rsa_rc4_128_sha", false);
|
defaultPref("security.ssl3.rsa_rc4_128_sha", false);
|
||||||
user_pref("security.ssl3.rsa_des_ede3_sha", false);
|
defaultPref("security.ssl3.rsa_des_ede3_sha", false);
|
||||||
user_pref("security.ssl3.dhe_rsa_aes_128_sha", false);
|
defaultPref("security.ssl3.dhe_rsa_aes_128_sha", false);
|
||||||
user_pref("security.ssl3.dhe_rsa_aes_256_sha", false);
|
defaultPref("security.ssl3.dhe_rsa_aes_256_sha", false);
|
||||||
Loading…
Add table
Reference in a new issue