validity
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
import { authenticatedRequestHeaders } from "@/next/http";
|
||||
import { apiOrigin } from "@ente/shared/network/api";
|
||||
import { LS_KEYS } from "@ente/shared/storage/localStorage";
|
||||
import type { KeyAttributes } from "@ente/shared/user/types";
|
||||
|
||||
type SessionValidity =
|
||||
| { status: "invalid" }
|
||||
| { status: "valid"; updatedKeyAttributes: KeyAttributes | undefined };
|
||||
|
||||
/**
|
||||
* [Note: Handle password changes]
|
||||
*
|
||||
@@ -9,9 +14,9 @@ import type { KeyAttributes } from "@ente/shared/user/types";
|
||||
* update our local state so that we use the latest password for verification.
|
||||
*
|
||||
* There is a straightforward way of doing this by always making a blocking API
|
||||
* call before showing this page, however that would add latency to the 99% user
|
||||
* experience (of normal unlocks) for the 1% case (they've changed their
|
||||
* password elsewhere).
|
||||
* call before showing the password unlock page, however that would add latency
|
||||
* to the 99% user experience (of normal unlocks) for the 1% case (they've
|
||||
* changed their password elsewhere).
|
||||
*
|
||||
* Another alternative would be to non-blockingly check if their password has
|
||||
* changed (e.g. by comparing the remote and local SRP attributes), and if so,
|
||||
@@ -35,46 +40,48 @@ import type { KeyAttributes } from "@ente/shared/user/types";
|
||||
* It does not take any parameters because it reads the current state (key
|
||||
* attributes) from local storage.
|
||||
*
|
||||
* @returns true if the session is valid, false if the session is invalid, and
|
||||
* the (new) remote {@link KeyAttributes} if they've changed.
|
||||
*
|
||||
* @throws Exceptions if something goes wrong (it doesn't attempt to swallow
|
||||
* failures, it is upto the caller to decide how to deal with failures in
|
||||
* determining session validity).
|
||||
* @returns status "invalid" if the current token has been invalidated, "valid"
|
||||
* otherwise. In case the {@link KeyAttributes} returned by remote are different
|
||||
* from the ones we have locally, then the {@link updatedKeyAttributes} property
|
||||
* will also be set alongwith the valid {@link status} in the result.
|
||||
*/
|
||||
export const checkSessionValidity = async (): Promise<
|
||||
boolean | KeyAttributes
|
||||
> => {
|
||||
// const user = getData(LS_KEYS.USER);
|
||||
// if (!user?.email) return "invalid";
|
||||
|
||||
// try {
|
||||
// const serverAttributes = await getSRPAttributes(email);
|
||||
// // (Arbitrarily) compare the salt to figure out if something changed
|
||||
// // (salt will always change on password changes).
|
||||
// if (serverAttributes?.kekSalt !== localSRPAttributes.kekSalt)
|
||||
// return true; /* password indeed did change */
|
||||
// return false;
|
||||
// } catch (e) {
|
||||
// // Ignore errors here. In rare cases, the stars may align and cause the
|
||||
// // API calls to fail in that 1 case where the user indeed changed their
|
||||
// // password, but we also don't want to start logging people out for
|
||||
// // harmless transient issues like network errors.
|
||||
// log.error("Failed to compare SRP attributes", e);
|
||||
// return false;
|
||||
// }
|
||||
await getSessionValidity();
|
||||
return true;
|
||||
};
|
||||
|
||||
const getSessionValidity = async () => {
|
||||
export const checkSessionValidity = async (): Promise<SessionValidity> => {
|
||||
const url = `${apiOrigin()}/users/session-validity/v2`;
|
||||
const res = await fetch(url, {
|
||||
headers: authenticatedRequestHeaders(),
|
||||
});
|
||||
if (!res.ok) {
|
||||
if (res.status == 401) return false; /* session is no longer valid */
|
||||
if (res.status == 401)
|
||||
return { status: "invalid" }; /* session is no longer valid */
|
||||
else throw new Error(`Failed to fetch ${url}: HTTP ${res.status}`);
|
||||
}
|
||||
return true;
|
||||
// See if the response contains keyAttributes (they might not for older
|
||||
// deployments).
|
||||
const json = await res.json();
|
||||
if (
|
||||
"keyAttributes" in json &&
|
||||
typeof json.keyAttributes == "object" &&
|
||||
json.keyAttributes !== null
|
||||
) {
|
||||
// Assume it is a `KeyAttributes`.
|
||||
//
|
||||
// Enhancement: Convert this to a zod validation.
|
||||
const remoteKeyAttributes = json.keyAttributes as KeyAttributes;
|
||||
// See if it is different from the one we have locally (if we have
|
||||
// something locally).
|
||||
const localKeyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
|
||||
if (localKeyAttributes) {
|
||||
// The kekSalt will be different if the key attributes change.
|
||||
if (remoteKeyAttributes.kekSalt != localKeyAttributes.kekSalt) {
|
||||
// The token is still valid, but the key attributes have
|
||||
// changed.
|
||||
return {
|
||||
status: "valid",
|
||||
updatedKeyAttributes: remoteKeyAttributes,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
// The token is still valid, but AFAWK, the key attributes are still the same.
|
||||
return { status: "valid" };
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user