mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-07-19 02:34:17 +01:00
Replace password storage with token-based authentication for server switching
Co-authored-by: retardgerman <78982850+retardgerman@users.noreply.github.com>
This commit is contained in:
@@ -11,10 +11,7 @@ interface Server {
|
|||||||
serverName?: string;
|
serverName?: string;
|
||||||
serverId?: string;
|
serverId?: string;
|
||||||
lastUsername?: string;
|
lastUsername?: string;
|
||||||
savedCredentials?: {
|
savedToken?: string;
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PreviousServersListProps {
|
interface PreviousServersListProps {
|
||||||
@@ -58,7 +55,7 @@ export const PreviousServersList: React.FC<PreviousServersListProps> = ({
|
|||||||
onPress={() => onServerSelect(s)}
|
onPress={() => onServerSelect(s)}
|
||||||
title={getServerDisplayName(s)}
|
title={getServerDisplayName(s)}
|
||||||
subtitle={getServerSubtitle(s)}
|
subtitle={getServerSubtitle(s)}
|
||||||
icon={s.savedCredentials ? "key" : "server"}
|
icon={s.savedToken ? "key" : "server"}
|
||||||
showArrow
|
showArrow
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -13,10 +13,7 @@ interface Server {
|
|||||||
serverName?: string;
|
serverName?: string;
|
||||||
serverId?: string;
|
serverId?: string;
|
||||||
lastUsername?: string;
|
lastUsername?: string;
|
||||||
savedCredentials?: {
|
savedToken?: string;
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props extends ViewProps {}
|
interface Props extends ViewProps {}
|
||||||
@@ -54,8 +51,8 @@ export const ServerSwitcher: React.FC<Props> = ({ ...props }) => {
|
|||||||
|
|
||||||
const getServerSubtitle = (server: Server) => {
|
const getServerSubtitle = (server: Server) => {
|
||||||
if (server.lastUsername) {
|
if (server.lastUsername) {
|
||||||
const hasCredentials = !!server.savedCredentials;
|
const hasToken = !!server.savedToken;
|
||||||
return hasCredentials
|
return hasToken
|
||||||
? `${server.lastUsername} • Auto-login available`
|
? `${server.lastUsername} • Auto-login available`
|
||||||
: `Last user: ${server.lastUsername}`;
|
: `Last user: ${server.lastUsername}`;
|
||||||
}
|
}
|
||||||
@@ -81,7 +78,7 @@ export const ServerSwitcher: React.FC<Props> = ({ ...props }) => {
|
|||||||
onPress={() => handleServerSwitch(server)}
|
onPress={() => handleServerSwitch(server)}
|
||||||
title={getServerDisplayName(server)}
|
title={getServerDisplayName(server)}
|
||||||
subtitle={getServerSubtitle(server)}
|
subtitle={getServerSubtitle(server)}
|
||||||
icon={server.savedCredentials ? "key" : "server"}
|
icon={server.savedToken ? "key" : "server"}
|
||||||
showArrow
|
showArrow
|
||||||
disabled={switchingServer === server.address}
|
disabled={switchingServer === server.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -33,10 +33,7 @@ interface Server {
|
|||||||
serverName?: string;
|
serverName?: string;
|
||||||
serverId?: string;
|
serverId?: string;
|
||||||
lastUsername?: string;
|
lastUsername?: string;
|
||||||
savedCredentials?: {
|
savedToken?: string;
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const apiAtom = atom<Api | null>(null);
|
export const apiAtom = atom<Api | null>(null);
|
||||||
@@ -256,7 +253,7 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
setApi(jellyfin.createApi(api?.basePath, auth.data?.AccessToken));
|
setApi(jellyfin.createApi(api?.basePath, auth.data?.AccessToken));
|
||||||
storage.set("token", 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) {
|
if (saveCredentials && api.basePath) {
|
||||||
const previousServers = JSON.parse(
|
const previousServers = JSON.parse(
|
||||||
storage.getString("previousServers") || "[]",
|
storage.getString("previousServers") || "[]",
|
||||||
@@ -267,7 +264,7 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
return {
|
return {
|
||||||
...server,
|
...server,
|
||||||
lastUsername: username,
|
lastUsername: username,
|
||||||
savedCredentials: { username, password }
|
savedToken: auth.data.AccessToken
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return server;
|
return server;
|
||||||
@@ -348,20 +345,42 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
// Get current server info for comparison
|
// Get current server info for comparison
|
||||||
const currentServerId = await getCurrentServerId();
|
const currentServerId = await getCurrentServerId();
|
||||||
|
|
||||||
// If switching to same server (different URL), try auto-login with saved credentials
|
// If switching to same server (different URL), try auto-login with saved token
|
||||||
if (server.serverId && server.serverId === currentServerId && server.savedCredentials) {
|
if (server.serverId && server.serverId === currentServerId && server.savedToken) {
|
||||||
try {
|
try {
|
||||||
// Just set the new server without logging out
|
// Create API instance with saved token
|
||||||
await setServerMutation.mutateAsync(server);
|
const apiInstance = jellyfin?.createApi(server.address, server.savedToken);
|
||||||
// Auto-login with saved credentials
|
if (!apiInstance) throw new Error("Failed to create API instance");
|
||||||
await loginMutation.mutateAsync({
|
|
||||||
username: server.savedCredentials.username,
|
// Validate the token by making an authenticated request
|
||||||
password: server.savedCredentials.password,
|
const userApi = getUserApi(apiInstance);
|
||||||
saveCredentials: false, // Don't save again
|
const userResponse = await userApi.getCurrentUser();
|
||||||
});
|
|
||||||
return;
|
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) {
|
} 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;
|
if (!jellyfin) return;
|
||||||
|
|
||||||
try {
|
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 token = getTokenFromStorage();
|
||||||
const serverUrl = getServerUrlFromStorage();
|
const serverUrl = getServerUrlFromStorage();
|
||||||
const storedUser = getUserFromStorage();
|
const storedUser = getUserFromStorage();
|
||||||
|
|||||||
Reference in New Issue
Block a user