Compare commits
2 Commits
026c405cd4
...
3a978441b6
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a978441b6 | |||
| a8503735d1 |
@@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace DysonNetwork.Sphere.Account;
|
||||
|
||||
@@ -421,6 +422,43 @@ public class AccountCurrentController(
|
||||
}
|
||||
}
|
||||
|
||||
public class AuthorizedDevice
|
||||
{
|
||||
public string? Label { get; set; }
|
||||
public string UserAgent { get; set; } = null!;
|
||||
public string DeviceId { get; set; } = null!;
|
||||
public List<Session> Sessions { get; set; } = new();
|
||||
}
|
||||
|
||||
[HttpGet("devices")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<List<AuthorizedDevice>>> GetDevices()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
// Group sessions by the related DeviceId, then create an AuthorizedDevice for each group.
|
||||
var deviceGroups = await db.AuthSessions
|
||||
.Where(s => s.Account.Id == currentUser.Id)
|
||||
// Include the challenge if you need it to access DeviceId
|
||||
.Include(s => s.Challenge)
|
||||
.GroupBy(s => s.Challenge.DeviceId!)
|
||||
.Select(g => new AuthorizedDevice
|
||||
{
|
||||
DeviceId = g.Key!,
|
||||
UserAgent = g.First(x => x.Challenge.UserAgent != null).Challenge.UserAgent!,
|
||||
Label = g.Where(x => string.IsNullOrWhiteSpace(x.Label)).Select(x => x.Label).FirstOrDefault(),
|
||||
Sessions = g
|
||||
.OrderByDescending(x => x.LastGrantedAt)
|
||||
.ToList()
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
return Ok(deviceGroups);
|
||||
}
|
||||
|
||||
[HttpGet("sessions")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<List<Session>>> GetSessions(
|
||||
@@ -434,8 +472,7 @@ public class AccountCurrentController(
|
||||
var query = db.AuthSessions
|
||||
.Include(session => session.Account)
|
||||
.Include(session => session.Challenge)
|
||||
.Where(session => session.Account.Id == currentUser.Id)
|
||||
.OrderByDescending(session => session.CreatedAt);
|
||||
.Where(session => session.Account.Id == currentUser.Id);
|
||||
|
||||
var total = await query.CountAsync();
|
||||
Response.Headers.Append("X-Total", total.ToString());
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
@@ -142,6 +144,8 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
|
||||
public async Task<ActionResult> SendMessage([FromBody] SendMessageRequest request, Guid roomId)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||
|
||||
request.Content = TextSanitizer.Sanitize(request.Content);
|
||||
if (string.IsNullOrWhiteSpace(request.Content) &&
|
||||
(request.AttachmentsId == null || request.AttachmentsId.Count == 0))
|
||||
return BadRequest("You cannot send an empty message.");
|
||||
@@ -218,18 +222,24 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||
|
||||
request.Content = TextSanitizer.Sanitize(request.Content);
|
||||
|
||||
var message = await db.ChatMessages
|
||||
.Include(m => m.Sender)
|
||||
.Include(m => m.Sender.Account)
|
||||
.Include(m => m.Sender.Account.Profile)
|
||||
.Include(message => message.ChatRoom)
|
||||
.FirstOrDefaultAsync(m => m.Id == messageId && m.ChatRoomId == roomId);
|
||||
|
||||
|
||||
if (message == null) return NotFound();
|
||||
|
||||
if (message.Sender.AccountId != currentUser.Id)
|
||||
return StatusCode(403, "You can only edit your own messages.");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(request.Content) &&
|
||||
(request.AttachmentsId == null || request.AttachmentsId.Count == 0))
|
||||
return BadRequest("You cannot send an empty message.");
|
||||
|
||||
if (request.RepliedMessageId.HasValue)
|
||||
{
|
||||
var repliedMessage = await db.ChatMessages
|
||||
@@ -248,8 +258,8 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
|
||||
|
||||
// Call service method to update the message
|
||||
await cs.UpdateMessageAsync(
|
||||
message,
|
||||
request.Meta,
|
||||
message,
|
||||
request.Meta,
|
||||
request.Content,
|
||||
request.RepliedMessageId,
|
||||
request.ForwardedMessageId,
|
||||
@@ -269,7 +279,7 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
|
||||
.Include(m => m.Sender)
|
||||
.Include(m => m.ChatRoom)
|
||||
.FirstOrDefaultAsync(m => m.Id == messageId && m.ChatRoomId == roomId);
|
||||
|
||||
|
||||
if (message == null) return NotFound();
|
||||
|
||||
if (message.Sender.AccountId != currentUser.Id)
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Text.Json;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Sphere.Publisher;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@@ -149,6 +150,7 @@ public class PostController(
|
||||
[FromHeader(Name = "X-Pub")] string? publisherName
|
||||
)
|
||||
{
|
||||
request.Content = TextSanitizer.Sanitize(request.Content);
|
||||
if (string.IsNullOrWhiteSpace(request.Content) && request.Attachments is { Count: 0 })
|
||||
return BadRequest("Content is required.");
|
||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||
@@ -290,6 +292,7 @@ public class PostController(
|
||||
[HttpPatch("{id:guid}")]
|
||||
public async Task<ActionResult<Post>> UpdatePost(Guid id, [FromBody] PostRequest request)
|
||||
{
|
||||
request.Content = TextSanitizer.Sanitize(request.Content);
|
||||
if (string.IsNullOrWhiteSpace(request.Content) && request.Attachments is { Count: 0 })
|
||||
return BadRequest("Content is required.");
|
||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||
|
||||
24
DysonNetwork.Sphere/Storage/TextSanitizer.cs
Normal file
24
DysonNetwork.Sphere/Storage/TextSanitizer.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace DysonNetwork.Sphere.Storage;
|
||||
|
||||
public abstract class TextSanitizer
|
||||
{
|
||||
public static string? Sanitize(string? text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text)) return text;
|
||||
|
||||
var filtered = new StringBuilder();
|
||||
foreach (var ch in from ch in text
|
||||
let category = CharUnicodeInfo.GetUnicodeCategory(ch)
|
||||
where category is not (UnicodeCategory.Control or UnicodeCategory.Format
|
||||
or UnicodeCategory.NonSpacingMark)
|
||||
select ch)
|
||||
{
|
||||
filtered.Append(ch);
|
||||
}
|
||||
|
||||
return filtered.ToString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user