diff --git a/frontend/electron/services/steam-client.ts b/frontend/electron/services/steam-client.ts index 79487a7..fb401f5 100644 --- a/frontend/electron/services/steam-client.ts +++ b/frontend/electron/services/steam-client.ts @@ -55,20 +55,13 @@ class SteamClientService { return path.join(this.steamPath, 'config', 'config.vdf'); } - /** - * Safe Atomic Write: Writes to a temp file and renames it. - * This prevents file corruption if the app crashes during write. - */ private safeWriteVdf(filePath: string, data: any) { const tempPath = `${filePath}.tmp_${Date.now()}`; const dir = path.dirname(filePath); - try { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); const vdfContent = stringify(data); fs.writeFileSync(tempPath, vdfContent, 'utf-8'); - - // Atomic rename fs.renameSync(tempPath, filePath); } catch (e: any) { console.error(`[SteamClient] Atomic write failed for ${filePath}: ${e.message}`); @@ -80,11 +73,9 @@ class SteamClientService { public startWatching(callback: (accounts: LocalSteamAccount[]) => void) { this.onAccountsChanged = callback; const loginUsersPath = this.getLoginUsersPath(); - if (loginUsersPath && fs.existsSync(loginUsersPath)) { this.readLocalAccounts(); chokidar.watch(loginUsersPath, { persistent: true, ignoreInitial: true }).on('change', () => { - console.log(`[SteamClient] loginusers.vdf changed, re-scanning...`); this.readLocalAccounts(); }); } @@ -93,64 +84,41 @@ class SteamClientService { private readLocalAccounts() { const filePath = this.getLoginUsersPath(); if (!filePath || !fs.existsSync(filePath)) return; - try { const content = fs.readFileSync(filePath, 'utf-8'); - if (!content.trim()) return; // Empty file - + if (!content.trim()) return; const data = parse(content) as any; if (!data || !data.users) return; - const accounts: LocalSteamAccount[] = []; for (const [steamId64, userData] of Object.entries(data.users)) { const user = userData as any; if (!user || !user.AccountName) continue; - accounts.push({ - steamId: steamId64, - accountName: user.AccountName, + steamId: steamId64, accountName: user.AccountName, personaName: user.PersonaName || user.AccountName, timestamp: parseInt(user.Timestamp) || 0 }); } - if (this.onAccountsChanged) this.onAccountsChanged(accounts); - } catch (error) { - console.error('[SteamClient] Error parsing loginusers.vdf:', error); - } + } catch (error) { } } public extractAccountConfig(accountName: string): any | null { const configPath = this.getConfigVdfPath(); if (!configPath || !fs.existsSync(configPath)) return null; - try { const content = fs.readFileSync(configPath, 'utf-8'); const data = parse(content) as any; const accounts = data?.InstallConfigStore?.Software?.Valve?.Steam?.Accounts; return (accounts && accounts[accountName]) ? accounts[accountName] : null; - } catch (e) { - console.error('[SteamClient] Failed to extract config.vdf data'); - return null; - } + } catch (e) { return null; } } public injectAccountConfig(accountName: string, accountData: any) { const configPath = this.getConfigVdfPath(); if (!configPath) return; - let data: any = { - InstallConfigStore: { - Software: { - Valve: { - Steam: { - Accounts: {} - } - } - } - } - }; - + let data: any = { InstallConfigStore: { Software: { Valve: { Steam: { Accounts: {} } } } } }; if (fs.existsSync(configPath)) { try { const content = fs.readFileSync(configPath, 'utf-8'); @@ -159,14 +127,24 @@ class SteamClientService { } catch (e) { } } - // Ensure safe nesting - if (!data.InstallConfigStore) data.InstallConfigStore = {}; - if (!data.InstallConfigStore.Software) data.InstallConfigStore.Software = {}; - if (!data.InstallConfigStore.Software.Valve) data.InstallConfigStore.Software.Valve = {}; - if (!data.InstallConfigStore.Software.Valve.Steam) data.InstallConfigStore.Software.Valve.Steam = {}; - if (!data.InstallConfigStore.Software.Valve.Steam.Accounts) data.InstallConfigStore.Software.Valve.Steam.Accounts = {}; + const ensurePath = (obj: any, keys: string[]) => { + let curr = obj; + for (const key of keys) { + if (!curr[key] || typeof curr[key] !== 'object') curr[key] = {}; + curr = curr[key]; + } + return curr; + }; - data.InstallConfigStore.Software.Valve.Steam.Accounts[accountName] = accountData; + const steamAccounts = ensurePath(data, ['InstallConfigStore', 'Software', 'Valve', 'Steam', 'Accounts']); + + // FAILPROOF: Force crucial flags that Steam uses to decide session validity + steamAccounts[accountName] = { + ...accountData, + RememberPassword: "1", + AllowAutoLogin: "1", + Timestamp: Math.floor(Date.now() / 1000).toString() + }; try { this.safeWriteVdf(configPath, data); @@ -226,6 +204,7 @@ class SteamClientService { } catch (e) { } } + // Injection of the actual authentication blob if (accountConfig && accountName) { this.injectAccountConfig(accountName, accountConfig); } @@ -239,13 +218,7 @@ class SteamClientService { for (const regPath of regLocations) { if (!fs.existsSync(path.dirname(regPath))) continue; - - let regData: any = { Registry: { HKCU: { Software: { Valve: { Steam: { - AutoLoginUser: "", - RememberPassword: "1", - AlreadyLoggedIn: "1" - } } } } } }; - + let regData: any = { Registry: { HKCU: { Software: { Valve: { Steam: { AutoLoginUser: "", RememberPassword: "1", AlreadyLoggedIn: "1" } } } } } }; if (fs.existsSync(regPath)) { try { const content = fs.readFileSync(regPath, 'utf-8'); @@ -254,13 +227,9 @@ class SteamClientService { } catch (e) { } } - // Deep merge helper const ensurePath = (obj: any, keys: string[]) => { let curr = obj; - for (const key of keys) { - if (!curr[key] || typeof curr[key] !== 'object') curr[key] = {}; - curr = curr[key]; - } + for (const key of keys) { if (!curr[key] || typeof curr[key] !== 'object') curr[key] = {}; curr = curr[key]; } return curr; }; @@ -269,10 +238,7 @@ class SteamClientService { steamKey.RememberPassword = "1"; steamKey.AlreadyLoggedIn = "1"; steamKey.WantsOfflineMode = "0"; - - try { - this.safeWriteVdf(regPath, regData); - } catch (e) { } + try { this.safeWriteVdf(regPath, regData); } catch (e) { } } }