mirror of
https://forge.fsky.io/oneflux/omegafox.git
synced 2026-02-10 08:02: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);
|
||||
|
||||
// Disable TLS 1.0 and 1.1
|
||||
user_pref("security.tls.version.min", 3); // 3 = TLS 1.2
|
||||
user_pref("security.tls.version.max", 4); // 4 = TLS 1.3
|
||||
defaultPref("security.tls.version.min", 3); // 3 = TLS 1.2
|
||||
defaultPref("security.tls.version.max", 4); // 4 = TLS 1.3
|
||||
|
||||
// Disable weak ciphers
|
||||
user_pref("security.ssl3.rsa_rc4_128_sha", false);
|
||||
user_pref("security.ssl3.rsa_des_ede3_sha", false);
|
||||
user_pref("security.ssl3.dhe_rsa_aes_128_sha", false);
|
||||
user_pref("security.ssl3.dhe_rsa_aes_256_sha", false);
|
||||
defaultPref("security.ssl3.rsa_rc4_128_sha", false);
|
||||
defaultPref("security.ssl3.rsa_des_ede3_sha", false);
|
||||
defaultPref("security.ssl3.dhe_rsa_aes_128_sha", false);
|
||||
defaultPref("security.ssl3.dhe_rsa_aes_256_sha", false);
|
||||
Loading…
Add table
Reference in a new issue