change initialisation status to a tri-state rather than a boolean

pull/28211/head
Hubert Chathi 2024-11-12 15:06:46 -05:00
parent 8078627984
commit 5615b9824a
1 changed files with 33 additions and 10 deletions

View File

@ -36,6 +36,16 @@ async function userNeedsApproval(crypto: CryptoApi, userId: string): Promise<boo
return verificationStatus.needsUserApproval; return verificationStatus.needsUserApproval;
} }
/**
* Whether the component is uninitialised, is in the process of initialising, or
* has completed initialising.
*/
enum InitialisationStatus {
Uninitialised,
Initialising,
Completed,
}
/** /**
* Displays a banner warning when there is an issue with a user's identity. * Displays a banner warning when there is an issue with a user's identity.
* *
@ -52,7 +62,7 @@ export const UserIdentityWarning: React.FC<UserIdentityWarningProps> = ({ room }
// Whether or not we've already initialised the component by loading the // Whether or not we've already initialised the component by loading the
// room membership. // room membership.
const initialisedRef = useRef<boolean>(false); const initialisedRef = useRef<InitialisationStatus>(InitialisationStatus.Uninitialised);
// Which room members need their identity approved. // Which room members need their identity approved.
const membersNeedingApprovalRef = useRef<Map<string, RoomMember>>(new Map()); const membersNeedingApprovalRef = useRef<Map<string, RoomMember>>(new Map());
// Whether we got a verification status update while we were fetching a // Whether we got a verification status update while we were fetching a
@ -89,7 +99,7 @@ export const UserIdentityWarning: React.FC<UserIdentityWarningProps> = ({ room }
// member of the room. If they are not a member, this function will do // member of the room. If they are not a member, this function will do
// nothing. // nothing.
const addMemberNeedingApproval = useCallback( const addMemberNeedingApproval = useCallback(
(userId: string, member?: RoomMember, updatePrompt: boolean = true): void => { (userId: string, member?: RoomMember): void => {
if (userId === cli.getUserId()) { if (userId === cli.getUserId()) {
// We always skip our own user, because we can't pin our own identity. // We always skip our own user, because we can't pin our own identity.
return; return;
@ -97,14 +107,24 @@ export const UserIdentityWarning: React.FC<UserIdentityWarningProps> = ({ room }
member = member ?? room.getMember(userId) ?? undefined; member = member ?? room.getMember(userId) ?? undefined;
if (member) { if (member) {
membersNeedingApprovalRef.current.set(userId, member); membersNeedingApprovalRef.current.set(userId, member);
if (updatePrompt) { // We only select the prompt if we are done initialising,
// because we will select the prompt after we're done
// initialising, and we want to start by displaying a warning
// for the user with the smallest ID.
if (initialisedRef.current === InitialisationStatus.Completed) {
setCurrentPrompt((currentPrompt) => { setCurrentPrompt((currentPrompt) => {
// If we aren't currently displaying a warning, we pick
// a new user to show a warning for. If we are already
// displaying a warning, don't change the display.
//
// We have to do this in a callback to // We have to do this in a callback to
// `setCurrentPrompt` because this function could have // `setCurrentPrompt` because this function could have
// been called after an `await`, and the `currentPrompt` // been called after an `await`, and the `currentPrompt`
// that this function would have may be outdated. // that this function would have may be outdated.
if (!currentPrompt) { if (!currentPrompt) {
return selectCurrentPrompt(); return selectCurrentPrompt();
} else {
return currentPrompt;
} }
}); });
} }
@ -117,7 +137,7 @@ export const UserIdentityWarning: React.FC<UserIdentityWarningProps> = ({ room }
// membersNeedingApproval map and update the prompt if needed. They will // membersNeedingApproval map and update the prompt if needed. They will
// only be added if they are a member of the room. // only be added if they are a member of the room.
const addMemberIfNeedsApproval = useCallback( const addMemberIfNeedsApproval = useCallback(
async (userId: string, member?: RoomMember, updatePrompt: boolean = true): Promise<void> => { async (userId: string, member?: RoomMember): Promise<void> => {
const gotVerificationStatusUpdate = gotVerificationStatusUpdateRef.current; const gotVerificationStatusUpdate = gotVerificationStatusUpdateRef.current;
const membersNeedingApproval = membersNeedingApprovalRef.current; const membersNeedingApproval = membersNeedingApprovalRef.current;
@ -129,7 +149,7 @@ export const UserIdentityWarning: React.FC<UserIdentityWarningProps> = ({ room }
gotVerificationStatusUpdate.set(userId, false); gotVerificationStatusUpdate.set(userId, false);
if (await userNeedsApproval(crypto!, userId)) { if (await userNeedsApproval(crypto!, userId)) {
if (!membersNeedingApproval.has(userId) && gotVerificationStatusUpdate.get(userId) === false) { if (!membersNeedingApproval.has(userId) && gotVerificationStatusUpdate.get(userId) === false) {
addMemberNeedingApproval(userId, member, updatePrompt); addMemberNeedingApproval(userId, member);
} }
} }
gotVerificationStatusUpdate.delete(userId); gotVerificationStatusUpdate.delete(userId);
@ -155,7 +175,7 @@ export const UserIdentityWarning: React.FC<UserIdentityWarningProps> = ({ room }
// Initialise the component. Get the room members, check which ones need // Initialise the component. Get the room members, check which ones need
// their identity approved, and pick one to display. // their identity approved, and pick one to display.
const loadMembers = useCallback(async (): Promise<void> => { const loadMembers = useCallback(async (): Promise<void> => {
if (!crypto || initialisedRef.current) { if (!crypto || initialisedRef.current != InitialisationStatus.Uninitialised) {
return; return;
} }
// If encryption is not enabled in the room, we don't need to do // If encryption is not enabled in the room, we don't need to do
@ -164,15 +184,16 @@ export const UserIdentityWarning: React.FC<UserIdentityWarningProps> = ({ room }
if (!(await crypto.isEncryptionEnabledInRoom(room.roomId))) { if (!(await crypto.isEncryptionEnabledInRoom(room.roomId))) {
return; return;
} }
initialisedRef.current = true; initialisedRef.current = InitialisationStatus.Initialising;
const members = await room.getEncryptionTargetMembers(); const members = await room.getEncryptionTargetMembers();
for (const member of members) { for (const member of members) {
await addMemberIfNeedsApproval(member.userId, member, false); await addMemberIfNeedsApproval(member.userId, member);
} }
setCurrentPrompt(selectCurrentPrompt()); setCurrentPrompt(selectCurrentPrompt());
initialisedRef.current = InitialisationStatus.Completed;
}, [crypto, room, addMemberIfNeedsApproval, selectCurrentPrompt]); }, [crypto, room, addMemberIfNeedsApproval, selectCurrentPrompt]);
loadMembers().catch((e) => { loadMembers().catch((e) => {
@ -185,7 +206,9 @@ export const UserIdentityWarning: React.FC<UserIdentityWarningProps> = ({ room }
(userId: string, verificationStatus: UserVerificationStatus): void => { (userId: string, verificationStatus: UserVerificationStatus): void => {
const gotVerificationStatusUpdate = gotVerificationStatusUpdateRef.current; const gotVerificationStatusUpdate = gotVerificationStatusUpdateRef.current;
if (!initialisedRef.current) { // If we haven't started initialising, that means that we're in a
// room where we don't need to display any warnings.
if (initialisedRef.current === InitialisationStatus.Uninitialised) {
return; return;
} }
@ -222,7 +245,7 @@ export const UserIdentityWarning: React.FC<UserIdentityWarningProps> = ({ room }
return; return;
} }
if (!initialisedRef.current) { if (initialisedRef.current === InitialisationStatus.Uninitialised) {
return; return;
} }