Files
Moonlight/Moonlight/Core/Http/Controllers/AvatarController.cs
2024-06-05 13:27:09 +02:00

112 lines
3.4 KiB
C#

using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using MoonCore.Abstractions;
using MoonCore.Helpers;
using MoonCore.Services;
using Moonlight.Core.Attributes;
using Moonlight.Core.Configuration;
using Moonlight.Core.Database.Entities;
using Moonlight.Core.Services;
namespace Moonlight.Core.Http.Controllers;
[ApiController]
[ApiDocument("internal")]
[Route("api/core/avatar")]
public class AvatarController : Controller
{
private readonly Repository<User> UserRepository;
private readonly ConfigService<CoreConfiguration> ConfigService;
private readonly IdentityService IdentityService;
public AvatarController(
Repository<User> userRepository,
IdentityService identityService,
ConfigService<CoreConfiguration> configService)
{
UserRepository = userRepository;
IdentityService = identityService;
ConfigService = configService;
}
[HttpGet]
public async Task<ActionResult> Get()
{
if (!Request.Cookies.ContainsKey("token"))
return StatusCode(403);
var token = Request.Cookies["token"];
await IdentityService.Authenticate(token!);
if (!IdentityService.IsLoggedIn)
return StatusCode(403);
return File(await GetAvatar(IdentityService.CurrentUser), "image/jpeg");
}
[HttpGet("{id:int}")]
public async Task<ActionResult> Get(int id)
{
if (!Request.Cookies.ContainsKey("token"))
return StatusCode(403);
var token = Request.Cookies["token"];
await IdentityService.Authenticate(token!);
if (!IdentityService.IsLoggedIn)
return StatusCode(403);
if (ConfigService.Get().Security.EnforceAvatarPrivacy && // Do we need to enforce privacy?
id != IdentityService.CurrentUser.Id && // is the user not viewing his own image?
IdentityService.CurrentUser.Permissions < 1000) // and not an admin?
{
return StatusCode(403);
}
var user = UserRepository
.Get()
.FirstOrDefault(x => x.Id == id);
if (user == null)
return NotFound();
return File(await GetAvatar(user), "image/jpeg");
}
private async Task<Stream> GetAvatar(User user)
{
try
{
var hash = Hash(user.Email.ToLower());
using var httpClient = new HttpClient();
var stream = await httpClient.GetStreamAsync($"https://gravatar.com/avatar/{hash}");
return stream;
}
catch (Exception e)
{
if(e is HttpRequestException requestException && requestException.InnerException is IOException ioException)
Logger.Warn($"Unable to fetch gravatar for user {user.Id}. Is moonlight inside a proxy requiring network?: {ioException.Message}");
else
{
Logger.Warn($"Unable to fetch gravatar for user {user.Id}");
Logger.Warn(e);
}
return new MemoryStream();
}
}
private string Hash(string input)
{
var md5 = MD5.Create();
var inputBytes = Encoding.ASCII.GetBytes(input);
var hash = md5.ComputeHash(inputBytes);
var sb = new StringBuilder();
foreach (var t in hash) sb.Append(t.ToString("X2"));
return sb.ToString().ToLower();
}
}