mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
fix(app): load saved account avatars from their own instance (#3267)
This commit is contained in:
1 parent
de358c0def
commit
e218ba21de
3 files changed
+2
-62
No files matched your search
@@ -1,40 +1,11 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import RuntimeConfig, {runtimeConfigSnapshotsAreSameInstance} from '@app/features/app/state/RuntimeConfig';
|
||||
import type {Account} from '@app/features/platform/state/AuthSession';
|
||||
import * as AvatarUtils from '@app/features/user/utils/AvatarUtils';
|
||||
import {getDefaultAvatarAssetURL} from '@app/features/user/utils/DefaultAvatars';
|
||||
import type {MediaProxyImageSize} from '@fluxer/constants/src/MediaProxyImageSizes';
|
||||
import {useMemo} from 'react';
|
||||
|
||||
const LOCAL_ACCOUNT_AVATAR_DATA_URL_PATTERN = /^data:image\/(?:avif|gif|jpeg|png|webp);base64,[a-zA-Z0-9+/]+=*$/u;
|
||||
|
||||
function cachedAccountAvatarURL(account: Account, avatar: string, size?: MediaProxyImageSize): string | null {
|
||||
const userData = account.userData;
|
||||
if (!userData || userData.localAvatarHash !== avatar) {
|
||||
return null;
|
||||
}
|
||||
const localAvatarURL = userData.localAvatarURL;
|
||||
if (localAvatarURL == null || !LOCAL_ACCOUNT_AVATAR_DATA_URL_PATTERN.test(localAvatarURL)) {
|
||||
return null;
|
||||
}
|
||||
if (size != null && (typeof userData.localAvatarSize !== 'number' || userData.localAvatarSize < size)) {
|
||||
return null;
|
||||
}
|
||||
return localAvatarURL;
|
||||
}
|
||||
|
||||
function accountInstanceMediaEndpoint(account: Account): string | null {
|
||||
const instance = account.instance;
|
||||
if (instance == null || typeof instance.mediaEndpoint !== 'string' || instance.mediaEndpoint.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (!runtimeConfigSnapshotsAreSameInstance(instance, RuntimeConfig.getSnapshotOrNull())) {
|
||||
return null;
|
||||
}
|
||||
return instance.mediaEndpoint;
|
||||
}
|
||||
|
||||
function defaultAccountAvatarURL(account: Account, size?: MediaProxyImageSize): string {
|
||||
try {
|
||||
return AvatarUtils.getUserAvatarURL({id: account.userId, avatar: null}, false, size);
|
||||
@@ -45,15 +16,8 @@ function defaultAccountAvatarURL(account: Account, size?: MediaProxyImageSize):
|
||||
|
||||
function resolveAccountAvatarURL(account: Account, size?: MediaProxyImageSize): string {
|
||||
const avatar = account.userData?.avatar ?? null;
|
||||
if (avatar == null || avatar.length === 0) {
|
||||
return defaultAccountAvatarURL(account, size);
|
||||
}
|
||||
const cached = cachedAccountAvatarURL(account, avatar, size);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
const mediaEndpoint = accountInstanceMediaEndpoint(account);
|
||||
if (mediaEndpoint == null) {
|
||||
const mediaEndpoint = account.instance?.mediaEndpoint ?? null;
|
||||
if (avatar == null || avatar.length === 0 || mediaEndpoint == null || mediaEndpoint.length === 0) {
|
||||
return defaultAccountAvatarURL(account, size);
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -20,9 +20,6 @@ export interface UserData {
|
||||
globalName?: string | null;
|
||||
email?: string | null;
|
||||
avatar?: string | null;
|
||||
localAvatarHash?: string | null;
|
||||
localAvatarURL?: string | null;
|
||||
localAvatarSize?: number | null;
|
||||
}
|
||||
|
||||
export interface AccountPresenceIntent {
|
||||
|
||||
@@ -90,14 +90,6 @@ function readUserData(value: unknown): UserData | undefined {
|
||||
if (typeof source.username !== 'string' || typeof source.discriminator !== 'string') {
|
||||
throw new StoredAccountRuntimeRecoveryError('Stored account user data must contain a username and discriminator');
|
||||
}
|
||||
const localAvatarSize = source.localAvatarSize;
|
||||
if (
|
||||
localAvatarSize !== undefined &&
|
||||
localAvatarSize !== null &&
|
||||
(typeof localAvatarSize !== 'number' || !Number.isFinite(localAvatarSize))
|
||||
) {
|
||||
throw new StoredAccountRuntimeRecoveryError('Stored account local avatar size must be finite, null, or absent');
|
||||
}
|
||||
const userData: UserData = {
|
||||
username: source.username,
|
||||
discriminator: source.discriminator,
|
||||
@@ -111,19 +103,6 @@ function readUserData(value: unknown): UserData | undefined {
|
||||
if (Object.hasOwn(source, 'avatar')) {
|
||||
userData.avatar = readOptionalNullableString(source, 'avatar', 'Stored account avatar');
|
||||
}
|
||||
if (Object.hasOwn(source, 'localAvatarHash')) {
|
||||
userData.localAvatarHash = readOptionalNullableString(
|
||||
source,
|
||||
'localAvatarHash',
|
||||
'Stored account local avatar hash',
|
||||
);
|
||||
}
|
||||
if (Object.hasOwn(source, 'localAvatarURL')) {
|
||||
userData.localAvatarURL = readOptionalNullableString(source, 'localAvatarURL', 'Stored account local avatar URL');
|
||||
}
|
||||
if (Object.hasOwn(source, 'localAvatarSize')) {
|
||||
userData.localAvatarSize = localAvatarSize;
|
||||
}
|
||||
return userData;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user