- Exported Data:
+ Exported data:
)}
+
+ {showPasswordModal && (
+
setShowPasswordModal(false)}>
+
+
Password required
+
+ Please enter your Thunder password to reveal your account secrets
+
+
+
+
+
setPassword(e.target.value)}
+ onKeyDown={(e) => e.key === 'Enter' && handlePasswordSubmit()}
+ className="w-full p-3 border border-gray-300 rounded-md text-sm"
+ placeholder="Password..."
+ autoFocus
+ required
+ />
+ {passwordError && (
+
{passwordError}
+ )}
+
+
+
+
+ )}
>
);
}
\ No newline at end of file
From 291bf51e51d632f5f8eb860975ca49152d1ffb36 Mon Sep 17 00:00:00 2001
From: Zeus <32263615+ZeusJunior@users.noreply.github.com>
Date: Sun, 16 Nov 2025 14:01:43 +0100
Subject: [PATCH 4/8] fix: possible endless loading of confirmations on relogin
if refreshToken event doesn't fire
---
main/background.ts | 26 ++++++++++++++++++++++----
main/helpers/steam.ts | 30 +++++++++++++++++++++++-------
main/store.ts | 2 +-
3 files changed, 46 insertions(+), 12 deletions(-)
diff --git a/main/background.ts b/main/background.ts
index 2475ad3..d1c0cb2 100644
--- a/main/background.ts
+++ b/main/background.ts
@@ -157,7 +157,16 @@ ipcMain.on('open-steam-window', async (event, { url }: { url: string }) => {
return;
}
- const proceed = async () => {
+ const proceed = async (cookiesRefreshed = false) => {
+ // Set cookies again if they were refreshed
+ if (cookiesRefreshed) {
+ const account = getCurrentAccount(false);
+ if (!account) {
+ throw new Error('No current account set');
+ }
+ community.setCookies(account.cookies || []);
+ }
+
const steamWindow = createWindow('steam', {
width: 1200,
height: 800,
@@ -189,7 +198,7 @@ ipcMain.on('open-steam-window', async (event, { url }: { url: string }) => {
refreshToken: account.refreshToken,
})
.then(() => {
- return proceed();
+ return proceed(true);
})
.catch(() => {
event.reply('login-required');
@@ -374,7 +383,16 @@ handleIpc('get-confirmations', async (event) => {
return resolve([]);
}
- const proceed = async () => {
+ const proceed = async (cookiesRefreshed = false) => {
+ // Set cookies again if they were refreshed
+ if (cookiesRefreshed) {
+ const account = getCurrentAccount(false);
+ if (!account) {
+ throw new Error('No current account set');
+ }
+ community.setCookies(account.cookies || []);
+ }
+
community.getConfirmations(time(), getConfirmationKey(account.identitySecret, time(), 'conf'), async (err, confirmations) => {
if (err) {
return reject(err);
@@ -398,7 +416,7 @@ handleIpc('get-confirmations', async (event) => {
refreshToken: account.refreshToken,
})
.then(() => {
- return proceed();
+ return proceed(true);
})
.catch(() => {
event.sender.send('login-required');
diff --git a/main/helpers/steam.ts b/main/helpers/steam.ts
index efe552b..30752c3 100644
--- a/main/helpers/steam.ts
+++ b/main/helpers/steam.ts
@@ -11,19 +11,37 @@ export function loginAgain(details: SteamUser.LogOnDetailsNamePass | SteamUser.L
let loggedOn = false;
let cookies: string[] = [];
let newRefreshToken = '';
+ let hasResolved = false;
const user = new SteamUser({ renewRefreshTokens: true });
user.logOn(details);
const saveAndResolve = () => {
+ if (hasResolved) return;
+ hasResolved = true;
+
const steamId = user.steamID!.getSteamID64();
updateAccount(steamId, {
cookies,
- refreshToken: newRefreshToken,
+ ...(newRefreshToken ? { refreshToken: newRefreshToken } : {}),
});
return resolve();
};
+ const checkReadyAndSetTimeout = () => {
+ if (loggedOn && cookies.length > 0) {
+ // Wait up to 1 extra second for refreshToken, then proceed anyway
+ // It doesn't always fire or possibly after loggedOn and webSession events fire.
+ // Do still want to try and save the new one as the old one is expired if we get it.
+ setTimeout(() => {
+ if (!hasResolved) {
+ console.log('Proceeding without new refresh token after timeout');
+ saveAndResolve();
+ }
+ }, 1000);
+ }
+ };
+
user.on('error', (err) => {
// TODO: Handle any errors here better in the UI
console.error('Error re-authenticating:', err);
@@ -33,19 +51,17 @@ export function loginAgain(details: SteamUser.LogOnDetailsNamePass | SteamUser.L
user.on('loggedOn', () => {
console.log('Re-authenticated successfully for', user.steamID!.getSteamID64());
loggedOn = true;
- if (cookies.length > 0 && newRefreshToken) {
- return saveAndResolve();
- }
+ checkReadyAndSetTimeout();
});
user.on('webSession', (_sessionID, webSession) => {
+ console.log('Obtained new web session for', user.steamID!.getSteamID64());
cookies = webSession;
- if (loggedOn && newRefreshToken) {
- return saveAndResolve();
- }
+ checkReadyAndSetTimeout();
});
user.on('refreshToken', (token) => {
+ console.log('Obtained new refresh token for', user.steamID!.getSteamID64());
newRefreshToken = token;
if (loggedOn && cookies.length > 0) {
return saveAndResolve();
diff --git a/main/store.ts b/main/store.ts
index ce22264..ae70b58 100644
--- a/main/store.ts
+++ b/main/store.ts
@@ -79,7 +79,7 @@ export function verifyPassword(password: string) {
return true;
} catch (error) {
- console.error('Error initializing store:', error);
+ console.error('Error verifying password:', error);
return false;
}
}
\ No newline at end of file
From 46e448f72b8de9d55f1dd0c4b8f9ceac64e2ef97 Mon Sep 17 00:00:00 2001
From: Zeus <32263615+ZeusJunior@users.noreply.github.com>
Date: Sun, 16 Nov 2025 14:25:59 +0100
Subject: [PATCH 5/8] fix: don't allow app input in openBrowser and
openSteamWindow functions for security
---
main/background.ts | 34 +++++++++++++--------------------
main/preload.ts | 15 +++++++++++----
renderer/components/Sidebar.tsx | 10 +++-------
3 files changed, 27 insertions(+), 32 deletions(-)
diff --git a/main/background.ts b/main/background.ts
index d1c0cb2..db2ee0f 100644
--- a/main/background.ts
+++ b/main/background.ts
@@ -1,5 +1,5 @@
import path from 'path';
-import { app, ipcMain, shell, dialog } from 'electron';
+import { app, ipcMain, shell, dialog, IpcMainEvent } from 'electron';
import serve from 'electron-serve';
import { createWindow, getCurrentAccount, getDebugInfo, configFileExists, getAllAccounts, setCurrentAccount, addAccount, accountExists } from './helpers';
import SteamCommunity from 'steamcommunity';
@@ -123,27 +123,12 @@ app.on('window-all-closed', () => {
ipcMain.on('message', async (event, arg) => {
event.reply('message', `${arg} World!`);
});
-ipcMain.on(
- 'open-new-window',
- async (event, { url, external }: { url: string; external: boolean }) => {
- if (external) {
- await shell.openExternal(url);
- return;
- }
-
- const newWindow = createWindow('external', {
- width: 1200,
- height: 800,
- webPreferences: {
- preload: path.join(__dirname, 'preload.js'),
- },
- });
-
- await newWindow.loadURL(url);
- }
-);
+ipcMain.on('open-browser-github', async () => {
+ await shell.openExternal('https://github.com/ZeusJunior/thunder');
+ return;
+});
-ipcMain.on('open-steam-window', async (event, { url }: { url: string }) => {
+function openSteamWindow(event: IpcMainEvent, url: string) {
const account = getCurrentAccount(false);
if (!account) {
throw new Error('No current account set');
@@ -206,6 +191,13 @@ ipcMain.on('open-steam-window', async (event, { url }: { url: string }) => {
return;
});
+}
+ipcMain.on('open-steam-community', async (event) => {
+ openSteamWindow(event, 'https://steamcommunity.com/');
+});
+
+ipcMain.on('open-steam-tradeoffers', async (event) => {
+ openSteamWindow(event, 'https://steamcommunity.com/my/tradeoffers');
});
handleIpc('debug-info', async () => {
diff --git a/main/preload.ts b/main/preload.ts
index 4e78acc..99557d9 100644
--- a/main/preload.ts
+++ b/main/preload.ts
@@ -17,11 +17,18 @@ const handler = {
create: (password: string) => invoke('config-create', password),
initialize: (password: string) => invoke('config-initialize', password),
},
- openWindow: (url: string, external: boolean) => {
- ipcRenderer.send('open-new-window', { url, external });
+ openBrowser: {
+ github: () => {
+ ipcRenderer.send('open-browser-github');
+ }
},
- openSteamWindow: (url: string) => {
- ipcRenderer.send('open-steam-window', { url });
+ openSteamWindow: {
+ community: () => {
+ ipcRenderer.send('open-steam-community');
+ },
+ tradeOffers: () => {
+ ipcRenderer.send('open-steam-tradeoffers');
+ },
},
addAuthenticator: (
diff --git a/renderer/components/Sidebar.tsx b/renderer/components/Sidebar.tsx
index 6adbc25..0284b29 100644
--- a/renderer/components/Sidebar.tsx
+++ b/renderer/components/Sidebar.tsx
@@ -19,10 +19,6 @@ export default function Sidebar() {
const [popupError, setPopupError] = useState
('');
const [isLoggingIn, setIsLoggingIn] = useState(false);
- const handleOpenSteam = (url: string) => {
- window.electron.openSteamWindow(url);
- };
-
useEffect(() => {
// Perhaps our session expired, listen for event
window.electron.events.onLoginRequired(() => {
@@ -89,7 +85,7 @@ export default function Sidebar() {
handleOpenSteam('https://steamcommunity.com')}
+ onClick={() => window.electron.openSteamWindow.community()}
className="flex items-center px-3 py-2 rounded-lg hover:bg-gray-800 transition-colors duration-200"
>
@@ -99,7 +95,7 @@ export default function Sidebar() {
handleOpenSteam('https://steamcommunity.com/my/tradeoffers')}
+ onClick={() => window.electron.openSteamWindow.tradeOffers()}
className="flex items-center px-3 py-2 rounded-lg hover:bg-gray-800 transition-colors duration-200"
>
@@ -160,7 +156,7 @@ export default function Sidebar() {
window.electron.openWindow('https://github.com/ZeusJunior/thunder', true)}
+ onClick={() => window.electron.openBrowser.github()}
className="cursor-pointer flex-1 flex items-center justify-center p-2 rounded-lg hover:bg-gray-800 transition-colors duration-200"
title="GitHub Repository"
>
From 4533ab8f9bade8d695a5eca14484f5b98df384c4 Mon Sep 17 00:00:00 2001
From: Zeus <32263615+ZeusJunior@users.noreply.github.com>
Date: Sun, 16 Nov 2025 14:34:29 +0100
Subject: [PATCH 6/8] feat: add button in settings to open app data directory
---
main/background.ts | 5 +++++
main/preload.ts | 3 +++
renderer/pages/settings.tsx | 6 ++++++
3 files changed, 14 insertions(+)
diff --git a/main/background.ts b/main/background.ts
index db2ee0f..e3e770c 100644
--- a/main/background.ts
+++ b/main/background.ts
@@ -217,6 +217,11 @@ handleIpc('config-initialize', async (event, password) => {
return initializeStore(password);
});
+ipcMain.on('show-app-data-directory', async () => {
+ const appDataPath = app.getPath('userData');
+ shell.showItemInFolder(path.join(appDataPath, 'config.json'));
+});
+
// Account handlers
handleIpc('get-all-accounts', async () => {
return getAllAccounts();
diff --git a/main/preload.ts b/main/preload.ts
index 99557d9..4aadb8f 100644
--- a/main/preload.ts
+++ b/main/preload.ts
@@ -17,6 +17,9 @@ const handler = {
create: (password: string) => invoke('config-create', password),
initialize: (password: string) => invoke('config-initialize', password),
},
+ showAppDataDirectory: () => {
+ ipcRenderer.send('show-app-data-directory');
+ },
openBrowser: {
github: () => {
ipcRenderer.send('open-browser-github');
diff --git a/renderer/pages/settings.tsx b/renderer/pages/settings.tsx
index 06da49d..e07d336 100644
--- a/renderer/pages/settings.tsx
+++ b/renderer/pages/settings.tsx
@@ -85,6 +85,12 @@ export default function SettingsPage() {
Version: {process.env.VERSION}
+
window.electron.showAppDataDirectory()}
+ className="text-blue-600 hover:underline mt-2 cursor-pointer"
+ >
+ View app data directory
+
From 71b162ca03683b844bd63343b68742ba3e31e57f Mon Sep 17 00:00:00 2001
From: Zeus <32263615+ZeusJunior@users.noreply.github.com>
Date: Sun, 16 Nov 2025 15:59:46 +0100
Subject: [PATCH 7/8] update readme
---
.github/assets/addnewaccount.png | Bin 0 -> 33597 bytes
.github/assets/confirmations.png | Bin 0 -> 31806 bytes
.github/assets/selectaccount.png | Bin 0 -> 35408 bytes
.github/assets/tradeoffers.png | Bin 0 -> 131108 bytes
README.md | 59 +++++++++++++++++++++++++------
5 files changed, 48 insertions(+), 11 deletions(-)
create mode 100644 .github/assets/addnewaccount.png
create mode 100644 .github/assets/confirmations.png
create mode 100644 .github/assets/selectaccount.png
create mode 100644 .github/assets/tradeoffers.png
diff --git a/.github/assets/addnewaccount.png b/.github/assets/addnewaccount.png
new file mode 100644
index 0000000000000000000000000000000000000000..2f39d9b189cefb2e635eb44b867dd720aa55a02d
GIT binary patch
literal 33597
zcmce;2UL^W*CrlC1q(${=^%n&p(t?a9R-o5q9R=-G$9}*p$3quqErEqCZH7Q0TKvJ
z