mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-07-15 17:02:58 +01:00
fix(login): ask how to protect a saved account after the login succeeds
The protection picker used to show before the login attempt, so a wrong password still walked the user through choosing a PIN/password for an account that never logged in - and a Quick Connect login could not save the account at all. Login flows now only flag the intent (pendingAccountSaveAtom); the picker is a global PendingAccountSaveModal mounted at the root, shown once the session is authorized - the login screen unmounts on success, so it cannot host the modal itself. Works identically for the password and Quick Connect flows; the credential is saved from the live session token (saveCurrentAccount). Cancelling saves nothing, and a logout before answering drops the intent.
This commit is contained in:
@@ -92,6 +92,12 @@ export const apiAtom = atom<Api | null>(initialApi);
|
||||
export const userAtom = atom<UserDto | null>(initialUser);
|
||||
export const wsAtom = atom<WebSocket | null>(null);
|
||||
export const cacheVersionAtom = atom<number>(0);
|
||||
// Set by a login flow that wants the account saved: the protection picker
|
||||
// shows AFTER the session is authorized (the login screen unmounts on
|
||||
// success, so the modal lives at the root — see PendingAccountSaveModal).
|
||||
export const pendingAccountSaveAtom = atom<{ serverName?: string } | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
interface LoginOptions {
|
||||
saveAccount?: boolean;
|
||||
@@ -109,6 +115,11 @@ interface JellyfinContextValue {
|
||||
serverName?: string,
|
||||
options?: LoginOptions,
|
||||
) => Promise<void>;
|
||||
saveCurrentAccount: (options?: {
|
||||
securityType?: AccountSecurityType;
|
||||
pinCode?: string;
|
||||
serverName?: string;
|
||||
}) => Promise<void>;
|
||||
logout: () => Promise<void>;
|
||||
initiateQuickConnect: () => Promise<string | undefined>;
|
||||
stopQuickConnectPolling: () => void;
|
||||
@@ -348,6 +359,37 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
|
||||
},
|
||||
});
|
||||
|
||||
// Persist the CURRENT session to secure storage — used by the post-login
|
||||
// save-account modal (the protection picker shows AFTER a successful
|
||||
// login, for both the password and Quick Connect flows).
|
||||
const saveCurrentAccount = useCallback(
|
||||
async (options?: {
|
||||
securityType?: AccountSecurityType;
|
||||
pinCode?: string;
|
||||
serverName?: string;
|
||||
}) => {
|
||||
const token = storage.getString("token");
|
||||
if (!api?.basePath || !user?.Id || !user.Name || !token) return;
|
||||
const securityType = options?.securityType || "none";
|
||||
let pinHash: string | undefined;
|
||||
if (securityType === "pin" && options?.pinCode) {
|
||||
pinHash = await hashPIN(options.pinCode);
|
||||
}
|
||||
await saveAccountCredential({
|
||||
serverUrl: api.basePath,
|
||||
serverName: options?.serverName || "",
|
||||
token,
|
||||
userId: user.Id,
|
||||
username: user.Name,
|
||||
savedAt: Date.now(),
|
||||
securityType,
|
||||
pinHash,
|
||||
primaryImageTag: user.PrimaryImageTag ?? undefined,
|
||||
});
|
||||
},
|
||||
[api?.basePath, user],
|
||||
);
|
||||
|
||||
const loginMutation = useMutation({
|
||||
mutationFn: async ({
|
||||
username,
|
||||
@@ -427,7 +469,7 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
|
||||
default:
|
||||
throw new Error(
|
||||
t(
|
||||
"login.an_unexpected_error_occurred_did_you_enter_the_correct_url",
|
||||
"login.an_unexpected_error_occured_did_you_enter_the_correct_url",
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -732,6 +774,7 @@ export const JellyfinProvider: React.FC<{ children: ReactNode }> = ({
|
||||
removeServer: () => removeServerMutation.mutateAsync(),
|
||||
login: (username, password, serverName, options) =>
|
||||
loginMutation.mutateAsync({ username, password, serverName, options }),
|
||||
saveCurrentAccount,
|
||||
logout: () => logoutMutation.mutateAsync(),
|
||||
initiateQuickConnect,
|
||||
stopQuickConnectPolling,
|
||||
|
||||
Reference in New Issue
Block a user