Compare commits
7 Commits
1d2f96b2f4
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
| e1e8a834b2 | |||
| 61f3d2889c | |||
| 66a7e633a9 | |||
| fff484d4ba | |||
| e69550048b | |||
| a29fb27b0d | |||
| c23cc4a03a |
@@ -6,4 +6,6 @@ public class GetDiscussionDto
|
|||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
public bool IsGroup { get; set; }
|
public bool IsGroup { get; set; }
|
||||||
public int? MembersCount { get; set; }
|
public int? MembersCount { get; set; }
|
||||||
|
|
||||||
|
public int? GroupId { get; set; }
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,6 @@ public class GetMessageDetailsDto
|
|||||||
public DateTime Date { get; set; }
|
public DateTime Date { get; set; }
|
||||||
public Boolean Type { get; set; }
|
public Boolean Type { get; set; }
|
||||||
|
|
||||||
public int AuthorId { get; set; }
|
public int UserId { get; set; }
|
||||||
public string AuthorName { get; set; } = "";
|
public string AuthorName { get; set; } = "";
|
||||||
}
|
}
|
||||||
@@ -3,10 +3,11 @@ using Knots.DTO.Discussion;
|
|||||||
using Knots.Models;
|
using Knots.Models;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using Knots.Services;
|
||||||
|
|
||||||
namespace Knots.Endpoints.Discussion;
|
namespace Knots.Endpoints.Discussion;
|
||||||
|
|
||||||
public class CreateGroupDiscussionEndpoint(KnotsDbContext db) : Endpoint<CreateGroupDiscussionRequest, GetDiscussionDto>
|
public class CreateGroupDiscussionEndpoint(KnotsDbContext db, EncryptionService encryption) : Endpoint<CreateGroupDiscussionRequest, GetDiscussionDto>
|
||||||
{
|
{
|
||||||
public override void Configure()
|
public override void Configure()
|
||||||
{
|
{
|
||||||
@@ -44,6 +45,7 @@ public class CreateGroupDiscussionEndpoint(KnotsDbContext db) : Endpoint<CreateG
|
|||||||
Models.Discussion discussion = new()
|
Models.Discussion discussion = new()
|
||||||
{
|
{
|
||||||
IsGroup = true,
|
IsGroup = true,
|
||||||
|
Key = new Models.Key { EnKey = encryption.GenerateKey() },
|
||||||
UserDiscussions = targets
|
UserDiscussions = targets
|
||||||
.Select(t => new UserDiscussion { UserId = t.Id })
|
.Select(t => new UserDiscussion { UserId = t.Id })
|
||||||
.Append(new UserDiscussion { UserId = currentUserId })
|
.Append(new UserDiscussion { UserId = currentUserId })
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ using Knots.DTO.Discussion;
|
|||||||
using Knots.Models;
|
using Knots.Models;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using Knots.Services;
|
||||||
|
|
||||||
namespace Knots.Endpoints.Discussion;
|
namespace Knots.Endpoints.Discussion;
|
||||||
|
|
||||||
public class CreatePrivateDiscussionEndpoint(KnotsDbContext db)
|
public class CreatePrivateDiscussionEndpoint(KnotsDbContext db, EncryptionService encryption)
|
||||||
: Endpoint<CreatePrivateDiscussionRequest, GetDiscussionDto>
|
: Endpoint<CreatePrivateDiscussionRequest, GetDiscussionDto>
|
||||||
{
|
{
|
||||||
public override void Configure()
|
public override void Configure()
|
||||||
@@ -57,6 +58,7 @@ public class CreatePrivateDiscussionEndpoint(KnotsDbContext db)
|
|||||||
Models.Discussion discussion = new()
|
Models.Discussion discussion = new()
|
||||||
{
|
{
|
||||||
IsGroup = false,
|
IsGroup = false,
|
||||||
|
Key = new Models.Key { EnKey = encryption.GenerateKey() },
|
||||||
UserDiscussions =
|
UserDiscussions =
|
||||||
[
|
[
|
||||||
new UserDiscussion { UserId = currentUserId },
|
new UserDiscussion { UserId = currentUserId },
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Security.Claims;
|
||||||
|
using FastEndpoints;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Knots.Endpoints.Discussion;
|
||||||
|
|
||||||
|
public class GetDiscussionMembersEndpoint(KnotsDbContext db) : EndpointWithoutRequest<List<string>>
|
||||||
|
{
|
||||||
|
public override void Configure()
|
||||||
|
{
|
||||||
|
Get("/discussions/{discussionId}/members");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task HandleAsync(CancellationToken ct)
|
||||||
|
{
|
||||||
|
int discussionId = Route<int>("discussionId");
|
||||||
|
|
||||||
|
Models.Discussion? discussion = await db.Discussions
|
||||||
|
.Include(d => d.UserDiscussions)
|
||||||
|
.ThenInclude(ud => ud.User)
|
||||||
|
.SingleOrDefaultAsync(d => d.Id == discussionId, ct);
|
||||||
|
|
||||||
|
if (discussion is null)
|
||||||
|
{
|
||||||
|
await SendNotFoundAsync(ct);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> members = discussion.UserDiscussions
|
||||||
|
.Select(ud => ud.User.Username!)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
await SendOkAsync(members, ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using FastEndpoints;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Knots.Endpoints.Discussion;
|
||||||
|
|
||||||
|
public class GetDiscussionMembersWithRolesEndpoint(KnotsDbContext db) : EndpointWithoutRequest<List<MemberWithRoleDto>>
|
||||||
|
{
|
||||||
|
public override void Configure()
|
||||||
|
{
|
||||||
|
Get("/discussions/{discussionId}/members/roles");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task HandleAsync(CancellationToken ct)
|
||||||
|
{
|
||||||
|
int discussionId = Route<int>("discussionId");
|
||||||
|
|
||||||
|
Models.Discussion? discussion = await db.Discussions
|
||||||
|
.Include(d => d.Group)
|
||||||
|
.ThenInclude(g => g!.GroupUsers)
|
||||||
|
.ThenInclude(gu => gu.User)
|
||||||
|
.Include(d => d.Group)
|
||||||
|
.ThenInclude(g => g!.GroupUsers)
|
||||||
|
.ThenInclude(gu => gu.Role)
|
||||||
|
.SingleOrDefaultAsync(d => d.Id == discussionId, ct);
|
||||||
|
|
||||||
|
if (discussion?.Group is null)
|
||||||
|
{
|
||||||
|
await SendNotFoundAsync(ct);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MemberWithRoleDto> members = discussion.Group.GroupUsers
|
||||||
|
.Select(gu => new MemberWithRoleDto
|
||||||
|
{
|
||||||
|
UserId = gu.UserId,
|
||||||
|
Username = gu.User.Username!,
|
||||||
|
RoleId = gu.RoleId,
|
||||||
|
RoleLibelle = gu.Role?.Libelle
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
await SendOkAsync(members, ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MemberWithRoleDto
|
||||||
|
{
|
||||||
|
public int UserId { get; set; }
|
||||||
|
public string Username { get; set; } = "";
|
||||||
|
public int? RoleId { get; set; }
|
||||||
|
public string? RoleLibelle { get; set; }
|
||||||
|
}
|
||||||
@@ -27,7 +27,8 @@ public class GetMyDiscussionEndpoint(KnotsDbContext db) : EndpointWithoutRequest
|
|||||||
.Where(ud => ud.UserId != userId)
|
.Where(ud => ud.UserId != userId)
|
||||||
.Select(ud => ud.User.Username)
|
.Select(ud => ud.User.Username)
|
||||||
.FirstOrDefault() ?? "",
|
.FirstOrDefault() ?? "",
|
||||||
MembersCount = null
|
MembersCount = null,
|
||||||
|
GroupId = null
|
||||||
});
|
});
|
||||||
|
|
||||||
// Discussions de groupe : l'utilisateur est membre du groupe
|
// Discussions de groupe : l'utilisateur est membre du groupe
|
||||||
@@ -38,7 +39,8 @@ public class GetMyDiscussionEndpoint(KnotsDbContext db) : EndpointWithoutRequest
|
|||||||
Id = d.Id,
|
Id = d.Id,
|
||||||
IsGroup = true,
|
IsGroup = true,
|
||||||
Name = d.Group!.Name!,
|
Name = d.Group!.Name!,
|
||||||
MembersCount = d.Group.MembersAmount
|
MembersCount = d.Group.MembersAmount,
|
||||||
|
GroupId = d.Group.Id
|
||||||
});
|
});
|
||||||
|
|
||||||
List<GetDiscussionDto> discussions = await privees.Concat(groupes).ToListAsync(ct);
|
List<GetDiscussionDto> discussions = await privees.Concat(groupes).ToListAsync(ct);
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ using System.Security.Claims;
|
|||||||
using FastEndpoints;
|
using FastEndpoints;
|
||||||
using Knots.DTO.Message;
|
using Knots.DTO.Message;
|
||||||
using Knots.DTO.User;
|
using Knots.DTO.User;
|
||||||
|
using Knots.Services;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Knots.Endpoints.Message;
|
namespace Knots.Endpoints.Message;
|
||||||
|
|
||||||
public class GetMessageEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<GetDiscussionMessagesRequest, List<GetMessageDetailsDto>>
|
public class GetMessageEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper, EncryptionService encryption) : Endpoint<GetDiscussionMessagesRequest, List<GetMessageDetailsDto>>
|
||||||
{
|
{
|
||||||
public override void Configure()
|
public override void Configure()
|
||||||
{
|
{
|
||||||
@@ -31,19 +32,26 @@ public class GetMessageEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) :
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<GetMessageDetailsDto> messages = await db.Messages
|
string? key = await db.Discussions
|
||||||
|
.Where(d => d.Id == req.DiscussionId)
|
||||||
|
.Select(d => d.Key!.EnKey)
|
||||||
|
.SingleAsync(ct);
|
||||||
|
|
||||||
|
var rows = await db.Messages
|
||||||
.Where(m => m.DiscussionId == req.DiscussionId)
|
.Where(m => m.DiscussionId == req.DiscussionId)
|
||||||
.OrderBy(m => m.Date)
|
.OrderBy(m => m.Date)
|
||||||
.Select(m => new GetMessageDetailsDto
|
.Select(m => new { m.Id, m.Contenu, m.Date, m.UserId, AuthorName = m.User.Username! })
|
||||||
{
|
|
||||||
Id = m.Id,
|
|
||||||
Contenu = m.Contenu!,
|
|
||||||
Date = m.Date,
|
|
||||||
AuthorId = m.UserId,
|
|
||||||
AuthorName = m.User.Username!
|
|
||||||
})
|
|
||||||
.ToListAsync(ct);
|
.ToListAsync(ct);
|
||||||
|
|
||||||
|
List<GetMessageDetailsDto> messages = rows.Select(m => new GetMessageDetailsDto
|
||||||
|
{
|
||||||
|
Id = m.Id,
|
||||||
|
Contenu = encryption.Decrypt(m.Contenu!, key!),
|
||||||
|
Date = m.Date,
|
||||||
|
UserId = m.UserId,
|
||||||
|
AuthorName = m.AuthorName
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
await SendOkAsync(messages, ct);
|
await SendOkAsync(messages, ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using FastEndpoints;
|
||||||
|
using Knots.Models;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Knots.Endpoints.Role;
|
||||||
|
|
||||||
|
public class AssignRoleEndpoint(KnotsDbContext db) : Endpoint<AssignRoleRequest>
|
||||||
|
{
|
||||||
|
public override void Configure()
|
||||||
|
{
|
||||||
|
Post("/groups/{groupId}/members/{userId}/role");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task HandleAsync(AssignRoleRequest req, CancellationToken ct)
|
||||||
|
{
|
||||||
|
int groupId = Route<int>("groupId");
|
||||||
|
int userId = Route<int>("userId");
|
||||||
|
|
||||||
|
GroupUser? groupUser = await db.GroupUsers
|
||||||
|
.SingleOrDefaultAsync(gu => gu.GroupId == groupId && gu.UserId == userId, ct);
|
||||||
|
|
||||||
|
if (groupUser is null)
|
||||||
|
{
|
||||||
|
await SendNotFoundAsync(ct);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool roleExists = await db.Roles.AnyAsync(r => r.Id == req.RoleId, ct);
|
||||||
|
if (!roleExists)
|
||||||
|
{
|
||||||
|
await SendNotFoundAsync(ct);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
groupUser.RoleId = req.RoleId;
|
||||||
|
await db.SaveChangesAsync(ct);
|
||||||
|
|
||||||
|
await SendOkAsync(ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AssignRoleRequest
|
||||||
|
{
|
||||||
|
public int RoleId { get; set; }
|
||||||
|
}
|
||||||
@@ -1,22 +1,32 @@
|
|||||||
using FastEndpoints;
|
using FastEndpoints;
|
||||||
using Knots.DTO.Role;
|
using Knots.Models;
|
||||||
using Knots.DTO.User;
|
|
||||||
|
|
||||||
namespace Knots.Endpoints.Role;
|
namespace Knots.Endpoints.Role;
|
||||||
|
|
||||||
public class CreateRoleEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<CreateRoleDto>
|
public class CreateRoleEndpoint(KnotsDbContext db) : Endpoint<CreateRoleRequest, RoleDto>
|
||||||
{
|
{
|
||||||
public override void Configure()
|
public override void Configure()
|
||||||
{
|
{
|
||||||
Post("/roles");
|
Post("/roles");
|
||||||
AllowAnonymous();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task HandleAsync(CreateRoleDto req, CancellationToken ct)
|
public override async Task HandleAsync(CreateRoleRequest req, CancellationToken ct)
|
||||||
{
|
{
|
||||||
Models.Role? role = mapper.Map<Models.Role>(req);
|
Models.Role role = new() { Libelle = req.Libelle };
|
||||||
db.Roles.Add(role);
|
db.Roles.Add(role);
|
||||||
await db.SaveChangesAsync(ct);
|
await db.SaveChangesAsync(ct);
|
||||||
await SendNoContentAsync(ct);
|
|
||||||
|
await SendOkAsync(new RoleDto { Id = role.Id, Libelle = role.Libelle! }, ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class CreateRoleRequest
|
||||||
|
{
|
||||||
|
public string Libelle { get; set; } = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RoleDto
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Libelle { get; set; } = "";
|
||||||
|
}
|
||||||
+30
-15
@@ -1,45 +1,60 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Knots.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Knots.Hubs;
|
namespace Knots.Hubs;
|
||||||
|
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class ChatHub(KnotsDbContext db, AutoMapper.IMapper mapper) : Hub
|
public class ChatHub(KnotsDbContext db, AutoMapper.IMapper mapper, EncryptionService encryption) : Hub
|
||||||
{
|
{
|
||||||
// Rejoindre une conversation (room)
|
// Rejoindre une conversation (room)
|
||||||
public async Task JoinConversation(string conversationId)
|
public async Task JoinConversation(string discussionId)
|
||||||
{
|
{
|
||||||
await Groups.AddToGroupAsync(Context.ConnectionId, conversationId);
|
await Groups.AddToGroupAsync(Context.ConnectionId, discussionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quitter une conversation
|
// Quitter une conversation
|
||||||
public async Task LeaveConversation(string conversationId)
|
public async Task LeaveConversation(string discussionId)
|
||||||
{
|
{
|
||||||
await Groups.RemoveFromGroupAsync(Context.ConnectionId, conversationId);
|
await Groups.RemoveFromGroupAsync(Context.ConnectionId, discussionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Envoyer un message à une conversation
|
// Envoyer un message à une conversation
|
||||||
public async Task SendMessage(string conversationId, string content)
|
public async Task SendMessage(string discussionId, string content)
|
||||||
{
|
{
|
||||||
|
int id = int.Parse(discussionId);
|
||||||
|
|
||||||
|
Models.Discussion discussion = await db.Discussions
|
||||||
|
.Include(d => d.Key)
|
||||||
|
.SingleAsync(d => d.Id == id);
|
||||||
|
|
||||||
var message = new Models.Message
|
var message = new Models.Message
|
||||||
{
|
{
|
||||||
// adapte aux noms réels de ton modèle (AuthorId, Contenu, Date...)
|
Contenu = encryption.Encrypt(content, discussion.Key!.EnKey!), // chiffré en base
|
||||||
AuthorId = int.Parse(Context.UserIdentifier!),
|
Date = DateTime.UtcNow,
|
||||||
Contenu = content,
|
Type = false,
|
||||||
Date = DateTime.UtcNow,
|
UserId = int.Parse(Context.UserIdentifier!),
|
||||||
DiscussionId = int.Parse(conversationId)
|
DiscussionId = id
|
||||||
};
|
};
|
||||||
|
|
||||||
db.Messages.Add(message);
|
db.Messages.Add(message);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
await Clients.Group(conversationId).SendAsync("ReceiveMessage", message);
|
// diffusion en clair, avec les noms de champs attendus par le front
|
||||||
|
await Clients.Group(discussionId).SendAsync("ReceiveMessage", new
|
||||||
|
{
|
||||||
|
id = message.Id,
|
||||||
|
contenu = content,
|
||||||
|
date = message.Date,
|
||||||
|
userId = message.UserId
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notifier que l'utilisateur est en train d'écrire
|
// Notifier que l'utilisateur est en train d'écrire
|
||||||
public async Task Typing(string conversationId)
|
public async Task Typing(string discussionId)
|
||||||
{
|
{
|
||||||
await Clients.OthersInGroup(conversationId)
|
await Clients.OthersInGroup(discussionId)
|
||||||
.SendAsync("UserTyping", Context.UserIdentifier);
|
.SendAsync("UserTyping", Context.UserIdentifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,9 @@ public class Discussion
|
|||||||
public int? GroupId { get; set; }
|
public int? GroupId { get; set; }
|
||||||
public Group? Group { get; set; }
|
public Group? Group { get; set; }
|
||||||
|
|
||||||
|
public int? KeyId { get; set; }
|
||||||
|
public Key? Key { get; set; }
|
||||||
|
|
||||||
public List<Message> Messages { get; set; } = [];
|
public List<Message> Messages { get; set; } = [];
|
||||||
public List<UserDiscussion> UserDiscussions { get; set; } = [];
|
public List<UserDiscussion> UserDiscussions { get; set; } = [];
|
||||||
}
|
}
|
||||||
@@ -6,5 +6,4 @@ public class Key
|
|||||||
{
|
{
|
||||||
[Key] public int Id { get; set; }
|
[Key] public int Id { get; set; }
|
||||||
[Required, MaxLength(50)] public string? EnKey { get; set; }
|
[Required, MaxLength(50)] public string? EnKey { get; set; }
|
||||||
public List<Message> Messages { get; set; } = [];
|
|
||||||
}
|
}
|
||||||
@@ -9,8 +9,6 @@ public class Message
|
|||||||
[Required] public DateTime Date { get; set; }
|
[Required] public DateTime Date { get; set; }
|
||||||
[Required] public Boolean Type { get; set; }
|
[Required] public Boolean Type { get; set; }
|
||||||
|
|
||||||
public int AuthorId { get; set; }
|
|
||||||
|
|
||||||
public int UserId { get; set; }
|
public int UserId { get; set; }
|
||||||
public User User { get; set; } = null!;
|
public User User { get; set; } = null!;
|
||||||
|
|
||||||
@@ -18,5 +16,4 @@ public class Message
|
|||||||
public Discussion Discussion { get; set; } = null!;
|
public Discussion Discussion { get; set; } = null!;
|
||||||
|
|
||||||
public Group? Group { get; set; }
|
public Group? Group { get; set; }
|
||||||
public Key? Key { get; set; }
|
|
||||||
}
|
}
|
||||||
@@ -73,6 +73,8 @@ builder.Services.AddSignalR();
|
|||||||
|
|
||||||
builder.Services.AddAutoMapper(cfg => { }, typeof(Program).Assembly);
|
builder.Services.AddAutoMapper(cfg => { }, typeof(Program).Assembly);
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<EncryptionService>();
|
||||||
|
|
||||||
// On construit l'application en lui donnant vie
|
// On construit l'application en lui donnant vie
|
||||||
WebApplication app = builder.Build();
|
WebApplication app = builder.Build();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Knots.Services;
|
||||||
|
|
||||||
|
public class EncryptionService
|
||||||
|
{
|
||||||
|
private const int NonceSize = 12; // AesGcm.NonceByteSizes.MaxSize
|
||||||
|
private const int TagSize = 16; // AesGcm.TagByteSizes.MaxSize
|
||||||
|
|
||||||
|
// Génère une clé AES-256 (32 octets) encodée en Base64
|
||||||
|
public string GenerateKey()
|
||||||
|
=> Convert.ToBase64String(RandomNumberGenerator.GetBytes(32));
|
||||||
|
|
||||||
|
// Chiffre → renvoie Base64(nonce + tag + ciphertext)
|
||||||
|
public string Encrypt(string plainText, string base64Key)
|
||||||
|
{
|
||||||
|
byte[] key = Convert.FromBase64String(base64Key);
|
||||||
|
byte[] plain = Encoding.UTF8.GetBytes(plainText);
|
||||||
|
|
||||||
|
byte[] nonce = RandomNumberGenerator.GetBytes(NonceSize);
|
||||||
|
byte[] cipher = new byte[plain.Length];
|
||||||
|
byte[] tag = new byte[TagSize];
|
||||||
|
|
||||||
|
using AesGcm aes = new(key, TagSize);
|
||||||
|
aes.Encrypt(nonce, plain, cipher, tag);
|
||||||
|
|
||||||
|
byte[] result = new byte[NonceSize + TagSize + cipher.Length];
|
||||||
|
Buffer.BlockCopy(nonce, 0, result, 0, NonceSize);
|
||||||
|
Buffer.BlockCopy(tag, 0, result, NonceSize, TagSize);
|
||||||
|
Buffer.BlockCopy(cipher, 0, result, NonceSize + TagSize, cipher.Length);
|
||||||
|
|
||||||
|
return Convert.ToBase64String(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Déchiffre Base64(nonce + tag + ciphertext)
|
||||||
|
public string Decrypt(string base64Cipher, string base64Key)
|
||||||
|
{
|
||||||
|
byte[] key = Convert.FromBase64String(base64Key);
|
||||||
|
byte[] data = Convert.FromBase64String(base64Cipher);
|
||||||
|
|
||||||
|
byte[] nonce = new byte[NonceSize];
|
||||||
|
byte[] tag = new byte[TagSize];
|
||||||
|
byte[] cipher = new byte[data.Length - NonceSize - TagSize];
|
||||||
|
|
||||||
|
Buffer.BlockCopy(data, 0, nonce, 0, NonceSize);
|
||||||
|
Buffer.BlockCopy(data, NonceSize, tag, 0, TagSize);
|
||||||
|
Buffer.BlockCopy(data, NonceSize + TagSize, cipher, 0, cipher.Length);
|
||||||
|
|
||||||
|
byte[] plain = new byte[cipher.Length];
|
||||||
|
using AesGcm aes = new(key, TagSize);
|
||||||
|
aes.Decrypt(nonce, cipher, tag, plain);
|
||||||
|
|
||||||
|
return Encoding.UTF8.GetString(plain);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ public class CreateMessageDtoValidator : Validator<CreateMessageDto>
|
|||||||
RuleFor(x => x.Contenu)
|
RuleFor(x => x.Contenu)
|
||||||
.NotEmpty()
|
.NotEmpty()
|
||||||
.WithMessage("Le message ne peux pas être vide")
|
.WithMessage("Le message ne peux pas être vide")
|
||||||
.MaximumLength(1000)
|
.MaximumLength(2000)
|
||||||
.WithMessage("Le message ne doit pas faire plus de 1000 caractères");
|
.WithMessage("Le message ne doit pas faire plus de 1000 caractères");
|
||||||
|
|
||||||
RuleFor(x => x.Date)
|
RuleFor(x => x.Date)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -13,7 +13,7 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Knots")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("Knots")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+f1cdc5de19a96d553f0eaf2fbe65392602c54f85")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+61f3d2889c45fcfb95557be37845198db85b3972")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("Knots")]
|
[assembly: System.Reflection.AssemblyProductAttribute("Knots")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("Knots")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("Knots")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
0618e480c1221c208fb53c91259f81c85675af45b5772bccc9fee873e927c02b
|
589797db71c3ee2db1d8c966ae2f187808629461cd5e264f494b12d939f74905
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1afb5c57f375954b5501d52f6ccbfcdd0c9a4a7d75abca85439c878c12264607
|
8c008e0540a310c319081e4a6b8a7ce2f5c9b271d5260b8b45b33f49b9ad5228
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
17811302030866425
|
17811676816949331
|
||||||
@@ -1 +1 @@
|
|||||||
17811302053941977
|
17811669515789890
|
||||||
Reference in New Issue
Block a user