diff --git a/components/PreviousServersList.tsx b/components/PreviousServersList.tsx index 2a115fb8..c2e7034e 100644 --- a/components/PreviousServersList.tsx +++ b/components/PreviousServersList.tsx @@ -11,10 +11,7 @@ interface Server { serverName?: string; serverId?: string; lastUsername?: string; - savedCredentials?: { - username: string; - password: string; - }; + savedToken?: string; } interface PreviousServersListProps { @@ -58,7 +55,7 @@ export const PreviousServersList: React.FC = ({ onPress={() => onServerSelect(s)} title={getServerDisplayName(s)} subtitle={getServerSubtitle(s)} - icon={s.savedCredentials ? "key" : "server"} + icon={s.savedToken ? "key" : "server"} showArrow /> ))} diff --git a/components/settings/ServerSwitcher.tsx b/components/settings/ServerSwitcher.tsx index 18feac82..93664b6d 100644 --- a/components/settings/ServerSwitcher.tsx +++ b/components/settings/ServerSwitcher.tsx @@ -13,10 +13,7 @@ interface Server { serverName?: string; serverId?: string; lastUsername?: string; - savedCredentials?: { - username: string; - password: string; - }; + savedToken?: string; } interface Props extends ViewProps {} @@ -54,8 +51,8 @@ export const ServerSwitcher: React.FC = ({ ...props }) => { const getServerSubtitle = (server: Server) => { if (server.lastUsername) { - const hasCredentials = !!server.savedCredentials; - return hasCredentials + const hasToken = !!server.savedToken; + return hasToken ? `${server.lastUsername} • Auto-login available` : `Last user: ${server.lastUsername}`; } @@ -81,7 +78,7 @@ export const ServerSwitcher: React.FC = ({ ...props }) => { onPress={() => handleServerSwitch(server)} title={getServerDisplayName(server)} subtitle={getServerSubtitle(server)} - icon={server.savedCredentials ? "key" : "server"} + icon={server.savedToken ? "key" : "server"} showArrow disabled={switchingServer === server.address} /> diff --git a/providers/JellyfinProvider.tsx b/providers/JellyfinProvider.tsx index 0b42eb7e..e8adb115 100644 --- a/providers/JellyfinProvider.tsx +++ b/providers/JellyfinProvider.tsx @@ -33,10 +33,7 @@ interface Server { serverName?: string; serverId?: string; lastUsername?: string; - savedCredentials?: { - username: string; - password: string; - }; + savedToken?: string; } export const apiAtom = atom(null); @@ -256,7 +253,7 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({ setApi(jellyfin.createApi(api?.basePath, auth.data?.AccessToken)); storage.set("token", auth.data?.AccessToken); - // Save credentials to the current server if requested + // Save token to the current server if requested if (saveCredentials && api.basePath) { const previousServers = JSON.parse( storage.getString("previousServers") || "[]", @@ -267,7 +264,7 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({ return { ...server, lastUsername: username, - savedCredentials: { username, password } + savedToken: auth.data.AccessToken }; } return server; @@ -348,20 +345,42 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({ // Get current server info for comparison const currentServerId = await getCurrentServerId(); - // If switching to same server (different URL), try auto-login with saved credentials - if (server.serverId && server.serverId === currentServerId && server.savedCredentials) { + // If switching to same server (different URL), try auto-login with saved token + if (server.serverId && server.serverId === currentServerId && server.savedToken) { try { - // Just set the new server without logging out - await setServerMutation.mutateAsync(server); - // Auto-login with saved credentials - await loginMutation.mutateAsync({ - username: server.savedCredentials.username, - password: server.savedCredentials.password, - saveCredentials: false, // Don't save again - }); - return; + // Create API instance with saved token + const apiInstance = jellyfin?.createApi(server.address, server.savedToken); + if (!apiInstance) throw new Error("Failed to create API instance"); + + // Validate the token by making an authenticated request + const userApi = getUserApi(apiInstance); + const userResponse = await userApi.getCurrentUser(); + + if (userResponse.data) { + // Token is valid, update the API and user + setApi(apiInstance); + setUser(userResponse.data); + storage.set("serverUrl", server.address); + storage.set("token", server.savedToken); + storage.set("user", JSON.stringify(userResponse.data)); + return; + } } catch (error) { - console.warn("Auto-login failed, falling back to manual login:", error); + console.warn("Saved token is invalid, falling back to manual login:", error); + // Remove invalid token from server + const previousServers = JSON.parse( + storage.getString("previousServers") || "[]", + ) as Server[]; + + const updatedServers = previousServers.map((s) => { + if (s.address === server.address) { + const { savedToken, ...serverWithoutToken } = s; + return serverWithoutToken; + } + return s; + }); + + storage.set("previousServers", JSON.stringify(updatedServers)); } } @@ -441,6 +460,23 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({ if (!jellyfin) return; try { + // Migrate any existing savedCredentials to remove them + const previousServers = JSON.parse( + storage.getString("previousServers") || "[]", + ) as any[]; + + if (previousServers.length > 0) { + const migratedServers = previousServers.map((server) => { + if (server.savedCredentials) { + // Remove savedCredentials field for security + const { savedCredentials, ...serverWithoutCredentials } = server; + return serverWithoutCredentials; + } + return server; + }); + storage.set("previousServers", JSON.stringify(migratedServers)); + } + const token = getTokenFromStorage(); const serverUrl = getServerUrlFromStorage(); const storedUser = getUserFromStorage();