diff --git a/.github/workflows/electron.yml b/.github/workflows/electron.yml index 4fe67f29..5a6f61db 100644 --- a/.github/workflows/electron.yml +++ b/.github/workflows/electron.yml @@ -78,62 +78,60 @@ jobs: - name: Upload Windows x64 NSIS Installer uses: actions/upload-artifact@v4 - if: hashFiles('release/*_x64_*_nsis.exe') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_windows_x64_nsis.exe') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_windows_x64_nsis - path: release/*_x64_*_nsis.exe + path: release/termix_windows_x64_nsis.exe retention-days: 30 - name: Upload Windows ia32 NSIS Installer uses: actions/upload-artifact@v4 - if: hashFiles('release/*_ia32_*_nsis.exe') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_windows_ia32_nsis.exe') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_windows_ia32_nsis - path: release/*_ia32_*_nsis.exe + path: release/termix_windows_ia32_nsis.exe retention-days: 30 - name: Upload Windows x64 MSI Installer uses: actions/upload-artifact@v4 - if: hashFiles('release/*_x64_*_msi.msi') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_windows_x64_msi.msi') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_windows_x64_msi - path: release/*_x64_*_msi.msi + path: release/termix_windows_x64_msi.msi retention-days: 30 - name: Upload Windows ia32 MSI Installer uses: actions/upload-artifact@v4 - if: hashFiles('release/*_ia32_*_msi.msi') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_windows_ia32_msi.msi') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_windows_ia32_msi - path: release/*_ia32_*_msi.msi + path: release/termix_windows_ia32_msi.msi retention-days: 30 - name: Create Windows x64 Portable zip if: hashFiles('release/win-unpacked/*') != '' run: | - $VERSION = "${{ steps.package-version.outputs.version }}" - Compress-Archive -Path "release\win-unpacked\*" -DestinationPath "termix_windows_x64_${VERSION}_portable.zip" + Compress-Archive -Path "release\win-unpacked\*" -DestinationPath "termix_windows_x64_portable.zip" - name: Create Windows ia32 Portable zip if: hashFiles('release/win-ia32-unpacked/*') != '' run: | - $VERSION = "${{ steps.package-version.outputs.version }}" - Compress-Archive -Path "release\win-ia32-unpacked\*" -DestinationPath "termix_windows_ia32_${VERSION}_portable.zip" + Compress-Archive -Path "release\win-ia32-unpacked\*" -DestinationPath "termix_windows_ia32_portable.zip" - name: Upload Windows x64 Portable uses: actions/upload-artifact@v4 - if: hashFiles('termix_windows_x64_*_portable.zip') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('termix_windows_x64_portable.zip') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_windows_x64_portable - path: termix_windows_x64_*_portable.zip + path: termix_windows_x64_portable.zip retention-days: 30 - name: Upload Windows ia32 Portable uses: actions/upload-artifact@v4 - if: hashFiles('termix_windows_ia32_*_portable.zip') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('termix_windows_ia32_portable.zip') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_windows_ia32_portable - path: termix_windows_ia32_*_portable.zip + path: termix_windows_ia32_portable.zip retention-days: 30 build-linux: @@ -181,24 +179,16 @@ jobs: VERSION=$(node -p "require('./package.json').version") cd release - if [ -f "termix_linux_x86_64_${VERSION}_appimage.AppImage" ]; then - mv "termix_linux_x86_64_${VERSION}_appimage.AppImage" "termix_linux_x64_${VERSION}_appimage.AppImage" - fi - - if [ -f "termix_linux_amd64_${VERSION}_deb.deb" ]; then - mv "termix_linux_amd64_${VERSION}_deb.deb" "termix_linux_x64_${VERSION}_deb.deb" - fi - if [ -f "termix-${VERSION}.tar.gz" ]; then - mv "termix-${VERSION}.tar.gz" "termix_linux_x64_${VERSION}_portable.tar.gz" + mv "termix-${VERSION}.tar.gz" "termix_linux_x64_portable.tar.gz" fi if [ -f "termix-${VERSION}-arm64.tar.gz" ]; then - mv "termix-${VERSION}-arm64.tar.gz" "termix_linux_arm64_${VERSION}_portable.tar.gz" + mv "termix-${VERSION}-arm64.tar.gz" "termix_linux_arm64_portable.tar.gz" fi if [ -f "termix-${VERSION}-armv7l.tar.gz" ]; then - mv "termix-${VERSION}-armv7l.tar.gz" "termix_linux_armv7l_${VERSION}_portable.tar.gz" + mv "termix-${VERSION}-armv7l.tar.gz" "termix_linux_armv7l_portable.tar.gz" fi cd .. @@ -209,66 +199,66 @@ jobs: - name: Upload Linux x64 AppImage uses: actions/upload-artifact@v4 - if: hashFiles('release/*_x64_*_appimage.AppImage') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_linux_x64_appimage.AppImage') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_linux_x64_appimage - path: release/*_x64_*_appimage.AppImage + path: release/termix_linux_x64_appimage.AppImage retention-days: 30 - name: Upload Linux arm64 AppImage uses: actions/upload-artifact@v4 - if: hashFiles('release/*_arm64_*_appimage.AppImage') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_linux_arm64_appimage.AppImage') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_linux_arm64_appimage - path: release/*_arm64_*_appimage.AppImage + path: release/termix_linux_arm64_appimage.AppImage retention-days: 30 - name: Upload Linux x64 DEB uses: actions/upload-artifact@v4 - if: hashFiles('release/*_x64_*_deb.deb') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_linux_x64_deb.deb') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_linux_x64_deb - path: release/*_x64_*_deb.deb + path: release/termix_linux_x64_deb.deb retention-days: 30 - name: Upload Linux arm64 DEB uses: actions/upload-artifact@v4 - if: hashFiles('release/*_arm64_*_deb.deb') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_linux_arm64_deb.deb') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_linux_arm64_deb - path: release/*_arm64_*_deb.deb + path: release/termix_linux_arm64_deb.deb retention-days: 30 - name: Upload Linux armv7l DEB uses: actions/upload-artifact@v4 - if: hashFiles('release/*_armv7l_*_deb.deb') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_linux_armv7l_deb.deb') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_linux_armv7l_deb - path: release/*_armv7l_*_deb.deb + path: release/termix_linux_armv7l_deb.deb retention-days: 30 - name: Upload Linux x64 tar.gz uses: actions/upload-artifact@v4 - if: hashFiles('release/*_x64_*_portable.tar.gz') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_linux_x64_portable.tar.gz') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_linux_x64_portable - path: release/*_x64_*_portable.tar.gz + path: release/termix_linux_x64_portable.tar.gz retention-days: 30 - name: Upload Linux arm64 tar.gz uses: actions/upload-artifact@v4 - if: hashFiles('release/*_arm64_*_portable.tar.gz') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_linux_arm64_portable.tar.gz') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_linux_arm64_portable - path: release/*_arm64_*_portable.tar.gz + path: release/termix_linux_arm64_portable.tar.gz retention-days: 30 - name: Upload Linux armv7l tar.gz uses: actions/upload-artifact@v4 - if: hashFiles('release/*_armv7l_*_portable.tar.gz') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_linux_armv7l_portable.tar.gz') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_linux_armv7l_portable - path: release/*_armv7l_*_portable.tar.gz + path: release/termix_linux_armv7l_portable.tar.gz retention-days: 30 build-macos: @@ -420,36 +410,36 @@ jobs: ls -R release/ || echo "Release directory not found" - name: Upload macOS MAS PKG - if: steps.check_certs.outputs.has_certs == 'true' && hashFiles('release/*_*_*_mas.pkg') != '' && (github.event.inputs.artifact_destination == 'file' || github.event.inputs.artifact_destination == 'release' || github.event.inputs.artifact_destination == 'submit') + if: steps.check_certs.outputs.has_certs == 'true' && hashFiles('release/termix_macos_universal_mas.pkg') != '' && (github.event.inputs.artifact_destination == 'file' || github.event.inputs.artifact_destination == 'release' || github.event.inputs.artifact_destination == 'submit') uses: actions/upload-artifact@v4 with: name: termix_macos_mas - path: release/*_*_*_mas.pkg + path: release/termix_macos_universal_mas.pkg retention-days: 30 if-no-files-found: warn - name: Upload macOS Universal DMG uses: actions/upload-artifact@v4 - if: hashFiles('release/*_universal_*_dmg.dmg') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_macos_universal_dmg.dmg') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_macos_universal_dmg - path: release/*_universal_*_dmg.dmg + path: release/termix_macos_universal_dmg.dmg retention-days: 30 - name: Upload macOS x64 DMG uses: actions/upload-artifact@v4 - if: hashFiles('release/*_x64_*_dmg.dmg') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_macos_x64_dmg.dmg') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_macos_x64_dmg - path: release/*_x64_*_dmg.dmg + path: release/termix_macos_x64_dmg.dmg retention-days: 30 - name: Upload macOS arm64 DMG uses: actions/upload-artifact@v4 - if: hashFiles('release/*_arm64_*_dmg.dmg') != '' && github.event.inputs.artifact_destination != 'none' + if: hashFiles('release/termix_macos_arm64_dmg.dmg') != '' && github.event.inputs.artifact_destination != 'none' with: name: termix_macos_arm64_dmg - path: release/*_arm64_*_dmg.dmg + path: release/termix_macos_arm64_dmg.dmg retention-days: 30 - name: Check for App Store Connect API credentials diff --git a/electron-builder.json b/electron-builder.json index cf736e74..fc7d05dd 100644 --- a/electron-builder.json +++ b/electron-builder.json @@ -40,14 +40,14 @@ "nsis": { "oneClick": false, "allowToChangeInstallationDirectory": true, - "artifactName": "termix_windows_${arch}_${version}_nsis.${ext}", + "artifactName": "termix_windows_${arch}_nsis.${ext}", "createDesktopShortcut": true, "createStartMenuShortcut": true, "shortcutName": "Termix", "uninstallDisplayName": "Termix" }, "msi": { - "artifactName": "termix_windows_${arch}_${version}_msi.${ext}" + "artifactName": "termix_windows_${arch}_msi.${ext}" }, "linux": { "target": [ @@ -78,10 +78,10 @@ } }, "appImage": { - "artifactName": "termix_linux_${arch}_${version}_appimage.${ext}" + "artifactName": "termix_linux_${arch}_appimage.${ext}" }, "deb": { - "artifactName": "termix_linux_${arch}_${version}_deb.${ext}" + "artifactName": "termix_linux_${arch}_deb.${ext}" }, "mac": { "target": [ @@ -104,7 +104,7 @@ "minimumSystemVersion": "10.15" }, "dmg": { - "artifactName": "termix_macos_${arch}_${version}_dmg.${ext}", + "artifactName": "termix_macos_${arch}_dmg.${ext}", "sign": true }, "afterSign": "build/notarize.cjs", @@ -117,7 +117,7 @@ "asarUnpack": ["**/*.node"], "type": "distribution", "category": "public.app-category.developer-tools", - "artifactName": "termix_macos_${arch}_${version}_mas.${ext}", + "artifactName": "termix_macos_${arch}_mas.${ext}", "extendInfo": { "ITSAppUsesNonExemptEncryption": false, "NSAppleEventsUsageDescription": "Termix needs access to control other applications for terminal operations." diff --git a/src/ui/desktop/apps/dashboard/Dashboard.tsx b/src/ui/desktop/apps/dashboard/Dashboard.tsx index 5e4bc5e9..6d4c9320 100644 --- a/src/ui/desktop/apps/dashboard/Dashboard.tsx +++ b/src/ui/desktop/apps/dashboard/Dashboard.tsx @@ -159,7 +159,8 @@ export function Dashboard({ setDbHealth("error"); } - const hosts = await getSSHHosts(); + const hostsResponse = await getSSHHosts(); + const hosts = Array.isArray(hostsResponse) ? hostsResponse : []; setTotalServers(hosts.length); let totalTunnelsCount = 0; @@ -177,11 +178,17 @@ export function Dashboard({ } setTotalTunnels(totalTunnelsCount); - const credentials = await getCredentials(); + const credentialsResponse = await getCredentials(); + const credentials = Array.isArray(credentialsResponse) + ? credentialsResponse + : []; setTotalCredentials(credentials.length); setRecentActivityLoading(true); - const activity = await getRecentActivity(35); + const activityResponse = await getRecentActivity(35); + const activity = Array.isArray(activityResponse) + ? activityResponse + : []; setRecentActivity(activity); setRecentActivityLoading(false); diff --git a/src/ui/desktop/authentication/ElectronLoginForm.tsx b/src/ui/desktop/authentication/ElectronLoginForm.tsx index 29f1271e..95fb3e39 100644 --- a/src/ui/desktop/authentication/ElectronLoginForm.tsx +++ b/src/ui/desktop/authentication/ElectronLoginForm.tsx @@ -3,7 +3,7 @@ import { Button } from "@/components/ui/button.tsx"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert.tsx"; import { useTranslation } from "react-i18next"; import { AlertCircle, Loader2, ArrowLeft, RefreshCw } from "lucide-react"; -import { getCookie } from "@/ui/main-axios.ts"; +import { getCookie, getUserInfo } from "@/ui/main-axios.ts"; interface ElectronLoginFormProps { serverUrl: string; @@ -53,11 +53,22 @@ export function ElectronLoginForm({ throw new Error("Failed to save JWT to localStorage"); } + try { + await getUserInfo(); + } catch (verifyErr) { + localStorage.removeItem("jwt"); + throw new Error("Invalid or expired authentication token"); + } + await new Promise((resolve) => setTimeout(resolve, 500)); onAuthSuccess(); } catch (err) { - setError(t("errors.authTokenSaveFailed")); + const errorMessage = + err instanceof Error + ? err.message + : t("errors.authTokenSaveFailed"); + setError(errorMessage); setIsAuthenticating(false); hasAuthenticatedRef.current = false; }