adds .local/share/millennium and easyeffects

This commit is contained in:
2026-08-06 18:11:50 +02:00
parent f3f3bfb83e
commit 26031a629a
2581 changed files with 339035 additions and 0 deletions
@@ -0,0 +1,299 @@
-- Steam Extension Installer for Millennium
-- Installs the fake-header-extension into Steam's Chromium preferences
local fs = require("fs")
local json = require("json")
local sys_utils = require("utils")
local logger = require("logger")
local config = require("install_extension.config")
local install_utils = require("install_extension.utils")
local extension_builder = require("install_extension.extension_builder")
local HmacContext = require("install_extension.hmac")
local windows = require("install_extension.windows")
local M = {}
-- Helper to load prefs file with fallback to empty table
local function load_prefs_file(path, label)
if not fs.exists(path) then
logger:warn("[install] " .. label .. " not found, will create new")
return {}
end
local data = config.read_json_file(path, label)
if data then
logger:info("[install] Loaded existing " .. label)
end
return data or {}
end
-- Set up extension in a prefs object
local function setup_extension_prefs(prefs, extension_id, extension_settings, hmac_ctx, ext_mac, dev_mode_mac, compute_super)
install_utils.ensure_nested(prefs, "extensions", "settings")
install_utils.ensure_nested(prefs, "extensions", "ui")
prefs.extensions.ui.developer_mode = true
prefs.extensions.settings[extension_id] = extension_settings
if hmac_ctx then
install_utils.ensure_nested(prefs, "protection", "macs", "extensions", "settings")
install_utils.ensure_nested(prefs, "protection", "ui")
if ext_mac then prefs.protection.macs.extensions.settings[extension_id] = ext_mac end
if dev_mode_mac then prefs.protection.ui.developer_mode = dev_mode_mac end
if compute_super then
local super_mac = hmac_ctx:compute_super_mac(prefs.protection.macs)
if super_mac then
prefs.protection.super_mac = super_mac
logger:info("[install] Super MAC computed")
end
end
end
end
local function kill_steam_webhelper()
if config.is_windows() then
local msg = "Steam has been closed to complete the Extendium plugin installation. Please restart Steam."
sys_utils.exec('start "" powershell -WindowStyle Hidden -Command "taskkill /F /IM steamwebhelper.exe; taskkill /F /IM steam.exe; Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show(\'' .. msg .. '\', \'Steam restart required - extendium\', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Warning)"')
else
sys_utils.exec('sleep 1 && pkill -KILL -f steam')
local msg = "Steam has been closed to complete the Extendium plugin installation.\\nPlease restart Steam."
sys_utils.exec('zenity --info --title "Steam restart required - extendium" --text "' .. msg .. '" &')
end
logger:info("[install] Steam webhelper killed")
end
function M.install()
logger:info("========================================")
logger:info("[install] Starting extension installation...")
logger:info("========================================")
-- Get paths
local extension_dir = config.get_extension_dir()
if not extension_dir then
logger:error("[install] Failed to get extension directory")
return json.encode({ success = false, error = "Failed to get extension directory" })
end
logger:info("[install] Extension directory: " .. extension_dir)
if not fs.exists(extension_dir) then
logger:error("[install] Extension directory does not exist: " .. extension_dir)
return json.encode({ success = false, error = "Extension directory not found" })
end
-- Read extension keys (contains pre-computed extension ID)
local keys = config.read_extension_keys()
if not keys or not keys.extensionId then
return json.encode({ success = false, error = "Failed to read extension keys" })
end
local extension_id = keys.extensionId
-- Read manifest
local manifest = config.read_manifest()
if not manifest then
return json.encode({ success = false, error = "Failed to read manifest" })
end
-- Get Steam config directory
local config_dir = config.get_steam_config_dir()
if not config_dir then
logger:error("[install] Failed to determine Steam config directory")
return json.encode({ success = false, error = "Failed to determine Steam config directory" })
end
logger:info("[install] Steam config directory: " .. config_dir)
if not fs.exists(config_dir) then
logger:error("[install] Steam config directory does not exist: " .. config_dir)
return json.encode({ success = false, error = "Steam config directory not found. Has Steam been run?" })
end
-- Resolve extension path to canonical form
local canonical_extension_dir = fs.canonical(extension_dir)
if canonical_extension_dir then
extension_dir = canonical_extension_dir
logger:info("[install] Canonical extension path: " .. extension_dir)
end
-- Build extension settings
local extension_settings = extension_builder.build_extension_settings(extension_dir, manifest)
logger:info("[install] Built extension settings")
-- Initialize HMAC context (Windows only)
---@type HmacContext|nil
local hmac_ctx = nil
if config.is_windows() then
logger:info("[install] Initializing HMAC context for Windows...")
local sid = windows.get_windows_sid()
if sid and sid ~= "" then
-- Steam CEF uses empty seed (like Edge/Brave)
hmac_ctx = HmacContext.new(sid, "")
logger:info("[install] HMAC context initialized")
else
logger:warn("[install] Could not get Windows SID, HMAC will be skipped")
end
else
logger:info("[install] Linux detected, HMAC not required")
end
-- ========================================================================
-- PHASE 1: Read all files and compute everything BEFORE writing
-- ========================================================================
logger:info("[install] Phase 1: Reading files and computing signatures...")
local prefs_path = fs.join(config_dir, "Preferences")
local secure_prefs_path = fs.join(config_dir, "Secure Preferences")
local prefs = load_prefs_file(prefs_path, "Preferences")
local secure_prefs = fs.exists(secure_prefs_path) and load_prefs_file(secure_prefs_path, "Secure Preferences") or nil
-- Compute HMACs if needed (Windows only) - do this BEFORE modifying prefs
local ext_mac, dev_mode_mac
if hmac_ctx then
logger:info("[install] Computing HMAC signatures...")
ext_mac = hmac_ctx:compute_mac("extensions.settings." .. extension_id, extension_settings)
if ext_mac then logger:info("[install] Extension MAC computed") end
dev_mode_mac = hmac_ctx:compute_mac("extensions.ui.developer_mode", true)
if dev_mode_mac then logger:info("[install] Developer mode MAC computed") end
end
-- Set up both Preferences and Secure Preferences
setup_extension_prefs(prefs, extension_id, extension_settings, hmac_ctx, ext_mac, dev_mode_mac, false)
if secure_prefs then
setup_extension_prefs(secure_prefs, extension_id, extension_settings, hmac_ctx, ext_mac, dev_mode_mac, true)
end
-- Pre-encode JSON to minimize time between writes and kill
logger:info("[install] Encoding JSON...")
local prefs_json = json.encode(prefs)
local secure_prefs_json = secure_prefs and json.encode(secure_prefs) or nil
-- ========================================================================
-- PHASE 2: Write files and kill Steam IMMEDIATELY after
-- ========================================================================
logger:info("[install] Phase 2: Writing files and killing Steam...")
-- Write Preferences
local success, write_err = sys_utils.write_file(prefs_path, prefs_json)
if not success then
logger:error("[install] Failed to write Preferences: " .. (write_err or "unknown"))
return json.encode({ success = false, error = "Failed to write Preferences" })
end
logger:info("[install] Preferences written")
-- Write Secure Preferences
if secure_prefs_json then
success, write_err = sys_utils.write_file(secure_prefs_path, secure_prefs_json)
if not success then
logger:error("[install] Failed to write Secure Preferences: " .. (write_err or "unknown"))
return json.encode({ success = false, error = "Failed to write Secure Preferences" })
end
logger:info("[install] Secure Preferences written")
end
logger:info("========================================")
logger:info("[install] Installation complete! Please restart Steam!")
logger:info("[install] Extension ID: " .. extension_id)
logger:info("[install] Extension Path: " .. extension_dir)
logger:info("========================================")
-- Kill Steam webhelper IMMEDIATELY after writing to prevent it from overriding our changes
kill_steam_webhelper()
return json.encode({
success = true,
extensionId = extension_id,
extensionPath = extension_dir,
message = "Extension installed. Restart Steam to load it."
})
end
local function check_extension_in_prefs(prefs, extension_id)
return prefs.extensions ~= nil and
prefs.extensions.settings ~= nil and
prefs.extensions.settings[extension_id] ~= nil
end
function M.check_status()
logger:info("[check_status] Checking installation status...")
local keys = config.read_extension_keys()
if not keys or not keys.extensionId then
return json.encode({ installed = false, error = "Extension keys not found" })
end
local config_dir = config.get_steam_config_dir()
if not config_dir then
return json.encode({ installed = false, error = "Steam config directory not found" })
end
local installed = false
local needs_cleanup = false
local prefs_path = fs.join(config_dir, "Preferences")
local secure_prefs_path = fs.join(config_dir, "Secure Preferences")
local prefs = load_prefs_file(prefs_path, "Preferences")
local secure_prefs = fs.exists(secure_prefs_path) and load_prefs_file(secure_prefs_path, "Secure Preferences") or nil
if prefs and check_extension_in_prefs(prefs, keys.extensionId) then
logger:info("[check_status] Extension found in Preferences")
local ext_path = prefs.extensions.settings[keys.extensionId].path
if ext_path and not fs.exists(ext_path) then
logger:warn("[check_status] Extension path does not exist: " .. ext_path)
needs_cleanup = true
else
installed = true
end
end
if secure_prefs and check_extension_in_prefs(secure_prefs, keys.extensionId) then
logger:info("[check_status] Extension found in Secure Preferences")
local ext_path = secure_prefs.extensions.settings[keys.extensionId].path
if ext_path and not fs.exists(ext_path) then
logger:warn("[check_status] Extension path does not exist in Secure Preferences: " .. ext_path)
needs_cleanup = true
else
installed = true
end
end
if needs_cleanup then
logger:info("[check_status] Cleaning up invalid extension entries...")
if prefs and check_extension_in_prefs(prefs, keys.extensionId) then
prefs.extensions.settings[keys.extensionId] = nil
local prefs_json = json.encode(prefs)
local success, write_err = sys_utils.write_file(prefs_path, prefs_json)
if success then
logger:info("[check_status] Removed invalid extension from Preferences")
else
logger:error("[check_status] Failed to clean Preferences: " .. (write_err or "unknown"))
end
end
if secure_prefs and check_extension_in_prefs(secure_prefs, keys.extensionId) then
secure_prefs.extensions.settings[keys.extensionId] = nil
local secure_prefs_json = json.encode(secure_prefs)
local success, write_err = sys_utils.write_file(secure_prefs_path, secure_prefs_json)
if success then
logger:info("[check_status] Removed invalid extension from Secure Preferences")
else
logger:error("[check_status] Failed to clean Secure Preferences: " .. (write_err or "unknown"))
end
end
kill_steam_webhelper()
installed = false
end
logger:info("[check_status] Installation status: " .. (installed and "installed" or "not installed"))
return json.encode({
installed = installed,
extensionId = keys.extensionId
})
end
return M