Launcher fixes for Windows

- Use GetEnvironmentVariableW to get CAMOU_CONFIG in UTF-16 instead of ANSI on Windows. Prevents data loss.
- Added ability to pass in CAMOU_CONFIG in multiple environment variables
- Split environment variables into 2047 character chunks on Windows
- Use github.com/goccy/go-json for faster JSON encoding
- Fix Windows not finding relative camoufox.exe file
This commit is contained in:
daijro.dev@gmail.com 2024-08-06 05:40:54 -05:00
parent a58428b534
commit 0448ea1c20
5 changed files with 85 additions and 9 deletions

View file

@ -1,5 +1,5 @@
/*
Helper to extract values from the Mask Config JSON file.
Helper to extract values from the CAMOU_CONFIG environment variable(s).
Written by daijro.
*/
@ -15,17 +15,60 @@ Written by daijro.
#include <stdlib.h>
#include <stdio.h>
#ifdef _WIN32
# include <windows.h>
#endif
namespace MaskConfig {
inline std::optional<std::string> get_env_utf8(const std::string& name) {
#ifdef _WIN32
std::wstring wName(name.begin(), name.end());
DWORD size = GetEnvironmentVariableW(wName.c_str(), nullptr, 0);
if (size == 0) return std::nullopt; // Environment variable not found
std::vector<wchar_t> buffer(size);
GetEnvironmentVariableW(wName.c_str(), buffer.data(), size);
std::wstring wValue(buffer.data());
// Convert UTF-16 to UTF-8
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
return converter.to_bytes(wValue);
#else
const char* value = getenv(name.c_str());
if (!value) return std::nullopt;
return std::string(value);
#endif
}
inline const nlohmann::json& GetJson() {
static const nlohmann::json jsonConfig = []() {
const char* jsonString = getenv("CAMOU_CONFIG");
if (!jsonString) return nlohmann::json{};
std::string jsonString;
int index = 1;
while (true) {
std::string envName = "CAMOU_CONFIG_" + std::to_string(index);
auto partialConfig = get_env_utf8(envName);
if (!partialConfig) break;
jsonString += *partialConfig;
index++;
}
if (jsonString.empty()) {
// Check for the original CAMOU_CONFIG as fallback
auto originalConfig = get_env_utf8("CAMOU_CONFIG");
if (originalConfig) jsonString = *originalConfig;
}
if (jsonString.empty()) return nlohmann::json{};
// Validate
if (!nlohmann::json::accept(jsonString)) {
printf_stderr("ERROR: Invalid JSON passed to CAMOU_CONFIG!\n");
return nlohmann::json{};
}
nlohmann::json result = nlohmann::json::parse(jsonString);
return result;
}();

View file

@ -1,7 +1,7 @@
package main
// List of fonts for each OS
var fontsByOS = map[string][]string{
var FontsByOS = map[string][]string{
"windows": {
"Arial", "Arial Black", "Bahnschrift", "Calibri", "Calibri Light", "Cambria", "Cambria Math", "Candara", "Candara Light", "Comic Sans MS", "Consolas", "Constantia", "Corbel", "Corbel Light", "Courier New", "Ebrima", "Franklin Gothic Medium", "Gabriola", "Gadugi", "Georgia", "HoloLens MDL2 Assets", "Impact", "Ink Free", "Javanese Text", "Leelawadee UI", "Leelawadee UI Semilight", "Lucida Console", "Lucida Sans Unicode", "MS Gothic", "MS PGothic", "MS UI Gothic", "MV Boli", "Malgun Gothic", "Malgun Gothic Semilight", "Marlett", "Microsoft Himalaya", "Microsoft JhengHei", "Microsoft JhengHei Light", "Microsoft JhengHei UI", "Microsoft JhengHei UI Light", "Microsoft New Tai Lue", "Microsoft PhagsPa", "Microsoft Sans Serif", "Microsoft Tai Le", "Microsoft YaHei", "Microsoft YaHei Light", "Microsoft YaHei UI", "Microsoft YaHei UI Light", "Microsoft Yi Baiti", "MingLiU-ExtB", "MingLiU_HKSCS-ExtB", "Mongolian Baiti", "Myanmar Text", "NSimSun", "Nirmala UI", "Nirmala UI Semilight", "PMingLiU-ExtB", "Palatino Linotype", "Segoe Fluent Icons", "Segoe MDL2 Assets", "Segoe Print", "Segoe Script", "Segoe UI", "Segoe UI Black", "Segoe UI Emoji", "Segoe UI Historic", "Segoe UI Light", "Segoe UI Semibold", "Segoe UI Semilight", "Segoe UI Symbol", "Segoe UI Variable", "SimSun", "SimSun-ExtB", "Sitka", "Sitka Text", "Sylfaen", "Symbol", "Tahoma", "Times New Roman", "Trebuchet MS", "Twemoji Mozilla", "Verdana", "Webdings", "Wingdings", "Yu Gothic", "Yu Gothic Light", "Yu Gothic Medium", "Yu Gothic UI", "Yu Gothic UI Light", "Yu Gothic UI Semibold", "Yu Gothic UI Semilight", "\u5b8b\u4f53", "\u5fae\u8edf\u6b63\u9ed1\u9ad4", "\u5fae\u8edf\u6b63\u9ed1\u9ad4 Light", "\u5fae\u8f6f\u96c5\u9ed1", "\u5fae\u8f6f\u96c5\u9ed1 Light", "\u65b0\u5b8b\u4f53", "\u65b0\u7d30\u660e\u9ad4-ExtB", "\u6e38\u30b4\u30b7\u30c3\u30af", "\u6e38\u30b4\u30b7\u30c3\u30af Light", "\u6e38\u30b4\u30b7\u30c3\u30af Medium", "\u7d30\u660e\u9ad4-ExtB", "\u7d30\u660e\u9ad4_HKSCS-ExtB", "\ub9d1\uc740 \uace0\ub515", "\ub9d1\uc740 \uace0\ub515 Semilight", "\uff2d\uff33 \u30b4\u30b7\u30c3\u30af", "\uff2d\uff33 \uff30\u30b4\u30b7\u30c3\u30af",
},

View file

@ -2,4 +2,6 @@ module launch
go 1.22.5
require github.com/mileusna/useragent v1.3.4 // indirect
require github.com/mileusna/useragent v1.3.4
require github.com/goccy/go-json v0.10.3 // indirect

View file

@ -1,2 +1,4 @@
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=

View file

@ -1,7 +1,6 @@
package main
import (
"encoding/json"
"fmt"
"io"
"os"
@ -9,7 +8,9 @@ import (
"path/filepath"
"runtime"
"strings"
"unicode/utf8"
json "github.com/goccy/go-json"
"github.com/mileusna/useragent"
)
@ -112,7 +113,7 @@ func updateFonts(configMap map[string]interface{}, userAgentOS string) {
existingFonts[f] = true
}
}
for _, font := range fontsByOS[userAgentOS] {
for _, font := range FontsByOS[userAgentOS] {
if !existingFonts[font] {
fonts = append(fonts, font)
}
@ -127,7 +128,35 @@ func setEnvironmentVariables(configMap map[string]interface{}, userAgentOS strin
os.Exit(1)
}
os.Setenv("CAMOU_CONFIG", string(updatedConfigData))
// 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 := filepath.Join("fontconfig", userAgentOS)
os.Setenv("FONTCONFIG_PATH", fontconfigPath)
@ -141,7 +170,7 @@ func getExecutableName() string {
case "macos":
return "./Camoufox.app"
case "windows":
return "camoufox.exe"
return "./camoufox.exe"
default:
// This should never be reached due to the check in normalizeOS
return ""