Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions apps/nextjs/src/components/user-avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import type { MantineSize } from "@mantine/core";

import { auth } from "@homarr/auth/next";
import { UserAvatar } from "@homarr/ui";
import { UserAvatar, UserProps } from "@homarr/ui";

interface UserAvatarProps {
interface CurrentUserAvatarProps {
size: MantineSize;
}

export const CurrentUserAvatar = async ({ size }: UserAvatarProps) => {
export const CurrentUserAvatar = async ({ size }: CurrentUserAvatarProps) => {
const currentSession = await auth();

const user = {
const user: UserProps = {
name: currentSession?.user.name ?? null,
image: currentSession?.user.image ?? null,
email: currentSession?.user.email ?? null,
};

if (!user.image && !user.email && user.name) user.image = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for this? Can you explain?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's redundant because of ?? null inside const user:.
I can remove that part yeah


return <UserAvatar user={user} size={size} />;
};
10 changes: 10 additions & 0 deletions packages/ui/src/components/user-avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
"use client";

import type { AvatarProps } from "@mantine/core";
import { Avatar } from "@mantine/core";
import { createHash } from "crypto";
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Node.js crypto module is being imported in a client component (marked with "use client"). This will cause a runtime error in the browser because the Node.js crypto module is not available in browser environments.

For client-side hashing, you should use the Web Crypto API instead:

const encoder = new TextEncoder();
const data = encoder.encode(user.email.trim().toLowerCase());
const hashBuffer = await crypto.subtle.digest('MD5', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const emailHash = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');

However, note that Web Crypto API's crypto.subtle.digest doesn't support MD5 in most browsers. You'll need to either:

  1. Use SHA-256 (supported by Web Crypto API): crypto.subtle.digest('SHA-256', data), or
  2. Use a client-side MD5 library like crypto-js or blueimp-md5, or
  3. Move the hash computation to the server side

Given that Gravatar/Libravatar specifically require MD5 hashing, option 2 or 3 would be most appropriate.

Copilot uses AI. Check for mistakes.

export interface UserProps {
name: string | null;
image: string | null;
email?: string | null;
}

interface UserAvatarProps {
Expand All @@ -13,9 +17,15 @@ interface UserAvatarProps {

export const UserAvatar = ({ user, size }: UserAvatarProps) => {
if (!user?.name) return <Avatar size={size} />;

if (user.image) {
return <Avatar src={user.image} alt={user.name} size={size} />;
}

if (user.email) {
const emailHash = createHash("md5").update(user.email.trim().toLowerCase()).digest("hex");
return <Avatar src={`https://seccdn.libravatar.org/avatar/${emailHash}?d=404`} alt={user.name} size={size} />;
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL uses d=404 which returns a 404 error when no avatar is found. This will cause the Avatar component to show a broken image icon instead of falling through to the initials-based avatar.

Consider using d=blank or d=mp (mystery person) as the default parameter, or omit the parameter entirely to let it fall back gracefully. Alternatively, you could handle the 404 error explicitly to fall back to the initials avatar:

<Avatar 
  src={`https://seccdn.libravatar.org/avatar/${emailHash}?d=blank`}
  alt={user.name} 
  size={size}
>
  {/* Avatar component should handle missing images automatically */}
</Avatar>

Or remove the d parameter to use libravatar's default behavior.

Suggested change
return <Avatar src={`https://seccdn.libravatar.org/avatar/${emailHash}?d=404`} alt={user.name} size={size} />;
return <Avatar src={`https://seccdn.libravatar.org/avatar/${emailHash}?d=blank`} alt={user.name} size={size} />;

Copilot uses AI. Check for mistakes.
}
Comment on lines +25 to +28
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have to check if the usage of crypto actually works


return <Avatar name={user.name} color="initials" size={size}></Avatar>;
};
Loading